From 9b868b760ba3876dbaea7fe628e81dbca588aa96 Mon Sep 17 00:00:00 2001 From: ccd0 Date: Mon, 2 Feb 2015 02:49:28 -0800 Subject: [PATCH] Add link to extract titles from WebM metadata. --- src/General/Config.coffee | 4 ++ src/General/CrossOrigin.coffee | 87 ++++++++++++++++++---------------- src/General/Main.coffee | 1 + src/General/css/style.css | 3 ++ src/Images/Metadata.coffee | 64 +++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 40 deletions(-) create mode 100644 src/Images/Metadata.coffee diff --git a/src/General/Config.coffee b/src/General/Config.coffee index f90ffe884..c4d3508d5 100755 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -205,6 +205,10 @@ Config = true 'Add sauce links to images.' ] + 'WEBM Metadata': [ + true + 'Add link to fetch title metadata from webm videos.' + ] 'Reveal Spoiler Thumbnails': [ false 'Replace spoiler thumbnails with the original image.' diff --git a/src/General/CrossOrigin.coffee b/src/General/CrossOrigin.coffee index 748339bda..e70ad2744 100644 --- a/src/General/CrossOrigin.coffee +++ b/src/General/CrossOrigin.coffee @@ -10,8 +10,51 @@ CrossOrigin = do -> callbacks[id] = cb <% } %> - file: do -> - makeBlob = (urlBlob, contentType, contentDisposition, url) -> + binary: (url, cb, headers={}) -> + <% if (type === 'crx') { %> + if /^https:\/\//.test(url) or location.protocol is 'http:' + xhr = new XMLHttpRequest() + xhr.open 'GET', url, true + xhr.setRequestHeader key, value for key, value of headers + xhr.responseType = 'arraybuffer' + xhr.onload = -> + return cb null unless @readyState is @DONE and @status in [200, 206] + contentType = @getResponseHeader 'Content-Type' + contentDisposition = @getResponseHeader 'Content-Disposition' + cb new Uint8Array(@response), contentType, contentDisposition + xhr.onerror = xhr.onabort = -> + cb null + xhr.send() + else + eventPageRequest url, 'arraybuffer', ({response, contentType, contentDisposition, error}) -> + return cb null if error + cb new Uint8Array(response), contentType, contentDisposition + <% } %> + <% if (type === 'userscript') { %> + GM_xmlhttpRequest + method: "GET" + url: url + headers: headers + overrideMimeType: "text/plain; charset=x-user-defined" + onload: (xhr) -> + r = xhr.responseText + data = new Uint8Array r.length + i = 0 + while i < r.length + data[i] = r.charCodeAt i + i++ + contentType = xhr.responseHeaders.match(/Content-Type:\s*(.*)/i)?[1] + contentDisposition = xhr.responseHeaders.match(/Content-Disposition:\s*(.*)/i)?[1] + cb data, contentType, contentDisposition + onerror: -> + cb null + onabort: -> + cb null + <% } %> + + file: (url, cb) -> + CrossOrigin.binary url, (data, contentType, contentDisposition) -> + return cb null unless data? name = url.match(/([^\/]+)\/*$/)?[1] mime = contentType?.match(/[^;]*/)[0] or 'application/octet-stream' match = @@ -19,45 +62,9 @@ CrossOrigin = do -> contentType?.match(/\bname\s*=\s*"((\\"|[^"])+)"/i)?[1] if match name = match.replace /\\"/g, '"' - blob = new Blob([urlBlob], {type: mime}) + blob = new Blob([data], {type: mime}) blob.name = name - blob - - (url, cb) -> - <% if (type === 'crx') { %> - if /^https:\/\//.test(url) or location.protocol is 'http:' - $.ajax url, - responseType: 'blob' - onload: -> - return cb null unless @readyState is @DONE and @status is 200 - contentType = @getResponseHeader 'Content-Type' - contentDisposition = @getResponseHeader 'Content-Disposition' - cb (makeBlob @response, contentType, contentDisposition, url) - onerror: -> - cb null - else - eventPageRequest url, 'arraybuffer', ({response, contentType, contentDisposition, error}) -> - return cb null if error - cb (makeBlob new Uint8Array(response), contentType, contentDisposition, url) - <% } %> - <% if (type === 'userscript') { %> - GM_xmlhttpRequest - method: "GET" - url: url - overrideMimeType: "text/plain; charset=x-user-defined" - onload: (xhr) -> - r = xhr.responseText - data = new Uint8Array r.length - i = 0 - while i < r.length - data[i] = r.charCodeAt i - i++ - contentType = xhr.responseHeaders.match(/Content-Type:\s*(.*)/i)?[1] - contentDisposition = xhr.responseHeaders.match(/Content-Disposition:\s*(.*)/i)?[1] - cb (makeBlob data, contentType, contentDisposition, url) - onerror: -> - cb null - <% } %> + cb blob json: do -> callbacks = {} diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 981806ec1..a7ec5e25b 100755 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -342,6 +342,7 @@ Main = ['Image Loading', ImageLoader] ['Image Hover', ImageHover] ['Volume Control', Volume] + ['WEBM Metadata', Metadata] ['Comment Expansion', ExpandComment] ['Thread Expansion', ExpandThread] ['Thread Excerpt', ThreadExcerpt] diff --git a/src/General/css/style.css b/src/General/css/style.css index be473d727..8a0f7e78f 100755 --- a/src/General/css/style.css +++ b/src/General/css/style.css @@ -928,6 +928,9 @@ span.hide-announcement { .fileThumb > .warning { clear: both; } +a.webm-title.ready { + text-decoration: underline; +} input[name="Default Volume"] { width: 4em; height: 1ex; diff --git a/src/Images/Metadata.coffee b/src/Images/Metadata.coffee new file mode 100644 index 000000000..cfc75223b --- /dev/null +++ b/src/Images/Metadata.coffee @@ -0,0 +1,64 @@ +Metadata = + init: -> + return unless Conf['WEBM Metadata'] and g.VIEW in ['index', 'thread'] and g.BOARD.ID isnt 'f' + + Post.callbacks.push + name: 'WEBM Metadata' + cb: @node + + node: -> + return unless @file and /webm$/i.test @file.URL + if @isClone + link = $ '.webm-title', @file.text + else + link = $.el 'a', + className: 'webm-title ready' + href: 'javascript:;' + textContent: 'title' + $.add @file.text, [$.tn('\u00A0'), link] + $.on link, 'click', Metadata[if link.dataset.title? then 'toggle' else 'load'] + + load: -> + $.off @, 'click', Metadata.load + $.rmClass @, 'ready' + @textContent = '...' + CrossOrigin.binary Get.postFromNode(@).file.URL, (data) => + if data? + Metadata.parse.call @, data + $.on @, 'click', Metadata.toggle + else + @textContent = 'error' + $.on @, 'click', Metadata.load + , + Range: 'bytes=0-9999' + + parse: (data) -> + readInt = -> + n = data[i++] + len = 0 + len++ while n < (0x80 >> len) + n ^= (0x80 >> len) + while len-- and i < data.length + n = (n << 8) ^ data[i++] + n + + i = 0 + while i < data.length + element = readInt() + size = readInt() + if element is 0x3BA9 # Title + title = '' + while size-- and i < data.length + title += String.fromCharCode data[i++] + @textContent = @dataset.title = decodeURIComponent escape title # UTF-8 decoding + return + else unless element in [0x8538067, 0x549A966] # Segment, Info + i += size + @textContent = 'not found' + + toggle: -> + @textContent = if $.hasClass @, 'ready' + @dataset.title or 'not found' + else + 'title' + $.toggleClass @, 'ready'