初回ロードのマウントポイント待機

This commit is contained in:
Keisuke Hirata 2026-04-09 03:01:58 +09:00
parent b23de0741a
commit 38dbd504d6

View File

@ -6,6 +6,38 @@ const CONTAINER_ID = "ytpf-playlist-table";
let currentHandle: PlaylistTableHandle | null = null; let currentHandle: PlaylistTableHandle | null = null;
function findAnchor(): { parent: Element; before: Element | null } | null {
// Primary: before ytd-playlist-video-list-renderer (sibling)
const videoList = document.querySelector("ytd-playlist-video-list-renderer");
if (videoList?.parentElement) {
return { parent: videoList.parentElement, before: videoList };
}
// Fallback: end of ytd-section-list-renderer > #contents
const sectionContents = document.querySelector(
"ytd-section-list-renderer > #contents",
);
if (sectionContents) {
return { parent: sectionContents, before: null };
}
// Last resort: #primary
const primary = document.querySelector(
"ytd-two-column-browse-results-renderer > #primary",
);
if (primary) {
return { parent: primary, before: null };
}
return null;
}
function insertAt(el: HTMLElement, anchor: { parent: Element; before: Element | null }): void {
anchor.parent.insertBefore(el, anchor.before);
}
let pendingObserver: MutationObserver | null = null;
export function mountTable(data: PlaylistData): void { export function mountTable(data: PlaylistData): void {
unmountTable(); unmountTable();
injectStyles(); injectStyles();
@ -14,32 +46,22 @@ export function mountTable(data: PlaylistData): void {
const el = currentHandle.element; const el = currentHandle.element;
el.id = CONTAINER_ID; el.id = CONTAINER_ID;
// Primary: before ytd-playlist-video-list-renderer (sibling) const anchor = findAnchor();
const videoList = document.querySelector("ytd-playlist-video-list-renderer"); if (anchor) {
if (videoList?.parentElement) { insertAt(el, anchor);
videoList.parentElement.insertBefore(el, videoList);
return; return;
} }
// Fallback: end of ytd-section-list-renderer > #contents // DOM not ready yet — wait for the anchor element to appear
const sectionContents = document.querySelector( pendingObserver = new MutationObserver(() => {
"ytd-section-list-renderer > #contents", const a = findAnchor();
); if (a) {
if (sectionContents) { pendingObserver!.disconnect();
sectionContents.appendChild(el); pendingObserver = null;
return; insertAt(el, a);
} }
});
// Last resort: #primary pendingObserver.observe(document.body, { childList: true, subtree: true });
const primary = document.querySelector(
"ytd-two-column-browse-results-renderer > #primary",
);
if (primary) {
primary.appendChild(el);
return;
}
console.warn("[yt-playlist-features] Could not find anchor to mount table");
} }
export function appendToTable(newVideos: PlaylistVideo[]): void { export function appendToTable(newVideos: PlaylistVideo[]): void {
@ -51,6 +73,10 @@ export function setTableComplete(extractedCount: number): void {
} }
export function unmountTable(): void { export function unmountTable(): void {
if (pendingObserver) {
pendingObserver.disconnect();
pendingObserver = null;
}
currentHandle = null; currentHandle = null;
document.getElementById(CONTAINER_ID)?.remove(); document.getElementById(CONTAINER_ID)?.remove();
} }