mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
poc
This commit is contained in:
parent
afe82140fd
commit
49b905c089
6 changed files with 147 additions and 21 deletions
|
@ -261,7 +261,7 @@ dependencies {
|
||||||
// color palette for images -> colors
|
// color palette for images -> colors
|
||||||
implementation("androidx.palette:palette-ktx:1.0.0")
|
implementation("androidx.palette:palette-ktx:1.0.0")
|
||||||
|
|
||||||
implementation("com.github.recloudstream:Aria2cStream:0.0.1")
|
implementation("com.github.recloudstream:Aria2cStream:0.0.3")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("androidSourcesJar", Jar::class) {
|
tasks.register("androidSourcesJar", Jar::class) {
|
||||||
|
|
|
@ -1569,14 +1569,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
|
|
||||||
//val defaultDirectory = "${filesDir.path}/torrent_tmp"
|
//val defaultDirectory = "${filesDir.path}/torrent_tmp"
|
||||||
//File(defaultDirectory).deleteRecursively()
|
//File(defaultDirectory).deleteRecursively()
|
||||||
navigate(
|
/*navigate(
|
||||||
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||||
ExtractorLinkGenerator(
|
ExtractorLinkGenerator(
|
||||||
listOf(
|
listOf(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
source = "",
|
source = "",
|
||||||
name = "hello world",
|
name = "hello world",
|
||||||
url = "",
|
|
||||||
"",
|
"",
|
||||||
Qualities.Unknown.value,
|
Qualities.Unknown.value,
|
||||||
type = INFER_TYPE
|
type = INFER_TYPE
|
||||||
|
@ -1585,7 +1584,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
emptyList()
|
emptyList()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)*/
|
||||||
|
|
||||||
// Used to check current focus for TV
|
// Used to check current focus for TV
|
||||||
// main {
|
// main {
|
||||||
|
|
|
@ -135,7 +135,7 @@ abstract class AbstractPlayerFragment(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateIsPlaying(wasPlaying : CSPlayerLoading,
|
open fun updateIsPlaying(wasPlaying : CSPlayerLoading,
|
||||||
isPlaying : CSPlayerLoading) {
|
isPlaying : CSPlayerLoading) {
|
||||||
val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying
|
val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying
|
||||||
val isPausedRightNow = CSPlayerLoading.IsPaused == isPlaying
|
val isPausedRightNow = CSPlayerLoading.IsPaused == isPlaying
|
||||||
|
|
|
@ -56,6 +56,7 @@ import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.USER_AGENT
|
import com.lagradost.cloudstream3.USER_AGENT
|
||||||
import com.lagradost.cloudstream3.app
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.mvvm.debugAssert
|
import com.lagradost.cloudstream3.mvvm.debugAssert
|
||||||
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
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.ui.subtitles.SaveCaptionStyle
|
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
|
||||||
|
@ -67,10 +68,15 @@ import com.lagradost.cloudstream3.utils.ExtractorLinkPlayList
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLinkType
|
import com.lagradost.cloudstream3.utils.ExtractorLinkType
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage
|
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage
|
||||||
|
import com.lagradost.fetchbutton.aria2c.Aria2Args
|
||||||
import com.lagradost.fetchbutton.aria2c.Aria2Settings
|
import com.lagradost.fetchbutton.aria2c.Aria2Settings
|
||||||
import com.lagradost.fetchbutton.aria2c.Aria2Starter
|
import com.lagradost.fetchbutton.aria2c.Aria2Starter
|
||||||
|
import com.lagradost.fetchbutton.aria2c.BtPieceSelector
|
||||||
import com.lagradost.fetchbutton.aria2c.DownloadListener
|
import com.lagradost.fetchbutton.aria2c.DownloadListener
|
||||||
import com.lagradost.fetchbutton.aria2c.DownloadStatusTell
|
import com.lagradost.fetchbutton.aria2c.DownloadStatusTell
|
||||||
|
import com.lagradost.fetchbutton.aria2c.FileAllocationType
|
||||||
|
import com.lagradost.fetchbutton.aria2c.FollowMetaLinkType
|
||||||
|
import com.lagradost.fetchbutton.aria2c.UriRequest
|
||||||
import com.lagradost.fetchbutton.aria2c.newUriRequest
|
import com.lagradost.fetchbutton.aria2c.newUriRequest
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -119,6 +125,9 @@ class CS3IPlayer : IPlayer {
|
||||||
private var lastMuteVolume: Float = 1.0f
|
private var lastMuteVolume: Float = 1.0f
|
||||||
|
|
||||||
private var currentLink: ExtractorLink? = null
|
private var currentLink: ExtractorLink? = null
|
||||||
|
|
||||||
|
private var currentAria2cRequestLink: ExtractorLink? = null
|
||||||
|
private var currentAria2cRequestId: Long? = null
|
||||||
private var currentDownloadedFile: ExtractorUri? = null
|
private var currentDownloadedFile: ExtractorUri? = null
|
||||||
private var hasUsedFirstRender = false
|
private var hasUsedFirstRender = false
|
||||||
|
|
||||||
|
@ -262,7 +271,7 @@ class CS3IPlayer : IPlayer {
|
||||||
link: ExtractorLink,
|
link: ExtractorLink,
|
||||||
requestId: Long,
|
requestId: Long,
|
||||||
) {
|
) {
|
||||||
val minimumBytes : Long = 30 shl 20
|
val minimumBytes: Long = 30 shl 20
|
||||||
var hasFileChecked = false
|
var hasFileChecked = false
|
||||||
while (true) {
|
while (true) {
|
||||||
val gid = DownloadListener.sessionIdToGid[requestId]
|
val gid = DownloadListener.sessionIdToGid[requestId]
|
||||||
|
@ -354,6 +363,8 @@ class CS3IPlayer : IPlayer {
|
||||||
?: throw Exception("Not downloaded enough")
|
?: throw Exception("Not downloaded enough")
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
//Log.i(TAG, "downloaded data: $metadata")
|
//Log.i(TAG, "downloaded data: $metadata")
|
||||||
|
exoPlayer?.release()
|
||||||
|
exoPlayer = null
|
||||||
loadOfflinePlayer(
|
loadOfflinePlayer(
|
||||||
activity,
|
activity,
|
||||||
ExtractorUri(
|
ExtractorUri(
|
||||||
|
@ -400,13 +411,64 @@ class CS3IPlayer : IPlayer {
|
||||||
private suspend fun playAria2c(activity: Activity, link: ExtractorLink) {
|
private suspend fun playAria2c(activity: Activity, link: ExtractorLink) {
|
||||||
// ephemeral id based on url to make it unique
|
// ephemeral id based on url to make it unique
|
||||||
val requestId = link.url.hashCode().toLong()
|
val requestId = link.url.hashCode().toLong()
|
||||||
|
currentAria2cRequestId = requestId
|
||||||
|
currentAria2cRequestLink = link
|
||||||
|
|
||||||
val uriReq = newUriRequest(
|
val uriReq = UriRequest(
|
||||||
id = requestId,
|
id = requestId,
|
||||||
uri = link.url,
|
uris = listOf(link.url),
|
||||||
fileName = null,
|
args = Aria2Args(
|
||||||
seed = false,
|
headers = link.headers,
|
||||||
stream = true,
|
referer = link.referer,
|
||||||
|
/** torrent specifics to make it possible to stream */
|
||||||
|
seedRatio = 0.0f,
|
||||||
|
seedTimeMin = 0.0f,
|
||||||
|
btPieceSelector = BtPieceSelector.Inorder,
|
||||||
|
followTorrent = FollowMetaLinkType.Mem,
|
||||||
|
fileAllocation = FileAllocationType.None,
|
||||||
|
btPrioritizePiece = "head=30M,tail=30M",
|
||||||
|
/** Best trackers to make it faster */
|
||||||
|
btTracker = listOf(
|
||||||
|
"udp://tracker.opentrackr.org:1337/announce",
|
||||||
|
"https://tracker2.ctix.cn/announce",
|
||||||
|
"https://tracker1.520.jp:443/announce",
|
||||||
|
"udp://opentracker.i2p.rocks:6969/announce",
|
||||||
|
"udp://open.tracker.cl:1337/announce",
|
||||||
|
"udp://open.demonii.com:1337/announce",
|
||||||
|
"http://tracker.openbittorrent.com:80/announce",
|
||||||
|
"udp://tracker.openbittorrent.com:6969/announce",
|
||||||
|
"udp://open.stealth.si:80/announce",
|
||||||
|
"udp://exodus.desync.com:6969/announce",
|
||||||
|
"udp://tracker-udp.gbitt.info:80/announce",
|
||||||
|
"udp://explodie.org:6969/announce",
|
||||||
|
"https://tracker.gbitt.info:443/announce",
|
||||||
|
"http://tracker.gbitt.info:80/announce",
|
||||||
|
"udp://uploads.gamecoast.net:6969/announce",
|
||||||
|
"udp://tracker1.bt.moack.co.kr:80/announce",
|
||||||
|
"udp://tracker.tiny-vps.com:6969/announce",
|
||||||
|
"udp://tracker.theoks.net:6969/announce",
|
||||||
|
"udp://tracker.dump.cl:6969/announce",
|
||||||
|
"udp://tracker.bittor.pw:1337/announce",
|
||||||
|
"https://tracker1.520.jp:443/announce",
|
||||||
|
"udp://opentracker.i2p.rocks:6969/announce",
|
||||||
|
"udp://open.tracker.cl:1337/announce",
|
||||||
|
"udp://open.demonii.com:1337/announce",
|
||||||
|
"http://tracker.openbittorrent.com:80/announce",
|
||||||
|
"udp://tracker.openbittorrent.com:6969/announce",
|
||||||
|
"udp://open.stealth.si:80/announce",
|
||||||
|
"udp://exodus.desync.com:6969/announce",
|
||||||
|
"udp://tracker-udp.gbitt.info:80/announce",
|
||||||
|
"udp://explodie.org:6969/announce",
|
||||||
|
"https://tracker.gbitt.info:443/announce",
|
||||||
|
"http://tracker.gbitt.info:80/announce",
|
||||||
|
"udp://uploads.gamecoast.net:6969/announce",
|
||||||
|
"udp://tracker1.bt.moack.co.kr:80/announce",
|
||||||
|
"udp://tracker.tiny-vps.com:6969/announce",
|
||||||
|
"udp://tracker.theoks.net:6969/announce",
|
||||||
|
"udp://tracker.dump.cl:6969/announce",
|
||||||
|
"udp://tracker.bittor.pw:1337/announce"
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val metadata =
|
val metadata =
|
||||||
|
@ -421,6 +483,7 @@ class CS3IPlayer : IPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
saveData()
|
||||||
awaitAria2c(activity, link, requestId)
|
awaitAria2c(activity, link, requestId)
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
// if we detect any download error then we delete it as we don't want any useless background tasks
|
// if we detect any download error then we delete it as we don't want any useless background tasks
|
||||||
|
@ -500,6 +563,7 @@ class CS3IPlayer : IPlayer {
|
||||||
if (link != null) {
|
if (link != null) {
|
||||||
loadOnlinePlayer(context, link)
|
loadOnlinePlayer(context, link)
|
||||||
} else if (data != null) {
|
} else if (data != null) {
|
||||||
|
currentAria2cRequestId = null
|
||||||
loadOfflinePlayer(context, data)
|
loadOfflinePlayer(context, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1320,10 +1384,64 @@ class CS3IPlayer : IPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlayerError(error: PlaybackException) {
|
override fun onPlayerError(error: PlaybackException) {
|
||||||
// If the Network fails then ignore the exception if the duration is set.
|
val aria2cRequestId = currentAria2cRequestId
|
||||||
// This is to switch mirrors automatically if the stream has not been fetched, but
|
val loadedLink = currentAria2cRequestLink
|
||||||
// allow playing the buffer without internet as then the duration is fetched.
|
|
||||||
when {
|
when {
|
||||||
|
// if we are loading an torrent, then we will get these errors, in that case
|
||||||
|
// we just treat it as buffering
|
||||||
|
aria2cRequestId != null && loadedLink != null &&
|
||||||
|
(error.errorCode == PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE
|
||||||
|
|| error.errorCode == PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED
|
||||||
|
|| error.errorCode == PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED
|
||||||
|
|| error.errorCode == PlaybackException.ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED
|
||||||
|
) -> {
|
||||||
|
|
||||||
|
val gid = DownloadListener.sessionIdToGid[aria2cRequestId]
|
||||||
|
Log.i(TAG, "Aria2 error $error error ${error.errorCode}")
|
||||||
|
if(gid == null) {
|
||||||
|
event(ErrorEvent(error))
|
||||||
|
super.onPlayerError(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
event(
|
||||||
|
StatusEvent(
|
||||||
|
wasPlaying = CSPlayerLoading.IsPlaying,
|
||||||
|
isPlaying = CSPlayerLoading.IsBuffering
|
||||||
|
)
|
||||||
|
)
|
||||||
|
CoroutineScope(Dispatchers.IO).launchSafe {
|
||||||
|
for (i in 0..5) {
|
||||||
|
val metadata = DownloadListener.getInfo(gid)
|
||||||
|
event(
|
||||||
|
DownloadEvent(
|
||||||
|
downloadedBytes = metadata.downloadedLength,
|
||||||
|
downloadSpeed = metadata.downloadSpeed,
|
||||||
|
totalBytes = metadata.totalLength,
|
||||||
|
connections = metadata.items.sumOf { it.connections }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommonActivity.activity?.runOnUiThread {
|
||||||
|
// exoPlayer?.prepare()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// shitty solution to release it every time, however we will get timeout otherwise
|
||||||
|
CommonActivity.activity?.let { act ->
|
||||||
|
try {
|
||||||
|
awaitAria2c(act, loadedLink, aria2cRequestId)
|
||||||
|
} catch (t : Throwable) {
|
||||||
|
event(ErrorEvent(t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the Network fails then ignore the exception if the duration is set.
|
||||||
|
// This is to switch mirrors automatically if the stream has not been fetched, but
|
||||||
|
// allow playing the buffer without internet as then the duration is fetched.
|
||||||
error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED
|
error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED
|
||||||
&& exoPlayer?.duration != TIME_UNSET -> {
|
&& exoPlayer?.duration != TIME_UNSET -> {
|
||||||
exoPlayer?.prepare()
|
exoPlayer?.prepare()
|
||||||
|
@ -1554,6 +1672,7 @@ class CS3IPlayer : IPlayer {
|
||||||
Log.i(TAG, "loadOnlinePlayer $link")
|
Log.i(TAG, "loadOnlinePlayer $link")
|
||||||
try {
|
try {
|
||||||
currentLink = link
|
currentLink = link
|
||||||
|
currentAria2cRequestId = null
|
||||||
|
|
||||||
if (ignoreSSL) {
|
if (ignoreSSL) {
|
||||||
// Disables ssl check
|
// Disables ssl check
|
||||||
|
|
|
@ -109,6 +109,14 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
showDownloadProgress(event)
|
showDownloadProgress(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*override fun updateIsPlaying(wasPlaying: CSPlayerLoading, isPlaying: CSPlayerLoading) {
|
||||||
|
super.updateIsPlaying(wasPlaying, isPlaying)
|
||||||
|
if(isPlaying == CSPlayerLoading.IsPlaying)
|
||||||
|
activity?.runOnUiThread {
|
||||||
|
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
private fun showDownloadProgress(event: DownloadEvent?) {
|
private fun showDownloadProgress(event: DownloadEvent?) {
|
||||||
activity?.runOnUiThread {
|
activity?.runOnUiThread {
|
||||||
if(event == null) {
|
if(event == null) {
|
||||||
|
|
|
@ -30,19 +30,19 @@
|
||||||
app:show_timeout="0" />
|
app:show_timeout="0" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
android:backgroundTint="@android:color/black">
|
android:backgroundTint="@android:color/black"
|
||||||
|
android:id="@+id/download_header"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/download_header"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical">
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/downloaded_progress_text"
|
android:id="@+id/downloaded_progress_text"
|
||||||
|
|
Loading…
Reference in a new issue