diff --git a/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt b/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt index fc3f15cd..57a6b999 100644 --- a/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt +++ b/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt @@ -3,6 +3,8 @@ package ani.dantotsu.media.anime import android.annotation.SuppressLint import android.app.Activity import android.app.AlertDialog +import android.content.ActivityNotFoundException +import android.content.ComponentName import android.content.DialogInterface import android.content.Intent import android.graphics.Color @@ -12,6 +14,8 @@ import android.util.TypedValue import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.result.ActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.fragment.app.activityViewModels @@ -28,10 +32,12 @@ import ani.dantotsu.media.Media import ani.dantotsu.media.MediaDetailsViewModel import ani.dantotsu.others.Download.download import ani.dantotsu.parsers.Subtitle +import ani.dantotsu.parsers.Video import ani.dantotsu.parsers.VideoExtractor import ani.dantotsu.parsers.VideoType import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName +import ani.dantotsu.util.Logger import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -212,11 +218,62 @@ class SelectorDialogFragment : BottomSheetDialogFragment() { super.onViewCreated(view, savedInstanceState) } + private val externalPlayerResult = registerForActivityResult( + ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> + Logger.log(result.data.toString()) + } + + private fun exportMagnetIntent(episode: Episode, video: Video) : Intent { + val amnis = "com.amnis" + return Intent(Intent.ACTION_VIEW).apply { + component = ComponentName(amnis, "$amnis.gui.player.PlayerActivity") + data = Uri.parse(video.file.url) + putExtra("title", "${media?.name} - ${episode.title}") + putExtra("position", 0) + putExtra(Intent.EXTRA_RETURN_RESULT, true) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + putExtra("secure_uri", true) + val headersArray = arrayOf() + video.file.headers.forEach { + headersArray.plus(arrayOf(it.key, it.value)) + } + putExtra("headers", headersArray) + } + } + @SuppressLint("UnsafeOptInUsageError") fun startExoplayer(media: Media) { prevEpisode = null dismiss() + + episode?.let { ep -> + val video = ep.extractors?.find { + it.server.name == ep.selectedExtractor + }?.videos?.getOrNull(ep.selectedVideo) + video?.file?.url?.let { url -> + if (url.startsWith("magnet:")) { + try { + externalPlayerResult.launch(exportMagnetIntent(ep, video)) + } catch (e: ActivityNotFoundException) { + val amnis = "com.amnis" + try { + startActivity(Intent( + Intent.ACTION_VIEW, + Uri.parse("market://details?id=$amnis")) + ) + } catch (e: ActivityNotFoundException) { + startActivity(Intent( + Intent.ACTION_VIEW, + Uri.parse("https://play.google.com/store/apps/details?id=$amnis") + )) + } + } + return + } + } + } + if (launch!! || model.watchSources!!.isDownloadedSource(media.selected!!.sourceIndex)) { stopAddingToList() val intent = Intent(activity, ExoplayerView::class.java) diff --git a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt index 623eae33..971f750a 100644 --- a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt +++ b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt @@ -1,9 +1,21 @@ package ani.dantotsu.parsers +import android.content.ActivityNotFoundException +import android.content.ComponentName +import android.content.ContentResolver +import android.content.ContentValues import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Build +import android.os.Environment +import android.provider.MediaStore import ani.dantotsu.FileUrl import ani.dantotsu.currContext import ani.dantotsu.media.anime.AnimeNameAdapter +import ani.dantotsu.media.anime.ExoplayerView import ani.dantotsu.media.manga.ImageData import ani.dantotsu.media.manga.MangaCache import ani.dantotsu.snackString @@ -39,6 +51,7 @@ import okhttp3.Request import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.UnsupportedEncodingException +import java.net.MalformedURLException import java.net.URL import java.net.URLDecoder @@ -523,35 +536,44 @@ class VideoServerPassthrough(private val videoServer: VideoServer) : VideoExtrac // Check for null video URL val videoUrl = aniVideo.videoUrl ?: throw Exception("Video URL is null") - val urlObj = URL(videoUrl) - val path = urlObj.path - val query = urlObj.query + var format: VideoType? - var format = getVideoType(path) + try { + val urlObj = URL(videoUrl) + val path = urlObj.path + val query = urlObj.query - if (format == null && query != null) { - val queryPairs: List> = query.split("&").map { - val idx = it.indexOf("=") - val key = URLDecoder.decode(it.substring(0, idx), "UTF-8") - val value = URLDecoder.decode(it.substring(idx + 1), "UTF-8") - Pair(key, value) + format = getVideoType(path) + + if (format == null && query != null) { + val queryPairs: List> = query.split("&").map { + val idx = it.indexOf("=") + val key = URLDecoder.decode(it.substring(0, idx), "UTF-8") + val value = URLDecoder.decode(it.substring(idx + 1), "UTF-8") + Pair(key, value) + } + + // Assume the file is named under the "file" query parameter + val fileName = queryPairs.find { it.first == "file" }?.second ?: "" + + format = getVideoType(fileName) + // this solves a problem no one has, so I'm commenting it out for now + //if (format == null) { + // val networkHelper = Injekt.get() + // format = headRequest(videoUrl, networkHelper) + //} } - // Assume the file is named under the "file" query parameter - val fileName = queryPairs.find { it.first == "file" }?.second ?: "" - - format = getVideoType(fileName) - // this solves a problem no one has, so I'm commenting it out for now - //if (format == null) { - // val networkHelper = Injekt.get() - // format = headRequest(videoUrl, networkHelper) - //} - } - - // If the format is still undetermined, log an error - if (format == null) { - Logger.log("Unknown video format: $videoUrl") - format = VideoType.CONTAINER + // If the format is still undetermined, log an error + if (format == null) { + Logger.log("Unknown video format: $videoUrl") + format = VideoType.CONTAINER + } + } catch (malformed: MalformedURLException) { + if (videoUrl.startsWith("magnet:")) + format = VideoType.CONTAINER + else + throw malformed } val headersMap: Map = aniVideo.headers?.toMultimap()?.mapValues { it.value.joinToString() } ?: mapOf() @@ -559,7 +581,7 @@ class VideoServerPassthrough(private val videoServer: VideoServer) : VideoExtrac return Video( number, - format, + format!!, FileUrl(videoUrl, headersMap), if (aniVideo.totalContentLength == 0L) null else aniVideo.bytesDownloaded.toDouble() )