mirror of
https://github.com/tubearchivist/tubearchivist-frontend.git
synced 2024-11-22 03:40:14 +00:00
Added sponsorblock skipping (#208)
* Added sponsorblock skipping. * Basic framework for sending SB timestamps * Sponsorblock send timestamp UI improvements * Added Sponsorblock Icons * Minor UI tweaks * Revert UI changes, implement in new UI * Added notification when sponsor segment is skipped * Add formatting for notifications & SB messages * Added SB messages to JS player * Added SB skip notifcation to videos page. * Added SB messages to video page * Change SB messages. * Check channel_overwrites * Check Per Channel Settings. * Cleanup
This commit is contained in:
parent
31378ac756
commit
c316d05549
@ -3,6 +3,36 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
{% load humanize %}
|
{% load humanize %}
|
||||||
<div class="video-main"></div>
|
<div class="video-main"></div>
|
||||||
|
<div class="notifications" id="notifications"></div>
|
||||||
|
<div class="sponsorblock" id="sponsorblock">
|
||||||
|
{% if video.channel.channel_overwrites.integrate_sponsorblock %}
|
||||||
|
{% if video.channel.channel_overwrites.integrate_sponsorblock == True %}
|
||||||
|
{% if not video.sponsorblock %}
|
||||||
|
<h4>This video doesn't have any sponsor segments added. To add a segment go to <u><a href="https://www.youtube.com/watch?v={{ video.youtube_id }}">this video on YouTube</a></u> and add a segment using the <u><a href="https://sponsor.ajay.app/">SponsorBlock</a></u> extension.</h4>
|
||||||
|
{% endif %}
|
||||||
|
{% if video.sponsorblock %}
|
||||||
|
{% for segment in video.sponsorblock %}
|
||||||
|
{% if segment.locked != 1 %}
|
||||||
|
<h4>This video has unlocked sponsor segments. Go to <u><a href="https://www.youtube.com/watch?v={{ video.youtube_id }}">this video on YouTube</a></u> and vote on the segments using the <u><a href="https://sponsor.ajay.app/">SponsorBlock</a></u> extension.</h4>
|
||||||
|
{{ break }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% elif config.downloads.integrate_sponsorblock %}
|
||||||
|
{% if not video.sponsorblock %}
|
||||||
|
<h4>This video doesn't have any sponsor segments added. To add a segment go to <u><a href="https://www.youtube.com/watch?v={{ video.youtube_id }}">this video on YouTube</a></u> and add a segment using the <u><a href="https://sponsor.ajay.app/">SponsorBlock</a></u> extension.</h4>
|
||||||
|
{% endif %}
|
||||||
|
{% if video.sponsorblock %}
|
||||||
|
{% for segment in video.sponsorblock %}
|
||||||
|
{% if segment.locked != 1 %}
|
||||||
|
<h4>This video has unlocked sponsor segments. Go to <u><a href="https://www.youtube.com/watch?v={{ video.youtube_id }}">this video on YouTube</a></u> and vote on the segments using the <u><a href="https://sponsor.ajay.app/">SponsorBlock</a></u> extension.</h4>
|
||||||
|
{{ break }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div class="boxed-content">
|
<div class="boxed-content">
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
{% if cast %}
|
{% if cast %}
|
||||||
@ -114,6 +144,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var videoData = getVideoData('{{ video.youtube_id }}');
|
var videoData = getVideoData('{{ video.youtube_id }}');
|
||||||
|
sponsorBlock = videoData.data.sponsorblock;
|
||||||
var videoProgress = getVideoProgress('{{ video.youtube_id }}').position;
|
var videoProgress = getVideoProgress('{{ video.youtube_id }}').position;
|
||||||
window.onload = insertVideoTag(videoData, videoProgress);
|
window.onload = insertVideoTag(videoData, videoProgress);
|
||||||
</script>
|
</script>
|
||||||
|
@ -62,6 +62,13 @@ h3 {
|
|||||||
color: var(--accent-font-light);
|
color: var(--accent-font-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 0.7em;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
font-family: Sen-Regular, sans-serif;
|
||||||
|
color: var(--accent-font-light);
|
||||||
|
}
|
||||||
|
|
||||||
p, i, li {
|
p, i, li {
|
||||||
font-family: Sen-Regular, sans-serif;
|
font-family: Sen-Regular, sans-serif;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
@ -355,6 +362,18 @@ button:hover {
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notifications {
|
||||||
|
text-align: center;
|
||||||
|
width: 80%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsorblock {
|
||||||
|
text-align: center;
|
||||||
|
width: 80%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.video-player video,
|
.video-player video,
|
||||||
.video-main video {
|
.video-main video {
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
|
@ -327,9 +327,33 @@ function cancelDelete() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// player
|
// player
|
||||||
|
var sponsorBlock = [];
|
||||||
function createPlayer(button) {
|
function createPlayer(button) {
|
||||||
var videoId = button.getAttribute('data-id');
|
var videoId = button.getAttribute('data-id');
|
||||||
var videoData = getVideoData(videoId);
|
var videoData = getVideoData(videoId);
|
||||||
|
|
||||||
|
var sponsorBlockElements = '';
|
||||||
|
if (videoData.config.downloads.integrate_sponsorblock && (typeof(videoData.data.channel.channel_overwrites) == "undefined" || typeof(videoData.data.channel.channel_overwrites.integrate_sponsorblock) == "undefined" || videoData.data.channel.channel_overwrites.integrate_sponsorblock == true)) {
|
||||||
|
sponsorBlock = videoData.data.sponsorblock;
|
||||||
|
if (!sponsorBlock) {
|
||||||
|
sponsorBlockElements = `
|
||||||
|
<div class="sponsorblock" id="sponsorblock">
|
||||||
|
<h4>This video doesn't have any sponsor segments added. To add a segment go to <u><a href="https://www.youtube.com/watch?v=${videoId}">this video on Youtube</a></u> and add a segment using the <u><a href="https://sponsor.ajay.app/">SponsorBlock</a></u> extension.</h4>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
for(let i in sponsorBlock) {
|
||||||
|
if(sponsorBlock[i].locked != 1) {
|
||||||
|
sponsorBlockElements = `
|
||||||
|
<div class="sponsorblock" id="sponsorblock">
|
||||||
|
<h4>This video has unlocked sponsor segments. Go to <u><a href="https://www.youtube.com/watch?v=${videoId}">this video on YouTube</a></u> and vote on the segments using the <u><a href="https://sponsor.ajay.app/">SponsorBlock</a></u> extension.</h4>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
var videoProgress = getVideoProgress(videoId).position;
|
var videoProgress = getVideoProgress(videoId).position;
|
||||||
var videoName = videoData.data.title;
|
var videoName = videoData.data.title;
|
||||||
|
|
||||||
@ -353,7 +377,6 @@ function createPlayer(button) {
|
|||||||
var channelName = videoData.data.channel.channel_name;
|
var channelName = videoData.data.channel.channel_name;
|
||||||
|
|
||||||
removePlayer();
|
removePlayer();
|
||||||
// document.getElementById(videoId).outerHTML = ''; // Remove watch indicator from video info
|
|
||||||
|
|
||||||
// If cast integration is enabled create cast button
|
// If cast integration is enabled create cast button
|
||||||
var castButton = '';
|
var castButton = '';
|
||||||
@ -383,6 +406,8 @@ function createPlayer(button) {
|
|||||||
const markup = `
|
const markup = `
|
||||||
<div class="video-player" data-id="${videoId}">
|
<div class="video-player" data-id="${videoId}">
|
||||||
${videoTag}
|
${videoTag}
|
||||||
|
<div class="notifications" id="notifications"></div>
|
||||||
|
${sponsorBlockElements}
|
||||||
<div class="player-title boxed-content">
|
<div class="player-title boxed-content">
|
||||||
<img class="close-button" src="/static/img/icon-close.svg" alt="close-icon" data="${videoId}" onclick="removePlayer()" title="Close player">
|
<img class="close-button" src="/static/img/icon-close.svg" alt="close-icon" data="${videoId}" onclick="removePlayer()" title="Close player">
|
||||||
${watchStatusIndicator}
|
${watchStatusIndicator}
|
||||||
@ -400,6 +425,53 @@ function createPlayer(button) {
|
|||||||
divPlayer.innerHTML = markup;
|
divPlayer.innerHTML = markup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// function sendSponsorBlockVote(uuid, vote) {
|
||||||
|
// var videoId = getVideoPlayerVideoId();
|
||||||
|
// postSponsorSegmentVote(videoId, uuid, vote);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// var sponsorBlockTimestamps = [];
|
||||||
|
// function sendSponsorBlockSegment() {
|
||||||
|
// var videoId = getVideoPlayerVideoId();
|
||||||
|
// var currentTime = getVideoPlayerCurrentTime();
|
||||||
|
// var sponsorBlockElement = document.getElementById("sponsorblock");
|
||||||
|
// if (sponsorBlockTimestamps[1]) {
|
||||||
|
// if (sponsorBlockTimestamps[1] > sponsorBlockTimestamps[0]) {
|
||||||
|
// postSponsorSegment(videoId, sponsorBlockTimestamps[0], sponsorBlockTimestamps[1]);
|
||||||
|
// sponsorBlockElement.innerHTML = `
|
||||||
|
// <p>Timestamps sent! (Not really)</p>
|
||||||
|
// `;
|
||||||
|
// setTimeout(function(){
|
||||||
|
// sponsorBlockElement.innerHTML = `
|
||||||
|
// <img src="/static/img/PlayerStartIconSponsorBlocker.svg" class="sponsorblockIcon"><button onclick="sendSponsorBlockSegment()">Start</button>
|
||||||
|
// `;
|
||||||
|
// }, 3000);
|
||||||
|
// } else {
|
||||||
|
// sponsorBlockElement.innerHTML = `
|
||||||
|
// <span class="danger-zone">Invalid Timestamps!</span>
|
||||||
|
// `;
|
||||||
|
// setTimeout(function(){
|
||||||
|
// sponsorBlockElement.innerHTML = `
|
||||||
|
// <img src="/static/img/PlayerStartIconSponsorBlocker.svg" class="sponsorblockIcon"><button onclick="sendSponsorBlockSegment()">Start</button>
|
||||||
|
// `;
|
||||||
|
// }, 3000);
|
||||||
|
// }
|
||||||
|
// sponsorBlockTimestamps = [];
|
||||||
|
// } else if (sponsorBlockTimestamps[0]) {
|
||||||
|
// sponsorBlockTimestamps.push(currentTime);
|
||||||
|
// sponsorBlockElement.innerHTML = `
|
||||||
|
// <img src="/static/img/PlayerStartIconSponsorBlocker.svg" class="sponsorblockIcon" onclick="getVideoPlayer().currentTime = '${sponsorBlockTimestamps[0]}'"><p>${sponsorBlockTimestamps[0].toFixed(1)} s | </p>
|
||||||
|
// <img src="/static/img/PlayerStopIconSponsorBlocker.svg" class="sponsorblockIcon" onclick="getVideoPlayer().currentTime = '${sponsorBlockTimestamps[1]}'"><p>${sponsorBlockTimestamps[1].toFixed(1)} s | </p>
|
||||||
|
// <img src="/static/img/PlayerUploadIconSponsorBlocker.svg" class="sponsorblockIcon"><button onclick="sendSponsorBlockSegment()">Confirm</button>
|
||||||
|
// `;
|
||||||
|
// } else {
|
||||||
|
// sponsorBlockTimestamps.push(currentTime);
|
||||||
|
// sponsorBlockElement.innerHTML = `
|
||||||
|
// <img src="/static/img/PlayerStopIconSponsorBlocker.svg" class="sponsorblockIcon"><button onclick="sendSponsorBlockSegment()">End</button>
|
||||||
|
// `;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Add video tag to video page when passed a video id, function loaded on page load `video.html (115-117)`
|
// Add video tag to video page when passed a video id, function loaded on page load `video.html (115-117)`
|
||||||
function insertVideoTag(videoData, videoProgress) {
|
function insertVideoTag(videoData, videoProgress) {
|
||||||
var videoTag = createVideoTag(videoData, videoProgress);
|
var videoTag = createVideoTag(videoData, videoProgress);
|
||||||
@ -488,6 +560,32 @@ function onVideoProgress() {
|
|||||||
var videoId = getVideoPlayerVideoId();
|
var videoId = getVideoPlayerVideoId();
|
||||||
var currentTime = getVideoPlayerCurrentTime();
|
var currentTime = getVideoPlayerCurrentTime();
|
||||||
var duration = getVideoPlayerDuration();
|
var duration = getVideoPlayerDuration();
|
||||||
|
var videoElement = getVideoPlayer();
|
||||||
|
// var sponsorBlockElement = document.getElementById("sponsorblock");
|
||||||
|
var notificationsElement = document.getElementById("notifications");
|
||||||
|
if (sponsorBlock) {
|
||||||
|
for(let i in sponsorBlock) {
|
||||||
|
if(sponsorBlock[i].segment[0] <= currentTime + 0.3 && sponsorBlock[i].segment[0] >= currentTime) {
|
||||||
|
videoElement.currentTime = sponsorBlock[i].segment[1];
|
||||||
|
notificationsElement.innerHTML += `<h3 id="notification-${sponsorBlock[i].UUID}">Skipped sponsor segment from ${formatTime(sponsorBlock[i].segment[0])} to ${formatTime(sponsorBlock[i].segment[1])}.</h3>`;
|
||||||
|
}
|
||||||
|
// if(currentTime >= sponsorBlock[i].segment[1] && currentTime <= sponsorBlock[i].segment[1] + 0.2) {
|
||||||
|
// if(sponsorBlock[i].locked != 1) {
|
||||||
|
// sponsorBlockElement.innerHTML += `
|
||||||
|
// <div id="${sponsorBlock[i].UUID}">
|
||||||
|
// <button onclick="sendSponsorBlockVote('${sponsorBlock[i].UUID}', 1)">Up Vote</button>
|
||||||
|
// <button onclick="sendSponsorBlockVote('${sponsorBlock[i].UUID}', -1)">Down Vote</button>
|
||||||
|
// </div>`;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if(currentTime > sponsorBlock[i].segment[1] + 10) {
|
||||||
|
var notificationsElementUUID = document.getElementById("notification-" + sponsorBlock[i].UUID);
|
||||||
|
if(notificationsElementUUID) {
|
||||||
|
notificationsElementUUID.outerHTML = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if ((currentTime % 10).toFixed(1) <= 0.2) { // Check progress every 10 seconds or else progress is checked a few times a second
|
if ((currentTime % 10).toFixed(1) <= 0.2) { // Check progress every 10 seconds or else progress is checked a few times a second
|
||||||
postVideoProgress(videoId, currentTime);
|
postVideoProgress(videoId, currentTime);
|
||||||
if (!getVideoPlayerWatchStatus()) { // Check if video is already marked as watched
|
if (!getVideoPlayerWatchStatus()) { // Check if video is already marked as watched
|
||||||
@ -542,6 +640,32 @@ function formatNumbers(number) {
|
|||||||
return numberFormatted;
|
return numberFormatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Formats times in seconds for frontend
|
||||||
|
function formatTime(time) {
|
||||||
|
var hoursUnformatted = time / 3600;
|
||||||
|
var minutesUnformatted = (time % 3600) / 60;
|
||||||
|
var secondsUnformatted = time % 60;
|
||||||
|
|
||||||
|
var hoursFormatted = Math.trunc(hoursUnformatted);
|
||||||
|
if(minutesUnformatted < 10 && hoursFormatted > 0) {
|
||||||
|
var minutesFormatted = "0" + Math.trunc(minutesUnformatted);
|
||||||
|
} else {
|
||||||
|
var minutesFormatted = Math.trunc(minutesUnformatted);
|
||||||
|
}
|
||||||
|
if(secondsUnformatted < 10) {
|
||||||
|
var secondsFormatted = "0" + Math.trunc(secondsUnformatted);
|
||||||
|
} else {
|
||||||
|
var secondsFormatted = Math.trunc(secondsUnformatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeUnformatted = '';
|
||||||
|
if(hoursFormatted > 0) {
|
||||||
|
timeUnformatted = hoursFormatted + ":"
|
||||||
|
}
|
||||||
|
var timeFormatted = timeUnformatted.concat(minutesFormatted, ":", secondsFormatted);
|
||||||
|
return timeFormatted;
|
||||||
|
}
|
||||||
|
|
||||||
// Gets video data when passed video ID
|
// Gets video data when passed video ID
|
||||||
function getVideoData(videoId) {
|
function getVideoData(videoId) {
|
||||||
var apiEndpoint = "/api/video/" + videoId + "/";
|
var apiEndpoint = "/api/video/" + videoId + "/";
|
||||||
@ -599,6 +723,30 @@ function postVideoProgress(videoId, videoProgress) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send sponsor segment when given video id and and timestamps
|
||||||
|
function postSponsorSegment(videoId, startTime, endTime) {
|
||||||
|
var apiEndpoint = "/api/video/" + videoId + "/sponsor/";
|
||||||
|
var data = {
|
||||||
|
"segment": {
|
||||||
|
"startTime": startTime,
|
||||||
|
"endTime": endTime
|
||||||
|
}
|
||||||
|
};
|
||||||
|
apiRequest(apiEndpoint, "POST", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send sponsor segment when given video id and and timestamps
|
||||||
|
function postSponsorSegmentVote(videoId, uuid, vote) {
|
||||||
|
var apiEndpoint = "/api/video/" + videoId + "/sponsor/";
|
||||||
|
var data = {
|
||||||
|
"vote": {
|
||||||
|
"uuid": uuid,
|
||||||
|
"yourVote": vote
|
||||||
|
}
|
||||||
|
};
|
||||||
|
apiRequest(apiEndpoint, "POST", data);
|
||||||
|
}
|
||||||
|
|
||||||
// Makes api requests when passed an endpoint and method ("GET", "POST", "DELETE")
|
// Makes api requests when passed an endpoint and method ("GET", "POST", "DELETE")
|
||||||
function apiRequest(apiEndpoint, method, data) {
|
function apiRequest(apiEndpoint, method, data) {
|
||||||
const xhttp = new XMLHttpRequest();
|
const xhttp = new XMLHttpRequest();
|
||||||
|
Loading…
Reference in New Issue
Block a user