Convenient ways of opening external subtitles

Play video with external subtiles by:
* selecting and opening both video+subs from file chooser/manager
* dropping subtitles file on player window
* opening subtiles from file chooser/manager while video plays
* send their file path/uri to player via WebSocket message
This commit is contained in:
Rafał Dzięgiel
2021-04-07 13:52:51 +02:00
parent 28d8986072
commit b15b94fc90
7 changed files with 92 additions and 86 deletions

View File

@@ -12,10 +12,7 @@ class ClapperApp extends AppBase
{
super._init();
this.set_flags(
this.get_flags()
| Gio.ApplicationFlags.HANDLES_OPEN
);
this.flags |= Gio.ApplicationFlags.HANDLES_OPEN;
}
vfunc_startup()
@@ -39,26 +36,7 @@ class ClapperApp extends AppBase
{
super.vfunc_open(files, hint);
const { player } = this.active_window.get_child();
if(!this.doneFirstActivate)
player._preparePlaylist(files);
else
player.set_playlist(files);
this._openFiles(files);
this.activate();
}
_onWindowShow(window)
{
super._onWindowShow(window);
const { player } = this.active_window.get_child();
const success = player.playlistWidget.nextTrack();
if(!success)
debug('playlist is empty');
player.widget.grab_focus();
}
});

View File

