Open VoxelPrismatic opened 1 week ago
Without the custom getRequestExectutor in my plugin, grayjay throws a toast "Block detected, attempting bypass"
However, I cannot hijack this getRequestExecutor such that executeRequest is called for every segment. It is only ever called to download the initial M3U8 manifest, and not for any of the segments.
https://github.com/user-attachments/assets/d4391207-6e56-465a-9457-db244b3cae5a
[INFO]
Call [requestExecutor.executeRequest()] succesful [104ms]
[INFO]
EXECUTOR! ~ executeRequest: https://cdn-vod-drm2.floatplane.com/Videos/skJTMsWmgd/720.mp4/chunk.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvNzIwLm1wNC9jaHVuay5tM3U4IiwicmVzc291cmNlUGF0aCI6Ii9WaWRlb3Mvc2tKVE1zV21nZC83MjAubXA0L2NodW5rLm0zdTgiLCJ1c2VySWQiOiI1YzNlNGU2ZDdhM2YwNjI0MjdkMzQ5MjAiLCJpYXQiOjE3MjkxOTkwMDAsImV4cCI6MTcyOTIyMDYwMH0.CTu2x2xnm8lJeXsL95K4RsKcBfOzOiZZ6PwiJlzbukA
[INFO]
Call [requestExecutor.executeRequest()] succesful [72ms]
[INFO]
EXECUTOR! ~ executeRequest: https://cdn-vod-drm2.floatplane.com/Videos/skJTMsWmgd/480.mp4/chunk.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvNDgwLm1wNC9jaHVuay5tM3U4IiwicmVzc291cmNlUGF0aCI6Ii9WaWRlb3Mvc2tKVE1zV21nZC80ODAubXA0L2NodW5rLm0zdTgiLCJ1c2VySWQiOiI1YzNlNGU2ZDdhM2YwNjI0MjdkMzQ5MjAiLCJpYXQiOjE3MjkxOTkwMDAsImV4cCI6MTcyOTIyMDYwMH0.YauQiaDr3fO525yixUUQAzeOAzlo9svaCIj51b-vte0
[INFO]
Call [requestExecutor.executeRequest()] succesful [60ms]
[INFO]
EXECUTOR! ~ executeRequest: https://cdn-vod-drm2.floatplane.com/Videos/skJTMsWmgd/360.mp4/chunk.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvMzYwLm1wNC9jaHVuay5tM3U4IiwicmVzc291cmNlUGF0aCI6Ii9WaWRlb3Mvc2tKVE1zV21nZC8zNjAubXA0L2NodW5rLm0zdTgiLCJ1c2VySWQiOiI1YzNlNGU2ZDdhM2YwNjI0MjdkMzQ5MjAiLCJpYXQiOjE3MjkxOTkwMDAsImV4cCI6MTcyOTIyMDYwMH0.Oz-ae4wc6Wwfi94jaYFy_wckuwaKjFs9kfGRGXBL9DY
[INFO]
Call [isVideoDetailsUrl("https://www.floatplane.com/post/l64I6dJA1X")] succesful [0ms]
[INFO]
Call [isVideoDetailsUrl("https://www.floatplane.com/post/l64I6dJA1X")] succesful [0ms]
[INFO]
Call [isVideoDetailsUrl("https://www.floatplane.com/post/l64I6dJA1X")] succesful [0ms]
[INFO]
Call [isVideoDetailsUrl("https://www.floatplane.com/post/l64I6dJA1X")] succesful [0ms]
[INFO]
Call [getVideoDetails] succesful [923ms]
[INFO]
[
{
"plugin_type": "HLSSource",
"name": "#1a=360p - I bought 2700 Compact Discs. *Floatplane edit*",
"duration": 1101,
"url": "https://cdn-vod-drm2.floatplane.com/Videos/skJTMsWmgd/360.mp4/chunk.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvMzYwLm1wNC9jaHVuay5tM3U4IiwicmVzc291cmNlUGF0aCI6Ii9WaWRlb3Mvc2tKVE1zV21nZC8zNjAubXA0L2NodW5rLm0zdTgiLCJ1c2VySWQiOiI1YzNlNGU2ZDdhM2YwNjI0MjdkMzQ5MjAiLCJpYXQiOjE3MjkxOTkwMDAsImV4cCI6MTcyOTIyMDYwMH0.Oz-ae4wc6Wwfi94jaYFy_wckuwaKjFs9kfGRGXBL9DY",
"priority": false
},
{
"plugin_type": "HLSSource",
"name": "#1a=480p - I bought 2700 Compact Discs. *Floatplane edit*",
"duration": 1101,
"url": "https://cdn-vod-drm2.floatplane.com/Videos/skJTMsWmgd/480.mp4/chunk.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvNDgwLm1wNC9jaHVuay5tM3U4IiwicmVzc291cmNlUGF0aCI6Ii9WaWRlb3Mvc2tKVE1zV21nZC80ODAubXA0L2NodW5rLm0zdTgiLCJ1c2VySWQiOiI1YzNlNGU2ZDdhM2YwNjI0MjdkMzQ5MjAiLCJpYXQiOjE3MjkxOTkwMDAsImV4cCI6MTcyOTIyMDYwMH0.YauQiaDr3fO525yixUUQAzeOAzlo9svaCIj51b-vte0",
"priority": false
},
{
"plugin_type": "HLSSource",
"name": "#1a=720p - I bought 2700 Compact Discs. *Floatplane edit*",
"duration": 1101,
"url": "https://cdn-vod-drm2.floatplane.com/Videos/skJTMsWmgd/720.mp4/chunk.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvNzIwLm1wNC9jaHVuay5tM3U4IiwicmVzc291cmNlUGF0aCI6Ii9WaWRlb3Mvc2tKVE1zV21nZC83MjAubXA0L2NodW5rLm0zdTgiLCJ1c2VySWQiOiI1YzNlNGU2ZDdhM2YwNjI0MjdkMzQ5MjAiLCJpYXQiOjE3MjkxOTkwMDAsImV4cCI6MTcyOTIyMDYwMH0.CTu2x2xnm8lJeXsL95K4RsKcBfOzOiZZ6PwiJlzbukA",
"priority": false
},
{
"plugin_type": "HLSSource",
"name": "#1a=1080p - I bought 2700 Compact Discs. *Floatplane edit*",
"duration": 1101,
"url": "https://cdn-vod-drm2.floatplane.com/Videos/skJTMsWmgd/1080.mp4/chunk.m3u8?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZXNvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvMTA4MC5tcDQvY2h1bmsubTN1OCIsInJlc3NvdXJjZVBhdGgiOiIvVmlkZW9zL3NrSlRNc1dtZ2QvMTA4MC5tcDQvY2h1bmsubTN1OCIsInVzZXJJZCI6IjVjM2U0ZTZkN2EzZjA2MjQyN2QzNDkyMCIsImlhdCI6MTcyOTE5OTAwMCwiZXhwIjoxNzI5MjIwNjAwfQ.trmtllAemWOmVRA-pv1dFoTEek2CqKtlbJ_6Cav4jZg",
"priority": false
}
]
[INFO]
EXECUTOR! ~ constructor
[INFO]
https://www.floatplane.com/api/video/watchKey?token=eyJwYXRoIjoiL1ZpZGVvcy9za0pUTXNXbWdkLzEwODAubXA0IiwidGltZXN0YW1wIjoxNzI5MTIzMjAwMDAwfQ
[INFO]
EXECUTOR! ~ constructor
[INFO]
https://www.floatplane.com/api/video/watchKey?token=eyJwYXRoIjoiL1ZpZGVvcy9za0pUTXNXbWdkLzcyMC5tcDQiLCJ0aW1lc3RhbXAiOjE3MjkxMjMyMDAwMDB9
[INFO]
EXECUTOR! ~ constructor
[INFO]
https://www.floatplane.com/api/video/watchKey?token=eyJwYXRoIjoiL1ZpZGVvcy9za0pUTXNXbWdkLzQ4MC5tcDQiLCJ0aW1lc3RhbXAiOjE3MjkxMjMyMDAwMDB9
[INFO]
EXECUTOR! ~ constructor
[INFO]
https://www.floatplane.com/api/video/watchKey?token=eyJwYXRoIjoiL1ZpZGVvcy9za0pUTXNXbWdkLzM2MC5tcDQiLCJ0aW1lc3RhbXAiOjE3MjkxMjMyMDAwMDB9
[INFO]
Call [isVideoDetailsUrl("https://www.floatplane.com/post/l64I6dJA1X")] succesful [0ms]
From /src/Wrapper.ts:143
export class FP_HLS_Executor {
url: string;
key: CryptoJS.lib.WordArray;
constructor(url: string, key: CryptoJS.lib.WordArray) {
this.url = url;
this.key = key;
log("EXECUTOR! ~ constructor");
}
findSegmentTime(index: number) {
log("EXECUTOR! ~ findSegmentTime");
throw new ScriptException("findSegmentTime not implemented");
}
cacheSegment(segment: object): void {
log("EXECUTOR! ~ cacheSegment");
throw new ScriptException("cacheSegment not implemented");
}
getCachedSegmentCount(): number {
log("EXECUTOR! ~ getCachedSegmentCount");
throw new ScriptException("getCachedSegmentCount not implemented");
}
getCachedSegment(index: number): string {
log("EXECUTOR! ~ getCachedSegment");
throw new ScriptException("getCachedSegment not implemented");
}
freeOldSegments(index: number | string) {
log("EXECUTOR! ~ freeOldSegments");
throw new ScriptException("freeOldSegments not implemented");
}
freeAllSegments(): void {
log("EXECUTOR! ~ freeAllSegments");
throw new ScriptException("freeAllSegments not implemented");
}
cleanup(): void {
log("EXECUTOR! ~ cleanup");
throw new ScriptException("cleanup not implemented");
}
executeRequest(url: string, headers: object, retryCount: number = 0): string {
log("EXECUTOR! ~ executeRequest: " + url);
if(url.includes("/chunk.m3u8?")) {
const resp = http.GET(url, { ...FP_Headers, ...headers }, true);
if(!resp.isOk) {
if(retryCount < 5) {
return this.executeRequest(url, headers, retryCount + 1);
}
throw new ScriptException(`Failed to fetch HLS stream: ${resp.code}`);
}
return "";
}
throw new ScriptException("executeRequest not implemented: " + url);
}
}
From /src/Grayjay.ts:121
import * as FP from "./Wrapper.ts";
function ToGrayjayVideoStream(...) {
//...
const source = new HLSSource({
name: `#${video_index}${group_letter}=${variant.label} - ${title}`,
url: origin + variant.url,
duration: duration,
priority: false
});
const enc_key = FP.getHlsToken(origin + variant.url);
const executor = new FP.FP_HLS_Executor(origin + variant.url, enc_key)
source.getRequestExecutor = () => executor;
return source;
}
*empty string or resp.body in FP_HLS_Executor.executeRequest yields the same result
Affected Pages
n/a
What is the docs issue?
There is no documentation for implementing a custom stream format, as seen in the YouTube plugin: https://gitlab.futo.org/videostreaming/plugins/youtube/-/blob/master/YoutubeScript.js?ref_type=heads#L1960
Therefore, when trying to implement a custom HLS executor that would decode HLS segments, I have no clue how to interface with Grayjay.
Proposal
Document it.
References
See https://github.com/voxelprismatic/grayjay-floatplane for my plugin and developer testing