added seek bar functionality
This commit is contained in:
parent
0b6058965f
commit
132ffe86ba
166
script.js
166
script.js
@ -1,8 +1,8 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name antisocial.moe - youtube music scrobbler
|
// @name antisocial.moe - youtube music scrobbler
|
||||||
// @namespace http://tampermonkey.net/
|
// @namespace http://tampermonkey.net/
|
||||||
// @version 2.0
|
// @version 2.1
|
||||||
// @author
|
// @description Scrobbles songs from YouTube Music to antisocial.moe, with progress bar monitoring
|
||||||
// @match https://music.youtube.com/*
|
// @match https://music.youtube.com/*
|
||||||
// @grant GM_xmlhttpRequest
|
// @grant GM_xmlhttpRequest
|
||||||
// @grant GM_setValue
|
// @grant GM_setValue
|
||||||
@ -186,6 +186,90 @@
|
|||||||
// Timer for scrobbling after 10 seconds of playback
|
// Timer for scrobbling after 10 seconds of playback
|
||||||
let playbackTimer = null;
|
let playbackTimer = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ============================
|
||||||
|
* Progress Monitoring Logic
|
||||||
|
* ============================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current progress percentage of the song.
|
||||||
|
* @returns {number|null} Progress percentage (0-100) or null if not available.
|
||||||
|
*/
|
||||||
|
function getProgressPercentage() {
|
||||||
|
const progressBar = querySelectorDeep('#progress-bar');
|
||||||
|
if (progressBar) {
|
||||||
|
const valueNow = parseInt(progressBar.getAttribute('aria-valuenow'), 10);
|
||||||
|
const valueMax = parseInt(progressBar.getAttribute('aria-valuemax'), 10);
|
||||||
|
if (!isNaN(valueNow) && !isNaN(valueMax) && valueMax > 0) {
|
||||||
|
return (valueNow / valueMax) * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable to keep track of last progress percentage
|
||||||
|
let lastProgressPercentage = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles progress changes and detects jumps from >95% to <5%.
|
||||||
|
* @param {number} newPercentage - The new progress percentage.
|
||||||
|
*/
|
||||||
|
function handleProgressChange(newPercentage) {
|
||||||
|
if (lastProgressPercentage === null) {
|
||||||
|
lastProgressPercentage = newPercentage;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lastProgressPercentage > 95 && newPercentage < 5) {
|
||||||
|
console.log('Progress jumped from >95% to <5%. Sending new scrobble.');
|
||||||
|
const songInfo = getSongInfo();
|
||||||
|
if (songInfo) {
|
||||||
|
scrobble(songInfo.title, songInfo.author, songInfo.album);
|
||||||
|
} else {
|
||||||
|
console.warn('Cannot scrobble: song information not found.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastProgressPercentage = newPercentage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a MutationObserver to monitor the progress bar's aria-valuenow.
|
||||||
|
*/
|
||||||
|
function initProgressObserver() {
|
||||||
|
const progressBar = querySelectorDeep('#progress-bar');
|
||||||
|
if (!progressBar) {
|
||||||
|
console.error('Progress bar not found. Progress monitoring not initialized.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize lastProgressPercentage
|
||||||
|
lastProgressPercentage = getProgressPercentage();
|
||||||
|
console.debug('Initial progress percentage:', lastProgressPercentage);
|
||||||
|
|
||||||
|
// Create observer
|
||||||
|
const progressObserver = new MutationObserver((mutations) => {
|
||||||
|
for (let mutation of mutations) {
|
||||||
|
if (mutation.type === 'attributes' && mutation.attributeName === 'aria-valuenow') {
|
||||||
|
const newPercentage = getProgressPercentage();
|
||||||
|
if (newPercentage !== null) {
|
||||||
|
console.debug(`Progress updated: ${newPercentage.toFixed(2)}%`);
|
||||||
|
handleProgressChange(newPercentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Observe aria-valuenow
|
||||||
|
progressObserver.observe(progressBar, { attributes: true, attributeFilter: ['aria-valuenow'] });
|
||||||
|
console.log('Progress observer initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ============================
|
||||||
|
* Scrobbling Logic (continued)
|
||||||
|
* ============================
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the scrobbling logic when a song change or playback state change is detected.
|
* Handles the scrobbling logic when a song change or playback state change is detected.
|
||||||
* Scrobbles the song only if it has been playing for more than 10 seconds and is currently playing.
|
* Scrobbles the song only if it has been playing for more than 10 seconds and is currently playing.
|
||||||
@ -208,31 +292,33 @@
|
|||||||
if (!areSongsEqual(lastScrobbledSong, songInfo)) {
|
if (!areSongsEqual(lastScrobbledSong, songInfo)) {
|
||||||
console.log(`New song detected: "${songInfo.title}" by ${songInfo.author} from "${songInfo.album}"`);
|
console.log(`New song detected: "${songInfo.title}" by ${songInfo.author} from "${songInfo.album}"`);
|
||||||
|
|
||||||
// Update lastScrobbledSong to prevent repeated attempts
|
|
||||||
// Note: We update it here to prevent multiple timers for the same song
|
|
||||||
lastScrobbledSong = songInfo;
|
|
||||||
|
|
||||||
// Clear any existing timer
|
|
||||||
if (playbackTimer) {
|
|
||||||
clearTimeout(playbackTimer);
|
|
||||||
playbackTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the song is currently playing
|
// Check if the song is currently playing
|
||||||
if (isPlaying()) {
|
if (isPlaying() && !scrobbleScheduled) {
|
||||||
if (!scrobbleScheduled) {
|
scrobbleScheduled = true;
|
||||||
scrobbleScheduled = true;
|
|
||||||
playbackTimer = setTimeout(() => {
|
// Update lastScrobbledSong to prevent repeated attempts
|
||||||
if (isPlaying()) {
|
// Note: We update it here to prevent multiple timers for the same song
|
||||||
scrobble(songInfo.title, songInfo.author, songInfo.album);
|
lastScrobbledSong = songInfo;
|
||||||
playbackTimer = null;
|
|
||||||
} else {
|
// Clear any existing timer
|
||||||
console.log('Playback stopped before scrobble threshold.');
|
if (playbackTimer) {
|
||||||
scrobbleScheduled = false;
|
clearTimeout(playbackTimer);
|
||||||
}
|
playbackTimer = null;
|
||||||
}, 10000); // 10 seconds
|
scrobbleScheduled = false;
|
||||||
console.log('Started 10-second timer for scrobble.');
|
}
|
||||||
}
|
|
||||||
|
playbackTimer = setTimeout(() => {
|
||||||
|
if (isPlaying()) {
|
||||||
|
scrobble(songInfo.title, songInfo.author, songInfo.album);
|
||||||
|
playbackTimer = null;
|
||||||
|
} else {
|
||||||
|
console.log('Playback stopped before scrobble threshold.');
|
||||||
|
scrobbleScheduled = false;
|
||||||
|
}
|
||||||
|
}, 10000); // 10 seconds
|
||||||
|
console.log('Started 10-second timer for scrobble.');
|
||||||
|
} else {
|
||||||
|
console.debug(`isPlaying: ${isPlaying()} scrobbleScheduled: ${scrobbleScheduled}`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.debug('Same song, no action needed.');
|
console.debug('Same song, no action needed.');
|
||||||
@ -298,6 +384,12 @@
|
|||||||
console.log('YouTube Music Scrobbler with Conditional Scrobbling is now active.');
|
console.log('YouTube Music Scrobbler with Conditional Scrobbling is now active.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ============================
|
||||||
|
* Initialization
|
||||||
|
* ============================
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for the player bar to be available in the DOM before initializing the observer.
|
* Waits for the player bar to be available in the DOM before initializing the observer.
|
||||||
*/
|
*/
|
||||||
@ -309,6 +401,9 @@
|
|||||||
initObserver();
|
initObserver();
|
||||||
// Initial scrobble handling
|
// Initial scrobble handling
|
||||||
handleScrobble();
|
handleScrobble();
|
||||||
|
|
||||||
|
// Initialize progress observer
|
||||||
|
initProgressObserver();
|
||||||
}
|
}
|
||||||
}, 1000); // Check every second
|
}, 1000); // Check every second
|
||||||
|
|
||||||
@ -319,12 +414,6 @@
|
|||||||
// }, 30000); // 30 seconds
|
// }, 30000); // 30 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ============================
|
|
||||||
* UI for Managing AUTH_KEY
|
|
||||||
* ============================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompts the user to enter their AUTH_KEY and stores it using GM_setValue.
|
* Prompts the user to enter their AUTH_KEY and stores it using GM_setValue.
|
||||||
*/
|
*/
|
||||||
@ -350,15 +439,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ============================
|
* Optionally, prompt the user to set the AUTH_KEY if it's not already set.
|
||||||
* Initialization
|
|
||||||
* ============================
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Register the menu command for setting the AUTH_KEY
|
|
||||||
registerMenuCommands();
|
|
||||||
|
|
||||||
// Optionally, prompt the user to set the AUTH_KEY if it's not already set
|
|
||||||
function promptForAuthKeyIfNeeded() {
|
function promptForAuthKeyIfNeeded() {
|
||||||
const authKey = GM_getValue('AUTH_KEY', '');
|
const authKey = GM_getValue('AUTH_KEY', '');
|
||||||
if (!authKey) {
|
if (!authKey) {
|
||||||
@ -366,6 +448,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register the menu command for setting the AUTH_KEY
|
||||||
|
registerMenuCommands();
|
||||||
|
|
||||||
// Start the script by waiting for the player bar to load
|
// Start the script by waiting for the player bar to load
|
||||||
waitForPlayerBar();
|
waitForPlayerBar();
|
||||||
|
|
||||||
@ -373,4 +458,3 @@
|
|||||||
promptForAuthKeyIfNeeded();
|
promptForAuthKeyIfNeeded();
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user