mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 07:42:23 +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();
|
super._init();
|
||||||
|
|
||||||
this.set_flags(
|
this.flags |= Gio.ApplicationFlags.HANDLES_OPEN;
|
||||||
this.get_flags()
|
|
||||||
| Gio.ApplicationFlags.HANDLES_OPEN
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_startup()
|
vfunc_startup()
|
||||||
@@ -39,26 +36,7 @@ class ClapperApp extends AppBase
|
|||||||
{
|
{
|
||||||
super.vfunc_open(files, hint);
|
super.vfunc_open(files, hint);
|
||||||
|
|
||||||
const { player } = this.active_window.get_child();
|
this._openFiles(files);
|
||||||
|
|
||||||
if(!this.doneFirstActivate)
|
|
||||||
player._preparePlaylist(files);
|
|
||||||
else
|
|
||||||
player.set_playlist(files);
|
|
||||||
|
|
||||||
this.activate();
|
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()
|
_onFirstActivate()
|
||||||
{
|
{
|
||||||
const gtkSettings = Gtk.Settings.get_default();
|
const gtkSettings = Gtk.Settings.get_default();
|
||||||
@@ -71,19 +82,9 @@ class ClapperAppBase extends Gtk.Application
|
|||||||
this._onIconThemeChanged(gtkSettings);
|
this._onIconThemeChanged(gtkSettings);
|
||||||
gtkSettings.connect('notify::gtk-theme-name', this._onThemeChanged.bind(this));
|
gtkSettings.connect('notify::gtk-theme-name', this._onThemeChanged.bind(this));
|
||||||
gtkSettings.connect('notify::gtk-icon-theme-name', this._onIconThemeChanged.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;
|
this.doneFirstActivate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onWindowShow(window)
|
|
||||||
{
|
|
||||||
window.disconnect(this.windowShowSignal);
|
|
||||||
this.windowShowSignal = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_onThemeChanged(gtkSettings)
|
_onThemeChanged(gtkSettings)
|
||||||
{
|
{
|
||||||
const theme = gtkSettings.gtk_theme_name;
|
const theme = gtkSettings.gtk_theme_name;
|
||||||
|
@@ -24,10 +24,7 @@ class ClapperFileChooser extends Gtk.FileChooserNative
|
|||||||
filter.add_mime_type('video/*');
|
filter.add_mime_type('video/*');
|
||||||
filter.add_mime_type('audio/*');
|
filter.add_mime_type('audio/*');
|
||||||
filter.add_mime_type('application/claps');
|
filter.add_mime_type('application/claps');
|
||||||
this.subsMimes = [
|
Misc.subsMimes.forEach(mime => filter.add_mime_type(mime));
|
||||||
'application/x-subrip',
|
|
||||||
];
|
|
||||||
this.subsMimes.forEach(mime => filter.add_mime_type(mime));
|
|
||||||
this.add_filter(filter);
|
this.add_filter(filter);
|
||||||
|
|
||||||
this.responseSignal = this.connect('response', this._onResponse.bind(this));
|
this.responseSignal = this.connect('response', this._onResponse.bind(this));
|
||||||
@@ -46,36 +43,26 @@ class ClapperFileChooser extends Gtk.FileChooserNative
|
|||||||
|
|
||||||
if(response === Gtk.ResponseType.ACCEPT) {
|
if(response === Gtk.ResponseType.ACCEPT) {
|
||||||
const files = this.get_files();
|
const files = this.get_files();
|
||||||
const playlist = [];
|
const filesArray = [];
|
||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
let file;
|
let file;
|
||||||
let subs;
|
|
||||||
|
|
||||||
while((file = files.get_item(index))) {
|
while((file = files.get_item(index))) {
|
||||||
const filename = file.get_basename();
|
filesArray.push(file);
|
||||||
const [type, isUncertain] = Gio.content_type_guess(filename, null);
|
|
||||||
|
|
||||||
if(this.subsMimes.includes(type)) {
|
|
||||||
subs = file;
|
|
||||||
files.remove(index);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
playlist.push(file);
|
|
||||||
index++;
|
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)
|
/* Remote app does not handle open */
|
||||||
player.set_playlist(playlist);
|
if(isHandlesOpen)
|
||||||
|
application.open(filesArray, "");
|
||||||
/* add subs to single selected video
|
else
|
||||||
or to already playing file */
|
application._openFiles(filesArray);
|
||||||
if(subs && !files.get_item(1))
|
|
||||||
player.set_subtitles(subs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.unref();
|
this.unref();
|
||||||
|
30
src/misc.js
30
src/misc.js
@@ -5,6 +5,9 @@ const { debug } = Debug;
|
|||||||
|
|
||||||
var appName = 'Clapper';
|
var appName = 'Clapper';
|
||||||
var appId = 'com.github.rafostar.Clapper';
|
var appId = 'com.github.rafostar.Clapper';
|
||||||
|
var subsMimes = [
|
||||||
|
'application/x-subrip',
|
||||||
|
];
|
||||||
|
|
||||||
var clapperPath = null;
|
var clapperPath = null;
|
||||||
var clapperVersion = null;
|
var clapperVersion = null;
|
||||||
@@ -96,6 +99,33 @@ function getFormattedTime(time, showHours)
|
|||||||
return parsed + `${minutes}:${seconds}`;
|
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)
|
function encodeHTML(text)
|
||||||
{
|
{
|
||||||
return text.replace(/&/g, '&')
|
return text.replace(/&/g, '&')
|
||||||
|
@@ -141,24 +141,14 @@ class ClapperPlayer extends PlayerBase
|
|||||||
this.set_playlist(playlist);
|
this.set_playlist(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
_preparePlaylist(playlist)
|
set_playlist(playlist)
|
||||||
{
|
{
|
||||||
this.playlistWidget.removeAll();
|
this.playlistWidget.removeAll();
|
||||||
|
|
||||||
for(let source of playlist) {
|
for(let source of playlist) {
|
||||||
const uri = (source.get_uri != null)
|
const uri = this._getSourceUri(source);
|
||||||
? source.get_uri()
|
|
||||||
: Gst.uri_is_valid(source)
|
|
||||||
? source
|
|
||||||
: Gst.filename_to_uri(source);
|
|
||||||
|
|
||||||
this.playlistWidget.addItem(uri);
|
this.playlistWidget.addItem(uri);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
set_playlist(playlist)
|
|
||||||
{
|
|
||||||
this._preparePlaylist(playlist);
|
|
||||||
|
|
||||||
const firstTrack = this.playlistWidget.get_row_at_index(0);
|
const firstTrack = this.playlistWidget.get_row_at_index(0);
|
||||||
if(!firstTrack) return;
|
if(!firstTrack) return;
|
||||||
@@ -168,9 +158,7 @@ class ClapperPlayer extends PlayerBase
|
|||||||
|
|
||||||
set_subtitles(source)
|
set_subtitles(source)
|
||||||
{
|
{
|
||||||
const uri = (source.get_uri)
|
const uri = this._getSourceUri(source);
|
||||||
? source.get_uri()
|
|
||||||
: source;
|
|
||||||
|
|
||||||
this.set_subtitle_uri(uri);
|
this.set_subtitle_uri(uri);
|
||||||
this.set_subtitle_track_enabled(true);
|
this.set_subtitle_track_enabled(true);
|
||||||
@@ -292,6 +280,7 @@ class ClapperPlayer extends PlayerBase
|
|||||||
case 'play':
|
case 'play':
|
||||||
case 'pause':
|
case 'pause':
|
||||||
case 'set_playlist':
|
case 'set_playlist':
|
||||||
|
case 'set_subtitles':
|
||||||
this[action](value);
|
this[action](value);
|
||||||
break;
|
break;
|
||||||
case 'toggle_maximized':
|
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)
|
_performCloseCleanup(window)
|
||||||
{
|
{
|
||||||
window.disconnect(this.closeRequestSignal);
|
window.disconnect(this.closeRequestSignal);
|
||||||
|
@@ -23,17 +23,27 @@ class ClapperPlayerRemote extends GObject.Object
|
|||||||
const uris = [];
|
const uris = [];
|
||||||
|
|
||||||
/* We can not send GioFiles via WebSocket */
|
/* We can not send GioFiles via WebSocket */
|
||||||
for(let source of playlist) {
|
for(let source of playlist)
|
||||||
const uri = (source.get_uri != null)
|
uris.push(this._getSourceUri(source));
|
||||||
? source.get_uri()
|
|
||||||
: source;
|
|
||||||
|
|
||||||
uris.push(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.webclient.sendMessage({
|
this.webclient.sendMessage({
|
||||||
action: 'set_playlist',
|
action: 'set_playlist',
|
||||||
value: uris
|
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 { Controls } = imports.src.controls;
|
||||||
const Debug = imports.src.debug;
|
const Debug = imports.src.debug;
|
||||||
const Dialogs = imports.src.dialogs;
|
const Dialogs = imports.src.dialogs;
|
||||||
@@ -907,15 +907,17 @@ class ClapperWidget extends Gtk.Grid
|
|||||||
|
|
||||||
_onDataDrop(dropTarget, value, x, y)
|
_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);
|
return Gst.uri_is_valid(uri);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!playlist.length)
|
if(!files.length)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this.player.set_playlist(playlist);
|
for(let index in files)
|
||||||
this.root.application.activate();
|
files[index] = Gio.File.new_for_uri(files[index]);
|
||||||
|
|
||||||
|
this.root.application.open(files, "");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user