mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 07:42:23 +02:00
YT: auto select best matching resolution for used monitor
This commit is contained in:
@@ -19,6 +19,7 @@ class ClapperPlayer extends PlayerBase
|
||||
this.needsFastSeekRestore = false;
|
||||
this.customVideoTitle = null;
|
||||
|
||||
this.windowMapped = false;
|
||||
this.canAutoFullscreen = false;
|
||||
this.playOnFullscreen = false;
|
||||
this.quitOnStop = false;
|
||||
@@ -54,7 +55,11 @@ class ClapperPlayer extends PlayerBase
|
||||
if(!this.ytClient)
|
||||
this.ytClient = new YouTube.YouTubeClient();
|
||||
|
||||
this.ytClient.getPlaybackDataAsync(videoId)
|
||||
const { root } = this.widget;
|
||||
const surface = root.get_surface();
|
||||
const monitor = root.display.get_monitor_at_surface(surface);
|
||||
|
||||
this.ytClient.getPlaybackDataAsync(videoId, monitor)
|
||||
.then(data => {
|
||||
this.customVideoTitle = data.title;
|
||||
super.set_uri(data.uri);
|
||||
@@ -121,10 +126,9 @@ class ClapperPlayer extends PlayerBase
|
||||
this.playlistWidget.addItem(uri);
|
||||
}
|
||||
|
||||
const firstTrack = this.playlistWidget.get_row_at_index(0);
|
||||
if(!firstTrack) return;
|
||||
|
||||
firstTrack.activate();
|
||||
/* If not mapped yet, first track will play after map */
|
||||
if(this.windowMapped)
|
||||
this._playFirstTrack();
|
||||
}
|
||||
|
||||
set_subtitles(source)
|
||||
@@ -291,6 +295,14 @@ class ClapperPlayer extends PlayerBase
|
||||
: Gst.filename_to_uri(source);
|
||||
}
|
||||
|
||||
_playFirstTrack()
|
||||
{
|
||||
const firstTrack = this.playlistWidget.get_row_at_index(0);
|
||||
if(!firstTrack) return;
|
||||
|
||||
firstTrack.activate();
|
||||
}
|
||||
|
||||
_performCloseCleanup(window)
|
||||
{
|
||||
window.disconnect(this.closeRequestSignal);
|
||||
@@ -522,6 +534,12 @@ class ClapperPlayer extends PlayerBase
|
||||
}
|
||||
}
|
||||
|
||||
_onWindowMap(window)
|
||||
{
|
||||
this.windowMapped = true;
|
||||
this._playFirstTrack();
|
||||
}
|
||||
|
||||
_onCloseRequest(window)
|
||||
{
|
||||
this._performCloseCleanup(window);
|
||||
|
@@ -578,6 +578,8 @@ class ClapperWidget extends Gtk.Grid
|
||||
|
||||
surface.connect('notify::state', this._onStateNotify.bind(this));
|
||||
surface.connect('layout', this._onLayoutUpdate.bind(this));
|
||||
|
||||
this.player._onWindowMap(window);
|
||||
}
|
||||
|
||||
_clearTimeout(name)
|
||||
|
@@ -3,6 +3,7 @@ const Dash = imports.src.dash;
|
||||
const Debug = imports.src.debug;
|
||||
const FileOps = imports.src.fileOps;
|
||||
const Misc = imports.src.misc;
|
||||
const YTItags = imports.src.youtubeItags;
|
||||
const YTDL = imports.src.assets['node-ytdl-core'];
|
||||
|
||||
const debug = Debug.ytDebug;
|
||||
@@ -304,7 +305,7 @@ var YouTubeClient = GObject.registerClass({
|
||||
});
|
||||
}
|
||||
|
||||
async getPlaybackDataAsync(videoId)
|
||||
async getPlaybackDataAsync(videoId, monitor)
|
||||
{
|
||||
const info = await this.getVideoInfoPromise(videoId).catch(debug);
|
||||
|
||||
@@ -312,7 +313,13 @@ var YouTubeClient = GObject.registerClass({
|
||||
throw new Error('no YouTube video info');
|
||||
|
||||
let uri = null;
|
||||
const dashInfo = await this.getDashInfoAsync(info).catch(debug);
|
||||
const itagOpts = {
|
||||
width: monitor.geometry.width * monitor.scale_factor,
|
||||
height: monitor.geometry.height * monitor.scale_factor,
|
||||
codec: 'h264',
|
||||
types: ['standard', 'hfr'],
|
||||
};
|
||||
const dashInfo = await this.getDashInfoAsync(info, itagOpts).catch(debug);
|
||||
|
||||
if(dashInfo) {
|
||||
debug('parsed video info to dash info');
|
||||
@@ -333,7 +340,7 @@ var YouTubeClient = GObject.registerClass({
|
||||
}
|
||||
|
||||
if(!uri)
|
||||
uri = this.getBestCombinedUri(info);
|
||||
uri = this.getBestCombinedUri(info, itagOpts);
|
||||
|
||||
if(!uri)
|
||||
throw new Error('no YouTube video URI');
|
||||
@@ -349,7 +356,7 @@ var YouTubeClient = GObject.registerClass({
|
||||
return { uri, title };
|
||||
}
|
||||
|
||||
async getDashInfoAsync(info)
|
||||
async getDashInfoAsync(info, itagOpts)
|
||||
{
|
||||
if(
|
||||
!info.streamingData
|
||||
@@ -360,20 +367,10 @@ var YouTubeClient = GObject.registerClass({
|
||||
|
||||
/* TODO: Options in prefs to set preferred video formats and adaptive streaming */
|
||||
const isAdaptiveEnabled = settings.get_boolean('yt-adaptive-enabled');
|
||||
const allowedFormats = {
|
||||
video: [
|
||||
133,
|
||||
134,
|
||||
135,
|
||||
136,
|
||||
137,
|
||||
298,
|
||||
299,
|
||||
],
|
||||
audio: [
|
||||
140,
|
||||
]
|
||||
};
|
||||
|
||||
debug(`obtaining dash itags for resolution: ${itagOpts.width}x${itagOpts.height}`);
|
||||
const dashItags = YTItags.getDashItags(itagOpts);
|
||||
debug(`dash itags: ${JSON.stringify(dashItags)}`);
|
||||
|
||||
const filteredStreams = {
|
||||
video: [],
|
||||
@@ -382,11 +379,11 @@ var YouTubeClient = GObject.registerClass({
|
||||
|
||||
for(let fmt of ['video', 'audio']) {
|
||||
debug(`filtering ${fmt} streams`);
|
||||
let index = allowedFormats[fmt].length;
|
||||
let index = dashItags[fmt].length;
|
||||
|
||||
while(index--) {
|
||||
const itag = allowedFormats[fmt][index];
|
||||
const foundStream = info.streamingData.adaptiveFormats.find(stream => (stream.itag == itag));
|
||||
const itag = dashItags[fmt][index];
|
||||
const foundStream = info.streamingData.adaptiveFormats.find(stream => stream.itag == itag);
|
||||
if(foundStream) {
|
||||
/* Parse and convert mimeType string into object */
|
||||
foundStream.mimeInfo = this._getMimeInfo(foundStream.mimeType);
|
||||
@@ -440,16 +437,33 @@ var YouTubeClient = GObject.registerClass({
|
||||
};
|
||||
}
|
||||
|
||||
getBestCombinedUri(info)
|
||||
getBestCombinedUri(info, itagOpts)
|
||||
{
|
||||
debug('obtaining best combined URL');
|
||||
debug(`obtaining best combined URL for resolution: ${itagOpts.width}x${itagOpts.height}`);
|
||||
|
||||
if(!info.streamingData.formats.length)
|
||||
return null;
|
||||
|
||||
const combinedStream = info.streamingData.formats[
|
||||
info.streamingData.formats.length - 1
|
||||
];
|
||||
let combinedStream;
|
||||
|
||||
const combinedItags = YTItags.getCombinedItags(itagOpts);
|
||||
let index = combinedItags.length;
|
||||
|
||||
while(index--) {
|
||||
const itag = combinedItags[index];
|
||||
combinedStream = info.streamingData.formats.find(stream => stream.itag == itag);
|
||||
if(combinedStream) {
|
||||
debug(`found best combined itag: ${combinedStream.itag}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!combinedStream) {
|
||||
debug('trying any combined stream as last resort');
|
||||
combinedStream = info.streamingData.formats[
|
||||
info.streamingData.formats.length - 1
|
||||
];
|
||||
}
|
||||
|
||||
if(!combinedStream || !combinedStream.url)
|
||||
return null;
|
||||
|
67
src/youtubeItags.js
Normal file
67
src/youtubeItags.js
Normal file
@@ -0,0 +1,67 @@
|
||||
const Itags = {
|
||||
video: {
|
||||
h264: {
|
||||
standard: {
|
||||
240: 133,
|
||||
360: 134,
|
||||
480: 135,
|
||||
720: 136,
|
||||
1080: 137,
|
||||
},
|
||||
hfr: {
|
||||
720: 298,
|
||||
1080: 299,
|
||||
},
|
||||
},
|
||||
},
|
||||
audio: {
|
||||
aac: [140],
|
||||
opus: [249, 250, 251],
|
||||
},
|
||||
combined: {
|
||||
360: 18,
|
||||
720: 22,
|
||||
}
|
||||
};
|
||||
|
||||
function _appendItagArray(arr, opts, formats)
|
||||
{
|
||||
const keys = Object.keys(formats);
|
||||
|
||||
for(let fmt of keys) {
|
||||
arr.push(formats[fmt]);
|
||||
|
||||
if(
|
||||
fmt >= opts.height
|
||||
|| Math.floor(fmt * 16 / 9) >= opts.width
|
||||
)
|
||||
break;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
function getDashItags(opts)
|
||||
{
|
||||
const allowed = {
|
||||
video: [],
|
||||
audio: (opts.codec === 'h264')
|
||||
? Itags.audio.aac
|
||||
: Itags.audio.opus
|
||||
};
|
||||
|
||||
for(let type of opts.types) {
|
||||
const formats = Itags.video[opts.codec][type];
|
||||
_appendItagArray(allowed.video, opts, formats);
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
function getCombinedItags(opts)
|
||||
{
|
||||
const arr = [];
|
||||
_appendItagArray(arr, opts, Itags.combined);
|
||||
|
||||
return arr;
|
||||
}
|
Reference in New Issue
Block a user