mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
YT: resolve redirects on the Clapper side
Instead of providing URIs directly to GStreamer, follow redirects and provide that final URI. With this change souphttpsrc will not have to go through redirects from the beginning for each video segment.
This commit is contained in:
38
src/dash.js
38
src/dash.js
@@ -4,29 +4,11 @@ const Misc = imports.src.misc;
|
||||
|
||||
const { debug } = Debug;
|
||||
|
||||
function generateDash(info)
|
||||
function generateDash(dashInfo)
|
||||
{
|
||||
if(
|
||||
!info.streamingData
|
||||
|| !info.streamingData.adaptiveFormats
|
||||
|| !info.streamingData.adaptiveFormats.length
|
||||
)
|
||||
return null;
|
||||
|
||||
debug('generating dash');
|
||||
|
||||
/* TODO: Options in prefs to set preferred video formats for adaptive streaming */
|
||||
const videoStream = info.streamingData.adaptiveFormats.find(stream => {
|
||||
return (stream.mimeType.startsWith('video/mp4') && stream.quality === 'hd1080');
|
||||
});
|
||||
const audioStream = info.streamingData.adaptiveFormats.find(stream => {
|
||||
return (stream.mimeType.startsWith('audio/mp4'));
|
||||
});
|
||||
|
||||
if(!videoStream || !audioStream)
|
||||
return null;
|
||||
|
||||
const bufferSec = Math.min(4, info.videoDetails.lengthSeconds);
|
||||
const bufferSec = Math.min(4, dashInfo.duration);
|
||||
|
||||
const dash = [
|
||||
`<?xml version="1.0" encoding="UTF-8"?>`,
|
||||
@@ -34,19 +16,23 @@ function generateDash(info)
|
||||
` xmlns="urn:mpeg:dash:schema:mpd:2011"`,
|
||||
` xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd"`,
|
||||
` type="static"`,
|
||||
` mediaPresentationDuration="PT${info.videoDetails.lengthSeconds}S"`,
|
||||
` mediaPresentationDuration="PT${dashInfo.duration}S"`,
|
||||
` minBufferTime="PT${bufferSec}S"`,
|
||||
` profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">`,
|
||||
` <Period>`,
|
||||
_addAdaptationSet([videoStream]),
|
||||
_addAdaptationSet([audioStream]),
|
||||
` <Period>`
|
||||
];
|
||||
|
||||
for(let adaptation of dashInfo.adaptations)
|
||||
dash.push(_addAdaptationSet(adaptation));
|
||||
|
||||
dash.push(
|
||||
` </Period>`,
|
||||
`</MPD>`
|
||||
].join('\n');
|
||||
);
|
||||
|
||||
debug('dash generated');
|
||||
|
||||
return dash;
|
||||
return dash.join('\n');
|
||||
}
|
||||
|
||||
function _addAdaptationSet(streamsArr)
|
||||
|
@@ -86,16 +86,23 @@ class ClapperPlayer extends PlayerBase
|
||||
if(!info)
|
||||
throw new Error('no YouTube video info');
|
||||
|
||||
const dash = Dash.generateDash(info);
|
||||
let videoUri = null;
|
||||
const dashInfo = await this.ytClient.getDashInfoAsync(info).catch(debug);
|
||||
|
||||
if(dash) {
|
||||
const dashFile = await FileOps.saveFilePromise(
|
||||
'tmp', null, 'clapper.mpd', dash
|
||||
).catch(debug);
|
||||
if(dashInfo) {
|
||||
debug('parsed video info to dash info');
|
||||
const dash = Dash.generateDash(dashInfo);
|
||||
|
||||
if(dashFile)
|
||||
videoUri = dashFile.get_uri();
|
||||
if(dash) {
|
||||
debug('got dash');
|
||||
|
||||
const dashFile = await FileOps.saveFilePromise(
|
||||
'tmp', null, 'clapper.mpd', dash
|
||||
).catch(debug);
|
||||
|
||||
if(dashFile)
|
||||
videoUri = dashFile.get_uri();
|
||||
}
|
||||
}
|
||||
|
||||
if(!videoUri)
|
||||
|
@@ -23,7 +23,7 @@ var YouTubeClient = GObject.registerClass({
|
||||
_init()
|
||||
{
|
||||
super._init({
|
||||
timeout: 5,
|
||||
timeout: 7,
|
||||
max_conns_per_host: 1,
|
||||
/* TODO: share this with GstClapper lib (define only once) */
|
||||
user_agent: 'Mozilla/5.0 (X11; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0',
|
||||
@@ -190,7 +190,10 @@ var YouTubeClient = GObject.registerClass({
|
||||
debug(`found player URI: ${ytUri}`);
|
||||
|
||||
const ytId = ytPath.split('/').find(el => Misc.isHex(el));
|
||||
let ytSigData = await FileOps.getFileContentsPromise('user_cache', 'yt-sig', ytId).catch(debug);
|
||||
let ytSigData = await FileOps.getFileContentsPromise(
|
||||
'user_cache', 'yt-sig', ytId
|
||||
).catch(debug);
|
||||
|
||||
if(ytSigData) {
|
||||
ytSigData = ytSigData.split(';');
|
||||
|
||||
@@ -299,8 +302,53 @@ var YouTubeClient = GObject.registerClass({
|
||||
});
|
||||
}
|
||||
|
||||
async getDashInfoAsync(info)
|
||||
{
|
||||
if(
|
||||
!info.streamingData
|
||||
|| !info.streamingData.adaptiveFormats
|
||||
|| !info.streamingData.adaptiveFormats.length
|
||||
)
|
||||
return null;
|
||||
|
||||
/* TODO: Options in prefs to set preferred video formats for adaptive streaming */
|
||||
const videoStream = info.streamingData.adaptiveFormats.find(stream => {
|
||||
return (stream.mimeType.startsWith('video/mp4') && stream.quality === 'hd1080');
|
||||
});
|
||||
const audioStream = info.streamingData.adaptiveFormats.find(stream => {
|
||||
return (stream.mimeType.startsWith('audio/mp4'));
|
||||
});
|
||||
|
||||
if(!videoStream || !audioStream)
|
||||
return null;
|
||||
|
||||
debug('following redirects');
|
||||
|
||||
for(let stream of [videoStream, audioStream]) {
|
||||
debug(`initial URL: ${stream.url}`);
|
||||
|
||||
const result = await this._downloadDataPromise(stream.url, 'HEAD').catch(debug);
|
||||
if(!result) return null;
|
||||
|
||||
stream.url = result.uri;
|
||||
debug(`resolved URL: ${stream.url}`);
|
||||
}
|
||||
|
||||
debug('all redirects resolved');
|
||||
|
||||
return {
|
||||
duration: info.videoDetails.lengthSeconds,
|
||||
adaptations: [
|
||||
[videoStream],
|
||||
[audioStream],
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
getBestCombinedUri(info)
|
||||
{
|
||||
debug('obtaining best combined URL');
|
||||
|
||||
if(!info.streamingData.formats.length)
|
||||
return null;
|
||||
|
||||
@@ -332,11 +380,14 @@ var YouTubeClient = GObject.registerClass({
|
||||
|
||||
_downloadDataPromise(url, method, reqData)
|
||||
{
|
||||
method = method || 'GET';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const message = Soup.Message.new(method || 'GET', url);
|
||||
const message = Soup.Message.new(method, url);
|
||||
const result = {
|
||||
data: null,
|
||||
isAborted: false,
|
||||
uri: null,
|
||||
};
|
||||
|
||||
if(reqData) {
|
||||
@@ -353,6 +404,10 @@ var YouTubeClient = GObject.registerClass({
|
||||
|
||||
if(statusCode === 200) {
|
||||
result.data = msg.response_body.data;
|
||||
|
||||
if(method === 'HEAD')
|
||||
result.uri = msg.uri.to_string(false);
|
||||
|
||||
return resolve(result);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user