mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
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:
26
src/app.js
26
src/app.js
@@ -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();
|
||||
}
|
||||
});
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
30
src/misc.js
30
src/misc.js
@@ -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, '&')
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
});
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user