diff --git a/src/lib/components/ScriptureViewSofria.svelte b/src/lib/components/ScriptureViewSofria.svelte index 09416af31..aa1e3814e 100644 --- a/src/lib/components/ScriptureViewSofria.svelte +++ b/src/lib/components/ScriptureViewSofria.svelte @@ -41,7 +41,7 @@ LOGGING: updateSelections } from '$lib/scripts/verseSelectUtil'; import { prepareAudioPhraseEndChars, parsePhrase } from '$lib/scripts/parsePhrase'; - import { createVideoBlock, addVideoLinks } from '$lib/video'; + import { createVideoBlock, addVideoLinks, createVideoBlockFromUrl } from '$lib/video'; import { loadDocSetIfNotLoaded } from '$lib/data/scripture'; import { seekToVerse, hasAudioPlayed } from '$lib/data/audio'; import { @@ -2186,11 +2186,21 @@ LOGGING: case 'usfm:zvideo': { const id = element.atts['id'][0]; const video = config.videos.find((x) => x.id === id); - workspace.videoDiv = createVideoBlock( - document, - video, - workspace.currentVideoIndex++ - ); + if (video) { + workspace.videoDiv = createVideoBlock( + document, + video, + workspace.currentVideoIndex++ + ); + } else { + // Proskomma did replacement of slashes in id + const videoUrl = id.replace(/รท/g, '/'); + workspace.videoDiv = createVideoBlockFromUrl( + document, + videoUrl, + config.mainFeatures + ); + } break; } case 'usfm:zaudioc': { diff --git a/src/lib/video/index.ts b/src/lib/video/index.ts index 930bb52d6..a61ab4557 100644 --- a/src/lib/video/index.ts +++ b/src/lib/video/index.ts @@ -6,6 +6,7 @@ enum VideoType { Vimeo = 'vimeo', Jesus = 'jesus', Gospel = 'gospel', + Daily = 'daily', Other = 'other', Mp4 = 'mp4', Hls = 'hls' @@ -23,6 +24,8 @@ export function getVideoType(url: string): VideoType { type = VideoType.Jesus; } else if (url.includes('dbt.io')) { type = VideoType.Gospel; + } else if (url.includes('dai.ly')) { + type = VideoType.Daily; } else if (url.toLowerCase().endsWith('.mp4')) { type = VideoType.Mp4; } else if (url.toLowerCase().endsWith('.m3u8')) { @@ -33,6 +36,132 @@ export function getVideoType(url: string): VideoType { return type; } +function getYouTubeVideoId(url: string): string { + let id = ''; + + // Regular expression for YouTube URL pattern (e.g., youtube.com/watch?v=...) + let pattern = /https:\/\/(?:www\.)?youtube\.(?:\w+)\/watch\?v=([a-zA-Z0-9-_]+)(?:&.+)*/; + let match = url.match(pattern); + + if (match) { + // If match is found, extract the video ID + id = match[1]; + } else { + // Regular expression for shortened YouTube URL pattern (e.g., youtu.be/...) + pattern = /https:\/\/(?:www\.)?youtu\.be\/([a-zA-Z0-9-_]+)(?:&.+)*/; + match = url.match(pattern); + + if (match) { + id = match[1]; + } + } + + return id; +} + +export function getEmbeddedVideoUrl( + videoUrl: string, + autoplay: boolean, + features: { [key: string]: string } +) { + let returnUrl = videoUrl; + const type = getVideoType(videoUrl); + + switch (type) { + case VideoType.YouTube: + // YouTube video + // Transform https://www.youtube.com/watch?v=abcdefghijk to https://www.youtube.com/embed/abcdefghijk + const videoId = getYouTubeVideoId(videoUrl); + if (videoId) { + returnUrl = 'https://www.youtube.com/embed/' + videoId; + let hasParams = false; + + if (autoplay) { + returnUrl += '?audioplay=1'; + hasParams = true; + } + + if (features && features['video-youtube-related-same-channel']) { + // After Sept 2018, you will not be able to disable related videos. + // Instead, if the rel parameter is set to 0, related videos will come + // from the same channel as the video that was just played. + // https://developers.google.com/youtube/player_parameters + returnUrl += hasParams ? '&' : '?'; + returnUrl += 'rel=0'; + } + } + break; + + case VideoType.Vimeo: + // Vimeo video + // Transform https://vimeo.com/12345678 to https://player.vimeo.com/video/12345678 + let pattern = /https:\/\/(?:www\.)?vimeo\.(\w+)\/([0-9]+)/; + let match = returnUrl.match(pattern); + + if (match) { + // Construct the Vimeo embed URL + returnUrl = `https://player.vimeo.com/video/${match[2]}`; + + // Add autoplay parameter if autoplay is true + if (autoplay) { + returnUrl += '?autoplay=1'; + } + } + break; + + case VideoType.Daily: + pattern = /https?:\/\/dai\\.ly\/(.*)/; + match = returnUrl.match(pattern); + + if (match) { + returnUrl = `https://www.dailymotion.com/embed/video/${match[1]}`; + } + break; + + case VideoType.Jesus: + // Jesus Film Media + // Get the embed code from https://www.jesusfilm.org/watch, select video and click Share > Embed Code + // Example: + // https://api.arclight.org/videoPlayerUrl?refId=1_20917-jf6144-0-0&apiSessionId=5a1bda77c898d6.05342318&playerStyle=default&player=bc.vanilla5 + if (!returnUrl.includes('playerStyle')) { + returnUrl = returnUrl + '&playerStyle=default&player=bc.vanilla5'; + } + break; + + case VideoType.Hls: + // Do nothing + break; + } + + return returnUrl; +} + +export function createVideoBlockFromUrl( + document: Document, + videoUrl: string, + features: { [key: string]: string } +): HTMLElement { + const url = getEmbeddedVideoUrl(videoUrl, false, features); + + const videoBlockDiv = document.createElement('div'); + videoBlockDiv.classList.add('video-block'); + const videoContainerDiv = document.createElement('div'); + videoContainerDiv.classList.add('video-container'); + videoBlockDiv.appendChild(videoContainerDiv); + + videoContainerDiv.classList.add('video-16-9'); + const iframe = document.createElement('iframe'); + iframe.setAttribute('width', '420'); + iframe.setAttribute('src', url); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('webkitallowfullscreen', ''); + iframe.setAttribute('mozallowfullscreen', ''); + iframe.setAttribute('allowfullscreen', ''); + videoContainerDiv.appendChild(iframe); + + return videoBlockDiv; +} + export function createVideoBlock(document: Document, video: any, index: any): HTMLElement { const type = getVideoType(video.onlineUrl); const videoBlockDiv = document.createElement('div'); @@ -55,6 +184,7 @@ export function createVideoBlock(document: Document, video: any, index: any): HT case VideoType.Vimeo: case VideoType.Hls: case VideoType.Gospel: + case VideoType.Daily: case VideoType.Other: videoContainerDiv.classList.add('video-' + type, 'video-16-9'); break;