diff --git a/apps/web/src/components/home-recommendations-section.tsx b/apps/web/src/components/home-recommendations-section.tsx
index 40a5697..36a9874 100644
--- a/apps/web/src/components/home-recommendations-section.tsx
+++ b/apps/web/src/components/home-recommendations-section.tsx
@@ -1,6 +1,7 @@
import { useBlockedFilter } from "../hooks/use-blocked-filter";
import { useHomeRecommendations } from "../hooks/use-home-recommendations";
import { trackRecommendationEvent } from "../lib/recommendation-tracker";
+import { HomeFallbackSection } from "./home-fallback-section";
import { ScrollSentinel } from "./scroll-sentinel";
import { VideoCardSkeleton } from "./video-card-skeleton";
import { VideoGrid } from "./video-grid";
@@ -18,12 +19,21 @@ function SkeletonGrid() {
}
export function HomeRecommendationsSection() {
- const { streams, serviceId, intent, isLoading, hasNextPage, isFetchingNextPage, fetchNextPage } =
- useHomeRecommendations();
+ const {
+ streams,
+ serviceId,
+ intent,
+ isLoading,
+ isError,
+ hasNextPage,
+ isFetchingNextPage,
+ fetchNextPage,
+ } = useHomeRecommendations();
const { filter } = useBlockedFilter();
const filtered = filter(streams);
if (isLoading) return ;
+ if (isError || filtered.length === 0) return ;
return (
<>
{
@@ -30,20 +28,16 @@ export function VideoPreview({ stream, show }: Props) {
}
hls = nextHls;
});
- } else if (src.type === "application/dash+xml") {
- void loadDash(video, src.url).then((player) => {
- if (disposed) {
- player?.destroy();
- return;
- }
- dash = player;
- });
+ } else {
+ video.src = src.url;
}
return () => {
disposed = true;
hls?.destroy();
- dash?.destroy();
+ video.pause();
+ video.removeAttribute("src");
+ video.load();
};
}, [show, stream]);
@@ -70,12 +64,7 @@ export function VideoPreview({ stream, show }: Props) {
);
}
-type PreviewSrc = { url: string; type: "application/x-mpegurl" | "application/dash+xml" } | null;
-
-function isFirefoxBrowser(): boolean {
- if (typeof navigator === "undefined") return false;
- return navigator.userAgent.includes("Firefox/");
-}
+type PreviewSrc = { url: string; type: "application/x-mpegurl" | "video/mp4" } | null;
function resolvePreviewSrc(stream: VideoStream): PreviewSrc {
if (typeof window !== "undefined" && window.matchMedia("(hover: none)").matches) {
@@ -90,33 +79,14 @@ function resolvePreviewSrc(stream: VideoStream): PreviewSrc {
};
}
- if (stream.videoOnlyStreams?.length && stream.audioStreams?.length) {
- const manifest = buildDashManifest(
- stream.videoOnlyStreams,
- stream.audioStreams,
- stream.duration,
- 480,
- );
- if (manifest) return { url: manifest, type: "application/dash+xml" };
- }
-
- if (isFirefoxBrowser()) {
- return {
- url: proxyDashManifest(`${API_BASE}/streams/manifest?url=${encodeURIComponent(stream.id)}`),
- type: "application/dash+xml",
- };
- }
-
- return {
- url: proxyDashManifest(
- `${API_BASE}/streams/native-manifest?url=${encodeURIComponent(stream.id)}`,
- ),
- type: "application/dash+xml",
- };
+ const progressive = [...(stream.videoStreams ?? [])]
+ .filter((candidate) => candidate.mimeType.includes("video/mp4"))
+ .sort((left, right) => (right.bitrate ?? 0) - (left.bitrate ?? 0))[0];
+ if (!progressive) return null;
+ return { url: proxyDashManifest(progressive.url), type: "video/mp4" };
}
type Hls = { destroy: () => void };
-type DashJs = { destroy: () => void };
async function loadHls(video: HTMLVideoElement, url: string): Promise {
if (!supportsNativeHls(video)) return null;
@@ -135,16 +105,3 @@ function supportsNativeHls(video: HTMLVideoElement): boolean {
const legacyType = video.canPlayType("application/x-mpegURL");
return appleType !== "" || legacyType !== "";
}
-
-async function loadDash(video: HTMLVideoElement, url: string): Promise {
- const dashjs = await import("dashjs");
- const player = dashjs.MediaPlayer().create();
- player.updateSettings({
- streaming: {
- buffer: { fastSwitchEnabled: true, bufferTimeAtTopQuality: 10 },
- abr: { initialBitrate: { video: 1000 }, maxBitrate: { video: 2000 } },
- },
- });
- player.initialize(video, url, false);
- return player;
-}
diff --git a/apps/web/src/hooks/use-home-recommendations.ts b/apps/web/src/hooks/use-home-recommendations.ts
index 67005ad..8601c48 100644
--- a/apps/web/src/hooks/use-home-recommendations.ts
+++ b/apps/web/src/hooks/use-home-recommendations.ts
@@ -12,6 +12,7 @@ type Result = {
serviceId: number;
intent: RecommendationIntent;
isLoading: boolean;
+ isError: boolean;
isFetchingNextPage: boolean;
hasNextPage: boolean;
fetchNextPage: () => void;
@@ -43,6 +44,7 @@ export function useHomeRecommendations(): Result {
serviceId: settings.defaultService,
intent,
isLoading: query.isLoading,
+ isError: query.isError,
isFetchingNextPage: query.isFetchingNextPage,
hasNextPage: query.hasNextPage,
fetchNextPage: query.fetchNextPage,