-
Notifications
You must be signed in to change notification settings - Fork 60
Add support for video captions #910
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
9cb6408
088b678
f2216ad
e1eacde
f681942
ce00b04
1362f92
15d412e
be25019
9f05ce1
d4c9014
01fc82e
a9cfee1
31cb81a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Generate HTML5 subtitle tracks dynamically based on the contents of the folder where the video is located. For example: given a movie 'video.mkv', the player will look for VTT subtitle files named 'video.XX.vtt' and '.video.XX.vtt', where XX is the two-letter code for the language. Signed-off-by: Frederic Ruget <[email protected]>
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ | |
| <!-- Plyr currently replaces the parent. Wrapping to prevent this | ||
| https://github.com/redxtech/vue-plyr/issues/259 --> | ||
| <div v-if="davPath"> | ||
| <div v-html="fetchTracks()" /> | ||
| <VuePlyr | ||
| ref="plyr" | ||
| :options="options" | ||
|
|
@@ -40,7 +41,8 @@ | |
| preload="metadata" | ||
| @ended="donePlaying" | ||
| @canplay="doneLoading" | ||
| @loadedmetadata="onLoadedMetadata"> | ||
| @loadedmetadata="onLoadedMetadata" | ||
| v-html="tracks"> | ||
|
|
||
| <!-- Omitting `type` on purpose because most of the | ||
| browsers auto detect the appropriate codec. | ||
|
|
@@ -58,6 +60,8 @@ | |
| import Vue from 'vue' | ||
| import VuePlyr from '@skjnldsv/vue-plyr' | ||
| import '@skjnldsv/vue-plyr/dist/vue-plyr.css' | ||
| import { extractFilePaths } from '../utils/fileUtils' | ||
| import getFileList from '../services/FileList' | ||
|
|
||
| const liveExt = ['jpg', 'jpeg', 'png'] | ||
| const liveExtRegex = new RegExp(`\\.(${liveExt.join('|')})$`, 'i') | ||
|
|
@@ -85,8 +89,10 @@ export default { | |
| options() { | ||
| return { | ||
| autoplay: this.active === true, | ||
| captions: { active: false, language: 'auto', update: true }, | ||
| controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'fullscreen'], | ||
| loadSprite: false, | ||
|
|
||
| } | ||
| }, | ||
| }, | ||
|
|
@@ -121,6 +127,232 @@ export default { | |
| onLoadedMetadata() { | ||
| this.updateVideoSize() | ||
| }, | ||
|
|
||
| async fetchFolder(dirPath) { | ||
| // Fetching the contents of the video folder must be asynchronous | ||
| const fileList = await getFileList(dirPath) | ||
| return fileList | ||
| }, | ||
|
|
||
| fetchTracks() { | ||
| const dirPath = extractFilePaths(this.filename)[0] | ||
| this.fetchFolder(dirPath).then(folder => { | ||
beardhatcode marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // ISO code for languages | ||
| // See https://www.loc.gov/standards/iso639-2/php/code_list.php | ||
| const languages = { | ||
| aa: 'Afar', | ||
| ab: 'Abkhazian', | ||
| ae: 'Avestan', | ||
| af: 'Afrikaans', | ||
| ak: 'Akan', | ||
| am: 'Amharic', | ||
| an: 'Aragonese', | ||
| ar: 'Arabic', | ||
| as: 'Assamese', | ||
| av: 'Avaric', | ||
| ay: 'Aymara', | ||
| az: 'Azerbaijani', | ||
| ba: 'Bashkir', | ||
| be: 'Belarusian', | ||
| bg: 'Bulgarian', | ||
| bh: 'Bihari languages', | ||
| bi: 'Bislama', | ||
| bm: 'Bambara', | ||
| bn: 'Bengali', | ||
| bo: 'Tibetan', | ||
| br: 'Breton', | ||
| bs: 'Bosnian', | ||
| ca: 'Catalan', | ||
| ce: 'Chechen', | ||
| ch: 'Chamorro', | ||
| co: 'Corsican', | ||
| cr: 'Cree', | ||
| cs: 'Czech', | ||
| cu: 'Church Slavic', | ||
| cv: 'Chuvash', | ||
| cy: 'Welsh', | ||
| da: 'Danish', | ||
| de: 'German', | ||
| dv: 'Divehi', | ||
| dz: 'Dzongkha', | ||
| ee: 'Ewe', | ||
| el: 'Greek', | ||
| en: 'English', | ||
| eo: 'Esperanto', | ||
| es: 'Spanish', | ||
| et: 'Estonian', | ||
| eu: 'Basque', | ||
| fa: 'Persian', | ||
| ff: 'Fulah', | ||
| fi: 'Finnish', | ||
| fj: 'Fijian', | ||
| fo: 'Faroese', | ||
| fr: 'French', | ||
| fy: 'Western Frisian', | ||
| ga: 'Irish', | ||
| gd: 'Gaelic', | ||
| gl: 'Galician', | ||
| gn: 'Guarani', | ||
| gu: 'Gujarati', | ||
| gv: 'Manx', | ||
| ha: 'Hausa', | ||
| he: 'Hebrew', | ||
| hi: 'Hindi', | ||
| ho: 'Hiri Motu', | ||
| hr: 'Croatian', | ||
| ht: 'Haitian', | ||
| hu: 'Hungarian', | ||
| hy: 'Armenian', | ||
| hz: 'Herero', | ||
| ia: 'Interlingua', | ||
| id: 'Indonesian', | ||
| ie: 'Interlingue', | ||
| ig: 'Igbo', | ||
| ii: 'Sichuan Yi', | ||
| ik: 'Inupiaq', | ||
| io: 'Ido', | ||
| is: 'Icelandic', | ||
| it: 'Italian', | ||
| iu: 'Inuktitut', | ||
| ja: 'Japanese', | ||
| jv: 'Javanese', | ||
| ka: 'Georgian', | ||
| kg: 'Kongo', | ||
| ki: 'Kikuyu', | ||
| kj: 'Kuanyama', | ||
| kk: 'Kazakh', | ||
| kl: 'Kalaallisut', | ||
| km: 'Central Khmer', | ||
| kn: 'Kannada', | ||
| ko: 'Korean', | ||
| kr: 'Kanuri', | ||
| ks: 'Kashmiri', | ||
| ku: 'Kurdish', | ||
| kv: 'Komi', | ||
| kw: 'Cornish', | ||
| ky: 'Kirghiz', | ||
| la: 'Latin', | ||
| lb: 'Luxembourgish', | ||
| lg: 'Ganda', | ||
| li: 'Limburgan', | ||
| ln: 'Lingala', | ||
| lo: 'Lao', | ||
| lt: 'Lithuanian', | ||
| lu: 'Luba-Katanga', | ||
| lv: 'Latvian', | ||
| mg: 'Malagasy', | ||
| mh: 'Marshallese', | ||
| mi: 'Maori', | ||
| mk: 'Macedonian', | ||
| ml: 'Malayalam', | ||
| mn: 'Mongolian', | ||
| mr: 'Marathi', | ||
| ms: 'Malay', | ||
| mt: 'Maltese', | ||
| my: 'Burmese', | ||
| na: 'Nauru', | ||
| nb: 'Norwegian Bokmål', | ||
| nd: 'Ndebele, North', | ||
| ne: 'Nepali', | ||
| ng: 'Ndonga', | ||
| nl: 'Dutch', | ||
| nn: 'Norwegian Nynorsk', | ||
| no: 'Norwegian', | ||
| nr: 'Ndebele, South', | ||
| nv: 'Navajo', | ||
| ny: 'Nyanja', | ||
| oc: 'Occitan', | ||
| oj: 'Ojibwa', | ||
| om: 'Oromo', | ||
| or: 'Oriya', | ||
| os: 'Ossetian', | ||
| pa: 'Panjabi', | ||
| pi: 'Pali', | ||
| pl: 'Polish', | ||
| ps: 'Pushto', | ||
| pt: 'Portuguese', | ||
| qu: 'Quechua', | ||
| rm: 'Romansh', | ||
| rn: 'Rundi', | ||
| ro: 'Romanian', | ||
| ru: 'Russian', | ||
| rw: 'Kinyarwanda', | ||
| sa: 'Sanskrit', | ||
| sc: 'Sardinian', | ||
| sd: 'Sindhi', | ||
| se: 'Northern Sami', | ||
| sg: 'Sango', | ||
| si: 'Sinhala', | ||
| sk: 'Slovak', | ||
| sl: 'Slovenian', | ||
| sm: 'Samoan', | ||
| sn: 'Shona', | ||
| so: 'Somali', | ||
| sq: 'Albanian', | ||
| sr: 'Serbian', | ||
| ss: 'Swati', | ||
| st: 'Sotho', | ||
| su: 'Sundanese', | ||
| sv: 'Swedish', | ||
| sw: 'Swahili', | ||
| ta: 'Tamil', | ||
| te: 'Telugu', | ||
| tg: 'Tajik', | ||
| th: 'Thai', | ||
| ti: 'Tigrinya', | ||
| tk: 'Turkmen', | ||
| tl: 'Tagalog', | ||
| tn: 'Tswana', | ||
| to: 'Tonga', | ||
| tr: 'Turkish', | ||
| ts: 'Tsonga', | ||
| tt: 'Tatar', | ||
| tw: 'Twi', | ||
| ty: 'Tahitian', | ||
| ug: 'Uighur', | ||
| uk: 'Ukrainian', | ||
| ur: 'Urdu', | ||
| uz: 'Uzbek', | ||
| ve: 'Venda', | ||
| vi: 'Vietnamese', | ||
| vo: 'Volapük', | ||
| wa: 'Walloon', | ||
| wo: 'Wolof', | ||
| xh: 'Xhosa', | ||
| yi: 'Yiddish', | ||
| yo: 'Yoruba', | ||
| za: 'Zhuang', | ||
| zh: 'Chinese', | ||
| zu: 'Zulu', | ||
|
Comment on lines
+148
to
+332
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This most likely already exists, but I can see where maintaining this list could be an issue. We have a dedicated php method to get those ressources.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @skjnldsv... so I would like to invoke L10N's php function 'findLanguageFromLocale()' from 'fetchTracks()'. public function findLanguageFromLocale(string $app = 'core', string $locale = null)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need the findLanguageFromLocale ? |
||
| } | ||
| const davDir = this.davPath.replace(/[^/]*$/, '') | ||
| const videoRoot = this.basename.replace(/[.][^.]+$/, '') | ||
| // Create caption tracks for the HTML5 player | ||
| // E.g.: <file>.mkv: look for <file>.xx.vtt or .<file>.xx.vtt | ||
| let capTracks = '' // '<source src="' + this.davPath + '" />\n' | ||
| for (let i = 0; i < folder.length; ++i) { | ||
| const basename = folder[i].basename | ||
| const index = basename.indexOf(videoRoot) | ||
| // Consider only file... or .file... | ||
| if (!(index === 0 || (index === 1 || basename[0] === '.'))) { | ||
| continue | ||
| } | ||
| const suffix = basename.slice(videoRoot.length + index) | ||
| // Consider only ...xx.vtt | ||
| if (suffix.search(/^[.]..[.]vtt$/) !== 0) { | ||
| continue | ||
| } | ||
| const lang = suffix.slice(1, 3) | ||
| const language = languages[lang] || lang | ||
| capTracks += '<track src="' + davDir + basename + '"' | ||
| + ' label="' + language + '"' | ||
| + ' kind="captions"' | ||
| + ' srclang="' + lang + '"' | ||
| + ' />\n' | ||
skjnldsv marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| this.tracks = capTracks | ||
beardhatcode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }) | ||
| }, | ||
| }, | ||
| } | ||
| </script> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.