Merge pull request #2538 from bbielsa/player-remember-position

Retain video time position in video player
This commit is contained in:
Samantaz Fox 2021-12-21 22:05:43 +01:00 committed by GitHub
commit 28a6589a1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 1 deletions

View file

@ -38,6 +38,8 @@ embed_url.searchParams.delete('v');
short_url = location.origin + '/' + video_data.id + embed_url.search; short_url = location.origin + '/' + video_data.id + embed_url.search;
embed_url = location.origin + '/embed/' + video_data.id + embed_url.search; embed_url = location.origin + '/embed/' + video_data.id + embed_url.search;
var save_player_pos_key = "save_player_pos";
var shareOptions = { var shareOptions = {
socials: ['fbFeed', 'tw', 'reddit', 'email'], socials: ['fbFeed', 'tw', 'reddit', 'email'],
@ -199,6 +201,32 @@ if (video_data.premiere_timestamp && Math.round(new Date() / 1000) < video_data.
player.getChild('bigPlayButton').hide(); player.getChild('bigPlayButton').hide();
} }
if (video_data.params.save_player_pos) {
const url = new URL(location);
const hasTimeParam = url.searchParams.has("t");
const remeberedTime = get_video_time();
let lastUpdated = 0;
if(!hasTimeParam) {
set_seconds_after_start(remeberedTime);
}
const updateTime = () => {
const raw = player.currentTime();
const time = Math.floor(raw);
if(lastUpdated !== time) {
save_video_time(time);
lastUpdated = time;
}
};
player.on("timeupdate", updateTime);
}
else {
remove_all_video_times();
}
if (video_data.params.autoplay) { if (video_data.params.autoplay) {
var bpb = player.getChild('bigPlayButton'); var bpb = player.getChild('bigPlayButton');
bpb.hide(); bpb.hide();
@ -330,6 +358,55 @@ function skip_seconds(delta) {
player.currentTime(newTime); player.currentTime(newTime);
} }
function set_seconds_after_start(delta) {
const start = video_data.params.video_start;
player.currentTime(start + delta);
}
function save_video_time(seconds) {
const videoId = video_data.id;
const all_video_times = get_all_video_times();
all_video_times[videoId] = seconds;
set_all_video_times(all_video_times);
}
function get_video_time() {
try {
const videoId = video_data.id;
const all_video_times = get_all_video_times();
const timestamp = all_video_times[videoId];
return timestamp || 0;
}
catch {
return 0;
}
}
function set_all_video_times(times) {
const json = JSON.stringify(times);
localStorage.setItem(save_player_pos_key, json);
}
function get_all_video_times() {
try {
const raw = localStorage.getItem(save_player_pos_key);
const times = JSON.parse(raw);
return times || {};
}
catch {
return {};
}
}
function remove_all_video_times() {
localStorage.removeItem(save_player_pos_key);
}
function set_time_percent(percent) { function set_time_percent(percent) {
const duration = player.duration(); const duration = player.duration();
const newTime = duration * (percent / 100); const newTime = duration * (percent / 100);

View file

@ -461,5 +461,6 @@
"download_subtitles": "Subtitles - `x` (.vtt)", "download_subtitles": "Subtitles - `x` (.vtt)",
"user_created_playlists": "`x` created playlists", "user_created_playlists": "`x` created playlists",
"user_saved_playlists": "`x` saved playlists", "user_saved_playlists": "`x` saved playlists",
"Video unavailable": "Video unavailable" "Video unavailable": "Video unavailable",
"preferences_save_player_pos_label": "Save the current video time: "
} }

View file

@ -42,6 +42,7 @@ struct ConfigPreferences
property volume : Int32 = 100 property volume : Int32 = 100
property vr_mode : Bool = true property vr_mode : Bool = true
property show_nick : Bool = true property show_nick : Bool = true
property save_player_pos : Bool = false
def to_tuple def to_tuple
{% begin %} {% begin %}

View file

@ -70,6 +70,10 @@ module Invidious::Routes::PreferencesRoute
vr_mode ||= "off" vr_mode ||= "off"
vr_mode = vr_mode == "on" vr_mode = vr_mode == "on"
save_player_pos = env.params.body["save_player_pos"]?.try &.as(String)
save_player_pos ||= "off"
save_player_pos = save_player_pos == "on"
show_nick = env.params.body["show_nick"]?.try &.as(String) show_nick = env.params.body["show_nick"]?.try &.as(String)
show_nick ||= "off" show_nick ||= "off"
show_nick = show_nick == "on" show_nick = show_nick == "on"
@ -165,6 +169,7 @@ module Invidious::Routes::PreferencesRoute
extend_desc: extend_desc, extend_desc: extend_desc,
vr_mode: vr_mode, vr_mode: vr_mode,
show_nick: show_nick, show_nick: show_nick,
save_player_pos: save_player_pos,
}.to_json).to_json }.to_json).to_json
if user = env.get? "user" if user = env.get? "user"

View file

@ -53,6 +53,7 @@ struct Preferences
property video_loop : Bool = CONFIG.default_user_preferences.video_loop property video_loop : Bool = CONFIG.default_user_preferences.video_loop
property extend_desc : Bool = CONFIG.default_user_preferences.extend_desc property extend_desc : Bool = CONFIG.default_user_preferences.extend_desc
property volume : Int32 = CONFIG.default_user_preferences.volume property volume : Int32 = CONFIG.default_user_preferences.volume
property save_player_pos : Bool = CONFIG.default_user_preferences.save_player_pos
module BoolToString module BoolToString
def self.to_json(value : String, json : JSON::Builder) def self.to_json(value : String, json : JSON::Builder)

View file

@ -246,6 +246,7 @@ struct VideoPreferences
property video_start : Float64 | Int32 property video_start : Float64 | Int32
property volume : Int32 property volume : Int32
property vr_mode : Bool property vr_mode : Bool
property save_player_pos : Bool
end end
struct Video struct Video
@ -1090,6 +1091,7 @@ def process_video_params(query, preferences)
extend_desc = query["extend_desc"]?.try { |q| (q == "true" || q == "1").to_unsafe } extend_desc = query["extend_desc"]?.try { |q| (q == "true" || q == "1").to_unsafe }
volume = query["volume"]?.try &.to_i? volume = query["volume"]?.try &.to_i?
vr_mode = query["vr_mode"]?.try { |q| (q == "true" || q == "1").to_unsafe } vr_mode = query["vr_mode"]?.try { |q| (q == "true" || q == "1").to_unsafe }
save_player_pos = query["save_player_pos"]?.try { |q| (q == "true" || q == "1").to_unsafe }
if preferences if preferences
# region ||= preferences.region # region ||= preferences.region
@ -1110,6 +1112,7 @@ def process_video_params(query, preferences)
extend_desc ||= preferences.extend_desc.to_unsafe extend_desc ||= preferences.extend_desc.to_unsafe
volume ||= preferences.volume volume ||= preferences.volume
vr_mode ||= preferences.vr_mode.to_unsafe vr_mode ||= preferences.vr_mode.to_unsafe
save_player_pos ||= preferences.save_player_pos.to_unsafe
end end
annotations ||= CONFIG.default_user_preferences.annotations.to_unsafe annotations ||= CONFIG.default_user_preferences.annotations.to_unsafe
@ -1129,6 +1132,7 @@ def process_video_params(query, preferences)
extend_desc ||= CONFIG.default_user_preferences.extend_desc.to_unsafe extend_desc ||= CONFIG.default_user_preferences.extend_desc.to_unsafe
volume ||= CONFIG.default_user_preferences.volume volume ||= CONFIG.default_user_preferences.volume
vr_mode ||= CONFIG.default_user_preferences.vr_mode.to_unsafe vr_mode ||= CONFIG.default_user_preferences.vr_mode.to_unsafe
save_player_pos ||= CONFIG.default_user_preferences.save_player_pos.to_unsafe
annotations = annotations == 1 annotations = annotations == 1
autoplay = autoplay == 1 autoplay = autoplay == 1
@ -1140,6 +1144,7 @@ def process_video_params(query, preferences)
video_loop = video_loop == 1 video_loop = video_loop == 1
extend_desc = extend_desc == 1 extend_desc = extend_desc == 1
vr_mode = vr_mode == 1 vr_mode = vr_mode == 1
save_player_pos = save_player_pos == 1
if CONFIG.disabled?("dash") && quality == "dash" if CONFIG.disabled?("dash") && quality == "dash"
quality = "high" quality = "high"
@ -1190,6 +1195,7 @@ def process_video_params(query, preferences)
video_start: video_start, video_start: video_start,
volume: volume, volume: volume,
vr_mode: vr_mode, vr_mode: vr_mode,
save_player_pos: save_player_pos,
}) })
return params return params

View file

@ -116,6 +116,11 @@
<input name="vr_mode" id="vr_mode" type="checkbox" <% if preferences.vr_mode %>checked<% end %>> <input name="vr_mode" id="vr_mode" type="checkbox" <% if preferences.vr_mode %>checked<% end %>>
</div> </div>
<div class="pure-control-group">
<label for="save_player_pos"><%= translate(locale, "preferences_save_player_pos_label") %></label>
<input name="save_player_pos" id="save_player_pos" type="checkbox" <% if preferences.save_player_pos %>checked<% end %>>
</div>
<legend><%= translate(locale, "preferences_category_visual") %></legend> <legend><%= translate(locale, "preferences_category_visual") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">