@atmtfy/video-background
Version:
Automatic background video from various sources (Youtube, MP4, vimeo) with autoplay across devices. No JS dependencies.
194 lines (157 loc) • 5.38 kB
text/typescript
type CompiledSourcesOrFalse = CompiledSources | false
interface CompiledSources {
sources: SourcesShape, type: SourceType, url: string, breakpoints?:Array<number>
}
function compileSources(srcString:string|null): CompiledSourcesOrFalse {
if ( srcString == null) {
return false;
}
let src = srcString.trim()
let srcsToReturn:SourcesShape = [];
let srcStrings: string[]= [];
let sizeStrings = [];
let hasMultipleSrcs = false,
hasSizes = false;
if (src.indexOf(',') >= 0) {
//Looks like https://something 300w, https://something https://another one, else etc 500w,
sizeStrings = srcString.split(',');
if (sizeStrings.length >= 2) {
sizeStrings.forEach(sizeString => {
const splitString = sizeString.trim().split(' ');
if (splitString.length <= 1) {
srcsToReturn.push(prepareSingleSource(sizeString))
} else {
const size = parseInt(splitString[splitString.length -1].replace('w', ''));
splitString.forEach((string:string)=>{ srcsToReturn.push(prepareSingleSource(string, size))});
}
})
}
hasSizes = true;
}
if (src.indexOf(' ') >= 0) {
// logger.log('Has multiple sources separated by spaces')
if (sizeStrings.length >=2) {
} else {
const array = srcString.split(' ');
array.forEach(item=> { srcStrings.push(item.trim())})
}
srcStrings.forEach((string:string)=>{ srcsToReturn.push(prepareSingleSource(string))});
}
if (!hasSizes && !hasMultipleSrcs) {
//Build from single source
srcsToReturn.push(prepareSingleSource(src))
}
return cleanupSources(srcsToReturn);
}
/**
* Removes conflicting sources of different types (can only have one of each type)
*/
function cleanupSources(sources:SourcesShape): CompiledSources {
//Type first
let res:CompiledSources = {
type: sources[0].type,
url: sources[0].url,
sources: []
}
//Return object if only one.
if (typeof sources != 'object' || sources.length <= 1) {
res.sources = sources;
} else {
if (res.type == 'youtube' || res.type == 'vimeo' ) {
res.sources = [sources[0]];
} else {
// Get sizes
let sizes:Array<number> = [];
sources.forEach((source)=> {
if (!('maxWidth' in source) || typeof source.maxWidth != 'number') {
return
}
if (!sizes.includes(source.maxWidth)) {
sizes.push(source.maxWidth);
}
res.breakpoints = sizes;
})
res.sources = sources.filter(src=>{ return src.type == res.type });
}
}
return res;
}
function getSourceType(url:string|null):SourceType {
if (url == null) {
return "error";
}
const ytTest = new RegExp(/^(?:https?:)?(?:\/\/)?(?:youtu\.be\/|(?:www\.|m\.)?youtube\.com\/(?:watch|v|embed)(?:\.php)?(?:\?.*v=|\/))([a-zA-Z0-9\_-]{7,15})(?:[\?&][a-zA-Z0-9\_-]+=[a-zA-Z0-9\_-]+)*$/);
const vimeoTest = new RegExp(/\/\/(?:www\.)?vimeo.com\/([0-9a-z\-_]+)/i);
const videoTest = new RegExp(/.*?\/.*(webm|mp4|ogg|ogm).*?/i);
if (ytTest.test(url)) {
return 'youtube'
} else if (vimeoTest.test(url)) {
return 'vimeo'
} else if (videoTest.test(url)) {
return 'local'
} else {
return 'error'
}
}
function prepareSingleSource(url:string, size: number|false = false):LocalSource|Source {
const urlType = getSourceType(url);
let returner:Source|LocalSource = {
url: url,
type: urlType,
}
if (urlType == 'local' ) {
const ft = getFileType(url)
if (ft) {
return {...returner, maxWidth: size, fileType: ft}
}
}
return returner;
}
function getSourcesFilteredBySize(sources:SourcesShape, breakpoints?:number[]):LocalSource[] {
const wW = window.innerWidth;
let sortedBySize:SizedSources = { 'max' : []};
sources.forEach((source)=> {
if (('maxWidth' in source) && source.maxWidth ) {
const w = source.maxWidth.toString();
if (sortedBySize != undefined && !Object.keys(sortedBySize).includes(w)) {
sortedBySize[w] = [ source ];
} else {
sortedBySize[w].push(source);
}
} else if ('maxWidth' in source) {
sortedBySize['max'].push(source)
}
})
if (!breakpoints) {
return sources.map((src:Source|LocalSource) => {
return {
url: src.url,
type: 'local',
fileType: getFileType(src.url)
}
});
}
let breakpointsWithPresent = [...breakpoints, wW].sort((a, b) => a - b)
const currentIndex = breakpointsWithPresent.indexOf(wW);
if (currentIndex == breakpointsWithPresent.length - 1) {
return sortedBySize['max'];
} else {
return sortedBySize[breakpointsWithPresent[currentIndex+1].toString()];
}
}
function getFileType(url:string):FileType {
if (url.includes('.mp4')) {
return 'mp4';
}
if (url.includes('.webm')) {
return 'webm';
}
if (url.includes('.ogg')) {
return 'ogg';
}
if (url.includes('.ogm')) {
return 'ogm';
}
return 'mp4'
}
export { getSourceType, compileSources, getFileType, prepareSingleSource , getSourcesFilteredBySize}