Created
March 23, 2024 17:51
-
-
Save muekoeff/8b4c5ac2d9d36f072eb1e29965b38d3f to your computer and use it in GitHub Desktop.
Favorite tracks on Jellyfin from a list of tracks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1. Navigate to: https://your.jellyfin.instance/web/index.html#!/search.html | |
// 2. Define `const tracks`, each track is an object with `title` and `artist` | |
// 3. Define `section_title` to match the section title for tracks | |
// 4. Call `await favItems(tracks);` | |
const section_title = 'Lieder'; | |
const delay = 750; | |
async function favItems(items) { | |
const success = []; | |
const fail = []; | |
for (const item of items) { | |
await search(item); | |
const favSuccessful = await favItem(item); | |
if (favSuccessful) { | |
console.debug(`${item.artist} – ${item.title} succeeded`); | |
success.push(item); | |
} else { | |
console.debug(`${item.artist} – ${item.title} failed`); | |
fail.push(item); | |
} | |
} | |
return { | |
fail: fail, | |
success: success | |
}; | |
} | |
async function favItem(track) { | |
// Find tracks-container | |
const containers = [...document.querySelectorAll('.searchResults .verticalSection')].filter((container) => { | |
return container.querySelector('.sectionTitle').textContent === section_title; | |
}); | |
if (containers.length !== 1) { | |
return false; | |
} | |
const container = containers[0]; | |
// Find track-card | |
const cards = [...container.querySelectorAll('.card')].filter((card) => { | |
const title = card.querySelector('.cardText-first').textContent; | |
const artist = card.querySelector('.cardText-secondary').textContent; | |
return normaliseTitle(track.title) === normaliseTitle(title) && (normaliseTitle(track.artist) === normaliseTitle(artist) || artist === 'Various Artists'); | |
}); | |
if (cards.length !== 1) { | |
return false; | |
} | |
const card = cards[0]; | |
// Fav track | |
const fav = card.querySelector('.favorite'); | |
if (!fav.matches('.ratingbutton-icon-withrating')) { | |
fav.click(); | |
await (new Promise((resolve) => setTimeout(resolve, delay))); | |
} | |
return true; | |
} | |
function normaliseTitle(title) { | |
return title.split(' feat. ')[0].replace(/ &/g, ','); | |
} | |
async function search(item) { | |
const fields = document.querySelectorAll('.searchfields-txtSearch'); | |
const field = fields[fields.length - 1]; | |
field.value = item.title; | |
field.dispatchEvent(new Event('input')); | |
await (new Promise((resolve) => setTimeout(resolve, delay))); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment