diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f3a88fd..e7c4447a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,6 +46,8 @@ jobs: SORAHE: ${{ secrets.SORAHE }} SORAXA: ${{ secrets.SORAXA }} SORATED: ${{ secrets.SORATED }} + DUMP_API: ${{ secrets.DUMP_API }} + DUMP_KEY: ${{ secrets.DUMP_KEY }} CRUNCHYROLL_BASIC_TOKEN: ${{ secrets.CRUNCHYROLL_BASIC_TOKEN }} CRUNCHYROLL_REFRESH_TOKEN: ${{ secrets.CRUNCHYROLL_REFRESH_TOKEN }} run: | @@ -54,6 +56,8 @@ jobs: echo SORAHE=$SORAHE >> local.properties echo SORAXA=$SORAXA >> local.properties echo SORATED=$SORATED >> local.properties + echo DUMP_API=$DUMP_API >> local.properties + echo DUMP_KEY=$DUMP_KEY >> local.properties echo CRUNCHYROLL_BASIC_TOKEN=$CRUNCHYROLL_BASIC_TOKEN >> local.properties echo CRUNCHYROLL_REFRESH_TOKEN=$CRUNCHYROLL_REFRESH_TOKEN >> local.properties diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index e46e9fdb..1d00ea54 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -12,6 +12,8 @@ android { buildConfigField("String", "SORAHE", "\"${properties.getProperty("SORAHE")}\"") buildConfigField("String", "SORAXA", "\"${properties.getProperty("SORAXA")}\"") buildConfigField("String", "SORATED", "\"${properties.getProperty("SORATED")}\"") + buildConfigField("String", "DUMP_API", "\"${properties.getProperty("DUMP_API")}\"") + buildConfigField("String", "DUMP_KEY", "\"${properties.getProperty("DUMP_KEY")}\"") buildConfigField("String", "CRUNCHYROLL_BASIC_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_BASIC_TOKEN")}\"") buildConfigField("String", "CRUNCHYROLL_REFRESH_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_REFRESH_TOKEN")}\"") diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index d1e264d0..e6b225ac 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1,6 +1,5 @@ package com.hexated -import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson @@ -688,7 +687,7 @@ object SoraExtractor : SoraStream() { } } - suspend fun invokeSoraStream( + suspend fun invokeDumpStream( title: String? = null, year: Int? = null, season: Int? = null, @@ -696,8 +695,8 @@ object SoraExtractor : SoraStream() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit, ) { - val (id, type) = getSoraIdAndType(title, year, season) ?: return - val json = fetchSoraEpisodes(id, type, episode) ?: return + val (id, type) = getDumpIdAndType(title, year, season) + val json = fetchDumpEpisodes("$id", "$type", episode) ?: return json.subtitlingList?.map { sub -> subtitleCallback.invoke( @@ -1567,7 +1566,7 @@ object SoraExtractor : SoraStream() { } - suspend fun invokeCrunchyroll( + private suspend fun invokeCrunchyroll( aniId: Int? = null, malId: Int? = null, epsTitle: String? = null, @@ -3040,481 +3039,3 @@ object SoraExtractor : SoraStream() { } -data class FDMovieIFrame( - val link: String, - val quality: String, - val size: String, - val type: String, -) - -data class BaymoviesConfig( - val country: String, - val downloadTime: String, - val workers: List -) - -data class AniIds( - var id: Int? = null, - var idMal: Int? = null -) - -data class AniMedia( - @JsonProperty("id") var id: Int? = null, - @JsonProperty("idMal") var idMal: Int? = null -) - -data class AniPage( - @JsonProperty("media") var media: java.util.ArrayList = arrayListOf() -) - -data class AniData( - @JsonProperty("Page") var Page: AniPage? = AniPage() -) - -data class AniSearch( - @JsonProperty("data") var data: AniData? = AniData() -) - -data class Tmdb2Anilist( - @JsonProperty("tmdb_id") val tmdb_id: String? = null, - @JsonProperty("anilist_id") val anilist_id: String? = null, - @JsonProperty("mal_id") val mal_id: String? = null, -) - -data class Movie123Media( - @JsonProperty("url") val url: String? = null, -) - -data class Movie123Data( - @JsonProperty("t") val t: String? = null, - @JsonProperty("s") val s: String? = null, -) - -data class Movie123Search( - @JsonProperty("data") val data: ArrayList? = arrayListOf(), -) - -data class GomoviesSources( - @JsonProperty("src") val src: String, - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: Int? = null, - @JsonProperty("max") val max: String, - @JsonProperty("size") val size: String, -) - -data class UHDBackupUrl( - @JsonProperty("url") val url: String? = null, -) - -data class MoviesbayValues( - @JsonProperty("values") val values: List>? = arrayListOf(), -) - -data class HdMovieBoxTracks( - @JsonProperty("label") val label: String? = null, - @JsonProperty("file") val file: String? = null, -) - -data class HdMovieBoxSource( - @JsonProperty("videoUrl") val videoUrl: String? = null, - @JsonProperty("videoServer") val videoServer: String? = null, - @JsonProperty("videoDisk") val videoDisk: Any? = null, - @JsonProperty("tracks") val tracks: ArrayList? = arrayListOf(), -) - -data class HdMovieBoxIframe( - @JsonProperty("api_iframe") val apiIframe: String? = null, -) - -data class ResponseHash( - @JsonProperty("embed_url") val embed_url: String, - @JsonProperty("type") val type: String?, -) - -data class SubtitlingList( - @JsonProperty("languageAbbr") val languageAbbr: String? = null, - @JsonProperty("language") val language: String? = null, - @JsonProperty("subtitlingUrl") val subtitlingUrl: String? = null, -) - -data class DefinitionList( - @JsonProperty("code") val code: String? = null, - @JsonProperty("description") val description: String? = null, -) - -data class EpisodeVo( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("seriesNo") val seriesNo: Int? = null, - @JsonProperty("definitionList") val definitionList: ArrayList? = arrayListOf(), - @JsonProperty("subtitlingList") val subtitlingList: ArrayList? = arrayListOf(), -) - -data class MediaDetail( - @JsonProperty("episodeVo") val episodeVo: ArrayList? = arrayListOf(), -) - -data class Load( - @JsonProperty("data") val data: MediaDetail? = null, -) - -data class KisskhSources( - @JsonProperty("Video") val video: String?, - @JsonProperty("ThirdParty") val thirdParty: String?, -) - -data class KisskhSubtitle( - @JsonProperty("src") val src: String?, - @JsonProperty("label") val label: String?, -) - -data class KisskhEpisodes( - @JsonProperty("id") val id: Int?, - @JsonProperty("number") val number: Int?, -) - -data class KisskhDetail( - @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), -) - -data class KisskhResults( - @JsonProperty("id") val id: Int?, - @JsonProperty("title") val title: String?, -) - -data class EpisodesFwatayako( - @JsonProperty("id") val id: String? = null, - @JsonProperty("file") val file: String? = null, - @JsonProperty("download") val download: HashMap? = hashMapOf(), -) - -data class SeasonFwatayako( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("folder") val folder: ArrayList? = arrayListOf(), -) - -data class SourcesFwatayako( - @JsonProperty("movie") val sourcesMovie: String? = null, - @JsonProperty("tv") val sourcesTv: ArrayList? = arrayListOf(), - @JsonProperty("movie_dl") val movie_dl: HashMap? = hashMapOf(), - @JsonProperty("tv_dl") val tv_dl: ArrayList? = arrayListOf(), -) - -data class DriveBotLink( - @JsonProperty("url") val url: String? = null, -) - -data class DirectDl( - @JsonProperty("download_url") val download_url: String? = null, -) - -data class Safelink( - @JsonProperty("safelink") val safelink: String? = null, -) - -data class FDAds( - @JsonProperty("linkr") val linkr: String? = null, -) - -data class Smashy1Tracks( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, -) - -data class Smashy1Source( - @JsonProperty("file") val file: String? = null, - @JsonProperty("tracks") val tracks: ArrayList? = arrayListOf(), -) - -data class WatchsomuchTorrents( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("movieId") val movieId: Int? = null, - @JsonProperty("season") val season: Int? = null, - @JsonProperty("episode") val episode: Int? = null, -) - -data class WatchsomuchMovies( - @JsonProperty("torrents") val torrents: ArrayList? = arrayListOf(), -) - -data class WatchsomuchResponses( - @JsonProperty("movie") val movie: WatchsomuchMovies? = null, -) - -data class WatchsomuchSubtitles( - @JsonProperty("url") val url: String? = null, - @JsonProperty("label") val label: String? = null, -) - -data class WatchsomuchSubResponses( - @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), -) - -data class IndexMedia( - @JsonProperty("id") val id: String? = null, - @JsonProperty("driveId") val driveId: String? = null, - @JsonProperty("mimeType") val mimeType: String? = null, - @JsonProperty("size") val size: String? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("modifiedTime") val modifiedTime: String? = null, -) - -data class IndexData( - @JsonProperty("files") val files: ArrayList? = arrayListOf(), -) - -data class IndexSearch( - @JsonProperty("data") val data: IndexData? = null, -) - -data class TgarMedia( - @JsonProperty("_id") val _id: Int? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("size") val size: Double? = null, - @JsonProperty("file_unique_id") val file_unique_id: String? = null, - @JsonProperty("mime_type") val mime_type: String? = null, -) - -data class TgarData( - @JsonProperty("documents") val documents: ArrayList? = arrayListOf(), -) - -data class SorastreamResponse( - @JsonProperty("data") val data: SorastreamVideos? = null, -) - -data class SorastreamVideos( - @JsonProperty("mediaUrl") val mediaUrl: String? = null, - @JsonProperty("currentDefinition") val currentDefinition: String? = null, -) - -data class BiliBiliEpisodes( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("sourceId") val sourceId: String? = null, - @JsonProperty("sourceEpisodeId") val sourceEpisodeId: String? = null, - @JsonProperty("sourceMediaId") val sourceMediaId: String? = null, - @JsonProperty("episodeNumber") val episodeNumber: Int? = null, -) - -data class BiliBiliDetails( - @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), -) - -data class BiliBiliSubtitles( - @JsonProperty("file") val file: String? = null, - @JsonProperty("lang") val lang: String? = null, - @JsonProperty("language") val language: String? = null, -) - -data class BiliBiliSources( - @JsonProperty("file") val file: String? = null, - @JsonProperty("type") val type: String? = null, -) - -data class BiliBiliSourcesResponse( - @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), - @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), -) - -data class WatchOnlineItems( - @JsonProperty("slug") val slug: String? = null, - @JsonProperty("tmdb_id") val tmdb_id: Int? = null, - @JsonProperty("imdb_id") val imdb_id: String? = null, -) - -data class WatchOnlineSearch( - @JsonProperty("items") val items: ArrayList? = arrayListOf(), -) - -data class WatchOnlineResponse( - @JsonProperty("streams") val streams: HashMap? = null, - @JsonProperty("subtitles") val subtitles: Any? = null, -) - -data class PutlockerEpisodes( - @JsonProperty("html") val html: String? = null, -) - -data class PutlockerEmbed( - @JsonProperty("src") val src: String? = null, -) - -data class PutlockerSources( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String? = null, - @JsonProperty("type") val type: String? = null, -) - -data class PutlockerResponses( - @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), - @JsonProperty("backupLink") val backupLink: String? = null, -) - -data class ShivamhwSources( - @JsonProperty("id") val id: String? = null, - @JsonProperty("stream_link") val stream_link: String? = null, - @JsonProperty("process_link") val process_link: String? = null, - @JsonProperty("name") val name: String, - @JsonProperty("size") val size: String, -) - -data class CryMoviesProxyHeaders( - @JsonProperty("request") val request: Map?, -) - -data class CryMoviesBehaviorHints( - @JsonProperty("proxyHeaders") val proxyHeaders: CryMoviesProxyHeaders?, -) - -data class CryMoviesStream( - @JsonProperty("title") val title: String? = null, - @JsonProperty("url") val url: String? = null, - @JsonProperty("description") val description: String? = null, - @JsonProperty("behaviorHints") val behaviorHints: CryMoviesBehaviorHints? = null, -) - -data class CryMoviesResponse( - @JsonProperty("streams") val streams: List? = null, -) - -data class DudetvSources( - @JsonProperty("file") val file: String? = null, - @JsonProperty("title") val title: String? = null, -) - -data class FmoviesResponses( - @JsonProperty("result") val result: FmoviesResult? = null, -) - -data class FmoviesResult( - @JsonProperty("html") val html: String? = null, - @JsonProperty("result") val result: String? = null, - @JsonProperty("url") val url: String? = null, -) - -data class FmoviesSubtitles( - @JsonProperty("label") val label: String? = null, - @JsonProperty("file") val file: String? = null, -) - -data class VizcloudSources( - @JsonProperty("file") val file: String? = null, -) - -data class VizcloudMedia( - @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), -) - -data class VizcloudData( - @JsonProperty("media") val media: VizcloudMedia? = null, -) - -data class VizcloudResponses( - @JsonProperty("data") val data: VizcloudData? = null, -) - -data class AnilistExternalLinks( - @JsonProperty("id") var id: Int? = null, - @JsonProperty("site") var site: String? = null, - @JsonProperty("url") var url: String? = null, - @JsonProperty("type") var type: String? = null, -) - -data class AnilistMedia( - @JsonProperty("externalLinks") var externalLinks: ArrayList = arrayListOf() -) - -data class AnilistData( - @JsonProperty("Media") var Media: AnilistMedia? = AnilistMedia() -) - -data class AnilistResponses( - @JsonProperty("data") var data: AnilistData? = AnilistData() -) - -data class CrunchyrollToken( - @JsonProperty("access_token") val accessToken: String? = null, - @JsonProperty("expires_in") val expiresIn: Int? = null, - @JsonProperty("token_type") val tokenType: String? = null, - @JsonProperty("scope") val scope: String? = null, - @JsonProperty("country") val country: String? = null -) - -data class CrunchyrollVersions( - @JsonProperty("audio_locale") val audio_locale: String? = null, - @JsonProperty("guid") val guid: String? = null, -) - -data class CrunchyrollData( - @JsonProperty("id") val id: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("slug_title") val slug_title: String? = null, - @JsonProperty("season_number") val season_number: Int? = null, - @JsonProperty("episode_number") val episode_number: Int? = null, - @JsonProperty("versions") val versions: ArrayList? = null, - @JsonProperty("streams_link") val streams_link: String? = null, - @JsonProperty("adaptive_hls") val adaptive_hls: HashMap>? = hashMapOf(), - @JsonProperty("vo_adaptive_hls") val vo_adaptive_hls: HashMap>? = hashMapOf(), -) - -data class CrunchyrollResponses( - @JsonProperty("data") val data: ArrayList? = arrayListOf(), -) - -data class CrunchyrollMeta( - @JsonProperty("subtitles") val subtitles: HashMap>? = hashMapOf(), -) - -data class CrunchyrollSourcesResponses( - @JsonProperty("data") val data: ArrayList? = arrayListOf(), - @JsonProperty("meta") val meta: CrunchyrollMeta? = null, -) - -data class MALSyncPages( - @JsonProperty("Zoro") val zoro: HashMap>? = hashMapOf(), -) - -data class MALSyncResponses( - @JsonProperty("Pages") val pages: MALSyncPages? = null, -) - -data class ZoroResponses( - @JsonProperty("html") val html: String? = null, - @JsonProperty("link") val link: String? = null, -) - -data class MalSyncRes( - @JsonProperty("Sites") val Sites: Map>>? = null, -) - -data class GokuData( - @JsonProperty("link") val link: String? = null, -) - -data class GokuServer( - @JsonProperty("data") val data: GokuData? = GokuData(), -) - -data class NavyEpisodeFolder( - @JsonProperty("title") val title: String? = null, - @JsonProperty("id") val id: String? = null, - @JsonProperty("file") val file: String? = null, -) - -data class NavySeasonFolder( - @JsonProperty("episode") val episode: String? = null, - @JsonProperty("id") val id: String? = null, - @JsonProperty("folder") val folder: ArrayList? = arrayListOf(), -) - -data class NavyServer( - @JsonProperty("title") val title: String? = null, - @JsonProperty("id") val id: String? = null, - @JsonProperty("file") val file: String? = null, - @JsonProperty("folder") val folder: ArrayList? = arrayListOf(), -) - -data class NavyPlaylist( - @JsonProperty("file") val file: String? = null, - @JsonProperty("key") val key: String? = null, - @JsonProperty("href") val href: String? = null, -) \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt new file mode 100644 index 00000000..49629b5b --- /dev/null +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -0,0 +1,497 @@ +package com.hexated + +import com.fasterxml.jackson.annotation.JsonProperty + +data class FDMovieIFrame( + val link: String, + val quality: String, + val size: String, + val type: String, +) + +data class BaymoviesConfig( + val country: String, + val downloadTime: String, + val workers: List +) + +data class AniIds( + var id: Int? = null, + var idMal: Int? = null +) + +data class AniMedia( + @JsonProperty("id") var id: Int? = null, + @JsonProperty("idMal") var idMal: Int? = null +) + +data class AniPage( + @JsonProperty("media") var media: java.util.ArrayList = arrayListOf() +) + +data class AniData( + @JsonProperty("Page") var Page: AniPage? = AniPage() +) + +data class AniSearch( + @JsonProperty("data") var data: AniData? = AniData() +) + +data class Tmdb2Anilist( + @JsonProperty("tmdb_id") val tmdb_id: String? = null, + @JsonProperty("anilist_id") val anilist_id: String? = null, + @JsonProperty("mal_id") val mal_id: String? = null, +) + +data class Movie123Media( + @JsonProperty("url") val url: String? = null, +) + +data class Movie123Data( + @JsonProperty("t") val t: String? = null, + @JsonProperty("s") val s: String? = null, +) + +data class Movie123Search( + @JsonProperty("data") val data: ArrayList? = arrayListOf(), +) + +data class GomoviesSources( + @JsonProperty("src") val src: String, + @JsonProperty("file") val file: String? = null, + @JsonProperty("label") val label: Int? = null, + @JsonProperty("max") val max: String, + @JsonProperty("size") val size: String, +) + +data class UHDBackupUrl( + @JsonProperty("url") val url: String? = null, +) + +data class MoviesbayValues( + @JsonProperty("values") val values: List>? = arrayListOf(), +) + +data class HdMovieBoxTracks( + @JsonProperty("label") val label: String? = null, + @JsonProperty("file") val file: String? = null, +) + +data class HdMovieBoxSource( + @JsonProperty("videoUrl") val videoUrl: String? = null, + @JsonProperty("videoServer") val videoServer: String? = null, + @JsonProperty("videoDisk") val videoDisk: Any? = null, + @JsonProperty("tracks") val tracks: ArrayList? = arrayListOf(), +) + +data class HdMovieBoxIframe( + @JsonProperty("api_iframe") val apiIframe: String? = null, +) + +data class ResponseHash( + @JsonProperty("embed_url") val embed_url: String, + @JsonProperty("type") val type: String?, +) + +data class KisskhSources( + @JsonProperty("Video") val video: String?, + @JsonProperty("ThirdParty") val thirdParty: String?, +) + +data class KisskhSubtitle( + @JsonProperty("src") val src: String?, + @JsonProperty("label") val label: String?, +) + +data class KisskhEpisodes( + @JsonProperty("id") val id: Int?, + @JsonProperty("number") val number: Int?, +) + +data class KisskhDetail( + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), +) + +data class KisskhResults( + @JsonProperty("id") val id: Int?, + @JsonProperty("title") val title: String?, +) + +data class EpisodesFwatayako( + @JsonProperty("id") val id: String? = null, + @JsonProperty("file") val file: String? = null, + @JsonProperty("download") val download: HashMap? = hashMapOf(), +) + +data class SeasonFwatayako( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("folder") val folder: ArrayList? = arrayListOf(), +) + +data class SourcesFwatayako( + @JsonProperty("movie") val sourcesMovie: String? = null, + @JsonProperty("tv") val sourcesTv: ArrayList? = arrayListOf(), + @JsonProperty("movie_dl") val movie_dl: HashMap? = hashMapOf(), + @JsonProperty("tv_dl") val tv_dl: ArrayList? = arrayListOf(), +) + +data class DriveBotLink( + @JsonProperty("url") val url: String? = null, +) + +data class DirectDl( + @JsonProperty("download_url") val download_url: String? = null, +) + +data class Safelink( + @JsonProperty("safelink") val safelink: String? = null, +) + +data class FDAds( + @JsonProperty("linkr") val linkr: String? = null, +) + +data class Smashy1Tracks( + @JsonProperty("file") val file: String? = null, + @JsonProperty("label") val label: String? = null, +) + +data class Smashy1Source( + @JsonProperty("file") val file: String? = null, + @JsonProperty("tracks") val tracks: ArrayList? = arrayListOf(), +) + +data class WatchsomuchTorrents( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("movieId") val movieId: Int? = null, + @JsonProperty("season") val season: Int? = null, + @JsonProperty("episode") val episode: Int? = null, +) + +data class WatchsomuchMovies( + @JsonProperty("torrents") val torrents: ArrayList? = arrayListOf(), +) + +data class WatchsomuchResponses( + @JsonProperty("movie") val movie: WatchsomuchMovies? = null, +) + +data class WatchsomuchSubtitles( + @JsonProperty("url") val url: String? = null, + @JsonProperty("label") val label: String? = null, +) + +data class WatchsomuchSubResponses( + @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), +) + +data class IndexMedia( + @JsonProperty("id") val id: String? = null, + @JsonProperty("driveId") val driveId: String? = null, + @JsonProperty("mimeType") val mimeType: String? = null, + @JsonProperty("size") val size: String? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("modifiedTime") val modifiedTime: String? = null, +) + +data class IndexData( + @JsonProperty("files") val files: ArrayList? = arrayListOf(), +) + +data class IndexSearch( + @JsonProperty("data") val data: IndexData? = null, +) + +data class TgarMedia( + @JsonProperty("_id") val _id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("size") val size: Double? = null, + @JsonProperty("file_unique_id") val file_unique_id: String? = null, + @JsonProperty("mime_type") val mime_type: String? = null, +) + +data class TgarData( + @JsonProperty("documents") val documents: ArrayList? = arrayListOf(), +) + +data class SorastreamResponse( + @JsonProperty("data") val data: SorastreamVideos? = null, +) + +data class SorastreamVideos( + @JsonProperty("mediaUrl") val mediaUrl: String? = null, + @JsonProperty("currentDefinition") val currentDefinition: String? = null, +) + +data class BiliBiliEpisodes( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("sourceId") val sourceId: String? = null, + @JsonProperty("sourceEpisodeId") val sourceEpisodeId: String? = null, + @JsonProperty("sourceMediaId") val sourceMediaId: String? = null, + @JsonProperty("episodeNumber") val episodeNumber: Int? = null, +) + +data class BiliBiliDetails( + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), +) + +data class BiliBiliSubtitles( + @JsonProperty("file") val file: String? = null, + @JsonProperty("lang") val lang: String? = null, + @JsonProperty("language") val language: String? = null, +) + +data class BiliBiliSources( + @JsonProperty("file") val file: String? = null, + @JsonProperty("type") val type: String? = null, +) + +data class BiliBiliSourcesResponse( + @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), + @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), +) + +data class WatchOnlineItems( + @JsonProperty("slug") val slug: String? = null, + @JsonProperty("tmdb_id") val tmdb_id: Int? = null, + @JsonProperty("imdb_id") val imdb_id: String? = null, +) + +data class WatchOnlineSearch( + @JsonProperty("items") val items: ArrayList? = arrayListOf(), +) + +data class WatchOnlineResponse( + @JsonProperty("streams") val streams: HashMap? = null, + @JsonProperty("subtitles") val subtitles: Any? = null, +) + +data class PutlockerEpisodes( + @JsonProperty("html") val html: String? = null, +) + +data class PutlockerEmbed( + @JsonProperty("src") val src: String? = null, +) + +data class PutlockerSources( + @JsonProperty("file") val file: String, + @JsonProperty("label") val label: String? = null, + @JsonProperty("type") val type: String? = null, +) + +data class PutlockerResponses( + @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), + @JsonProperty("backupLink") val backupLink: String? = null, +) + +data class ShivamhwSources( + @JsonProperty("id") val id: String? = null, + @JsonProperty("stream_link") val stream_link: String? = null, + @JsonProperty("process_link") val process_link: String? = null, + @JsonProperty("name") val name: String, + @JsonProperty("size") val size: String, +) + +data class CryMoviesProxyHeaders( + @JsonProperty("request") val request: Map?, +) + +data class CryMoviesBehaviorHints( + @JsonProperty("proxyHeaders") val proxyHeaders: CryMoviesProxyHeaders?, +) + +data class CryMoviesStream( + @JsonProperty("title") val title: String? = null, + @JsonProperty("url") val url: String? = null, + @JsonProperty("description") val description: String? = null, + @JsonProperty("behaviorHints") val behaviorHints: CryMoviesBehaviorHints? = null, +) + +data class CryMoviesResponse( + @JsonProperty("streams") val streams: List? = null, +) + +data class DudetvSources( + @JsonProperty("file") val file: String? = null, + @JsonProperty("title") val title: String? = null, +) + +data class FmoviesResponses( + @JsonProperty("result") val result: FmoviesResult? = null, +) + +data class FmoviesResult( + @JsonProperty("html") val html: String? = null, + @JsonProperty("result") val result: String? = null, + @JsonProperty("url") val url: String? = null, +) + +data class FmoviesSubtitles( + @JsonProperty("label") val label: String? = null, + @JsonProperty("file") val file: String? = null, +) + +data class VizcloudSources( + @JsonProperty("file") val file: String? = null, +) + +data class VizcloudMedia( + @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), +) + +data class VizcloudData( + @JsonProperty("media") val media: VizcloudMedia? = null, +) + +data class VizcloudResponses( + @JsonProperty("data") val data: VizcloudData? = null, +) + +data class AnilistExternalLinks( + @JsonProperty("id") var id: Int? = null, + @JsonProperty("site") var site: String? = null, + @JsonProperty("url") var url: String? = null, + @JsonProperty("type") var type: String? = null, +) + +data class AnilistMedia( + @JsonProperty("externalLinks") var externalLinks: ArrayList = arrayListOf() +) + +data class AnilistData( + @JsonProperty("Media") var Media: AnilistMedia? = AnilistMedia() +) + +data class AnilistResponses( + @JsonProperty("data") var data: AnilistData? = AnilistData() +) + +data class CrunchyrollToken( + @JsonProperty("access_token") val accessToken: String? = null, + @JsonProperty("expires_in") val expiresIn: Int? = null, + @JsonProperty("token_type") val tokenType: String? = null, + @JsonProperty("scope") val scope: String? = null, + @JsonProperty("country") val country: String? = null +) + +data class CrunchyrollVersions( + @JsonProperty("audio_locale") val audio_locale: String? = null, + @JsonProperty("guid") val guid: String? = null, +) + +data class CrunchyrollData( + @JsonProperty("id") val id: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("slug_title") val slug_title: String? = null, + @JsonProperty("season_number") val season_number: Int? = null, + @JsonProperty("episode_number") val episode_number: Int? = null, + @JsonProperty("versions") val versions: ArrayList? = null, + @JsonProperty("streams_link") val streams_link: String? = null, + @JsonProperty("adaptive_hls") val adaptive_hls: HashMap>? = hashMapOf(), + @JsonProperty("vo_adaptive_hls") val vo_adaptive_hls: HashMap>? = hashMapOf(), +) + +data class CrunchyrollResponses( + @JsonProperty("data") val data: ArrayList? = arrayListOf(), +) + +data class CrunchyrollMeta( + @JsonProperty("subtitles") val subtitles: HashMap>? = hashMapOf(), +) + +data class CrunchyrollSourcesResponses( + @JsonProperty("data") val data: ArrayList? = arrayListOf(), + @JsonProperty("meta") val meta: CrunchyrollMeta? = null, +) + +data class MALSyncPages( + @JsonProperty("Zoro") val zoro: HashMap>? = hashMapOf(), +) + +data class MALSyncResponses( + @JsonProperty("Pages") val pages: MALSyncPages? = null, +) + +data class ZoroResponses( + @JsonProperty("html") val html: String? = null, + @JsonProperty("link") val link: String? = null, +) + +data class MalSyncRes( + @JsonProperty("Sites") val Sites: Map>>? = null, +) + +data class GokuData( + @JsonProperty("link") val link: String? = null, +) + +data class GokuServer( + @JsonProperty("data") val data: GokuData? = GokuData(), +) + +data class NavyEpisodeFolder( + @JsonProperty("title") val title: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("file") val file: String? = null, +) + +data class NavySeasonFolder( + @JsonProperty("episode") val episode: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("folder") val folder: ArrayList? = arrayListOf(), +) + +data class NavyServer( + @JsonProperty("title") val title: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("file") val file: String? = null, + @JsonProperty("folder") val folder: ArrayList? = arrayListOf(), +) + +data class NavyPlaylist( + @JsonProperty("file") val file: String? = null, + @JsonProperty("key") val key: String? = null, + @JsonProperty("href") val href: String? = null, +) + +data class DumpMedia( + @JsonProperty("id") val id: String? = null, + @JsonProperty("domainType") val domainType: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("releaseTime") val releaseTime: String? = null, +) + +data class DumpQuickSearchData( + @JsonProperty("searchResults") val searchResults: ArrayList? = arrayListOf(), +) + +data class DumpQuickSearchRes( + @JsonProperty("data") val data: DumpQuickSearchData? = DumpQuickSearchData(), +) + +data class SubtitlingList( + @JsonProperty("languageAbbr") val languageAbbr: String? = null, + @JsonProperty("language") val language: String? = null, + @JsonProperty("subtitlingUrl") val subtitlingUrl: String? = null, +) + +data class DefinitionList( + @JsonProperty("code") val code: String? = null, + @JsonProperty("description") val description: String? = null, +) + +data class EpisodeVo( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("seriesNo") val seriesNo: Int? = null, + @JsonProperty("definitionList") val definitionList: ArrayList? = arrayListOf(), + @JsonProperty("subtitlingList") val subtitlingList: ArrayList? = arrayListOf(), +) + +data class DumpMediaDetail( + @JsonProperty("episodeVo") val episodeVo: ArrayList? = arrayListOf(), +) + +data class DumpLoad( + @JsonProperty("data") val data: DumpMediaDetail? = null, +) \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index 8b10ef1a..0fe1ed27 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -44,12 +44,11 @@ import com.hexated.SoraExtractor.invokeNowTv import com.hexated.SoraExtractor.invokePutlocker import com.hexated.SoraExtractor.invokeRStream import com.hexated.SoraExtractor.invokeRidomovies -import com.hexated.SoraExtractor.invokeRinzrymovies import com.hexated.SoraExtractor.invokeRubyMovies import com.hexated.SoraExtractor.invokeShinobiMovies import com.hexated.SoraExtractor.invokeShivamhw import com.hexated.SoraExtractor.invokeSmashyStream -import com.hexated.SoraExtractor.invokeSoraStream +import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeTvMovies import com.hexated.SoraExtractor.invokeUhdmovies import com.hexated.SoraExtractor.invokeVitoenMovies @@ -381,7 +380,7 @@ open class SoraStream : TmdbProvider() { argamap( { - invokeSoraStream( + invokeDumpStream( res.title, res.year, res.season, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt index b7b12fdb..46859759 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -26,7 +26,7 @@ import com.hexated.SoraExtractor.invokeRStream import com.hexated.SoraExtractor.invokeRidomovies import com.hexated.SoraExtractor.invokeSeries9 import com.hexated.SoraExtractor.invokeSmashyStream -import com.hexated.SoraExtractor.invokeSoraStream +import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeWatchOnline import com.hexated.SoraExtractor.invokeWatchsomuch @@ -67,7 +67,7 @@ class SoraStreamLite : SoraStream() { ) }, { - invokeSoraStream( + invokeDumpStream( res.title, res.year, res.season, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index e40da8de..cf0d1762 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -2,6 +2,7 @@ package com.hexated import android.util.Base64 import com.fasterxml.jackson.annotation.JsonProperty +import com.hexated.DumpUtils.createHeaders import com.hexated.SoraStream.Companion.anilistAPI import com.hexated.SoraStream.Companion.base64DecodeAPI import com.hexated.SoraStream.Companion.baymoviesAPI @@ -33,10 +34,12 @@ import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody import org.jsoup.nodes.Document +import java.math.BigInteger import java.net.* import java.nio.charset.StandardCharsets -import java.security.MessageDigest -import java.security.SecureRandom +import java.security.* +import java.security.spec.PKCS8EncodedKeySpec +import java.security.spec.X509EncodedKeySpec import java.text.SimpleDateFormat import java.util.* import javax.crypto.Cipher @@ -45,8 +48,6 @@ import javax.crypto.spec.SecretKeySpec import kotlin.collections.ArrayList import kotlin.math.min -val soraAPI = - base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=") val bflixChipperKey = base64DecodeAPI("Yjc=ejM=TzA=YTk=WHE=WnU=bXU=RFo=") const val bflixKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" const val kaguyaBaseUrl = "https://kaguya.app/" @@ -598,55 +599,57 @@ suspend fun invokeSmashyRip( } -suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?): Pair? { - val doc = - app.get("${base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")}/search?keyword=$title").document - val scriptData = doc.select("div.search-list div.search-video-card").map { - Triple( - it.selectFirst("h2.title")?.text().toString(), - it.selectFirst("div.desc")?.text() - ?.substringBefore(".")?.toIntOrNull(), - it.selectFirst("a")?.attr("href")?.split("/") - ) - } +suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair { + val body = mapOf( + "searchKeyWord" to "$title", + "size" to "50", + "sort" to "", + "searchType" to "", + ) + val res = app.post( + "${BuildConfig.DUMP_API}/search/searchWithKeyWord", + requestBody = body.toJson().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()), + headers = createHeaders(body) + ).parsedSafe()?.data?.searchResults - val script = if (scriptData.size == 1) { - scriptData.firstOrNull() + val media = if (res?.size == 1) { + res.firstOrNull() } else { - scriptData.find { + res?.find { when (season) { null -> { - it.first.equals( + it.name.equals( title, true - ) && it.second == year + ) && it.releaseTime == "$year" && it.domainType == 0 } 1 -> { - it.first.contains( + it.name?.contains( "$title", true - ) && (it.second == year || it.first.contains("Season $season", true)) + ) == true && (it.releaseTime == "$year" || it.name.contains("Season $season", true)) && it.domainType == 1 } else -> { - it.first.contains(Regex("(?i)$title\\s?($season|${season.toRomanNumeral()}|Season\\s$season)")) && it.second == year + it.name?.contains(Regex("(?i)$title\\s?($season|${season.toRomanNumeral()}|Season\\s$season)")) == true && it.releaseTime == "$year" && it.domainType == 1 } } } } - val id = script?.third?.last()?.substringBefore("-") ?: return null - val type = script.third?.get(2)?.let { - if (it == "drama") "1" else "0" - } ?: return null + return media?.id to media?.domainType - return id to type } -suspend fun fetchSoraEpisodes(id: String, type: String, episode: Int?): EpisodeVo? { +suspend fun fetchDumpEpisodes(id: String, type: String, episode: Int?): EpisodeVo? { + val params = mapOf( + "category" to type, + "id" to id, + ) return app.get( - "$soraAPI/movieDrama/get?id=${id}&category=${type}", - headers = soraHeaders - ).parsedSafe()?.data?.episodeVo?.find { + "${BuildConfig.DUMP_API}/movieDrama/get", + params = params, + headers = createHeaders(params) + ).parsedSafe()?.data?.episodeVo?.find { it.seriesNo == (episode ?: 0) } } @@ -1403,12 +1406,12 @@ fun getDeviceId(length: Int = 16): String { } suspend fun comsumetEncodeVrf(query: String): String? { - return app.get("$consumetHelper?query=$query&action=fmovies-vrf") + return app.get("$consumetHelper?query=$query&action=fmovies-vrf", timeout = 30L) .parsedSafe>()?.get("url") } suspend fun comsumetDecodeVrf(query: String): String? { - val res = app.get("$consumetHelper?query=$query&action=fmovies-decrypt") + val res = app.get("$consumetHelper?query=$query&action=fmovies-decrypt", timeout = 30L) return tryParseJson>(res.text)?.get("url") } @@ -2048,4 +2051,100 @@ object RabbitStream { @JsonProperty("tracks") val tracks: List? ) +} + +object DumpUtils { + + private val deviceId = getDeviceId() + fun createHeaders( + params: Map, + currentTime: String = System.currentTimeMillis().toString(), + ): Map { + return mapOf( + "lang" to "en", + "currentTime" to currentTime, + "sign" to getSign(currentTime, params, deviceId).toString(), + "aesKey" to getAesKey(deviceId).toString(), + ) + } + + private fun cryptoHandler( + string: String, + secretKeyString: String, + encrypt: Boolean = true + ): String { + val secretKey = SecretKeySpec(secretKeyString.toByteArray(), "AES") + val cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING") + return if (!encrypt) { + cipher.init(Cipher.DECRYPT_MODE, secretKey) + String(cipher.doFinal(base64DecodeArray(string))) + } else { + cipher.init(Cipher.ENCRYPT_MODE, secretKey) + base64Encode(cipher.doFinal(string.toByteArray())) + } + } + + private fun getAesKey(deviceId: String): String? { + val publicKey = RSAEncryptionHelper.getPublicKeyFromString(BuildConfig.DUMP_KEY) ?: return null + return RSAEncryptionHelper.encryptText(deviceId, publicKey) + } + + private fun getSign(currentTime: String, params: Map, deviceId: String): String? { + val chipper = listOf(currentTime, params.map { it.value }.joinToString("")).joinToString("") + val enc = cryptoHandler(chipper, deviceId) + return md5(enc) + } + + private fun md5(input: String): String { + val md = MessageDigest.getInstance("MD5") + return BigInteger(1, md.digest(input.toByteArray())).toString(16).padStart(32, '0') + } + +} + +object RSAEncryptionHelper { + + private const val RSA_ALGORITHM = "RSA" + private const val CIPHER_TYPE_FOR_RSA = "RSA/ECB/PKCS1Padding" + + private val keyFactory = KeyFactory.getInstance(RSA_ALGORITHM) + private val cipher = Cipher.getInstance(CIPHER_TYPE_FOR_RSA) + + fun getPublicKeyFromString(publicKeyString: String): PublicKey? = + try { + val keySpec = + X509EncodedKeySpec(Base64.decode(publicKeyString.toByteArray(), Base64.NO_WRAP)) + keyFactory.generatePublic(keySpec) + } catch (exception: Exception) { + exception.printStackTrace() + null + } + + fun getPrivateKeyFromString(privateKeyString: String): PrivateKey? = + try { + val keySpec = + PKCS8EncodedKeySpec(Base64.decode(privateKeyString.toByteArray(), Base64.DEFAULT)) + keyFactory.generatePrivate(keySpec) + } catch (exception: Exception) { + exception.printStackTrace() + null + } + + fun encryptText(plainText: String, publicKey: PublicKey): String? = + try { + cipher.init(Cipher.ENCRYPT_MODE, publicKey) + Base64.encodeToString(cipher.doFinal(plainText.toByteArray()), Base64.NO_WRAP) + } catch (exception: Exception) { + exception.printStackTrace() + null + } + + fun decryptText(encryptedText: String, privateKey: PrivateKey): String? = + try { + cipher.init(Cipher.DECRYPT_MODE, privateKey) + String(cipher.doFinal(Base64.decode(encryptedText, Base64.DEFAULT))) + } catch (exception: Exception) { + exception.printStackTrace() + null + } } \ No newline at end of file