diff --git a/.gitmodules b/.gitmodules index 3ba3f3f6..00037939 100644 --- a/.gitmodules +++ b/.gitmodules @@ -100,3 +100,9 @@ [submodule "app/src/unstable/assets/sources/curiositystream"] path = app/src/unstable/assets/sources/curiositystream url = ../plugins/curiositystream.git +[submodule "app/src/unstable/assets/sources/crunchyroll"] + path = app/src/unstable/assets/sources/crunchyroll + url = ../plugins/crunchyroll.git +[submodule "app/src/stable/assets/sources/crunchyroll"] + path = app/src/stable/assets/sources/crunchyroll + url = ../plugins/crunchyroll.git diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt index 84aa2ab6..788fd4c1 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt @@ -71,7 +71,8 @@ class ChannelContentsFragment(private val subType: String? = null) : Fragment(), val lastPolycentricProfile = _lastPolycentricProfile; var pager: IPager? = null; if (lastPolycentricProfile != null && StatePolycentric.instance.enabled) - pager = StatePolycentric.instance.getChannelContent(lifecycleScope, lastPolycentricProfile); + pager = + StatePolycentric.instance.getChannelContent(lifecycleScope, lastPolycentricProfile, type = subType); if(pager == null) { if(subType != null) diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt index 2f33538d..7833b781 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt @@ -732,7 +732,7 @@ class StatePlatform { } } - fun getChannelContent(baseClient: IPlatformClient, channelUrl: String, isSubscriptionOptimized: Boolean = false, usePooledClients: Int = 0): IPager { + fun getChannelContent(baseClient: IPlatformClient, channelUrl: String, isSubscriptionOptimized: Boolean = false, usePooledClients: Int = 0, type: String? = null): IPager { val clientCapabilities = baseClient.getChannelCapabilities(); val client = if(usePooledClients > 1) _channelClientPool.getClientPooled(baseClient, usePooledClients); @@ -741,66 +741,75 @@ class StatePlatform { var lastStream: OffsetDateTime? = null; val pagerResult: IPager; - if(!clientCapabilities.hasType(ResultCapabilities.TYPE_MIXED) && - ( clientCapabilities.hasType(ResultCapabilities.TYPE_VIDEOS) || - clientCapabilities.hasType(ResultCapabilities.TYPE_STREAMS) || - clientCapabilities.hasType(ResultCapabilities.TYPE_LIVE) || - clientCapabilities.hasType(ResultCapabilities.TYPE_POSTS) - )) { - val toQuery = mutableListOf(); - if(clientCapabilities.hasType(ResultCapabilities.TYPE_VIDEOS)) - toQuery.add(ResultCapabilities.TYPE_VIDEOS); - if(clientCapabilities.hasType(ResultCapabilities.TYPE_STREAMS)) - toQuery.add(ResultCapabilities.TYPE_STREAMS); - if(clientCapabilities.hasType(ResultCapabilities.TYPE_LIVE)) - toQuery.add(ResultCapabilities.TYPE_LIVE); - if(clientCapabilities.hasType(ResultCapabilities.TYPE_POSTS)) - toQuery.add(ResultCapabilities.TYPE_POSTS); + if (type == null) { + if(!clientCapabilities.hasType(ResultCapabilities.TYPE_MIXED) && + ( clientCapabilities.hasType(ResultCapabilities.TYPE_VIDEOS) || + clientCapabilities.hasType(ResultCapabilities.TYPE_STREAMS) || + clientCapabilities.hasType(ResultCapabilities.TYPE_LIVE) || + clientCapabilities.hasType(ResultCapabilities.TYPE_POSTS) + )) { + val toQuery = mutableListOf(); + if(clientCapabilities.hasType(ResultCapabilities.TYPE_VIDEOS)) + toQuery.add(ResultCapabilities.TYPE_VIDEOS); + if(clientCapabilities.hasType(ResultCapabilities.TYPE_STREAMS)) + toQuery.add(ResultCapabilities.TYPE_STREAMS); + if(clientCapabilities.hasType(ResultCapabilities.TYPE_LIVE)) + toQuery.add(ResultCapabilities.TYPE_LIVE); + if(clientCapabilities.hasType(ResultCapabilities.TYPE_POSTS)) + toQuery.add(ResultCapabilities.TYPE_POSTS); - if(isSubscriptionOptimized) { - val sub = StateSubscriptions.instance.getSubscription(channelUrl); - if(sub != null) { - if(!sub.shouldFetchStreams()) { - Logger.i(TAG, "Subscription [${sub.channel.name}:${channelUrl}] Last livestream > 7 days, skipping live streams [${sub.lastLiveStream.getNowDiffDays()} days ago]"); - toQuery.remove(ResultCapabilities.TYPE_LIVE); - } - if(!sub.shouldFetchLiveStreams()) { - Logger.i(TAG, "Subscription [${sub.channel.name}:${channelUrl}] Last livestream > 15 days, skipping streams [${sub.lastLiveStream.getNowDiffDays()} days ago]"); - toQuery.remove(ResultCapabilities.TYPE_STREAMS); - } - if(!sub.shouldFetchPosts()) { - Logger.i(TAG, "Subscription [${sub.channel.name}:${channelUrl}] Last livestream > 5 days, skipping posts [${sub.lastPost.getNowDiffDays()} days ago]"); - toQuery.remove(ResultCapabilities.TYPE_POSTS); - } - } - } - - //Merged pager - val pagers = toQuery - .parallelStream() - .map { - val results = client.getChannelContents(channelUrl, it, ResultCapabilities.ORDER_CHONOLOGICAL) ; - - when(it) { - ResultCapabilities.TYPE_STREAMS -> { - val streamResults = results.getResults(); - if(streamResults.size == 0) - lastStream = OffsetDateTime.MIN; - else - lastStream = results.getResults().firstOrNull()?.datetime; + if(isSubscriptionOptimized) { + val sub = StateSubscriptions.instance.getSubscription(channelUrl); + if(sub != null) { + if(!sub.shouldFetchStreams()) { + Logger.i(TAG, "Subscription [${sub.channel.name}:${channelUrl}] Last livestream > 7 days, skipping live streams [${sub.lastLiveStream.getNowDiffDays()} days ago]"); + toQuery.remove(ResultCapabilities.TYPE_LIVE); + } + if(!sub.shouldFetchLiveStreams()) { + Logger.i(TAG, "Subscription [${sub.channel.name}:${channelUrl}] Last livestream > 15 days, skipping streams [${sub.lastLiveStream.getNowDiffDays()} days ago]"); + toQuery.remove(ResultCapabilities.TYPE_STREAMS); + } + if(!sub.shouldFetchPosts()) { + Logger.i(TAG, "Subscription [${sub.channel.name}:${channelUrl}] Last livestream > 5 days, skipping posts [${sub.lastPost.getNowDiffDays()} days ago]"); + toQuery.remove(ResultCapabilities.TYPE_POSTS); } } - return@map results; } - .asSequence() - .toList(); - val pager = MultiChronoContentPager(pagers.toTypedArray()); - pager.initialize(); - pagerResult = pager; + //Merged pager + val pagers = toQuery + .parallelStream() + .map { + val results = client.getChannelContents(channelUrl, it, ResultCapabilities.ORDER_CHONOLOGICAL) ; + + when(it) { + ResultCapabilities.TYPE_STREAMS -> { + val streamResults = results.getResults(); + if(streamResults.size == 0) + lastStream = OffsetDateTime.MIN; + else + lastStream = results.getResults().firstOrNull()?.datetime; + } + } + return@map results; + } + .asSequence() + .toList(); + + val pager = MultiChronoContentPager(pagers.toTypedArray()); + pager.initialize(); + pagerResult = pager; + } + else { + pagerResult = client.getChannelContents(channelUrl, ResultCapabilities.TYPE_MIXED, ResultCapabilities.ORDER_CHONOLOGICAL); + } + } else { + pagerResult = if (type == ResultCapabilities.TYPE_SHORTS && clientCapabilities.hasType(ResultCapabilities.TYPE_SHORTS)) { + client.getChannelContents(channelUrl, ResultCapabilities.TYPE_SHORTS, ResultCapabilities.ORDER_CHONOLOGICAL); + } else { + EmptyPager() + } } - else - pagerResult = client.getChannelContents(channelUrl, ResultCapabilities.TYPE_MIXED, ResultCapabilities.ORDER_CHONOLOGICAL); //Subscription optimization val sub = StateSubscriptions.instance.getSubscription(channelUrl); @@ -852,10 +861,10 @@ class StatePlatform { return pagerResult; } - fun getChannelContent(channelUrl: String, isSubscriptionOptimized: Boolean = false, usePooledClients: Int = 0, ignorePlugins: List? = null): IPager { + fun getChannelContent(channelUrl: String, isSubscriptionOptimized: Boolean = false, usePooledClients: Int = 0, ignorePlugins: List? = null, type: String? = null): IPager { Logger.i(TAG, "Platform - getChannelVideos"); val baseClient = getChannelClient(channelUrl, ignorePlugins); - return getChannelContent(baseClient, channelUrl, isSubscriptionOptimized, usePooledClients); + return getChannelContent(baseClient, channelUrl, isSubscriptionOptimized, usePooledClients, type); } fun getChannelContent(channelUrl: String, type: String?, ordering: String = ResultCapabilities.ORDER_CHONOLOGICAL): IPager { val client = getChannelClient(channelUrl); diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt b/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt index 9d6f7437..86ae541a 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt @@ -236,7 +236,7 @@ class StatePolycentric { return Pair(didUpdate, listOf(url)); } - fun getChannelContent(scope: CoroutineScope, profile: PolycentricProfile, isSubscriptionOptimized: Boolean = false, channelConcurrency: Int = -1): IPager? { + fun getChannelContent(scope: CoroutineScope, profile: PolycentricProfile, isSubscriptionOptimized: Boolean = false, channelConcurrency: Int = -1, type: String? = null): IPager? { ensureEnabled() //TODO: Currently abusing subscription concurrency for parallelism @@ -248,7 +248,11 @@ class StatePolycentric { return@mapNotNull Pair(client, scope.async(Dispatchers.IO) { try { - return@async StatePlatform.instance.getChannelContent(url, isSubscriptionOptimized, concurrency); + if (type == null) { + return@async StatePlatform.instance.getChannelContent(url, isSubscriptionOptimized, concurrency); + } else { + return@async StatePlatform.instance.getChannelContent(url, isSubscriptionOptimized, concurrency, type = type); + } } catch (ex: Throwable) { Logger.e(TAG, "getChannelContent", ex); return@async null; diff --git a/app/src/stable/assets/sources/crunchyroll b/app/src/stable/assets/sources/crunchyroll new file mode 160000 index 00000000..1aa91f21 --- /dev/null +++ b/app/src/stable/assets/sources/crunchyroll @@ -0,0 +1 @@ +Subproject commit 1aa91f216c0a87604aed1669b63b7830e4288630 diff --git a/app/src/stable/res/raw/plugin_config.json b/app/src/stable/res/raw/plugin_config.json index 4dea0f2e..ce535388 100644 --- a/app/src/stable/res/raw/plugin_config.json +++ b/app/src/stable/res/raw/plugin_config.json @@ -15,7 +15,8 @@ "e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json", "89ae4889-0420-4d16-ad6c-19c776b28f99": "sources/apple-podcasts/ApplePodcastsConfig.json", "8d029a7f-5507-4e36-8bd8-c19a3b77d383": "sources/tedtalks/TedTalksConfig.json", - "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json" + "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json", + "9bb33039-8580-48d4-9849-21319ae845a4": "sources/crunchyroll/CrunchyrollConfig.json" }, "SOURCES_EMBEDDED_DEFAULT": [ "35ae969a-a7db-11ed-afa1-0242ac120002" diff --git a/app/src/unstable/assets/sources/crunchyroll b/app/src/unstable/assets/sources/crunchyroll new file mode 160000 index 00000000..1aa91f21 --- /dev/null +++ b/app/src/unstable/assets/sources/crunchyroll @@ -0,0 +1 @@ +Subproject commit 1aa91f216c0a87604aed1669b63b7830e4288630 diff --git a/app/src/unstable/res/raw/plugin_config.json b/app/src/unstable/res/raw/plugin_config.json index 40b10e11..5abe547e 100644 --- a/app/src/unstable/res/raw/plugin_config.json +++ b/app/src/unstable/res/raw/plugin_config.json @@ -15,7 +15,8 @@ "e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json", "89ae4889-0420-4d16-ad6c-19c776b28f99": "sources/apple-podcasts/ApplePodcastsConfig.json", "8d029a7f-5507-4e36-8bd8-c19a3b77d383": "sources/tedtalks/TedTalksConfig.json", - "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json" + "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json", + "9bb33039-8580-48d4-9849-21319ae845a4": "sources/crunchyroll/CrunchyrollConfig.json" }, "SOURCES_EMBEDDED_DEFAULT": [ "35ae969a-a7db-11ed-afa1-0242ac120002"