Merge: promote dev to prod
This commit is contained in:
commit
a2c3053a46
6 changed files with 60 additions and 7 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
0.5.0
|
||||
0.5.1
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||
import type { TFunction } from "i18next";
|
||||
import { createPortal } from "react-dom";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { ArrowLeft, Check, CheckCheck, SkipBack, SkipForward, X } from "lucide-react";
|
||||
import { AlertTriangle, ArrowLeft, Check, CheckCheck, ExternalLink, SkipBack, SkipForward, X } from "lucide-react";
|
||||
import Avatar from "./Avatar";
|
||||
import AddToPlaylist from "./AddToPlaylist";
|
||||
import { api, type Video } from "../lib/api";
|
||||
|
|
@ -237,12 +237,17 @@ export default function PlayerModal({
|
|||
const navigated = currentVideoId !== active.id;
|
||||
// Title/author of a navigated-to video, read from the player (free, no API call).
|
||||
const [liveData, setLiveData] = useState<{ title?: string; author?: string } | null>(null);
|
||||
// IFrame Player API error code, when the current video can't play in the embed (e.g. an
|
||||
// auto-generated Topic "Art Track" with embedding disabled → 101/150, or removed/private →
|
||||
// 100). We overlay a friendly message + "Open on YouTube" instead of YouTube's bare error.
|
||||
const [playerError, setPlayerError] = useState<number | null>(null);
|
||||
|
||||
const loadVideo = (id: string, start: number | null) => {
|
||||
const p = playerRef.current;
|
||||
if (!p || typeof p.loadVideoById !== "function") return;
|
||||
// Explicit start wins; otherwise resume the active item, start others at 0.
|
||||
const startSeconds = start != null ? start : id === active.id ? resumeAt : 0;
|
||||
setPlayerError(null);
|
||||
p.loadVideoById({ videoId: id, startSeconds: startSeconds || 0 });
|
||||
currentIdRef.current = id;
|
||||
setCurrentVideoId(id);
|
||||
|
|
@ -330,6 +335,7 @@ export default function PlayerModal({
|
|||
let cancelled = false;
|
||||
const id = active.id;
|
||||
autoMarkedRef.current = false;
|
||||
setPlayerError(null);
|
||||
|
||||
// Auto-watch only applies to the active item — not to other videos the player
|
||||
// navigated to via description links.
|
||||
|
|
@ -388,6 +394,9 @@ export default function PlayerModal({
|
|||
if (queue && index < queue.length - 1) setPlayingId(queue[index + 1].id);
|
||||
}
|
||||
},
|
||||
// The embed couldn't play this video (embedding disabled, removed, private…).
|
||||
// Surface our own message + an "Open on YouTube" escape hatch.
|
||||
onError: (e: any) => setPlayerError(typeof e?.data === "number" ? e.data : -1),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
@ -427,8 +436,32 @@ export default function PlayerModal({
|
|||
className="glass-card relative w-full max-w-4xl max-h-full overflow-y-auto rounded-2xl shadow-2xl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="aspect-video w-full bg-black rounded-t-2xl overflow-hidden">
|
||||
<div ref={mountRef} className="w-full h-full" />
|
||||
<div className="relative aspect-video w-full bg-black rounded-t-2xl overflow-hidden">
|
||||
{/* Hide the iframe entirely on error so YouTube's own error screen can't bleed
|
||||
through our overlay. */}
|
||||
<div ref={mountRef} className={`w-full h-full ${playerError != null ? "invisible" : ""}`} />
|
||||
{playerError != null && (
|
||||
<div className="absolute inset-0 grid place-items-center bg-bg p-6 text-center">
|
||||
<div className="max-w-sm">
|
||||
<AlertTriangle className="w-8 h-8 text-amber-500 mx-auto mb-3" />
|
||||
<h3 className="text-base font-semibold">{t("player.unavailableTitle")}</h3>
|
||||
<p className="text-sm text-muted mt-1.5 mb-4">
|
||||
{playerError === 101 || playerError === 150
|
||||
? t("player.embedDisabledBody")
|
||||
: t("player.unavailableBody")}
|
||||
</p>
|
||||
<a
|
||||
href={`https://www.youtube.com/watch?v=${currentVideoId}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex items-center justify-center gap-2 px-4 py-2 rounded-xl font-semibold bg-accent text-accent-fg hover:opacity-90 transition"
|
||||
>
|
||||
<ExternalLink className="w-4 h-4" />
|
||||
{t("player.openOnYoutube")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasQueue && (
|
||||
|
|
|
|||
|
|
@ -15,5 +15,9 @@
|
|||
"markWatched": "Als angesehen markieren",
|
||||
"watchedUnmark": "Angesehen — zum Aufheben klicken",
|
||||
"jumpToTime": "Zu dieser Stelle springen",
|
||||
"playInApp": "Im integrierten Player abspielen"
|
||||
"playInApp": "Im integrierten Player abspielen",
|
||||
"unavailableTitle": "Hier nicht abspielbar",
|
||||
"unavailableBody": "Dieses Video ist nicht verfügbar — möglicherweise privat, entfernt oder regional gesperrt.",
|
||||
"embedDisabledBody": "Der Eigentümer hat die Wiedergabe auf anderen Seiten deaktiviert (häufig bei automatisch generierten „Topic“-Musiktiteln). Auf YouTube ist es weiterhin abspielbar.",
|
||||
"openOnYoutube": "Auf YouTube öffnen"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,5 +15,9 @@
|
|||
"markWatched": "Mark watched",
|
||||
"watchedUnmark": "Watched — click to unmark",
|
||||
"jumpToTime": "Jump to this time",
|
||||
"playInApp": "Play in the in-app player"
|
||||
"playInApp": "Play in the in-app player",
|
||||
"unavailableTitle": "Can't play this here",
|
||||
"unavailableBody": "This video isn't available — it may be private, removed, or region-restricted.",
|
||||
"embedDisabledBody": "The owner disabled playback on other sites (common for auto-generated “Topic” music tracks). It still plays on YouTube.",
|
||||
"openOnYoutube": "Open on YouTube"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,5 +15,9 @@
|
|||
"markWatched": "Megtekintettnek jelöl",
|
||||
"watchedUnmark": "Megtekintve — kattints a jelölés visszavonásához",
|
||||
"jumpToTime": "Ugrás erre az időpontra",
|
||||
"playInApp": "Lejátszás a beépített lejátszóban"
|
||||
"playInApp": "Lejátszás a beépített lejátszóban",
|
||||
"unavailableTitle": "Ez itt nem játszható le",
|
||||
"unavailableBody": "Ez a videó nem elérhető — lehet privát, eltávolított vagy régiókorlátozott.",
|
||||
"embedDisabledBody": "A tulajdonos letiltotta a lejátszást más oldalakon (gyakori az auto-generált „Topic” zenei sávoknál). A YouTube-on viszont lejátszható.",
|
||||
"openOnYoutube": "Megnyitás YouTube-on"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@ export interface ReleaseEntry {
|
|||
}
|
||||
|
||||
export const RELEASE_NOTES: ReleaseEntry[] = [
|
||||
{
|
||||
version: "0.5.1",
|
||||
date: "2026-06-16",
|
||||
summary: "A clearer message when a video can't play in the in-app player.",
|
||||
fixes: [
|
||||
"When a video can't be played here — some music tracks and other videos have embedding disabled by their owner — the player now shows a clear note and an “Open on YouTube” button instead of a blank error screen.",
|
||||
],
|
||||
},
|
||||
{
|
||||
version: "0.5.0",
|
||||
date: "2026-06-16",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue