Skip to content

Commit

Permalink
linked captions + primary navigation dropdown
Browse files Browse the repository at this point in the history
Co-authored-by: Jip Frijlink <[email protected]>
  • Loading branch information
mrjvs and JipFr committed Nov 19, 2023
1 parent 9152ad7 commit fa990d1
Show file tree
Hide file tree
Showing 19 changed files with 359 additions and 325 deletions.
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dependencies": {
"@formkit/auto-animate": "^0.7.0",
"@headlessui/react": "^1.5.0",
"@movie-web/providers": "^1.0.5",
"@movie-web/providers": "^1.1.2",
"@noble/hashes": "^1.3.2",
"@react-spring/web": "^9.7.1",
"@scure/bip39": "^1.2.1",
Expand All @@ -18,7 +18,6 @@
"flag-icons": "^6.11.1",
"fscreen": "^1.2.0",
"fuse.js": "^6.4.6",
"graphql-request": "^6.1.0",
"hls.js": "^1.0.7",
"i18next": "^22.4.5",
"immer": "^10.0.2",
Expand All @@ -35,7 +34,6 @@
"react-use": "^17.4.0",
"slugify": "^1.6.6",
"subsrt-ts": "^2.1.1",
"unzipit": "^1.4.3",
"zustand": "^4.3.9"
},
"scripts": {
Expand Down
64 changes: 10 additions & 54 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

135 changes: 26 additions & 109 deletions src/backend/helpers/subs.ts
Original file line number Diff line number Diff line change
@@ -1,116 +1,33 @@
import { gql, request } from "graphql-request";
import { list } from "subsrt-ts";
import { unzip } from "unzipit";

import { proxiedFetch } from "@/backend/helpers/fetch";
import { languageMap } from "@/setup/iso6391";
import { PlayerMeta } from "@/stores/player/slices/source";
import { convertSubtitlesToSrt } from "@/components/player/utils/captions";
import { CaptionListItem } from "@/stores/player/slices/source";
import { SimpleCache } from "@/utils/cache";

const GQL_API = "https://gqlos.plus-sub.com";

const subtitleSearchQuery = gql`
query SubtitleSearch($tmdb_id: String!, $ep: Int, $season: Int) {
subtitleSearch(
tmdb_id: $tmdb_id
language: ""
episode_number: $ep
season_number: $season
) {
data {
attributes {
language
subtitle_id
ai_translated
auto_translation
ratings
votes
legacy_subtitle_id
}
id
}
}
export const subtitleTypeList = list().map((type) => `.${type}`);
const downloadCache = new SimpleCache<string, string>();
downloadCache.setCompare((a, b) => a === b);
const expirySeconds = 24 * 60 * 60;

/**
* Always returns SRT
*/
export async function downloadCaption(
caption: CaptionListItem
): Promise<string> {
const cached = downloadCache.get(caption.url);
if (cached) return cached;

let data: string | undefined;
if (caption.needsProxy) {
data = await proxiedFetch<string>(caption.url, { responseType: "text" });
} else {
data = await fetch(caption.url).then((v) => v.text());
}
`;

interface RawSubtitleSearchItem {
id: string;
attributes: {
language: string;
ai_translated: boolean | null;
auto_translation: null | boolean;
ratings: number;
votes: number | null;
legacy_subtitle_id: string | null;
};
}
if (!data) throw new Error("failed to get caption data");

export interface SubtitleSearchItem {
id: string;
attributes: {
language: string;
ai_translated: boolean | null;
auto_translation: null | boolean;
ratings: number;
votes: number | null;
legacy_subtitle_id: string;
};
const output = convertSubtitlesToSrt(data);
downloadCache.set(caption.url, output, expirySeconds);
return output;
}

interface SubtitleSearchData {
subtitleSearch: {
data: RawSubtitleSearchItem[];
};
}

export async function searchSubtitles(
meta: PlayerMeta
): Promise<SubtitleSearchItem[]> {
const data = await request<SubtitleSearchData>({
document: subtitleSearchQuery,
url: GQL_API,
variables: {
tmdb_id: meta.tmdbId,
ep: meta.episode?.number,
season: meta.season?.number,
},
});

const sortedByLanguage: Record<string, RawSubtitleSearchItem[]> = {};
data.subtitleSearch.data.forEach((v) => {
if (!sortedByLanguage[v.attributes.language])
sortedByLanguage[v.attributes.language] = [];
sortedByLanguage[v.attributes.language].push(v);
});

return Object.values(sortedByLanguage).map((langs) => {
const onlyLegacySubs = langs.filter(
(v): v is SubtitleSearchItem => !!v.attributes.legacy_subtitle_id
);
const sortedByRating = onlyLegacySubs.sort(
(a, b) =>
b.attributes.ratings * (b.attributes.votes ?? 0) -
a.attributes.ratings * (a.attributes.votes ?? 0)
);
return sortedByRating[0];
});
}

export async function downloadSrt(legacySubId: string): Promise<string> {
// TODO there is cloudflare protection so this may not always work. what to do about that?
// TODO also there is ratelimit on the page itself
// language code is hardcoded here, it does nothing
const zipFile = await proxiedFetch<ArrayBuffer>(
`https://dl.opensubtitles.org/en/subtitleserve/sub/${legacySubId}`,
{
responseType: "arrayBuffer",
}
);

const { entries } = await unzip(zipFile);
const srtEntry = Object.values(entries).find((v) => v.name);
if (!srtEntry) throw new Error("No srt file found in zip");
const srtData = srtEntry.text();
return srtData;
}

export const subtitleTypeList = list().map((type) => `.${type}`);
8 changes: 8 additions & 0 deletions src/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export enum Icons {
COPY = "copy",
USER = "user",
UP_DOWN_ARROW = "up_down_arrow",
RISING_STAR = "rising_star",
SETTINGS = "settings",
COINS = "coins",
LOGOUT = "logout",
}

export interface IconProps {
Expand Down Expand Up @@ -111,6 +115,10 @@ const iconList: Record<Icons, string> = {
copy: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-copy"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`,
user: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>`,
up_down_arrow: `<svg width="1em" height="1em" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4.53803 5.19018C4.50013 5.09883 4.49018 4.99829 4.50942 4.90128C4.52867 4.80427 4.57625 4.71514 4.64616 4.64518L7.64616 1.64518C7.69259 1.59869 7.74774 1.56181 7.80844 1.53665C7.86913 1.51149 7.9342 1.49854 7.99991 1.49854C8.06561 1.49854 8.13068 1.51149 8.19138 1.53665C8.25207 1.56181 8.30722 1.59869 8.35366 1.64518L11.3537 4.64518C11.4237 4.71511 11.4713 4.80423 11.4907 4.90128C11.51 4.99832 11.5001 5.09891 11.4622 5.19032C11.4243 5.28174 11.3602 5.35985 11.2779 5.41479C11.1956 5.46972 11.0989 5.49901 10.9999 5.49893H4.99991C4.90102 5.49891 4.80435 5.46956 4.72214 5.41461C4.63993 5.35965 4.57586 5.28155 4.53803 5.19018ZM10.9999 10.4989H4.99991C4.90096 10.4988 4.80421 10.5281 4.72191 10.5831C4.63962 10.638 4.57547 10.7161 4.53759 10.8075C4.49972 10.8989 4.48982 10.9995 4.50914 11.0966C4.52847 11.1936 4.57615 11.2828 4.64616 11.3527L7.64616 14.3527C7.69259 14.3992 7.74774 14.436 7.80844 14.4612C7.86913 14.4864 7.9342 14.4993 7.99991 14.4993C8.06561 14.4993 8.13068 14.4864 8.19138 14.4612C8.25207 14.436 8.30722 14.3992 8.35366 14.3527L11.3537 11.3527C11.4237 11.2828 11.4713 11.1936 11.4907 11.0966C11.51 10.9995 11.5001 10.8989 11.4622 10.8075C11.4243 10.7161 11.3602 10.638 11.2779 10.5831C11.1956 10.5281 11.0989 10.4988 10.9999 10.4989Z" fill="currentColor"/></svg>`,
rising_star: `<svg width="1em" height="1em" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.5509 6.91102L15.5716 8.59852L16.1643 11.1108C16.2061 11.2869 16.195 11.4714 16.1325 11.6412C16.0699 11.811 15.9587 11.9587 15.8127 12.0656C15.6651 12.174 15.4888 12.2365 15.3058 12.2453C15.1229 12.254 14.9414 12.2087 14.7841 12.1148L12.5341 10.7789L10.2841 12.1148C10.1268 12.2087 9.94528 12.254 9.76231 12.2453C9.57935 12.2365 9.40303 12.174 9.2554 12.0656C9.10948 11.9586 8.99833 11.811 8.9358 11.6412C8.87328 11.4713 8.86216 11.2869 8.90384 11.1108L9.49657 8.59852L7.51657 6.91102C7.37802 6.79275 7.27755 6.63613 7.22781 6.46088C7.17808 6.28563 7.1813 6.09959 7.23708 5.92617C7.29286 5.75275 7.39869 5.59971 7.54126 5.48631C7.68383 5.37291 7.85677 5.30423 8.03829 5.28891L10.656 5.06742L11.677 2.68734C11.749 2.52049 11.8683 2.37837 12.0202 2.27853C12.1721 2.17869 12.3499 2.12549 12.5316 2.12549C12.7134 2.12549 12.8911 2.17869 13.043 2.27853C13.1949 2.37837 13.3142 2.52049 13.3863 2.68734L14.4072 5.06883L17.0242 5.28891C17.2062 5.30319 17.3798 5.37111 17.5231 5.48409C17.6665 5.59707 17.7731 5.75002 17.8294 5.9236C17.8858 6.09718 17.8894 6.28358 17.8399 6.45922C17.7903 6.63486 17.6897 6.79185 17.5509 6.91031V6.91102ZM7.02298 9.03938C6.97074 8.98708 6.9087 8.94559 6.84041 8.91728C6.77213 8.88897 6.69893 8.8744 6.62501 8.8744C6.55109 8.8744 6.47789 8.88897 6.4096 8.91728C6.34132 8.94559 6.27928 8.98708 6.22704 9.03938L2.28954 12.9769C2.18399 13.0824 2.12469 13.2256 2.12469 13.3748C2.12469 13.5241 2.18399 13.6673 2.28954 13.7728C2.39509 13.8784 2.53824 13.9377 2.68751 13.9377C2.83677 13.9377 2.97993 13.8784 3.08548 13.7728L7.02298 9.83531C7.07528 9.78307 7.11677 9.72104 7.14507 9.65275C7.17338 9.58446 7.18795 9.51127 7.18795 9.43735C7.18795 9.36342 7.17338 9.29023 7.14507 9.22194C7.11677 9.15365 7.07528 9.09162 7.02298 9.03938ZM8.14798 12.9769C8.09574 12.9246 8.0337 12.8831 7.96541 12.8548C7.89713 12.8265 7.82393 12.8119 7.75001 12.8119C7.67609 12.8119 7.60289 12.8265 7.5346 12.8548C7.46632 12.8831 7.40428 12.9246 7.35204 12.9769L3.41454 16.9144C3.36228 16.9666 3.32082 17.0287 3.29254 17.097C3.26425 17.1652 3.24969 17.2384 3.24969 17.3123C3.24969 17.3863 3.26425 17.4594 3.29254 17.5277C3.32082 17.596 3.36228 17.6581 3.41454 17.7103C3.52009 17.8159 3.66324 17.8752 3.81251 17.8752C3.88642 17.8752 3.9596 17.8606 4.02789 17.8323C4.09617 17.804 4.15821 17.7626 4.21048 17.7103L8.14798 13.7728C8.20028 13.7206 8.24177 13.6585 8.27007 13.5902C8.29838 13.522 8.31295 13.4488 8.31295 13.3748C8.31295 13.3009 8.29838 13.2277 8.27007 13.1594C8.24177 13.0912 8.20028 13.0291 8.14798 12.9769ZM12.4152 12.9769L8.47774 16.9144C8.37219 17.0199 8.3129 17.1631 8.3129 17.3123C8.3129 17.4616 8.37219 17.6048 8.47774 17.7103C8.58329 17.8159 8.72644 17.8752 8.87571 17.8752C9.02498 17.8752 9.16813 17.8159 9.27368 17.7103L13.2112 13.7728C13.3167 13.6674 13.3761 13.5243 13.3761 13.3751C13.3762 13.2259 13.317 13.0828 13.2115 12.9772C13.1061 12.8717 12.963 12.8123 12.8138 12.8123C12.6646 12.8122 12.5215 12.8714 12.4159 12.9769H12.4152Z" fill="currentColor"/></svg>`,
settings: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`,
coins: `<svg width="1em" height="1em" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.8125 7.69742V7.21875C15.8125 5.06344 12.5615 3.4375 8.25 3.4375C3.93852 3.4375 0.6875 5.06344 0.6875 7.21875V10.6562C0.6875 12.4515 2.94336 13.878 6.1875 14.3052V14.7812C6.1875 16.9366 9.43852 18.5625 13.75 18.5625C18.0615 18.5625 21.3125 16.9366 21.3125 14.7812V11.3438C21.3125 9.56484 19.128 8.13656 15.8125 7.69742ZM4.8125 12.6216C3.12898 12.1516 2.0625 11.3773 2.0625 10.6562V9.44711C2.76375 9.94383 3.70305 10.3443 4.8125 10.6133V12.6216ZM11.6875 10.6133C12.797 10.3443 13.7362 9.94383 14.4375 9.44711V10.6562C14.4375 11.3773 13.371 12.1516 11.6875 12.6216V10.6133ZM10.3125 16.7466C8.62898 16.2766 7.5625 15.5023 7.5625 14.7812V14.4229C7.78852 14.4315 8.01711 14.4375 8.25 14.4375C8.58344 14.4375 8.90914 14.4263 9.22883 14.4074C9.58397 14.5346 9.94572 14.6424 10.3125 14.7305V16.7466ZM10.3125 12.9121C9.62964 13.013 8.94027 13.0633 8.25 13.0625C7.55973 13.0633 6.87036 13.013 6.1875 12.9121V10.8677C6.87137 10.9568 7.56035 11.001 8.25 11C8.93965 11.001 9.62863 10.9568 10.3125 10.8677V12.9121ZM15.8125 17.0371C14.4448 17.2376 13.0552 17.2376 11.6875 17.0371V14.9875C12.3712 15.0794 13.0602 15.1253 13.75 15.125C14.4397 15.126 15.1286 15.0818 15.8125 14.9927V17.0371ZM19.9375 14.7812C19.9375 15.5023 18.871 16.2766 17.1875 16.7466V14.7383C18.297 14.4693 19.2362 14.0688 19.9375 13.5721V14.7812Z" fill="currentColor"/></svg>`,
logout: `<svg style="transform: scaleX(-1);" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-out"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg>`,
};

function ChromeCastButton() {
Expand Down
Loading

0 comments on commit fa990d1

Please sign in to comment.