├── .env ├── app ├── .gitignore ├── google-services.json.enc ├── sampledata │ └── images │ │ ├── img_1.jpg │ │ ├── img_2.jpg │ │ ├── img_3.png │ │ ├── img_4.jpg │ │ └── img_5.png ├── src │ ├── main │ │ ├── ic_launcher-web.png │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── values │ │ │ │ ├── integers.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── strings_leakcanary.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── values-v19 │ │ │ │ ├── dimens.xml │ │ │ │ └── styles.xml │ │ │ ├── values-w600dp │ │ │ │ ├── integers.xml │ │ │ │ └── dimens.xml │ │ │ ├── values-w900dp │ │ │ │ └── integers.xml │ │ │ ├── drawable │ │ │ │ ├── img_error.xml │ │ │ │ ├── ic_skip_next_black_24dp.xml │ │ │ │ ├── ic_cast_black_24dp.xml │ │ │ │ ├── ic_search_black_24dp.xml │ │ │ │ ├── img_loading.xml │ │ │ │ ├── ic_history_black_24dp.xml │ │ │ │ ├── ic_cast_connected_black_24dp.xml │ │ │ │ └── ic_settings_black_24dp.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ ├── fragment_episode.xml │ │ │ │ ├── activity_onboarding.xml │ │ │ │ ├── item_unknown.xml │ │ │ │ ├── activity_home.xml │ │ │ │ ├── item_empty.xml │ │ │ │ ├── fragment_search.xml │ │ │ │ └── item_episode.xml │ │ │ └── menu │ │ │ │ └── home.xml │ │ ├── kotlin │ │ │ └── brunodles │ │ │ │ ├── animewatcher │ │ │ │ ├── cast │ │ │ │ │ ├── DeviceConnectedListener.kt │ │ │ │ │ ├── Caster.kt │ │ │ │ │ ├── CastOptionsProvider.kt │ │ │ │ │ ├── MultiCaster.kt │ │ │ │ │ └── GoogleCaster.kt │ │ │ │ ├── persistence │ │ │ │ │ ├── UrlFixer.kt │ │ │ │ │ └── Preferences.kt │ │ │ │ ├── search │ │ │ │ │ ├── AutoCompleteAdapter.kt │ │ │ │ │ └── SearchController.kt │ │ │ │ ├── parcelable │ │ │ │ │ ├── EpisodeParceler.kt │ │ │ │ │ └── EpisodeParcel.kt │ │ │ │ ├── Application.kt │ │ │ │ ├── explorer │ │ │ │ │ └── Episode.kt │ │ │ │ ├── api │ │ │ │ │ └── ApiFactory.kt │ │ │ │ ├── player │ │ │ │ │ ├── PlayerListener.kt │ │ │ │ │ ├── Player.kt │ │ │ │ │ └── EpisodeController.kt │ │ │ │ ├── home │ │ │ │ │ └── HomeActivity.kt │ │ │ │ ├── nextepisodes │ │ │ │ │ ├── EpisodeAdapter.kt │ │ │ │ │ └── NextEpisodeFragment.kt │ │ │ │ └── ImageLoader.kt │ │ │ │ ├── extensions │ │ │ │ └── ListExtensions.kt │ │ │ │ ├── rxpicasso │ │ │ │ └── RxPicasso.kt │ │ │ │ ├── bindingadapter │ │ │ │ └── RecyclerViewBindingAdapter.kt │ │ │ │ ├── adapter │ │ │ │ ├── EmptyAdapter.kt │ │ │ │ └── ViewDataBindingAdapter.kt │ │ │ │ ├── rxfirebase │ │ │ │ ├── SingleValueEvent.kt │ │ │ │ ├── TypedEvent.kt │ │ │ │ └── ChildAddedEvent.kt │ │ │ │ ├── components │ │ │ │ └── TextInputAutoCompleteTextView.kt │ │ │ │ └── collection │ │ │ │ └── ArrayWithKeys.kt │ │ └── manifest │ │ │ └── AndroidManifest.xml │ ├── debug │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ │ └── brunodles │ │ │ └── animewatcher │ │ │ ├── AnrWatchDogMod.kt │ │ │ ├── StrictModeMod.kt │ │ │ └── LocalCrashes.kt │ ├── connectsdk_enabled │ │ └── kotlin │ │ │ └── brunodles │ │ │ └── animewatcher │ │ │ └── cast │ │ │ └── ConnectSdkCasterFactory.kt │ ├── androidTest │ │ └── java │ │ │ └── brunodles │ │ │ └── animewatcher │ │ │ └── ExampleInstrumentedTest.kt │ └── connectsdk_disabled │ │ └── kotlin │ │ └── brunodles │ │ └── animewatcher │ │ └── cast │ │ └── ConnectSdkCasterFactory.kt ├── launchOnDevice.sh ├── README.md └── proguard-rules.pro ├── server-ktor ├── .gitignore ├── Procfile ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── brunodles │ │ │ └── animewatcher │ │ │ └── serverktor │ │ │ ├── Main.kt │ │ │ └── Application.kt │ └── test │ │ └── kotlin │ │ └── com │ │ └── brunodles │ │ └── animewatcher │ │ └── serverktor │ │ └── ApplicationKtTest.kt └── build.gradle ├── cli ├── .gitignore ├── README.md ├── src │ └── main │ │ └── kotlin │ │ └── com │ │ └── brunodles │ │ └── animewatcher │ │ └── cli │ │ └── Decoder.kt └── build.gradle ├── explorer ├── .gitignore ├── src │ ├── test │ │ ├── resources │ │ │ ├── cache │ │ │ └── responses │ │ │ │ ├── animakai │ │ │ │ ├── error_episodes.json │ │ │ │ ├── umaruchan_episodes.json │ │ │ │ └── tskipro_episodes.json │ │ │ │ ├── animesorion │ │ │ │ ├── noNext_episodes.json │ │ │ │ └── singleNext_episodes.json │ │ │ │ ├── tvcurse │ │ │ │ ├── player_without_next_episodes.json │ │ │ │ └── player_with_next_episodes.json │ │ │ │ ├── anitubebr │ │ │ │ └── player_episodes.json │ │ │ │ ├── animetubebrasil │ │ │ │ └── player_episodes.json │ │ │ │ ├── onepiecex │ │ │ │ └── player_episodes.json │ │ │ │ ├── anitubesite │ │ │ │ └── player_episodes.json │ │ │ │ └── animesonlinebr │ │ │ │ └── player_episodes.json │ │ └── kotlin │ │ │ ├── brunodles │ │ │ ├── animewatcher │ │ │ │ ├── testhelper │ │ │ │ │ ├── FailFetcher.kt │ │ │ │ │ ├── RetryFetcher.kt │ │ │ │ │ └── ResourceFetcher.kt │ │ │ │ └── decoders │ │ │ │ │ ├── AnitubeSiteFactoryTest.kt │ │ │ │ │ ├── AnimeTubeBrasilFactoryTest.kt │ │ │ │ │ ├── OnePieceXFactoryTest.kt │ │ │ │ │ ├── AnitubeBrFactoryTest.kt │ │ │ │ │ ├── AnimesOnlineBrFactoryTest.kt │ │ │ │ │ ├── XvideosFactoryTest.kt │ │ │ │ │ ├── TvCurseFactoryTest.kt │ │ │ │ │ ├── AnimaKaiFactoryTest.kt │ │ │ │ │ └── AnimesOrionFactoryTest.kt │ │ │ ├── ResourceLoader.kt │ │ │ └── urlfetcher │ │ │ │ └── CacheFetcherTest.kt │ │ │ └── JsonMaker.kt │ └── main │ │ └── kotlin │ │ └── brunodles │ │ ├── animewatcher │ │ ├── decoders │ │ │ ├── TypeAlias.kt │ │ │ ├── UrlChecker.kt │ │ │ ├── AnimeTubeBrasilFactory.kt │ │ │ ├── AnimaKaiFactory.kt │ │ │ ├── AnitubeBrFactory.kt │ │ │ ├── AnitubeSiteFactory.kt │ │ │ ├── TvCurseFactory.kt │ │ │ └── AnimesOrionFactory.kt │ │ ├── explorer │ │ │ ├── PageParser.kt │ │ │ └── Episode.kt │ │ └── AlchemistFactory.kt │ │ ├── kotlin │ │ └── annotation │ │ │ └── NoArgs.kt │ │ └── urlfetcher │ │ ├── Logger.kt │ │ ├── UrlFetcherComposable.kt │ │ ├── Extensions.kt │ │ ├── JsoupFetcher.kt │ │ ├── UrlFetcher.kt │ │ ├── RedirectFetcher.kt │ │ └── CacheFetcher.kt ├── README.md └── build.gradle ├── decoders ├── anitubex │ ├── .gitignore │ ├── build.gradle │ └── src │ │ ├── test │ │ └── kotlin │ │ │ └── brunodles │ │ │ └── anitubex │ │ │ └── AnitubexFactoryTest.kt │ │ └── main │ │ └── kotlin │ │ └── brunodles │ │ └── anitubex │ │ └── AnitubexFactory.kt ├── animesproject │ ├── .gitignore │ ├── build.gradle │ └── src │ │ ├── test │ │ └── kotlin │ │ │ └── brunodles │ │ │ └── animesproject │ │ │ └── AnimesProjectFactoryTest.kt │ │ └── main │ │ └── kotlin │ │ └── brunodles │ │ └── animesproject │ │ └── AnimesProjectFactory.kt └── README.md ├── feature_toggle.properties ├── keystore ├── server-spark ├── Procfile ├── herokuRequest ├── build.gradle ├── server_blueprint.md ├── src │ └── main │ │ └── kotlin │ │ └── com │ │ └── brunodles │ │ └── videowatcher │ │ └── serverspark │ │ └── ApplicationRouter.kt └── README.md ├── cloudfunctions ├── .firebaserc ├── firebase.json ├── functions │ ├── package.json │ ├── search.js │ ├── index.js │ └── gateway.js ├── .gitignore └── README.md ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── checkstyle.gradle ├── decoder_build.gradle ├── ktlint.gradle ├── jacoco.gradle ├── sites.gradle ├── resource_helper.gradle └── buildconfig.gradle ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── kotlinc.xml ├── inspectionProfiles │ └── Project_Default.xml └── runConfigurations.xml ├── settings.gradle ├── cache ├── README.md └── yasopp.onepieceex.com.br │ └── playerphpcodeplayseuZKaRb4qH18qkwx2FxodvEhf8pFKKbt6 ├── .travis.yml ├── ciVerifications ├── gradle.properties ├── .circleci └── config.yml ├── README.md ├── Firebase.md └── gradlew.bat /.env: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /server-ktor/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /cli/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | cache 3 | -------------------------------------------------------------------------------- /explorer/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /cache -------------------------------------------------------------------------------- /decoders/anitubex/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /feature_toggle.properties: -------------------------------------------------------------------------------- 1 | CONNECT_SDK=true -------------------------------------------------------------------------------- /decoders/animesproject/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /explorer/src/test/resources/cache: -------------------------------------------------------------------------------- 1 | ../../../../cache -------------------------------------------------------------------------------- /keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/keystore -------------------------------------------------------------------------------- /server-ktor/Procfile: -------------------------------------------------------------------------------- 1 | web: ./server-ktor/build/install/server-ktor/bin/server-ktor -------------------------------------------------------------------------------- /server-spark/Procfile: -------------------------------------------------------------------------------- 1 | web: ./server-spark/build/install/server-spark/bin/server-spark -------------------------------------------------------------------------------- /decoders/anitubex/build.gradle: -------------------------------------------------------------------------------- 1 | apply from: rootProject.file("gradle/decoder_build.gradle") -------------------------------------------------------------------------------- /decoders/README.md: -------------------------------------------------------------------------------- 1 | This module will be removed, but still have some code that need to be moved. -------------------------------------------------------------------------------- /decoders/animesproject/build.gradle: -------------------------------------------------------------------------------- 1 | apply from: rootProject.file("gradle/decoder_build.gradle") -------------------------------------------------------------------------------- /cloudfunctions/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "animewatcher-bbdf0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/google-services.json.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/google-services.json.enc -------------------------------------------------------------------------------- /app/sampledata/images/img_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/sampledata/images/img_1.jpg -------------------------------------------------------------------------------- /app/sampledata/images/img_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/sampledata/images/img_2.jpg -------------------------------------------------------------------------------- /app/sampledata/images/img_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/sampledata/images/img_3.png -------------------------------------------------------------------------------- /app/sampledata/images/img_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/sampledata/images/img_4.jpg -------------------------------------------------------------------------------- /app/sampledata/images/img_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/sampledata/images/img_5.png -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /explorer/README.md: -------------------------------------------------------------------------------- 1 | # Anime Watcher - Explorer 2 | Explores the html pages for wanted content. 3 | 4 | This module exposes the way to decode the pages. -------------------------------------------------------------------------------- /app/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | -------------------------------------------------------------------------------- /cloudfunctions/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "functions": { 3 | "predeploy": [ 4 | "npm --prefix \"$RESOURCE_DIR\" run lint" 5 | ] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-v19/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 56dp 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-w600dp/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-w900dp/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 3 4 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-w600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 120dp 4 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /explorer/src/main/kotlin/brunodles/animewatcher/decoders/TypeAlias.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.decoders 2 | 3 | typealias Regexp = com.brunodles.alchemist.regex.Regex -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunodles/anime-watcher/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/animewatcher/cast/DeviceConnectedListener.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.cast 2 | 3 | internal typealias DeviceConnectedListener = (Caster) -> Unit -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /cli/README.md: -------------------------------------------------------------------------------- 1 | # Anime Watcher - CLI 2 | This Command Line Interface just interacts with explorer module to decode pages 3 | locally. 4 | 5 | We may add more functions here later. 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings_leakcanary.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | AnimeWatcher leaks 5 | -------------------------------------------------------------------------------- /explorer/src/main/kotlin/brunodles/kotlin/annotation/NoArgs.kt: -------------------------------------------------------------------------------- 1 | package brunodles.kotlin.annotation 2 | 3 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 4 | @Retention(AnnotationRetention.BINARY) 5 | annotation class NoArgs 6 | -------------------------------------------------------------------------------- /explorer/src/main/kotlin/brunodles/animewatcher/explorer/PageParser.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.explorer 2 | 3 | interface PageParser { 4 | 5 | fun isEpisode(url: String): Boolean 6 | 7 | fun episode(url: String): Episode 8 | } -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/animewatcher/persistence/UrlFixer.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.persistence 2 | 3 | private val INVALID_TEXT_PATTERN = Regex("[^\\d\\w]+") 4 | 5 | fun fixUrlToFirebase(url: String): String = url.replace(INVALID_TEXT_PATTERN, "") -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #f49569 4 | #c65e35 5 | #e90111 6 | 7 | -------------------------------------------------------------------------------- /app/launchOnDevice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z $1 ]; then 3 | echo "Missing url parameter" 4 | echo "Usage: $0 " 5 | echo "Sample: $0 https://github.com/brunodles/anime-watcher" 6 | else 7 | adb shell am start -a "android.intent.action.VIEW" -d "$1" 8 | fi -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Oct 16 18:39:37 BRT 2018 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-4.6-all.zip 7 | -------------------------------------------------------------------------------- /app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gradle/checkstyle.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'checkstyle' 2 | 3 | checkstyle { 4 | toolVersion "7.6.1" 5 | sourceSets = [ project.sourceSets.main ] 6 | } 7 | 8 | checkstyleMain { 9 | source 'src/main/' 10 | exclude '**/build/**' 11 | configFile rootProject.file('checkstyle.xml') 12 | } -------------------------------------------------------------------------------- /explorer/src/main/kotlin/brunodles/urlfetcher/Logger.kt: -------------------------------------------------------------------------------- 1 | package brunodles.urlfetcher 2 | 3 | internal object Logger { 4 | 5 | var useLog: Boolean = false 6 | 7 | internal fun log(function: () -> String) { 8 | if (useLog) 9 | println("UrlFetcher: ${function()}") 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/res/values-v19/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':explorer' 2 | include ':cli' 3 | include ':server-spark', ':server-ktor' 4 | 5 | // include android related modules inside this verification 6 | // This will be used to skip android modules for web server releases. 7 | if ((System.getenv("INCLUDE_ANDROID") ?: "true").toBoolean()) { 8 | include ':app' 9 | } -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4dp 4 | 8dp 5 | 2dp 6 | 80dp 7 | 8 | 0dp 9 | -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/animakai/error_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": " online aqui no site", 3 | "number": 1, 4 | "animeName": " online aqui no site", 5 | "image": "http/imagens/848x380/", 6 | "video": "", 7 | "link": "https://www.animeskai.net/anime/my-hero/ep-01", 8 | "nextEpisodes": [], 9 | "temporaryVideoUrl": false 10 | } -------------------------------------------------------------------------------- /gradle/decoder_build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'kotlin' 3 | 4 | dependencies { 5 | compile project(':explorer') 6 | 7 | testCompile project(':decodertesthelper') 8 | testCompile 'junit:junit:4.12' 9 | testCompile 'com.greghaskins:spectrum:1.1.1' 10 | } 11 | 12 | sourceCompatibility = "1.7" 13 | targetCompatibility = "1.7" 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/extensions/ListExtensions.kt: -------------------------------------------------------------------------------- 1 | package brunodles.extensions 2 | 3 | import java.util.Random 4 | 5 | private fun List.firsts(max: Int): List { 6 | val lastIndex = if (this.size >= max) max else this.size 7 | return this.subList(0, lastIndex) 8 | } 9 | 10 | private fun List.random(): E = this[Random().nextInt(this.size)] 11 | -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/animewatcher/search/AutoCompleteAdapter.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.search 2 | 3 | import android.content.Context 4 | import android.widget.ArrayAdapter 5 | import android.widget.Filterable 6 | 7 | class AutoCompleteAdapter(context: Context) : 8 | ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line), Filterable { 9 | 10 | } -------------------------------------------------------------------------------- /cache/README.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | This folder provides cached pages for our tests. 3 | With it we don't need to fetch pages every time. 4 | 5 | The cache is also useful to look the real page content, as it will not execute 6 | `javascript` nor `iframes`. Some pages also have different responses depending 7 | on `user agent` used to fetch the page. 8 | 9 | This cache cam be disabled during build time. 10 | -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/animesorion/noNext_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Himouto! Umaru-chan Episódio 12 – FINAL", 3 | "number": 12, 4 | "animeName": "Himouto! Umaru-chan 1 Legendado", 5 | "video": "https://www.blogger.com/video-play.mp4?contentId\u003de4e3e680e0b6ed74", 6 | "link": "http://www.animesorion.tv/51555", 7 | "nextEpisodes": [], 8 | "temporaryVideoUrl": false 9 | } -------------------------------------------------------------------------------- /server-spark/herokuRequest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z $1 ]; then 3 | echo "Missing url parameter" 4 | echo "Usage: $0 " 5 | echo "Sample: $0 https://github.com/brunodles/anime-watcher" 6 | else 7 | # deprecated 8 | #curl https://anime-watcher-spark.herokuapp.com/decoder -d "$1" 9 | curl -G https://anime-watcher-spark.herokuapp.com/v1/decoder --data-urlencode "url=$1" 10 | fi -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_episode.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_skip_next_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /cache/yasopp.onepieceex.com.br/playerphpcodeplayseuZKaRb4qH18qkwx2FxodvEhf8pFKKbt6: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {"total":2,"LQ":"https:\/\/yasopp.onepieceex.com.br\/episodios\/lq\/OpEx_210_LQ.mp4?st=faAdmibhdMuL59gREzBICg&e=1540950612","Online":"https:\/\/yasopp.onepieceex.com.br\/episodios\/online\/OpEx_210_online.webm?st=naV6WzqRzANboDn3miGwyw&e=1540950612","andamento":100,"code":0,"mensagem":"Tudo pronto."} 5 | 6 | -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/animakai/umaruchan_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Himouto! Umaru-chan 1 online aqui no site", 3 | "number": 1, 4 | "animeName": "Himouto! Umaru-chan online aqui no site", 5 | "image": "http/imagens/848x380/", 6 | "video": "http://www.blogger.com/video-play.mp4?contentId\u003da1bc047412d3b897", 7 | "link": "https://www.animeskai.net/himouto-umaru-chan/ep-1", 8 | "nextEpisodes": [], 9 | "temporaryVideoUrl": false 10 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/rxpicasso/RxPicasso.kt: -------------------------------------------------------------------------------- 1 | package brunodles.rxpicasso 2 | 3 | import android.graphics.Bitmap 4 | import com.squareup.picasso.RequestCreator 5 | import io.reactivex.Single 6 | 7 | fun RequestCreator.asSingle(): Single { 8 | return Single.create { subject -> 9 | try { 10 | subject.onSuccess(this.get()) 11 | } catch (exception: Exception) { 12 | subject.onError(exception) 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /gradle/ktlint.gradle: -------------------------------------------------------------------------------- 1 | configurations { 2 | ktlint 3 | } 4 | 5 | dependencies { 6 | ktlint 'com.github.shyiko:ktlint:0.14.0' 7 | } 8 | 9 | task ktlint(type: JavaExec) { 10 | group "verification" 11 | description "Check kotlin code style." 12 | classpath configurations.ktlint 13 | main 'com.github.shyiko.ktlint.Main' 14 | args "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml", "src/**/*.kt" 15 | } 16 | 17 | check.dependsOn ktlint -------------------------------------------------------------------------------- /explorer/src/test/kotlin/brunodles/animewatcher/testhelper/FailFetcher.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.testhelper 2 | 3 | import brunodles.urlfetcher.UrlFetcher 4 | import org.jsoup.nodes.Document 5 | 6 | internal class FailFetcher : UrlFetcher { 7 | 8 | override fun get(url: String): Document { 9 | throw FetchingException("Failed to fetch: $url") 10 | } 11 | 12 | class FetchingException internal constructor(msg: String) : RuntimeException(msg) 13 | } 14 | -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/tvcurse/player_without_next_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Assistir Himouto! Umaru-chan ova 11 – Especial ova 11 Online", 3 | "number": 11, 4 | "animeName": "Himouto! Umaru-chan", 5 | "image": "https://tvcurse.com/imgs/himouto-umaru-chan-ova-11.webp", 6 | "video": "https://tvcurse.com/dd/YzRjMjhmMDc4MGY5NzExNg\u003d\u003d", 7 | "link": "https://tvcurse.com/?p\u003d43449", 8 | "nextEpisodes": [], 9 | "temporaryVideoUrl": false 10 | } -------------------------------------------------------------------------------- /app/src/debug/kotlin/brunodles/animewatcher/AnrWatchDogMod.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher 2 | 3 | import com.brunodles.environmentmods.annotation.ModFor 4 | import com.github.anrwatchdog.ANRWatchDog 5 | 6 | object AnrWatchDogMod { 7 | 8 | private val TIMEOUT = 10000 9 | 10 | @JvmStatic 11 | @ModFor(Application::class) 12 | fun startAnrWatchDog(){ 13 | ANRWatchDog(TIMEOUT) 14 | .setIgnoreDebugger(true) 15 | .start() 16 | } 17 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: oraclejdk8 3 | 4 | env: 5 | - INCLUDE_ANDROID=false 6 | 7 | script: 8 | - ./gradlew clean assemble 9 | - ./gradlew ktlint checkstyleMain --continue 10 | # - ./gradlew cleanTest test -Pusecache=true -PparallelForks=1 11 | 12 | before_cache: 13 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 14 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 15 | cache: 16 | directories: 17 | - $HOME/.gradle/caches/ 18 | - $HOME/.gradle/wrapper/ 19 | -------------------------------------------------------------------------------- /app/src/connectsdk_enabled/kotlin/brunodles/animewatcher/cast/ConnectSdkCasterFactory.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.cast 2 | 3 | import android.app.Activity 4 | import android.widget.ImageButton 5 | 6 | object ConnectSdkCasterFactory { 7 | internal fun create( 8 | activity: Activity, mediaRouteButton: ImageButton?, 9 | listener: DeviceConnectedListener? = null 10 | ): ConnectSdkCaster { 11 | return ConnectSdkCaster(activity, mediaRouteButton, listener) 12 | } 13 | } -------------------------------------------------------------------------------- /server-ktor/src/main/java/com/brunodles/animewatcher/serverktor/Main.kt: -------------------------------------------------------------------------------- 1 | package com.brunodles.animewatcher.serverktor 2 | 3 | import io.ktor.server.engine.embeddedServer 4 | import io.ktor.server.netty.Netty 5 | 6 | fun main(args: Array) { 7 | val port = getHerokuAssignedPort() 8 | val server = embeddedServer(Netty, port = port) { 9 | animewatcher() 10 | } 11 | server.start(wait = true) 12 | } 13 | 14 | fun getHerokuAssignedPort(): Int = System.getenv("PORT")?.toInt() ?: 4567 15 | -------------------------------------------------------------------------------- /cli/src/main/kotlin/com/brunodles/animewatcher/cli/Decoder.kt: -------------------------------------------------------------------------------- 1 | package com.brunodles.animewatcher.cli 2 | 3 | import brunodles.animewatcher.decoders.UrlChecker 4 | import brunodles.urlfetcher.UrlFetcher 5 | 6 | fun main(args: Array) { 7 | val cacheDir = UrlFetcher.cacheDir + "/cli/cache" 8 | println("CacheDir $cacheDir") 9 | UrlFetcher.cacheDir = cacheDir 10 | UrlFetcher.useLog = true 11 | println("\n\n") 12 | val videoInfo = UrlChecker.videoInfo(args[0]) 13 | println(videoInfo) 14 | } -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/animakai/tskipro_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Tsukipro The Animation 1 online aqui no site", 3 | "number": 1, 4 | "animeName": "Tsukipro The Animation online aqui no site", 5 | "image": "http://www.animekai.info/2017/10/Screenshot_33.jpg", 6 | "video": "http://www.blogger.com/video-play.mp4?contentId\u003db186c220e9973f58", 7 | "link": "https://www.animekaionline.com/tsukipro-the-animation/episodio-1", 8 | "nextEpisodes": [], 9 | "temporaryVideoUrl": false 10 | } -------------------------------------------------------------------------------- /ciVerifications: -------------------------------------------------------------------------------- 1 | # This script is currently simulating ci builds. 2 | # It does the same commands currently on ci. 3 | # need to be on environment vars: 4 | # GOOGLE_SERVICES_KEY 5 | 6 | # Setup environment 7 | rm app/google-services.json 8 | 9 | # Fail fast, if a command fail the script will fail 10 | set -e 11 | ./gradlew clean app:googleServicesDecrypt assembleDebug 12 | ./gradlew lint ktlint checkstyleMain --continue -x app:ktlint 13 | ./gradlew cleanTest test -Pusecache=true -PparallelForks=1 14 | ./gradlew jacocoTestReport -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/bindingadapter/RecyclerViewBindingAdapter.kt: -------------------------------------------------------------------------------- 1 | package brunodles.bindingadapter 2 | 3 | import android.databinding.BindingAdapter 4 | import android.support.v7.widget.RecyclerView 5 | 6 | object RecyclerViewBindingAdapter { 7 | 8 | @JvmStatic 9 | @BindingAdapter("nestedScrollingEnabled", requireAll = false) 10 | fun nestedScrollingEnabled(recyclerView: RecyclerView, nestedScrollingEnabled: Boolean) { 11 | recyclerView.isNestedScrollingEnabled = nestedScrollingEnabled 12 | } 13 | } -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/anitubebr/player_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "One Piece 01", 3 | "number": 1, 4 | "animeName": "One Piece", 5 | "image": "", 6 | "link": "https://anitubebr.com/vd/19249/", 7 | "nextEpisodes": [ 8 | { 9 | "description": "Próximo Episódio", 10 | "number": 2, 11 | "animeName": "One Piece", 12 | "link": "https://anitubebr.com/vd/19250/", 13 | "nextEpisodes": [], 14 | "temporaryVideoUrl": false 15 | } 16 | ], 17 | "temporaryVideoUrl": false 18 | } -------------------------------------------------------------------------------- /explorer/src/test/kotlin/brunodles/animewatcher/testhelper/RetryFetcher.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.testhelper 2 | 3 | import brunodles.urlfetcher.UrlFetcher 4 | import org.jsoup.nodes.Document 5 | 6 | internal class RetryFetcher(private val fetcher: UrlFetcher) : UrlFetcher { 7 | 8 | override fun get(url: String): Document { 9 | return try { 10 | fetcher.get(url) 11 | } catch (e: Exception) { 12 | e.printStackTrace(System.err) 13 | fetcher.get(url) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/debug/kotlin/brunodles/animewatcher/StrictModeMod.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher 2 | 3 | import android.os.StrictMode 4 | import com.brunodles.environmentmods.annotation.ModFor 5 | 6 | object StrictModeMod { 7 | 8 | @JvmStatic 9 | @ModFor(Application::class) 10 | fun applyThreadPolicy() { 11 | StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() 12 | .detectAll() 13 | .penaltyLog() 14 | .penaltyFlashScreen() 15 | .penaltyDeath() 16 | .build()) 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/animetubebrasil/player_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Eu Sou Ruffy!", 3 | "number": 1, 4 | "animeName": "One Piece", 5 | "video": "https://www.blogger.com/video-play.mp4?contentId\u003d3eb2b428663ef38f", 6 | "link": "https://animetubebrasil.com/1582/", 7 | "nextEpisodes": [ 8 | { 9 | "description": "Next", 10 | "number": 2, 11 | "animeName": "One Piece", 12 | "link": "https://animetubebrasil.com/1583/", 13 | "nextEpisodes": [], 14 | "temporaryVideoUrl": false 15 | } 16 | ], 17 | "temporaryVideoUrl": false 18 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_cast_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/animewatcher/parcelable/EpisodeParceler.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.parcelable 2 | 3 | import brunodles.animewatcher.explorer.Episode 4 | 5 | object EpisodeParceler { 6 | 7 | fun toParcel(episode: Episode) = EpisodeParcel(episode) 8 | 9 | fun fromParcel(episode: EpisodeParcel): Episode = Episode( 10 | episode.description, 11 | episode.number, 12 | episode.animeName, 13 | episode.image, 14 | episode.video, 15 | episode.link, 16 | episode.nextEpisodes.map { fromParcel(it) }.toList() 17 | ) 18 | } -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/adapter/EmptyAdapter.kt: -------------------------------------------------------------------------------- 1 | package brunodles.adapter 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.ViewGroup 5 | 6 | class EmptyAdapter : RecyclerView.Adapter() { 7 | 8 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 9 | } 10 | 11 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 12 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 13 | } 14 | 15 | override fun getItemCount(): Int = 0 16 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_history_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/animesorion/singleNext_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Boku No Hero Academia Episódio 2", 3 | "number": 2, 4 | "animeName": "Boku No Hero Academia 1", 5 | "video": "https://www.blogger.com/video-play.mp4?contentId\u003db0bccad36e2be8e1", 6 | "link": "https://www.animesorion.site/71672", 7 | "nextEpisodes": [ 8 | { 9 | "description": "Next", 10 | "number": 3, 11 | "animeName": "Boku No Hero Academia 1", 12 | "link": "https://www.animesorion.org/71808", 13 | "nextEpisodes": [], 14 | "temporaryVideoUrl": false 15 | } 16 | ], 17 | "temporaryVideoUrl": false 18 | } -------------------------------------------------------------------------------- /explorer/src/main/kotlin/brunodles/urlfetcher/UrlFetcherComposable.kt: -------------------------------------------------------------------------------- 1 | package brunodles.urlfetcher 2 | 3 | import org.jsoup.nodes.Document 4 | 5 | class UrlFetcherComposable internal constructor() : UrlFetcher { 6 | private var internalFetcher: UrlFetcher = JsoupFetcher() 7 | 8 | fun withCache(): UrlFetcherComposable { 9 | internalFetcher = CacheFetcher(internalFetcher) 10 | return this 11 | } 12 | 13 | fun withJsRedirect(): UrlFetcherComposable { 14 | internalFetcher = RedirectFetcher(internalFetcher) 15 | return this 16 | } 17 | 18 | override fun get(url: String): Document = internalFetcher.get(url) 19 | } 20 | -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/onepiecex/player_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Os piratas do Foxy!! A Davy Back!", 3 | "number": 208, 4 | "animeName": "One Piece", 5 | "video": "https:\\/\\/\\w+.onepieceex\\.com\\.br\\/episodios\\/\\w+\\/OpEx_\\d+_\\w+.mp4\\?st\u003d.*", 6 | "link": "https://onepiece-ex.com.br/episodios/online/208/", 7 | "nextEpisodes": [ 8 | { 9 | "description": "Next", 10 | "number": 209, 11 | "animeName": "One Piece", 12 | "link": "https://onepiece-ex.com.br/episodios/online/209", 13 | "nextEpisodes": [], 14 | "temporaryVideoUrl": false 15 | } 16 | ], 17 | "temporaryVideoUrl": false 18 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_cast_connected_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /cloudfunctions/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "lint": "eslint .", 6 | "serve": "firebase serve --only functions", 7 | "shell": "firebase functions:shell", 8 | "start": "npm run shell", 9 | "deploy": "firebase deploy --only functions", 10 | "logs": "firebase functions:log" 11 | }, 12 | "dependencies": { 13 | "firebase-admin": "~6.0.0", 14 | "firebase-functions": "^2.0.3", 15 | "node-rest-client": "^3.1.0" 16 | }, 17 | "devDependencies": { 18 | "eslint": "^4.12.0", 19 | "eslint-plugin-promise": "^3.6.0" 20 | }, 21 | "private": true 22 | } 23 | -------------------------------------------------------------------------------- /explorer/src/test/resources/responses/anitubesite/player_episodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Eu Sou Ruffy!", 3 | "number": 1, 4 | "animeName": "One Piece", 5 | "image": "https://www.anitube.site/player/img/Capa-Player-Cine.png", 6 | "video": "https://www.blogger.com/video-play.mp4?contentId\u003d3eb2b428663ef38f", 7 | "link": "https://www.anitube.site/765/", 8 | "nextEpisodes": [ 9 | { 10 | "description": "O Grande Espadachim Aparece!", 11 | "number": 2, 12 | "animeName": "One Piece", 13 | "link": "https://www.anitube.site/802/", 14 | "nextEpisodes": [], 15 | "temporaryVideoUrl": false 16 | } 17 | ], 18 | "temporaryVideoUrl": false 19 | } -------------------------------------------------------------------------------- /gradle/jacoco.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "jacoco" 2 | 3 | jacoco { 4 | toolVersion = "0.7.6.201602180812" 5 | } 6 | 7 | jacocoTestReport { 8 | reports { 9 | xml.enabled true 10 | csv.enabled true 11 | html.enabled true 12 | } 13 | additionalSourceDirs = files(sourceSets.main.allSource.srcDirs) 14 | sourceDirectories = files(sourceSets.main.allSource.srcDirs) 15 | classDirectories = files(sourceSets.main.output) 16 | } 17 | 18 | test { 19 | ignoreFailures = properties.get("ignoreFailures", false) 20 | reports { 21 | junitXml.enabled = true 22 | html.enabled = true 23 | } 24 | jacoco { 25 | append = false 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_onboarding.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/kotlin/brunodles/animewatcher/cast/Caster.kt: -------------------------------------------------------------------------------- 1 | package brunodles.animewatcher.cast 2 | 3 | import android.app.Activity 4 | import android.support.v7.app.MediaRouteButton 5 | import android.widget.ImageButton 6 | import brunodles.animewatcher.explorer.Episode 7 | 8 | interface Caster { 9 | 10 | fun playRemote(currentEpisode: Episode, position: Long) 11 | fun isConnected(): Boolean 12 | 13 | object Factory { 14 | fun multiCaster(activity: Activity, mediaRouterButton: MediaRouteButton, imageButton: ImageButton): Caster 15 | = MultiCaster(activity, mediaRouterButton, imageButton) 16 | } 17 | } 18 | 19 | fun Caster?.isConnected(): Boolean = this?.isConnected() ?: false -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | 16 |