mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-05-29 21:10:24 +02:00
Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay
This commit is contained in:
commit
ecca3b6793
12
.gitmodules
vendored
12
.gitmodules
vendored
@ -70,3 +70,15 @@
|
|||||||
[submodule "app/src/unstable/assets/sources/spotify"]
|
[submodule "app/src/unstable/assets/sources/spotify"]
|
||||||
path = app/src/unstable/assets/sources/spotify
|
path = app/src/unstable/assets/sources/spotify
|
||||||
url = ../plugins/spotify.git
|
url = ../plugins/spotify.git
|
||||||
|
[submodule "app/src/stable/assets/sources/bitchute"]
|
||||||
|
path = app/src/stable/assets/sources/bitchute
|
||||||
|
url = ../plugins/bitchute.git
|
||||||
|
[submodule "app/src/unstable/assets/sources/bitchute"]
|
||||||
|
path = app/src/unstable/assets/sources/bitchute
|
||||||
|
url = ../plugins/bitchute.git
|
||||||
|
[submodule "app/src/unstable/assets/sources/dailymotion"]
|
||||||
|
path = app/src/unstable/assets/sources/dailymotion
|
||||||
|
url = ../plugins/dailymotion.git
|
||||||
|
[submodule "app/src/stable/assets/sources/dailymotion"]
|
||||||
|
path = app/src/stable/assets/sources/dailymotion
|
||||||
|
url = ../plugins/dailymotion.git
|
||||||
|
@ -58,6 +58,7 @@ import kotlinx.serialization.Transient
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.lang.Thread.sleep
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
@ -168,6 +169,7 @@ class VideoDownload {
|
|||||||
this.targetBitrate = targetBitrate;
|
this.targetBitrate = targetBitrate;
|
||||||
this.hasVideoRequestExecutor = video is JSSource && video.hasRequestExecutor;
|
this.hasVideoRequestExecutor = video is JSSource && video.hasRequestExecutor;
|
||||||
this.requiresLiveVideoSource = false;
|
this.requiresLiveVideoSource = false;
|
||||||
|
this.requiresLiveAudioSource = false;
|
||||||
this.targetVideoName = videoSource?.name;
|
this.targetVideoName = videoSource?.name;
|
||||||
this.requireVideoSource = targetPixelCount != null
|
this.requireVideoSource = targetPixelCount != null
|
||||||
this.requireAudioSource = targetBitrate != null; //TODO: May not be a valid check.. can only be determined after live fetch?
|
this.requireAudioSource = targetBitrate != null; //TODO: May not be a valid check.. can only be determined after live fetch?
|
||||||
@ -697,7 +699,7 @@ class VideoDownload {
|
|||||||
if(Settings.instance.downloads.byteRangeDownload && head?.containsKey("accept-ranges") == true && head.containsKey("content-length"))
|
if(Settings.instance.downloads.byteRangeDownload && head?.containsKey("accept-ranges") == true && head.containsKey("content-length"))
|
||||||
{
|
{
|
||||||
val concurrency = Settings.instance.downloads.getByteRangeThreadCount();
|
val concurrency = Settings.instance.downloads.getByteRangeThreadCount();
|
||||||
Logger.i(TAG, "Download $name ByteRange Parallel (${concurrency})");
|
Logger.i(TAG, "Download $name ByteRange Parallel (${concurrency}): " + videoUrl);
|
||||||
sourceLength = head["content-length"]!!.toLong();
|
sourceLength = head["content-length"]!!.toLong();
|
||||||
onProgress(sourceLength, 0, 0);
|
onProgress(sourceLength, 0, 0);
|
||||||
downloadSource_Ranges(name, client, fileStream, videoUrl, sourceLength, 1024*512, concurrency, onProgress);
|
downloadSource_Ranges(name, client, fileStream, videoUrl, sourceLength, 1024*512, concurrency, onProgress);
|
||||||
@ -781,6 +783,76 @@ class VideoDownload {
|
|||||||
onProgress(sourceLength, totalRead, 0);
|
onProgress(sourceLength, totalRead, 0);
|
||||||
return sourceLength;
|
return sourceLength;
|
||||||
}
|
}
|
||||||
|
/*private fun downloadSource_Sequential(client: ManagedHttpClient, fileStream: FileOutputStream, url: String, onProgress: (Long, Long, Long) -> Unit): Long {
|
||||||
|
val progressRate: Int = 4096 * 25
|
||||||
|
var lastProgressCount: Int = 0
|
||||||
|
val speedRate: Int = 4096 * 25
|
||||||
|
var readSinceLastSpeedTest: Long = 0
|
||||||
|
var timeSinceLastSpeedTest: Long = System.currentTimeMillis()
|
||||||
|
|
||||||
|
var lastSpeed: Long = 0
|
||||||
|
|
||||||
|
var totalRead: Long = 0
|
||||||
|
var sourceLength: Long
|
||||||
|
val buffer = ByteArray(4096)
|
||||||
|
|
||||||
|
var isPartialDownload = false
|
||||||
|
var result: ManagedHttpClient.Response? = null
|
||||||
|
do {
|
||||||
|
result = client.get(url, if (isPartialDownload) hashMapOf("Range" to "bytes=$totalRead-") else hashMapOf())
|
||||||
|
if (isPartialDownload) {
|
||||||
|
if (result.code != 206)
|
||||||
|
throw IllegalStateException("Failed to download source, byte range fallback failed. Web[${result.code}] Error")
|
||||||
|
} else {
|
||||||
|
if (!result.isOk)
|
||||||
|
throw IllegalStateException("Failed to download source. Web[${result.code}] Error")
|
||||||
|
}
|
||||||
|
if (result.body == null)
|
||||||
|
throw IllegalStateException("Failed to download source. Web[${result.code}] No response")
|
||||||
|
|
||||||
|
isPartialDownload = true
|
||||||
|
sourceLength = result.body!!.contentLength()
|
||||||
|
val sourceStream = result.body!!.byteStream()
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
val read = sourceStream.read(buffer)
|
||||||
|
if (read <= 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStream.write(buffer, 0, read)
|
||||||
|
|
||||||
|
totalRead += read
|
||||||
|
readSinceLastSpeedTest += read
|
||||||
|
|
||||||
|
if (totalRead / progressRate > lastProgressCount) {
|
||||||
|
onProgress(sourceLength, totalRead, lastSpeed)
|
||||||
|
lastProgressCount++
|
||||||
|
}
|
||||||
|
if (readSinceLastSpeedTest > speedRate) {
|
||||||
|
val lastSpeedTime = timeSinceLastSpeedTest
|
||||||
|
timeSinceLastSpeedTest = System.currentTimeMillis()
|
||||||
|
val timeSince = timeSinceLastSpeedTest - lastSpeedTime
|
||||||
|
if (timeSince > 0)
|
||||||
|
lastSpeed = (readSinceLastSpeedTest / (timeSince / 1000.0)).toLong()
|
||||||
|
readSinceLastSpeedTest = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCancelled)
|
||||||
|
throw CancellationException("Cancelled")
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.w(TAG, "Sequential download was interrupted, trying to fallback to byte ranges", e)
|
||||||
|
} finally {
|
||||||
|
sourceStream.close()
|
||||||
|
result.body?.close()
|
||||||
|
}
|
||||||
|
} while (totalRead < sourceLength)
|
||||||
|
|
||||||
|
onProgress(sourceLength, totalRead, 0)
|
||||||
|
return sourceLength
|
||||||
|
}*/
|
||||||
private fun downloadSource_Ranges(name: String, client: ManagedHttpClient, fileStream: FileOutputStream, url: String, sourceLength: Long, rangeSize: Int, concurrency: Int = 1, onProgress: (Long, Long, Long) -> Unit) {
|
private fun downloadSource_Ranges(name: String, client: ManagedHttpClient, fileStream: FileOutputStream, url: String, sourceLength: Long, rangeSize: Int, concurrency: Int = 1, onProgress: (Long, Long, Long) -> Unit) {
|
||||||
val progressRate: Int = 4096 * 5;
|
val progressRate: Int = 4096 * 5;
|
||||||
var lastProgressCount: Int = 0;
|
var lastProgressCount: Int = 0;
|
||||||
@ -853,18 +925,42 @@ class VideoDownload {
|
|||||||
return tasks.map { it.get() };
|
return tasks.map { it.get() };
|
||||||
}
|
}
|
||||||
private fun requestByteRange(client: ManagedHttpClient, url: String, rangeStart: Long, rangeEnd: Long): Triple<ByteArray, Long, Long> {
|
private fun requestByteRange(client: ManagedHttpClient, url: String, rangeStart: Long, rangeEnd: Long): Triple<ByteArray, Long, Long> {
|
||||||
val toRead = rangeEnd - rangeStart;
|
var retryCount = 0
|
||||||
val req = client.get(url, mutableMapOf(Pair("Range", "bytes=${rangeStart}-${rangeEnd}")));
|
var lastException: Throwable? = null
|
||||||
if(!req.isOk)
|
|
||||||
throw IllegalStateException("Range request failed Code [${req.code}] due to: ${req.message}");
|
|
||||||
if(req.body == null)
|
|
||||||
throw IllegalStateException("Range request failed, No body");
|
|
||||||
val read = req.body.contentLength();
|
|
||||||
|
|
||||||
if(read < toRead)
|
while (retryCount <= 3) {
|
||||||
throw IllegalStateException("Byte-Range request attempted to provide less (${read} < ${toRead})");
|
try {
|
||||||
|
val toRead = rangeEnd - rangeStart;
|
||||||
|
val req = client.get(url, mutableMapOf(Pair("Range", "bytes=${rangeStart}-${rangeEnd}")));
|
||||||
|
if (!req.isOk) {
|
||||||
|
val bodyString = req.body?.string()
|
||||||
|
req.body?.close()
|
||||||
|
throw IllegalStateException("Range request failed Code [${req.code}] due to: ${req.message}");
|
||||||
|
}
|
||||||
|
if (req.body == null)
|
||||||
|
throw IllegalStateException("Range request failed, No body");
|
||||||
|
val read = req.body.contentLength();
|
||||||
|
|
||||||
return Triple(req.body.bytes(), rangeStart, rangeEnd);
|
if (read < toRead)
|
||||||
|
throw IllegalStateException("Byte-Range request attempted to provide less (${read} < ${toRead})");
|
||||||
|
|
||||||
|
return Triple(req.body.bytes(), rangeStart, rangeEnd);
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Logger.w(TAG, "Failed to download range (url=${url} bytes=${rangeStart}-${rangeEnd})", e)
|
||||||
|
|
||||||
|
retryCount++
|
||||||
|
lastException = e
|
||||||
|
|
||||||
|
sleep(when (retryCount) {
|
||||||
|
1 -> 1000 + ((Math.random() * 300.0).toLong() - 150)
|
||||||
|
2 -> 2000 + ((Math.random() * 300.0).toLong() - 150)
|
||||||
|
3 -> 4000 + ((Math.random() * 300.0).toLong() - 150)
|
||||||
|
else -> 1000 + ((Math.random() * 300.0).toLong() - 150)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw lastException!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validate() {
|
fun validate() {
|
||||||
|
@ -28,7 +28,12 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import java.net.Proxy
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
|
import java.time.Duration
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
class DownloadService : Service() {
|
class DownloadService : Service() {
|
||||||
@ -44,7 +49,12 @@ class DownloadService : Service() {
|
|||||||
private var _notificationManager: NotificationManager? = null;
|
private var _notificationManager: NotificationManager? = null;
|
||||||
private var _notificationChannel: NotificationChannel? = null;
|
private var _notificationChannel: NotificationChannel? = null;
|
||||||
|
|
||||||
private val _client = ManagedHttpClient();
|
private val _client = ManagedHttpClient(OkHttpClient.Builder()
|
||||||
|
//.proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress(InetAddress.getByName("192.168.1.175"), 8081)))
|
||||||
|
.readTimeout(Duration.ofSeconds(30))
|
||||||
|
.writeTimeout(Duration.ofSeconds(30))
|
||||||
|
.connectTimeout(Duration.ofSeconds(30))
|
||||||
|
.callTimeout(Duration.ofMinutes(30)))
|
||||||
|
|
||||||
private var _started = false;
|
private var _started = false;
|
||||||
|
|
||||||
|
@ -33,6 +33,11 @@
|
|||||||
<data android:host="bilibili.com" />
|
<data android:host="bilibili.com" />
|
||||||
<data android:host="bilibili.tv" />
|
<data android:host="bilibili.tv" />
|
||||||
<data android:host="spotify.com" />
|
<data android:host="spotify.com" />
|
||||||
|
<data android:host="dailymotion.com" />
|
||||||
|
<data android:host="www.dailymotion.com" />
|
||||||
|
<data android:host="bitchute.com" />
|
||||||
|
<data android:host="www.bitchute.com" />
|
||||||
|
<data android:host="old.bitchute.com" />
|
||||||
<data android:pathPrefix="/" />
|
<data android:pathPrefix="/" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter android:autoVerify="true">
|
<intent-filter android:autoVerify="true">
|
||||||
@ -57,6 +62,11 @@
|
|||||||
<data android:host="bilibili.com" />
|
<data android:host="bilibili.com" />
|
||||||
<data android:host="bilibili.tv" />
|
<data android:host="bilibili.tv" />
|
||||||
<data android:host="spotify.com" />
|
<data android:host="spotify.com" />
|
||||||
|
<data android:host="dailymotion.com" />
|
||||||
|
<data android:host="www.dailymotion.com" />
|
||||||
|
<data android:host="bitchute.com" />
|
||||||
|
<data android:host="www.bitchute.com" />
|
||||||
|
<data android:host="old.bitchute.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
1
app/src/stable/assets/sources/bitchute
Submodule
1
app/src/stable/assets/sources/bitchute
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 41fe8f79735176cd8a0ae8c971936cafed00fa16
|
1
app/src/stable/assets/sources/dailymotion
Submodule
1
app/src/stable/assets/sources/dailymotion
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 069aa3d31a35559e45c1fe1ea1eb2a94d3b5d120
|
@ -10,7 +10,9 @@
|
|||||||
"aac9e9f0-24b5-11ee-be56-0242ac120002": "sources/patreon/PatreonConfig.json",
|
"aac9e9f0-24b5-11ee-be56-0242ac120002": "sources/patreon/PatreonConfig.json",
|
||||||
"9d703ff5-c556-4962-a990-4f000829cb87": "sources/nebula/NebulaConfig.json",
|
"9d703ff5-c556-4962-a990-4f000829cb87": "sources/nebula/NebulaConfig.json",
|
||||||
"cf8ea74d-ad9b-489e-a083-539b6aa8648c": "sources/bilibili/build/BiliBiliConfig.json",
|
"cf8ea74d-ad9b-489e-a083-539b6aa8648c": "sources/bilibili/build/BiliBiliConfig.json",
|
||||||
"4e365633-6d3f-4267-8941-fdc36631d813": "sources/spotify/build/SpotifyConfig.json"
|
"4e365633-6d3f-4267-8941-fdc36631d813": "sources/spotify/build/SpotifyConfig.json",
|
||||||
|
"9c87e8db-e75d-48f4-afe5-2d203d4b95c5": "sources/dailymotion/build/DailymotionConfig.json",
|
||||||
|
"e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json"
|
||||||
},
|
},
|
||||||
"SOURCES_EMBEDDED_DEFAULT": [
|
"SOURCES_EMBEDDED_DEFAULT": [
|
||||||
"35ae969a-a7db-11ed-afa1-0242ac120002"
|
"35ae969a-a7db-11ed-afa1-0242ac120002"
|
||||||
|
@ -34,6 +34,11 @@
|
|||||||
<data android:host="bilibili.com" />
|
<data android:host="bilibili.com" />
|
||||||
<data android:host="bilibili.tv" />
|
<data android:host="bilibili.tv" />
|
||||||
<data android:host="spotify.com" />
|
<data android:host="spotify.com" />
|
||||||
|
<data android:host="dailymotion.com" />
|
||||||
|
<data android:host="www.dailymotion.com" />
|
||||||
|
<data android:host="bitchute.com" />
|
||||||
|
<data android:host="www.bitchute.com" />
|
||||||
|
<data android:host="old.bitchute.com" />
|
||||||
<data android:pathPrefix="/" />
|
<data android:pathPrefix="/" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter android:autoVerify="true">
|
<intent-filter android:autoVerify="true">
|
||||||
@ -58,6 +63,11 @@
|
|||||||
<data android:host="bilibili.com" />
|
<data android:host="bilibili.com" />
|
||||||
<data android:host="bilibili.tv" />
|
<data android:host="bilibili.tv" />
|
||||||
<data android:host="spotify.com" />
|
<data android:host="spotify.com" />
|
||||||
|
<data android:host="dailymotion.com" />
|
||||||
|
<data android:host="www.dailymotion.com" />
|
||||||
|
<data android:host="bitchute.com" />
|
||||||
|
<data android:host="www.bitchute.com" />
|
||||||
|
<data android:host="old.bitchute.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
1
app/src/unstable/assets/sources/bitchute
Submodule
1
app/src/unstable/assets/sources/bitchute
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 41fe8f79735176cd8a0ae8c971936cafed00fa16
|
1
app/src/unstable/assets/sources/dailymotion
Submodule
1
app/src/unstable/assets/sources/dailymotion
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 069aa3d31a35559e45c1fe1ea1eb2a94d3b5d120
|
@ -10,7 +10,9 @@
|
|||||||
"aac9e9f0-24b5-11ee-be56-0242ac120002": "sources/patreon/PatreonConfig.json",
|
"aac9e9f0-24b5-11ee-be56-0242ac120002": "sources/patreon/PatreonConfig.json",
|
||||||
"9d703ff5-c556-4962-a990-4f000829cb87": "sources/nebula/NebulaConfig.json",
|
"9d703ff5-c556-4962-a990-4f000829cb87": "sources/nebula/NebulaConfig.json",
|
||||||
"cf8ea74d-ad9b-489e-a083-539b6aa8648c": "sources/bilibili/build/BiliBiliConfig.json",
|
"cf8ea74d-ad9b-489e-a083-539b6aa8648c": "sources/bilibili/build/BiliBiliConfig.json",
|
||||||
"4e365633-6d3f-4267-8941-fdc36631d813": "sources/spotify/build/SpotifyConfig.json"
|
"4e365633-6d3f-4267-8941-fdc36631d813": "sources/spotify/build/SpotifyConfig.json",
|
||||||
|
"9c87e8db-e75d-48f4-afe5-2d203d4b95c5": "sources/dailymotion/build/DailymotionConfig.json",
|
||||||
|
"e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json"
|
||||||
},
|
},
|
||||||
"SOURCES_EMBEDDED_DEFAULT": [
|
"SOURCES_EMBEDDED_DEFAULT": [
|
||||||
"35ae969a-a7db-11ed-afa1-0242ac120002"
|
"35ae969a-a7db-11ed-afa1-0242ac120002"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user