improve getting links

This commit is contained in:
jmir1 2021-05-02 18:47:04 +02:00
parent d387b8c76f
commit 8423e9e35f
11 changed files with 144 additions and 14 deletions

View file

@ -20,17 +20,20 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.AnimeSourceManager
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.anime.AnimeController import eu.kanade.tachiyomi.ui.anime.AnimeController
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.watcher.WatcherActivity import eu.kanade.tachiyomi.ui.watcher.WatcherActivity
import eu.kanade.tachiyomi.util.lang.awaitSingle
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.runBlocking
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -433,7 +436,8 @@ class NotificationReceiver : BroadcastReceiver() {
* @param episode episode that needs to be opened * @param episode episode that needs to be opened
*/ */
internal fun openEpisodePendingActivity(context: Context, anime: Anime, episode: Episode): PendingIntent { internal fun openEpisodePendingActivity(context: Context, anime: Anime, episode: Episode): PendingIntent {
val newIntent = WatcherActivity.newIntent(context, anime, episode) val source = Injekt.get<AnimeSourceManager>().getOrStub(anime.source)
val newIntent = WatcherActivity.newIntent(context, anime, episode, runBlocking { source.fetchEpisodeLink(episode).awaitSingle() })
return PendingIntent.getActivity(context, anime.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getActivity(context, anime.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT)
} }

View file

@ -37,13 +37,21 @@ interface AnimeSource : tachiyomi.source.AnimeSource {
fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> fun fetchAnimeDetails(anime: SAnime): Observable<SAnime>
/** /**
* Returns an observable with all the available chapters for a anime. * Returns an observable with all the available episodes for an anime.
* *
* @param anime the anime to update. * @param anime the anime to update.
*/ */
@Deprecated("Use getEpisodeList instead") @Deprecated("Use getEpisodeList instead")
fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>>
/**
* Returns an observable with a link for the episode of an anime.
*
* @param episode the episode to get the link for.
*/
@Deprecated("Use getEpisodeList instead")
fun fetchEpisodeLink(episode: SEpisode): Observable<String>
/** /**
* Returns an observable with the list of pages a chapter has. * Returns an observable with the list of pages a chapter has.
* *
@ -64,7 +72,7 @@ interface AnimeSource : tachiyomi.source.AnimeSource {
} }
/** /**
* [1.x API] Get all the available chapters for a anime. * [1.x API] Get all the available episodes for a anime.
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
override suspend fun getEpisodeList(anime: AnimeInfo): List<EpisodeInfo> { override suspend fun getEpisodeList(anime: AnimeInfo): List<EpisodeInfo> {
@ -72,6 +80,14 @@ interface AnimeSource : tachiyomi.source.AnimeSource {
.map { it.toEpisodeInfo() } .map { it.toEpisodeInfo() }
} }
/**
* [1.x API] Get a link for the episode of an anime.
*/
@Suppress("DEPRECATION")
override suspend fun getEpisodeLink(episode: EpisodeInfo): String {
return fetchEpisodeLink(episode.toSEpisode()).awaitSingle()
}
/** /**
* [1.x API] Get the list of pages a chapter has. * [1.x API] Get the list of pages a chapter has.
*/ */

View file

@ -62,6 +62,10 @@ open class AnimeSourceManager(private val context: Context) {
return Observable.error(getSourceNotInstalledException()) return Observable.error(getSourceNotInstalledException())
} }
override fun fetchEpisodeLink(episode: SEpisode): Observable<String> {
return Observable.error(getSourceNotInstalledException())
}
override fun fetchPageList(episode: SEpisode): Observable<List<Page>> { override fun fetchPageList(episode: SEpisode): Observable<List<Page>> {
return Observable.error(getSourceNotInstalledException()) return Observable.error(getSourceNotInstalledException())
} }

View file

@ -203,6 +203,12 @@ class LocalAnimeSource(private val context: Context) : AnimeCatalogueSource {
return Observable.just(episodes) return Observable.just(episodes)
} }
override fun fetchEpisodeLink(episode: SEpisode): Observable<String> {
val link = episode.url
return Observable.just(link)
}
/** /**
* Strips the anime title from a episode name, matching only based on alphanumeric and whitespace * Strips the anime title from a episode name, matching only based on alphanumeric and whitespace
* characters. * characters.

View file

@ -218,6 +218,14 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
} }
} }
override fun fetchEpisodeLink(episode: SEpisode): Observable<String> {
return client.newCall(episodeLinkRequest(episode))
.asObservableSuccess()
.map { response ->
episodeLinkParse(response)
}
}
/** /**
* Returns the request for updating the episode list. Override only if it's needed to override * Returns the request for updating the episode list. Override only if it's needed to override
* the url, send different headers or request method like POST. * the url, send different headers or request method like POST.
@ -228,6 +236,16 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
return GET(baseUrl + anime.url, headers) return GET(baseUrl + anime.url, headers)
} }
/**
* Returns the request for getting the episode link. Override only if it's needed to override
* the url, send different headers or request method like POST.
*
* @param episode the episode to look for links.
*/
protected open fun episodeLinkRequest(episode: SEpisode): Request {
return GET(baseUrl + episode.url, headers)
}
/** /**
* Parses the response from the site and returns a list of episodes. * Parses the response from the site and returns a list of episodes.
* *
@ -235,6 +253,13 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
*/ */
protected abstract fun episodeListParse(response: Response): List<SEpisode> protected abstract fun episodeListParse(response: Response): List<SEpisode>
/**
* Parses the response from the site and returns a list of episodes.
*
* @param response the response from the site.
*/
protected abstract fun episodeLinkParse(response: Response): String
/** /**
* Returns an observable with the page list for a episode. * Returns an observable with the page list for a episode.
* *

View file

@ -159,6 +159,21 @@ abstract class ParsedAnimeHttpSource : AnimeHttpSource() {
*/ */
protected abstract fun episodeListSelector(): String protected abstract fun episodeListSelector(): String
/**
* Parses the response from the site and returns a list of episodes.
*
* @param response the response from the site.
*/
override fun episodeLinkParse(response: Response): String {
val document = response.asJsoup()
return linkFromElement(document.select(episodeLinkSelector()).first())
}
/**
* Returns the Jsoup selector that returns a list of [Element] corresponding to each episode.
*/
protected abstract fun episodeLinkSelector(): String
/** /**
* Returns a episode from the given element. * Returns a episode from the given element.
* *
@ -166,6 +181,13 @@ abstract class ParsedAnimeHttpSource : AnimeHttpSource() {
*/ */
protected abstract fun episodeFromElement(element: Element): SEpisode protected abstract fun episodeFromElement(element: Element): SEpisode
/**
* Returns a episode from the given element.
*
* @param element an element obtained from [episodeListSelector].
*/
protected abstract fun linkFromElement(element: Element): String
/** /**
* Parses the response from the site and returns the page list. * Parses the response from the site and returns the page list.
* *

View file

@ -79,6 +79,9 @@ import eu.kanade.tachiyomi.util.view.shrinkOnScroll
import eu.kanade.tachiyomi.util.view.snack import eu.kanade.tachiyomi.util.view.snack
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.Callback
import reactivecircus.flowbinding.recyclerview.scrollEvents import reactivecircus.flowbinding.recyclerview.scrollEvents
import reactivecircus.flowbinding.swiperefreshlayout.refreshes import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import timber.log.Timber import timber.log.Timber
@ -722,6 +725,14 @@ class AnimeController :
} }
} }
private fun fetchEpisodeLinksFromSource(manualFetch: Boolean = false, episode: Episode): String {
return presenter.fetchEpisodeLinksFromSource(manualFetch, episode)
}
fun onFetchEpisodeLinksError(error: Throwable) {
activity?.toast("no links found")
}
fun onEpisodeDownloadUpdate(download: AnimeDownload) { fun onEpisodeDownloadUpdate(download: AnimeDownload) {
episodesAdapter?.currentItems?.find { it.id == download.episode.id }?.let { episodesAdapter?.currentItems?.find { it.id == download.episode.id }?.let {
episodesAdapter?.updateItem(it, it.status) episodesAdapter?.updateItem(it, it.status)
@ -730,12 +741,17 @@ class AnimeController :
fun openEpisode(episode: Episode, hasAnimation: Boolean = false) { fun openEpisode(episode: Episode, hasAnimation: Boolean = false) {
val activity = activity ?: return val activity = activity ?: return
val intent = WatcherActivity.newIntent(activity, presenter.anime, episode) runBlocking {
launch {
val url = fetchEpisodeLinksFromSource(false, episode)
val intent = WatcherActivity.newIntent(activity, presenter.anime, episode, url)
if (hasAnimation) { if (hasAnimation) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
} }
startActivityForResult(intent, REQUEST_SECONDS) startActivityForResult(intent, REQUEST_SECONDS)
} }
}
}
override fun onItemClick(view: View?, position: Int): Boolean { override fun onItemClick(view: View?, position: Int): Boolean {
val adapter = episodesAdapter ?: return false val adapter = episodesAdapter ?: return false

View file

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.anime
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log
import com.jakewharton.rxrelay.PublishRelay import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.data.cache.AnimeCoverCache import eu.kanade.tachiyomi.data.cache.AnimeCoverCache
import eu.kanade.tachiyomi.data.database.AnimeDatabaseHelper import eu.kanade.tachiyomi.data.database.AnimeDatabaseHelper
@ -19,6 +20,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.source.AnimeSource import eu.kanade.tachiyomi.source.AnimeSource
import eu.kanade.tachiyomi.source.LocalAnimeSource import eu.kanade.tachiyomi.source.LocalAnimeSource
import eu.kanade.tachiyomi.source.model.toEpisodeInfo
import eu.kanade.tachiyomi.source.model.toSAnime import eu.kanade.tachiyomi.source.model.toSAnime
import eu.kanade.tachiyomi.source.model.toSEpisode import eu.kanade.tachiyomi.source.model.toSEpisode
import eu.kanade.tachiyomi.ui.anime.episode.EpisodeItem import eu.kanade.tachiyomi.ui.anime.episode.EpisodeItem
@ -31,10 +33,7 @@ import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
import kotlinx.coroutines.Job import kotlinx.coroutines.*
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.supervisorScope
import rx.Observable import rx.Observable
import rx.Subscription import rx.Subscription
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
@ -43,6 +42,8 @@ import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Date import java.util.Date
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class AnimePresenter( class AnimePresenter(
val anime: Anime, val anime: Anime,
@ -83,6 +84,11 @@ class AnimePresenter(
*/ */
private var fetchEpisodesJob: Job? = null private var fetchEpisodesJob: Job? = null
/**
* Subscription to retrieve the new link of episodes from the source.
*/
private var fetchEpisodeLinksJob: Job? = null
/** /**
* Subscription to observe download status changes. * Subscription to observe download status changes.
*/ */
@ -391,6 +397,28 @@ class AnimePresenter(
} }
} }
/**
* Requests an updated list of episodes from the source.
*/
fun fetchEpisodeLinksFromSource(manualFetch: Boolean = false, episode: Episode): String {
hasRequested = true
var link = runBlocking {
return@runBlocking suspendCoroutine<String> { continuation ->
var link: String
presenterScope.launchIO {
try {
link = source.getEpisodeLink(episode.toEpisodeInfo())
continuation.resume(link)
} catch (e: Throwable) {
withUIContext { view?.onFetchEpisodeLinksError(e) }
}
}
}
}
Log.i("lol", "omg" + link)
return link
}
/** /**
* Updates the UI after applying the filters. * Updates the UI after applying the filters.
*/ */

