-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathparseAbsoluteLink.ts
More file actions
171 lines (153 loc) · 5.06 KB
/
parseAbsoluteLink.ts
File metadata and controls
171 lines (153 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/** Parse `LinkNode` of [@progfay/scrapbox-parser](https://jsr.io/@progfay/scrapbox-parser) in detail
*
* @module
*/
import type { LinkNode } from "@progfay/scrapbox-parser";
import { parseYoutube } from "./parser/youtube.ts";
import { parseVimeo } from "./parser/vimeo.ts";
import { parseSpotify } from "./parser/spotify.ts";
import { parseAnchorFM } from "./parser/anchor-fm.ts";
export type { LinkNode };
export interface AbsoluteLinkNode {
type: "absoluteLink";
content: string;
href: string;
raw: string;
}
/** YouTube Embed Node
* Represents a YouTube video embed with detailed information about the video
* and its URL parameters. Supports various YouTube URL formats including
* youtube.com, youtu.be, and YouTube Shorts.
*/
export interface YoutubeNode {
type: "youtube";
videoId: string;
pathType: "com" | "dotbe" | "short";
params: URLSearchParams;
href: string;
raw: string;
}
/** YouTube Playlist Embed Node
* Represents a YouTube playlist embed. This type is specifically for
* playlist URLs that contain a list parameter, allowing for embedding
* entire playlists rather than single videos.
*/
export interface YoutubeListNode {
type: "youtube";
listId: string;
pathType: "list";
params: URLSearchParams;
href: string;
raw: string;
}
/** Vimeo Embed Node
* Represents a Vimeo video embed. Extracts and stores the video ID
* from Vimeo URLs for proper embedding in Scrapbox pages.
*/
export interface VimeoNode {
type: "vimeo";
videoId: string;
href: string;
raw: string;
}
/** Spotify Embed Node
* Represents various types of Spotify content embeds including tracks,
* artists, playlists, albums, episodes, and shows. Supports all major
* Spotify content types for rich media integration.
*/
export interface SpotifyNode {
type: "spotify";
videoId: string;
pathType: "track" | "artist" | "playlist" | "album" | "episode" | "show";
href: string;
raw: string;
}
/** Anchor FM Embed Node
* Represents an Anchor FM podcast episode embed. Extracts the episode ID
* from Anchor FM URLs to enable podcast episode playback directly within
* Scrapbox pages.
*/
export interface AnchorFMNode {
type: "anchor-fm";
videoId: string;
href: string;
raw: string;
}
/** Generic Video Embed Node
* Represents a direct video file embed (mp4 or webm formats).
* Used for embedding video files that aren't from specific platforms
* like YouTube or Vimeo.
*/
export interface VideoNode {
type: "video";
href: VideoURL;
raw: string;
}
/** Generic Audio Embed Node
* Represents a direct audio file embed supporting common formats
* (mp3, ogg, wav, aac). Used for embedding audio content that
* isn't from specific platforms like Spotify.
*/
export interface AudioNode {
type: "audio";
content: string;
href: AudioURL;
raw: string;
}
/** Parse external link syntax from scrapbox-parser into specific embed types
*
* This function analyzes external links that were initially parsed by
* scrapbox-parser and categorizes them into specific embed types based on
* their URLs. It supports various media platforms and file types:
*
* - YouTube videos and playlists
* - Vimeo videos
* - Spotify content (tracks, artists, playlists, etc.)
* - Anchor FM podcast episodes
* - Direct video files (mp4, webm)
* - Direct audio files (mp3, ogg, wav, aac)
* - Regular absolute links (fallback)
*
* The function automatically detects the appropriate embed type and returns
* a strongly-typed object containing all necessary information for rendering
* the embed in Scrapbox.
*
* @param link - Link node object from scrapbox-parser with absolute path type
* @returns A {@linkcode ParsedLink} containing:
* - Success: Link object with specific embed type and metadata
* - Error: {@linkcode null} if parsing fails
*/
export const parseAbsoluteLink = (
link: LinkNode & { pathType: "absolute" },
):
| AbsoluteLinkNode
| VideoNode
| AudioNode
| YoutubeNode
| YoutubeListNode
| VimeoNode
| SpotifyNode
| AnchorFMNode => {
const { type: _, pathType: __, content, href, ...baseLink } = link;
if (content === "") {
const youtube = parseYoutube(href);
if (youtube) return { type: "youtube", href, ...youtube, ...baseLink };
const vimeoId = parseVimeo(href);
if (vimeoId) return { type: "vimeo", videoId: vimeoId, href, ...baseLink };
const spotify = parseSpotify(href);
if (spotify) return { type: "spotify", href, ...spotify, ...baseLink };
const anchorFMId = parseAnchorFM(href);
if (anchorFMId) {
return { type: "anchor-fm", videoId: anchorFMId, href, ...baseLink };
}
if (isVideoURL(href)) return { type: "video", href, ...baseLink };
}
if (isAudioURL(href)) return { type: "audio", content, href, ...baseLink };
return { type: "absoluteLink", content, href, ...baseLink };
};
export type AudioURL = `${string}.${"mp3" | "ogg" | "wav" | "acc"}`;
const isAudioURL = (url: string): url is AudioURL =>
/\.(?:mp3|ogg|wav|aac)$/.test(url);
export type VideoURL = `${string}.${"mp4" | "webm"}`;
const isVideoURL = (url: string): url is VideoURL =>
/\.(?:mp4|webm)$/.test(url);