Skip to content

Commit 8ab207f

Browse files
committed
feat: auto sort playlists
The playlists in which the video exists will be displayed first.
1 parent ae1b98c commit 8ab207f

1 file changed

Lines changed: 52 additions & 1 deletion

File tree

user script/yt-playlist-filter.user.js

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// ==UserScript==
22
// @name YouTube Save to Playlist filter
33
// @namespace fred.vatin.yt-playlists-filter
4-
// @version 1.0
4+
// @version 1.1.0
55
// @description Tap P key to open the “save to playlist” menu where your can type to filter
66
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
77
// @author Fred Vatin, Flemming Steffensen
@@ -49,6 +49,7 @@
4949
const selector_Header = "yt-panel-header-view-model";
5050
const selector_List = ".ytListViewModelHost";
5151
const selector_ListItems = ".toggleableListItemViewModelHost";
52+
const selector_SelItems = `:scope > yt-list-item-view-model[aria-pressed="true"]`;
5253
const selector_Item = ".yt-core-attributed-string";
5354
const selector_OpenMenuParent = "ytd-app ytd-popup-container";
5455
const InputId = "filterPlaylist";
@@ -314,6 +315,8 @@
314315
function addFilterInput(elements = {}) {
315316
const { list = null, header = null } = elements;
316317

318+
autoTopList(list);
319+
317320
const existingFilterInput = document.getElementById(InputId);
318321

319322
if (!existingFilterInput) {
@@ -362,6 +365,11 @@
362365
* @param {string} filterText - The text to filter playlist items by. Items not containing this text will be hidden.
363366
*/
364367
function filterPlaylist(playlist, filterText) {
368+
if (!playlist) {
369+
console.log("❌ filterPlaylist(playlist, filterText): playlist is null or invalid");
370+
return;
371+
}
372+
365373
const listItems = playlist.querySelectorAll(selector_ListItems);
366374
// const listItems = query(playlist, selector_ListItems);
367375
const text = filterText.trim().toLowerCase();
@@ -374,6 +382,49 @@
374382
});
375383
}
376384

385+
/**
386+
* Automatically sorts playlist items by placing selected items at the top.
387+
* Selected items are playlists in which the current video already exists.
388+
* @param {HTMLElement} playlist - The playlist container element to sort
389+
* @returns {void}
390+
* @description
391+
* This function reorganizes playlist items so that selected items appear first,
392+
* followed by unselected items. It filters items using predefined selectors,
393+
* logs the operation status, and reinserts items in the new order.
394+
* @example
395+
* const playlistElement = document.querySelector('.playlist');
396+
* autoTopList(playlistElement);
397+
*/
398+
function autoTopList(playlist) {
399+
if (!playlist) {
400+
console.log("❌ autoTopList(playlist): playlist is null or invalid");
401+
return;
402+
}
403+
404+
// Collect all items
405+
const listItems = Array.from(playlist.querySelectorAll(selector_ListItems));
406+
console.log("✅ autoTopList(playlist), listItems number: ", listItems.length);
407+
408+
// Separates the selected ones from the rest
409+
const selected = listItems.filter((item) => item.querySelector(selector_SelItems));
410+
const unselected = listItems.filter((item) => !item.querySelector(selector_SelItems));
411+
412+
if (selected.length > 0) {
413+
console.log(`✅ autoTopList(playlist), this video belongs to ${selected.length} playlist(s)`);
414+
// Reinsert in the desired order
415+
[...selected, ...unselected].forEach((item) => {
416+
playlist.appendChild(item);
417+
});
418+
419+
console.log(`✅ autoTopList(playlist), playlists have been sorted.`);
420+
421+
const sortedItems = Array.from(playlist.querySelectorAll(selector_ListItems));
422+
console.log("✅ autoTopList(playlist), sortedItems number: ", sortedItems.length);
423+
} else {
424+
console.log("❌ autoTopList(playlist): this video doesn’t belong to any existing playlist");
425+
}
426+
}
427+
377428
/**
378429
* Sets focus to the input element with the given ID, resets its value,
379430
* and dispatches an "input" event to trigger any associated handlers.

0 commit comments

Comments
 (0)