@@ -59,6 +59,17 @@ class ClapperAppBase extends Gtk.Application
);
}
_openFiles(files)
{
const [playlist, subs] = Misc.parsePlaylistFiles(files);
const { player } = this.active_window.get_child();
if(playlist && playlist.length)
player.set_playlist(playlist);
if(subs)
player.set_subtitles(subs);
}
_onFirstActivate()
{
const gtkSettings = Gtk.Settings.get_default();
@@ -71,19 +82,9 @@ class ClapperAppBase extends Gtk.Application
this._onIconThemeChanged(gtkSettings);
gtkSettings.connect('notify::gtk-theme-name', this._onThemeChanged.bind(this));
gtkSettings.connect('notify::gtk-icon-theme-name', this._onIconThemeChanged.bind(this));
this.windowShowSignal = this.active_window.connect(
'show', this._onWindowShow.bind(this)
);
this.doneFirstActivate = true;
}
_onWindowShow(window)
{
window.disconnect(this.windowShowSignal);
this.windowShowSignal = null;
}
_onThemeChanged(gtkSettings)
{
const theme = gtkSettings.gtk_theme_name;

View File

@@ -24,10 +24,7 @@ class ClapperFileChooser extends Gtk.FileChooserNative
filter.add_mime_type('video/*');
filter.add_mime_type('audio/*');
filter.add_mime_type('application/claps');
this.subsMimes = [
'application/x-subrip',
];
this.subsMimes.forEach(mime => filter.add_mime_type(mime));
Misc.subsMimes.forEach(mime => filter.add_mime_type(mime));
this.add_filter(filter);
this.responseSignal = this.connect('response', this._onResponse.bind(this));
@@ -46,36 +43,26 @@ class ClapperFileChooser extends Gtk.FileChooserNative
if(response === Gtk.ResponseType.ACCEPT) {
const files = this.get_files();
const playlist = [];
const filesArray = [];
let index = 0;
let file;
let subs;
while((file = files.get_item(index))) {
const filename = file.get_basename();
const [type, isUncertain] = Gio.content_type_guess(filename, null);
if(this.subsMimes.includes(type)) {
subs = file;
files.remove(index);
continue;
}
playlist.push(file);
filesArray.push(file);
index++;
}
const { player } = this.get_transient_for().get_child();
const { application } = this.transient_for;
const isHandlesOpen = Boolean(
application.flags & Gio.ApplicationFlags.HANDLES_OPEN
);
if(playlist.length)
player.set_playlist(playlist);
/* add subs to single selected video
or to already playing file */
if(subs && !files.get_item(1))
player.set_subtitles(subs);
/* Remote app does not handle open */
if(isHandlesOpen)
application.open(filesArray, "");
else
application._openFiles(filesArray);
}
this.unref();

View File

@@ -5,6 +5,9 @@ const { debug } = Debug;
var appName = 'Clapper';
var appId = 'com.github.rafostar.Clapper';
var subsMimes = [
'application/x-subrip',
];
var clapperPath = null;
var clapperVersion = null;
@@ -96,6 +99,33 @@ function getFormattedTime(time, showHours)
return parsed + `${minutes}:${seconds}`;
}
function parsePlaylistFiles(filesArray)
{
let index = filesArray.length;
let subs = null;
while(index--) {
const file = filesArray[index];
const filename = (file.get_basename)
? file.get_basename()
: file.substring(file.lastIndexOf('/') + 1);
const [type, isUncertain] = Gio.content_type_guess(filename, null);
if(subsMimes.includes(type)) {
subs = file;
filesArray.splice(index, 1);
}
}
/* We only support single video
* with external subtitles */
if(subs && filesArray.length > 1)
subs = null;
return [filesArray, subs];
}
function encodeHTML(text)
{
return text.replace(/&/g, '&')

View File

@@ -141,24 +141,14 @@ class ClapperPlayer extends PlayerBase
this.set_playlist(playlist);
}
_preparePlaylist(playlist)
set_playlist(playlist)
{
this.playlistWidget.removeAll();
for(let source of playlist) {
const uri = (source.get_uri != null)
? source.get_uri()
: Gst.uri_is_valid(source)
? source
: Gst.filename_to_uri(source);
const uri = this._getSourceUri(source);
this.playlistWidget.addItem(uri);
}
}
set_playlist(playlist)
{
this._preparePlaylist(playlist);
const firstTrack = this.playlistWidget.get_row_at_index(0);
if(!firstTrack) return;
@@ -168,9 +158,7 @@ class ClapperPlayer extends PlayerBase
set_subtitles(source)
{
const uri = (source.get_uri)
? source.get_uri()
: source;
const uri = this._getSourceUri(source);
this.set_subtitle_uri(uri);
this.set_subtitle_track_enabled(true);
@@ -292,6 +280,7 @@ class ClapperPlayer extends PlayerBase
case 'play':
case 'pause':
case 'set_playlist':
case 'set_subtitles':
this[action](value);
break;
case 'toggle_maximized':
@@ -315,6 +304,15 @@ class ClapperPlayer extends PlayerBase
}
}
_getSourceUri(source)
{
return (source.get_uri != null)
? source.get_uri()
: Gst.uri_is_valid(source)
? source
: Gst.filename_to_uri(source);
}
_performCloseCleanup(window)
{
window.disconnect(this.closeRequestSignal);

View File

@@ -23,17 +23,27 @@ class ClapperPlayerRemote extends GObject.Object
const uris = [];
/* We can not send GioFiles via WebSocket */
for(let source of playlist) {
const uri = (source.get_uri != null)
? source.get_uri()
: source;
uris.push(uri);
}
for(let source of playlist)
uris.push(this._getSourceUri(source));
this.webclient.sendMessage({
action: 'set_playlist',
value: uris
});
}
set_subtitles(source)
{
this.webclient.sendMessage({
action: 'set_subtitles',
value: this._getSourceUri(source)
});
}
_getSourceUri(source)
{
return (source.get_uri != null)
? source.get_uri()
: source;
}
});

View File

@@ -1,4 +1,4 @@
const { Gdk, GLib, GObject, Gst, GstClapper, Gtk } = imports.gi;
const { Gdk, Gio, GLib, GObject, Gst, GstClapper, Gtk } = imports.gi;
const { Controls } = imports.src.controls;
const Debug = imports.src.debug;
const Dialogs = imports.src.dialogs;
@@ -907,15 +907,17 @@ class ClapperWidget extends Gtk.Grid
_onDataDrop(dropTarget, value, x, y)
{
const playlist = value.split(/\r?\n/).filter(uri => {
const files = value.split(/\r?\n/).filter(uri => {
return Gst.uri_is_valid(uri);
});
if(!playlist.length)
if(!files.length)
return false;
this.player.set_playlist(playlist);
this.root.application.activate();
for(let index in files)
files[index] = Gio.File.new_for_uri(files[index]);
this.root.application.open(files, "");
return true;
}