Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
},
Expand Down
13 changes: 11 additions & 2 deletions src/components/player/display/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,17 @@
}
}
} else {
hls.currentLevel = -1;
hls.loadLevel = -1;
// Good job fucking up auto qualities on non standarts so i have to make this fix

Check failure on line 170 in src/components/player/display/base.ts

View workflow job for this annotation

GitHub Actions / Run Linters

Delete `·`
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
Expand Down
21 changes: 1 addition & 20 deletions src/pages/migration/Migration.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -26,25 +26,6 @@ export function MigrationPage() {
{t("migration.start.explainer")}
</Paragraph>

<div className="w-full bg-pill-background bg-opacity-50 border border-white border-opacity-10 rounded-xl px-5 py-4 mb-6 flex gap-3 items-start">
<Icon
icon={Icons.CIRCLE_QUESTION}
className="text-type-dimmed text-lg mt-0.5 shrink-0"
/>
<p className="text-sm text-type-dimmed">
Need to export your data from the original P-Stream first?{" "}
<a
href="https://pstream-export-visualizer.vercel.app/"
target="_blank"
rel="noreferrer"
className="text-type-link underline hover:opacity-80 transition-opacity"
>
Use this tool to export your account data
</a>{" "}
before migrating.
</p>
</div>

<div className="w-full flex flex-col md:flex-row gap-3">
<Card
onClick={() => navigate("/migration/direct")}
Expand Down
37 changes: 35 additions & 2 deletions src/pages/parts/home/BookmarksPart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
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";
Expand Down Expand Up @@ -58,6 +60,7 @@
const saved = localStorage.getItem("__MW::bookmarksSort");
return (saved as SortOption) || "date";
});
const [runtimeData, setRuntimeData] = useState<Record<string, number>>({});
const [activeFolderModal, setActiveFolderModal] = useState<string | null>(
null,
);
Expand All @@ -74,6 +77,34 @@
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;

Check failure on line 88 in src/pages/parts/home/BookmarksPart.tsx

View workflow job for this annotation

GitHub Actions / Run Linters

Replace `·bookmarks[id].type·===·"movie"·?·TMDBContentTypes.MOVIE` with `⏎··········bookmarks[id].type·===·"movie"⏎············?·TMDBContentTypes.MOVIE⏎···········`
try {
const data = await getMediaDetails(id, type, false);
const value = type === TMDBContentTypes.MOVIE

Check failure on line 91 in src/pages/parts/home/BookmarksPart.tsx

View workflow job for this annotation

GitHub Actions / Run Linters

Insert `⏎···········`
? (data as any).runtime ?? 0

Check failure on line 92 in src/pages/parts/home/BookmarksPart.tsx

View workflow job for this annotation

GitHub Actions / Run Linters

Replace `?·(data·as·any).runtime·??·0` with `··?·((data·as·any).runtime·??·0)`
: (data as any).number_of_episodes ?? 0;

Check failure on line 93 in src/pages/parts/home/BookmarksPart.tsx

View workflow job for this annotation

GitHub Actions / Run Linters

Replace `:·(data·as·any).number_of_episodes·??·0` with `··:·((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<string, number>) => {
const next = { ...prev };
results.forEach(([id, val]) => { next[id] = val; });

Check failure on line 102 in src/pages/parts/home/BookmarksPart.tsx

View workflow job for this annotation

GitHub Actions / Run Linters

Replace `·next[id]·=·val;` with `⏎··········next[id]·=·val;⏎·······`
return next;
});
});
}, [sortBy, bookmarks, runtimeData]);

const { allGroups, rootMediaItems } = useMemo(() => {
const list = getList(bookmarks);

Expand Down Expand Up @@ -103,9 +134,9 @@

return {
allGroups: sortedGroups,
rootMediaItems: sortMedia(rootItems, sortBy, bookmarks, progressItems),
rootMediaItems: sortMedia(rootItems, sortBy, bookmarks, progressItems, runtimeData),

Check failure on line 137 in src/pages/parts/home/BookmarksPart.tsx

View workflow job for this annotation

GitHub Actions / Run Linters

Replace `rootItems,·sortBy,·bookmarks,·progressItems,·runtimeData` with `⏎········rootItems,⏎········sortBy,⏎········bookmarks,⏎········progressItems,⏎········runtimeData,⏎······`
};
}, [bookmarks, groupOrder, sortBy, progressItems]);
}, [bookmarks, groupOrder, sortBy, progressItems, runtimeData]);

useEffect(() => {
onItemsChange(Object.keys(bookmarks).length > 0);
Expand Down Expand Up @@ -163,6 +194,8 @@
{ 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 =
Expand Down
3 changes: 2 additions & 1 deletion src/pages/parts/home/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function sortMedia(
sortBy: SortOption,
bookmarks?: Record<string, BookmarkMediaItem>,
progressItems?: Record<string, ProgressMediaItem>,
runtimeData?: Record<string, number>,
): MediaItem[] {
return sortMediaItems(items, sortBy, bookmarks, progressItems);
return sortMediaItems(items, sortBy, bookmarks, progressItems, runtimeData);
}
38 changes: 35 additions & 3 deletions src/utils/mediaSorting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, BookmarkMediaItem>,
progressItems?: Record<string, ProgressMediaItem>,
runtimeData?: Record<string, number>,
): MediaItem[] {
const sorted = [...items];

Expand Down Expand Up @@ -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];
Expand All @@ -104,7 +136,7 @@ export function sortMediaItems(
progressB?.updatedAt ?? 0,
);

return dateB - dateA; // Newest first
return dateB - dateA;
});
break;
}
Expand Down
Loading