Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions assets/js/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,15 @@
event.preventDefault();
}
});

// Handle the video watched state with JavaScript (if enabled)
const anchorElements = document.querySelectorAll('a[href^="/watch"]');

for (const anchorElement of anchorElements) {
const url = new URL(anchorElement.href);

url.searchParams.set("mark_watched", "0");

anchorElement.href = url.href;
}
})();
71 changes: 69 additions & 2 deletions assets/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,37 @@ function addCurrentTimeToURL(url, base) {
*/
var timeupdate_last_ts = 5;

/**
* Global variable to save the total video time watched (in seconds).
*/
let time_watched = 0;

/**
* The duration of a short video (in seconds).
* This value is used to determine whether the video should be watched fully before
* being marked as watched.
*
* @default 30
*/
const SHORT_VIDEO_DURATION = 30;

/**
* The duration (in seconds) after which a video should be marked as watched.
*
* @default 30
*/
const MARK_WATCHED_AFTER_DURATION = SHORT_VIDEO_DURATION;

/**
* Callback that updates the timestamp on all external links
* Callback that updates the timestamp on all external links and marks the video as watched after:
* - fully watching short videos (<=30 seconds)
* - time watched reaches 30 seconds for long videos (>30 seconds)
*/
player.on('timeupdate', function () {
// Only update once every second
let current_ts = Math.floor(player.currentTime());
if (current_ts > timeupdate_last_ts) timeupdate_last_ts = current_ts;
const last_player_time = timeupdate_last_ts;
if (current_ts !== timeupdate_last_ts) timeupdate_last_ts = current_ts;
else return;

// YouTube links
Expand Down Expand Up @@ -166,6 +190,49 @@ player.on('timeupdate', function () {
let base_url_iv_other = elem_iv_other.getAttribute('data-base-url');
elem_iv_other.href = addCurrentTimeToURL(base_url_iv_other, domain);
}

// Only increase time watched when the time difference is one second and the video has not been marked as watched
const isOneSecondDifference = current_ts - last_player_time === 1;
const exceedsMarkWatchedAfterDuration = time_watched > MARK_WATCHED_AFTER_DURATION;

if (!isOneSecondDifference || exceedsMarkWatchedAfterDuration) return;

time_watched += 1;

// Check if time watched exceeds 30 seconds or the video is fully watched
const absolute_video_duration = Math.floor(player.duration());
const watched_at_timestamp = absolute_video_duration > SHORT_VIDEO_DURATION
? MARK_WATCHED_AFTER_DURATION
: absolute_video_duration;

if (time_watched !== watched_at_timestamp) return;

const video_id = document.querySelector('[name="id"]').value;
const $csrfToken = document.querySelector('[name="csrf_token"]');

// User is not logged in
if ($csrfToken === null) return;

// Mark the video as watched
const csrf_token = $csrfToken.value;

const params = new URLSearchParams({
action: "mark_watched",
redirect: false,
id: video_id
});

const url = `/watch_ajax?${params}`;

helpers.xhr('POST', url, { payload: `csrf_token=${csrf_token}` }, {
on200: () => {
console.info(`Marked video ${video_id} as watched`);
},
onNon200: ({ response }) => {
console.error(`Something went wrong while marking video ${video_id} as watched:`, response);
}
});

});


Expand Down
2 changes: 1 addition & 1 deletion src/invidious/routes/watch.cr
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ module Invidious::Routes::Watch
end
env.params.query.delete_all("iv_load_policy")

if watched && preferences.watch_history
if watched && (env.params.query["mark_watched"]? || "1") == "1"
Invidious::Database::Users.mark_watched(user.as(User), id)
end

Expand Down