import Plyr from '../vendor/plyr-3.7.3.mjs'; const container = document.getElementById('container'); function displayError(message) { const errorBox = document.createElement('div'); errorBox.classList.add('error'); errorBox.innerText = message; container.appendChild(errorBox); throw new Error(); // abort } function loadPlaybackState(videoUrl) { const item = localStorage.getItem('wfm__playerstate'); if (item) { const data = JSON.parse(item); if (Object.prototype.hasOwnProperty.call(data, videoUrl)) { return data[videoUrl]; } } return { time: 0, }; } function savePlaybackState(videoUrl, state) { const item = localStorage.getItem('wfm__playerstate'); let data; if (item) { data = JSON.parse(item); } else { data = {}; } data[videoUrl] = state; localStorage.setItem('wfm__playerstate', JSON.stringify(data)); } function parseQuery() { if (window.location.hash.length > 1) { const qs = window.location.hash.substring(1); const query = new URLSearchParams(qs); if (query.has('source')) { const source = query.get('source'); const sourceType = query.get('source_type'); const captions = query.getAll('captions'); const captionLanguages = query.getAll('caption_langs'); const captionLabels = query.getAll('caption_labels'); if (!source || !sourceType) { displayError('missing source or sourceType parameter'); } if (captions.length !== captionLanguages.length || captions.length !== captionLabels.length) { displayError('mismatch between captions, caption_langs and caption_labels length'); } return { source, sourceType, captions, captionLanguages, captionLabels, } } else if (query.has('base')) { return { base: query.get('base'), } } } return null; } function parseTimestamp(timestamp) { const results = /^(0|[1-9]+):([0-9]{2}):([0-9]{2}).([0-9]+)$/g.exec(timestamp); const [_, hours, mins, secs, frac] = results; return { hours, mins, secs, frac, }; } function formatTimestamp({ hours, mins, secs, frac }) { const ms = `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; if (hours !== 0) { return `${hours}:${ms}`; } else { return ms; } } const query = parseQuery(); if (query !== null && query.source) { const { source, sourceType, captions, captionLanguages, captionLabels } = query; const video = document.createElement('video'); video.controls = true; video.crossOrigin = 'anonymous'; document.title = 'Watching :D'; const sourceEle = document.createElement('source'); sourceEle.src = source; sourceEle.type = sourceType; video.appendChild(sourceEle); for (let i = 0; i < captions.length; i++) { const url = captions[i]; const lang = captionLanguages[i]; const label = captionLabels[i]; const track = document.createElement('track'); track.kind = 'subtitles'; track.label = label; track.srclang = lang; track.src = url; video.appendChild(track); } video.autoplay = true; container.appendChild(video); const player = new Plyr(video, { captions: { active: true, }, iconUrl: 'vendor/plyr-3.7.3.svg', }); player.on('ready', () => { const state = loadPlaybackState(source); console.log('setting start time', state); player.currentTime = state.time; console.log(player.currentTime); }); player.on('timeupdate', () => { savePlaybackState(source, { time: player.currentTime, }); }); } else { let base = '/videos/'; if (query !== null && query.base) { base = query.base; } if (!base.endsWith('/')) { base = base + '/'; } fetch(base+'media.json') .then(res => res.json()) .then(({ videos }) => { const ul = document.createElement('ul'); ul.classList.add('video-list'); for (const video of videos) { //if (!video.filename.includes('telescope')) continue; const query = [ ['source', base+video.filename], ['source_type', 'video/mp4'], ...video.subtitles.map(subName => ['captions', base+subName]), ...video.subtitles.map(subName => { const s = subName.split('.'); return ['caption_langs', s[s.length - 2]]; }), ...video.subtitles.map(subName => ['caption_labels', subName]), ]; const duration = parseTimestamp(video.duration); const thumbnail = video.thumbnail; const thumbnailContainer = document.createElement('div'); thumbnailContainer.classList.add('thumbnail-container'); const durationEle = document.createElement('p'); durationEle.classList.add('thumbnail-duration'); durationEle.innerText = formatTimestamp(duration); const img = document.createElement('img'); img.src = base+thumbnail; img.classList.add('thumbnail'); const qs = new URLSearchParams(query).toString(); const ele = document.createElement('li'); const a = document.createElement('a'); a.classList.add('video-card'); a.href = '#' + qs; const title = document.createElement('h2'); title.innerText = video.filename; thumbnailContainer.appendChild(img); thumbnailContainer.appendChild(durationEle); a.appendChild(thumbnailContainer); a.appendChild(title); ele.appendChild(a); ul.appendChild(ele); } container.appendChild(ul); }); } window.addEventListener('hashchange', (e) => { window.location.reload(); });