├── gradle.properties ├── fastlane └── metadata │ └── android │ ├── en-US │ ├── short_description.txt │ ├── images │ │ ├── icon.png │ │ ├── featureGraphic.png │ │ └── phoneScreenshots │ │ │ ├── 1.png │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ └── 8.jpg │ └── full_description.txt │ └── de │ └── full_description.txt ├── proguard-rules.pro ├── src ├── main │ ├── res │ │ ├── drawable │ │ │ ├── about.png │ │ │ ├── add.png │ │ │ ├── file.png │ │ │ ├── menu.png │ │ │ ├── move.png │ │ │ ├── pause.png │ │ │ ├── play.png │ │ │ ├── play2.png │ │ │ ├── proxy.png │ │ │ ├── rss.png │ │ │ ├── start.png │ │ │ ├── stop.png │ │ │ ├── trash.png │ │ │ ├── watch.png │ │ │ ├── banner.png │ │ │ ├── browse.png │ │ │ ├── expand.png │ │ │ ├── expand2.png │ │ │ ├── folder.png │ │ │ ├── remove.png │ │ │ ├── resume.png │ │ │ ├── storage.png │ │ │ ├── suspend.png │ │ │ ├── trash2.png │ │ │ ├── verify.png │ │ │ ├── add_file.png │ │ │ ├── add_link.png │ │ │ ├── collapse.png │ │ │ ├── collapse2.png │ │ │ ├── downloads.png │ │ │ ├── folder_up.png │ │ │ ├── rss_active.png │ │ │ ├── settings.png │ │ │ ├── about_active.png │ │ │ ├── proxy_active.png │ │ │ ├── watch_active.png │ │ │ ├── settings_active.png │ │ │ ├── downloads_active.png │ │ │ ├── separator.xml │ │ │ ├── highlight.xml │ │ │ ├── focusable.xml │ │ │ └── border.xml │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ ├── values │ │ │ ├── ids.xml │ │ │ ├── theme.xml │ │ │ ├── colors.xml │ │ │ └── attrs.xml │ │ ├── menu │ │ │ ├── select_file_menu.xml │ │ │ ├── torrent_menu.xml │ │ │ └── main_menu.xml │ │ └── layout │ │ │ ├── checkbox_view.xml │ │ │ ├── downloads.xml │ │ │ ├── rss.xml │ │ │ ├── watch_view.xml │ │ │ ├── about.xml │ │ │ ├── dir_view.xml │ │ │ ├── file_view.xml │ │ │ ├── select_file.xml │ │ │ ├── browse_view.xml │ │ │ ├── path_view.xml │ │ │ ├── torrent_view.xml │ │ │ ├── main.xml │ │ │ ├── download_torrent.xml │ │ │ ├── watch_dirs.xml │ │ │ └── proxy.xml │ ├── java │ │ └── com │ │ │ └── ap │ │ │ └── transmission │ │ │ └── btc │ │ │ ├── func │ │ │ ├── Supplier.java │ │ │ ├── Consumer.java │ │ │ ├── Function.java │ │ │ └── Promise.java │ │ │ ├── Localizable.java │ │ │ ├── torrent │ │ │ ├── TorrentItemContainer.java │ │ │ ├── TorrentItem.java │ │ │ ├── TorrentException.java │ │ │ ├── NoSuchTorrentException.java │ │ │ ├── DuplicateTorrentException.java │ │ │ ├── TorrentStat.java │ │ │ ├── MediaInfo.java │ │ │ └── TorrentDir.java │ │ │ ├── http │ │ │ ├── RequestHandler.java │ │ │ ├── HttpServer.java │ │ │ ├── Method.java │ │ │ ├── HttpVersion.java │ │ │ ├── Range.java │ │ │ ├── handlers │ │ │ │ ├── AssetHandler.java │ │ │ │ ├── StaticResourceHandler.java │ │ │ │ ├── upnp │ │ │ │ │ └── DescriptorHandler.java │ │ │ │ ├── SoapHandler.java │ │ │ │ └── HandlerBase.java │ │ │ └── Response.java │ │ │ ├── activities │ │ │ ├── ActivityResultHandler.java │ │ │ ├── ActivityBase.java │ │ │ └── OpenTorrentActivity.java │ │ │ ├── Baos.java │ │ │ ├── EncrMode.java │ │ │ ├── views │ │ │ ├── TabInfo.java │ │ │ ├── WatchView.java │ │ │ ├── CheckBoxView.java │ │ │ ├── WatchItemView.java │ │ │ ├── PageFragment.java │ │ │ ├── TorrentsList.java │ │ │ ├── BrowseView.java │ │ │ └── PathItem.java │ │ │ ├── CompletedFuture.java │ │ │ ├── NaturalOrderComparator.java │ │ │ ├── receivers │ │ │ ├── ConnectivityChangeReceiver.java │ │ │ └── BootOrUpdateReceiver.java │ │ │ ├── Scripts.java │ │ │ ├── PowerLock.java │ │ │ ├── BindingHelper.java │ │ │ └── Adapters.java │ ├── cpp │ │ ├── native_to_java.h │ │ ├── transmission-private.h │ │ ├── sem.cc │ │ ├── env.cc │ │ ├── stdredirect.cc │ │ ├── hash.cc │ │ ├── curl.cc │ │ ├── commons.h │ │ ├── commons.cc │ │ └── native_to_java.cc │ └── assets │ │ ├── scripts │ │ └── set_so_buf.sh │ │ └── upnp │ │ ├── ConnectionManagerScpd.xml │ │ └── ContentDirectoryScpd.xml ├── basic │ └── AndroidManifest.xml └── test │ └── java │ └── com │ └── ap │ └── transmission │ └── btc │ └── MiscTest.java ├── .gitignore ├── local.properties ├── cmake ├── cURL.cmake ├── Event.cmake ├── Transmission.cmake └── OpenSSL.cmake ├── README.md └── CMakeLists.txt /gradle.properties: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | Transmission BitTorrent Client -------------------------------------------------------------------------------- /proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes LineNumberTable,SourceFile 2 | -keep class com.ap.** { *; } 3 | -dontwarn com.ap.** 4 | -------------------------------------------------------------------------------- /src/main/res/drawable/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/about.png -------------------------------------------------------------------------------- /src/main/res/drawable/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/add.png -------------------------------------------------------------------------------- /src/main/res/drawable/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/file.png -------------------------------------------------------------------------------- /src/main/res/drawable/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/menu.png -------------------------------------------------------------------------------- /src/main/res/drawable/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/move.png -------------------------------------------------------------------------------- /src/main/res/drawable/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/pause.png -------------------------------------------------------------------------------- /src/main/res/drawable/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/play.png -------------------------------------------------------------------------------- /src/main/res/drawable/play2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/play2.png -------------------------------------------------------------------------------- /src/main/res/drawable/proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/proxy.png -------------------------------------------------------------------------------- /src/main/res/drawable/rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/rss.png -------------------------------------------------------------------------------- /src/main/res/drawable/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/start.png -------------------------------------------------------------------------------- /src/main/res/drawable/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/stop.png -------------------------------------------------------------------------------- /src/main/res/drawable/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/trash.png -------------------------------------------------------------------------------- /src/main/res/drawable/watch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/watch.png -------------------------------------------------------------------------------- /src/main/res/drawable/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/banner.png -------------------------------------------------------------------------------- /src/main/res/drawable/browse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/browse.png -------------------------------------------------------------------------------- /src/main/res/drawable/expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/expand.png -------------------------------------------------------------------------------- /src/main/res/drawable/expand2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/expand2.png -------------------------------------------------------------------------------- /src/main/res/drawable/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/folder.png -------------------------------------------------------------------------------- /src/main/res/drawable/remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/remove.png -------------------------------------------------------------------------------- /src/main/res/drawable/resume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/resume.png -------------------------------------------------------------------------------- /src/main/res/drawable/storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/storage.png -------------------------------------------------------------------------------- /src/main/res/drawable/suspend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/suspend.png -------------------------------------------------------------------------------- /src/main/res/drawable/trash2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/trash2.png -------------------------------------------------------------------------------- /src/main/res/drawable/verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/verify.png -------------------------------------------------------------------------------- /src/main/res/drawable/add_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/add_file.png -------------------------------------------------------------------------------- /src/main/res/drawable/add_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/add_link.png -------------------------------------------------------------------------------- /src/main/res/drawable/collapse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/collapse.png -------------------------------------------------------------------------------- /src/main/res/drawable/collapse2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/collapse2.png -------------------------------------------------------------------------------- /src/main/res/drawable/downloads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/downloads.png -------------------------------------------------------------------------------- /src/main/res/drawable/folder_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/folder_up.png -------------------------------------------------------------------------------- /src/main/res/drawable/rss_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/rss_active.png -------------------------------------------------------------------------------- /src/main/res/drawable/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/settings.png -------------------------------------------------------------------------------- /src/main/res/drawable/about_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/about_active.png -------------------------------------------------------------------------------- /src/main/res/drawable/proxy_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/proxy_active.png -------------------------------------------------------------------------------- /src/main/res/drawable/watch_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/watch_active.png -------------------------------------------------------------------------------- /src/main/res/drawable/settings_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/settings_active.png -------------------------------------------------------------------------------- /src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/drawable/downloads_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/drawable/downloads_active.png -------------------------------------------------------------------------------- /src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/icon.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/featureGraphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/featureGraphic.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/5.jpg -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyPavlenko/transmissionbtc/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/8.jpg -------------------------------------------------------------------------------- /src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/res/drawable/separator.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/func/Supplier.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.func; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public interface Supplier { 7 | T get(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/Localizable.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public interface Localizable { 7 | int getResourceId(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/func/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.func; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public interface Consumer { 7 | void accept(T t); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/func/Function.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.func; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public interface Function { 7 | R apply(T t); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/res/drawable/highlight.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .externalNativeBuild/ 2 | .gradle/ 3 | .idea/ 4 | .cxx/ 5 | .settings/ 6 | .project 7 | .classpath 8 | build/ 9 | dist/ 10 | *.iml 11 | gradle/ 12 | gradlew 13 | gradlew.bat 14 | local.properties 15 | -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | ndk.dir=$ANDROID_NDK_ROOT 2 | sdk.dir=$ANDROID_SDK_ROOT 3 | depends=$ANDROID_BUILD_ROOT/install 4 | kestorePath=$HOME/.java/my-keystore.ks 5 | kestorePassword=123456 6 | kestoreAlias=my-keystore 7 | kestoreKeyPassword=123456 8 | -------------------------------------------------------------------------------- /src/main/res/values/theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /src/main/res/menu/select_file_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/torrent/TorrentItemContainer.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.torrent; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Andrey Pavlenko 7 | */ 8 | public interface TorrentItemContainer extends TorrentItem { 9 | List ls(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/http/RequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.http; 2 | 3 | import java.net.Socket; 4 | 5 | /** 6 | * @author Andrey Pavlenko 7 | */ 8 | public interface RequestHandler { 9 | void handle(HttpServer server, Request req, Socket socket) throws Throwable; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/res/drawable/focusable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/activities/ActivityResultHandler.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.activities; 2 | 3 | import android.content.Intent; 4 | 5 | /** 6 | * @author Andrey Pavlenko 7 | */ 8 | public interface ActivityResultHandler { 9 | boolean onActivityResult(int requestCode, int resultCode, Intent data); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/res/drawable/border.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/torrent/TorrentItem.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.torrent; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public interface TorrentItem { 7 | 8 | String getId(); 9 | 10 | String getName(); 11 | 12 | boolean isComplete(); 13 | 14 | boolean isDnd(); 15 | 16 | TorrentItemContainer getParent(); 17 | 18 | TorrentFs getFs(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/cpp/native_to_java.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andrey on 5/28/18. 3 | // 4 | 5 | #ifndef TRANSMISSIONBTC_NATIVE_TO_JAVA_H 6 | #define TRANSMISSIONBTC_NATIVE_TO_JAVA_H 7 | 8 | extern "C" { 9 | void callAddedOrChangedCallback(); 10 | 11 | void callStoppedCallback(); 12 | 13 | void callSessionChangedCallback(); 14 | 15 | void callScheduledAltSpeedCallback(); 16 | 17 | } // extern "C" 18 | #endif //TRANSMISSIONBTC_NATIVE_TO_JAVA_H 19 | -------------------------------------------------------------------------------- /src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffcd2626 4 | #c0f7ff 5 | #dcf7fa 6 | #dfdcdc 7 | #fabe00 8 | #009688 9 | #000000 10 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/torrent/TorrentException.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.torrent; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | @SuppressWarnings("unused") 7 | public class TorrentException extends Exception { 8 | public TorrentException() {} 9 | public TorrentException(String msg) {super(msg);} 10 | public TorrentException(Throwable ex) {super(ex);} 11 | public TorrentException(String msg, Throwable ex) {super(msg, ex);} 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/Baos.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.nio.ByteBuffer; 5 | 6 | /** 7 | * @author Andrey Pavlenko 8 | */ 9 | public class Baos extends ByteArrayOutputStream { 10 | 11 | public Baos(int size) { super(size); } 12 | 13 | public byte[] buf() { 14 | return buf; 15 | } 16 | 17 | public ByteBuffer byteBuf() { 18 | return ByteBuffer.wrap(buf(), 0, size()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/assets/scripts/set_so_buf.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | R=4194304 4 | W=1048576 5 | 6 | RMAX=$(cat /proc/sys/net/core/rmem_max) 7 | WMAX=$(cat /proc/sys/net/core/wmem_max) 8 | 9 | [ $RMAX -lt $R ] && echo $R > /proc/sys/net/core/rmem_max 10 | [ $WMAX -lt $W ] && echo $W > /proc/sys/net/core/wmem_max 11 | 12 | RMAX=$(cat /proc/sys/net/core/rmem_max) 13 | WMAX=$(cat /proc/sys/net/core/wmem_max) 14 | 15 | if [ $RMAX -lt $R ] || [ $WMAX -lt $W ]; then 16 | exit 2 17 | else 18 | exit 0 19 | fi 20 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/torrent/NoSuchTorrentException.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.torrent; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | @SuppressWarnings("unused") 7 | public class NoSuchTorrentException extends TorrentException { 8 | public NoSuchTorrentException() {} 9 | public NoSuchTorrentException(String msg) {super(msg);} 10 | public NoSuchTorrentException(Throwable ex) {super(ex);} 11 | public NoSuchTorrentException(String msg, Throwable ex) {super(msg, ex);} 12 | } 13 | -------------------------------------------------------------------------------- /src/main/cpp/transmission-private.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSMISSION_PRIVATE_H 2 | #define TRANSMISSION_PRIVATE_H 3 | #define __TRANSMISSION__ 4 | 5 | #ifndef NDEBUG 6 | #define NDEBUG 7 | #include 8 | #undef NDEBUG 9 | #else 10 | #include 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #endif -------------------------------------------------------------------------------- /src/basic/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/torrent/DuplicateTorrentException.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.torrent; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | @SuppressWarnings("unused") 7 | public class DuplicateTorrentException extends TorrentException { 8 | public DuplicateTorrentException() {} 9 | public DuplicateTorrentException(String msg) {super(msg);} 10 | public DuplicateTorrentException(Throwable ex) {super(ex);} 11 | public DuplicateTorrentException(String msg, Throwable ex) {super(msg, ex);} 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/func/Promise.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.func; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public interface Promise { 7 | T get() throws Throwable; 8 | 9 | void cancel(); 10 | 11 | @SuppressWarnings("unused") 12 | class Completed implements Promise { 13 | private final T result; 14 | 15 | public Completed(T result) {this.result = result;} 16 | 17 | @Override 18 | public T get() { 19 | return result; 20 | } 21 | 22 | @Override 23 | public void cancel() { } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/http/HttpServer.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.http; 2 | 3 | import com.ap.transmission.btc.torrent.Transmission; 4 | 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | 8 | /** 9 | * @author Andrey Pavlenko 10 | */ 11 | public interface HttpServer extends Closeable { 12 | 13 | void start() throws IOException; 14 | 15 | void stop(); 16 | 17 | boolean isRunning(); 18 | 19 | Transmission getTransmission(); 20 | 21 | int getPort(); 22 | 23 | String getHostName(); 24 | 25 | String getAddress(); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/http/Method.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.http; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * @author Andrey Pavlenko 7 | */ 8 | public enum Method { 9 | GET, POST, HEAD; // Supported methods 10 | 11 | public static Method fromString(String s) { 12 | switch (s) { 13 | case "GET": 14 | return GET; 15 | case "POST": 16 | return POST; 17 | case "HEAD": 18 | return HEAD; 19 | default: 20 | Log.w(Method.class.getName(), "Unsupported method: " + s); 21 | return null; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/EncrMode.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public enum EncrMode implements Localizable { 7 | Allow(R.string.encr_mode_allow), 8 | Prefer(R.string.encr_mode_prefer), 9 | Require(R.string.encr_mode_require); 10 | private static EncrMode[] values = values(); 11 | private final int resId; 12 | 13 | private EncrMode(int resId) {this.resId = resId;} 14 | 15 | public static EncrMode get(int ordinal) { 16 | return values[ordinal]; 17 | } 18 | 19 | @Override 20 | public int getResourceId() { 21 | return resId; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/http/HttpVersion.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.http; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * @author Andrey Pavlenko 7 | */ 8 | public enum HttpVersion { 9 | HTTP_1_0, HTTP_1_1; // Supported versions 10 | 11 | public static HttpVersion fromString(String s) { 12 | switch (s) { 13 | case "HTTP/1.0": 14 | return HTTP_1_0; 15 | case "HTTP/1.1": 16 | return HTTP_1_1; 17 | default: 18 | Log.w(HttpVersion.class.getName(), "Unsupported HTTP version: " + s); 19 | return null; 20 | } 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "HTTP/" + name().substring(5).replace('_', '.'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/views/TabInfo.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.views; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public class TabInfo { 7 | private final int title; 8 | private final int icon; 9 | private final int activeIcon; 10 | private final int layout; 11 | 12 | 13 | public TabInfo(int title, int icon, int activeIcon, int layout) { 14 | this.title = title; 15 | this.icon = icon; 16 | this.activeIcon = activeIcon; 17 | this.layout = layout; 18 | } 19 | 20 | public int getTitle() { 21 | return title; 22 | } 23 | 24 | public int getIcon() { 25 | return icon; 26 | } 27 | 28 | public int getActiveIcon() { 29 | return activeIcon; 30 | } 31 | 32 | public int getLayout() { 33 | return layout; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/res/layout/checkbox_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /src/main/cpp/sem.cc: -------------------------------------------------------------------------------- 1 | #include "commons.h" 2 | #include 3 | #include 4 | 5 | extern "C" { 6 | 7 | JNIEXPORT jlong 8 | JNICALL 9 | Java_com_ap_transmission_btc_Native_semCreate(JNIEnv *__unused env, jclass __unused c) { 10 | sem_t *sem = (sem_t *) malloc(sizeof(sem_t)); 11 | memset(sem, 0, sizeof(sem_t)); 12 | sem_init(sem, 0, 0); 13 | return (jlong) 14 | sem; 15 | } 16 | 17 | JNIEXPORT void JNICALL 18 | Java_com_ap_transmission_btc_Native_semDestroy(JNIEnv * __unused env, jclass 19 | __unused c, 20 | jlong 21 | jsem ) { 22 | sem_t *sem = (sem_t *) jsem; 23 | sem_destroy(sem); 24 | free(sem); 25 | } 26 | 27 | JNIEXPORT void JNICALL 28 | Java_com_ap_transmission_btc_Native_semPost(JNIEnv 29 | * 30 | __unused env, jclass 31 | __unused c, 32 | jlong 33 | jsem) { 34 | sem_t *sem = (sem_t *) jsem; 35 | sem_post(sem); 36 | } 37 | 38 | } // extern "C" -------------------------------------------------------------------------------- /src/main/res/layout/downloads.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 17 | 18 | 19 | 22 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/cpp/env.cc: -------------------------------------------------------------------------------- 1 | #include "commons.h" 2 | #include 3 | 4 | extern "C" { 5 | JNIEXPORT void JNICALL 6 | Java_com_ap_transmission_btc_Native_envUnset( 7 | JNIEnv *env, jclass __unused c, jstring jname) { 8 | const char *name = env->GetStringUTFChars(jname, 0); 9 | unsetenv(name); 10 | env->ReleaseStringUTFChars(jname, name); 11 | } 12 | 13 | JNIEXPORT void JNICALL 14 | Java_com_ap_transmission_btc_Native_envSet( 15 | JNIEnv *env, jclass __unused c, jstring jname, jstring jvalue) { 16 | if ((jvalue == NULL) || (env->GetStringUTFLength(jvalue) == 0)) { 17 | Java_com_ap_transmission_btc_Native_envUnset(env, c, jname); 18 | } else { 19 | const char *name = env->GetStringUTFChars(jname, 0); 20 | const char *value = env->GetStringUTFChars(jvalue, 0); 21 | setenv(name, value, 1); 22 | env->ReleaseStringUTFChars(jname, name); 23 | env->ReleaseStringUTFChars(jvalue, value); 24 | } 25 | } 26 | } // extern "C" -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/CompletedFuture.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.util.concurrent.Future; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * @author Andrey Pavlenko 10 | */ 11 | public class CompletedFuture implements Future { 12 | public static final CompletedFuture VOID = new CompletedFuture<>(null); 13 | private final T result; 14 | 15 | public CompletedFuture(T result) {this.result = result;} 16 | 17 | @Override 18 | public boolean cancel(boolean mayInterruptIfRunning) { 19 | return false; 20 | } 21 | 22 | @Override 23 | public boolean isCancelled() { 24 | return false; 25 | } 26 | 27 | @Override 28 | public boolean isDone() { 29 | return true; 30 | } 31 | 32 | @Override 33 | public T get() { 34 | return result; 35 | } 36 | 37 | @Override 38 | public T get(long timeout, @NonNull TimeUnit unit) { 39 | return result; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/views/WatchView.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.views; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.GridLayout; 6 | 7 | import com.ap.transmission.btc.Prefs; 8 | 9 | /** 10 | * @author Andrey Pavlenko 11 | */ 12 | public class WatchView extends GridLayout { 13 | 14 | public WatchView(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | setColumnCount(1); 17 | } 18 | 19 | public void setPrefs(Prefs prefs) { 20 | int max = prefs.getMaxIndex(Prefs.K.WATCH_DIR); 21 | 22 | if (getChildCount() == max) { 23 | for (int i = 0; i < max; i++) { 24 | WatchItemView wi = (WatchItemView) getChildAt(i); 25 | wi.update(prefs); 26 | } 27 | } else { 28 | removeAllViews(); 29 | 30 | for (int i = 0; i < max; i++) { 31 | WatchItemView wi = new WatchItemView(getContext(), null); 32 | wi.setIndex(i); 33 | addView(wi); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/http/Range.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.http; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public class Range { 7 | long start; 8 | long end; 9 | 10 | public Range(long start, long end) { 11 | this.start = start; 12 | this.end = end; 13 | } 14 | 15 | public long getStart() { 16 | return start; 17 | } 18 | 19 | public long getEnd() { 20 | return end; 21 | } 22 | 23 | public void allign(long length) { 24 | if (start < 0) { 25 | start = -start; 26 | end = length - 1; 27 | } else if (end < 0) { 28 | start = 0; 29 | end = length + end - 1; 30 | } else if (end >= length) { 31 | end = length - 1; 32 | } 33 | } 34 | 35 | public boolean isSatisfiable(long length) { 36 | return (start < length) && (end < length) && (start <= end); 37 | } 38 | 39 | public long getLength() { 40 | return getEnd() - getStart() + 1; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | if (start < 0) { 46 | return -start + "-"; 47 | } else if (end < 0) { 48 | return -end + ""; 49 | } else { 50 | return start + "-" + end; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /cmake/cURL.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(ExternalProject) 3 | include(ProcessorCount) 4 | 5 | set(CURL_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}") 6 | set(CURL_CMAKE_ARGS -DBUILD_TESTING=false 7 | -DBUILD_SHARED_LIBS=false -DCURL_DISABLE_DICT=true -DCURL_DISABLE_DICT=true 8 | -DCURL_DISABLE_GOPHER=true -DCURL_DISABLE_IMAP=true -DCURL_DISABLE_POP3=true 9 | -DCURL_DISABLE_RTSP=true -DCURL_DISABLE_SMTP=true -DCURL_DISABLE_TELNET=true -DCURL_DISABLE_TFTP=true 10 | ${EXT_CMAKE_ARGS}) 11 | 12 | set(CURL_LIBRARIES "${CURL_INSTALL_DIR}${CMAKE_INSTALL_PREFIX}/lib/libcurl.a") 13 | set(CURL_INCLUDE_DIR "${CURL_INSTALL_DIR}${CMAKE_INSTALL_PREFIX}/include") 14 | 15 | ProcessorCount(NCPU) 16 | find_program(MAKE_EXE NAMES make gmake nmake) 17 | 18 | ExternalProject_Add(curl 19 | URL "https://curl.se/download/curl-7.78.0.tar.xz" 20 | PREFIX curl 21 | BUILD_IN_SOURCE 1 22 | CONFIGURE_COMMAND ${CMAKE_COMMAND} ${CURL_CMAKE_ARGS} 23 | BUILD_COMMAND ${MAKE_EXE} -j${NCPU} 24 | INSTALL_COMMAND ${MAKE_EXE} install DESTDIR=${CURL_INSTALL_DIR} 25 | BUILD_BYPRODUCTS ${CURL_LIBRARIES}) 26 | 27 | add_dependencies(curl openssl) 28 | add_dependencies(${PROJECT_NAME} curl) 29 | -------------------------------------------------------------------------------- /cmake/Event.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(ExternalProject) 3 | include(ProcessorCount) 4 | 5 | set(EVENT_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}") 6 | set(EVENT_CMAKE_ARGS -DEVENT__LIBRARY_TYPE=STATIC -DEVENT__DISABLE_BENCHMARK=true 7 | -DEVENT__DISABLE_TESTS=true -DEVENT__DISABLE_REGRESS=true -DEVENT__DISABLE_SAMPLES=true 8 | ${EXT_CMAKE_ARGS}) 9 | 10 | set(EVENT_LIBRARIES "${EVENT_INSTALL_DIR}${CMAKE_INSTALL_PREFIX}/lib/libevent.a") 11 | set(EVENT_INCLUDE_DIR "${EVENT_INSTALL_DIR}${CMAKE_INSTALL_PREFIX}/include") 12 | 13 | ProcessorCount(NCPU) 14 | find_program(MAKE_EXE NAMES make gmake nmake) 15 | 16 | ExternalProject_Add(libevent 17 | URL "https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz" 18 | PREFIX libevent 19 | BUILD_IN_SOURCE 1 20 | CONFIGURE_COMMAND ${CMAKE_COMMAND} ${EVENT_CMAKE_ARGS} 21 | PATCH_COMMAND ${CMAKE_COMMAND} -E touch cmake/Uninstall.cmake.in 22 | BUILD_COMMAND ${MAKE_EXE} -j${NCPU} 23 | INSTALL_COMMAND ${MAKE_EXE} install DESTDIR=${EVENT_INSTALL_DIR} 24 | BUILD_BYPRODUCTS ${EVENT_LIBRARIES}) 25 | 26 | add_dependencies(libevent openssl) 27 | add_dependencies(${PROJECT_NAME} libevent) 28 | -------------------------------------------------------------------------------- /src/main/res/layout/rss.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 18 | 19 | 20 | 25 | 26 | 30 | 31 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/cpp/stdredirect.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef NDEBUG 4 | JNIEXPORT void JNICALL 5 | Java_com_ap_transmission_btc_Native_stdRedirect(JNIEnv *__unused env, jclass __unused c) {} 6 | #else 7 | 8 | #include "commons.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | extern "C" { 15 | 16 | static int pfd[2]; 17 | static pthread_t thr; 18 | 19 | static void *thread_func(void *__unused args) { 20 | ssize_t rdsz; 21 | char buf[128]; 22 | while ((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) { 23 | if (buf[rdsz - 1] == '\n') --rdsz; 24 | buf[rdsz] = 0; 25 | __android_log_write(ANDROID_LOG_DEBUG, "libtransmission", buf); 26 | } 27 | return 0; 28 | } 29 | 30 | JNIEXPORT void JNICALL 31 | Java_com_ap_transmission_btc_Native_stdRedirect(JNIEnv *env, jclass __unused c) { 32 | setvbuf(stdout, 0, _IOLBF, 0); 33 | setvbuf(stderr, 0, _IONBF, 0); 34 | 35 | pipe(pfd); 36 | dup2(pfd[1], 1); 37 | dup2(pfd[1], 2); 38 | 39 | if (pthread_create(&thr, 0, thread_func, 0) == -1) { 40 | throwEX(env, "java/lang/RuntimeException", "pthread_create() failed"); 41 | } else { 42 | pthread_detach(thr); 43 | } 44 | 45 | CATCH:; 46 | } 47 | 48 | } // extern "C" 49 | #endif -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/activities/ActivityBase.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.activities; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | import com.ap.transmission.btc.Native; 8 | import com.ap.transmission.btc.Prefs; 9 | 10 | /** 11 | * @author Andrey Pavlenko 12 | */ 13 | public abstract class ActivityBase extends AppCompatActivity { 14 | private Prefs prefs; 15 | private ActivityResultHandler activityResultHandler; 16 | 17 | protected void onCreate(Bundle savedInstanceState) { 18 | Native.Init.init(getApplicationContext()); 19 | prefs = new Prefs(getApplicationContext()); 20 | super.onCreate(savedInstanceState); 21 | } 22 | 23 | public Prefs getPrefs() { 24 | return prefs; 25 | } 26 | 27 | public void setActivityResultHandler(ActivityResultHandler h) { 28 | activityResultHandler = h; 29 | } 30 | 31 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 32 | ActivityResultHandler h = activityResultHandler; 33 | 34 | if (h != null) { 35 | activityResultHandler = null; 36 | if (h.onActivityResult(requestCode, resultCode, data)) return; 37 | } 38 | 39 | super.onActivityResult(requestCode, resultCode, data); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/http/handlers/AssetHandler.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.http.handlers; 2 | 3 | import android.content.res.AssetManager; 4 | 5 | import com.ap.transmission.btc.http.HttpServer; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.net.Socket; 10 | 11 | /** 12 | * @author Andrey Pavlenko 13 | */ 14 | public class AssetHandler extends StaticResourceHandler { 15 | private final AssetManager amgr; 16 | private final String path; 17 | private final String contentType; 18 | private final String logTag; 19 | 20 | public AssetHandler(AssetManager amgr, String path, String contentType) { 21 | this.amgr = amgr; 22 | this.path = path; 23 | this.contentType = contentType; 24 | logTag = "File: " + path; 25 | } 26 | 27 | @Override 28 | protected Handler createHandler(HttpServer server, Socket socket) { 29 | return new Handler(server, socket); 30 | } 31 | 32 | private final class Handler extends StaticResourceHandler.Handler { 33 | 34 | protected Handler(HttpServer server, Socket socket) { 35 | super(logTag, server, socket); 36 | } 37 | 38 | @Override 39 | protected InputStream open() throws IOException { 40 | return amgr.open(path); 41 | } 42 | 43 | @Override 44 | protected String getContentType() { 45 | return contentType; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/res/menu/torrent_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/res/layout/watch_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 22 | 23 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/res/layout/about.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 22 | 23 | 24 | 29 | 30 | 34 | 35 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/torrent/TorrentStat.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.torrent; 2 | 3 | /** 4 | * @author Andrey Pavlenko 5 | */ 6 | public class TorrentStat { 7 | private long[] stat; 8 | private int offset; 9 | private String error; 10 | 11 | TorrentStat(long[] stat, int offset, String error) { 12 | this.stat = stat; 13 | this.offset = offset; 14 | this.error = error; 15 | } 16 | 17 | void update(long[] stat, int offset, String error) { 18 | this.stat = stat; 19 | this.offset = offset; 20 | this.error = error; 21 | } 22 | 23 | public Status getStatus() { 24 | return Status.values[(int) stat[offset + 1]]; 25 | } 26 | 27 | public int getProgress() { 28 | return (int) stat[offset + 2]; 29 | } 30 | 31 | public long getTotalLength() { 32 | return stat[offset + 3]; 33 | } 34 | 35 | public long getRemainingLength() { 36 | return stat[offset + 4]; 37 | } 38 | 39 | public long getUploadedLength() { 40 | return stat[offset + 5]; 41 | } 42 | 43 | public int getPeersUp() { 44 | return (int) stat[offset + 6]; 45 | } 46 | 47 | public int getPeersDown() { 48 | return (int) stat[offset + 7]; 49 | } 50 | 51 | public int getSpeedUp() { 52 | return (int) stat[offset + 8]; 53 | } 54 | 55 | public int getSpeedDown() { 56 | return (int) stat[offset + 9]; 57 | } 58 | 59 | public String getError() { 60 | return error; 61 | } 62 | 63 | public enum Status { 64 | STOPPED, CHECK, DOWNLOAD, SEED, ERROR; 65 | private static final Status[] values = values(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/NaturalOrderComparator.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc; 2 | 3 | import java.util.Comparator; 4 | 5 | import static java.lang.Character.isDigit; 6 | 7 | /** 8 | * @author Andrey Pavlenko 9 | */ 10 | public class NaturalOrderComparator implements Comparator { 11 | public int compare(String a, String b) { 12 | int alen = a.length(); 13 | int blen = b.length(); 14 | 15 | for (int aidx = 0, bidx = 0; ; ) { 16 | if (aidx == alen) return (bidx == blen) ? 0 : -1; 17 | if (bidx == blen) return 1; 18 | 19 | char ca = a.charAt(aidx); 20 | char cb = b.charAt(bidx); 21 | 22 | if (isDigit(ca) && isDigit(cb)) { 23 | int aoff = aidx; 24 | int boff = bidx; 25 | 26 | for (aidx++; (aidx < alen) && isDigit(a.charAt(aidx)); aidx++) ; 27 | for (bidx++; (bidx < blen) && isDigit(b.charAt(bidx)); bidx++) ; 28 | 29 | int nalen = aidx - aoff; 30 | int nblen = bidx - boff; 31 | 32 | if ((nalen != 1) || (nblen != 1)) { 33 | long na = Long.valueOf(a.substring(aoff, aidx)); 34 | long nb = Long.valueOf(b.substring(boff, bidx)); 35 | 36 | if (na == nb) { 37 | if (nalen != nblen) return (nalen < nblen) ? -1 : 1; 38 | } else if (na < nb) { 39 | return -1; 40 | } else { 41 | return 1; 42 | } 43 | } else if (ca != cb) { 44 | return (ca < cb) ? -1 : 1; 45 | } 46 | } else if (ca != cb) { 47 | return (ca < cb) ? -1 : 1; 48 | } else { 49 | aidx++; 50 | bidx++; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/receivers/ConnectivityChangeReceiver.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.receivers; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.IntentFilter; 7 | import android.net.ConnectivityManager; 8 | 9 | import com.ap.transmission.btc.Prefs; 10 | import com.ap.transmission.btc.Utils; 11 | import com.ap.transmission.btc.services.TransmissionService; 12 | import com.ap.transmission.btc.torrent.Transmission; 13 | 14 | /** 15 | * @author Andrey Pavlenko 16 | */ 17 | public class ConnectivityChangeReceiver extends BroadcastReceiver { 18 | private static ConnectivityChangeReceiver instance; 19 | 20 | public static synchronized void register(Context context) { 21 | if (instance != null) return; 22 | IntentFilter intentFilter = new IntentFilter(); 23 | intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 24 | context.registerReceiver(instance = new ConnectivityChangeReceiver(), intentFilter); 25 | } 26 | 27 | public static synchronized void unregister(Context context) { 28 | if (instance == null) return; 29 | context.unregisterReceiver(instance); 30 | instance = null; 31 | } 32 | 33 | @Override 34 | public void onReceive(Context context, Intent intent) { 35 | Utils.resetInterfaceAddress(); 36 | Transmission tr = TransmissionService.getTransmission(); 37 | if ((tr == null) || !tr.isRunning()) return; 38 | Prefs prefs = new Prefs(context); 39 | 40 | if (prefs.isWifiEthOnly() && !tr.isSuspendedByUser()) { 41 | tr.suspend(!Utils.isWifiEthActive(prefs.getContext(), prefs.getWifiSsid()), false, null); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 |

Transmission is a powerful yet extremely lightweight and fast BitTorrent client. It has the features you want from a BitTorrent client: encryption, a web interface, peer exchange, magnet links, DHT, µTP, UPnP and NAT-PMP port forwarding, webseed support, tracker editing, global and per-torrent speed limits, and more.

This application is a port of the Transmission daemon for Android with a few enhancements and additions. The daemon is running in background as an Android service. To communicate with the daemon you may either use the built-in WEB interface or any Transmission remote of choice.

For more information on the Transmission client please refer to the official site of the Transmission Project.


Features of the app:

  • Manage downloads directly from the application.
  • Multiple watch/download directories.
  • Support for HTTP(S)/SOCKS proxy.
  • WiFi/Ethernet mode to save on mobile data.
  • Allowed WiFi SSIDs - if configured, the service is running only if connected to the specified networks.
  • Keep CPU/WiFi awake to complete all downloads before the device goes to sleep.
  • Sequential download allows playing media files while downloading.
  • Open .torrent files or torrent/magnet URLs and stream the selected files to a media player.
  • Builtin UPnP MediaServer. Download media files to a phone/tablet/TV-box and watch on a TV or another UPnP compatible media player connected to the same network.
  • M3U playlists for all torrents/folders containing audio/video files. To get the playlist URL - long click on the play icon.
  • Alternative web interface - Transmission Web Control
-------------------------------------------------------------------------------- /src/main/cpp/hash.cc: -------------------------------------------------------------------------------- 1 | #include "commons.h" 2 | #include 3 | #include 4 | 5 | extern "C" { 6 | JNIEXPORT jint JNICALL 7 | Java_com_ap_transmission_btc_Native_hashLength(JNIEnv *__unused env, jclass __unused c) { 8 | return SHA_DIGEST_LENGTH; 9 | } 10 | 11 | JNIEXPORT jstring JNICALL 12 | Java_com_ap_transmission_btc_Native_hashBytesToString( 13 | JNIEnv *env, jclass __unused c, jbyteArray jhash) { 14 | char hash[SHA_DIGEST_LENGTH]; 15 | char hashString[1 + 2 * SHA_DIGEST_LENGTH]; 16 | env->GetByteArrayRegion(jhash, 0, sizeof(hash), (jbyte *) hash); 17 | tr_binary_to_hex(hash, hashString, sizeof(hash)); 18 | return env->NewStringUTF((const char *) hashString); 19 | } 20 | 21 | JNIEXPORT jbyteArray JNICALL 22 | Java_com_ap_transmission_btc_Native_hashStringToBytes( 23 | JNIEnv *env, jclass __unused c, jstring jhashString) { 24 | char hash[SHA_DIGEST_LENGTH]; 25 | const char *hashString = env->GetStringUTFChars(jhashString, 0); 26 | tr_hex_to_binary(hashString, hash, sizeof(hash)); 27 | env->ReleaseStringUTFChars(jhashString, hashString); 28 | jbyteArray jhash = env->NewByteArray(sizeof(hash)); 29 | env->SetByteArrayRegion(jhash, 0, sizeof(hash), (const jbyte *) hash); 30 | return jhash; 31 | } 32 | 33 | JNIEXPORT jbyteArray JNICALL 34 | Java_com_ap_transmission_btc_Native_hashGetTorrentHash( 35 | JNIEnv *env, jclass __unused c, jstring torrentPath) { 36 | { 37 | tr_info info; 38 | infoFromFileEx(env, 0, torrentPath, &info); 39 | jbyteArray jhash = env->NewByteArray(SHA_DIGEST_LENGTH); 40 | env->SetByteArrayRegion(jhash, 0, SHA_DIGEST_LENGTH, (const jbyte *) info.hash); 41 | tr_metainfoFree(&info); 42 | return jhash; 43 | } CATCH: 44 | return NULL; 45 | } 46 | } // extern "C" -------------------------------------------------------------------------------- /cmake/Transmission.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(ExternalProject) 3 | include(ProcessorCount) 4 | 5 | option(TR_SRC_DIR "Transmission sources" "${CMAKE_CURRENT_BINARY_DIR}/transmission/src") 6 | set(TR_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/transmission/src/transmission-build") 7 | set(TR_CMAKE_ARGS -DENABLE_TESTS=OFF -DENABLE_DAEMON=OFF -DINSTALL_DOC=OFF -DENABLE_UTILS=OFF 8 | -DENABLE_CLI=OFF -DENABLE_GTK=OFF -DENABLE_QT=OFF -DENABLE_MAC=OFF -DINSTALL_DOC=OFF 9 | -DENABLE_WEB=ON ${EXT_CMAKE_ARGS}) 10 | 11 | set(TR_LIBRARIES 12 | "${TR_BUILD_DIR}/libtransmission/libtransmission.a" 13 | "${TR_BUILD_DIR}/third-party/dht/lib/libdht.a" 14 | "${TR_BUILD_DIR}/third-party/arc4/src/libarc4.a" 15 | "${TR_BUILD_DIR}/third-party/b64/lib/libb64.a" 16 | "${TR_BUILD_DIR}/third-party/natpmp/lib/libnatpmp.a" 17 | "${TR_BUILD_DIR}/third-party/miniupnpc/lib/libminiupnpc.a" 18 | "${TR_BUILD_DIR}/third-party/utp/lib/libutp.a") 19 | 20 | set(TR_INCLUDE_DIR "${TR_SRC_DIR}" "${TR_BUILD_DIR}") 21 | 22 | ProcessorCount(NCPU) 23 | find_program(MAKE_EXE NAMES make gmake nmake) 24 | 25 | ExternalProject_Add(transmission 26 | GIT_REPOSITORY "https://github.com/AndreyPavlenko/transmission.git" 27 | GIT_TAG "transmissionbtc" 28 | SOURCE_DIR ${TR_SRC_DIR} 29 | PREFIX transmission 30 | GIT_SHALLOW 1 31 | GIT_PROGRESS 1 32 | GIT_SUBMODULES_RECURSE 1 33 | CONFIGURE_COMMAND ${CMAKE_COMMAND} ${TR_SRC_DIR} ${TR_CMAKE_ARGS} 34 | BUILD_COMMAND ${MAKE_EXE} -j${NCPU} 35 | INSTALL_COMMAND ${MAKE_EXE} install "DESTDIR=${TR_WEB_INSTALL_DIR}" 36 | BUILD_BYPRODUCTS ${TR_LIBRARIES}) 37 | 38 | add_dependencies(transmission openssl curl libevent) 39 | add_dependencies(${PROJECT_NAME} transmission) 40 | -------------------------------------------------------------------------------- /src/main/res/menu/main_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/cpp/curl.cc: -------------------------------------------------------------------------------- 1 | #include "commons.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern "C" { 9 | JNIEXPORT void JNICALL 10 | Java_com_ap_transmission_btc_Native_curl(JNIEnv *env, jclass __unused c, 11 | jstring jurl, jstring jdst, jint timeout) { 12 | const char *dst = env->GetStringUTFChars(jdst, 0); 13 | FILE *file = fopen(dst, "wb"); 14 | 15 | { 16 | if (file == NULL) { 17 | throwEX(env, CLASS_IOEX, "Failed to open file %s: %s", dst, strerror(errno)); 18 | } 19 | 20 | CURL *curl = curl_easy_init(); 21 | 22 | if (curl) { 23 | char err[CURL_ERROR_SIZE]; 24 | const char *url = env->GetStringUTFChars(jurl, 0); 25 | curl_easy_setopt(curl, CURLOPT_URL, url); 26 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err); 27 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); 28 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); 29 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 30 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 31 | curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L); 32 | curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L); 33 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "Transmission/" SHORT_VERSION_STRING); 34 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); 35 | 36 | #ifndef NDEBUG 37 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); 38 | #endif 39 | 40 | CURLcode res = curl_easy_perform(curl); 41 | env->ReleaseStringUTFChars(jurl, url); 42 | curl_easy_cleanup(curl); 43 | 44 | if (res != CURLE_OK) { 45 | throwEX(env, CLASS_IOEX, err); 46 | } 47 | } else { 48 | throwEX(env, CLASS_IOEX, "Failed to initialize curl"); 49 | } 50 | 51 | } CATCH: 52 | env->ReleaseStringUTFChars(jdst, dst); 53 | if (file != NULL) fclose(file); 54 | } 55 | } //extern "C" -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/receivers/BootOrUpdateReceiver.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.receivers; 2 | 3 | import static android.content.Intent.ACTION_BOOT_COMPLETED; 4 | import static android.content.Intent.ACTION_MY_PACKAGE_REPLACED; 5 | import static com.ap.transmission.btc.Utils.err; 6 | import static com.ap.transmission.btc.services.TransmissionService.start; 7 | 8 | import android.content.BroadcastReceiver; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | import android.os.Handler; 12 | import android.util.Log; 13 | 14 | import com.ap.transmission.btc.Prefs; 15 | 16 | /** 17 | * @author Andrey Pavlenko 18 | */ 19 | public class BootOrUpdateReceiver extends BroadcastReceiver { 20 | 21 | @Override 22 | public void onReceive(Context ctx, Intent intent) { 23 | String a = intent.getAction(); 24 | Prefs p = new Prefs(ctx.getApplicationContext()); 25 | onReceive(ctx, a, p); 26 | } 27 | 28 | private void onReceive(Context ctx, String a, Prefs p) { 29 | try { 30 | handle(ctx, a, p); 31 | } catch (IllegalStateException ex) { 32 | err(getClass().getName(), ex, "Failed to handle action %s - retrying in 10 seconds", a); 33 | new Handler(ctx.getMainLooper()).postDelayed(() -> onReceive(ctx, a, p), 10000L); 34 | } 35 | } 36 | 37 | private static void handle(Context context, String a, Prefs p) { 38 | if (ACTION_BOOT_COMPLETED.equals(a)) { 39 | if (!p.isStartOnBoot()) return; 40 | int delay = p.getBootDelay(); 41 | 42 | if (delay > 0) { 43 | Log.i(BootOrUpdateReceiver.class.getName(), "Waiting " + delay + " seconds before start"); 44 | new Handler(context.getMainLooper()).postDelayed(() -> start(context, null), delay * 1000L); 45 | } else { 46 | start(context, null); 47 | } 48 | } else if (ACTION_MY_PACKAGE_REPLACED.equals(a)) { 49 | if (p.isStartOnBoot()) start(context, null); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/views/CheckBoxView.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc.views; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.support.annotation.Nullable; 6 | import android.util.AttributeSet; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.CheckBox; 10 | import android.widget.GridLayout; 11 | import android.widget.TextView; 12 | 13 | import com.ap.transmission.btc.Adapters; 14 | import com.ap.transmission.btc.Prefs; 15 | import com.ap.transmission.btc.R; 16 | 17 | /** 18 | * @author Andrey Pavlenko 19 | */ 20 | public class CheckBoxView extends GridLayout { 21 | private OnClickListener clickListener; 22 | 23 | public CheckBoxView(Context context, AttributeSet attrs) { 24 | super(context, attrs); 25 | setColumnCount(2); 26 | 27 | LayoutInflater i = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 28 | if (i == null) throw new RuntimeException("Inflater is null"); 29 | i.inflate(R.layout.checkbox_view, this, true); 30 | 31 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckBoxView, 0, 0); 32 | String text = a.getString(R.styleable.CheckBoxView_text); 33 | a.recycle(); 34 | getText().setText(text); 35 | setClickable(true); 36 | 37 | super.setOnClickListener(new OnClickListener() { 38 | @Override 39 | public void onClick(View v) { 40 | getCheckBox().performClick(); 41 | if (clickListener != null) clickListener.onClick(getCheckBox()); 42 | } 43 | }); 44 | } 45 | 46 | public TextView getText() { 47 | return (TextView) getChildAt(0); 48 | } 49 | 50 | public CheckBox getCheckBox() { 51 | return (CheckBox) getChildAt(1); 52 | } 53 | 54 | public void setPref(Prefs.K pref) { 55 | Adapters.checkBoxPropAdapter(getCheckBox(), pref); 56 | } 57 | 58 | public void setOnClick(@Nullable OnClickListener l) { 59 | clickListener = l; 60 | if (l != null) l.onClick(getCheckBox()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/Scripts.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static com.ap.transmission.btc.Utils.copyAssets; 11 | 12 | /** 13 | * @author Andrey Pavlenko 14 | */ 15 | @SuppressWarnings("unused") 16 | public class Scripts { 17 | private final File scriptsDir; 18 | private static volatile Scripts instance; 19 | 20 | private Scripts(Context ctx) throws IOException { 21 | if (Utils.exec(15000, null, "su", "-c", "ls") != 0) { 22 | throw new IOException("Root privileges not granted"); 23 | } 24 | 25 | File dataDir = new File(ctx.getApplicationInfo().dataDir); 26 | scriptsDir = new File(dataDir, "scripts"); 27 | copyAssets(ctx.getAssets(), "scripts", dataDir); 28 | 29 | int status = Utils.exec(3000, null, "su", "-c", 30 | "chmod 777 '" + scriptsDir.getAbsolutePath() + "'/*"); 31 | if (status != 0) { 32 | throw new IOException("Command failed: su -c chmod 777 '" + 33 | scriptsDir.getAbsolutePath() + "'/*"); 34 | } 35 | } 36 | 37 | public static Scripts getInstance(Context ctx) throws IOException { 38 | Scripts i = instance; 39 | 40 | if (i == null) { 41 | synchronized (Scripts.class) { 42 | if ((i = instance) == null) { 43 | instance = i = new Scripts(ctx); 44 | } 45 | } 46 | } 47 | 48 | return i; 49 | } 50 | 51 | public int execScript(Script script, String... args) throws IOException { 52 | File f = new File(scriptsDir, script.toString() + ".sh"); 53 | List cmd = new ArrayList<>(3); 54 | StringBuilder scriptCmd = new StringBuilder(100); 55 | 56 | scriptCmd.append('\'').append(f.getAbsolutePath()).append('\''); 57 | for (String a : args) scriptCmd.append(' ').append(a); 58 | 59 | cmd.add("su"); 60 | cmd.add("-c"); 61 | cmd.add(scriptCmd.toString()); 62 | return Utils.exec(3000, null, cmd); 63 | } 64 | 65 | public enum Script { 66 | set_so_buf, create_dir, create_file 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /fastlane/metadata/android/de/full_description.txt: -------------------------------------------------------------------------------- 1 |

Transmission ist ein leistungsstarker und dennoch extrem leichter und schneller BitTorrent-Client. Es bietet die Funktionen, die Sie von einem BitTorrent-Client erwarten: Verschlüsselung, Webschnittstelle, Peer-Exchange, Magnetlinks, DHT, µTP, UPnP und NAT-PMP-Portweiterleitung, Webseed-Unterstützung, Tracker-Bearbeitung, Geschwindigkeitsbegrenzungen für globale und pro Torrent und mehr.

Diese App ist ein Port des Transmission-Daemons für Android, der folgende Funktionen enthält:

  • Verwalten Sie Downloads direkt aus der Anwendung.
  • Mehrere Watch- / Download-Verzeichnisse.
  • Unterstützung für HTTP (S) / SOCKS-Proxy.
  • WiFi / Ethernet-Modus zum Speichern mobiler Daten.
  • Zugelassene WLAN-SSIDs: Wenn konfiguriert, wird der Dienst nur ausgeführt, wenn er mit den angegebenen Netzwerken verbunden ist.
  • Behalten Sie die CPU / WLAN-Verbindung bei, um alle Downloads abzuschließen, bevor das Gerät in den Ruhezustand wechselt.
  • Sequentieller Download ermöglicht das Abspielen von Mediendateien während des Herunterladens.
  • Öffnen Sie Torrent-Dateien oder Torrent- / Magnet-URLs und streamen Sie die ausgewählten Dateien auf einen Media Player.
  • Integrierter UPnP MediaServer. Laden Sie Mediendateien auf ein Telefon / Tablet / TV-Box herunter und sehen Sie sich auf einem Fernsehgerät oder einem anderen UPnP-kompatiblen Mediaplayer an, der mit demselben Netzwerk verbunden ist.
  • M3U-Wiedergabelisten für alle Torrents / Ordner, die Audio- / Videodateien enthalten. Um die Wiedergabelisten-URL abzurufen, klicken Sie lange auf das Wiedergabesymbol.
  • Alternative Weboberfläche - Transmission Web Control.

Der Daemon läuft als Hintergrunddienst. Für die Fernkommunikation mit dem Dämon können Sie entweder die integrierte WEB-Schnittstelle oder eine beliebige Transmission-Fernbedienung verwenden.

Weitere Informationen finden Sie auf der offiziellen Website des Transmission-Projekts: transmissionbt.com. -------------------------------------------------------------------------------- /src/main/java/com/ap/transmission/btc/PowerLock.java: -------------------------------------------------------------------------------- 1 | package com.ap.transmission.btc; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.net.wifi.WifiManager; 6 | import android.net.wifi.WifiManager.WifiLock; 7 | import android.os.PowerManager; 8 | import android.os.PowerManager.WakeLock; 9 | 10 | import static android.content.Context.POWER_SERVICE; 11 | import static android.content.Context.WIFI_SERVICE; 12 | import static android.net.wifi.WifiManager.WIFI_MODE_FULL; 13 | import static android.os.PowerManager.PARTIAL_WAKE_LOCK; 14 | import static com.ap.transmission.btc.Utils.debug; 15 | 16 | /** 17 | * @author Andrey Pavlenko 18 | */ 19 | public class PowerLock { 20 | private static final String TAG = "TransmissionLock"; 21 | private final WakeLock wakeLock; 22 | private final WifiLock wifiLock; 23 | 24 | private PowerLock(PowerManager.WakeLock wakeLock, WifiManager.WifiLock wifiLock) { 25 | this.wakeLock = wakeLock; 26 | this.wifiLock = wifiLock; 27 | } 28 | 29 | @SuppressLint("WakelockTimeout") 30 | public void acquire() { 31 | if (wakeLock != null) { 32 | debug(TAG, "Acquiring CPU lock"); 33 | wakeLock.acquire(); 34 | } 35 | if (wifiLock != null) { 36 | debug(TAG, "Acquiring WiFi lock"); 37 | wifiLock.acquire(); 38 | } 39 | } 40 | 41 | public void release() { 42 | if (wakeLock != null) { 43 | debug(TAG, "Releasing CPU lock"); 44 | wakeLock.release(); 45 | } 46 | if (wifiLock != null) { 47 | debug(TAG, "Releasing WiFi lock"); 48 | wifiLock.release(); 49 | } 50 | } 51 | 52 | public static PowerLock newLock(Context ctx) { 53 | PowerManager pmgr = (PowerManager) ctx.getApplicationContext().getSystemService(POWER_SERVICE); 54 | WifiManager wmgr = (WifiManager) ctx.getApplicationContext().getSystemService(WIFI_SERVICE); 55 | WakeLock wakeLock = (pmgr == null) ? null : pmgr.newWakeLock(PARTIAL_WAKE_LOCK, TAG); 56 | WifiLock wifiLock = (wmgr == null) ? null : wmgr.createWifiLock(WIFI_MODE_FULL, TAG); 57 | return ((wakeLock == null) && (wifiLock == null)) ? null : new PowerLock(wakeLock, wifiLock); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /cmake/OpenSSL.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(ExternalProject) 3 | include(ProcessorCount) 4 | 5 | if (ANDROID_ABI MATCHES "armeabi") 6 | set(OPENSSL_ANDROID_ABI "android-arm") 7 | elseif (ANDROID_ABI STREQUAL "arm64-v8a") 8 | set(OPENSSL_ANDROID_ABI "android-arm64") 9 | elseif (ANDROID_ABI STREQUAL "x86_64") 10 | set(OPENSSL_ANDROID_ABI "android-x86_64") 11 | elseif (ANDROID_ABI STREQUAL "x86") 12 | set(OPENSSL_ANDROID_ABI "android-x86") 13 | else () 14 | message(FATAL_ERROR "Unsupported ANDROID_ABI: ${ANDROID_ABI}") 15 | endif () 16 | 17 | ProcessorCount(NCPU) 18 | find_program(MAKE_EXE NAMES make gmake nmake) 19 | 20 | set(OPENSSL_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin:$ENV{PATH}") 21 | set(OPENSSL_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}") 22 | set(OPENSSL_ENV "export ANDROID_NDK_HOME='${ANDROID_NDK}' && \ 23 | export PATH='${ANDROID_TOOLCHAIN_ROOT}/bin:$ENV{PATH}'") 24 | set(OPENSSL_CONFIGURE_CMD eval ${OPENSSL_ENV} && ./Configure) 25 | set(OPENSSL_BUILD_CMD eval ${OPENSSL_ENV} && ${MAKE_EXE} -j${NCPU}) 26 | 27 | set(OPENSSL_CONFIGURE_OPTS --prefix=${CMAKE_INSTALL_PREFIX} no-shared no-idea no-camellia 28 | no-seed no-bf no-cast no-rc2 no-md2 no-md4 no-mdc2 no-dsa no-err no-engine 29 | no-tests no-unit-test no-external-tests no-dso no-dynamic-engine no-stdio zlib 30 | ${OPENSSL_ANDROID_ABI} -D__ANDROID_API__=${ANDROID_NATIVE_API_LEVEL}) 31 | 32 | set(OPENSSL_ROOT_DIR "${OPENSSL_INSTALL_DIR}${CMAKE_INSTALL_PREFIX}") 33 | set(OPENSSL_LIB_DIR "${OPENSSL_ROOT_DIR}/lib") 34 | set(OPENSSL_LIBRARIES "${OPENSSL_LIB_DIR}/libssl.a" "${OPENSSL_LIB_DIR}/libcrypto.a") 35 | set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include") 36 | 37 | message(STATUS "OpenSSL config: ${OPENSSL_CONFIGURE_OPTS}") 38 | 39 | ExternalProject_Add(openssl 40 | URL "https://www.openssl.org/source/openssl-1.1.1l.tar.gz" 41 | PREFIX openssl 42 | BUILD_IN_SOURCE 1 43 | CONFIGURE_COMMAND ${OPENSSL_CONFIGURE_CMD} ${OPENSSL_CONFIGURE_OPTS} 44 | BUILD_COMMAND ${OPENSSL_BUILD_CMD} 45 | INSTALL_COMMAND ${MAKE_EXE} install_sw DESTDIR=${OPENSSL_INSTALL_DIR} 46 | BUILD_BYPRODUCTS ${OPENSSL_LIBRARIES}) 47 | 48 | add_dependencies(${PROJECT_NAME} openssl) 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Transmission BitTorrent Client for Android 2 | [Get it on Google Play](https://play.google.com/store/apps/details?id=com.ap.transmission.btc) 3 | [Get it at IzzyOnDroid](https://apt.izzysoft.de/packages/com.ap.transmission.btc) 4 | 5 | ## About 6 | This application is a port of the Transmission daemon for Android complemented with the following features: 7 | 8 | * Manage downloads directly from the application 9 | * Multiple watch/download directories 10 | * Support for HTTP(S)/SOCKS proxy 11 | * WiFi/Ethernet mode to save on mobile data 12 | * Keep CPU/WiFi awake to complete all downloads before the device goes to sleep 13 | * Sequential download allows playing media files while downloading 14 | * Open .torrent files or torrent/magnet URLs and stream the selected files to a media player 15 | * Builtin UPnP MediaServer. Download media files to a phone/tablet/TV-box and watch on a TV or another UPnP compatible media player connected to the same network 16 | * M3U playlists for all torrents/folders containing audio/video files. To get the playlist URL - long click on the play icon 17 | 18 | ## Building 19 | 20 | * Download the latest Android NDK from https://developer.android.com/ndk/downloads/ 21 | * Download the latest Android SDK or Android Studio from https://developer.android.com/studio/ 22 | * Extract the downloaded archives 23 | * Export the environment variable ANDROID_NDK_ROOT pointing to the NDK directory 24 | 25 | ### Build dependencies 26 | 27 | $ git clone https://github.com/AndreyPavlenko/android-build.git 28 | $ export ANDROID_BUILD_ROOT="$PWD/android-build" 29 | $ cd "$ANDROID_BUILD_ROOT/packages/transmission" 30 | $ ./build.sh all 31 | 32 | ### Build the apks 33 | $ git clone https://github.com/AndreyPavlenko/transmissionbtc.git 34 | 35 | Open the local.properties file in a text editor and enter the valid paths to ndk.dir, sdk.dir, depends and keystore, set the keystore properties. 36 | 37 | $ cd transmissionbtc 38 | $ gradle cleanAll assembleRelease 39 | -------------------------------------------------------------------------------- /src/main/res/layout/dir_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 24 | 25 | 26 | 39 | 40 | 49 | 50 | 57 | -------------------------------------------------------------------------------- /src/main/res/layout/file_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 24 | 25 | 26 | 39 | 40 | 49 | 50 | 58 | -------------------------------------------------------------------------------- /src/main/res/layout/select_file.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 21 | 22 | 32 | 33 | 39 | 40 |