forked from recloudstream/cloudstream
fixes I guess
This commit is contained in:
parent
4d9c13ac2e
commit
0c6d4d62bd
10 changed files with 92 additions and 37 deletions
|
@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
|
||||||
class XStreamCdn : ExtractorApi() {
|
class XStreamCdn : ExtractorApi() {
|
||||||
override val name: String = "XStreamCdn"
|
override val name: String = "XStreamCdn"
|
||||||
override val mainUrl: String = "https://fcdn.stream"
|
override val mainUrl: String = "https://embedsito.com"
|
||||||
override val requiresReferer = false
|
override val requiresReferer = false
|
||||||
|
|
||||||
private data class ResponseData(
|
private data class ResponseData(
|
||||||
|
|
|
@ -57,7 +57,7 @@ class HDMProvider : MainAPI() {
|
||||||
override fun load(url: String): LoadResponse? {
|
override fun load(url: String): LoadResponse? {
|
||||||
val response = khttp.get(url)
|
val response = khttp.get(url)
|
||||||
val document = Jsoup.parse(response.text)
|
val document = Jsoup.parse(response.text)
|
||||||
val title = document.selectFirst("h2.movieTitle").text()
|
val title = document.selectFirst("h2.movieTitle")?.text() ?: throw ErrorLoadingException("No Data Found")
|
||||||
val poster = document.selectFirst("div.post-thumbnail > img").attr("src")
|
val poster = document.selectFirst("div.post-thumbnail > img").attr("src")
|
||||||
val descript = document.selectFirst("div.synopsis > p").text()
|
val descript = document.selectFirst("div.synopsis > p").text()
|
||||||
val year = document.select("div.movieInfoAll > div.row > div.col-md-6")?.get(1)?.selectFirst("> p > a")?.text()
|
val year = document.select("div.movieInfoAll > div.row > div.col-md-6")?.get(1)?.selectFirst("> p > a")?.text()
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.lagradost.cloudstream3.syncproviders
|
||||||
|
|
||||||
|
//TODO dropbox sync
|
||||||
|
class Dropbox : OAuth2Interface {
|
||||||
|
override val key: String
|
||||||
|
get() = "zlqsamadlwydvb2"
|
||||||
|
override val redirectUrl: String
|
||||||
|
get() = "dropboxlogin"
|
||||||
|
|
||||||
|
override fun handleRedirect(url: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.lagradost.cloudstream3.syncproviders
|
||||||
|
|
||||||
|
interface OAuth2Interface {
|
||||||
|
val key : String
|
||||||
|
val redirectUrl : String
|
||||||
|
fun handleRedirect(url : String)
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import androidx.fragment.app.FragmentActivity
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||||
import com.lagradost.cloudstream3.ui.player.UriData
|
import com.lagradost.cloudstream3.ui.player.UriData
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||||
|
|
||||||
|
@ -28,8 +29,8 @@ object DownloadButtonSetup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setTitle("Delete File") //TODO FIX NAME
|
builder.setTitle("Delete File")
|
||||||
builder.setMessage("This will permanently delete ${click.data.name ?: "Episode ${click.data.episode}"}\nAre you sure?")
|
builder.setMessage("This will permanently delete ${getNameFull(click.data.name,click.data.episode,click.data.season)}\nAre you sure?")
|
||||||
.setTitle("Delete")
|
.setTitle("Delete")
|
||||||
.setPositiveButton("Delete", dialogClickListener)
|
.setPositiveButton("Delete", dialogClickListener)
|
||||||
.setNegativeButton("Cancel", dialogClickListener)
|
.setNegativeButton("Cancel", dialogClickListener)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.cardview.widget.CardView
|
||||||
import androidx.core.widget.ContentLoadingProgressBar
|
import androidx.core.widget.ContentLoadingProgressBar
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||||
|
@ -99,7 +100,7 @@ class DownloadChildAdapter(
|
||||||
private val progressBarDownload: ContentLoadingProgressBar = itemView.download_child_episode_progress_downloaded
|
private val progressBarDownload: ContentLoadingProgressBar = itemView.download_child_episode_progress_downloaded
|
||||||
private val downloadImage: ImageView = itemView.download_child_episode_download
|
private val downloadImage: ImageView = itemView.download_child_episode_download
|
||||||
|
|
||||||
var localCard : VisualDownloadChildCached? = null
|
var localCard: VisualDownloadChildCached? = null
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
fun bind(card: VisualDownloadChildCached) {
|
fun bind(card: VisualDownloadChildCached) {
|
||||||
|
@ -116,7 +117,7 @@ class DownloadChildAdapter(
|
||||||
progressBar.visibility = View.GONE
|
progressBar.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
title.text = d.name ?: "Episode ${d.episode}" //TODO FIX
|
title.text = getNameFull(d.name, d.episode, d.season)
|
||||||
title.isSelected = true // is needed for text repeating
|
title.isSelected = true // is needed for text repeating
|
||||||
|
|
||||||
downloadButton.setUpButton(
|
downloadButton.setUpButton(
|
||||||
|
|
|
@ -226,7 +226,6 @@ class ResultViewModel : ViewModel() {
|
||||||
episodes.add(
|
episodes.add(
|
||||||
context.buildResultEpisode(
|
context.buildResultEpisode(
|
||||||
i.name,
|
i.name,
|
||||||
//?: (if (i.season != null && i.episode != null) "S${i.season}:E${i.episode}" else null)), // TODO ADD NAMES
|
|
||||||
i.posterUrl,
|
i.posterUrl,
|
||||||
i.episode ?: (index + 1),
|
i.episode ?: (index + 1),
|
||||||
i.season,
|
i.season,
|
||||||
|
|
|
@ -43,6 +43,31 @@ object AppUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**| S1:E2 Hello World
|
||||||
|
* | Episode 2. Hello world
|
||||||
|
* | Hello World
|
||||||
|
* | Season 1 - Episode 2
|
||||||
|
* | Episode 2
|
||||||
|
* **/
|
||||||
|
fun getNameFull(name: String?, episode: Int?, season: Int?): String {
|
||||||
|
if (name != null) {
|
||||||
|
return if(episode != null && season != null) {
|
||||||
|
"S${season}:E${episode} $name"
|
||||||
|
} else if(episode != null) {
|
||||||
|
"Episode $episode. $name"
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(episode != null && season != null) {
|
||||||
|
return "Season $season - Episode $episode"
|
||||||
|
} else if(season == null) {
|
||||||
|
return "Episode $episode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
fun AppCompatActivity.loadResult(url: String, apiName: String, startAction: Int = 0) {
|
fun AppCompatActivity.loadResult(url: String, apiName: String, startAction: Int = 0) {
|
||||||
this.runOnUiThread {
|
this.runOnUiThread {
|
||||||
viewModelStore.clear()
|
viewModelStore.clear()
|
||||||
|
|
|
@ -14,7 +14,6 @@ const val RESULT_WATCH_STATE = "result_watch_state"
|
||||||
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data"
|
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data"
|
||||||
const val RESULT_SEASON = "result_season"
|
const val RESULT_SEASON = "result_season"
|
||||||
|
|
||||||
|
|
||||||
object DataStoreHelper {
|
object DataStoreHelper {
|
||||||
data class PosDur(val position: Long, val duration: Long)
|
data class PosDur(val position: Long, val duration: Long)
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ object VideoDownloadManager {
|
||||||
private var currentDownloads = mutableListOf<Int>()
|
private var currentDownloads = mutableListOf<Int>()
|
||||||
|
|
||||||
private const val USER_AGENT =
|
private const val USER_AGENT =
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
"Mozilla/5.0 (Windows NT 10.0; rv:68.0) Gecko/20100101 Firefox/68.0"
|
||||||
|
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
const val imgDone = R.drawable.rddone
|
const val imgDone = R.drawable.rddone
|
||||||
|
@ -207,6 +207,7 @@ object VideoDownloadManager {
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setColorized(true)
|
.setColorized(true)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
|
.setShowWhen(false)
|
||||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
.setColor(context.colorFromAttribute(R.attr.colorPrimary))
|
.setColor(context.colorFromAttribute(R.attr.colorPrimary))
|
||||||
.setContentTitle(ep.mainName)
|
.setContentTitle(ep.mainName)
|
||||||
|
@ -359,41 +360,49 @@ object VideoDownloadManager {
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.Q)
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
private fun ContentResolver.getExistingDownloadUriOrNullQ(relativePath: String, displayName: String): Uri? {
|
private fun ContentResolver.getExistingDownloadUriOrNullQ(relativePath: String, displayName: String): Uri? {
|
||||||
val projection = arrayOf(
|
try {
|
||||||
MediaStore.MediaColumns._ID,
|
val projection = arrayOf(
|
||||||
//MediaStore.MediaColumns.DISPLAY_NAME, // unused (for verification use only)
|
MediaStore.MediaColumns._ID,
|
||||||
//MediaStore.MediaColumns.RELATIVE_PATH, // unused (for verification use only)
|
//MediaStore.MediaColumns.DISPLAY_NAME, // unused (for verification use only)
|
||||||
)
|
//MediaStore.MediaColumns.RELATIVE_PATH, // unused (for verification use only)
|
||||||
|
)
|
||||||
|
|
||||||
val selection =
|
val selection =
|
||||||
"${MediaStore.MediaColumns.RELATIVE_PATH}='$relativePath' AND " + "${MediaStore.MediaColumns.DISPLAY_NAME}='$displayName'"
|
"${MediaStore.MediaColumns.RELATIVE_PATH}='$relativePath' AND " + "${MediaStore.MediaColumns.DISPLAY_NAME}='$displayName'"
|
||||||
|
|
||||||
val result = this.query(
|
val result = this.query(
|
||||||
MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
|
MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
|
||||||
projection, selection, null, null
|
projection, selection, null, null
|
||||||
)
|
)
|
||||||
|
|
||||||
result.use { c ->
|
result.use { c ->
|
||||||
if (c != null && c.count >= 1) {
|
if (c != null && c.count >= 1) {
|
||||||
c.moveToFirst().let {
|
c.moveToFirst().let {
|
||||||
val id = c.getLong(c.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
|
val id = c.getLong(c.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
|
||||||
/*
|
/*
|
||||||
val cDisplayName = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME))
|
val cDisplayName = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME))
|
||||||
val cRelativePath = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH))*/
|
val cRelativePath = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH))*/
|
||||||
|
|
||||||
return ContentUris.withAppendedId(
|
return ContentUris.withAppendedId(
|
||||||
MediaStore.Downloads.EXTERNAL_CONTENT_URI, id
|
MediaStore.Downloads.EXTERNAL_CONTENT_URI, id
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.Q)
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
fun ContentResolver.getFileLength(fileUri: Uri): Long {
|
fun ContentResolver.getFileLength(fileUri: Uri): Long? {
|
||||||
return this.openFileDescriptor(fileUri, "r")
|
return try {
|
||||||
.use { it?.statSize ?: 0 }
|
this.openFileDescriptor(fileUri, "r")
|
||||||
|
.use { it?.statSize ?: 0 }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isScopedStorage(): Boolean {
|
private fun isScopedStorage(): Boolean {
|
||||||
|
@ -439,7 +448,8 @@ object VideoDownloadManager {
|
||||||
cr.getExistingDownloadUriOrNullQ(relativePath, displayName) // CURRENT FILE WITH THE SAME PATH
|
cr.getExistingDownloadUriOrNullQ(relativePath, displayName) // CURRENT FILE WITH THE SAME PATH
|
||||||
|
|
||||||
fileLength =
|
fileLength =
|
||||||
if (currentExistingFile == null || !resume) 0 else cr.getFileLength(currentExistingFile) // IF NOT RESUME THEN 0, OTHERWISE THE CURRENT FILE SIZE
|
if (currentExistingFile == null || !resume) 0 else (cr.getFileLength(currentExistingFile)
|
||||||
|
?: 0)// IF NOT RESUME THEN 0, OTHERWISE THE CURRENT FILE SIZE
|
||||||
|
|
||||||
if (!resume && currentExistingFile != null) { // DELETE FILE IF FILE EXITS AND NOT RESUME
|
if (!resume && currentExistingFile != null) { // DELETE FILE IF FILE EXITS AND NOT RESUME
|
||||||
val rowsDeleted = context.contentResolver.delete(currentExistingFile, null, null)
|
val rowsDeleted = context.contentResolver.delete(currentExistingFile, null, null)
|
||||||
|
@ -500,7 +510,7 @@ object VideoDownloadManager {
|
||||||
connection.setRequestProperty("Accept-Encoding", "identity")
|
connection.setRequestProperty("Accept-Encoding", "identity")
|
||||||
connection.setRequestProperty("User-Agent", USER_AGENT)
|
connection.setRequestProperty("User-Agent", USER_AGENT)
|
||||||
if (link.referer.isNotEmpty()) connection.setRequestProperty("Referer", link.referer)
|
if (link.referer.isNotEmpty()) connection.setRequestProperty("Referer", link.referer)
|
||||||
if (resume) connection.setRequestProperty("Range", "bytes=${fileLength}-")
|
connection.setRequestProperty("Range", "bytes=${(if (resume) fileLength else 0)}-")
|
||||||
val resumeLength = (if (resume) fileLength else 0)
|
val resumeLength = (if (resume) fileLength else 0)
|
||||||
|
|
||||||
// ON CONNECTION
|
// ON CONNECTION
|
||||||
|
@ -705,7 +715,7 @@ object VideoDownloadManager {
|
||||||
val cr = context.contentResolver ?: return null
|
val cr = context.contentResolver ?: return null
|
||||||
val fileUri =
|
val fileUri =
|
||||||
cr.getExistingDownloadUriOrNullQ(info.relativePath, info.displayName) ?: return null
|
cr.getExistingDownloadUriOrNullQ(info.relativePath, info.displayName) ?: return null
|
||||||
val fileLength = cr.getFileLength(fileUri)
|
val fileLength = cr.getFileLength(fileUri) ?: return null
|
||||||
if (fileLength == 0L) return null
|
if (fileLength == 0L) return null
|
||||||
return DownloadedFileInfoResult(fileLength, info.totalBytes, fileUri)
|
return DownloadedFileInfoResult(fileLength, info.totalBytes, fileUri)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue