mirror of
				https://gitea.invidious.io/iv-org/invidious
				synced 2025-06-05 23:29:12 +02:00 
			
		
		
		
	Merge pull request #2538 from bbielsa/player-remember-position
Retain video time position in video player
This commit is contained in:
		| @@ -38,6 +38,8 @@ embed_url.searchParams.delete('v'); | ||||
| short_url = location.origin + '/' + 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 = { | ||||
|     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(); | ||||
| } | ||||
|  | ||||
| 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) { | ||||
|     var bpb = player.getChild('bigPlayButton'); | ||||
|     bpb.hide(); | ||||
| @@ -330,6 +358,55 @@ function skip_seconds(delta) { | ||||
|     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) { | ||||
|     const duration = player.duration(); | ||||
|     const newTime = duration * (percent / 100); | ||||
|   | ||||
| @@ -461,5 +461,6 @@ | ||||
|     "download_subtitles": "Subtitles - `x` (.vtt)", | ||||
|     "user_created_playlists": "`x` created 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: " | ||||
| } | ||||
|   | ||||
| @@ -42,6 +42,7 @@ struct ConfigPreferences | ||||
|   property volume : Int32 = 100 | ||||
|   property vr_mode : Bool = true | ||||
|   property show_nick : Bool = true | ||||
|   property save_player_pos : Bool = false | ||||
|  | ||||
|   def to_tuple | ||||
|     {% begin %} | ||||
|   | ||||
| @@ -70,6 +70,10 @@ module Invidious::Routes::PreferencesRoute | ||||
|     vr_mode ||= "off" | ||||
|     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 ||= "off" | ||||
|     show_nick = show_nick == "on" | ||||
| @@ -165,6 +169,7 @@ module Invidious::Routes::PreferencesRoute | ||||
|       extend_desc:                 extend_desc, | ||||
|       vr_mode:                     vr_mode, | ||||
|       show_nick:                   show_nick, | ||||
|       save_player_pos:             save_player_pos, | ||||
|     }.to_json).to_json | ||||
|  | ||||
|     if user = env.get? "user" | ||||
|   | ||||
| @@ -53,6 +53,7 @@ struct Preferences | ||||
|   property video_loop : Bool = CONFIG.default_user_preferences.video_loop | ||||
|   property extend_desc : Bool = CONFIG.default_user_preferences.extend_desc | ||||
|   property volume : Int32 = CONFIG.default_user_preferences.volume | ||||
|   property save_player_pos : Bool = CONFIG.default_user_preferences.save_player_pos | ||||
|  | ||||
|   module BoolToString | ||||
|     def self.to_json(value : String, json : JSON::Builder) | ||||
|   | ||||
| @@ -246,6 +246,7 @@ struct VideoPreferences | ||||
|   property video_start : Float64 | Int32 | ||||
|   property volume : Int32 | ||||
|   property vr_mode : Bool | ||||
|   property save_player_pos : Bool | ||||
| end | ||||
|  | ||||
| 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 } | ||||
|   volume = query["volume"]?.try &.to_i? | ||||
|   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 | ||||
|     # region ||= preferences.region | ||||
| @@ -1110,6 +1112,7 @@ def process_video_params(query, preferences) | ||||
|     extend_desc ||= preferences.extend_desc.to_unsafe | ||||
|     volume ||= preferences.volume | ||||
|     vr_mode ||= preferences.vr_mode.to_unsafe | ||||
|     save_player_pos ||= preferences.save_player_pos.to_unsafe | ||||
|   end | ||||
|  | ||||
|   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 | ||||
|   volume ||= CONFIG.default_user_preferences.volume | ||||
|   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 | ||||
|   autoplay = autoplay == 1 | ||||
| @@ -1140,6 +1144,7 @@ def process_video_params(query, preferences) | ||||
|   video_loop = video_loop == 1 | ||||
|   extend_desc = extend_desc == 1 | ||||
|   vr_mode = vr_mode == 1 | ||||
|   save_player_pos = save_player_pos == 1 | ||||
|  | ||||
|   if CONFIG.disabled?("dash") && quality == "dash" | ||||
|     quality = "high" | ||||
| @@ -1190,6 +1195,7 @@ def process_video_params(query, preferences) | ||||
|     video_start:        video_start, | ||||
|     volume:             volume, | ||||
|     vr_mode:            vr_mode, | ||||
|     save_player_pos:    save_player_pos, | ||||
|   }) | ||||
|  | ||||
|   return params | ||||
|   | ||||
| @@ -116,6 +116,11 @@ | ||||
|                 <input name="vr_mode" id="vr_mode" type="checkbox" <% if preferences.vr_mode %>checked<% end %>> | ||||
|             </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> | ||||
|  | ||||
|             <div class="pure-control-group"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user