diff --git a/src/components/modals/add-source-form.tsx b/src/components/modals/add-source-form.tsx index 2bfe104..1e8dd3b 100644 --- a/src/components/modals/add-source-form.tsx +++ b/src/components/modals/add-source-form.tsx @@ -29,6 +29,7 @@ const CONTENT_TYPE_BY_SOURCE: Partial> = { [SOURCE_TYPES.YOUTUBE_SHORT]: "audio_video", [SOURCE_TYPES.WEB_PAGE]: "webpage", [SOURCE_TYPES.DOCUMENT]: "document", + [SOURCE_TYPES.ARXIV_PAPER]: "arxiv_paper", } const IN_PROGRESS_STATUSES = ["in_progress", "running", "pending"] diff --git a/src/lib/__tests__/source-detection.test.ts b/src/lib/__tests__/source-detection.test.ts index df3a0ef..44e87a8 100644 --- a/src/lib/__tests__/source-detection.test.ts +++ b/src/lib/__tests__/source-detection.test.ts @@ -105,4 +105,22 @@ describe("detectSourceType", () => { }) }) }) + + describe("arXiv Paper URLs", () => { + it("detects arxiv.org/abs/ as ARXIV_PAPER", async () => { + expect(await detectSourceType("https://arxiv.org/abs/2301.00001")).toBe(SOURCE_TYPES.ARXIV_PAPER) + }) + + it("detects arxiv.org/pdf/ as ARXIV_PAPER", async () => { + expect(await detectSourceType("https://arxiv.org/pdf/2301.00001")).toBe(SOURCE_TYPES.ARXIV_PAPER) + }) + + it("detects arxiv.org/abs/ with http as ARXIV_PAPER", async () => { + expect(await detectSourceType("http://arxiv.org/abs/2301.00001")).toBe(SOURCE_TYPES.ARXIV_PAPER) + }) + + it("does NOT detect a non-arXiv HTTPS URL as ARXIV_PAPER (regression guard)", async () => { + expect(await detectSourceType("https://example.com/paper")).toBe(SOURCE_TYPES.WEB_PAGE) + }) + }) }) diff --git a/src/lib/source-detection.ts b/src/lib/source-detection.ts index c069c36..4d66cf6 100644 --- a/src/lib/source-detection.ts +++ b/src/lib/source-detection.ts @@ -10,6 +10,7 @@ export const SOURCE_TYPES = { WEB_PAGE: "web_page", DOCUMENT: "document", LINK: "link", + ARXIV_PAPER: "arxiv_paper", } as const export type SourceType = (typeof SOURCE_TYPES)[keyof typeof SOURCE_TYPES] @@ -36,6 +37,7 @@ const rssRegex = const youtubeChannelPattern = /https?:\/\/(www\.)?youtube\.com\/(user\/)?(@)?([\w-]+)/ const githubRepoPattern = /https:\/\/github\.com\/[\w-]+\/[\w-]+/ +const arxivPattern = /https?:\/\/arxiv\.org\/(abs|pdf)\/[\d.]+/ const genericUrlRegex = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/ async function checkIfRSS(url: string): Promise { @@ -71,6 +73,7 @@ export async function detectSourceType(source: string): Promise { if (twitterHandlePattern.test(source)) return SOURCE_TYPES.TWITTER_HANDLE if (rssRegex.test(source)) return SOURCE_TYPES.RSS if (githubRepoPattern.test(source)) return SOURCE_TYPES.GITHUB_REPOSITORY + if (arxivPattern.test(source)) return SOURCE_TYPES.ARXIV_PAPER if (genericUrlRegex.test(source)) { const isRSS = await checkIfRSS(source) @@ -105,6 +108,7 @@ export const SOURCE_TYPE_LABELS: Record = { [SOURCE_TYPES.WEB_PAGE]: "Web Page", [SOURCE_TYPES.DOCUMENT]: "Document", [SOURCE_TYPES.LINK]: "Link", + [SOURCE_TYPES.ARXIV_PAPER]: "arXiv Paper", } const SUBSCRIPTION_TYPES: string[] = [