added seek bar functionality
This commit is contained in:
parent
0b6058965f
commit
132ffe86ba
166
script.js
166
script.js
@ -1,8 +1,8 @@
|
||||
// ==UserScript==
|
||||
// @name antisocial.moe - youtube music scrobbler
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 2.0
|
||||
// @author
|
||||
// @version 2.1
|
||||
// @description Scrobbles songs from YouTube Music to antisocial.moe, with progress bar monitoring
|
||||
// @match https://music.youtube.com/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @grant GM_setValue
|
||||
@ -186,6 +186,90 @@
|
||||
// Timer for scrobbling after 10 seconds of playback
|
||||
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.
|
||||
* 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)) {
|
||||
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
|
||||
if (isPlaying()) {
|
||||
if (!scrobbleScheduled) {
|
||||
scrobbleScheduled = true;
|
||||
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.');
|
||||
}
|
||||
if (isPlaying() && !scrobbleScheduled) {
|
||||
scrobbleScheduled = true;
|
||||
|
||||
// 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;
|
||||
scrobbleScheduled = false;
|
||||
}
|
||||
|
||||
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 {
|
||||
console.debug('Same song, no action needed.');
|
||||
@ -298,6 +384,12 @@
|
||||
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.
|
||||
*/
|
||||
@ -309,6 +401,9 @@
|
||||
initObserver();
|
||||
// Initial scrobble handling
|
||||
handleScrobble();
|
||||
|
||||
// Initialize progress observer
|
||||
initProgressObserver();
|
||||
}
|
||||
}, 1000); // Check every second
|
||||
|
||||
@ -319,12 +414,6 @@
|
||||
// }, 30000); // 30 seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* ============================
|
||||
* UI for Managing AUTH_KEY
|
||||
* ============================
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prompts the user to enter their AUTH_KEY and stores it using GM_setValue.
|
||||
*/
|
||||
@ -350,15 +439,8 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* ============================
|
||||
* Initialization
|
||||
* ============================
|
||||
* Optionally, prompt the user to set the AUTH_KEY if it's not already set.
|
||||
*/
|
||||
|
||||
// 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() {
|
||||
const authKey = GM_getValue('AUTH_KEY', '');
|
||||
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
|
||||
waitForPlayerBar();
|
||||
|
||||
@ -373,4 +458,3 @@
|
||||
promptForAuthKeyIfNeeded();
|
||||
|
||||
})();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user