mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 07:42:23 +02:00
@@ -32,6 +32,14 @@
|
|||||||
<default>"second"</default>
|
<default>"second"</default>
|
||||||
<summary>Unit to use with seeking value</summary>
|
<summary>Unit to use with seeking value</summary>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="resume-enabled" type="b">
|
||||||
|
<default>true</default>
|
||||||
|
<summary>Ask to resume unfinished video</summary>
|
||||||
|
</key>
|
||||||
|
<key name="resume-database" type="s">
|
||||||
|
<default>'[]'</default>
|
||||||
|
<summary>Data storing unfinished videos resume info</summary>
|
||||||
|
</key>
|
||||||
|
|
||||||
<!-- Audio -->
|
<!-- Audio -->
|
||||||
<key name="audio-offset" type="d">
|
<key name="audio-offset" type="d">
|
||||||
|
@@ -162,6 +162,45 @@ class ClapperUriDialog extends Gtk.Dialog
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var ResumeDialog = GObject.registerClass(
|
||||||
|
class ClapperResumeDialog extends Gtk.MessageDialog
|
||||||
|
{
|
||||||
|
_init(window, resumeInfo)
|
||||||
|
{
|
||||||
|
const percentage = Math.round((resumeInfo.time / resumeInfo.duration) * 100);
|
||||||
|
|
||||||
|
const msg = [
|
||||||
|
`<b>Title:</b> ${resumeInfo.title}`,
|
||||||
|
`<b>Completed:</b> ${percentage}%`
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
super._init({
|
||||||
|
transient_for: window,
|
||||||
|
modal: true,
|
||||||
|
message_type: Gtk.MessageType.QUESTION,
|
||||||
|
buttons: Gtk.ButtonsType.YES_NO,
|
||||||
|
text: 'Resume playback?',
|
||||||
|
secondary_use_markup: true,
|
||||||
|
secondary_text: msg,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resumeInfo = resumeInfo;
|
||||||
|
this.connect('response', this._onResponse.bind(this));
|
||||||
|
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onResponse(dialog, respId)
|
||||||
|
{
|
||||||
|
const { player } = this.transient_for.child;
|
||||||
|
|
||||||
|
if(respId === Gtk.ResponseType.YES)
|
||||||
|
player.seek_seconds(this.resumeInfo.time);
|
||||||
|
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var PrefsDialog = GObject.registerClass(
|
var PrefsDialog = GObject.registerClass(
|
||||||
class ClapperPrefsDialog extends Gtk.Dialog
|
class ClapperPrefsDialog extends Gtk.Dialog
|
||||||
{
|
{
|
||||||
|
@@ -372,6 +372,27 @@ class ClapperPlayer extends PlayerBase
|
|||||||
if(size[0] > 0 && size[1] > 0)
|
if(size[0] > 0 && size[1] > 0)
|
||||||
clapperWidget._saveWindowSize(size);
|
clapperWidget._saveWindowSize(size);
|
||||||
}
|
}
|
||||||
|
/* If "quitOnStop" is set here it means that we are in middle of autoclosing */
|
||||||
|
if(this.state !== GstClapper.ClapperState.STOPPED && !this.quitOnStop) {
|
||||||
|
let resumeInfo = {};
|
||||||
|
if(settings.get_boolean('resume-enabled')) {
|
||||||
|
const resumeTime = Math.floor(this.position / 1000000000);
|
||||||
|
const resumeDuration = this.duration / 1000000000;
|
||||||
|
|
||||||
|
/* Do not save resume info when video is short, just started or almost finished */
|
||||||
|
if(resumeDuration > 60 && resumeTime > 15 && resumeDuration - resumeTime > 20) {
|
||||||
|
resumeInfo.title = this.playlistWidget.getActiveFilename();
|
||||||
|
resumeInfo.time = resumeTime;
|
||||||
|
resumeInfo.duration = resumeDuration;
|
||||||
|
|
||||||
|
debug(`saving resume info for: ${resumeInfo.title}`);
|
||||||
|
debug(`resume time: ${resumeInfo.time}, duration: ${resumeInfo.duration}`);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug('resume info is not worth saving');
|
||||||
|
}
|
||||||
|
settings.set_string('resume-database', JSON.stringify([resumeInfo]));
|
||||||
|
}
|
||||||
settings.set_double('volume-last', this.volume);
|
settings.set_double('volume-last', this.volume);
|
||||||
|
|
||||||
clapperWidget.controls._onCloseRequest();
|
clapperWidget.controls._onCloseRequest();
|
||||||
@@ -427,8 +448,8 @@ class ClapperPlayer extends PlayerBase
|
|||||||
|
|
||||||
if(settings.get_boolean('close-auto')) {
|
if(settings.get_boolean('close-auto')) {
|
||||||
/* Stop will be automatically called soon afterwards */
|
/* Stop will be automatically called soon afterwards */
|
||||||
this._performCloseCleanup(this.widget.get_root());
|
|
||||||
this.quitOnStop = true;
|
this.quitOnStop = true;
|
||||||
|
this._performCloseCleanup(this.widget.get_root());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -70,6 +70,9 @@ class ClapperBehaviourPage extends PrefsBase.Grid
|
|||||||
['percentage', "Percentage"],
|
['percentage', "Percentage"],
|
||||||
], 'seeking-unit');
|
], 'seeking-unit');
|
||||||
this.addSpinButton('Value', 1, 99, 'seeking-value');
|
this.addSpinButton('Value', 1, 99, 'seeking-value');
|
||||||
|
|
||||||
|
this.addTitle('Resume');
|
||||||
|
this.addCheckButton('Ask to resume last unfinished video', 'resume-enabled');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
const { Gdk, GLib, GObject, GstClapper, Gtk } = imports.gi;
|
const { Gdk, GLib, GObject, 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 Misc = imports.src.misc;
|
const Misc = imports.src.misc;
|
||||||
const { Player } = imports.src.player;
|
const { Player } = imports.src.player;
|
||||||
const Revealers = imports.src.revealers;
|
const Revealers = imports.src.revealers;
|
||||||
@@ -487,21 +488,45 @@ class ClapperWidget extends Gtk.Grid
|
|||||||
this.revealerTop.endTime.set_visible(isNotStopped);
|
this.revealerTop.endTime.set_visible(isNotStopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPlayerDurationChanged(player)
|
_onPlayerDurationChanged(player, duration)
|
||||||
{
|
{
|
||||||
const duration = Math.floor(player.get_duration() / 1000000000);
|
const durationSeconds = duration / 1000000000;
|
||||||
|
const durationFloor = Math.floor(durationSeconds);
|
||||||
|
|
||||||
/* Sometimes GstPlayer might re-emit
|
/* Sometimes GstPlayer might re-emit
|
||||||
* duration changed during playback */
|
* duration changed during playback */
|
||||||
if(this.controls.currentDuration === duration)
|
if(this.controls.currentDuration === durationFloor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.controls.currentDuration = duration;
|
this.controls.currentDuration = durationFloor;
|
||||||
this.controls.showHours = (duration >= 3600);
|
this.controls.showHours = (durationFloor >= 3600);
|
||||||
|
|
||||||
this.controls.positionAdjustment.set_upper(duration);
|
this.controls.positionAdjustment.set_upper(durationFloor);
|
||||||
this.controls.durationFormatted = Misc.getFormattedTime(duration);
|
this.controls.durationFormatted = Misc.getFormattedTime(durationFloor);
|
||||||
this.controls.updateElapsedLabel();
|
this.controls.updateElapsedLabel();
|
||||||
|
|
||||||
|
if(settings.get_boolean('resume-enabled')) {
|
||||||
|
const resumeDatabase = JSON.parse(settings.get_string('resume-database'));
|
||||||
|
const title = player.playlistWidget.getActiveFilename();
|
||||||
|
|
||||||
|
debug(`searching database for resume info: ${title}`);
|
||||||
|
|
||||||
|
const resumeInfo = resumeDatabase.find(info => {
|
||||||
|
return (info.title === title && info.duration === durationSeconds);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(resumeInfo) {
|
||||||
|
debug('found resume info: ' + JSON.stringify(resumeInfo));
|
||||||
|
new Dialogs.ResumeDialog(this.root, resumeInfo);
|
||||||
|
|
||||||
|
const shrunkDatabase = resumeDatabase.filter(info => {
|
||||||
|
return !(info.title === title && info.duration === durationSeconds);
|
||||||
|
});
|
||||||
|
settings.set_string('resume-database', JSON.stringify(shrunkDatabase));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug('resume info not found');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPlayerPositionUpdated(player, position)
|
_onPlayerPositionUpdated(player, position)
|
||||||
|
Reference in New Issue
Block a user