@banou/media-player 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/build/chrome/bottom.d.ts +20 -0
- package/build/chrome/index.d.ts +26 -0
- package/build/chrome/overlay.d.ts +9 -0
- package/build/index.d.ts +48 -0
- package/build/index.js +2725 -0
- package/build/languages.d.ts +260 -0
- package/build/main.d.ts +1 -0
- package/build/mp4box.d.ts +61 -0
- package/build/use-local-storage.d.ts +6 -0
- package/build/use-scrub.d.ts +10 -0
- package/build/utils.d.ts +13 -0
- package/package.json +49 -0
- package/src/chrome/bottom.tsx +651 -0
- package/src/chrome/index.tsx +197 -0
- package/src/chrome/overlay.tsx +104 -0
- package/src/index.tsx +597 -0
- package/src/languages.ts +262 -0
- package/src/main.tsx +187 -0
- package/src/mp4box.ts +74 -0
- package/src/use-local-storage.ts +32 -0
- package/src/use-scrub.ts +39 -0
- package/src/utils.ts +385 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +26 -0
- package/tsconfig.node.json +9 -0
package/src/languages.ts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
type Language = {
|
|
2
|
+
tag: string
|
|
3
|
+
name: string
|
|
4
|
+
originalName: string
|
|
5
|
+
locale: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const languages: Language[] = JSON.parse(`[{"tag":"zu","name":"isiZulu","originalName":"isiZulu","locale":"zu-ZA"},{"tag":"zh","name":"Chinese","originalName":"中文","locale":"zh-CHS"},{"tag":"yo","name":"Yoruba","originalName":"Yoruba","locale":"yo-NG"},{"tag":"xh","name":"isiXhosa","originalName":"isiXhosa","locale":"xh-ZA"},{"tag":"wo","name":"Wolof","originalName":"Wolof","locale":"wo-SN"},{"tag":"vi","name":"Vietnamese","originalName":"Tiếng Việt","locale":"vi"},{"tag":"uz","name":"Uzbek","originalName":"U'zbek","locale":"uz"},{"tag":"ur","name":"Urdu","originalName":"اُردو","locale":"ur"},{"tag":"uk","name":"Ukrainian","originalName":"україньска","locale":"uk"},{"tag":"ug","name":"Uyghur","originalName":"ئۇيغۇرچە","locale":"ug-CN"},{"tag":"tzm","name":"Tamazight","originalName":"Tamazight","locale":"tzm-Latn-DZ"},{"tag":"tt","name":"Tatar","originalName":"Татар","locale":"tt"},{"tag":"tr","name":"Turkish","originalName":"Türkçe","locale":"tr"},{"tag":"tn","name":"Setswana","originalName":"Setswana","locale":"tn-ZA"},{"tag":"tk","name":"Turkmen","originalName":"türkmençe","locale":"tk-TM"},{"tag":"th","name":"Thai","originalName":"ไทย","locale":"th"},{"tag":"tg","name":"Tajik","originalName":"Тоҷикӣ","locale":"tg-Cyrl-TJ"},{"tag":"te","name":"Telugu","originalName":"తెలుగు","locale":"te"},{"tag":"ta","name":"Tamil","originalName":"தமிழ்","locale":"ta"},{"tag":"syr","name":"Syriac","originalName":"ܣܘܪܝܝܐ","locale":"syr"},{"tag":"sw","name":"Kiswahili","originalName":"Kiswahili","locale":"sw"},{"tag":"sv","name":"Swedish","originalName":"svenska","locale":"sv"},{"tag":"sr","name":"Serbian","originalName":"srpski","locale":"sr"},{"tag":"sq","name":"Albanian","originalName":"shqipe","locale":"sq"},{"tag":"sms","name":"Sami","originalName":"sääm´ǩiõll","locale":"sms-FI"},{"tag":"smn","name":"Sami","originalName":"sämikielâ","locale":"smn-FI"},{"tag":"smj","name":"Sami","originalName":"julevusámegiella","locale":"smj-NO"},{"tag":"sma","name":"Sami","originalName":"åarjelsaemiengiele","locale":"sma-NO"},{"tag":"sl","name":"Slovenian","originalName":"slovenski","locale":"sl"},{"tag":"sk","name":"Slovak","originalName":"slovenčina","locale":"sk"},{"tag":"si","name":"Sinhala","originalName":"සිංහ","locale":"si-LK"},{"tag":"se","name":"Sami","originalName":"davvisámegiella","locale":"se-FI"},{"tag":"sah","name":"Yakut","originalName":"саха","locale":"sah-RU"},{"tag":"sa","name":"Sanskrit","originalName":"संस्कृत","locale":"sa"},{"tag":"rw","name":"Kinyarwanda","originalName":"Kinyarwanda","locale":"rw-RW"},{"tag":"ru","name":"Russian","originalName":"русский","locale":"ru"},{"tag":"ro","name":"Romanian","originalName":"română","locale":"ro"},{"tag":"rm","name":"Romansh","originalName":"Rumantsch","locale":"rm-CH"},{"tag":"quz","name":"Quechua","originalName":"runasimi","locale":"quz-BO"},{"tag":"qut","name":"K'iche","originalName":"K'iche","locale":"qut-GT"},{"tag":"pt","name":"Portuguese","originalName":"Português","locale":"pt"},{"tag":"ps","name":"Pashto","originalName":"پښتو","locale":"ps-AF"},{"tag":"prs","name":"Dari","originalName":"درى","locale":"prs-AF"},{"tag":"pl","name":"Polish","originalName":"polski","locale":"pl"},{"tag":"pa","name":"Punjabi","originalName":"ਪੰਜਾਬੀ","locale":"pa"},{"tag":"or","name":"Oriya","originalName":"ଓଡ଼ିଆ","locale":"or-IN"},{"tag":"oc","name":"Occitan","originalName":"Occitan","locale":"oc-FR"},{"tag":"nso","name":"Sesotho sa Leboa","originalName":"Sesotho sa Leboa","locale":"nso-ZA"},{"tag":"no","name":"Norwegian","originalName":"norsk","locale":"no"},{"tag":"nn","name":"Norwegian, Nynorsk","originalName":"norsk, nynorsk","locale":"nn-NO"},{"tag":"nl","name":"Dutch","originalName":"Nederlands","locale":"nl"},{"tag":"ne","name":"Nepali","originalName":"नेपाली","locale":"ne-NP"},{"tag":"nb","name":"Norwegian, Bokmål","originalName":"norsk, bokmål","locale":"nb-NO"},{"tag":"mt","name":"Maltese","originalName":"Malti","locale":"mt-MT"},{"tag":"ms","name":"Malay","originalName":"Bahasa Malaysia","locale":"ms"},{"tag":"mr","name":"Marathi","originalName":"मराठी","locale":"mr"},{"tag":"moh","name":"Mohawk","originalName":"Kanien'kéha","locale":"moh-CA"},{"tag":"mn","name":"Mongolian","originalName":"Монгол хэл","locale":"mn"},{"tag":"ml","name":"Malayalam","originalName":"മലയാളം","locale":"ml-IN"},{"tag":"mk","name":"Macedonian","originalName":"македонски јазик","locale":"mk"},{"tag":"mi","name":"Maori","originalName":"Reo Māori","locale":"mi-NZ"},{"tag":"lv","name":"Latvian","originalName":"latviešu","locale":"lv"},{"tag":"lt","name":"Lithuanian","originalName":"lietuvių","locale":"lt"},{"tag":"lo","name":"Lao","originalName":"ລາວ","locale":"lo-LA"},{"tag":"lb","name":"Luxembourgish","originalName":"Lëtzebuergesch","locale":"lb-LU"},{"tag":"ky","name":"Kyrgyz","originalName":"Кыргыз","locale":"ky"},{"tag":"kok","name":"Konkani","originalName":"कोंकणी","locale":"kok"},{"tag":"ko","name":"Korean","originalName":"한국어","locale":"ko"},{"tag":"kn","name":"Kannada","originalName":"ಕನ್ನಡ","locale":"kn"},{"tag":"km","name":"Khmer","originalName":"ខ្មែរ","locale":"km-KH"},{"tag":"kl","name":"Greenlandic","originalName":"kalaallisut","locale":"kl-GL"},{"tag":"kk","name":"Kazakh","originalName":"Қазащb","locale":"kk"},{"tag":"ka","name":"Georgian","originalName":"ქართული","locale":"ka"},{"tag":"ja","name":"Japanese","originalName":"日本語","locale":"ja"},{"tag":"iu","name":"Inuktitut","originalName":"ᐃᓄᒃᑎᑐᑦ","locale":"iu-Cans-CA"},{"tag":"it","name":"Italian","originalName":"italiano","locale":"it"},{"tag":"is","name":"Icelandic","originalName":"íslenska","locale":"is"},{"tag":"ii","name":"Yi","originalName":"ꆈꌠꁱꂷ","locale":"ii-CN"},{"tag":"ig","name":"Igbo","originalName":"Igbo","locale":"ig-NG"},{"tag":"id","name":"Indonesian","originalName":"Bahasa Indonesia","locale":"id"},{"tag":"hy","name":"Armenian","originalName":"Հայերեն","locale":"hy"},{"tag":"hu","name":"Hungarian","originalName":"magyar","locale":"hu"},{"tag":"hsb","name":"Upper Sorbian","originalName":"hornjoserbšćina","locale":"hsb-DE"},{"tag":"hr","name":"Croatian","originalName":"hrvatski","locale":"hr"},{"tag":"hi","name":"Hindi","originalName":"हिंदी","locale":"hi"},{"tag":"he","name":"Hebrew","originalName":"עברית","locale":"he"},{"tag":"ha","name":"Hausa","originalName":"Hausa","locale":"ha-Latn-NG"},{"tag":"gu","name":"Gujarati","originalName":"ગુજરાતી","locale":"gu"},{"tag":"gsw","name":"Alsatian","originalName":"Elsässisch","locale":"gsw-FR"},{"tag":"gl","name":"Galician","originalName":"galego","locale":"gl"},{"tag":"gd","name":"Scottish Gaelic","originalName":"Gàidhlig","locale":"gd-GB"},{"tag":"ga","name":"Irish","originalName":"Gaeilge","locale":"ga-IE"},{"tag":"fy","name":"Frisian","originalName":"Frysk","locale":"fy-NL"},{"tag":"fr","name":"French","originalName":"français","locale":"fr"},{"tag":"fo","name":"Faroese","originalName":"føroyskt","locale":"fo"},{"tag":"fil","name":"Filipino","originalName":"Filipino","locale":"fil-PH"},{"tag":"fi","name":"Finnish","originalName":"suomi","locale":"fi"},{"tag":"fa","name":"Persian","originalName":"فارسى","locale":"fa"},{"tag":"eu","name":"Basque","originalName":"euskara","locale":"eu"},{"tag":"et","name":"Estonian","originalName":"eesti","locale":"et"},{"tag":"es","name":"Spanish","originalName":"español","locale":"es"},{"tag":"en","name":"English","originalName":"English","locale":"en"},{"tag":"el","name":"Greek","originalName":"ελληνικά","locale":"el"},{"tag":"dv","name":"Divehi","originalName":"ދިވެހިބަސް","locale":"dv"},{"tag":"dsb","name":"Lower Sorbian","originalName":"dolnoserbšćina","locale":"dsb-DE"},{"tag":"de","name":"German","originalName":"Deutsch","locale":"de"},{"tag":"da","name":"Danish","originalName":"dansk","locale":"da"},{"tag":"cy","name":"Welsh","originalName":"Cymraeg","locale":"cy-GB"},{"tag":"cs","name":"Czech","originalName":"čeština","locale":"cs"},{"tag":"co","name":"Corsican","originalName":"Corsu","locale":"co-FR"},{"tag":"ca","name":"Catalan","originalName":"català","locale":"ca"},{"tag":"bs","name":"Bosnian","originalName":"босански","locale":"bs-Cyrl-BA"},{"tag":"br","name":"Breton","originalName":"brezhoneg","locale":"br-FR"},{"tag":"bo","name":"Tibetan","originalName":"བོད་ཡིག","locale":"bo-CN"},{"tag":"bn","name":"Bengali","originalName":"বাংলা","locale":"bn-BD"},{"tag":"bg","name":"Bulgarian","originalName":"български","locale":"bg"},{"tag":"be","name":"Belarusian","originalName":"Беларускі","locale":"be"},{"tag":"ba","name":"Bashkir","originalName":"Башҡорт","locale":"ba-RU"},{"tag":"az","name":"Azeri","originalName":"Azərbaycanılı","locale":"az"},{"tag":"as","name":"Assamese","originalName":"অসমীয়া","locale":"as-IN"},{"tag":"arn","name":"Mapudungun","originalName":"Mapudungun","locale":"arn-CL"},{"tag":"ar","name":"Arabic","originalName":"العربية","locale":"ar"},{"tag":"am","name":"Amharic","originalName":"አማርኛ","locale":"am-ET"},{"tag":"af","name":"Afrikaans","originalName":"Afrikaans","locale":"af"},{"tag":"iv","name":"Invariant Language","originalName":"Invariant Language","locale":""},{"tag":"Two letter","name":"English","originalName":"Native","locale":"Culture .NET"}]`)
|
|
9
|
+
|
|
10
|
+
export const languageToTag = (lang: string) => languages.find(language => language.name === lang)?.tag
|
|
11
|
+
export const tagToLanguage = (langTag: string) => languages.find(language => language.tag === langTag)?.name
|
|
12
|
+
|
|
13
|
+
export enum LanguageTag {
|
|
14
|
+
/** isiZulu */
|
|
15
|
+
ZU = 'zu',// "isiZulu",
|
|
16
|
+
/** Chinese */
|
|
17
|
+
ZH = 'zh',// "Chinese",
|
|
18
|
+
/** Yoruba */
|
|
19
|
+
YO = 'yo',// "Yoruba",
|
|
20
|
+
/** isiXhosa */
|
|
21
|
+
XH = 'xh',// "isiXhosa",
|
|
22
|
+
/** Wolof */
|
|
23
|
+
WO = 'wo',// "Wolof",
|
|
24
|
+
/** Vietnamese */
|
|
25
|
+
VI = 'vi',// "Vietnamese",
|
|
26
|
+
/** Uzbek */
|
|
27
|
+
UZ = 'uz',// "Uzbek",
|
|
28
|
+
/** Urdu */
|
|
29
|
+
UR = 'ur',// "Urdu",
|
|
30
|
+
/** Ukrainian */
|
|
31
|
+
UK = 'uk',// "Ukrainian",
|
|
32
|
+
/** Uyghur */
|
|
33
|
+
UG = 'ug',// "Uyghur",
|
|
34
|
+
/** Tamazight */
|
|
35
|
+
TZM = 'tzm',// "Tamazight",
|
|
36
|
+
/** Tatar */
|
|
37
|
+
TT = 'tt',// "Tatar",
|
|
38
|
+
/** Turkish */
|
|
39
|
+
TR = 'tr',// "Turkish",
|
|
40
|
+
/** Setswana */
|
|
41
|
+
TN = 'tn',// "Setswana",
|
|
42
|
+
/** Turkmen */
|
|
43
|
+
TK = 'tk',// "Turkmen",
|
|
44
|
+
/** Thai */
|
|
45
|
+
TH = 'th',// "Thai",
|
|
46
|
+
/** Tajik */
|
|
47
|
+
TG = 'tg',// "Tajik",
|
|
48
|
+
/** Telugu */
|
|
49
|
+
TE = 'te',// "Telugu",
|
|
50
|
+
/** Tamil */
|
|
51
|
+
TA = 'ta',// "Tamil",
|
|
52
|
+
/** Syriac */
|
|
53
|
+
SYR = 'syr',// "Syriac",
|
|
54
|
+
/** Kiswahili */
|
|
55
|
+
SW = 'sw',// "Kiswahili",
|
|
56
|
+
/** Swedish */
|
|
57
|
+
SV = 'sv',// "Swedish",
|
|
58
|
+
/** Serbian */
|
|
59
|
+
SR = 'sr',// "Serbian",
|
|
60
|
+
/** Albanian */
|
|
61
|
+
SQ = 'sq',// "Albanian",
|
|
62
|
+
/** Sami */
|
|
63
|
+
SMS = 'sms',// "Sami",
|
|
64
|
+
/** Sami */
|
|
65
|
+
SMN = 'smn',// "Sami",
|
|
66
|
+
/** Sami */
|
|
67
|
+
SMJ = 'smj',// "Sami",
|
|
68
|
+
/** Sami */
|
|
69
|
+
SMA = 'sma',// "Sami",
|
|
70
|
+
/** Slovenian */
|
|
71
|
+
SL = 'sl',// "Slovenian",
|
|
72
|
+
/** Slovak */
|
|
73
|
+
SK = 'sk',// "Slovak",
|
|
74
|
+
/** Sinhala */
|
|
75
|
+
SI = 'si',// "Sinhala",
|
|
76
|
+
/** Sami */
|
|
77
|
+
SE = 'se',// "Sami",
|
|
78
|
+
/** Yakut */
|
|
79
|
+
SAH = 'sah',// "Yakut",
|
|
80
|
+
/** Sanskrit */
|
|
81
|
+
SA = 'sa',// "Sanskrit",
|
|
82
|
+
/** Kinyarwanda */
|
|
83
|
+
RW = 'rw',// "Kinyarwanda",
|
|
84
|
+
/** Russian */
|
|
85
|
+
RU = 'ru',// "Russian",
|
|
86
|
+
/** Romanian */
|
|
87
|
+
RO = 'ro',// "Romanian",
|
|
88
|
+
/** Romansh */
|
|
89
|
+
RM = 'rm',// "Romansh",
|
|
90
|
+
/** Quechua */
|
|
91
|
+
QUZ = 'quz',// "Quechua",
|
|
92
|
+
/** K */
|
|
93
|
+
QUT = 'qut',// "K'iche",
|
|
94
|
+
/** Portuguese */
|
|
95
|
+
PT = 'pt',// "Portuguese",
|
|
96
|
+
/** Pashto */
|
|
97
|
+
PS = 'ps',// "Pashto",
|
|
98
|
+
/** Dari */
|
|
99
|
+
PRS = 'prs',// "Dari",
|
|
100
|
+
/** Polish */
|
|
101
|
+
PL = 'pl',// "Polish",
|
|
102
|
+
/** Punjabi */
|
|
103
|
+
PA = 'pa',// "Punjabi",
|
|
104
|
+
/** Oriya */
|
|
105
|
+
OR = 'or',// "Oriya",
|
|
106
|
+
/** Occitan */
|
|
107
|
+
OC = 'oc',// "Occitan",
|
|
108
|
+
/** Sesotho sa Leboa */
|
|
109
|
+
NSO = 'nso',// "Sesotho sa Leboa",
|
|
110
|
+
/** Norwegian */
|
|
111
|
+
NO = 'no',// "Norwegian",
|
|
112
|
+
/** Norwegian, Nynorsk */
|
|
113
|
+
NN = 'nn',// "Norwegian, Nynorsk",
|
|
114
|
+
/** Dutch */
|
|
115
|
+
NL = 'nl',// "Dutch",
|
|
116
|
+
/** Nepali */
|
|
117
|
+
NE = 'ne',// "Nepali",
|
|
118
|
+
/** Norwegian, Bokmål */
|
|
119
|
+
NB = 'nb',// "Norwegian, Bokmål",
|
|
120
|
+
/** Maltese */
|
|
121
|
+
MT = 'mt',// "Maltese",
|
|
122
|
+
/** Malay */
|
|
123
|
+
MS = 'ms',// "Malay",
|
|
124
|
+
/** Marathi */
|
|
125
|
+
MR = 'mr',// "Marathi",
|
|
126
|
+
/** Mohawk */
|
|
127
|
+
MOH = 'moh',// "Mohawk",
|
|
128
|
+
/** Mongolian */
|
|
129
|
+
MN = 'mn',// "Mongolian",
|
|
130
|
+
/** Malayalam */
|
|
131
|
+
ML = 'ml',// "Malayalam",
|
|
132
|
+
/** Macedonian */
|
|
133
|
+
MK = 'mk',// "Macedonian",
|
|
134
|
+
/** Maori */
|
|
135
|
+
MI = 'mi',// "Maori",
|
|
136
|
+
/** Latvian */
|
|
137
|
+
LV = 'lv',// "Latvian",
|
|
138
|
+
/** Lithuanian */
|
|
139
|
+
LT = 'lt',// "Lithuanian",
|
|
140
|
+
/** Lao */
|
|
141
|
+
LO = 'lo',// "Lao",
|
|
142
|
+
/** Luxembourgish */
|
|
143
|
+
LB = 'lb',// "Luxembourgish",
|
|
144
|
+
/** Kyrgyz */
|
|
145
|
+
KY = 'ky',// "Kyrgyz",
|
|
146
|
+
/** Konkani */
|
|
147
|
+
KOK = 'kok',// "Konkani",
|
|
148
|
+
/** Korean */
|
|
149
|
+
KO = 'ko',// "Korean",
|
|
150
|
+
/** Kannada */
|
|
151
|
+
KN = 'kn',// "Kannada",
|
|
152
|
+
/** Khmer */
|
|
153
|
+
KM = 'km',// "Khmer",
|
|
154
|
+
/** Greenlandic */
|
|
155
|
+
KL = 'kl',// "Greenlandic",
|
|
156
|
+
/** Kazakh */
|
|
157
|
+
KK = 'kk',// "Kazakh",
|
|
158
|
+
/** Georgian */
|
|
159
|
+
KA = 'ka',// "Georgian",
|
|
160
|
+
/** Japanese */
|
|
161
|
+
JA = 'ja',// "Japanese",
|
|
162
|
+
/** Inuktitut */
|
|
163
|
+
IU = 'iu',// "Inuktitut",
|
|
164
|
+
/** Italian */
|
|
165
|
+
IT = 'it',// "Italian",
|
|
166
|
+
/** Icelandic */
|
|
167
|
+
IS = 'is',// "Icelandic",
|
|
168
|
+
/** Yi */
|
|
169
|
+
II = 'ii',// "Yi",
|
|
170
|
+
/** Igbo */
|
|
171
|
+
IG = 'ig',// "Igbo",
|
|
172
|
+
/** Indonesian */
|
|
173
|
+
ID = 'id',// "Indonesian",
|
|
174
|
+
/** Armenian */
|
|
175
|
+
HY = 'hy',// "Armenian",
|
|
176
|
+
/** Hungarian */
|
|
177
|
+
HU = 'hu',// "Hungarian",
|
|
178
|
+
/** Upper Sorbian */
|
|
179
|
+
HSB = 'hsb',// "Upper Sorbian",
|
|
180
|
+
/** Croatian */
|
|
181
|
+
HR = 'hr',// "Croatian",
|
|
182
|
+
/** Hindi */
|
|
183
|
+
HI = 'hi',// "Hindi",
|
|
184
|
+
/** Hebrew */
|
|
185
|
+
HE = 'he',// "Hebrew",
|
|
186
|
+
/** Hausa */
|
|
187
|
+
HA = 'ha',// "Hausa",
|
|
188
|
+
/** Gujarati */
|
|
189
|
+
GU = 'gu',// "Gujarati",
|
|
190
|
+
/** Alsatian */
|
|
191
|
+
GSW = 'gsw',// "Alsatian",
|
|
192
|
+
/** Galician */
|
|
193
|
+
GL = 'gl',// "Galician",
|
|
194
|
+
/** Scottish Gaelic */
|
|
195
|
+
GD = 'gd',// "Scottish Gaelic",
|
|
196
|
+
/** Irish */
|
|
197
|
+
GA = 'ga',// "Irish",
|
|
198
|
+
/** Frisian */
|
|
199
|
+
FY = 'fy',// "Frisian",
|
|
200
|
+
/** French */
|
|
201
|
+
FR = 'fr',// "French",
|
|
202
|
+
/** Faroese */
|
|
203
|
+
FO = 'fo',// "Faroese",
|
|
204
|
+
/** Filipino */
|
|
205
|
+
FIL = 'fil',// "Filipino",
|
|
206
|
+
/** Finnish */
|
|
207
|
+
FI = 'fi',// "Finnish",
|
|
208
|
+
/** Persian */
|
|
209
|
+
FA = 'fa',// "Persian",
|
|
210
|
+
/** Basque */
|
|
211
|
+
EU = 'eu',// "Basque",
|
|
212
|
+
/** Estonian */
|
|
213
|
+
ET = 'et',// "Estonian",
|
|
214
|
+
/** Spanish */
|
|
215
|
+
ES = 'es',// "Spanish",
|
|
216
|
+
/** English */
|
|
217
|
+
EN = 'en',// "English",
|
|
218
|
+
/** Greek */
|
|
219
|
+
EL = 'el',// "Greek",
|
|
220
|
+
/** Divehi */
|
|
221
|
+
DV = 'dv',// "Divehi",
|
|
222
|
+
/** Lower Sorbian */
|
|
223
|
+
DSB = 'dsb',// "Lower Sorbian",
|
|
224
|
+
/** German */
|
|
225
|
+
DE = 'de',// "German",
|
|
226
|
+
/** Danish */
|
|
227
|
+
DA = 'da',// "Danish",
|
|
228
|
+
/** Welsh */
|
|
229
|
+
CY = 'cy',// "Welsh",
|
|
230
|
+
/** Czech */
|
|
231
|
+
CS = 'cs',// "Czech",
|
|
232
|
+
/** Corsican */
|
|
233
|
+
CO = 'co',// "Corsican",
|
|
234
|
+
/** Catalan */
|
|
235
|
+
CA = 'ca',// "Catalan",
|
|
236
|
+
/** Bosnian */
|
|
237
|
+
BS = 'bs',// "Bosnian",
|
|
238
|
+
/** Breton */
|
|
239
|
+
BR = 'br',// "Breton",
|
|
240
|
+
/** Tibetan */
|
|
241
|
+
BO = 'bo',// "Tibetan",
|
|
242
|
+
/** Bengali */
|
|
243
|
+
BN = 'bn',// "Bengali",
|
|
244
|
+
/** Bulgarian */
|
|
245
|
+
BG = 'bg',// "Bulgarian",
|
|
246
|
+
/** Belarusian */
|
|
247
|
+
BE = 'be',// "Belarusian",
|
|
248
|
+
/** Bashkir */
|
|
249
|
+
BA = 'ba',// "Bashkir",
|
|
250
|
+
/** Azeri */
|
|
251
|
+
AZ = 'az',// "Azeri",
|
|
252
|
+
/** Assamese */
|
|
253
|
+
AS = 'as',// "Assamese",
|
|
254
|
+
/** Mapudungun */
|
|
255
|
+
ARN = 'arn',// "Mapudungun",
|
|
256
|
+
/** Arabic */
|
|
257
|
+
AR = 'ar',// "Arabic",
|
|
258
|
+
/** Amharic */
|
|
259
|
+
AM = 'am',// "Amharic",
|
|
260
|
+
/** Afrikaans */
|
|
261
|
+
AF = 'af'// "Afrikaans"
|
|
262
|
+
}
|
package/src/main.tsx
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/// <reference types="@emotion/react/types/css-prop" />
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
3
|
+
import { createRoot } from 'react-dom/client'
|
|
4
|
+
import { css, Global } from '@emotion/react'
|
|
5
|
+
|
|
6
|
+
import MediaPlayer from './index'
|
|
7
|
+
import { bufferStream } from './utils'
|
|
8
|
+
|
|
9
|
+
const mountStyle = css`
|
|
10
|
+
display: grid;
|
|
11
|
+
height: 100%;
|
|
12
|
+
width: 100%;
|
|
13
|
+
`
|
|
14
|
+
|
|
15
|
+
const BASE_BUFFER_SIZE = 5_000_000
|
|
16
|
+
const STREAM_RESPONSES = false
|
|
17
|
+
|
|
18
|
+
const Mount = () => {
|
|
19
|
+
const [videoElemRef, setVideoElemRef] = useState<HTMLVideoElement | null>()
|
|
20
|
+
const [size, setSize] = useState<number>()
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!videoElemRef) return
|
|
24
|
+
videoElemRef.addEventListener('error', err => console.log('err', err))
|
|
25
|
+
}, [videoElemRef])
|
|
26
|
+
|
|
27
|
+
const [currentStreamOffset, setCurrentStreamOffset] = useState<number>(0)
|
|
28
|
+
const [streamReader, setStreamReader] = useState<ReadableStreamDefaultReader<Uint8Array>>()
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!streamReader) return
|
|
32
|
+
return () => {
|
|
33
|
+
streamReader.cancel()
|
|
34
|
+
}
|
|
35
|
+
}, [streamReader])
|
|
36
|
+
|
|
37
|
+
const setupStream = async (offset: number) => {
|
|
38
|
+
if (streamReader) {
|
|
39
|
+
streamReader.cancel()
|
|
40
|
+
}
|
|
41
|
+
const streamResponse = await onFetch(offset, undefined, true)
|
|
42
|
+
if (!streamResponse.body) throw new Error('no body')
|
|
43
|
+
const stream = bufferStream({ stream: streamResponse.body, size: BASE_BUFFER_SIZE })
|
|
44
|
+
const reader = stream.getReader()
|
|
45
|
+
setStreamReader(reader)
|
|
46
|
+
setCurrentStreamOffset(offset)
|
|
47
|
+
return reader
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const onFetch = async (offset: number, end?: number, force?: boolean) => {
|
|
51
|
+
if (force || end !== undefined && ((end - offset) + 1) !== BASE_BUFFER_SIZE) {
|
|
52
|
+
return (
|
|
53
|
+
fetch(
|
|
54
|
+
'/video3.mkv',
|
|
55
|
+
{
|
|
56
|
+
headers: {
|
|
57
|
+
Range: `bytes=${offset}-${end ?? ''}`
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
const _streamReader =
|
|
64
|
+
currentStreamOffset !== offset
|
|
65
|
+
? await setupStream(offset)
|
|
66
|
+
: streamReader
|
|
67
|
+
|
|
68
|
+
if (!_streamReader) throw new Error('Stream reader not ready')
|
|
69
|
+
return new Response(
|
|
70
|
+
await _streamReader
|
|
71
|
+
.read()
|
|
72
|
+
.then(({ value }) => {
|
|
73
|
+
if (value) {
|
|
74
|
+
setCurrentStreamOffset(offset => offset + value.byteLength)
|
|
75
|
+
}
|
|
76
|
+
return value
|
|
77
|
+
})
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
onFetch(0, 1, true).then(async ({ headers, body }) => {
|
|
83
|
+
if (!body) throw new Error('no body')
|
|
84
|
+
const contentRangeContentLength = headers.get('Content-Range')?.split('/').at(1)
|
|
85
|
+
const contentLength =
|
|
86
|
+
contentRangeContentLength
|
|
87
|
+
? Number(contentRangeContentLength)
|
|
88
|
+
: Number(headers.get('Content-Length'))
|
|
89
|
+
if (STREAM_RESPONSES) await setupStream(0)
|
|
90
|
+
setSize(contentLength)
|
|
91
|
+
})
|
|
92
|
+
}, [])
|
|
93
|
+
|
|
94
|
+
const jassubWorkerUrl = useMemo(() => {
|
|
95
|
+
const workerUrl = new URL('/build/jassub-worker.js', import.meta.url).toString()
|
|
96
|
+
const blob = new Blob([`importScripts(${JSON.stringify(workerUrl)})`], { type: 'application/javascript' })
|
|
97
|
+
return URL.createObjectURL(blob)
|
|
98
|
+
}, [])
|
|
99
|
+
|
|
100
|
+
const libavWorkerUrl = useMemo(() => {
|
|
101
|
+
const workerUrl = new URL('/build/libav.js', new URL(window.location.toString()).origin).toString()
|
|
102
|
+
const blob = new Blob([`importScripts(${JSON.stringify(workerUrl)})`], { type: 'application/javascript' })
|
|
103
|
+
return URL.createObjectURL(blob)
|
|
104
|
+
}, [])
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div css={mountStyle}>
|
|
108
|
+
<MediaPlayer
|
|
109
|
+
baseBufferSize={BASE_BUFFER_SIZE}
|
|
110
|
+
ref={setVideoElemRef}
|
|
111
|
+
size={size}
|
|
112
|
+
fetch={(offset, end) => onFetch(offset, end, STREAM_RESPONSES ? false : true)}
|
|
113
|
+
publicPath={new URL('/build/', new URL(import.meta.url).origin).toString()}
|
|
114
|
+
wasmUrl={new URL('/build/jassub-worker-modern.wasm', new URL(import.meta.url).origin).toString()}
|
|
115
|
+
libavWorkerUrl={libavWorkerUrl}
|
|
116
|
+
libassWorkerUrl={jassubWorkerUrl}
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const globalStyle = css`
|
|
123
|
+
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=Fira+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,500;1,600;1,700;1,800;1,900&family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
|
|
124
|
+
|
|
125
|
+
*, *::before, *::after {
|
|
126
|
+
box-sizing: border-box;
|
|
127
|
+
margin: 0;
|
|
128
|
+
padding: 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
html {
|
|
132
|
+
font-size: 62.5%;
|
|
133
|
+
height: 100%;
|
|
134
|
+
width: 100%;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
body {
|
|
138
|
+
margin: 0;
|
|
139
|
+
height: 100%;
|
|
140
|
+
width: 100%;
|
|
141
|
+
font-size: 1.6rem;
|
|
142
|
+
font-family: Fira Sans;
|
|
143
|
+
color: #fff;
|
|
144
|
+
|
|
145
|
+
font-family: Montserrat;
|
|
146
|
+
// font-family: "Segoe UI", Roboto, "Fira Sans", "Helvetica Neue", Arial, sans-serif;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
body > div {
|
|
150
|
+
height: 100%;
|
|
151
|
+
width: 100%;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
a {
|
|
155
|
+
color: #777777;
|
|
156
|
+
text-decoration: none;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
a:hover {
|
|
160
|
+
color: #fff;
|
|
161
|
+
text-decoration: underline;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
ul {
|
|
165
|
+
list-style: none;
|
|
166
|
+
}
|
|
167
|
+
`
|
|
168
|
+
|
|
169
|
+
const mountElement = document.createElement('div')
|
|
170
|
+
|
|
171
|
+
const root = createRoot(
|
|
172
|
+
document.body.appendChild(mountElement)
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
root.render(
|
|
176
|
+
<>
|
|
177
|
+
<Global styles={globalStyle}/>
|
|
178
|
+
<Mount/>
|
|
179
|
+
</>
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
if (import.meta.hot) {
|
|
183
|
+
import.meta.hot.dispose((data) => {
|
|
184
|
+
root.unmount()
|
|
185
|
+
mountElement.remove()
|
|
186
|
+
})
|
|
187
|
+
}
|
package/src/mp4box.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
declare module "mp4box" {
|
|
2
|
+
|
|
3
|
+
export interface MP4MediaTrack {
|
|
4
|
+
id: number
|
|
5
|
+
created: Date
|
|
6
|
+
modified: Date
|
|
7
|
+
movie_duration: number
|
|
8
|
+
layer: number
|
|
9
|
+
alternate_group: number
|
|
10
|
+
volume: number
|
|
11
|
+
track_width: number
|
|
12
|
+
track_height: number
|
|
13
|
+
timescale: number
|
|
14
|
+
duration: number
|
|
15
|
+
bitrate: number
|
|
16
|
+
codec: string
|
|
17
|
+
language: string
|
|
18
|
+
nb_samples: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface MP4VideoData {
|
|
22
|
+
width: number
|
|
23
|
+
height: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface MP4VideoTrack extends MP4MediaTrack {
|
|
27
|
+
video: MP4VideoData
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface MP4AudioData {
|
|
31
|
+
sample_rate: number
|
|
32
|
+
channel_count: number
|
|
33
|
+
sample_size: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface MP4AudioTrack extends MP4MediaTrack {
|
|
37
|
+
audio: MP4AudioData
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type MP4Track = MP4VideoTrack | MP4AudioTrack
|
|
41
|
+
|
|
42
|
+
export interface MP4Info {
|
|
43
|
+
duration: number
|
|
44
|
+
timescale: number
|
|
45
|
+
fragment_duration: number
|
|
46
|
+
isFragmented: boolean
|
|
47
|
+
isProgressive: boolean
|
|
48
|
+
hasIOD: boolean
|
|
49
|
+
brands: string[]
|
|
50
|
+
created: Date
|
|
51
|
+
modified: Date
|
|
52
|
+
tracks: MP4Track[]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type MP4ArrayBuffer = ArrayBuffer & { fileStart: number }
|
|
56
|
+
|
|
57
|
+
export interface MP4File {
|
|
58
|
+
|
|
59
|
+
onMoovStart?: () => void
|
|
60
|
+
onReady?: (info: MP4Info) => void
|
|
61
|
+
onError?: (e: Error) => void
|
|
62
|
+
|
|
63
|
+
appendBuffer(data: MP4ArrayBuffer): number
|
|
64
|
+
start(): void
|
|
65
|
+
stop(): void
|
|
66
|
+
flush(): void
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createFile(): MP4File
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
const useNamespacedLocalStorage = <T extends { [key: PropertyKey]: string | boolean | number | undefined | null | object | any[] }>(namespace: string) => {
|
|
4
|
+
const [state, setState] = useState<T>(() => {
|
|
5
|
+
const storedValue = localStorage.getItem(namespace)
|
|
6
|
+
return (
|
|
7
|
+
storedValue
|
|
8
|
+
? JSON.parse(storedValue)
|
|
9
|
+
: {}
|
|
10
|
+
)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
localStorage.setItem(namespace, JSON.stringify(state));
|
|
15
|
+
}, [namespace, state])
|
|
16
|
+
|
|
17
|
+
return <T2 extends keyof T, T3 extends T[T2]>(key: T2, value: T[T2]) => {
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
setState(state => ({ ...state, [key]: value }))
|
|
20
|
+
}, [])
|
|
21
|
+
return [
|
|
22
|
+
state[key],
|
|
23
|
+
(newValue: T3 | ((oldValue: T3) => T3)) =>
|
|
24
|
+
typeof newValue === 'function'
|
|
25
|
+
// @ts-expect-error
|
|
26
|
+
? setState(state => ({ ...state, [key]: newValue(state[key]) }))
|
|
27
|
+
: setState(state => ({ ...state, [key]: newValue }))
|
|
28
|
+
] as const
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default useNamespacedLocalStorage
|
package/src/use-scrub.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { MouseEventHandler, RefObject } from 'react'
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react'
|
|
4
|
+
|
|
5
|
+
export default ({ ref, defaultValue }: { ref: RefObject<HTMLElement>, defaultValue?: number }) => {
|
|
6
|
+
const [value, setValue] = useState(defaultValue)
|
|
7
|
+
const [scrubbing, setScrubbing] = useState(false)
|
|
8
|
+
|
|
9
|
+
const scrub: MouseEventHandler<HTMLDivElement> = (ev) => {
|
|
10
|
+
setScrubbing(true)
|
|
11
|
+
if (!ref.current) return
|
|
12
|
+
const { clientX: x } = ev
|
|
13
|
+
const { left, right } = ref.current.getBoundingClientRect()
|
|
14
|
+
setValue(Math.min(Math.max(((x - left) / (right - left)), 0), 1))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!scrubbing) return
|
|
19
|
+
const mouseUp = () => setScrubbing(false)
|
|
20
|
+
const mouseMove = (ev: globalThis.MouseEvent) => {
|
|
21
|
+
if (!ref.current) return
|
|
22
|
+
const { clientX: x } = ev
|
|
23
|
+
const { left, right } = ref.current.getBoundingClientRect()
|
|
24
|
+
setValue(Math.min(Math.max(((x - left) / (right - left)), 0), 1))
|
|
25
|
+
}
|
|
26
|
+
document.addEventListener('mousemove', mouseMove)
|
|
27
|
+
document.addEventListener('mouseup', mouseUp)
|
|
28
|
+
return () => {
|
|
29
|
+
document.removeEventListener('mousemove', mouseMove)
|
|
30
|
+
document.removeEventListener('mouseup', mouseUp)
|
|
31
|
+
}
|
|
32
|
+
}, [scrubbing])
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
value,
|
|
36
|
+
scrubbing,
|
|
37
|
+
scrub
|
|
38
|
+
}
|
|
39
|
+
}
|