├── .gitignore
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── github
│ └── sv244
│ └── torrentstream
│ ├── StreamStatus.java
│ ├── Torrent.java
│ ├── TorrentOptions.java
│ ├── TorrentStream.java
│ ├── exceptions
│ ├── DirectoryCreationException.java
│ ├── NotInitializedException.java
│ └── TorrentInfoException.java
│ ├── listeners
│ ├── DHTStatsAlertListener.java
│ ├── TorrentAddedAlertListener.java
│ └── TorrentListener.java
│ └── utils
│ ├── FileUtils.java
│ └── ThreadUtils.java
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── eu
│ │ └── sv244
│ │ └── torrentstreamer
│ │ └── sample
│ │ └── MainActivity.java
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── menu_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | .idea/
15 | *.iml
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Keystore
31 | *.jks
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | TorrentStream-Android
2 | ======
3 |
4 | A torrent streamer library for Android based on [jlibtorrent](https://github.com/frostwire/frostwire-jlibtorrent).
5 |
6 | Used in [Popcorn Time for Android](https://github.com/popcorn-official/popcorn-android) and definitely not done yet.
7 |
8 | Using
9 | --------
10 |
11 | See the sample.
12 |
13 | Available on Maven Central as 'com.github.sv244:torrentstream-android'
14 |
15 | License
16 | --------
17 |
18 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
19 |
20 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 |
22 | You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
23 |
24 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidTorrent/TorrentStream-Android/b2e49cd2ab8078d8686e6cd68adcc4ca16fb2d9a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Aug 08 21:50:44 CEST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | }
5 |
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:1.3.0'
8 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | def groupId = 'com.github.sv244'
17 | def artifactId = 'torrentstream-android'
18 | def version = '1.0.2'
19 | def localReleaseDest = "${buildDir}/release/${version}"
20 |
21 | apply plugin: 'com.android.library'
22 | apply plugin: 'maven'
23 | apply plugin: 'signing'
24 |
25 | android {
26 | compileSdkVersion 23
27 | buildToolsVersion "23.0.0"
28 |
29 | defaultConfig {
30 | minSdkVersion 15
31 | targetSdkVersion 23
32 | versionCode 1
33 | versionName '1.0.2'
34 | }
35 |
36 | buildTypes {
37 | release {
38 | minifyEnabled false
39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
40 | }
41 | }
42 |
43 | lintOptions {
44 | abortOnError false
45 | }
46 | }
47 |
48 | dependencies {
49 | compile fileTree(dir: 'libs', include: ['*.jar'])
50 | compile 'com.frostwire:jlibtorrent:1.1.0.9'
51 | compile 'com.frostwire:jlibtorrent-android:1.1.0.9'
52 | }
53 |
54 | task androidJavadocs(type: Javadoc) {
55 | source = android.sourceSets.main.java.srcDirs
56 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
57 | }
58 |
59 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
60 | classifier = 'javadoc'
61 | from androidJavadocs.destinationDir
62 | }
63 |
64 | task androidSourcesJar(type: Jar) {
65 | classifier = 'sources'
66 | from android.sourceSets.main.java.srcDirs
67 | }
68 |
69 | artifacts {
70 | archives androidSourcesJar
71 | archives androidJavadocsJar
72 | }
73 |
74 | signing {
75 | sign configurations.archives
76 | }
77 |
78 | uploadArchives {
79 | repositories.mavenDeployer {
80 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
81 | pom.groupId = groupId
82 | pom.artifactId = artifactId
83 | pom.version = version
84 | pom.project {
85 | name 'TorrentStream-Android'
86 | packaging 'aar'
87 | description 'Android Torrent Streaming library'
88 | url 'https://github.com/sv244/TorrentStream-Android'
89 |
90 | scm {
91 | url 'https://github.com/sv244/TorrentStream-Android'
92 | connection 'scm:git@github.com:sv244/TorrentStream-Android.git'
93 | developerConnection 'scm:git@github.com:sv244/TorrentStream-Android.git'
94 | }
95 |
96 | licenses {
97 | license {
98 | name 'GNU General Public License, Version 3.0'
99 | url 'www.gnu.org/licenses/gpl-3.0.html'
100 | }
101 | }
102 |
103 | developers {
104 | developer {
105 | id 'sv244'
106 | name 'sv244'
107 | email 'sv244@it.pt'
108 | }
109 | }
110 | }
111 |
112 | repository(url: "file://${localReleaseDest}")
113 | }
114 | }
115 |
116 | task zipRelease(type: Zip) {
117 | from (localReleaseDest + '/com/github/sv244/torrentstream-android/' + version + '/')
118 | destinationDir buildDir
119 | archiveName "release-${version}.zip"
120 | }
121 |
122 | task generateRelease << {
123 | println "Release ${version} can be found at ${localReleaseDest}/"
124 | println "Release ${version} zipped can be found ${buildDir}/release-${version}.zip"
125 | }
126 |
127 | generateRelease.dependsOn(uploadArchives)
128 | generateRelease.dependsOn(zipRelease)
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Sebastiaan/Development/Android/SDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/StreamStatus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of TorrentStreamer-Android.
3 | *
4 | * TorrentStreamer-Android is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * TorrentStreamer-Android is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with TorrentStreamer-Android. If not, see .
16 | */
17 |
18 | package com.github.sv244.torrentstream;
19 |
20 | public class StreamStatus {
21 | public final float progress;
22 | public final int bufferProgress;
23 | public final int seeds;
24 | public final float downloadSpeed;
25 |
26 | protected StreamStatus(float progress, int bufferProgress, int seeds, int downloadSpeed) {
27 | this.progress = progress;
28 | this.bufferProgress = bufferProgress;
29 | this.seeds = seeds;
30 | this.downloadSpeed = downloadSpeed;
31 | }
32 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/Torrent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of TorrentStreamer-Android.
3 | *
4 | * TorrentStreamer-Android is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * TorrentStreamer-Android is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with TorrentStreamer-Android. If not, see .
16 | */
17 |
18 | package com.github.sv244.torrentstream;
19 |
20 | import com.frostwire.jlibtorrent.AlertListener;
21 | import com.frostwire.jlibtorrent.FileStorage;
22 | import com.frostwire.jlibtorrent.Priority;
23 | import com.frostwire.jlibtorrent.TorrentHandle;
24 | import com.frostwire.jlibtorrent.TorrentInfo;
25 | import com.frostwire.jlibtorrent.TorrentStatus;
26 | import com.frostwire.jlibtorrent.alerts.Alert;
27 | import com.frostwire.jlibtorrent.alerts.AlertType;
28 | import com.frostwire.jlibtorrent.alerts.BlockFinishedAlert;
29 | import com.frostwire.jlibtorrent.alerts.PieceFinishedAlert;
30 |
31 | import java.io.File;
32 | import java.util.ArrayList;
33 | import java.util.Arrays;
34 | import java.util.Iterator;
35 | import java.util.List;
36 |
37 | import com.github.sv244.torrentstream.listeners.TorrentListener;
38 |
39 | public class Torrent implements AlertListener {
40 |
41 | private final static Integer MAX_PREPARE_COUNT = 20;
42 | private final static Integer MIN_PREPARE_COUNT = 2;
43 | private final static Integer DEFAULT_PREPARE_COUNT = 5;
44 |
45 | public enum State { UNKNOWN, RETRIEVING_META, STARTING, STREAMING }
46 |
47 | private Integer mPiecesToPrepare;
48 | private Integer mLastPieceIndex;
49 | private Integer mFirstPieceIndex;
50 | private Integer mSelectedFile = -1;
51 | private Long mPrepareSize;
52 |
53 | private Double mPrepareProgress = 0d;
54 | private Double mProgressStep = 0d;
55 | private List mPreparePieces;
56 | private Boolean[] mHasPieces;
57 | private Integer[] mProcessingPieces = new Integer[5];
58 |
59 | private TorrentHandle mTorrentHandle;
60 | private TorrentListener mListener;
61 |
62 | private State mState = State.RETRIEVING_META;
63 |
64 | /**
65 | * The constructor for a new Torrent
66 | *
67 | * First the largest file in the download is selected as the file for playback
68 | *
69 | * After setting this priority, the first and last index of the pieces that make up this file are determined.
70 | * And last: amount of pieces that are needed for playback are calculated (needed for playback means: make up 10 megabyte of the file)
71 | *
72 | * @param torrentHandle jlibtorrent TorrentHandle
73 | */
74 | public Torrent(TorrentHandle torrentHandle, TorrentListener listener, Long prepareSize) {
75 | mTorrentHandle = torrentHandle;
76 | mListener = listener;
77 |
78 | mPrepareSize = prepareSize;
79 |
80 | torrentHandle.setPriority(Priority.NORMAL.getSwig());
81 |
82 | if(mSelectedFile == -1)
83 | setLargestFile();
84 |
85 | if(mListener != null)
86 | mListener.onStreamPrepared(this);
87 | }
88 |
89 | /**
90 | * Reset piece priorities
91 | * First set all piece priorities to {@link Priority}.IGNORE and then set the file priority to the file selected for playback.
92 | */
93 | private void resetPriorities() {
94 | Priority[] priorities = mTorrentHandle.getPiecePriorities();
95 | for (int i = 0; i < priorities.length; i++) {
96 | if(i >= mFirstPieceIndex && i <= mLastPieceIndex) {
97 | mTorrentHandle.setPiecePriority(i, Priority.NORMAL);
98 | } else {
99 | mTorrentHandle.setPiecePriority(i, Priority.IGNORE);
100 | }
101 | }
102 | }
103 |
104 | /**
105 | * Get LibTorrent torrent handle of this torrent
106 | * @return
107 | */
108 | public TorrentHandle getTorrentHandle() {
109 | return mTorrentHandle;
110 | }
111 |
112 | public File getVideoFile() {
113 | return new File(mTorrentHandle.getSavePath() + "/" + mTorrentHandle.getTorrentInfo().getFiles().getFilePath(mSelectedFile));
114 | }
115 |
116 | public File getSaveLocation() {
117 | return new File(mTorrentHandle.getSavePath() + "/" + mTorrentHandle.getName());
118 | }
119 |
120 | public void resume() {
121 | mTorrentHandle.resume();
122 | }
123 |
124 | public void pause() {
125 | mTorrentHandle.pause();
126 | }
127 |
128 | public void setLargestFile() {
129 | setSelectedFile(-1);
130 | }
131 |
132 | /**
133 | * Set the file to download
134 | * If the given index is -1, then the largest file is chosen
135 | * @param selectedFileIndex Integer
136 | */
137 | public void setSelectedFile(Integer selectedFileIndex) {
138 | TorrentInfo torrentInfo = mTorrentHandle.getTorrentInfo();
139 | FileStorage fileStorage = torrentInfo.getFiles();
140 |
141 | if(selectedFileIndex == -1) {
142 | long highestFileSize = 0;
143 | int selectedFile = -1;
144 | for (int i = 0; i < fileStorage.getNumFiles(); i++) {
145 | long fileSize = fileStorage.getFileSize(i);
146 | if (highestFileSize < fileSize) {
147 | highestFileSize = fileSize;
148 | mTorrentHandle.setFilePriority(selectedFile, Priority.IGNORE);
149 | selectedFile = i;
150 | mTorrentHandle.setFilePriority(i, Priority.NORMAL);
151 | } else {
152 | mTorrentHandle.setFilePriority(i, Priority.IGNORE);
153 | }
154 | }
155 | selectedFileIndex = selectedFile;
156 | } else {
157 | for (int i = 0; i < fileStorage.getNumFiles(); i++) {
158 | if(i == selectedFileIndex) {
159 | mTorrentHandle.setFilePriority(i, Priority.NORMAL);
160 | } else {
161 | mTorrentHandle.setFilePriority(i, Priority.IGNORE);
162 | }
163 | }
164 | }
165 | mSelectedFile = selectedFileIndex;
166 |
167 | Priority[] piecePriorities = mTorrentHandle.getPiecePriorities();
168 | int firstPieceIndex = -1;
169 | int lastPieceIndex = -1;
170 | for (int i = 0; i < piecePriorities.length; i++) {
171 | if (piecePriorities[i] != Priority.IGNORE) {
172 | if (firstPieceIndex == -1) {
173 | firstPieceIndex = i;
174 | }
175 | piecePriorities[i] = Priority.IGNORE;
176 | } else {
177 | if (firstPieceIndex != -1 && lastPieceIndex == -1) {
178 | lastPieceIndex = i - 1;
179 | }
180 | }
181 | }
182 |
183 | if (lastPieceIndex == -1) {
184 | lastPieceIndex = piecePriorities.length - 1;
185 | }
186 | int pieceCount = lastPieceIndex - firstPieceIndex + 1;
187 | int pieceLength = mTorrentHandle.getTorrentInfo().getPieceLength();
188 | int activePieceCount;
189 | if (pieceLength > 0) {
190 | activePieceCount = (int) (mPrepareSize / pieceLength);
191 | if (activePieceCount < MIN_PREPARE_COUNT) {
192 | activePieceCount = MIN_PREPARE_COUNT;
193 | } else if (activePieceCount > MAX_PREPARE_COUNT) {
194 | activePieceCount = MAX_PREPARE_COUNT;
195 | }
196 | } else {
197 | activePieceCount = DEFAULT_PREPARE_COUNT;
198 | }
199 |
200 | if (pieceCount < activePieceCount) {
201 | activePieceCount = pieceCount / 2;
202 | }
203 |
204 | mFirstPieceIndex = firstPieceIndex;
205 | mLastPieceIndex = lastPieceIndex;
206 | mPiecesToPrepare = activePieceCount;
207 | }
208 |
209 | public String[] getFileNames() {
210 | FileStorage fileStorage = mTorrentHandle.getTorrentInfo().getFiles();
211 | String[] fileNames = new String[fileStorage.getNumFiles()];
212 | for(int i = 0; i < fileStorage.getNumFiles(); i++) {
213 | fileNames[i] = fileStorage.getFileName(i);
214 | }
215 | return fileNames;
216 | }
217 |
218 | /**
219 | * Prepare torrent for playback. Prioritize the first `mPiecesToPrepare` pieces and the last `mPiecesToPrepare` pieces
220 | * from `mFirstPieceIndex` and `mLastPieceIndex`. Ignore all other pieces.
221 | */
222 | public void startDownload() {
223 | if(mState == State.STREAMING) return;
224 | mState = State.STARTING;
225 | mTorrentHandle.setPriority(Priority.NORMAL.getSwig());
226 |
227 | List indices = new ArrayList<>();
228 |
229 | Priority[] priorities = mTorrentHandle.getPiecePriorities();
230 | for (int i = 0; i < priorities.length; i++) {
231 | if(priorities[i] != Priority.IGNORE) {
232 | mTorrentHandle.setPiecePriority(i, Priority.NORMAL);
233 | }
234 | }
235 |
236 | for (int i = 0; i < mPiecesToPrepare; i++) {
237 | indices.add(mLastPieceIndex - i);
238 | mTorrentHandle.setPiecePriority(mLastPieceIndex - i, Priority.SEVEN);
239 | mTorrentHandle.setPieceDeadline(mLastPieceIndex - i, 1000);
240 | }
241 |
242 | for (int i = 0; i < mPiecesToPrepare; i++) {
243 | indices.add(mFirstPieceIndex + i);
244 | mTorrentHandle.setPiecePriority(mFirstPieceIndex + i, Priority.SEVEN);
245 | mTorrentHandle.setPieceDeadline(mFirstPieceIndex + i, 1000);
246 | }
247 |
248 | mPreparePieces = indices;
249 |
250 | mHasPieces = new Boolean[mLastPieceIndex - mFirstPieceIndex + 1];
251 | Arrays.fill(mHasPieces, false);
252 |
253 | TorrentInfo torrentInfo = mTorrentHandle.getTorrentInfo();
254 | TorrentStatus status = mTorrentHandle.getStatus();
255 |
256 | double blockCount = indices.size() * torrentInfo.getPieceLength() / status.getBlockSize();
257 |
258 | mProgressStep = 100 / blockCount;
259 |
260 | mTorrentHandle.resume();
261 |
262 | mListener.onStreamStarted(this);
263 | }
264 |
265 | private void startSequentialMode() {
266 | resetPriorities();
267 |
268 | if(mHasPieces == null) {
269 | mTorrentHandle.setSequentialDownload(true);
270 | } else {
271 | for (int i = mFirstPieceIndex + mPiecesToPrepare; i < mFirstPieceIndex + mPiecesToPrepare + 5; i++) {
272 | mTorrentHandle.setPiecePriority(i, Priority.SEVEN);
273 | mTorrentHandle.setPieceDeadline(i, 1000);
274 | }
275 | }
276 | }
277 |
278 | public State getState() {
279 | return mState;
280 | }
281 |
282 | public void pieceFinished(PieceFinishedAlert alert) {
283 | if(mState == State.STREAMING && mHasPieces != null) {
284 | mHasPieces[alert.getPieceIndex() - mFirstPieceIndex] = true;
285 |
286 | for(int i = alert.getPieceIndex() - mFirstPieceIndex; i < mHasPieces.length; i++) {
287 | if(!mHasPieces[i]) {
288 | mTorrentHandle.setPiecePriority(i + mFirstPieceIndex, Priority.SEVEN);
289 | mTorrentHandle.setPieceDeadline(i + mFirstPieceIndex, 1000);
290 | break;
291 | }
292 | }
293 | } else {
294 | Iterator piecesIterator = mPreparePieces.iterator();
295 | while (piecesIterator.hasNext()) {
296 | int index = piecesIterator.next();
297 | if (index == alert.getPieceIndex()) {
298 | piecesIterator.remove();
299 | }
300 | }
301 |
302 | if(mHasPieces != null)
303 | mHasPieces[alert.getPieceIndex() - mFirstPieceIndex] = true;
304 |
305 | if (mPreparePieces.size() == 0) {
306 | startSequentialMode();
307 |
308 | mPrepareProgress = 100d;
309 | sendStreamProgress();
310 | mState = State.STREAMING;
311 |
312 | if (mListener != null)
313 | mListener.onStreamReady(this);
314 | }
315 | }
316 | }
317 |
318 | public void blockFinished(BlockFinishedAlert alert) {
319 | for (Integer index : mPreparePieces) {
320 | if (index == alert.getPieceIndex()) {
321 | mPrepareProgress += mProgressStep;
322 | break;
323 | }
324 | }
325 |
326 | sendStreamProgress();
327 | }
328 |
329 | private void sendStreamProgress() {
330 | TorrentStatus status = mTorrentHandle.getStatus();
331 | float progress = status.getProgress() * 100;
332 | int seeds = status.getNumSeeds();
333 | int downloadSpeed = status.getDownloadPayloadRate();
334 |
335 | if(mListener != null && mPrepareProgress >= 1)
336 | mListener.onStreamProgress(this, new StreamStatus(progress, mPrepareProgress.intValue(), seeds, downloadSpeed));
337 | }
338 |
339 | @Override
340 | public int[] types() {
341 | return new int[] { AlertType.PIECE_FINISHED.getSwig(), AlertType.BLOCK_FINISHED.getSwig() };
342 | }
343 |
344 | @Override
345 | public void alert(Alert> alert) {
346 | switch (alert.getType()) {
347 | case PIECE_FINISHED:
348 | pieceFinished((PieceFinishedAlert) alert);
349 | break;
350 | case BLOCK_FINISHED:
351 | blockFinished((BlockFinishedAlert) alert);
352 | break;
353 | }
354 | }
355 |
356 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/TorrentOptions.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package com.github.sv244.torrentstream;
21 |
22 | import java.io.File;
23 |
24 | public class TorrentOptions {
25 |
26 | protected String mSaveLocation = "/", mProxyHost, mProxyUsername, mProxyPassword, mPeerFingerprint;
27 | protected Integer mMaxDownloadSpeed = 0, mMaxUploadSpeed = 0, mMaxConnections = 200, mMaxDht = 88, mListeningPort = -1;
28 | protected Boolean mRemoveFiles = false, mAnonymousMode = true;
29 | protected Long mPrepareSize = 10 * 1024L * 1024L;
30 |
31 | public void setSaveLocation(String saveLocation) {
32 | mSaveLocation = saveLocation;
33 | }
34 |
35 | public void setSaveLocation(File saveLocation) {
36 | mSaveLocation = saveLocation.getAbsolutePath();
37 | }
38 |
39 | public void setMaxUploadSpeed(Integer maxUploadSpeed) {
40 | mMaxUploadSpeed = maxUploadSpeed;
41 | }
42 |
43 | public void setMaxDownloadSpeed(Integer maxDownloadSpeed) {
44 | mMaxDownloadSpeed = maxDownloadSpeed;
45 | }
46 |
47 | public void setMaxConnections(Integer maxConnections) {
48 | mMaxConnections = maxConnections;
49 | }
50 |
51 | public void setMaxActiveDHT(Integer maxActiveDHT) {
52 | mMaxDht = maxActiveDHT;
53 | }
54 |
55 | public void setRemoveFilesAfterStop(Boolean b) {
56 | mRemoveFiles = b;
57 | }
58 |
59 | public void setPrepareSize(Long prepareSize) {
60 | mPrepareSize = prepareSize;
61 | }
62 |
63 | public void setListeningPort(Integer port) {
64 | mListeningPort = port;
65 | }
66 |
67 | public void setProxy(String host, String username, String password) {
68 | mProxyHost = host;
69 | mProxyUsername = username;
70 | mProxyPassword = password;
71 | }
72 |
73 | public void setPeerFingerprint(String peerId) {
74 | mPeerFingerprint = peerId;
75 | mAnonymousMode = false;
76 | }
77 |
78 | public void setAnonymousMode(Boolean enable) {
79 | mAnonymousMode = enable;
80 | if(mAnonymousMode)
81 | mPeerFingerprint = null;
82 | }
83 |
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/TorrentStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of TorrentStreamer-Android.
3 | *
4 | * TorrentStreamer-Android is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * TorrentStreamer-Android is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with TorrentStreamer-Android. If not, see .
16 | */
17 |
18 | package com.github.sv244.torrentstream;
19 |
20 | import android.net.Uri;
21 | import android.os.Handler;
22 | import android.os.HandlerThread;
23 |
24 | import com.frostwire.jlibtorrent.DHT;
25 | import com.frostwire.jlibtorrent.Downloader;
26 | import com.frostwire.jlibtorrent.Priority;
27 | import com.frostwire.jlibtorrent.Session;
28 | import com.frostwire.jlibtorrent.SettingsPack;
29 | import com.frostwire.jlibtorrent.TorrentHandle;
30 | import com.frostwire.jlibtorrent.TorrentInfo;
31 | import com.frostwire.jlibtorrent.alerts.TorrentAddedAlert;
32 | import com.frostwire.jlibtorrent.swig.settings_pack;
33 | import com.github.sv244.torrentstream.exceptions.DirectoryCreationException;
34 | import com.github.sv244.torrentstream.exceptions.NotInitializedException;
35 | import com.github.sv244.torrentstream.exceptions.TorrentInfoException;
36 | import com.github.sv244.torrentstream.listeners.DHTStatsAlertListener;
37 | import com.github.sv244.torrentstream.listeners.TorrentAddedAlertListener;
38 | import com.github.sv244.torrentstream.listeners.TorrentListener;
39 | import com.github.sv244.torrentstream.utils.FileUtils;
40 | import com.github.sv244.torrentstream.utils.ThreadUtils;
41 |
42 | import java.io.ByteArrayOutputStream;
43 | import java.io.File;
44 | import java.io.FileInputStream;
45 | import java.io.FileNotFoundException;
46 | import java.io.IOException;
47 | import java.io.InputStream;
48 | import java.net.HttpURLConnection;
49 | import java.net.MalformedURLException;
50 | import java.net.URL;
51 | import java.util.ArrayList;
52 | import java.util.List;
53 |
54 | public class TorrentStream {
55 |
56 | private static final String LIBTORRENT_THREAD_NAME = "TORRENTSTREAM_LIBTORRENT", STREAMING_THREAD_NAME = "TORRENTSTREAMER_STREAMING";
57 | private static TorrentStream INSTANCE;
58 |
59 | private Session mTorrentSession;
60 | private DHT mDHT;
61 | private Boolean mInitialised = false, mIsStreaming = false, mIsCancelled = false;
62 | private TorrentOptions mTorrentOptions;
63 |
64 | private Torrent mCurrentTorrent;
65 | private String mCurrentTorrentUrl;
66 | private Integer mDhtNodes = 0;
67 |
68 | private List mListener = new ArrayList<>();
69 |
70 | private HandlerThread mLibTorrentThread, mStreamingThread;
71 | private Handler mLibTorrentHandler, mStreamingHandler;
72 |
73 | private TorrentStream(TorrentOptions options) {
74 | mTorrentOptions = options;
75 | initialise();
76 | }
77 |
78 | public static TorrentStream init(TorrentOptions options) {
79 | INSTANCE = new TorrentStream(options);
80 | return INSTANCE;
81 | }
82 |
83 | public static TorrentStream getInstance() throws NotInitializedException {
84 | if(INSTANCE == null)
85 | throw new NotInitializedException();
86 |
87 | return INSTANCE;
88 | }
89 |
90 | private void initialise() {
91 | if (mLibTorrentThread != null && mTorrentSession != null) {
92 | resumeSession();
93 | } else {
94 | if(mInitialised) {
95 | if (mLibTorrentThread != null) {
96 | mLibTorrentThread.interrupt();
97 | }
98 | }
99 |
100 | mLibTorrentThread = new HandlerThread(LIBTORRENT_THREAD_NAME);
101 | mLibTorrentThread.start();
102 | mLibTorrentHandler = new Handler(mLibTorrentThread.getLooper());
103 | mLibTorrentHandler.post(new Runnable() {
104 | @Override
105 | public void run() {
106 | mTorrentSession = new Session();
107 | setOptions(mTorrentOptions);
108 |
109 | mTorrentSession.addListener(mDhtStatsAlertListener);
110 |
111 | mDHT = new DHT(mTorrentSession);
112 | mDHT.start();
113 |
114 | mInitialised = true;
115 | }
116 | });
117 | }
118 | }
119 |
120 | /**
121 | * Resume TorrentSession
122 | */
123 | public void resumeSession() {
124 | if (mLibTorrentThread != null && mTorrentSession != null) {
125 | mLibTorrentHandler.removeCallbacksAndMessages(null);
126 |
127 | //resume torrent session if needed
128 | if (mTorrentSession.isPaused()) {
129 | mLibTorrentHandler.post(new Runnable() {
130 | @Override
131 | public void run() {
132 | mTorrentSession.resume();
133 | }
134 | });
135 | }
136 |
137 | //start DHT if needed
138 | if (mDHT != null && !mDHT.isRunning()) {
139 | mLibTorrentHandler.post(new Runnable() {
140 | @Override
141 | public void run() {
142 | mDHT.start();
143 | }
144 | });
145 | }
146 | }
147 | }
148 |
149 | /**
150 | * Pause TorrentSession
151 | */
152 | public void pauseSession() {
153 | if(!mIsStreaming)
154 | mLibTorrentHandler.post(new Runnable() {
155 | @Override
156 | public void run() {
157 | mTorrentSession.pause();
158 | }
159 | });
160 | }
161 |
162 | /**
163 | * Get torrent metadata, either by downloading the .torrent or fetching the magnet
164 | * @param torrentUrl {@link String} URL to .torrent or magnet link
165 | * @return {@link TorrentInfo}
166 | */
167 | private TorrentInfo getTorrentInfo(String torrentUrl) {
168 | if (torrentUrl.startsWith("magnet")) {
169 | Downloader d = new Downloader(mTorrentSession);
170 |
171 | byte[] data = d.fetchMagnet(torrentUrl, 30000);
172 | if(data != null)
173 | try {
174 | return TorrentInfo.bdecode(data);
175 | } catch (IllegalArgumentException e) {
176 | // Eat exception
177 | }
178 |
179 | } else if(torrentUrl.startsWith("http") || torrentUrl.startsWith("https")){
180 | try {
181 | URL url = new URL(torrentUrl);
182 | HttpURLConnection connection = (HttpURLConnection) url.openConnection();
183 |
184 | connection.setRequestMethod("GET");
185 | connection.setInstanceFollowRedirects(true);
186 | connection.connect();
187 |
188 | InputStream inputStream = connection.getInputStream();
189 |
190 | byte[] responseByteArray = new byte[0];
191 |
192 | if(connection.getResponseCode() == 200) {
193 | responseByteArray = getBytesFromInputStream(inputStream);
194 | }
195 |
196 | inputStream.close();
197 | connection.disconnect();
198 |
199 | if(responseByteArray.length > 0) {
200 | return TorrentInfo.bdecode(responseByteArray);
201 | }
202 | } catch (MalformedURLException e) {
203 | // Eat exception
204 | } catch (IOException e) {
205 | // Eat exception
206 | } catch (IllegalArgumentException e) {
207 | // Eat exception
208 | }
209 | } else if(torrentUrl.startsWith("file")) {
210 | Uri path = Uri.parse(torrentUrl);
211 | File file = new File(path.getPath());
212 |
213 | try {
214 | FileInputStream fileInputStream = new FileInputStream(file);
215 | byte[] responseByteArray = getBytesFromInputStream(fileInputStream);
216 | fileInputStream.close();
217 |
218 | if(responseByteArray.length > 0) {
219 | return TorrentInfo.bdecode(responseByteArray);
220 | }
221 | } catch (FileNotFoundException e) {
222 | // Eat exception
223 | } catch (IOException e) {
224 | // Eat exception
225 | } catch (IllegalArgumentException e) {
226 | // Eat exception
227 | }
228 | }
229 | return null;
230 | }
231 |
232 | private byte[] getBytesFromInputStream(InputStream inputStream) throws IOException {
233 | ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
234 |
235 | int bufferSize = 1024;
236 | byte[] buffer = new byte[bufferSize];
237 |
238 | int len = 0;
239 | while ((len = inputStream.read(buffer)) != -1) {
240 | byteBuffer.write(buffer, 0, len);
241 | }
242 |
243 | return byteBuffer.toByteArray();
244 | }
245 |
246 | /**
247 | * Start stream download for specified torrent
248 | * @param torrentUrl {@link String} .torrent or magnet link
249 | */
250 | public void startStream(final String torrentUrl) {
251 | if(!mInitialised)
252 | initialise();
253 |
254 | if (mLibTorrentHandler == null || mIsStreaming) return;
255 |
256 | mIsCancelled = false;
257 |
258 | mStreamingThread = new HandlerThread(STREAMING_THREAD_NAME);
259 | mStreamingThread.start();
260 | mStreamingHandler = new Handler(mStreamingThread.getLooper());
261 |
262 | mStreamingHandler.post(new Runnable() {
263 | @Override
264 | public void run() {
265 | mIsStreaming = true;
266 | mCurrentTorrentUrl = torrentUrl;
267 |
268 | File saveDirectory = new File(mTorrentOptions.mSaveLocation);
269 | if (!saveDirectory.isDirectory()) {
270 | if (!saveDirectory.mkdirs()) {
271 | for (final TorrentListener listener : mListener) {
272 | ThreadUtils.runOnUiThread(new Runnable() {
273 | @Override
274 | public void run() {
275 | listener.onStreamError(null, new DirectoryCreationException());
276 | }
277 | });
278 | }
279 | mIsStreaming = false;
280 | return;
281 | }
282 | }
283 |
284 | mTorrentSession.removeListener(mTorrentAddedAlertListener);
285 | TorrentInfo torrentInfo = getTorrentInfo(torrentUrl);
286 | mTorrentSession.addListener(mTorrentAddedAlertListener);
287 |
288 | if (torrentInfo == null) {
289 | for (final TorrentListener listener : mListener) {
290 | ThreadUtils.runOnUiThread(new Runnable() {
291 | @Override
292 | public void run() {
293 | listener.onStreamError(null, new TorrentInfoException());
294 | }
295 | });
296 | }
297 | mIsStreaming = false;
298 | return;
299 | }
300 |
301 | Priority[] priorities = new Priority[torrentInfo.getNumPieces()];
302 | for (int i = 0; i < priorities.length; i++) {
303 | priorities[i] = Priority.IGNORE;
304 | }
305 |
306 | if (!mCurrentTorrentUrl.equals(torrentUrl) || mIsCancelled) {
307 | return;
308 | }
309 |
310 | mTorrentSession.asyncAddTorrent(torrentInfo, saveDirectory, priorities, null);
311 | }
312 | });
313 | }
314 |
315 | /**
316 | * Stop current torrent stream
317 | */
318 | public void stopStream() {
319 | //remove all callbacks from handler
320 | if(mLibTorrentHandler != null)
321 | mLibTorrentHandler.removeCallbacksAndMessages(null);
322 | if(mStreamingHandler != null)
323 | mStreamingHandler.removeCallbacksAndMessages(null);
324 |
325 | mIsCancelled = true;
326 | mIsStreaming = false;
327 | if (mCurrentTorrent != null) {
328 | final File saveLocation = mCurrentTorrent.getSaveLocation();
329 |
330 | mCurrentTorrent.pause();
331 | mTorrentSession.removeListener(mCurrentTorrent);
332 | mTorrentSession.removeTorrent(mCurrentTorrent.getTorrentHandle());
333 | mCurrentTorrent = null;
334 |
335 | if (mTorrentOptions.mRemoveFiles) {
336 | new Thread(new Runnable() {
337 | @Override
338 | public void run() {
339 | int tries = 0;
340 | while(!FileUtils.recursiveDelete(saveLocation) && tries < 5) {
341 | tries++;
342 | try {
343 | Thread.sleep(1000); // If deleted failed then something is still using the file, wait and then retry
344 | } catch (InterruptedException e) {
345 | // Eat exception
346 | }
347 | }
348 | }
349 | }).start();
350 | }
351 | }
352 |
353 | if(mStreamingThread != null)
354 | mStreamingThread.interrupt();
355 |
356 | for (final TorrentListener listener : mListener) {
357 | ThreadUtils.runOnUiThread(new Runnable() {
358 | @Override
359 | public void run() {
360 | listener.onStreamStopped();
361 | }
362 | });
363 | }
364 | }
365 |
366 | public TorrentOptions getOptions() {
367 | return mTorrentOptions;
368 | }
369 |
370 | public void setOptions(TorrentOptions options) {
371 | mTorrentOptions = options;
372 |
373 | SettingsPack settingsPack = new SettingsPack();
374 | settingsPack.setAnonymousMode(mTorrentOptions.mAnonymousMode);
375 |
376 | settingsPack.setConnectionsLimit(mTorrentOptions.mMaxConnections);
377 | settingsPack.setDownloadRateLimit(mTorrentOptions.mMaxDownloadSpeed);
378 | settingsPack.setUploadRateLimit(mTorrentOptions.mMaxUploadSpeed);
379 | settingsPack.setInteger(settings_pack.int_types.active_dht_limit.swigValue(), mTorrentOptions.mMaxDht);
380 |
381 | if(mTorrentOptions.mListeningPort != -1) {
382 | String if_string = String.format("%s:%d", "0.0.0.0", mTorrentOptions.mListeningPort);
383 | settingsPack.setString(settings_pack.string_types.listen_interfaces.swigValue(), if_string);
384 | }
385 |
386 | if(mTorrentOptions.mProxyHost != null)
387 | settingsPack.setString(settings_pack.string_types.proxy_hostname.swigValue(), mTorrentOptions.mProxyHost);
388 | if(mTorrentOptions.mProxyUsername != null)
389 | settingsPack.setString(settings_pack.string_types.proxy_username.swigValue(), mTorrentOptions.mProxyUsername);
390 | if(mTorrentOptions.mProxyPassword != null)
391 | settingsPack.setString(settings_pack.string_types.proxy_password.swigValue(), mTorrentOptions.mProxyPassword);
392 |
393 | if(mTorrentOptions.mPeerFingerprint != null)
394 | settingsPack.setString(settings_pack.string_types.peer_fingerprint.swigValue(), mTorrentOptions.mPeerFingerprint);
395 |
396 | mTorrentSession.applySettings(settingsPack);
397 | }
398 |
399 | public boolean isStreaming() {
400 | return mIsStreaming;
401 | }
402 |
403 | public String getCurrentTorrentUrl() {
404 | return mCurrentTorrentUrl;
405 | }
406 |
407 | public Integer getTotalDhtNodes() {
408 | return mDhtNodes;
409 | }
410 |
411 | public void addListener(TorrentListener listener) {
412 | if(listener != null)
413 | mListener.add(listener);
414 | }
415 |
416 | public void removeListener(TorrentListener listener) {
417 | if(listener != null)
418 | mListener.remove(listener);
419 | }
420 |
421 | private DHTStatsAlertListener mDhtStatsAlertListener = new DHTStatsAlertListener() {
422 | @Override
423 | public void stats(int totalDhtNodes) {
424 | mDhtNodes = totalDhtNodes;
425 | }
426 | };
427 |
428 | private TorrentAddedAlertListener mTorrentAddedAlertListener = new TorrentAddedAlertListener() {
429 | @Override
430 | public void torrentAdded(TorrentAddedAlert alert) {
431 | InternalTorrentListener listener = new InternalTorrentListener();
432 | TorrentHandle th = mTorrentSession.findTorrent((alert).getHandle().getInfoHash());
433 | mCurrentTorrent = new Torrent(th, listener, mTorrentOptions.mPrepareSize);
434 | mTorrentSession.addListener(mCurrentTorrent);
435 | }
436 | };
437 |
438 | protected class InternalTorrentListener implements TorrentListener {
439 |
440 | public void onStreamStarted(final Torrent torrent) {
441 | for (final TorrentListener listener : mListener) {
442 | ThreadUtils.runOnUiThread(new Runnable() {
443 | @Override
444 | public void run() {
445 | listener.onStreamStarted(torrent);
446 | }
447 | });
448 | }
449 | }
450 |
451 | public void onStreamError(final Torrent torrent, final Exception e) {
452 | for (final TorrentListener listener : mListener) {
453 | ThreadUtils.runOnUiThread(new Runnable() {
454 | @Override
455 | public void run() {
456 | listener.onStreamError(torrent, e);
457 | }
458 | });
459 | }
460 | }
461 |
462 | public void onStreamReady(final Torrent torrent) {
463 | for (final TorrentListener listener : mListener) {
464 | ThreadUtils.runOnUiThread(new Runnable() {
465 | @Override
466 | public void run() {
467 | listener.onStreamReady(torrent);
468 | }
469 | });
470 | }
471 | }
472 |
473 | public void onStreamProgress(final Torrent torrent, final StreamStatus status) {
474 | for (final TorrentListener listener : mListener) {
475 | ThreadUtils.runOnUiThread(new Runnable() {
476 | @Override
477 | public void run() {
478 | listener.onStreamProgress(torrent, status);
479 | }
480 | });
481 | }
482 | }
483 |
484 | @Override
485 | public void onStreamStopped() {
486 | // Not used
487 | }
488 |
489 | @Override
490 | public void onStreamPrepared(final Torrent torrent) {
491 | for (final TorrentListener listener : mListener) {
492 | ThreadUtils.runOnUiThread(new Runnable() {
493 | @Override
494 | public void run() {
495 | listener.onStreamPrepared(torrent);
496 | }
497 | });
498 | }
499 | }
500 | }
501 |
502 | }
503 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/exceptions/DirectoryCreationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package com.github.sv244.torrentstream.exceptions;
21 |
22 | public class DirectoryCreationException extends Exception {
23 |
24 | public DirectoryCreationException() {
25 | super("Could not create save directory");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/exceptions/NotInitializedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of TorrentStreamer-Android.
3 | *
4 | * TorrentStreamer-Android is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * TorrentStreamer-Android is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with TorrentStreamer-Android. If not, see .
16 | */
17 |
18 | package com.github.sv244.torrentstream.exceptions;
19 |
20 | public class NotInitializedException extends Exception {
21 |
22 | public NotInitializedException() {
23 | super("TorrentStreamer is not initialized. Call init() first before getting an instance.");
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/exceptions/TorrentInfoException.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package com.github.sv244.torrentstream.exceptions;
21 |
22 | public class TorrentInfoException extends Exception {
23 |
24 | public TorrentInfoException() {
25 | super("No torrent info could be found");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/listeners/DHTStatsAlertListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package com.github.sv244.torrentstream.listeners;
21 |
22 | import com.frostwire.jlibtorrent.AlertListener;
23 | import com.frostwire.jlibtorrent.DHTRoutingBucket;
24 | import com.frostwire.jlibtorrent.alerts.Alert;
25 | import com.frostwire.jlibtorrent.alerts.AlertType;
26 | import com.frostwire.jlibtorrent.alerts.DhtStatsAlert;
27 |
28 | public abstract class DHTStatsAlertListener implements AlertListener {
29 | @Override
30 | public int[] types() {
31 | return new int[] { AlertType.DHT_STATS.getSwig() };
32 | }
33 |
34 | public void alert(Alert> alert) {
35 | if (alert instanceof DhtStatsAlert) {
36 | DhtStatsAlert dhtAlert = (DhtStatsAlert) alert;
37 | stats(countTotalDHTNodes(dhtAlert));
38 | }
39 | }
40 |
41 | public abstract void stats(int totalDhtNodes);
42 |
43 | private int countTotalDHTNodes(DhtStatsAlert alert) {
44 | final DHTRoutingBucket[] routingTable = alert.getRoutingTable();
45 |
46 | int totalNodes = 0;
47 | if (routingTable != null && routingTable.length > 0) {
48 | for (int i=0; i < routingTable.length; i++) {
49 | DHTRoutingBucket bucket = routingTable[i];
50 | totalNodes += bucket.numNodes();
51 | }
52 | }
53 |
54 | return totalNodes;
55 | }
56 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/listeners/TorrentAddedAlertListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package com.github.sv244.torrentstream.listeners;
21 |
22 | import com.frostwire.jlibtorrent.AlertListener;
23 | import com.frostwire.jlibtorrent.alerts.Alert;
24 | import com.frostwire.jlibtorrent.alerts.AlertType;
25 | import com.frostwire.jlibtorrent.alerts.TorrentAddedAlert;
26 |
27 | public abstract class TorrentAddedAlertListener implements AlertListener {
28 | @Override
29 | public int[] types() {
30 | return new int[] { AlertType.TORRENT_ADDED.getSwig() };
31 | }
32 |
33 | @Override
34 | public void alert(Alert> alert) {
35 | switch (alert.getType()) {
36 | case TORRENT_ADDED:
37 | torrentAdded((TorrentAddedAlert) alert);
38 | break;
39 | }
40 | }
41 |
42 | public abstract void torrentAdded(TorrentAddedAlert alert);
43 | }
44 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/listeners/TorrentListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of TorrentStreamer-Android.
3 | *
4 | * TorrentStreamer-Android is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * TorrentStreamer-Android is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with TorrentStreamer-Android. If not, see .
16 | */
17 |
18 | package com.github.sv244.torrentstream.listeners;
19 |
20 | import com.github.sv244.torrentstream.StreamStatus;
21 | import com.github.sv244.torrentstream.Torrent;
22 |
23 | public interface TorrentListener {
24 | void onStreamPrepared(Torrent torrent);
25 |
26 | void onStreamStarted(Torrent torrent);
27 |
28 | void onStreamError(Torrent torrent, Exception e);
29 |
30 | void onStreamReady(Torrent torrent);
31 |
32 | void onStreamProgress(Torrent torrent, StreamStatus status);
33 |
34 | void onStreamStopped();
35 | }
36 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package com.github.sv244.torrentstream.utils;
21 |
22 | import java.io.File;
23 |
24 | public class FileUtils {
25 |
26 | /**
27 | * Delete every item below the File location
28 | *
29 | * @param file Location
30 | */
31 | public static boolean recursiveDelete(File file) {
32 | if (file.isDirectory()) {
33 | String[] children = file.list();
34 | if (children == null) return false;
35 | for (String child : children) {
36 | recursiveDelete(new File(file, child));
37 | }
38 | }
39 |
40 | return file.delete();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/library/src/main/java/com/github/sv244/torrentstream/utils/ThreadUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package com.github.sv244.torrentstream.utils;
21 |
22 | import android.os.Handler;
23 | import android.os.Looper;
24 |
25 | public class ThreadUtils {
26 |
27 | /**
28 | * Execute the given {@link Runnable} on the ui thread.
29 | *
30 | * @param runnable The runnable to execute.
31 | */
32 | public static void runOnUiThread(Runnable runnable) {
33 | Thread uiThread = Looper.getMainLooper().getThread();
34 | if (Thread.currentThread() != uiThread) new Handler(Looper.getMainLooper()).post(runnable);
35 | else runnable.run();
36 | }
37 | }
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | apply plugin: 'com.android.application'
21 |
22 | android {
23 | compileSdkVersion 23
24 | buildToolsVersion "23.0.0"
25 |
26 | defaultConfig {
27 | applicationId "com.github.torrentstreamer.sample"
28 | minSdkVersion 15
29 | targetSdkVersion 23
30 | versionCode 1
31 | versionName "1.0"
32 | }
33 | buildTypes {
34 | release {
35 | minifyEnabled false
36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
37 | }
38 | }
39 | lintOptions {
40 | abortOnError false
41 | }
42 | }
43 |
44 | dependencies {
45 | compile fileTree(dir: 'libs', include: ['*.jar'])
46 | compile 'com.android.support:appcompat-v7:23.0.1'
47 | compile project(':library')
48 | }
49 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Sebastiaan/Development/Android/SDK/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/sample/src/main/java/eu/sv244/torrentstreamer/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | package eu.sv244.torrentstreamer.sample;
21 |
22 | import android.content.Intent;
23 | import android.net.Uri;
24 | import android.os.Bundle;
25 | import android.os.Environment;
26 | import android.support.v7.app.AppCompatActivity;
27 | import android.util.Log;
28 | import android.view.View;
29 | import android.widget.Button;
30 | import android.widget.ProgressBar;
31 |
32 | import com.github.sv244.torrentstream.StreamStatus;
33 | import com.github.sv244.torrentstream.Torrent;
34 | import com.github.sv244.torrentstream.TorrentOptions;
35 | import com.github.sv244.torrentstream.TorrentStream;
36 | import com.github.sv244.torrentstream.listeners.TorrentListener;
37 |
38 | import java.io.UnsupportedEncodingException;
39 | import java.net.URLDecoder;
40 |
41 | public class MainActivity extends AppCompatActivity implements TorrentListener {
42 |
43 | private Button mButton;
44 | private ProgressBar mProgressBar;
45 | private TorrentStream mTorrentStream;
46 |
47 | private String mStreamUrl = "magnet:?xt=urn:btih:D60795899F8488E7E489BA642DEFBCE1B23C9DA0&dn=Kingsman%3A+The+Secret+Service+%282014%29+%5B720p%5D&tr=http%3A%2F%2Ftracker.yify-torrents.com%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=udp%3A%2F%2Ftracker.publicbt.org%3A80&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Fopen.demonii.com%3A1337&tr=udp%3A%2F%2Fp4p.arenabg.ch%3A1337&tr=udp%3A%2F%2Fp4p.arenabg.com%3A1337";
48 |
49 | @Override
50 | protected void onCreate(Bundle savedInstanceState) {
51 | super.onCreate(savedInstanceState);
52 | setContentView(R.layout.activity_main);
53 |
54 | String action = getIntent().getAction();
55 | Uri data = getIntent().getData();
56 | if (action != null && action.equals(Intent.ACTION_VIEW) && data != null) {
57 | try {
58 | mStreamUrl = URLDecoder.decode(data.toString(), "utf-8");
59 | } catch (UnsupportedEncodingException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 |
64 | TorrentOptions torrentOptions = new TorrentOptions();
65 | torrentOptions.setSaveLocation(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
66 | torrentOptions.setRemoveFilesAfterStop(true);
67 |
68 | mTorrentStream = TorrentStream.init(torrentOptions);
69 | mTorrentStream.addListener(this);
70 |
71 | mButton = (Button) findViewById(R.id.button);
72 | mButton.setOnClickListener(mOnClickListener);
73 | mProgressBar = (ProgressBar) findViewById(R.id.progress);
74 |
75 | mProgressBar.setMax(100);
76 | }
77 |
78 | View.OnClickListener mOnClickListener = new View.OnClickListener() {
79 | @Override
80 | public void onClick(View v) {
81 | mProgressBar.setProgress(0);
82 | if(mTorrentStream.isStreaming()) {
83 | mTorrentStream.stopStream();
84 | mButton.setText("Start stream");
85 | return;
86 | }
87 | //mTorrentStream.startStream("https://yts.to/torrent/download/D60795899F8488E7E489BA642DEFBCE1B23C9DA0.torrent");
88 | mTorrentStream.startStream(mStreamUrl); // Start Torrent Stream download to phone
89 | mButton.setText("Stop stream");
90 | }
91 | };
92 |
93 | @Override
94 | public void onStreamPrepared(Torrent torrent) {
95 | Log.d("Torrent", "OnStreamPrepared");
96 | torrent.startDownload();
97 | }
98 |
99 | @Override
100 | public void onStreamStarted(Torrent torrent) {
101 | Log.d("Torrent", "onStreamStarted");
102 | }
103 |
104 | @Override
105 | public void onStreamError(Torrent torrent, Exception e) {
106 | Log.d("Torrent", "onStreamError");
107 | mButton.setText("Start stream");
108 | }
109 |
110 | @Override
111 | public void onStreamReady(Torrent torrent) {
112 | mProgressBar.setProgress(100);
113 | Log.d("Torrent", "onStreamReady: " + torrent.getVideoFile());
114 |
115 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(torrent.getVideoFile().toString()));
116 | intent.setDataAndType(Uri.parse(torrent.getVideoFile().toString()), "video/mp4");
117 | startActivity(intent);
118 | }
119 |
120 | @Override
121 | public void onStreamProgress(Torrent torrent, StreamStatus status) {
122 | if(status.bufferProgress <= 100 && mProgressBar.getProgress() < 100 && mProgressBar.getProgress() != status.bufferProgress) {
123 | Log.d("Torrent", "Progress: " + status.bufferProgress);
124 | mProgressBar.setProgress(status.bufferProgress);
125 | }
126 | }
127 |
128 | @Override
129 | public void onStreamStopped() {
130 | Log.d("Torrent", "onStreamStopped");
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
27 |
28 |
34 |
35 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/sample/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
26 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidTorrent/TorrentStream-Android/b2e49cd2ab8078d8686e6cd68adcc4ca16fb2d9a/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidTorrent/TorrentStream-Android/b2e49cd2ab8078d8686e6cd68adcc4ca16fb2d9a/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidTorrent/TorrentStream-Android/b2e49cd2ab8078d8686e6cd68adcc4ca16fb2d9a/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidTorrent/TorrentStream-Android/b2e49cd2ab8078d8686e6cd68adcc4ca16fb2d9a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
24 | 64dp
25 |
26 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 | 16dp
23 | 16dp
24 |
25 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 | TorrentStreamer Sample
22 |
23 | Hello world!
24 | Settings
25 |
26 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * * This file is part of TorrentStreamer-Android.
4 | * *
5 | * * TorrentStreamer-Android is free software: you can redistribute it and/or modify
6 | * * it under the terms of the GNU General Public License as published by
7 | * * the Free Software Foundation, either version 3 of the License, or
8 | * * (at your option) any later version.
9 | * *
10 | * * TorrentStreamer-Android is distributed in the hope that it will be useful,
11 | * * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * * GNU General Public License for more details.
14 | * *
15 | * * You should have received a copy of the GNU General Public License
16 | * * along with TorrentStreamer-Android. If not, see .
17 | *
18 | */
19 |
20 | include ':library', ':sample'
21 |
--------------------------------------------------------------------------------