View file

@ -43,8 +43,8 @@ import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.ToolbarLiftOnScrollController import eu.kanade.tachiyomi.ui.base.controller.ToolbarLiftOnScrollController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.BrowseController import eu.kanade.tachiyomi.ui.browse.BrowseController
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.ui.browse.animesource.browse.BrowseAnimeSourceController import eu.kanade.tachiyomi.ui.browse.animesource.browse.BrowseAnimeSourceController
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
import eu.kanade.tachiyomi.ui.download.DownloadController import eu.kanade.tachiyomi.ui.download.DownloadController
import eu.kanade.tachiyomi.ui.library.LibraryController import eu.kanade.tachiyomi.ui.library.LibraryController

View file

@ -42,6 +42,7 @@ class WatcherActivity : AppCompatActivity() {
setContentView(R.layout.watcher_activity) setContentView(R.layout.watcher_activity)
playerView = findViewById(R.id.player_view) playerView = findViewById(R.id.player_view)
dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, "xyz.jmir.tachiyomi.mi")) dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, "xyz.jmir.tachiyomi.mi"))
Log.i("uri is ", intent.getStringExtra("uri"))
mediaItem = MediaItem.Builder() mediaItem = MediaItem.Builder()
.setUri(intent.getStringExtra("uri")) .setUri(intent.getStringExtra("uri"))
.setMimeType(MimeTypes.VIDEO_MP4) .setMimeType(MimeTypes.VIDEO_MP4)
@ -127,12 +128,13 @@ class WatcherActivity : AppCompatActivity() {
} }
companion object { companion object {
fun newIntent(context: Context, anime: Anime, episode: Episode): Intent { fun newIntent(context: Context, anime: Anime, episode: Episode, url: String): Intent {
return Intent(context, WatcherActivity::class.java).apply { return Intent(context, WatcherActivity::class.java).apply {
putExtra("anime", anime.id) putExtra("anime", anime.id)
putExtra("episode", episode) putExtra("episode", episode)
putExtra("second", episode.last_second_seen) putExtra("second", episode.last_second_seen)
putExtra("uri", episode.url) putExtra("uri", url)
Log.i("bruhh", url)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
} }
} }

View file

@ -36,6 +36,13 @@ interface AnimeSource {
*/ */
suspend fun getEpisodeList(anime: AnimeInfo): List<EpisodeInfo> suspend fun getEpisodeList(anime: AnimeInfo): List<EpisodeInfo>
/**
* Returns an observable with all the available chapters for a anime.
*
* @param anime the anime to update.
*/
suspend fun getEpisodeLink(episode: EpisodeInfo): String
/** /**
* Returns an observable with the list of pages a chapter has. * Returns an observable with the list of pages a chapter has.
* *