返回 slidev
timestring.ts
根目录 / packages / parser / src / timesplit / timestring.ts
1 /**
2 * Parse timestamp into seconds
3 *
4 * Accepts:
5 * - 10:50.1
6 * - 10s
7 * - 5m
8 * - 3min
9 * - 3mins 5secs
10 * - 10.5m3s
11 * - +10s
12 * - 1h10m30s
13 * - 1h4s
14 * - 1:1:1
15 */
16 const RE_ALPHA = /[a-z]/i
17
18 export function parseTimeString(timestamp: string | number): {
19 seconds: number
20 relative: boolean
21 } {
22 if (typeof timestamp === 'number') {
23 return {
24 seconds: timestamp,
25 relative: false,
26 }
27 }
28
29 const relative = timestamp.startsWith('+')
30 if (relative) {
31 timestamp = timestamp.slice(1)
32 }
33 let seconds = 0
34 if (timestamp.includes(':')) {
35 const parts = timestamp.split(':').map(Number)
36 let h = 0
37 let m = 0
38 let s = 0
39 if (parts.length === 3) {
40 h = parts[0]
41 m = parts[1]
42 s = parts[2]
43 }
44 else if (parts.length === 2) {
45 m = parts[0]
46 s = parts[1]
47 }
48 else if (parts.length === 1) {
49 s = parts[0]
50 }
51 else {
52 throw new TypeError('Invalid timestamp format')
53 }
54 if (Number.isNaN(h) || Number.isNaN(m) || Number.isNaN(s)) {
55 throw new TypeError('Invalid timestamp format')
56 }
57 seconds = (h || 0) * 3600 + (m || 0) * 60 + (s || 0)
58 }
59 else if (!RE_ALPHA.test(timestamp)) {
60 seconds = Number(timestamp)
61 }
62 else {
63 const unitMap: Record<string, number> = {
64 s: 1,
65 sec: 1,
66 secs: 1,
67 m: 60,
68 min: 60,
69 mins: 60,
70 h: 3600,
71 hr: 3600,
72 hrs: 3600,
73 hour: 3600,
74 hours: 3600,
75 day: 86400,
76 days: 86400,
77 week: 604800,
78 weeks: 604800,
79 month: 2629746,
80 months: 2629746,
81 year: 31556952,
82 years: 31556952,
83 }
84 const regex = /([\d.]+)([a-z]+)/gi
85 const matches = timestamp.matchAll(regex)
86 if (matches) {
87 for (const match of matches) {
88 const value = Number(match[1])
89 if (Number.isNaN(value)) {
90 throw new TypeError(`Invalid timestamp value: ${match[1]}`)
91 }
92 const unit = match[2].toLowerCase()
93 if (!(unit in unitMap)) {
94 throw new TypeError(`Invalid timestamp unit: ${unit}`)
95 }
96 seconds += value * unitMap[unit]
97 }
98 }
99 const remaining = timestamp.replace(regex, '').trim()
100 if (remaining) {
101 throw new TypeError(`Unknown timestamp remaining: ${remaining}`)
102 }
103 }
104
105 return {
106 seconds,
107 relative,
108 }
109 }
110
110 lines TYPESCRIPT