mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-16 04:52:39 +02:00
Properly propagated request modifier in casting.
This commit is contained in:
+39
-9
@@ -5,6 +5,7 @@ import android.util.Log
|
||||
import com.futo.platformplayer.api.http.server.HttpContext
|
||||
import com.futo.platformplayer.api.http.server.HttpHeaders
|
||||
import com.futo.platformplayer.api.http.ManagedHttpClient
|
||||
import com.futo.platformplayer.api.media.models.modifier.IRequest
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.parsers.HttpResponseParser
|
||||
import com.futo.platformplayer.readLine
|
||||
@@ -27,6 +28,7 @@ class HttpProxyHandler(method: String, path: String, val targetUrl: String, priv
|
||||
private var _injectReferer = false;
|
||||
|
||||
private val _client = ManagedHttpClient();
|
||||
private var _requestModifier: ((String, Map<String, String>) -> IRequest)? = null;
|
||||
|
||||
override fun handle(context: HttpContext) {
|
||||
if (useTcp) {
|
||||
@@ -43,21 +45,33 @@ class HttpProxyHandler(method: String, path: String, val targetUrl: String, priv
|
||||
for (injectHeader in _injectRequestHeader)
|
||||
proxyHeaders[injectHeader.first] = injectHeader.second;
|
||||
|
||||
val parsed = Uri.parse(targetUrl);
|
||||
val req = _requestModifier?.invoke(targetUrl, proxyHeaders)
|
||||
var url = targetUrl
|
||||
if (req != null) {
|
||||
req.url?.let {
|
||||
url = it
|
||||
}
|
||||
req.headers.let {
|
||||
proxyHeaders.clear()
|
||||
proxyHeaders.putAll(it)
|
||||
}
|
||||
}
|
||||
|
||||
val parsed = Uri.parse(url);
|
||||
if(_injectHost)
|
||||
proxyHeaders.put("Host", parsed.host!!);
|
||||
if(_injectReferer)
|
||||
proxyHeaders.put("Referer", targetUrl);
|
||||
proxyHeaders.put("Referer", url);
|
||||
|
||||
val useMethod = if (method == "inherit") context.method else method;
|
||||
Logger.i(TAG, "handleWithOkHttp Proxied Request ${useMethod}: ${targetUrl}");
|
||||
Logger.i(TAG, "handleWithOkHttp Proxied Request ${useMethod}: ${url}");
|
||||
Logger.i(TAG, "handleWithOkHttp Headers:" + proxyHeaders.map { "${it.key}: ${it.value}" }.joinToString("\n"));
|
||||
|
||||
val resp = when (useMethod) {
|
||||
"GET" -> _client.get(targetUrl, proxyHeaders);
|
||||
"POST" -> _client.post(targetUrl, content ?: "", proxyHeaders);
|
||||
"HEAD" -> _client.head(targetUrl, proxyHeaders)
|
||||
else -> _client.requestMethod(useMethod, targetUrl, proxyHeaders);
|
||||
"GET" -> _client.get(url, proxyHeaders);
|
||||
"POST" -> _client.post(url, content ?: "", proxyHeaders);
|
||||
"HEAD" -> _client.head(url, proxyHeaders)
|
||||
else -> _client.requestMethod(useMethod, url, proxyHeaders);
|
||||
};
|
||||
|
||||
Logger.i(TAG, "Proxied Response [${resp.code}]");
|
||||
@@ -91,11 +105,23 @@ class HttpProxyHandler(method: String, path: String, val targetUrl: String, priv
|
||||
for (injectHeader in _injectRequestHeader)
|
||||
proxyHeaders[injectHeader.first] = injectHeader.second;
|
||||
|
||||
val parsed = Uri.parse(targetUrl);
|
||||
val req = _requestModifier?.invoke(targetUrl, proxyHeaders)
|
||||
var url = targetUrl
|
||||
if (req != null) {
|
||||
req.url?.let {
|
||||
url = it
|
||||
}
|
||||
req.headers.let {
|
||||
proxyHeaders.clear()
|
||||
proxyHeaders.putAll(it)
|
||||
}
|
||||
}
|
||||
|
||||
val parsed = Uri.parse(url);
|
||||
if(_injectHost)
|
||||
proxyHeaders.put("Host", parsed.host!!);
|
||||
if(_injectReferer)
|
||||
proxyHeaders.put("Referer", targetUrl);
|
||||
proxyHeaders.put("Referer", url);
|
||||
|
||||
val useMethod = if (method == "inherit") context.method else method;
|
||||
Logger.i(TAG, "handleWithTcp Proxied Request ${useMethod}: ${parsed}");
|
||||
@@ -242,6 +268,10 @@ class HttpProxyHandler(method: String, path: String, val targetUrl: String, priv
|
||||
_ignoreRequestHeaders.add("referer");
|
||||
return this;
|
||||
}
|
||||
fun withRequestModifier(modifier: (String, Map<String, String>) -> IRequest) : HttpProxyHandler {
|
||||
_requestModifier = modifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "HttpProxyHandler"
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.futo.platformplayer.api.http.server.handlers.HttpConstantHandler
|
||||
import com.futo.platformplayer.api.http.server.handlers.HttpFileHandler
|
||||
import com.futo.platformplayer.api.http.server.handlers.HttpFunctionHandler
|
||||
import com.futo.platformplayer.api.http.server.handlers.HttpProxyHandler
|
||||
import com.futo.platformplayer.api.media.models.modifier.IRequestModifier
|
||||
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
|
||||
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
|
||||
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
|
||||
@@ -295,20 +296,63 @@ abstract class StateCasting {
|
||||
val url = getLocalUrl(ad);
|
||||
val id = UUID.randomUUID();
|
||||
|
||||
|
||||
if (videoSource is IVideoUrlSource) {
|
||||
val videoPath = "/video-${id}"
|
||||
val videoUrl = if(proxyStreams) url + videoPath else videoSource.getVideoUrl();
|
||||
Logger.i(TAG, "Casting as singular video");
|
||||
ad.loadVideo(if (video.isLive) "LIVE" else "BUFFERED", videoSource.container, videoUrl, resumePosition, video.duration.toDouble(), speed, metadataFromVideo(video));
|
||||
val videoPath = "/video-$id"
|
||||
val upstreamUrl = videoSource.getVideoUrl()
|
||||
val videoUrl = if (proxyStreams) url + videoPath else upstreamUrl
|
||||
val jsReqMod = (videoSource as? JSSource)?.getRequestModifier()
|
||||
|
||||
if (proxyStreams) {
|
||||
_castServer.addHandlerWithAllowAllOptions(
|
||||
HttpProxyHandler("GET", videoPath, upstreamUrl, true)
|
||||
.withIRequestModifier(jsReqMod)
|
||||
.withInjectedHost()
|
||||
.withHeader("Access-Control-Allow-Origin", "*"),
|
||||
true
|
||||
).withTag("castSingular")
|
||||
}
|
||||
|
||||
Logger.i(TAG, "Casting as singular video (proxy=$proxyStreams, url=$videoUrl)")
|
||||
ad.loadVideo(
|
||||
if (video.isLive) "LIVE" else "BUFFERED",
|
||||
videoSource.container,
|
||||
videoUrl,
|
||||
resumePosition,
|
||||
video.duration.toDouble(),
|
||||
speed,
|
||||
metadataFromVideo(video)
|
||||
)
|
||||
} else if (audioSource is IAudioUrlSource) {
|
||||
val audioPath = "/audio-${id}"
|
||||
val audioUrl = if(proxyStreams) url + audioPath else audioSource.getAudioUrl();
|
||||
Logger.i(TAG, "Casting as singular audio");
|
||||
ad.loadVideo(if (video.isLive) "LIVE" else "BUFFERED", audioSource.container, audioUrl, resumePosition, video.duration.toDouble(), speed, metadataFromVideo(video));
|
||||
val audioPath = "/audio-$id"
|
||||
val upstreamUrl = audioSource.getAudioUrl()
|
||||
val audioUrl = if (proxyStreams) url + audioPath else upstreamUrl
|
||||
val jsReqMod = (audioSource as? JSSource)?.getRequestModifier()
|
||||
|
||||
if (proxyStreams) {
|
||||
_castServer.addHandlerWithAllowAllOptions(
|
||||
HttpProxyHandler("GET", audioPath, upstreamUrl, true)
|
||||
.withIRequestModifier(jsReqMod)
|
||||
.withInjectedHost()
|
||||
.withHeader("Access-Control-Allow-Origin", "*"),
|
||||
true
|
||||
).withTag("castSingular")
|
||||
}
|
||||
|
||||
Logger.i(TAG, "Casting as singular audio (proxy=$proxyStreams, url=$audioUrl)")
|
||||
ad.loadVideo(
|
||||
if (video.isLive) "LIVE" else "BUFFERED",
|
||||
audioSource.container,
|
||||
audioUrl,
|
||||
resumePosition,
|
||||
video.duration.toDouble(),
|
||||
speed,
|
||||
metadataFromVideo(video)
|
||||
)
|
||||
} else if (videoSource is IHLSManifestSource) {
|
||||
if (proxyStreams || deviceProto == CastProtocolType.CHROMECAST) {
|
||||
Logger.i(TAG, "Casting as proxied HLS");
|
||||
castProxiedHls(video, videoSource.url, videoSource.codec, resumePosition, speed);
|
||||
castProxiedHls(video, videoSource.url, videoSource.codec, resumePosition, speed, (videoSource as JSSource?)?.getRequestModifier());
|
||||
} else {
|
||||
Logger.i(TAG, "Casting as non-proxied HLS");
|
||||
ad.loadVideo(if (video.isLive) "LIVE" else "BUFFERED", videoSource.container, videoSource.url, resumePosition, video.duration.toDouble(), speed, metadataFromVideo(video));
|
||||
@@ -316,7 +360,7 @@ abstract class StateCasting {
|
||||
} else if (audioSource is IHLSManifestAudioSource) {
|
||||
if (proxyStreams || deviceProto == CastProtocolType.CHROMECAST) {
|
||||
Logger.i(TAG, "Casting as proxied audio HLS");
|
||||
castProxiedHls(video, audioSource.url, audioSource.codec, resumePosition, speed);
|
||||
castProxiedHls(video, audioSource.url, audioSource.codec, resumePosition, speed, (audioSource as JSSource?)?.getRequestModifier());
|
||||
} else {
|
||||
Logger.i(TAG, "Casting as non-proxied audio HLS");
|
||||
ad.loadVideo(if (video.isLive) "LIVE" else "BUFFERED", audioSource.container, audioSource.url, resumePosition, video.duration.toDouble(), speed, metadataFromVideo(video));
|
||||
@@ -347,6 +391,11 @@ abstract class StateCasting {
|
||||
}
|
||||
}
|
||||
|
||||
private fun HttpProxyHandler.withIRequestModifier(requestModifier: IRequestModifier?): HttpProxyHandler {
|
||||
if (requestModifier == null) return this
|
||||
return withRequestModifier { url, headers -> requestModifier.modifyRequest(url, headers) }
|
||||
}
|
||||
|
||||
fun resumeVideo(): Boolean {
|
||||
val ad = activeDevice ?: return false;
|
||||
try {
|
||||
@@ -665,7 +714,8 @@ abstract class StateCasting {
|
||||
sourceUrl: String,
|
||||
codec: String?,
|
||||
resumePosition: Double,
|
||||
speed: Double?
|
||||
speed: Double?,
|
||||
requestModifier: IRequestModifier?
|
||||
): List<String> {
|
||||
_castServer.removeAllHandlers("castProxiedHlsMaster")
|
||||
|
||||
@@ -686,7 +736,9 @@ abstract class StateCasting {
|
||||
val headers = masterContext.headers.clone()
|
||||
headers["Content-Type"] = "application/vnd.apple.mpegurl";
|
||||
|
||||
val masterPlaylistResponse = _client.get(sourceUrl)
|
||||
val req = requestModifier?.modifyRequest(sourceUrl, mapOf())
|
||||
val masterPlaylistResponse = _client.get(req?.url ?: sourceUrl, (req?.headers ?: mapOf()).toMutableMap())
|
||||
|
||||
check(masterPlaylistResponse.isOk) { "Failed to get master playlist: ${masterPlaylistResponse.code}" }
|
||||
|
||||
val masterPlaylistContent = masterPlaylistResponse.body?.string()
|
||||
@@ -706,7 +758,7 @@ abstract class StateCasting {
|
||||
val variantPlaylist =
|
||||
HLS.parseVariantPlaylist(masterPlaylistContent, sourceUrl)
|
||||
val proxiedVariantPlaylist =
|
||||
proxyVariantPlaylist(url, id, variantPlaylist, video.isLive)
|
||||
proxyVariantPlaylist(url, id, variantPlaylist, video.isLive, requestModifier)
|
||||
val proxiedVariantPlaylist_m3u8 = proxiedVariantPlaylist.buildM3U8()
|
||||
masterContext.respondCode(200, vpHeaders, proxiedVariantPlaylist_m3u8);
|
||||
return@HttpFunctionHandler
|
||||
@@ -747,7 +799,7 @@ abstract class StateCasting {
|
||||
val variantPlaylist =
|
||||
HLS.parseVariantPlaylist(vpContent, variantPlaylistRef.url)
|
||||
val proxiedVariantPlaylist =
|
||||
proxyVariantPlaylist(url, playlistId, variantPlaylist, video.isLive)
|
||||
proxyVariantPlaylist(url, playlistId, variantPlaylist, video.isLive, requestModifier)
|
||||
val proxiedVariantPlaylist_m3u8 = proxiedVariantPlaylist.buildM3U8()
|
||||
vpContext.respondCode(200, vpHeaders, proxiedVariantPlaylist_m3u8);
|
||||
}.withHeader("Access-Control-Allow-Origin", "*"), true
|
||||
@@ -784,7 +836,7 @@ abstract class StateCasting {
|
||||
val variantPlaylist =
|
||||
HLS.parseVariantPlaylist(vpContent, mediaRendition.uri)
|
||||
val proxiedVariantPlaylist = proxyVariantPlaylist(
|
||||
url, playlistId, variantPlaylist, video.isLive
|
||||
url, playlistId, variantPlaylist, video.isLive, requestModifier
|
||||
)
|
||||
val proxiedVariantPlaylist_m3u8 = proxiedVariantPlaylist.buildM3U8()
|
||||
vpContext.respondCode(200, vpHeaders, proxiedVariantPlaylist_m3u8);
|
||||
@@ -826,13 +878,13 @@ abstract class StateCasting {
|
||||
return listOf(hlsUrl);
|
||||
}
|
||||
|
||||
private fun proxyVariantPlaylist(url: String, playlistId: UUID, variantPlaylist: HLS.VariantPlaylist, isLive: Boolean, proxySegments: Boolean = true): HLS.VariantPlaylist {
|
||||
private fun proxyVariantPlaylist(url: String, playlistId: UUID, variantPlaylist: HLS.VariantPlaylist, isLive: Boolean, requestModifier: IRequestModifier?, proxySegments: Boolean = true): HLS.VariantPlaylist {
|
||||
val newSegments = arrayListOf<HLS.Segment>()
|
||||
|
||||
if (proxySegments) {
|
||||
variantPlaylist.segments.forEachIndexed { index, segment ->
|
||||
val sequenceNumber = (variantPlaylist.mediaSequence ?: 0) + index.toLong()
|
||||
newSegments.add(proxySegment(url, playlistId, segment, sequenceNumber))
|
||||
newSegments.add(proxySegment(url, playlistId, segment, sequenceNumber, requestModifier))
|
||||
}
|
||||
} else {
|
||||
newSegments.addAll(variantPlaylist.segments)
|
||||
@@ -850,7 +902,7 @@ abstract class StateCasting {
|
||||
)
|
||||
}
|
||||
|
||||
private fun proxySegment(url: String, playlistId: UUID, segment: HLS.Segment, index: Long): HLS.Segment {
|
||||
private fun proxySegment(url: String, playlistId: UUID, segment: HLS.Segment, index: Long, requestModifier: IRequestModifier?): HLS.Segment {
|
||||
if (segment is HLS.MediaSegment) {
|
||||
val newSegmentPath = "/hls-playlist-${playlistId}-segment-${index}"
|
||||
val newSegmentUrl = url + newSegmentPath;
|
||||
@@ -858,6 +910,7 @@ abstract class StateCasting {
|
||||
if (_castServer.getHandler("GET", newSegmentPath) == null) {
|
||||
_castServer.addHandlerWithAllowAllOptions(
|
||||
HttpProxyHandler("GET", newSegmentPath, segment.uri, true)
|
||||
.withIRequestModifier(requestModifier)
|
||||
.withInjectedHost()
|
||||
.withHeader("Access-Control-Allow-Origin", "*"), true
|
||||
).withTag("castProxiedHlsVariant")
|
||||
|
||||
Reference in New Issue
Block a user