From ef739422522fb23bc294fec8b516c756f3dd1949 Mon Sep 17 00:00:00 2001 From: xanning Date: Wed, 20 May 2026 18:13:35 +0300 Subject: [PATCH 1/5] Fix my TS crying about deprecations --- tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 4ad34a790..4207ed89e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,8 @@ "../node_modules/@sozialhelden/ietf-language-tags/dist/cjs" ] }, - "typeRoots": ["node_modules/@types"] + "typeRoots": ["node_modules/@types"], + "ignoreDeprecations": "6.0" }, "include": ["src", "themes"] } From b312c6f7fb62f499261f00e2500dfb59ca5000d3 Mon Sep 17 00:00:00 2001 From: xanning Date: Wed, 20 May 2026 19:36:10 +0300 Subject: [PATCH 2/5] add ability to sort by length --- src/assets/locales/en.json | 4 ++- src/pages/parts/home/BookmarksPart.tsx | 37 +++++++++++++++++++++++-- src/pages/parts/home/utils.ts | 3 +- src/utils/mediaSorting.ts | 38 ++++++++++++++++++++++++-- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json index 14e3c1944..24ffbc8aa 100644 --- a/src/assets/locales/en.json +++ b/src/assets/locales/en.json @@ -377,7 +377,9 @@ "titleAsc": "Title A-Z", "titleDesc": "Title Z-A", "yearAsc": "Release Date Oldest-Newest", - "yearDesc": "Release Date Newest-Oldest" + "yearDesc": "Release Date Newest-Oldest", + "lengthAsc": "Length Shortest-Longest", + "lengthDesc": "Length Longest-Shortest" } } }, diff --git a/src/pages/parts/home/BookmarksPart.tsx b/src/pages/parts/home/BookmarksPart.tsx index 412b44714..a4ed8ddbc 100644 --- a/src/pages/parts/home/BookmarksPart.tsx +++ b/src/pages/parts/home/BookmarksPart.tsx @@ -10,6 +10,8 @@ import { Listbox } from "@headlessui/react"; import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; +import { getMediaDetails } from "@/backend/metadata/tmdb"; +import { TMDBContentTypes } from "@/backend/metadata/types/tmdb"; import { EditButton } from "@/components/buttons/EditButton"; import { Dropdown, OptionItem } from "@/components/form/Dropdown"; import { Icon, Icons } from "@/components/Icon"; @@ -58,6 +60,7 @@ export function BookmarksPart({ const saved = localStorage.getItem("__MW::bookmarksSort"); return (saved as SortOption) || "date"; }); + const [runtimeData, setRuntimeData] = useState>({}); const [activeFolderModal, setActiveFolderModal] = useState( null, ); @@ -74,6 +77,34 @@ export function BookmarksPart({ localStorage.setItem("__MW::bookmarksSort", sortBy); }, [sortBy]); + useEffect(() => { + if (sortBy !== "length-asc" && sortBy !== "length-desc") return; + const ids = Object.keys(bookmarks); + const missing = ids.filter((id) => !(id in runtimeData)); + if (missing.length === 0) return; + + Promise.all( + missing.map(async (id) => { + const type = bookmarks[id].type === "movie" ? TMDBContentTypes.MOVIE : TMDBContentTypes.TV; + try { + const data = await getMediaDetails(id, type, false); + const value = type === TMDBContentTypes.MOVIE + ? (data as any).runtime ?? 0 + : (data as any).number_of_episodes ?? 0; + return [id, value] as [string, number]; + } catch { + return [id, 0] as [string, number]; + } + }), + ).then((results) => { + setRuntimeData((prev: Record) => { + const next = { ...prev }; + results.forEach(([id, val]) => { next[id] = val; }); + return next; + }); + }); + }, [sortBy, bookmarks, runtimeData]); + const { allGroups, rootMediaItems } = useMemo(() => { const list = getList(bookmarks); @@ -103,9 +134,9 @@ export function BookmarksPart({ return { allGroups: sortedGroups, - rootMediaItems: sortMedia(rootItems, sortBy, bookmarks, progressItems), + rootMediaItems: sortMedia(rootItems, sortBy, bookmarks, progressItems, runtimeData), }; - }, [bookmarks, groupOrder, sortBy, progressItems]); + }, [bookmarks, groupOrder, sortBy, progressItems, runtimeData]); useEffect(() => { onItemsChange(Object.keys(bookmarks).length > 0); @@ -163,6 +194,8 @@ export function BookmarksPart({ { id: "title-desc", name: t("home.bookmarks.sorting.options.titleDesc") }, { id: "year-asc", name: t("home.bookmarks.sorting.options.yearAsc") }, { id: "year-desc", name: t("home.bookmarks.sorting.options.yearDesc") }, + { id: "length-asc", name: t("home.bookmarks.sorting.options.lengthAsc") }, + { id: "length-desc", name: t("home.bookmarks.sorting.options.lengthDesc") }, ]; const selectedSortOption = diff --git a/src/pages/parts/home/utils.ts b/src/pages/parts/home/utils.ts index 1ce49d067..6969b55ce 100644 --- a/src/pages/parts/home/utils.ts +++ b/src/pages/parts/home/utils.ts @@ -18,6 +18,7 @@ export function sortMedia( sortBy: SortOption, bookmarks?: Record, progressItems?: Record, + runtimeData?: Record, ): MediaItem[] { - return sortMediaItems(items, sortBy, bookmarks, progressItems); + return sortMediaItems(items, sortBy, bookmarks, progressItems, runtimeData); } diff --git a/src/utils/mediaSorting.ts b/src/utils/mediaSorting.ts index 441da491c..e3de79f96 100644 --- a/src/utils/mediaSorting.ts +++ b/src/utils/mediaSorting.ts @@ -7,13 +7,16 @@ export type SortOption = | "title-asc" | "title-desc" | "year-asc" - | "year-desc"; + | "year-desc" + | "length-asc" + | "length-desc"; export function sortMediaItems( items: MediaItem[], sortBy: SortOption, bookmarks?: Record, progressItems?: Record, + runtimeData?: Record, ): MediaItem[] { const sorted = [...items]; @@ -87,8 +90,37 @@ export function sortMediaItems( break; } + case "length-asc": { + const movies = sorted.filter((i) => i.type === "movie"); + const shows = sorted.filter((i) => i.type === "show"); + const byLen = (a: MediaItem, b: MediaItem) => { + const lenA = runtimeData?.[a.id] ?? Number.MAX_SAFE_INTEGER; + const lenB = runtimeData?.[b.id] ?? Number.MAX_SAFE_INTEGER; + if (lenA === lenB) return (a.title ?? "").localeCompare(b.title ?? ""); + return lenA - lenB; + }; + movies.sort(byLen); + shows.sort(byLen); + sorted.splice(0, sorted.length, ...movies, ...shows); + break; + } + + case "length-desc": { + const movies = sorted.filter((i) => i.type === "movie"); + const shows = sorted.filter((i) => i.type === "show"); + const byLen = (a: MediaItem, b: MediaItem) => { + const lenA = runtimeData?.[a.id] ?? -1; + const lenB = runtimeData?.[b.id] ?? -1; + if (lenA === lenB) return (a.title ?? "").localeCompare(b.title ?? ""); + return lenB - lenA; + }; + movies.sort(byLen); + shows.sort(byLen); + sorted.splice(0, sorted.length, ...movies, ...shows); + break; + } + default: { - // Fallback to date sorting for unknown sort options sorted.sort((a, b) => { const bookmarkA = bookmarks?.[a.id]; const bookmarkB = bookmarks?.[b.id]; @@ -104,7 +136,7 @@ export function sortMediaItems( progressB?.updatedAt ?? 0, ); - return dateB - dateA; // Newest first + return dateB - dateA; }); break; } From e2760f8b3d9b32412d1ef5be9a97f9ecadd01f43 Mon Sep 17 00:00:00 2001 From: xanning Date: Wed, 20 May 2026 19:39:08 +0300 Subject: [PATCH 3/5] Revert "Fix my TS crying about deprecations" This reverts commit ef739422522fb23bc294fec8b516c756f3dd1949. --- tsconfig.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 4207ed89e..4ad34a790 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,8 +23,7 @@ "../node_modules/@sozialhelden/ietf-language-tags/dist/cjs" ] }, - "typeRoots": ["node_modules/@types"], - "ignoreDeprecations": "6.0" + "typeRoots": ["node_modules/@types"] }, "include": ["src", "themes"] } From 3b919b579b5cf0bb19fafd5ff2336b481ee8c1d3 Mon Sep 17 00:00:00 2001 From: xanning Date: Wed, 20 May 2026 21:44:20 +0300 Subject: [PATCH 4/5] remove notice of exporting data from original ps --- src/pages/migration/Migration.tsx | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/pages/migration/Migration.tsx b/src/pages/migration/Migration.tsx index a8e4c3155..bd66622d8 100644 --- a/src/pages/migration/Migration.tsx +++ b/src/pages/migration/Migration.tsx @@ -1,7 +1,7 @@ import { Trans, useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; -import { Icon, Icons } from "@/components/Icon"; +import { Icons } from "@/components/Icon"; import { Stepper } from "@/components/layout/Stepper"; import { BiggerCenterContainer } from "@/components/layout/ThinContainer"; import { VerticalLine } from "@/components/layout/VerticalLine"; @@ -26,25 +26,6 @@ export function MigrationPage() { {t("migration.start.explainer")} -
- -

- Need to export your data from the original P-Stream first?{" "} - - Use this tool to export your account data - {" "} - before migrating. -

-
-
navigate("/migration/direct")} From 89aaf62031145fa6485958958ac2adb3dc1438c3 Mon Sep 17 00:00:00 2001 From: xanning Date: Fri, 22 May 2026 18:42:35 +0300 Subject: [PATCH 5/5] auto quality fix --- src/components/player/display/base.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts index 3593f22b1..cc4de6b3d 100644 --- a/src/components/player/display/base.ts +++ b/src/components/player/display/base.ts @@ -167,8 +167,17 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { } } } else { - hls.currentLevel = -1; - hls.loadLevel = -1; + // Good job fucking up auto qualities on non standarts so i have to make this fix + const sortedLevels = sortLevelsByQuality(hls.levels); + const topLevel = sortedLevels[0]; + const topIndex = topLevel ? hls.levels.indexOf(topLevel) : -1; + if (topIndex !== -1) { + hls.startLevel = topIndex; + hls.nextLevel = topIndex; + } else { + hls.currentLevel = -1; + hls.loadLevel = -1; + } } // For manual quality selection, wait for LEVEL_SWITCHED to emit quality // to avoid showing intermediate states when HLS switches away from unplayable levels