From 789646614a483b8cd0c56a0295912a9faddf879c Mon Sep 17 00:00:00 2001 From: ccd0 Date: Thu, 25 Dec 2014 21:06:02 -0800 Subject: [PATCH] Break up Linkify.coffee. --- src/Linkification/Embedding.coffee | 365 +++++++++++++++++++++++++++++ src/Linkification/Linkify.coffee | 365 +---------------------------- 2 files changed, 368 insertions(+), 362 deletions(-) create mode 100644 src/Linkification/Embedding.coffee diff --git a/src/Linkification/Embedding.coffee b/src/Linkification/Embedding.coffee new file mode 100644 index 000000000..c8777052a --- /dev/null +++ b/src/Linkification/Embedding.coffee @@ -0,0 +1,365 @@ +Embedding = + init: -> + return unless Conf['Embedding'] or Conf['Link Title'] + @types = {} + @types[type.key] = type for type in @ordered_types + + if Conf['Link Title'] + $.on d, '4chanXInitFinished PostsInserted', -> + for key, service of Embedding.types when service.title?.batchSize + Embedding.flushTitles service.title + return + + events: (post) -> + return unless Conf['Embedding'] + i = 0 + items = $$ '.embedder', post.nodes.comment + while el = items[i++] + $.on el, 'click', Embedding.cb.toggle + Embedding.cb.toggle.call el if $.hasClass el, 'embedded' + return + + process: (link, post) -> + return unless Conf['Embedding'] or Conf['Link Title'] + return if $.x 'ancestor::pre', link + if data = Embedding.services link + data.post = post + Embedding.embed data if Conf['Embedding'] + Embedding.title data if Conf['Link Title'] + + services: (link) -> + {href} = link + for type in Embedding.ordered_types when match = type.regExp.exec href + return if type.dummy or type.httpOnly and location.protocol isnt 'http:' + return {key: type.key, uid: match[1], options: match[2], link} + return + + embed: (data) -> + {key, uid, options, link, post} = data + embed = $.el 'a', + className: 'embedder' + rel: 'nofollow noreferrer' + href: link.href + textContent: '(embed)' + + embed.dataset[name] = value for name, value of {key, uid, options} + + $.addClass link, "#{embed.dataset.key}" + + $.on embed, 'click', Embedding.cb.toggle + $.after link, [$.tn(' '), embed] + + if Conf['Auto-embed'] and !post.isFetchedQuote + $.asap (-> doc.contains embed), -> + Embedding.cb.toggle.call embed + + title: (data) -> + {key, uid, options, link, post} = data + return unless service = Embedding.types[key].title + if service.batchSize + (service.queue or= []).push data + if service.queue.length >= service.batchSize + Embedding.flushTitles service + else + unless $.cache service.api(uid), (-> Embedding.cb.title @, data), {responseType: 'json'} + $.extend link, <%= html('[${key}] Title Link Blocked (are you using NoScript?)') %> + + flushTitles: (service) -> + {queue} = service + return unless queue?.length + service.queue = [] + cb = -> + Embedding.cb.title @, data for data in queue + return + unless $.cache service.api(data.uid for data in queue), cb, {responseType: 'json'} + for data in queue + $.extend data.link, <%= html('[${data.key}] Title Link Blocked (are you using NoScript?)') %> + return + + cb: + toggle: (e) -> + e?.preventDefault() + if $.hasClass @, "embedded" + $.rm @previousElementSibling unless $.hasClass @previousElementSibling, 'linkify' + @previousElementSibling.hidden = false + @textContent = '(embed)' + else + @previousElementSibling.hidden = true + $.before @, Embedding.cb.embed @ + @textContent = '(unembed)' + $.toggleClass @, 'embedded' + + embed: (a) -> + # We create an element to embed + el = (type = Embedding.types[a.dataset.key]).el a + + # Set style values. + el.style.cssText = if type.style? + type.style + else + "border: 0; width: 640px; height: 390px" + + return el + + title: (req, data) -> + {key, uid, options, link, post} = data + {status} = req + service = Embedding.types[key].title + + text = "[#{key}] #{switch status + when 200, 304 + service.text req.response, uid + when 404 + "Not Found" + when 403 + "Forbidden or Private" + else + "#{status}'d" + }" + + link.dataset.original = link.textContent + link.textContent = text + for post2 in post.clones + for link2 in $$ 'a.linkify', post2.nodes.comment when link2.href is link.href + link2.dataset.original = link2.textContent + link2.textContent = text + return + + ordered_types: [ + key: 'audio' + regExp: /\.(?:mp3|ogg|wav)(?:\?|$)/i + style: '' + el: (a) -> + $.el 'audio', + controls: true + preload: 'auto' + src: a.href + , + key: 'gist' + regExp: /^\w+:\/\/gist\.github\.com\/(?:[\w\-]+\/)?(\w+)/ + el: (a) -> + el = $.el 'iframe' + el.setAttribute 'sandbox', 'allow-scripts' + content = <%= html('${a.dataset.uid}') %> + el.src = "data:text/html;charset=utf-8,#{encodeURIComponent content.innerHTML}" + el + title: + api: (uid) -> "https://api.github.com/gists/#{uid}" + text: ({files}) -> + return file for file of files when files.hasOwnProperty file + , + key: 'image' + regExp: /\.(?:gif|png|jpg|jpeg|bmp)(?:\?|$)/i + style: 'border: 0; width: auto; height: auto;' + el: (a) -> + $.el 'div', <%= html('') %> + , + key: 'InstallGentoo' + regExp: /^\w+:\/\/paste\.installgentoo\.com\/view\/(?:raw\/|download\/|embed\/)?(\w+)/ + el: (a) -> + $.el 'iframe', + src: "https://paste.installgentoo.com/view/embed/#{a.dataset.uid}" + , + key: 'Twitter' + regExp: /^\w+:\/\/(?:www\.)?twitter\.com\/(\w+\/status\/\d+)/ + el: (a) -> + $.el 'iframe', + src: "https://twitframe.com/show?url=https://twitter.com/#{a.dataset.uid}" + , + key: 'LiveLeak' + regExp: /^\w+:\/\/(?:\w+\.)?liveleak\.com\/.*\?.*i=(\w+)/ + httpOnly: true + el: (a) -> + el = $.el 'iframe', + width: "640", + height: "360", + src: "http://www.liveleak.com/ll_embed?i=#{a.dataset.uid}", + frameborder: "0" + el.setAttribute "allowfullscreen", "true" + el + , + key: 'MediaCrush' + regExp: /^\w+:\/\/(?:www\.)?mediacru\.sh\/([\w\-]+)/ + style: 'border: 0;' + el: (a) -> + el = $.el 'div' + $.queueTask -> $.cache "https://mediacru.sh/#{a.dataset.uid}.json", -> + return unless doc.contains el + {status} = @ + return el.textContent = "ERROR #{status}" unless status in [200, 304] + {files} = @response + for type in ['video/mp4', 'video/webm', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'audio/mpeg', 'audio/ogg'] + for file in files + if file.type is type + embed = file + break + break if embed + return el.textContent = "ERROR: Not a valid filetype" unless embed + switch embed.type + when 'video/mp4', 'video/webm', 'video/ogv' + $.extend el, <%= html('') %> + for ext, i in ['mp4', 'webm'] + el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}" + when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg' + $.extend el, <%= html('') %> + when 'audio/mpeg', 'audio/ogg' + $.extend el, <%= html('') %> + else + el.textContent = "ERROR: No valid filetype." + return + el + , + key: 'pastebin' + regExp: /^\w+:\/\/(?:\w+\.)?pastebin\.com\/(?!u\/)(?:[\w\.]+\?i\=)?(\w+)/ + httpOnly: true + el: (a) -> + div = $.el 'iframe', + src: "http://pastebin.com/embed_iframe.php?i=#{a.dataset.uid}" + , + key: 'gfycat' + regExp: /^\w+:\/\/(?:www\.)?gfycat\.com\/(?:iframe\/)?(\w+)/ + el: (a) -> + div = $.el 'iframe', + src: "//gfycat.com/iframe/#{a.dataset.uid}" + , + key: 'SoundCloud' + regExp: /^\w+:\/\/(?:www\.)?(?:soundcloud\.com\/|snd\.sc\/)([\w\-\/]+)/ + style: 'border: 0; width: 500px; height: 400px;' + el: (a) -> + $.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) -> "//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent uid}" + text: (_) -> _.title + , + key: 'StrawPoll' + regExp: /^\w+:\/\/(?:www\.)?strawpoll\.me\/(?:embed_\d+\/)?(\d+(?:\/r)?)/ + httpOnly: true + style: 'border: 0; width: 600px; height: 406px;' + el: (a) -> + $.el 'iframe', + src: "http://strawpoll.me/embed_1/#{a.dataset.uid}" + , + key: 'TwitchTV' + regExp: /^\w+:\/\/(?:www\.)?twitch\.tv\/([^#\&\?]*)/ + httpOnly: true + style: "border: none; width: 640px; height: 360px;" + el: (a) -> + if result = /(\w+)\/([bc])\/(\d+)/i.exec a.dataset.uid + [_, channel, type, id] = result + idparam = {'b': 'archive_id', 'c': 'chapter_id'} + obj = $.el 'object', + data: 'http://www.twitch.tv/widgets/archive_embed_player.swf' + $.extend obj, <%= html('') %> + obj.children[1].value = "channel=#{channel}&start_volume=25&auto_play=false&#{idparam[type]}=#{id}" + obj + else + channel = (/(\w+)/.exec a.dataset.uid)[0] + obj = $.el 'object', + data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=#{channel}" + $.extend obj, <%= html('') %> + obj.children[1].value = "hostname=www.twitch.tv&channel=#{channel}&auto_play=true&start_volume=25" + obj + , + key: 'Vocaroo' + regExp: /^\w+:\/\/(?:www\.)?vocaroo\.com\/i\/(\w+)/ + style: '' + el: (a) -> + $.el 'audio', + controls: true + preload: 'auto' + src: "http://vocaroo.com/media_command.php?media=#{a.dataset.uid}&command=download_ogg" + , + key: 'Vimeo' + regExp: /^\w+:\/\/(?:www\.)?vimeo\.com\/(\d+)/ + el: (a) -> + $.el 'iframe', + src: "//player.vimeo.com/video/#{a.dataset.uid}?wmode=opaque" + title: + api: (uid) -> "https://vimeo.com/api/oembed.json?url=http://vimeo.com/#{uid}" + text: (_) -> _.title + , + key: 'Vine' + regExp: /^\w+:\/\/(?:www\.)?vine\.co\/v\/(\w+)/ + style: 'border: none; width: 500px; height: 500px;' + el: (a) -> + $.el 'iframe', + src: "https://vine.co/v/#{a.dataset.uid}/card" + , + key: 'YouTube' + regExp: /^\w+:\/\/(?:youtu.be\/|[\w\.]*youtube[\w\.]*\/.*(?:v=|\/embed\/|\/v\/|\/videos\/))([\w\-]{11})[^#\&\?]?(.*)/ + el: (a) -> + start = a.dataset.options.match /\b(?:star)?t\=(\w+)/ + start = start[1] if start + if start and !/^\d+$/.test start + start += ' 0h0m0s' + start = 3600 * start.match(/(\d+)h/)[1] + 60 * start.match(/(\d+)m/)[1] + 1 * start.match(/(\d+)s/)[1] + el = $.el 'iframe', + src: "//www.youtube.com/embed/#{a.dataset.uid}?wmode=opaque#{if start then '&start=' + start else ''}" + el.setAttribute "allowfullscreen", "true" + el + title: + batchSize: 50 + api: (uids) -> + ids = encodeURIComponent uids.join(',') + key = '<%= meta.youtubeAPIKey %>' + "https://www.googleapis.com/youtube/v3/videos?part=snippet&id=#{ids}&fields=items%28id%2Csnippet%28title%29%29&key=#{key}" + text: (data, uid) -> + for item in data.items when item.id is uid + return item.snippet.title + 'Not Found' + , + key: 'Loopvid' + regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\/((?:pf|kd|lv|mc|gd|gh|db|nn)\/[\w\-]+(,[\w\-]+)*|fc\/\w+\/\d+)/ + style: 'border: 0; width: auto; height: auto;' + el: (a) -> + el = $.el 'video', + controls: true + preload: 'auto' + loop: true + [_, host, names] = a.dataset.uid.match /(\w+)\/(.*)/ + types = if host in ['gd', 'fc'] then [''] else ['.webm', '.mp4'] + for name in names.split ',' + for type in types + base = "#{name}#{type}" + url = switch host + # list from src/loopvid.py at http://loopvid.appspot.com/source.html + when 'pf' then "http://a.pomf.se/#{base}" + when 'kd' then "http://kastden.org/loopvid/#{base}" + when 'lv' then "http://loopvid.mooo.com/videos/#{base}" + when 'mc' then "https://cdn.mediacru.sh/#{base}" + when 'gd' then "https://docs.google.com/uc?export=download&id=#{base}" + when 'gh' then "https://googledrive.com/host/#{base}" + when 'db' then "https://googledrive.com/host/#{base}" + when 'fc' then "//i.4cdn.org/#{base}.webm" + when 'nn' then "http://naenara.eu/loopvids/#{base}" + $.add el, $.el 'source', src: url + el + , + key: 'Clyp' + regExp: /^\w+:\/\/(?:www\.)?clyp\.it\/(\w+)/ + style: '' + el: (a) -> + $.el 'audio', + controls: true + preload: 'auto' + src: "http://clyp.it/#{a.dataset.uid}.ogg" + , + # dummy entries: not implemented but included to prevent them being wrongly embedded as a subsequent type + key: 'Loopvid-dummy' + regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\// + dummy: true + , + key: 'MediaFire-dummy' + regExp: /^\w+:\/\/(?:www\.)?mediafire.com\// + dummy: true + , + key: 'video' + regExp: /\.(?:ogv|webm|mp4)(?:\?|$)/i + style: 'border: 0; width: auto; height: auto;' + el: (a) -> + $.el 'video', + controls: true + preload: 'auto' + src: a.href + ] diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 51c4ac7ec..caf7e39f6 100755 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -2,9 +2,6 @@ Linkify = init: -> return if g.VIEW is 'catalog' or not Conf['Linkify'] - @types = {} - @types[type.key] = type for type in @ordered_types - if Conf['Comment Expansion'] ExpandComment.callbacks.push @node @@ -12,21 +9,10 @@ Linkify = name: 'Linkify' cb: @node - $.on d, '4chanXInitFinished PostsInserted', -> - for key, service of Linkify.types when service.title?.batchSize - Linkify.flushTitles service.title - return - - events: (post) -> - i = 0 - items = $$ '.embedder', post.nodes.comment - while el = items[i++] - $.on el, 'click', Linkify.cb.toggle - Linkify.cb.toggle.call el if $.hasClass el, 'embedded' - return + Embedding.init() node: -> - return (if Conf['Embedding'] then Linkify.events @ else null) if @isClone + return Embedding.events @ if @isClone return unless Linkify.regString.test @info.comment test = /[^\s'"]+/g @@ -72,16 +58,9 @@ Linkify = i = links.length while i-- link = Linkify.makeLink links[i] - unless $.x 'ancestor::pre', link - Linkify.embedProcess link, @ + Embedding.process link, @ return - embedProcess: (link, post) -> - if data = Linkify.services link - data.post = post - Linkify.embed data if Conf['Embedding'] - Linkify.title data if Conf['Link Title'] - regString: ///( # http, magnet, ftp, etc (https?|mailto|git|magnet|ftp|irc):( @@ -149,341 +128,3 @@ Linkify = range.detach() a - - services: (link) -> - {href} = link - for type in Linkify.ordered_types when match = type.regExp.exec href - return if type.dummy or type.httpOnly and location.protocol isnt 'http:' - return {key: type.key, uid: match[1], options: match[2], link} - return - - embed: (data) -> - {key, uid, options, link, post} = data - embed = $.el 'a', - className: 'embedder' - rel: 'nofollow noreferrer' - href: link.href - textContent: '(embed)' - - embed.dataset[name] = value for name, value of {key, uid, options} - - $.addClass link, "#{embed.dataset.key}" - - $.on embed, 'click', Linkify.cb.toggle - $.after link, [$.tn(' '), embed] - - if Conf['Auto-embed'] and !post.isFetchedQuote - $.asap (-> doc.contains embed), -> - Linkify.cb.toggle.call embed - - title: (data) -> - {key, uid, options, link, post} = data - return unless service = Linkify.types[key].title - if service.batchSize - (service.queue or= []).push data - if service.queue.length >= service.batchSize - Linkify.flushTitles service - else - unless $.cache service.api(uid), (-> Linkify.cb.title @, data), {responseType: 'json'} - $.extend link, <%= html('[${key}] Title Link Blocked (are you using NoScript?)') %> - - flushTitles: (service) -> - {queue} = service - return unless queue?.length - service.queue = [] - cb = -> - Linkify.cb.title @, data for data in queue - return - unless $.cache service.api(data.uid for data in queue), cb, {responseType: 'json'} - for data in queue - $.extend data.link, <%= html('[${data.key}] Title Link Blocked (are you using NoScript?)') %> - return - - cb: - toggle: (e) -> - e?.preventDefault() - if $.hasClass @, "embedded" - $.rm @previousElementSibling unless $.hasClass @previousElementSibling, 'linkify' - @previousElementSibling.hidden = false - @textContent = '(embed)' - else - @previousElementSibling.hidden = true - $.before @, Linkify.cb.embed @ - @textContent = '(unembed)' - $.toggleClass @, 'embedded' - - embed: (a) -> - # We create an element to embed - el = (type = Linkify.types[a.dataset.key]).el a - - # Set style values. - el.style.cssText = if type.style? - type.style - else - "border: 0; width: 640px; height: 390px" - - return el - - title: (req, data) -> - {key, uid, options, link, post} = data - {status} = req - service = Linkify.types[key].title - - text = "[#{key}] #{switch status - when 200, 304 - service.text req.response, uid - when 404 - "Not Found" - when 403 - "Forbidden or Private" - else - "#{status}'d" - }" - - link.dataset.original = link.textContent - link.textContent = text - for post2 in post.clones - for link2 in $$ 'a.linkify', post2.nodes.comment when link2.href is link.href - link2.dataset.original = link2.textContent - link2.textContent = text - return - - ordered_types: [ - key: 'audio' - regExp: /\.(?:mp3|ogg|wav)(?:\?|$)/i - style: '' - el: (a) -> - $.el 'audio', - controls: true - preload: 'auto' - src: a.href - , - key: 'gist' - regExp: /^\w+:\/\/gist\.github\.com\/(?:[\w\-]+\/)?(\w+)/ - el: (a) -> - el = $.el 'iframe' - el.setAttribute 'sandbox', 'allow-scripts' - content = <%= html('${a.dataset.uid}') %> - el.src = "data:text/html;charset=utf-8,#{encodeURIComponent content.innerHTML}" - el - title: - api: (uid) -> "https://api.github.com/gists/#{uid}" - text: ({files}) -> - return file for file of files when files.hasOwnProperty file - , - key: 'image' - regExp: /\.(?:gif|png|jpg|jpeg|bmp)(?:\?|$)/i - style: 'border: 0; width: auto; height: auto;' - el: (a) -> - $.el 'div', <%= html('') %> - , - key: 'InstallGentoo' - regExp: /^\w+:\/\/paste\.installgentoo\.com\/view\/(?:raw\/|download\/|embed\/)?(\w+)/ - el: (a) -> - $.el 'iframe', - src: "https://paste.installgentoo.com/view/embed/#{a.dataset.uid}" - , - key: 'Twitter' - regExp: /^\w+:\/\/(?:www\.)?twitter\.com\/(\w+\/status\/\d+)/ - el: (a) -> - $.el 'iframe', - src: "https://twitframe.com/show?url=https://twitter.com/#{a.dataset.uid}" - , - key: 'LiveLeak' - regExp: /^\w+:\/\/(?:\w+\.)?liveleak\.com\/.*\?.*i=(\w+)/ - httpOnly: true - el: (a) -> - el = $.el 'iframe', - width: "640", - height: "360", - src: "http://www.liveleak.com/ll_embed?i=#{a.dataset.uid}", - frameborder: "0" - el.setAttribute "allowfullscreen", "true" - el - , - key: 'MediaCrush' - regExp: /^\w+:\/\/(?:www\.)?mediacru\.sh\/([\w\-]+)/ - style: 'border: 0;' - el: (a) -> - el = $.el 'div' - $.queueTask -> $.cache "https://mediacru.sh/#{a.dataset.uid}.json", -> - return unless doc.contains el - {status} = @ - return el.textContent = "ERROR #{status}" unless status in [200, 304] - {files} = @response - for type in ['video/mp4', 'video/webm', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'audio/mpeg', 'audio/ogg'] - for file in files - if file.type is type - embed = file - break - break if embed - return el.textContent = "ERROR: Not a valid filetype" unless embed - switch embed.type - when 'video/mp4', 'video/webm', 'video/ogv' - $.extend el, <%= html('') %> - for ext, i in ['mp4', 'webm'] - el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}" - when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg' - $.extend el, <%= html('') %> - when 'audio/mpeg', 'audio/ogg' - $.extend el, <%= html('') %> - else - el.textContent = "ERROR: No valid filetype." - return - el - , - key: 'pastebin' - regExp: /^\w+:\/\/(?:\w+\.)?pastebin\.com\/(?!u\/)(?:[\w\.]+\?i\=)?(\w+)/ - httpOnly: true - el: (a) -> - div = $.el 'iframe', - src: "http://pastebin.com/embed_iframe.php?i=#{a.dataset.uid}" - , - key: 'gfycat' - regExp: /^\w+:\/\/(?:www\.)?gfycat\.com\/(?:iframe\/)?(\w+)/ - el: (a) -> - div = $.el 'iframe', - src: "//gfycat.com/iframe/#{a.dataset.uid}" - , - key: 'SoundCloud' - regExp: /^\w+:\/\/(?:www\.)?(?:soundcloud\.com\/|snd\.sc\/)([\w\-\/]+)/ - style: 'border: 0; width: 500px; height: 400px;' - el: (a) -> - $.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) -> "//soundcloud.com/oembed?format=json&url=https%3A%2F%2Fsoundcloud.com%2F#{encodeURIComponent uid}" - text: (_) -> _.title - , - key: 'StrawPoll' - regExp: /^\w+:\/\/(?:www\.)?strawpoll\.me\/(?:embed_\d+\/)?(\d+(?:\/r)?)/ - httpOnly: true - style: 'border: 0; width: 600px; height: 406px;' - el: (a) -> - $.el 'iframe', - src: "http://strawpoll.me/embed_1/#{a.dataset.uid}" - , - key: 'TwitchTV' - regExp: /^\w+:\/\/(?:www\.)?twitch\.tv\/([^#\&\?]*)/ - httpOnly: true - style: "border: none; width: 640px; height: 360px;" - el: (a) -> - if result = /(\w+)\/([bc])\/(\d+)/i.exec a.dataset.uid - [_, channel, type, id] = result - idparam = {'b': 'archive_id', 'c': 'chapter_id'} - obj = $.el 'object', - data: 'http://www.twitch.tv/widgets/archive_embed_player.swf' - $.extend obj, <%= html('') %> - obj.children[1].value = "channel=#{channel}&start_volume=25&auto_play=false&#{idparam[type]}=#{id}" - obj - else - channel = (/(\w+)/.exec a.dataset.uid)[0] - obj = $.el 'object', - data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=#{channel}" - $.extend obj, <%= html('') %> - obj.children[1].value = "hostname=www.twitch.tv&channel=#{channel}&auto_play=true&start_volume=25" - obj - , - key: 'Vocaroo' - regExp: /^\w+:\/\/(?:www\.)?vocaroo\.com\/i\/(\w+)/ - style: '' - el: (a) -> - $.el 'audio', - controls: true - preload: 'auto' - src: "http://vocaroo.com/media_command.php?media=#{a.dataset.uid}&command=download_ogg" - , - key: 'Vimeo' - regExp: /^\w+:\/\/(?:www\.)?vimeo\.com\/(\d+)/ - el: (a) -> - $.el 'iframe', - src: "//player.vimeo.com/video/#{a.dataset.uid}?wmode=opaque" - title: - api: (uid) -> "https://vimeo.com/api/oembed.json?url=http://vimeo.com/#{uid}" - text: (_) -> _.title - , - key: 'Vine' - regExp: /^\w+:\/\/(?:www\.)?vine\.co\/v\/(\w+)/ - style: 'border: none; width: 500px; height: 500px;' - el: (a) -> - $.el 'iframe', - src: "https://vine.co/v/#{a.dataset.uid}/card" - , - key: 'YouTube' - regExp: /^\w+:\/\/(?:youtu.be\/|[\w\.]*youtube[\w\.]*\/.*(?:v=|\/embed\/|\/v\/|\/videos\/))([\w\-]{11})[^#\&\?]?(.*)/ - el: (a) -> - start = a.dataset.options.match /\b(?:star)?t\=(\w+)/ - start = start[1] if start - if start and !/^\d+$/.test start - start += ' 0h0m0s' - start = 3600 * start.match(/(\d+)h/)[1] + 60 * start.match(/(\d+)m/)[1] + 1 * start.match(/(\d+)s/)[1] - el = $.el 'iframe', - src: "//www.youtube.com/embed/#{a.dataset.uid}?wmode=opaque#{if start then '&start=' + start else ''}" - el.setAttribute "allowfullscreen", "true" - el - title: - batchSize: 50 - api: (uids) -> - ids = encodeURIComponent uids.join(',') - key = '<%= meta.youtubeAPIKey %>' - "https://www.googleapis.com/youtube/v3/videos?part=snippet&id=#{ids}&fields=items%28id%2Csnippet%28title%29%29&key=#{key}" - text: (data, uid) -> - for item in data.items when item.id is uid - return item.snippet.title - 'Not Found' - , - key: 'Loopvid' - regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\/((?:pf|kd|lv|mc|gd|gh|db|nn)\/[\w\-]+(,[\w\-]+)*|fc\/\w+\/\d+)/ - style: 'border: 0; width: auto; height: auto;' - el: (a) -> - el = $.el 'video', - controls: true - preload: 'auto' - loop: true - [_, host, names] = a.dataset.uid.match /(\w+)\/(.*)/ - types = if host in ['gd', 'fc'] then [''] else ['.webm', '.mp4'] - for name in names.split ',' - for type in types - base = "#{name}#{type}" - url = switch host - # list from src/loopvid.py at http://loopvid.appspot.com/source.html - when 'pf' then "http://a.pomf.se/#{base}" - when 'kd' then "http://kastden.org/loopvid/#{base}" - when 'lv' then "http://loopvid.mooo.com/videos/#{base}" - when 'mc' then "https://cdn.mediacru.sh/#{base}" - when 'gd' then "https://docs.google.com/uc?export=download&id=#{base}" - when 'gh' then "https://googledrive.com/host/#{base}" - when 'db' then "https://googledrive.com/host/#{base}" - when 'fc' then "//i.4cdn.org/#{base}.webm" - when 'nn' then "http://naenara.eu/loopvids/#{base}" - $.add el, $.el 'source', src: url - el - , - key: 'Clyp' - regExp: /^\w+:\/\/(?:www\.)?clyp\.it\/(\w+)/ - style: '' - el: (a) -> - $.el 'audio', - controls: true - preload: 'auto' - src: "http://clyp.it/#{a.dataset.uid}.ogg" - , - # dummy entries: not implemented but included to prevent them being wrongly embedded as a subsequent type - key: 'Loopvid-dummy' - regExp: /^\w+:\/\/(?:www\.)?loopvid.appspot.com\// - dummy: true - , - key: 'MediaFire-dummy' - regExp: /^\w+:\/\/(?:www\.)?mediafire.com\// - dummy: true - , - key: 'video' - regExp: /\.(?:ogv|webm|mp4)(?:\?|$)/i - style: 'border: 0; width: auto; height: auto;' - el: (a) -> - $.el 'video', - controls: true - preload: 'auto' - src: a.href - ] -