diff --git a/apps/app/src/icons.ts b/apps/app/src/icons.ts index 6e4c1a27..54bfbd00 100644 --- a/apps/app/src/icons.ts +++ b/apps/app/src/icons.ts @@ -5,8 +5,9 @@ const icons: Record< Exclude, string | null > = { - [SupportedMediaHost.Bilibili]: ``, - [SupportedMediaHost.Vimeo]: ``, + [SupportedMediaHost.Bilibili]: ``, + [SupportedMediaHost.Vimeo]: ``, + [SupportedMediaHost.Coursera]: ``, [SupportedMediaHost.YouTube]: null, }; diff --git a/apps/app/src/web/plugin.ts b/apps/app/src/web/plugin.ts index 0cef26b3..e6f53f95 100644 --- a/apps/app/src/web/plugin.ts +++ b/apps/app/src/web/plugin.ts @@ -7,5 +7,6 @@ export const plugins = { bilibili: BilibiliPlugin, youtube: YouTubePlugin, vimeo: VimeoPlugin, + coursera: undefined, generic: undefined, } satisfies Record; diff --git a/apps/app/src/web/title.ts b/apps/app/src/web/title.ts index 13fb8b19..dd891fe4 100644 --- a/apps/app/src/web/title.ts +++ b/apps/app/src/web/title.ts @@ -8,4 +8,5 @@ export const titleParser: Record< bilibili: (title) => title.replace(/_哔哩哔哩_bilibili$/, ""), youtube: (title) => title.replace(/ - YouTube$/, ""), vimeo: (title) => title.replace(/ on Vimeo$/, ""), + coursera: (title) => title.replace(/ \| Coursera$/, ""), }; diff --git a/apps/app/src/web/url-match/coursera.ts b/apps/app/src/web/url-match/coursera.ts new file mode 100644 index 00000000..aaccb104 --- /dev/null +++ b/apps/app/src/web/url-match/coursera.ts @@ -0,0 +1,19 @@ +import { noHashUrl } from "@/lib/url"; +import type { URLResolver } from "./base"; +import { SupportedMediaHost } from "./supported"; + +export const courseraResolver: URLResolver = (url) => { + if (url.hostname !== "www.coursera.org") return null; + const cleaned = noHashUrl(url); + cleaned.search = ""; + + const source = new URL(url); + // const tempFrag = parseTempFrag(source.hash); + // addTempFrag(source, tempFrag); + + return { + type: SupportedMediaHost.Coursera, + cleaned, + source, + }; +}; diff --git a/apps/app/src/web/url-match/index.ts b/apps/app/src/web/url-match/index.ts index fcdce142..f5f813a6 100644 --- a/apps/app/src/web/url-match/index.ts +++ b/apps/app/src/web/url-match/index.ts @@ -5,6 +5,7 @@ import { checkMediaType, type MediaType } from "@/patch/media-type"; import type { MxSettings } from "@/settings/def"; import type { URLResolveResult } from "./base"; import { bilibiliResolver } from "./bilibili"; +import { courseraResolver } from "./coursera"; import { genericResolver } from "./generic"; import type { SupportedMediaHost } from "./supported"; import { viemoResolver } from "./viemo"; @@ -57,7 +58,12 @@ export function resolveUrl(url: URL): URLResolveResult { if (url.protocol !== "http:" && url.protocol !== "https:") { return genericResolver(url); } - for (const resolve of [bilibiliResolver, youtubeResolver, viemoResolver]) { + for (const resolve of [ + bilibiliResolver, + youtubeResolver, + viemoResolver, + courseraResolver, + ]) { const result = resolve(url); if (result) return result; } diff --git a/apps/app/src/web/url-match/supported.ts b/apps/app/src/web/url-match/supported.ts index 53966931..3105959f 100644 --- a/apps/app/src/web/url-match/supported.ts +++ b/apps/app/src/web/url-match/supported.ts @@ -6,6 +6,7 @@ export const enum SupportedMediaHost { Bilibili = "bilibili", YouTube = "youtube", Vimeo = "vimeo", + Coursera = "coursera", Generic = "generic", } @@ -18,6 +19,7 @@ export const mediaHostUrl: Record = { [SupportedMediaHost.Bilibili]: "https://www.bilibili.com", [SupportedMediaHost.YouTube]: "https://www.youtube.com", [SupportedMediaHost.Vimeo]: "https://www.viemo.com", + [SupportedMediaHost.Coursera]: "https://www.coursera.org", }; export const mediaHostDisplayName: Record = { @@ -25,6 +27,7 @@ export const mediaHostDisplayName: Record = { [SupportedMediaHost.YouTube]: "YouTube", [SupportedMediaHost.Generic]: "Website", [SupportedMediaHost.Vimeo]: "Viemo", + [SupportedMediaHost.Coursera]: "Coursera", }; export const noGeneric = (labels: Record) => diff --git a/apps/app/src/web/url-match/view-type.ts b/apps/app/src/web/url-match/view-type.ts index 1098b0a5..30e4b037 100644 --- a/apps/app/src/web/url-match/view-type.ts +++ b/apps/app/src/web/url-match/view-type.ts @@ -39,6 +39,7 @@ export function getSupportedViewType(url: MediaInfo): MediaViewType[] { case SupportedMediaHost.Vimeo: return [MEDIA_WEBPAGE_VIEW_TYPE, MEDIA_EMBED_VIEW_TYPE]; case SupportedMediaHost.Bilibili: + case SupportedMediaHost.Coursera: return [MEDIA_WEBPAGE_VIEW_TYPE]; default: assertNever(url.type);