703 lines
24 KiB
TypeScript
703 lines
24 KiB
TypeScript
import Get from '../General/Get';
|
|
import Header from '../General/Header';
|
|
import UI from '../General/UI';
|
|
import { g, Conf, d, doc, E } from '../globals/globals';
|
|
import ImageHost from '../Images/ImageHost';
|
|
import Main from '../main/Main';
|
|
import $ from '../platform/$';
|
|
import $$ from '../platform/$$';
|
|
import CrossOrigin from '../platform/CrossOrigin';
|
|
import { dict } from '../platform/helpers';
|
|
import EmbeddingPage from './Embedding/Embed.html';
|
|
/*
|
|
* decaffeinate suggestions:
|
|
* DS102: Remove unnecessary code created because of implicit returns
|
|
* DS205: Consider reworking code to avoid use of IIFEs
|
|
* DS207: Consider shorter variations of null checks
|
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
|
*/
|
|
|
|
var Embedding = {
|
|
init() {
|
|
if (!['index', 'thread', 'archive'].includes(g.VIEW) || !Conf['Linkify'] || (!Conf['Embedding'] && !Conf['Link Title'] && !Conf['Cover Preview'])) { return; }
|
|
this.types = dict();
|
|
for (var type of this.ordered_types) { this.types[type.key] = type; }
|
|
|
|
if (Conf['Embedding'] && (g.VIEW !== 'archive')) {
|
|
this.dialog = UI.dialog('embedding',
|
|
{ innerHTML: EmbeddingPage });
|
|
this.media = $('#media-embed', this.dialog);
|
|
$.one(d, '4chanXInitFinished', this.ready);
|
|
$.on(d, 'IndexRefreshInternal', () => g.posts.forEach(function(post) {
|
|
for (post of [post, ...post.clones]) {
|
|
for (var embed of post.nodes.embedlinks) {
|
|
Embedding.cb.catalogRemove.call(embed);
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
if (Conf['Link Title']) {
|
|
return $.on(d, '4chanXInitFinished PostsInserted', function() {
|
|
for (var key in Embedding.types) {
|
|
var service = Embedding.types[key];
|
|
if (service.title?.batchSize) {
|
|
Embedding.flushTitles(service.title);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
events(post) {
|
|
let el, i, items;
|
|
if (g.VIEW === 'archive') { return; }
|
|
if (Conf['Embedding']) {
|
|
i = 0;
|
|
items = (post.nodes.embedlinks = $$('.embedder', post.nodes.comment));
|
|
while ((el = items[i++])) {
|
|
$.on(el, 'click', Embedding.cb.click);
|
|
if ($.hasClass(el, 'embedded')) { Embedding.cb.toggle.call(el); }
|
|
}
|
|
}
|
|
if (Conf['Cover Preview']) {
|
|
i = 0;
|
|
items = $$('.linkify', post.nodes.comment);
|
|
while ((el = items[i++])) {
|
|
var data;
|
|
if (data = Embedding.services(el)) {
|
|
Embedding.preview(data);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
},
|
|
|
|
process(link, post) {
|
|
let data;
|
|
if (!Conf['Embedding'] && !Conf['Link Title'] && !Conf['Cover Preview']) { return; }
|
|
if ($.x('ancestor::pre', link)) { return; }
|
|
if (data = Embedding.services(link)) {
|
|
data.post = post;
|
|
if (Conf['Embedding'] && (g.VIEW !== 'archive')) { Embedding.embed(data); }
|
|
if (Conf['Link Title']) { Embedding.title(data); }
|
|
if (Conf['Cover Preview'] && (g.VIEW !== 'archive')) { return Embedding.preview(data); }
|
|
}
|
|
},
|
|
|
|
services(link) {
|
|
const {href} = link;
|
|
for (var type of Embedding.ordered_types) {
|
|
var match;
|
|
if (match = type.regExp.exec(href)) {
|
|
return {key: type.key, uid: match[1], options: match[2], link};
|
|
}
|
|
}
|
|
},
|
|
|
|
embed(data) {
|
|
const {key, uid, options, link, post} = data;
|
|
const {href} = link;
|
|
|
|
$.addClass(link, key.toLowerCase());
|
|
|
|
const embed = $.el('a', {
|
|
className: 'embedder',
|
|
href: 'javascript:;'
|
|
}
|
|
,
|
|
{innerHTML: '(<span>un</span>embed)'});
|
|
|
|
const object = {key, uid, options, href};
|
|
for (var name in object) { var value = object[name]; embed.dataset[name] = value; }
|
|
|
|
$.on(embed, 'click', Embedding.cb.click);
|
|
$.after(link, [$.tn(' '), embed]);
|
|
post.nodes.embedlinks.push(embed);
|
|
|
|
if (Conf['Auto-embed'] && !Conf['Floating Embeds'] && !post.isFetchedQuote) {
|
|
if ($.hasClass(doc, 'catalog-mode')) {
|
|
return $.addClass(embed, 'embed-removed');
|
|
} else {
|
|
return Embedding.cb.toggle.call(embed);
|
|
}
|
|
}
|
|
},
|
|
|
|
ready() {
|
|
if (!Main.isThisPageLegit()) { return; }
|
|
$.addClass(Embedding.dialog, 'empty');
|
|
$.on($('.close', Embedding.dialog), 'click', Embedding.closeFloat);
|
|
$.on($('.move', Embedding.dialog), 'mousedown', Embedding.dragEmbed);
|
|
$.on($('.jump', Embedding.dialog), 'click', function() {
|
|
if (doc.contains(Embedding.lastEmbed)) { return Header.scrollTo(Embedding.lastEmbed); }
|
|
});
|
|
return $.add(d.body, Embedding.dialog);
|
|
},
|
|
|
|
closeFloat() {
|
|
delete Embedding.lastEmbed;
|
|
$.addClass(Embedding.dialog, 'empty');
|
|
return $.replace(Embedding.media.firstChild, $.el('div'));
|
|
},
|
|
|
|
dragEmbed() {
|
|
// only webkit can handle a blocking div
|
|
const {style} = Embedding.media;
|
|
if (Embedding.dragEmbed.mouseup) {
|
|
$.off(d, 'mouseup', Embedding.dragEmbed);
|
|
Embedding.dragEmbed.mouseup = false;
|
|
style.pointerEvents = '';
|
|
return;
|
|
}
|
|
$.on(d, 'mouseup', Embedding.dragEmbed);
|
|
Embedding.dragEmbed.mouseup = true;
|
|
return style.pointerEvents = 'none';
|
|
},
|
|
|
|
title(data) {
|
|
let service;
|
|
const {key, uid, options, link, post} = data;
|
|
if (!(service = Embedding.types[key].title)) { return; }
|
|
$.addClass(link, key.toLowerCase());
|
|
if (service.batchSize) {
|
|
(service.queue || (service.queue = [])).push(data);
|
|
if (service.queue.length >= service.batchSize) {
|
|
return Embedding.flushTitles(service);
|
|
}
|
|
} else {
|
|
return CrossOrigin.cache(service.api(uid), (function() { return Embedding.cb.title(this, data); }));
|
|
}
|
|
},
|
|
|
|
flushTitles(service) {
|
|
let data;
|
|
const {queue} = service;
|
|
if (!queue?.length) { return; }
|
|
service.queue = [];
|
|
const cb = function() {
|
|
for (data of queue) { Embedding.cb.title(this, data); }
|
|
};
|
|
return CrossOrigin.cache(service.api((() => {
|
|
const result = [];
|
|
for (data of queue) { result.push(data.uid);
|
|
}
|
|
return result;
|
|
})()), cb);
|
|
},
|
|
|
|
preview(data) {
|
|
let service;
|
|
const {key, uid, link} = data;
|
|
if (!(service = Embedding.types[key].preview)) { return; }
|
|
return $.on(link, 'mouseover', function(e) {
|
|
const src = service.url(uid);
|
|
const {height} = service;
|
|
const el = $.el('img', {
|
|
src,
|
|
id: 'ihover'
|
|
}
|
|
);
|
|
$.add(Header.hover, el);
|
|
return UI.hover({
|
|
root: link,
|
|
el,
|
|
latestEvent: e,
|
|
endEvents: 'mouseout click',
|
|
height
|
|
});
|
|
});
|
|
},
|
|
|
|
cb: {
|
|
click(e) {
|
|
e.preventDefault();
|
|
if (!$.hasClass(this, 'embedded') && (Conf['Floating Embeds'] || $.hasClass(doc, 'catalog-mode'))) {
|
|
let div;
|
|
if (!(div = Embedding.media.firstChild)) { return; }
|
|
$.replace(div, Embedding.cb.embed(this));
|
|
Embedding.lastEmbed = Get.postFromNode(this).nodes.root;
|
|
return $.rmClass(Embedding.dialog, 'empty');
|
|
} else {
|
|
return Embedding.cb.toggle.call(this);
|
|
}
|
|
},
|
|
|
|
toggle() {
|
|
if ($.hasClass(this, "embedded")) {
|
|
$.rm(this.nextElementSibling);
|
|
} else {
|
|
$.after(this, Embedding.cb.embed(this));
|
|
}
|
|
return $.toggleClass(this, 'embedded');
|
|
},
|
|
|
|
embed(a) {
|
|
// We create an element to embed
|
|
let el, type;
|
|
const container = $.el('div', {className: 'media-embed'});
|
|
$.add(container, (el = (type = Embedding.types[a.dataset.key]).el(a)));
|
|
|
|
// Set style values.
|
|
el.style.cssText = (type.style != null) ?
|
|
type.style
|
|
:
|
|
'border: none; width: 640px; height: 360px;';
|
|
|
|
return container;
|
|
},
|
|
|
|
catalogRemove() {
|
|
const isCatalog = $.hasClass(doc, 'catalog-mode');
|
|
if ((isCatalog && $.hasClass(this, 'embedded')) || (!isCatalog && $.hasClass(this, 'embed-removed'))) {
|
|
Embedding.cb.toggle.call(this);
|
|
return $.toggleClass(this, 'embed-removed');
|
|
}
|
|
},
|
|
|
|
title(req, data) {
|
|
let text;
|
|
const {key, uid, options, link, post} = data;
|
|
const service = Embedding.types[key].title;
|
|
|
|
let {status} = req;
|
|
if ([200, 304].includes(status) && service.status) {
|
|
status = service.status(req.response)[0];
|
|
}
|
|
|
|
if (!status) { return; }
|
|
|
|
text = `[${key}] ${(() => { switch (status) {
|
|
case 200: case 304:
|
|
text = service.text(req.response, uid);
|
|
if (typeof text === 'string') {
|
|
return text;
|
|
} else {
|
|
return text = link.textContent;
|
|
}
|
|
case 404:
|
|
return "Not Found";
|
|
case 403: case 401:
|
|
return "Forbidden or Private";
|
|
default:
|
|
return `${status}'d`;
|
|
} })()
|
|
}`;
|
|
|
|
link.dataset.original = link.textContent;
|
|
link.textContent = text;
|
|
for (var post2 of post.clones) {
|
|
for (var link2 of $$('a.linkify', post2.nodes.comment)) {
|
|
if (link2.href === link.href) {
|
|
if (link2.dataset.original == null) { link2.dataset.original = link2.textContent; }
|
|
link2.textContent = text;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
ordered_types: [{
|
|
key: 'audio',
|
|
regExp: /^[^?#]+\.(?:mp3|m4a|oga|wav|flac)(?:[?#]|$)/i,
|
|
style: '',
|
|
el(a) {
|
|
return $.el('audio', {
|
|
controls: true,
|
|
preload: 'auto',
|
|
src: a.dataset.href
|
|
}
|
|
);
|
|
}
|
|
}
|
|
, {
|
|
key: 'image',
|
|
regExp: /^[^?#]+\.(?:gif|png|jpg|jpeg|bmp|webp)(?::\w+)?(?:[?#]|$)/i,
|
|
style: '',
|
|
el(a) {
|
|
const hrefEsc = E(a.dataset.href);
|
|
return $.el('div', { innerHTML: `<a target="_blank" href="${hrefEsc}"><img src="${hrefEsc}" style="max-width: 80vw; max-height: 80vh;"></a>`});
|
|
}
|
|
}
|
|
, {
|
|
key: 'video',
|
|
regExp: /^[^?#]+\.(?:og[gv]|webm|mp4)(?:[?#]|$)/i,
|
|
style: 'max-width: 80vw; max-height: 80vh;',
|
|
el(a) {
|
|
const el = $.el('video', {
|
|
hidden: true,
|
|
controls: true,
|
|
preload: 'auto',
|
|
src: a.dataset.href,
|
|
loop: ImageHost.test(a.dataset.href.split('/')[2])
|
|
});
|
|
$.on(el, 'loadedmetadata', function() {
|
|
if ((el.videoHeight === 0) && el.parentNode) {
|
|
return $.replace(el, Embedding.types.audio.el(a));
|
|
} else {
|
|
return el.hidden = false;
|
|
}
|
|
});
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'PeerTube',
|
|
regExp: /^(\w+:\/\/[^\/]+\/videos\/watch\/\w{8}-\w{4}-\w{4}-\w{4}-\w{12})(.*)/,
|
|
el(a) {
|
|
let start;
|
|
const options = (start = a.dataset.options.match(/[?&](start=\w+)/)) ? `?${start[1]}` : '';
|
|
const el = $.el('iframe',
|
|
{src: a.dataset.uid.replace('/videos/watch/', '/videos/embed/') + options});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'BitChute',
|
|
regExp: /^\w+:\/\/(?:www\.)?bitchute\.com\/video\/([\w\-]+)/,
|
|
el(a) {
|
|
const el = $.el('iframe',
|
|
{src: `https://www.bitchute.com/embed/${a.dataset.uid}/`});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'Clyp',
|
|
regExp: /^\w+:\/\/(?:www\.)?clyp\.it\/(\w{8})/,
|
|
style: 'border: 0; width: 640px; height: 160px;',
|
|
el(a) {
|
|
return $.el('iframe',
|
|
{src: `https://clyp.it/${a.dataset.uid}/widget`});
|
|
},
|
|
title: {
|
|
api(uid) { return `https://api.clyp.it/oembed?url=https://clyp.it/${uid}`; },
|
|
text(_) { return _.title; }
|
|
}
|
|
}
|
|
, {
|
|
key: 'Dailymotion',
|
|
regExp: /^\w+:\/\/(?:(?:www\.)?dailymotion\.com\/(?:embed\/)?video|dai\.ly)\/([A-Za-z0-9]+)[^?]*(.*)/,
|
|
el(a) {
|
|
let start;
|
|
const options = (start = a.dataset.options.match(/[?&](start=\d+)/)) ? `?${start[1]}` : '';
|
|
const el = $.el('iframe',
|
|
{src: `//www.dailymotion.com/embed/video/${a.dataset.uid}${options}`});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
},
|
|
title: {
|
|
api(uid) { return `https://api.dailymotion.com/video/${uid}`; },
|
|
text(_) { return _.title; }
|
|
},
|
|
preview: {
|
|
url(uid) { return `https://www.dailymotion.com/thumbnail/video/${uid}`; },
|
|
height: 240
|
|
}
|
|
}
|
|
, {
|
|
key: 'Gfycat',
|
|
regExp: /^\w+:\/\/(?:www\.)?gfycat\.com\/(?:iframe\/)?(\w+)/,
|
|
el(a) {
|
|
const el = $.el('iframe',
|
|
{src: `//gfycat.com/ifr/${a.dataset.uid}`});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'Gist',
|
|
regExp: /^\w+:\/\/gist\.github\.com\/[\w\-]+\/(\w+)/,
|
|
style: '',
|
|
el: (function() {
|
|
let counter = 0;
|
|
return function(a) {
|
|
const el = $.el('pre', {
|
|
hidden: true,
|
|
id: `gist-embed-${counter++}`
|
|
}
|
|
);
|
|
CrossOrigin.cache(`https://api.github.com/gists/${a.dataset.uid}`, function() {
|
|
el.textContent = Object.values(this.response.files)[0].content;
|
|
el.className = 'prettyprint';
|
|
$.global(() => window.prettyPrint?.((function() {}), document.getElementById(document.currentScript.dataset.id).parentNode)
|
|
, {id: el.id});
|
|
return el.hidden = false;
|
|
});
|
|
return el;
|
|
};
|
|
})(),
|
|
title: {
|
|
api(uid) { return `https://api.github.com/gists/${uid}`; },
|
|
text({files}) {
|
|
for (var file in files) { if (files.hasOwnProperty(file)) { return file; } }
|
|
}
|
|
}
|
|
}
|
|
, {
|
|
key: 'InstallGentoo',
|
|
regExp: /^\w+:\/\/paste\.installgentoo\.com\/view\/(?:raw\/|download\/|embed\/)?(\w+)/,
|
|
el(a) {
|
|
return $.el('iframe',
|
|
{src: `https://paste.installgentoo.com/view/embed/${a.dataset.uid}`});
|
|
}
|
|
}
|
|
, {
|
|
key: 'LiveLeak',
|
|
regExp: /^\w+:\/\/(?:\w+\.)?liveleak\.com\/.*\?.*[tif]=(\w+)/,
|
|
el(a) {
|
|
const el = $.el('iframe',
|
|
{src: `https://www.liveleak.com/e/${a.dataset.uid}`,});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'Loopvid',
|
|
regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\/#?((?:pf|kd|lv|gd|gh|db|dx|nn|cp|wu|ig|ky|mf|m2|pc|1c|pi|ni|wl|ko|mm|ic|gc)\/[\w\-\/]+(?:,[\w\-\/]+)*|fc\/\w+\/\d+|https?:\/\/.+)/,
|
|
style: 'max-width: 80vw; max-height: 80vh;',
|
|
el(a) {
|
|
const el = $.el('video', {
|
|
controls: true,
|
|
preload: 'auto',
|
|
loop: true
|
|
}
|
|
);
|
|
if (/^http/.test(a.dataset.uid)) {
|
|
$.add(el, $.el('source', {src: a.dataset.uid}));
|
|
return el;
|
|
}
|
|
const [_, host, names] = a.dataset.uid.match(/(\w+)\/(.*)/);
|
|
const types = (() => { switch (host) {
|
|
case 'gd': case 'wu': case 'fc': return [''];
|
|
case 'gc': return ['giant', 'fat', 'zippy'];
|
|
default: return ['.webm', '.mp4'];
|
|
} })();
|
|
for (var name of names.split(',')) {
|
|
for (var type of types) {
|
|
var base = `${name}${type}`;
|
|
var urls = (() => { switch (host) {
|
|
// list from src/common.py at http://loopvid.appspot.com/source.html
|
|
case 'pf': return [`https://kastden.org/_loopvid_media/pf/${base}`, `https://web.archive.org/web/2/http://a.pomf.se/${base}`];
|
|
case 'kd': return [`https://kastden.org/loopvid/${base}`];
|
|
case 'lv': return [`https://lv.kastden.org/${base}`];
|
|
case 'gd': return [`https://docs.google.com/uc?export=download&id=${base}`];
|
|
case 'gh': return [`https://googledrive.com/host/${base}`];
|
|
case 'db': return [`https://dl.dropboxusercontent.com/u/${base}`];
|
|
case 'dx': return [`https://dl.dropboxusercontent.com/${base}`];
|
|
case 'nn': return [`https://kastden.org/_loopvid_media/nn/${base}`];
|
|
case 'cp': return [`https://copy.com/${base}`];
|
|
case 'wu': return [`http://webmup.com/${base}/vid.webm`];
|
|
case 'ig': return [`https://i.imgur.com/${base}`];
|
|
case 'ky': return [`https://kastden.org/_loopvid_media/ky/${base}`];
|
|
case 'mf': return [`https://kastden.org/_loopvid_media/mf/${base}`, `https://web.archive.org/web/2/https://d.maxfile.ro/${base}`];
|
|
case 'm2': return [`https://kastden.org/_loopvid_media/m2/${base}`];
|
|
case 'pc': return [`https://kastden.org/_loopvid_media/pc/${base}`, `https://web.archive.org/web/2/http://a.pomf.cat/${base}`];
|
|
case '1c': return [`http://b.1339.cf/${base}`];
|
|
case 'pi': return [`https://kastden.org/_loopvid_media/pi/${base}`, `https://web.archive.org/web/2/https://u.pomf.is/${base}`];
|
|
case 'ni': return [`https://kastden.org/_loopvid_media/ni/${base}`, `https://web.archive.org/web/2/https://u.nya.is/${base}`];
|
|
case 'wl': return [`http://webm.land/media/${base}`];
|
|
case 'ko': return [`https://kordy.kastden.org/loopvid/${base}`];
|
|
case 'mm': return [`https://kastden.org/_loopvid_media/mm/${base}`, `https://web.archive.org/web/2/https://my.mixtape.moe/${base}`];
|
|
case 'ic': return [`https://media.8ch.net/file_store/${base}`];
|
|
case 'fc': return [`//${ImageHost.host()}/${base}.webm`];
|
|
case 'gc': return [`https://${type}.gfycat.com/${name}.webm`];
|
|
} })();
|
|
|
|
for (var url of urls) {
|
|
$.add(el, $.el('source', {src: url}));
|
|
}
|
|
}
|
|
}
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'Openings.moe',
|
|
regExp: /^\w+:\/\/openings.moe\/\?video=([^.&=]+)/,
|
|
style: 'width: 1280px; height: 720px; max-width: 80vw; max-height: 80vh;',
|
|
el(a) {
|
|
const el = $.el('iframe',
|
|
{src: `https://openings.moe/?video=${a.dataset.uid}`,});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'Pastebin',
|
|
regExp: /^\w+:\/\/(?:\w+\.)?pastebin\.com\/(?!u\/)(?:[\w.]+(?:\/|\?i\=))?(\w+)/,
|
|
el(a) {
|
|
let div;
|
|
return div = $.el('iframe',
|
|
{src: `//pastebin.com/embed_iframe.php?i=${a.dataset.uid}`});
|
|
}
|
|
}
|
|
, {
|
|
key: 'SoundCloud',
|
|
regExp: /^\w+:\/\/(?:www\.)?(?:soundcloud\.com\/|snd\.sc\/)([\w\-\/]+)/,
|
|
style: 'border: 0; width: 500px; height: 400px;',
|
|
el(a) {
|
|
return $.el('iframe',
|
|
{src: `https://w.soundcloud.com/player/?visual=true&show_comments=false&url=https%3A%2F%2Fsoundcloud.com%2F${encodeURIComponent(a.dataset.uid)}`});
|
|
},
|
|
title: {
|
|
api(uid) { return `${location.protocol}//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F${encodeURIComponent(uid)}`; },
|
|
text(_) { return _.title; }
|
|
}
|
|
}
|
|
, {
|
|
key: 'StrawPoll',
|
|
regExp: /^\w+:\/\/(?:www\.)?strawpoll\.me\/(?:embed_\d+\/)?(\d+(?:\/r)?)/,
|
|
style: 'border: 0; width: 600px; height: 406px;',
|
|
el(a) {
|
|
return $.el('iframe',
|
|
{src: `https://www.strawpoll.me/embed_1/${a.dataset.uid}`});
|
|
}
|
|
}
|
|
, {
|
|
key: 'Streamable',
|
|
regExp: /^\w+:\/\/(?:www\.)?streamable\.com\/(\w+)/,
|
|
el(a) {
|
|
const el = $.el('iframe',
|
|
{src: `https://streamable.com/o/${a.dataset.uid}`});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
},
|
|
title: {
|
|
api(uid) { return `https://api.streamable.com/oembed?url=https://streamable.com/${uid}`; },
|
|
text(_) { return _.title; }
|
|
}
|
|
}
|
|
, {
|
|
key: 'TwitchTV',
|
|
regExp: /^\w+:\/\/(?:www\.|secure\.|clips\.|m\.)?twitch\.tv\/(\w[^#\&\?]*)/,
|
|
el(a) {
|
|
let url;
|
|
let m = a.dataset.href.match(/^\w+:\/\/(?:(clips\.)|\w+\.)?twitch\.tv\/(?:\w+\/)?(clip\/)?(\w[^#\&\?]*)/);
|
|
if (m[1] || m[2]) {
|
|
url = `//clips.twitch.tv/embed?clip=${m[3]}&parent=${location.hostname}`;
|
|
} else {
|
|
let time;
|
|
m = a.dataset.uid.match(/(\w+)(?:\/(?:v\/)?(\d+))?/);
|
|
url = `//player.twitch.tv/?${m[2] ? `video=v${m[2]}` : `channel=${m[1]}`}&autoplay=false&parent=${location.hostname}`;
|
|
if (time = a.dataset.href.match(/\bt=(\w+)/)) {
|
|
url += `&time=${time[1]}`;
|
|
}
|
|
}
|
|
const el = $.el('iframe',
|
|
{src: url});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'Twitter',
|
|
regExp: /^\w+:\/\/(?:www\.|mobile\.)?(?:twitter|x)\.com\/(\w+\/status\/\d+)/,
|
|
style: 'border: none; width: 550px; height: 250px; overflow: hidden; resize: both;',
|
|
el(a) {
|
|
const el = $.el('iframe');
|
|
$.on(el, 'load', function() {
|
|
return this.contentWindow.postMessage({element: 't', query: 'height'}, 'https://twitframe.com');
|
|
});
|
|
var onMessage = function(e) {
|
|
if ((e.source === el.contentWindow) && (e.origin === 'https://twitframe.com')) {
|
|
$.off(window, 'message', onMessage);
|
|
return (cont || el).style.height = `${+$.minmax(e.data.height, 250, 0.8 * doc.clientHeight)}px`;
|
|
}
|
|
};
|
|
$.on(window, 'message', onMessage);
|
|
el.src = `https://twitframe.com/show?url=https://twitter.com/${a.dataset.uid}`;
|
|
if ($.engine === 'gecko') {
|
|
// XXX https://bugzilla.mozilla.org/show_bug.cgi?id=680823
|
|
el.style.cssText = 'border: none; width: 100%; height: 100%;';
|
|
var cont = $.el('div');
|
|
$.add(cont, el);
|
|
return cont;
|
|
} else {
|
|
return el;
|
|
}
|
|
}
|
|
}
|
|
, {
|
|
key: 'VidLii',
|
|
regExp: /^\w+:\/\/(?:www\.)?vidlii\.com\/watch\?v=(\w{11})/,
|
|
style: 'border: none; width: 640px; height: 392px;',
|
|
el(a) {
|
|
const el = $.el('iframe',
|
|
{src: `https://www.vidlii.com/embed?v=${a.dataset.uid}&a=0`});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'Vimeo',
|
|
regExp: /^\w+:\/\/(?:www\.)?vimeo\.com\/(\d+)/,
|
|
el(a) {
|
|
const el = $.el('iframe',
|
|
{src: `//player.vimeo.com/video/${a.dataset.uid}?wmode=opaque`});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
},
|
|
title: {
|
|
api(uid) { return `https://vimeo.com/api/oembed.json?url=https://vimeo.com/${uid}`; },
|
|
text(_) { return _.title; }
|
|
}
|
|
}
|
|
, {
|
|
key: 'Vine',
|
|
regExp: /^\w+:\/\/(?:www\.)?vine\.co\/v\/(\w+)/,
|
|
style: 'border: none; width: 500px; height: 500px;',
|
|
el(a) {
|
|
return $.el('iframe',
|
|
{src: `https://vine.co/v/${a.dataset.uid}/card`});
|
|
}
|
|
}
|
|
, {
|
|
key: 'Vocaroo',
|
|
regExp: /^\w+:\/\/(?:(?:www\.|old\.)?vocaroo\.com|voca\.ro)\/((?:i\/)?\w+)/,
|
|
style: '',
|
|
el(a) {
|
|
const el = $.el('iframe');
|
|
el.width = 300;
|
|
el.height = 60;
|
|
el.setAttribute('frameborder', 0);
|
|
el.src = `https://vocaroo.com/embed/${a.dataset.uid.replace(/^i\//, '')}?autoplay=0`;
|
|
return el;
|
|
}
|
|
}
|
|
, {
|
|
key: 'YouTube',
|
|
regExp: /^\w+:\/\/(?:youtu.be\/|[\w.]*youtube[\w.]*\/.*(?:v=|\bembed\/|\bv\/|live\/))([\w\-]{11})(.*)/,
|
|
el(a) {
|
|
let start = a.dataset.options.match(/\b(?:star)?t\=(\w+)/);
|
|
if (start) { start = start[1]; }
|
|
if (start && !/^\d+$/.test(start)) {
|
|
start += ' 0h0m0s';
|
|
start = (3600 * start.match(/(\d+)h/)[1]) + (60 * start.match(/(\d+)m/)[1]) + (1 * start.match(/(\d+)s/)[1]);
|
|
}
|
|
const el = $.el('iframe',
|
|
{src: `//www.youtube.com/embed/${a.dataset.uid}?rel=0&wmode=opaque${start ? '&start=' + start : ''}`});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
},
|
|
title: {
|
|
api(uid) { return `https://www.youtube.com/oembed?url=https%3A//www.youtube.com/watch%3Fv%3D${uid}&format=json`; },
|
|
text(_) { return _.title; },
|
|
status(_) {
|
|
if (_.error) {
|
|
const m = _.error.match(/^(\d*)\s*(.*)/);
|
|
return [+m[1], m[2]];
|
|
} else {
|
|
return [200, 'OK'];
|
|
}
|
|
}
|
|
},
|
|
preview: {
|
|
url(uid) { return `https://img.youtube.com/vi/${uid}/0.jpg`; },
|
|
height: 360
|
|
}
|
|
}
|
|
]
|
|
};
|
|
export default Embedding;
|