forked from recloudstream/cloudstream
added download subtitles option and fixed subtitle download
This commit is contained in:
parent
d5a4a65ced
commit
10c945f497
6 changed files with 257 additions and 139 deletions
|
@ -71,6 +71,9 @@ class DownloadFileGenerator(
|
||||||
.removeSuffix(".vtt")
|
.removeSuffix(".vtt")
|
||||||
.removeSuffix(".srt")
|
.removeSuffix(".srt")
|
||||||
.removeSuffix(".txt")
|
.removeSuffix(".txt")
|
||||||
|
.trim()
|
||||||
|
.removePrefix("(")
|
||||||
|
.removeSuffix(")")
|
||||||
|
|
||||||
subtitleCallback(
|
subtitleCallback(
|
||||||
SubtitleData(
|
SubtitleData(
|
||||||
|
|
|
@ -48,6 +48,9 @@ const val ACTION_SHOW_OPTIONS = 10
|
||||||
const val ACTION_CLICK_DEFAULT = 11
|
const val ACTION_CLICK_DEFAULT = 11
|
||||||
const val ACTION_SHOW_TOAST = 12
|
const val ACTION_SHOW_TOAST = 12
|
||||||
|
|
||||||
|
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE = 13
|
||||||
|
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14
|
||||||
|
|
||||||
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
||||||
|
|
||||||
class EpisodeAdapter(
|
class EpisodeAdapter(
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.Context.CLIPBOARD_SERVICE
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.Intent.*
|
import android.content.Intent.*
|
||||||
|
@ -43,7 +44,6 @@ import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
import com.lagradost.cloudstream3.APIHolder.getId
|
import com.lagradost.cloudstream3.APIHolder.getId
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
|
@ -70,6 +70,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.isConnectedToChromecast
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||||
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getFolderName
|
import com.lagradost.cloudstream3.utils.DataStore.getFolderName
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
|
@ -88,6 +89,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.setImageBlur
|
import com.lagradost.cloudstream3.utils.UIHelper.setImageBlur
|
||||||
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getFileName
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||||
|
@ -205,7 +207,80 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
||||||
|
|
||||||
private var updateUIListener: (() -> Unit)? = null
|
private var updateUIListener: (() -> Unit)? = null
|
||||||
|
|
||||||
suspend fun startDownload(
|
private fun downloadSubtitle(
|
||||||
|
context: Context?,
|
||||||
|
link: SubtitleData,
|
||||||
|
meta: VideoDownloadManager.DownloadEpisodeMetadata,
|
||||||
|
) {
|
||||||
|
context?.let { ctx ->
|
||||||
|
val fileName = getFileName(ctx, meta)
|
||||||
|
val folder = getFolder(meta.type ?: return, meta.mainName)
|
||||||
|
downloadSubtitle(
|
||||||
|
ctx,
|
||||||
|
ExtractorSubtitleLink(link.name, link.url, ""),
|
||||||
|
fileName,
|
||||||
|
folder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadSubtitle(
|
||||||
|
context: Context?,
|
||||||
|
link: ExtractorSubtitleLink,
|
||||||
|
fileName: String,
|
||||||
|
folder: String
|
||||||
|
) {
|
||||||
|
ioSafe {
|
||||||
|
VideoDownloadManager.downloadThing(
|
||||||
|
context ?: return@ioSafe,
|
||||||
|
link,
|
||||||
|
"$fileName ${link.name}",
|
||||||
|
folder,
|
||||||
|
if (link.url.contains(".srt")) ".srt" else "vtt",
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
) {
|
||||||
|
// no notification
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMeta(
|
||||||
|
episode: ResultEpisode,
|
||||||
|
titleName: String,
|
||||||
|
apiName: String,
|
||||||
|
currentPoster: String,
|
||||||
|
currentIsMovie: Boolean,
|
||||||
|
tvType: TvType,
|
||||||
|
): VideoDownloadManager.DownloadEpisodeMetadata {
|
||||||
|
return VideoDownloadManager.DownloadEpisodeMetadata(
|
||||||
|
episode.id,
|
||||||
|
sanitizeFilename(titleName),
|
||||||
|
apiName,
|
||||||
|
episode.poster ?: currentPoster,
|
||||||
|
episode.name,
|
||||||
|
if (currentIsMovie) null else episode.season,
|
||||||
|
if (currentIsMovie) null else episode.episode,
|
||||||
|
tvType,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFolder(currentType: TvType, titleName: String): String {
|
||||||
|
return when (currentType) {
|
||||||
|
TvType.Anime -> "Anime/$titleName"
|
||||||
|
TvType.Movie -> "Movies"
|
||||||
|
TvType.AnimeMovie -> "Movies"
|
||||||
|
TvType.TvSeries -> "TVSeries/$titleName"
|
||||||
|
TvType.OVA -> "OVA"
|
||||||
|
TvType.Cartoon -> "Cartoons/$titleName"
|
||||||
|
TvType.Torrent -> "Torrent"
|
||||||
|
TvType.Documentary -> "Documentaries"
|
||||||
|
TvType.AsianDrama -> "AsianDrama"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startDownload(
|
||||||
|
context: Context?,
|
||||||
episode: ResultEpisode,
|
episode: ResultEpisode,
|
||||||
currentIsMovie: Boolean,
|
currentIsMovie: Boolean,
|
||||||
currentHeaderName: String,
|
currentHeaderName: String,
|
||||||
|
@ -217,110 +292,87 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
||||||
links: List<ExtractorLink>,
|
links: List<ExtractorLink>,
|
||||||
subs: List<SubtitleData>?
|
subs: List<SubtitleData>?
|
||||||
) {
|
) {
|
||||||
val titleName = sanitizeFilename(currentHeaderName)
|
try {
|
||||||
|
if (context == null) return
|
||||||
|
|
||||||
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
|
val meta =
|
||||||
episode.id,
|
getMeta(
|
||||||
titleName,
|
episode,
|
||||||
apiName,
|
currentHeaderName,
|
||||||
episode.poster ?: currentPoster,
|
apiName,
|
||||||
episode.name,
|
currentPoster,
|
||||||
if (currentIsMovie) null else episode.season,
|
currentIsMovie,
|
||||||
if (currentIsMovie) null else episode.episode
|
currentType
|
||||||
)
|
|
||||||
|
|
||||||
val folder = when (currentType) {
|
|
||||||
TvType.Anime -> "Anime/$titleName"
|
|
||||||
TvType.Movie -> "Movies"
|
|
||||||
TvType.AnimeMovie -> "Movies"
|
|
||||||
TvType.TvSeries -> "TVSeries/$titleName"
|
|
||||||
TvType.OVA -> "OVA"
|
|
||||||
TvType.Cartoon -> "Cartoons/$titleName"
|
|
||||||
TvType.Torrent -> "Torrent"
|
|
||||||
TvType.Documentary -> "Documentaries"
|
|
||||||
TvType.AsianDrama -> "AsianDrama"
|
|
||||||
}
|
|
||||||
|
|
||||||
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
|
|
||||||
|
|
||||||
// SET VISUAL KEYS
|
|
||||||
setKey(
|
|
||||||
DOWNLOAD_HEADER_CACHE,
|
|
||||||
parentId.toString(),
|
|
||||||
VideoDownloadHelper.DownloadHeaderCached(
|
|
||||||
apiName,
|
|
||||||
url,
|
|
||||||
currentType,
|
|
||||||
currentHeaderName,
|
|
||||||
currentPoster,
|
|
||||||
parentId,
|
|
||||||
System.currentTimeMillis(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
setKey(
|
|
||||||
getFolderName(
|
|
||||||
DOWNLOAD_EPISODE_CACHE,
|
|
||||||
parentId.toString()
|
|
||||||
), // 3 deep folder for faster acess
|
|
||||||
episode.id.toString(),
|
|
||||||
VideoDownloadHelper.DownloadEpisodeCached(
|
|
||||||
episode.name,
|
|
||||||
episode.poster,
|
|
||||||
episode.episode,
|
|
||||||
episode.season,
|
|
||||||
episode.id,
|
|
||||||
parentId,
|
|
||||||
episode.rating,
|
|
||||||
episode.description,
|
|
||||||
System.currentTimeMillis(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// DOWNLOAD VIDEO
|
|
||||||
VideoDownloadManager.downloadEpisodeUsingWorker(
|
|
||||||
context ?: return,
|
|
||||||
src,//url ?: return,
|
|
||||||
folder,
|
|
||||||
meta,
|
|
||||||
links
|
|
||||||
)
|
|
||||||
// 1. Checks if the lang should be downloaded
|
|
||||||
// 2. Makes it into the download format
|
|
||||||
// 3. Downloads it as a .vtt file
|
|
||||||
val downloadList = getDownloadSubsLanguageISO639_1()
|
|
||||||
subs?.let { subsList ->
|
|
||||||
subsList.filter {
|
|
||||||
downloadList.contains(
|
|
||||||
SubtitleHelper.fromLanguageToTwoLetters(
|
|
||||||
it.name,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
|
||||||
.map { ExtractorSubtitleLink(it.name, it.url, "") }
|
|
||||||
.forEach { link ->
|
|
||||||
val epName = meta.name
|
|
||||||
?: "${context?.getString(R.string.episode)} ${meta.episode}"
|
|
||||||
val fileName =
|
|
||||||
sanitizeFilename(epName + if (downloadList.size > 1) " ${link.name}" else "")
|
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
val folder = getFolder(currentType, currentHeaderName)
|
||||||
normalSafeApiCall {
|
|
||||||
VideoDownloadManager.downloadThing(
|
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
|
||||||
context ?: return@normalSafeApiCall,
|
|
||||||
link,
|
// SET VISUAL KEYS
|
||||||
fileName,
|
setKey(
|
||||||
folder,
|
DOWNLOAD_HEADER_CACHE,
|
||||||
"vtt",
|
parentId.toString(),
|
||||||
false,
|
VideoDownloadHelper.DownloadHeaderCached(
|
||||||
null
|
apiName,
|
||||||
) {
|
url,
|
||||||
// no notification
|
currentType,
|
||||||
}
|
currentHeaderName,
|
||||||
}
|
currentPoster,
|
||||||
}
|
parentId,
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
setKey(
|
||||||
|
getFolderName(
|
||||||
|
DOWNLOAD_EPISODE_CACHE,
|
||||||
|
parentId.toString()
|
||||||
|
), // 3 deep folder for faster acess
|
||||||
|
episode.id.toString(),
|
||||||
|
VideoDownloadHelper.DownloadEpisodeCached(
|
||||||
|
episode.name,
|
||||||
|
episode.poster,
|
||||||
|
episode.episode,
|
||||||
|
episode.season,
|
||||||
|
episode.id,
|
||||||
|
parentId,
|
||||||
|
episode.rating,
|
||||||
|
episode.description,
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// DOWNLOAD VIDEO
|
||||||
|
VideoDownloadManager.downloadEpisodeUsingWorker(
|
||||||
|
context,
|
||||||
|
src,//url ?: return,
|
||||||
|
folder,
|
||||||
|
meta,
|
||||||
|
links
|
||||||
|
)
|
||||||
|
|
||||||
|
// 1. Checks if the lang should be downloaded
|
||||||
|
// 2. Makes it into the download format
|
||||||
|
// 3. Downloads it as a .vtt file
|
||||||
|
val downloadList = getDownloadSubsLanguageISO639_1()
|
||||||
|
subs?.let { subsList ->
|
||||||
|
subsList.filter {
|
||||||
|
downloadList.contains(
|
||||||
|
SubtitleHelper.fromLanguageToTwoLetters(
|
||||||
|
it.name,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
.map { ExtractorSubtitleLink(it.name, it.url, "") }
|
||||||
|
.forEach { link ->
|
||||||
|
val fileName = getFileName(context, meta)
|
||||||
|
downloadSubtitle(context, link, fileName, folder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,6 +405,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
||||||
}
|
}
|
||||||
|
|
||||||
startDownload(
|
startDownload(
|
||||||
|
activity,
|
||||||
episode,
|
episode,
|
||||||
currentIsMovie,
|
currentIsMovie,
|
||||||
currentHeaderName,
|
currentHeaderName,
|
||||||
|
@ -737,6 +790,21 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
||||||
builder.create().show()
|
builder.create().show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun acquireSingleSubtitleLink(
|
||||||
|
links: List<SubtitleData>,
|
||||||
|
title: String,
|
||||||
|
callback: (SubtitleData) -> Unit
|
||||||
|
) {
|
||||||
|
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
|
||||||
|
|
||||||
|
builder.setTitle(title)
|
||||||
|
builder.setItems(links.map { it.name }.toTypedArray()) { dia, which ->
|
||||||
|
callback.invoke(links[which])
|
||||||
|
dia?.dismiss()
|
||||||
|
}
|
||||||
|
builder.create().show()
|
||||||
|
}
|
||||||
|
|
||||||
fun acquireSingeExtractorLink(title: String, callback: (ExtractorLink) -> Unit) {
|
fun acquireSingeExtractorLink(title: String, callback: (ExtractorLink) -> Unit) {
|
||||||
acquireSingleExtractorLink(sortUrls(currentLinks ?: return), title, callback)
|
acquireSingleExtractorLink(sortUrls(currentLinks ?: return), title, callback)
|
||||||
}
|
}
|
||||||
|
@ -839,6 +907,29 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACTION_DOWNLOAD_EPISODE_SUBTITLE -> {
|
||||||
|
acquireSingleSubtitleLink(
|
||||||
|
sortSubs(
|
||||||
|
currentSubs ?: return@main
|
||||||
|
),//(currentLinks ?: return@main).filter { !it.isM3u8 },
|
||||||
|
getString(R.string.episode_action_download_subtitle)
|
||||||
|
) { link ->
|
||||||
|
downloadSubtitle(
|
||||||
|
context,
|
||||||
|
link,
|
||||||
|
getMeta(
|
||||||
|
episodeClick.data,
|
||||||
|
currentHeaderName ?: return@acquireSingleSubtitleLink,
|
||||||
|
apiName,
|
||||||
|
currentPoster ?: return@acquireSingleSubtitleLink,
|
||||||
|
currentIsMovie ?: return@acquireSingleSubtitleLink,
|
||||||
|
currentType ?: return@acquireSingleSubtitleLink
|
||||||
|
)
|
||||||
|
)
|
||||||
|
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ACTION_SHOW_OPTIONS -> {
|
ACTION_SHOW_OPTIONS -> {
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
val builder = AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
val builder = AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
||||||
|
@ -862,6 +953,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
||||||
val add = when (opv) {
|
val add = when (opv) {
|
||||||
ACTION_CHROME_CAST_EPISODE -> isConnected
|
ACTION_CHROME_CAST_EPISODE -> isConnected
|
||||||
ACTION_CHROME_CAST_MIRROR -> isConnected
|
ACTION_CHROME_CAST_MIRROR -> isConnected
|
||||||
|
ACTION_DOWNLOAD_EPISODE_SUBTITLE -> !currentSubs.isNullOrEmpty()
|
||||||
ACTION_DOWNLOAD_EPISODE -> hasDownloadSupport
|
ACTION_DOWNLOAD_EPISODE -> hasDownloadSupport
|
||||||
ACTION_DOWNLOAD_MIRROR -> hasDownloadSupport
|
ACTION_DOWNLOAD_MIRROR -> hasDownloadSupport
|
||||||
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> context?.isAppInstalled(
|
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> context?.isAppInstalled(
|
||||||
|
@ -1015,21 +1107,20 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
||||||
),//(currentLinks ?: return@main).filter { !it.isM3u8 },
|
),//(currentLinks ?: return@main).filter { !it.isM3u8 },
|
||||||
getString(R.string.episode_action_download_mirror)
|
getString(R.string.episode_action_download_mirror)
|
||||||
) { link ->
|
) { link ->
|
||||||
main {
|
startDownload(
|
||||||
startDownload(
|
context,
|
||||||
episodeClick.data,
|
episodeClick.data,
|
||||||
currentIsMovie ?: return@main,
|
currentIsMovie ?: return@acquireSingleExtractorLink,
|
||||||
currentHeaderName ?: return@main,
|
currentHeaderName ?: return@acquireSingleExtractorLink,
|
||||||
currentType ?: return@main,
|
currentType ?: return@acquireSingleExtractorLink,
|
||||||
currentPoster ?: return@main,
|
currentPoster ?: return@acquireSingleExtractorLink,
|
||||||
apiName,
|
apiName,
|
||||||
currentId ?: return@main,
|
currentId ?: return@acquireSingleExtractorLink,
|
||||||
url ?: return@main,
|
url ?: return@acquireSingleExtractorLink,
|
||||||
listOf(link),
|
listOf(link),
|
||||||
sortSubs(currentSubs ?: return@main)
|
sortSubs(currentSubs ?: return@acquireSingleExtractorLink),
|
||||||
)
|
)
|
||||||
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT)
|
showToast(activity, R.string.download_started, Toast.LENGTH_SHORT)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.MainActivity
|
import com.lagradost.cloudstream3.MainActivity
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.services.VideoDownloadService
|
import com.lagradost.cloudstream3.services.VideoDownloadService
|
||||||
|
@ -116,7 +117,8 @@ object VideoDownloadManager {
|
||||||
@JsonProperty("poster") val poster: String?,
|
@JsonProperty("poster") val poster: String?,
|
||||||
@JsonProperty("name") val name: String?,
|
@JsonProperty("name") val name: String?,
|
||||||
@JsonProperty("season") val season: Int?,
|
@JsonProperty("season") val season: Int?,
|
||||||
@JsonProperty("episode") val episode: Int?
|
@JsonProperty("episode") val episode: Int?,
|
||||||
|
@JsonProperty("type") val type: TvType?,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class DownloadItem(
|
data class DownloadItem(
|
||||||
|
@ -1335,6 +1337,33 @@ object VideoDownloadManager {
|
||||||
return SUCCESS_DOWNLOAD_DONE
|
return SUCCESS_DOWNLOAD_DONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getFileName(context: Context, metadata: DownloadEpisodeMetadata): String {
|
||||||
|
return getFileName(context, metadata.name, metadata.episode, metadata.season)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFileName(context: Context, epName: String?, episode: Int?, season: Int?): String {
|
||||||
|
// kinda ugly ik
|
||||||
|
return sanitizeFilename(
|
||||||
|
if (epName == null) {
|
||||||
|
if (season != null) {
|
||||||
|
"${context.getString(R.string.season)} $season ${context.getString(R.string.episode)} $episode"
|
||||||
|
} else {
|
||||||
|
"${context.getString(R.string.episode)} $episode"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (episode != null) {
|
||||||
|
if (season != null) {
|
||||||
|
"${context.getString(R.string.season)} $season ${context.getString(R.string.episode)} $episode - $epName"
|
||||||
|
} else {
|
||||||
|
"${context.getString(R.string.episode)} $episode - $epName"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
epName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun downloadSingleEpisode(
|
private fun downloadSingleEpisode(
|
||||||
context: Context,
|
context: Context,
|
||||||
source: String?,
|
source: String?,
|
||||||
|
@ -1344,19 +1373,7 @@ object VideoDownloadManager {
|
||||||
notificationCallback: (Int, Notification) -> Unit,
|
notificationCallback: (Int, Notification) -> Unit,
|
||||||
tryResume: Boolean = false,
|
tryResume: Boolean = false,
|
||||||
): Int {
|
): Int {
|
||||||
val name =
|
val name = getFileName(context, ep)
|
||||||
// kinda ugly ik
|
|
||||||
sanitizeFilename(
|
|
||||||
if (ep.name == null) {
|
|
||||||
"${context.getString(R.string.episode)} ${ep.episode}"
|
|
||||||
} else {
|
|
||||||
if (ep.episode != null) {
|
|
||||||
"${context.getString(R.string.episode)} ${ep.episode} - ${ep.name}"
|
|
||||||
} else {
|
|
||||||
ep.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Make sure this is cancelled when download is done or cancelled.
|
// Make sure this is cancelled when download is done or cancelled.
|
||||||
val extractorJob = ioSafe {
|
val extractorJob = ioSafe {
|
||||||
|
|
|
@ -150,8 +150,10 @@
|
||||||
<item>@string/episode_action_copy_link</item>
|
<item>@string/episode_action_copy_link</item>
|
||||||
<item>@string/episode_action_auto_download</item>
|
<item>@string/episode_action_auto_download</item>
|
||||||
<item>@string/episode_action_download_mirror</item>
|
<item>@string/episode_action_download_mirror</item>
|
||||||
|
<item>@string/episode_action_download_subtitle</item>
|
||||||
<item>@string/episode_action_reload_links</item>
|
<item>@string/episode_action_reload_links</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<array name="episode_long_click_options_values">
|
<array name="episode_long_click_options_values">
|
||||||
<item>4</item>
|
<item>4</item>
|
||||||
<item>5</item>
|
<item>5</item>
|
||||||
|
@ -161,6 +163,7 @@
|
||||||
<item>9</item>
|
<item>9</item>
|
||||||
<item>6</item>
|
<item>6</item>
|
||||||
<item>7</item>
|
<item>7</item>
|
||||||
|
<item>13</item>
|
||||||
<item>8</item>
|
<item>8</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
|
|
@ -304,15 +304,16 @@
|
||||||
<string name="unexpected_error">Unexpected player error</string>
|
<string name="unexpected_error">Unexpected player error</string>
|
||||||
<string name="storage_error">Download error, check storage permissions</string>
|
<string name="storage_error">Download error, check storage permissions</string>
|
||||||
|
|
||||||
<string name="episode_action_chromecast_episode">Chromecast Episode</string>
|
<string name="episode_action_chromecast_episode">Chromecast episode</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast Mirror</string>
|
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
||||||
<string name="episode_action_play_in_app">Play In App</string>
|
<string name="episode_action_play_in_app">Play in app</string>
|
||||||
<string name="episode_action_play_in_vlc">Play In VLC</string>
|
<string name="episode_action_play_in_vlc">Play in VLC</string>
|
||||||
<string name="episode_action_play_in_browser">Play in browser</string>
|
<string name="episode_action_play_in_browser">Play in browser</string>
|
||||||
<string name="episode_action_copy_link">Copy Link</string>
|
<string name="episode_action_copy_link">Copy link</string>
|
||||||
<string name="episode_action_auto_download">Auto Download</string>
|
<string name="episode_action_auto_download">Auto download</string>
|
||||||
<string name="episode_action_download_mirror">Download Mirror</string>
|
<string name="episode_action_download_mirror">Download mirror</string>
|
||||||
<string name="episode_action_reload_links">Reload Links</string>
|
<string name="episode_action_reload_links">Reload links</string>
|
||||||
|
<string name="episode_action_download_subtitle">Download subtitles</string>
|
||||||
|
|
||||||
<string name="no_update_found">No Update Found</string>
|
<string name="no_update_found">No Update Found</string>
|
||||||
<string name="check_for_update">Check for Update</string>
|
<string name="check_for_update">Check for Update</string>
|
||||||
|
|
Loading…
Reference in a new issue