mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 16:02:00 +02:00
Cleanup: do not extend player class twice
We only use the base class once, no need to have it separately then. Merge into single file.
This commit is contained in:
226
src/player.js
226
src/player.js
@@ -1,19 +1,44 @@
|
|||||||
const { Gdk, Gio, GObject, Gst, GstClapper, Gtk } = imports.gi;
|
const { Gdk, Gio, GLib, GObject, Gst, GstClapper, Gtk } = imports.gi;
|
||||||
const ByteArray = imports.byteArray;
|
const ByteArray = imports.byteArray;
|
||||||
const Debug = imports.src.debug;
|
const Debug = imports.src.debug;
|
||||||
const Misc = imports.src.misc;
|
const Misc = imports.src.misc;
|
||||||
const YouTube = imports.src.youtube;
|
const YouTube = imports.src.youtube;
|
||||||
const { PlayerBase } = imports.src.playerBase;
|
const { PlaylistWidget } = imports.src.playlist;
|
||||||
|
const { WebApp } = imports.src.webApp;
|
||||||
|
|
||||||
const { debug } = Debug;
|
const { debug } = Debug;
|
||||||
const { settings } = Misc;
|
const { settings } = Misc;
|
||||||
|
|
||||||
|
let WebServer;
|
||||||
|
|
||||||
var Player = GObject.registerClass(
|
var Player = GObject.registerClass(
|
||||||
class ClapperPlayer extends PlayerBase
|
class ClapperPlayer extends GstClapper.Clapper
|
||||||
{
|
{
|
||||||
_init()
|
_init()
|
||||||
{
|
{
|
||||||
super._init();
|
const gtk4plugin = new GstClapper.ClapperGtk4Plugin();
|
||||||
|
const glsinkbin = Gst.ElementFactory.make('glsinkbin', null);
|
||||||
|
glsinkbin.sink = gtk4plugin.video_sink;
|
||||||
|
|
||||||
|
const dispatcher = new GstClapper.ClapperGMainContextSignalDispatcher();
|
||||||
|
const renderer = new GstClapper.ClapperVideoOverlayVideoRenderer({
|
||||||
|
video_sink: glsinkbin
|
||||||
|
});
|
||||||
|
|
||||||
|
super._init({
|
||||||
|
signal_dispatcher: dispatcher,
|
||||||
|
video_renderer: renderer
|
||||||
|
});
|
||||||
|
|
||||||
|
this.widget = gtk4plugin.video_sink.widget;
|
||||||
|
this.widget.add_css_class('videowidget');
|
||||||
|
|
||||||
|
this.state = GstClapper.ClapperState.STOPPED;
|
||||||
|
this.visualization_enabled = false;
|
||||||
|
|
||||||
|
this.webserver = null;
|
||||||
|
this.webapp = null;
|
||||||
|
this.playlistWidget = new PlaylistWidget();
|
||||||
|
|
||||||
this.seek_done = true;
|
this.seek_done = true;
|
||||||
this.needsFastSeekRestore = false;
|
this.needsFastSeekRestore = false;
|
||||||
@@ -33,15 +58,93 @@ class ClapperPlayer extends PlayerBase
|
|||||||
keyController.connect('key-released', this._onWidgetKeyReleased.bind(this));
|
keyController.connect('key-released', this._onWidgetKeyReleased.bind(this));
|
||||||
this.widget.add_controller(keyController);
|
this.widget.add_controller(keyController);
|
||||||
|
|
||||||
|
this.set_all_plugins_ranks();
|
||||||
|
this.set_initial_config();
|
||||||
|
this.set_and_bind_settings();
|
||||||
|
|
||||||
this.connect('state-changed', this._onStateChanged.bind(this));
|
this.connect('state-changed', this._onStateChanged.bind(this));
|
||||||
this.connect('uri-loaded', this._onUriLoaded.bind(this));
|
this.connect('uri-loaded', this._onUriLoaded.bind(this));
|
||||||
this.connect('end-of-stream', this._onStreamEnded.bind(this));
|
this.connect('end-of-stream', this._onStreamEnded.bind(this));
|
||||||
this.connect('warning', this._onPlayerWarning.bind(this));
|
this.connect('warning', this._onPlayerWarning.bind(this));
|
||||||
this.connect('error', this._onPlayerError.bind(this));
|
this.connect('error', this._onPlayerError.bind(this));
|
||||||
|
|
||||||
|
settings.connect('changed', this._onSettingsKeyChanged.bind(this));
|
||||||
|
|
||||||
this._realizeSignal = this.widget.connect('realize', this._onWidgetRealize.bind(this));
|
this._realizeSignal = this.widget.connect('realize', this._onWidgetRealize.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_and_bind_settings()
|
||||||
|
{
|
||||||
|
const settingsToSet = [
|
||||||
|
'seeking-mode',
|
||||||
|
'audio-offset',
|
||||||
|
'subtitle-offset',
|
||||||
|
'play-flags',
|
||||||
|
'webserver-enabled'
|
||||||
|
];
|
||||||
|
|
||||||
|
for(let key of settingsToSet)
|
||||||
|
this._onSettingsKeyChanged(settings, key);
|
||||||
|
|
||||||
|
const flag = Gio.SettingsBindFlags.GET;
|
||||||
|
settings.bind('subtitle-font', this.pipeline, 'subtitle_font_desc', flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_initial_config()
|
||||||
|
{
|
||||||
|
this.set_mute(false);
|
||||||
|
|
||||||
|
/* FIXME: change into option in preferences */
|
||||||
|
const pipeline = this.get_pipeline();
|
||||||
|
pipeline.ring_buffer_max_size = 8 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_all_plugins_ranks()
|
||||||
|
{
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
/* Set empty plugin list if someone messed it externally */
|
||||||
|
try {
|
||||||
|
data = JSON.parse(settings.get_string('plugin-ranking'));
|
||||||
|
if(!Array.isArray(data))
|
||||||
|
throw new Error('plugin ranking data is not an array!');
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
debug(err);
|
||||||
|
settings.set_string('plugin-ranking', "[]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let plugin of data) {
|
||||||
|
if(!plugin.apply || !plugin.name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this.set_plugin_rank(plugin.name, plugin.rank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_plugin_rank(name, rank)
|
||||||
|
{
|
||||||
|
const gstRegistry = Gst.Registry.get();
|
||||||
|
const feature = gstRegistry.lookup_feature(name);
|
||||||
|
if(!feature)
|
||||||
|
return debug(`plugin unavailable: ${name}`);
|
||||||
|
|
||||||
|
const oldRank = feature.get_rank();
|
||||||
|
if(rank === oldRank)
|
||||||
|
return;
|
||||||
|
|
||||||
|
feature.set_rank(rank);
|
||||||
|
debug(`changed rank: ${oldRank} -> ${rank} for ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_black(isEnabled)
|
||||||
|
{
|
||||||
|
this.widget.ignore_textures = isEnabled;
|
||||||
|
|
||||||
|
if(this.state !== GstClapper.ClapperState.PLAYING)
|
||||||
|
this.widget.queue_render();
|
||||||
|
}
|
||||||
|
|
||||||
set_uri(uri)
|
set_uri(uri)
|
||||||
{
|
{
|
||||||
this.customVideoTitle = null;
|
this.customVideoTitle = null;
|
||||||
@@ -255,6 +358,14 @@ class ClapperPlayer extends PlayerBase
|
|||||||
this[action]();
|
this[action]();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitWs(action, value)
|
||||||
|
{
|
||||||
|
if(!this.webserver)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.webserver.sendMessage({ action, value });
|
||||||
|
}
|
||||||
|
|
||||||
receiveWs(action, value)
|
receiveWs(action, value)
|
||||||
{
|
{
|
||||||
switch(action) {
|
switch(action) {
|
||||||
@@ -279,7 +390,7 @@ class ClapperPlayer extends PlayerBase
|
|||||||
clapperWidget.toggleFullscreen();
|
clapperWidget.toggleFullscreen();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
super.receiveWs(action, value);
|
debug(`unhandled WebSocket action: ${action}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -550,4 +661,109 @@ class ClapperPlayer extends PlayerBase
|
|||||||
this.quitOnStop = true;
|
this.quitOnStop = true;
|
||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onSettingsKeyChanged(settings, key)
|
||||||
|
{
|
||||||
|
let root, value, action;
|
||||||
|
|
||||||
|
switch(key) {
|
||||||
|
case 'seeking-mode':
|
||||||
|
this.seekingMode = settings.get_string('seeking-mode');
|
||||||
|
switch(this.seekingMode) {
|
||||||
|
case 'fast':
|
||||||
|
this.set_seek_mode(GstClapper.ClapperSeekMode.FAST);
|
||||||
|
break;
|
||||||
|
case 'accurate':
|
||||||
|
this.set_seek_mode(GstClapper.ClapperSeekMode.ACCURATE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.set_seek_mode(GstClapper.ClapperSeekMode.DEFAULT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'render-shadows':
|
||||||
|
root = this.widget.get_root();
|
||||||
|
if(!root) break;
|
||||||
|
|
||||||
|
const gpuClass = 'gpufriendly';
|
||||||
|
const renderShadows = settings.get_boolean(key);
|
||||||
|
const hasShadows = !root.has_css_class(gpuClass);
|
||||||
|
|
||||||
|
if(renderShadows === hasShadows)
|
||||||
|
break;
|
||||||
|
|
||||||
|
action = (renderShadows) ? 'remove' : 'add';
|
||||||
|
root[action + '_css_class'](gpuClass);
|
||||||
|
break;
|
||||||
|
case 'audio-offset':
|
||||||
|
value = Math.round(settings.get_double(key) * -Gst.MSECOND);
|
||||||
|
this.set_audio_video_offset(value);
|
||||||
|
debug(`set audio-video offset: ${value}`);
|
||||||
|
break;
|
||||||
|
case 'subtitle-offset':
|
||||||
|
value = Math.round(settings.get_double(key) * -Gst.MSECOND);
|
||||||
|
this.set_subtitle_video_offset(value);
|
||||||
|
debug(`set subtitle-video offset: ${value}`);
|
||||||
|
break;
|
||||||
|
case 'dark-theme':
|
||||||
|
root = this.widget.get_root();
|
||||||
|
if(!root) break;
|
||||||
|
|
||||||
|
root.application._onThemeChanged(Gtk.Settings.get_default());
|
||||||
|
break;
|
||||||
|
case 'play-flags':
|
||||||
|
const initialFlags = this.pipeline.flags;
|
||||||
|
const settingsFlags = settings.get_int(key);
|
||||||
|
|
||||||
|
if(initialFlags === settingsFlags)
|
||||||
|
break;
|
||||||
|
|
||||||
|
this.pipeline.flags = settingsFlags;
|
||||||
|
debug(`changed play flags: ${initialFlags} -> ${settingsFlags}`);
|
||||||
|
break;
|
||||||
|
case 'webserver-enabled':
|
||||||
|
case 'webapp-enabled':
|
||||||
|
const webserverEnabled = settings.get_boolean('webserver-enabled');
|
||||||
|
|
||||||
|
if(webserverEnabled) {
|
||||||
|
if(!WebServer) {
|
||||||
|
/* Probably most users will not use this,
|
||||||
|
* so conditional import for faster startup */
|
||||||
|
WebServer = imports.src.webServer.WebServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this.webserver) {
|
||||||
|
this.webserver = new WebServer(settings.get_int('webserver-port'));
|
||||||
|
this.webserver.passMsgData = this.receiveWs.bind(this);
|
||||||
|
}
|
||||||
|
this.webserver.startListening();
|
||||||
|
|
||||||
|
const webappEnabled = settings.get_boolean('webapp-enabled');
|
||||||
|
|
||||||
|
if(!this.webapp && !webappEnabled)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(webappEnabled) {
|
||||||
|
if(!this.webapp)
|
||||||
|
this.webapp = new WebApp();
|
||||||
|
|
||||||
|
this.webapp.startDaemonApp(settings.get_int('webapp-port'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(this.webserver) {
|
||||||
|
/* remote app will close when connection is lost
|
||||||
|
* which will cause the daemon to close too */
|
||||||
|
this.webserver.stopListening();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'webserver-port':
|
||||||
|
if(!this.webserver)
|
||||||
|
break;
|
||||||
|
|
||||||
|
this.webserver.setListeningPort(settings.get_int(key));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@@ -1,237 +0,0 @@
|
|||||||
const { Gio, GLib, GObject, Gst, GstClapper, Gtk } = imports.gi;
|
|
||||||
const Debug = imports.src.debug;
|
|
||||||
const Misc = imports.src.misc;
|
|
||||||
const { PlaylistWidget } = imports.src.playlist;
|
|
||||||
const { WebApp } = imports.src.webApp;
|
|
||||||
|
|
||||||
const { debug } = Debug;
|
|
||||||
const { settings } = Misc;
|
|
||||||
|
|
||||||
let WebServer;
|
|
||||||
|
|
||||||
var PlayerBase = GObject.registerClass(
|
|
||||||
class ClapperPlayerBase extends GstClapper.Clapper
|
|
||||||
{
|
|
||||||
_init()
|
|
||||||
{
|
|
||||||
const gtk4plugin = new GstClapper.ClapperGtk4Plugin();
|
|
||||||
const glsinkbin = Gst.ElementFactory.make('glsinkbin', null);
|
|
||||||
glsinkbin.sink = gtk4plugin.video_sink;
|
|
||||||
|
|
||||||
const dispatcher = new GstClapper.ClapperGMainContextSignalDispatcher();
|
|
||||||
const renderer = new GstClapper.ClapperVideoOverlayVideoRenderer({
|
|
||||||
video_sink: glsinkbin
|
|
||||||
});
|
|
||||||
|
|
||||||
super._init({
|
|
||||||
signal_dispatcher: dispatcher,
|
|
||||||
video_renderer: renderer
|
|
||||||
});
|
|
||||||
|
|
||||||
this.widget = gtk4plugin.video_sink.widget;
|
|
||||||
this.widget.add_css_class('videowidget');
|
|
||||||
|
|
||||||
this.state = GstClapper.ClapperState.STOPPED;
|
|
||||||
this.visualization_enabled = false;
|
|
||||||
|
|
||||||
this.webserver = null;
|
|
||||||
this.webapp = null;
|
|
||||||
this.playlistWidget = new PlaylistWidget();
|
|
||||||
|
|
||||||
this.set_all_plugins_ranks();
|
|
||||||
this.set_initial_config();
|
|
||||||
this.set_and_bind_settings();
|
|
||||||
|
|
||||||
settings.connect('changed', this._onSettingsKeyChanged.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
set_and_bind_settings()
|
|
||||||
{
|
|
||||||
const settingsToSet = [
|
|
||||||
'seeking-mode',
|
|
||||||
'audio-offset',
|
|
||||||
'subtitle-offset',
|
|
||||||
'play-flags',
|
|
||||||
'webserver-enabled'
|
|
||||||
];
|
|
||||||
|
|
||||||
for(let key of settingsToSet)
|
|
||||||
this._onSettingsKeyChanged(settings, key);
|
|
||||||
|
|
||||||
const flag = Gio.SettingsBindFlags.GET;
|
|
||||||
settings.bind('subtitle-font', this.pipeline, 'subtitle_font_desc', flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_initial_config()
|
|
||||||
{
|
|
||||||
this.set_mute(false);
|
|
||||||
|
|
||||||
/* FIXME: change into option in preferences */
|
|
||||||
const pipeline = this.get_pipeline();
|
|
||||||
pipeline.ring_buffer_max_size = 8 * 1024 * 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_all_plugins_ranks()
|
|
||||||
{
|
|
||||||
let data = [];
|
|
||||||
|
|
||||||
/* Set empty plugin list if someone messed it externally */
|
|
||||||
try {
|
|
||||||
data = JSON.parse(settings.get_string('plugin-ranking'));
|
|
||||||
if(!Array.isArray(data))
|
|
||||||
throw new Error('plugin ranking data is not an array!');
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
debug(err);
|
|
||||||
settings.set_string('plugin-ranking', "[]");
|
|
||||||
}
|
|
||||||
|
|
||||||
for(let plugin of data) {
|
|
||||||
if(!plugin.apply || !plugin.name)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this.set_plugin_rank(plugin.name, plugin.rank);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_plugin_rank(name, rank)
|
|
||||||
{
|
|
||||||
const gstRegistry = Gst.Registry.get();
|
|
||||||
const feature = gstRegistry.lookup_feature(name);
|
|
||||||
if(!feature)
|
|
||||||
return debug(`plugin unavailable: ${name}`);
|
|
||||||
|
|
||||||
const oldRank = feature.get_rank();
|
|
||||||
if(rank === oldRank)
|
|
||||||
return;
|
|
||||||
|
|
||||||
feature.set_rank(rank);
|
|
||||||
debug(`changed rank: ${oldRank} -> ${rank} for ${name}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_black(isEnabled)
|
|
||||||
{
|
|
||||||
this.widget.ignore_textures = isEnabled;
|
|
||||||
|
|
||||||
if(this.state !== GstClapper.ClapperState.PLAYING)
|
|
||||||
this.widget.queue_render();
|
|
||||||
}
|
|
||||||
|
|
||||||
emitWs(action, value)
|
|
||||||
{
|
|
||||||
if(!this.webserver)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.webserver.sendMessage({ action, value });
|
|
||||||
}
|
|
||||||
|
|
||||||
receiveWs(action, value)
|
|
||||||
{
|
|
||||||
debug(`unhandled WebSocket action: ${action}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onSettingsKeyChanged(settings, key)
|
|
||||||
{
|
|
||||||
let root, value, action;
|
|
||||||
|
|
||||||
switch(key) {
|
|
||||||
case 'seeking-mode':
|
|
||||||
this.seekingMode = settings.get_string('seeking-mode');
|
|
||||||
switch(this.seekingMode) {
|
|
||||||
case 'fast':
|
|
||||||
this.set_seek_mode(GstClapper.ClapperSeekMode.FAST);
|
|
||||||
break;
|
|
||||||
case 'accurate':
|
|
||||||
this.set_seek_mode(GstClapper.ClapperSeekMode.ACCURATE);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.set_seek_mode(GstClapper.ClapperSeekMode.DEFAULT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'render-shadows':
|
|
||||||
root = this.widget.get_root();
|
|
||||||
if(!root) break;
|
|
||||||
|
|
||||||
const gpuClass = 'gpufriendly';
|
|
||||||
const renderShadows = settings.get_boolean(key);
|
|
||||||
const hasShadows = !root.has_css_class(gpuClass);
|
|
||||||
|
|
||||||
if(renderShadows === hasShadows)
|
|
||||||
break;
|
|
||||||
|
|
||||||
action = (renderShadows) ? 'remove' : 'add';
|
|
||||||
root[action + '_css_class'](gpuClass);
|
|
||||||
break;
|
|
||||||
case 'audio-offset':
|
|
||||||
value = Math.round(settings.get_double(key) * -Gst.MSECOND);
|
|
||||||
this.set_audio_video_offset(value);
|
|
||||||
debug(`set audio-video offset: ${value}`);
|
|
||||||
break;
|
|
||||||
case 'subtitle-offset':
|
|
||||||
value = Math.round(settings.get_double(key) * -Gst.MSECOND);
|
|
||||||
this.set_subtitle_video_offset(value);
|
|
||||||
debug(`set subtitle-video offset: ${value}`);
|
|
||||||
break;
|
|
||||||
case 'dark-theme':
|
|
||||||
root = this.widget.get_root();
|
|
||||||
if(!root) break;
|
|
||||||
|
|
||||||
root.application._onThemeChanged(Gtk.Settings.get_default());
|
|
||||||
break;
|
|
||||||
case 'play-flags':
|
|
||||||
const initialFlags = this.pipeline.flags;
|
|
||||||
const settingsFlags = settings.get_int(key);
|
|
||||||
|
|
||||||
if(initialFlags === settingsFlags)
|
|
||||||
break;
|
|
||||||
|
|
||||||
this.pipeline.flags = settingsFlags;
|
|
||||||
debug(`changed play flags: ${initialFlags} -> ${settingsFlags}`);
|
|
||||||
break;
|
|
||||||
case 'webserver-enabled':
|
|
||||||
case 'webapp-enabled':
|
|
||||||
const webserverEnabled = settings.get_boolean('webserver-enabled');
|
|
||||||
|
|
||||||
if(webserverEnabled) {
|
|
||||||
if(!WebServer) {
|
|
||||||
/* Probably most users will not use this,
|
|
||||||
* so conditional import for faster startup */
|
|
||||||
WebServer = imports.src.webServer.WebServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this.webserver) {
|
|
||||||
this.webserver = new WebServer(settings.get_int('webserver-port'));
|
|
||||||
this.webserver.passMsgData = this.receiveWs.bind(this);
|
|
||||||
}
|
|
||||||
this.webserver.startListening();
|
|
||||||
|
|
||||||
const webappEnabled = settings.get_boolean('webapp-enabled');
|
|
||||||
|
|
||||||
if(!this.webapp && !webappEnabled)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(webappEnabled) {
|
|
||||||
if(!this.webapp)
|
|
||||||
this.webapp = new WebApp();
|
|
||||||
|
|
||||||
this.webapp.startDaemonApp(settings.get_int('webapp-port'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(this.webserver) {
|
|
||||||
/* remote app will close when connection is lost
|
|
||||||
* which will cause the daemon to close too */
|
|
||||||
this.webserver.stopListening();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'webserver-port':
|
|
||||||
if(!this.webserver)
|
|
||||||
break;
|
|
||||||
|
|
||||||
this.webserver.setListeningPort(settings.get_int(key));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
Reference in New Issue
Block a user