Parent directory

index.js

3676 bytes
  1document.addEventListener("DOMContentLoaded", function () {
  2	if (navigator.standalone === true) {
  3		document.addEventListener("click", function (event) {
  4		const link = event.target.closest("a[data-open-in-safari]");
  5		if (!link) return;
  6
  7		event.preventDefault();
  8		window.location.href = `x-safari-${link.href}`;
  9	});
 10	}
 11
 12	const addVideoModal = document.getElementById("add-video-modal");
 13	if (addVideoModal) {
 14		addVideoModal.addEventListener("shown.bs.modal", function () {
 15			const input = addVideoModal.querySelector("input");
 16			if (input) input.focus();
 17		});
 18	}
 19
 20	const searchInput = document.getElementById("video-search");
 21	if (!searchInput) return;
 22
 23	function performSearch() {
 24		const videoCards = Array.from(document.querySelectorAll(".video-card"));
 25		const query = searchInput.value.trim();
 26
 27		if (!query) {
 28			videoCards.forEach((card) => (card.style.display = ""));
 29			return;
 30		}
 31
 32		const videos = videoCards.map((card) => ({
 33			element: card,
 34			title: card.dataset.title || "",
 35			channelName: card.dataset.channelName || "",
 36		}));
 37
 38		const fuse = new Fuse(videos, {
 39			keys: ["title", "channelName"],
 40			threshold: 0.4,
 41			includeScore: true,
 42		});
 43
 44		const results = fuse.search(query);
 45		const resultElements = new Set(results.map((r) => r.item.element));
 46
 47		videoCards.forEach((card) => {
 48			card.style.display = resultElements.has(card) ? "" : "none";
 49		});
 50	}
 51
 52	searchInput.addEventListener("input", performSearch);
 53
 54	if (searchInput.value.trim()) {
 55		performSearch();
 56	}
 57});
 58
 59var currentVideoID = "";
 60
 61function openResolutionModal(button) {
 62	currentVideoID = button.dataset.videoId;
 63	document.getElementById("resolution-modal-title").textContent =
 64		button.dataset.videoTitle;
 65	new bootstrap.Modal(document.getElementById("resolution-modal")).show();
 66}
 67
 68document.addEventListener("click", function (e) {
 69	const btn = e.target.closest(".resolution-btn");
 70	if (!btn || !currentVideoID) return;
 71	const formData = new FormData();
 72	formData.append("format", btn.dataset.height);
 73	fetch("/videos/" + currentVideoID + "/download", {
 74		method: "POST",
 75		body: formData,
 76	}).then(function (resp) {
 77		if (resp.ok) {
 78			bootstrap.Modal.getInstance(
 79				document.getElementById("resolution-modal"),
 80			).hide();
 81			location.reload();
 82		}
 83	});
 84});
 85
 86function animateRemove(selector) {
 87	const el = document.querySelector(selector);
 88	if (!el) return;
 89	const siblings = [...el.parentElement.children].filter(c => c !== el);
 90	const oldRects = siblings.map(s => s.getBoundingClientRect());
 91
 92	el.style.transition = "opacity 0.15s ease-out";
 93	el.style.opacity = "0";
 94	setTimeout(() => {
 95		el.remove();
 96		siblings.forEach((s, i) => {
 97			const newRect = s.getBoundingClientRect();
 98			const dx = oldRects[i].left - newRect.left;
 99			const dy = oldRects[i].top - newRect.top;
100			if (!dx && !dy) return;
101			s.style.transition = "none";
102			s.style.transform = `translate(${dx}px, ${dy}px)`;
103			s.offsetHeight; // force reflow
104			s.style.transition = "transform 0.2s ease-out";
105			s.style.transform = "";
106		});
107	}, 150);
108}
109
110function showFormError(modalId, errorText) {
111	const modal = document.getElementById(modalId);
112	if (!modal) return;
113	const field = modal.querySelector("input");
114	if (!field) return;
115	field.setCustomValidity(errorText);
116	field.onfocus = () => field.reportValidity();
117	field.onchange = () => field.setCustomValidity("");
118	field.reportValidity();
119}
120
121if ("serviceWorker" in navigator) {
122	navigator.serviceWorker
123		.register("/assets/sw.js")
124		.then((registration) => {
125			console.log(
126				"Service Worker registered with scope:",
127				registration.scope,
128			);
129		})
130		.catch((error) => {
131			console.log("Service Worker registration failed:", error);
132		});
133}