[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#736541: pu: package libquvi-scripts/0.4.21-1~deb7u1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: pu

Hi,

as the point release draws closer I would like to update
libquvi-scripts in Wheezy. As usual it contains changes for several
websites and also support for a new one (dorkly.com), cf. NEWS.

I've attached a diff with most of the version change noise removed.

Ansgar
diff -Nru libquvi-scripts-0.4.19/NEWS libquvi-scripts-0.4.21/NEWS
--- libquvi-scripts-0.4.19/NEWS	2013-10-04 16:02:50.000000000 +0200
+++ libquvi-scripts-0.4.21/NEWS	2013-11-30 16:52:15.000000000 +0100
@@ -1,3 +1,37 @@
+v0.4.21  (2013-11-30) / Toni Gundogdu
+
+Toni Gundogdu:
+  - FIX: website/101greatgoals: redirect: Add URL scheme [d1313ea]
+  - FIX: website/arte: Reimpl. support [7084f63]
+  - FIX: website/beeg: title pattern [6dd0013]
+  - FIX: website/cbsnews: Adapt to website changes [cda2d12]
+  - FIX: website/publicsenat: Reimpl. support [e33d3f9]
+  - FIX: website/senat: Reimpl. support [cf3210c]
+  - FIX: website/spankwire: Reimpl. support [33745ae]
+  - FIX: website/vimeo: Reimpl. support [ac21fa0]
+  - Mark website/imdb as "FIXME" [a3e6fb3]
+  - Mark website/justintv as "FIXME" [f50dc23]
+  - Mark website/wdrmaus as "FIXME" [547ba93]
+  - quvi/util: Add json_get function [43d2654]
+  - quvi/util: Add xml_get [e24824c]
+  - website/canalplus.lua: Add support for {d8,d17} [a505772]
+
+ 44 files changed, 539 insertions(+), 542 deletions(-)
+
+
+v0.4.20  (2013-11-04) / Toni Gundogdu
+
+Toni Gundogdu:
+  - Add website/dorkly.lua for dorkly.com [6528f5d]
+  - FIX: website/collegehumor.lua [168d954]
+  - FIX: website/redtube.lua: media stream URL pattern [ed756ef]
+  - FIX: website/tcmag.lua: Media stream URL pattern [e90c00d]
+  - website/arte.lua: Mark as FIXME [a823ef0]
+  - website/vimeo.lua: Mark as FIXME [a2279ff]
+
+ 14 files changed, 202 insertions(+), 189 deletions(-)
+
+
 v0.4.19  (2013-10-04) / Toni Gundogdu
 
 Toni Gundogdu:
diff -Nru libquvi-scripts-0.4.19/debian/changelog libquvi-scripts-0.4.21/debian/changelog
--- libquvi-scripts-0.4.19/debian/changelog	2013-10-05 10:35:31.000000000 +0200
+++ libquvi-scripts-0.4.21/debian/changelog	2014-01-24 19:52:00.000000000 +0100
@@ -1,3 +1,23 @@
+libquvi-scripts (0.4.21-1~deb7u1) wheezy; urgency=medium
+
+  * Upload to wheezy.
+
+ -- Ansgar Burchardt <ansgar@debian.org>  Fri, 24 Jan 2014 19:51:40 +0100
+
+libquvi-scripts (0.4.21-1) unstable; urgency=medium
+
+  * New upstream release.
+  * debian/copyright: Update for new upstream release.
+
+ -- Ansgar Burchardt <ansgar@debian.org>  Sun, 08 Dec 2013 23:05:16 +0100
+
+libquvi-scripts (0.4.20-1) unstable; urgency=low
+
+  * New upstream release.
+  * debian/copyright: Update for new upstream release.
+
+ -- Ansgar Burchardt <ansgar@debian.org>  Sun, 10 Nov 2013 13:09:22 +0100
+
 libquvi-scripts (0.4.19-1~deb7u1) wheezy; urgency=low
 
   * Upload to wheezy.
@@ -84,7 +104,7 @@
   * New upstream release.
   * Fix d/watch to allow xz|gz|bz2.
   * Add new entry to d/copyright (share/lua/website/tapuz.lua).
-  * Remove d/patches. Upstream author include patch. 
+  * Remove d/patches. Upstream author include patch.
 
  -- Alejandro Garrido Mota <garridomota@gmail.com>  Sun, 16 Dec 2012 10:07:38 -0430
 
@@ -149,7 +169,7 @@
 libquvi-scripts (0.4.2-1) unstable; urgency=low
 
   * New upstream release.
-  * d/control: 
+  * d/control:
      + Improve package description (thanks Ansgar) (Closes: #650984)
      + Switch Architecture field to all (Closes: #650983).
 
diff -Nru libquvi-scripts-0.4.19/debian/copyright libquvi-scripts-0.4.21/debian/copyright
--- libquvi-scripts-0.4.19/debian/copyright	2013-07-11 23:23:08.000000000 +0200
+++ libquvi-scripts-0.4.21/debian/copyright	2014-01-24 19:50:59.000000000 +0100
@@ -13,7 +13,8 @@
 Copyright: 2013, Thomas Weißschuh
 License: LGPL-2.1+
 
-Files: share/lua/website/tagtele.lua
+Files: share/lua/website/canalplus.lua
+       share/lua/website/tagtele.lua
        share/lua/website/keezmovies.lua
        share/lua/website/xhamster.lua
        share/lua/website/pornhub.lua
@@ -33,8 +34,13 @@
 Copyright: 2011, Thomas Preud'homme <robotux@celest.fr>
 License: LGPL-2.1+
 
+Files: share/lua/website/collegehumor.lua
+Copyright:
+ 2012-2013, Toni Gundogdu <legatvs@gmail.com>
+ 2010-2011, Lionel Elie Mamane <lionel@mamane.lu>
+License: LGPL-2.1+
+
 Files: share/lua/website/foxnews.lua
-       share/lua/website/collegehumor.lua
        share/lua/website/metacafe.lua
 Copyright: 2011 Lionel Elie Mamane <lionel@mamane.lu>
 License: LGPL-2.1+
@@ -42,7 +48,9 @@
 Files: share/lua/website/arte.lua
        share/lua/website/publicsenat.lua
        share/lua/website/senat.lua
-Copyright: 2011-2012, Raphaël Droz <raphael.droz+floss@gmail.com>
+Copyright:
+ 2013,      Toni Gundogdu <legatvs@gmail.com>
+ 2011-2012, Raphaël Droz <raphael.droz+floss@gmail.com>
 License: LGPL-2.1+
 
 Files: share/lua/website/tvrain.lua
diff -Nru libquvi-scripts-0.4.19/debian/gbp.conf libquvi-scripts-0.4.21/debian/gbp.conf
--- libquvi-scripts-0.4.19/debian/gbp.conf	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/debian/gbp.conf	2014-01-24 19:50:59.000000000 +0100
@@ -0,0 +1,3 @@
+[DEFAULT]
+debian-branch = sid-0.4.x
+upstream-branch = upstream-0.4.x
diff -Nru libquvi-scripts-0.4.19/share/Makefile.am libquvi-scripts-0.4.21/share/Makefile.am
--- libquvi-scripts-0.4.19/share/Makefile.am	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/share/Makefile.am	2013-11-30 16:50:24.000000000 +0100
@@ -22,13 +22,13 @@
  lua/website/canalplus.lua \
  lua/website/cbsnews.lua \
  lua/website/clipfish.lua \
+ lua/website/collegehumor.lua \
  lua/website/dailymotion.lua \
+ lua/website/dorkly.lua \
  lua/website/foxnews.lua \
  lua/website/funnyordie.lua \
  lua/website/gaskrank.lua \
  lua/website/guardian.lua \
- lua/website/imdb.lua \
- lua/website/justintv.lua \
  lua/website/lego.lua \
  lua/website/liveleak.lua \
  lua/website/metacafe.lua \
@@ -49,7 +49,6 @@
  lua/website/videa.lua \
  lua/website/videobash.lua \
  lua/website/vimeo.lua \
- lua/website/wdrmaus.lua \
  lua/website/wimp.lua \
  lua/website/youtube.lua
 
@@ -77,12 +76,14 @@
  lua/website/bloomberg.lua \
  lua/website/break.lua \
  lua/website/charlierose.lua \
- lua/website/collegehumor.lua \
  lua/website/francetelevisions.lua \
  lua/website/globo.lua \
  lua/website/golem.lua \
+ lua/website/imdb.lua \
+ lua/website/justintv.lua \
  lua/website/mgnetwork.lua \
- lua/website/pluzz.lua
+ lua/website/pluzz.lua \
+ lua/website/wdrmaus.lua
 if WITH_NSFW
 DIST_lua+=\
  lua/website/fastjizz.lua \
diff -Nru libquvi-scripts-0.4.19/share/lua/website/101greatgoals.lua libquvi-scripts-0.4.21/share/lua/website/101greatgoals.lua
--- libquvi-scripts-0.4.19/share/lua/website/101greatgoals.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/101greatgoals.lua	2013-11-30 16:53:31.000000000 +0100
@@ -94,8 +94,12 @@
 function HaOgg.chk_ext_content(self)
     local p = quvi.fetch(self.page_url)
 
-    self.redirect_url = HaOgg.chk_self_hosted(p) or HaOgg.chk_embedded(p)
-                          or error('unable to determine media source')
+    local r = HaOgg.chk_self_hosted(p) or HaOgg.chk_embedded(p)
+                  or error('unable to determine media source')
+
+    self.redirect_url = (not r:match('^%w+://'))
+                         and table.concat({'http:',r})
+                          or r
 
     return self
 end
diff -Nru libquvi-scripts-0.4.19/share/lua/website/arte.lua libquvi-scripts-0.4.21/share/lua/website/arte.lua
--- libquvi-scripts-0.4.19/share/lua/website/arte.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/arte.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,6 +1,6 @@
 
--- libquvi-scripts v0.4.19
--- Copyright (C) 2012  Toni Gundogdu <legatvs@gmail.com>
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2012,2013  Toni Gundogdu <legatvs@gmail.com>
 -- Copyright (C) 2011  Raphaël Droz <raphael.droz+floss@gmail.com>
 --
 -- This file is part of libquvi-scripts <http://quvi.googlecode.com/>.
@@ -28,24 +28,25 @@
 function ident(self)
     package.path = self.script_dir .. '/?.lua'
     local C      = require 'quvi/const'
-    local r      = {}
-    r.domain     = "videos%.arte%.tv"
-    r.formats    = "default|best"
-    r.categories = C.proto_rtmp
     local U      = require 'quvi/util'
-    r.handles    = U.handles(self.page_url, {r.domain}, {"/%w+/videos/"})
-    return r
+    local B      = require 'quvi/bit'
+    local d      = 'www%.arte%.tv'
+    return {
+        handles    = U.handles(self.page_url, {d}, {"/guide/%w+/"}),
+        categories = B.bit_or(C.proto_http, C.proto_rtmp),
+        formats    = 'default|best',
+        domain     = d
+    }
 end
 
 -- Query available formats.
 function query_formats(self)
-    local config  = Arte.get_config(self)
-    local U       = require 'quvi/util'
-    local formats = Arte.iter_formats(config, U)
+    local c,U = Arte.get_config(self)
+    local s = Arte.iter_streams(U, c)
 
     local t = {}
-    for _,v in pairs(formats) do
-        table.insert(t, Arte.to_s(v))
+    for _,v in pairs(s) do
+        table.insert(t, Arte.to_id(v))
     end
 
     table.sort(t)
@@ -57,18 +58,21 @@
 -- Parse media URL.
 function parse(self)
     self.host_id  = 'arte'
-    local config  = Arte.get_config(self)
-    local U       = require 'quvi/util'
-    local formats = Arte.iter_formats(config, U)
-    local format  = U.choose_format(self, formats,
-                                    Arte.choose_best,
-                                    Arte.choose_default,
-                                    Arte.to_s)
-                        or error("unable to choose format")
-    self.title         = format.title or error('no match: title')
-    self.id            = format.id or error('no match: id')
-    self.thumbnail_url = format.thumb or ''
-    self.url           = {format.url or error("no match: media url")}
+
+    local c,U = Arte.get_config(self)
+
+    self.duration = U.json_get(c, 'videoDurationSeconds', true) * 1000
+
+    self.thumbnail_url = U.json_get(c, 'programImage')
+
+    self.title = U.json_get(c, 'VTI')
+
+    self.id = U.json_get(c, 'VPI')
+
+    local c = U.choose_format(self, Arte.iter_streams(U,c), Arte.choose_best,
+                              Arte.choose_default, Arte.to_id)
+
+    self.url = {c.url or error("no match: media stream URL")}
 
     return self
 end
@@ -77,89 +81,94 @@
 -- Utility functions
 --
 
-function Arte.get_config(self)
-    local p = quvi.fetch(self.page_url)
-
-    local c_url = p:match('videorefFileUrl = "(.-)"')
-                    or error('no match: config URL')
-
-    return Arte.get_lang_config(quvi.fetch(c_url, {fetch_type='config'}))
-end
-
-function Arte.get_lang_config(config)
-    local t = {}
-    for lang,url in config:gmatch('<video lang="(%w+)" ref="(.-)"') do
-        table.insert(t, {lang=lang,
-                         config=quvi.fetch(url, {fetch_type = 'config'})})
+function Arte.iter_streams(U, c)
+    local s = c:match('"VSR":(.-)$') or error('no match: VSR')
+    local r = {}
+    for id,p in s:gmatch('"(.-)":{(.-)}') do
+        local m = U.json_get(p, 'streamer')
+        local u = U.json_get(p, 'url')
+        local g = (#m >0) and table.concat({m,'mp4:',u}) or u
+        local t = {
+            bitrate = U.json_get(p, 'bitrate', true),
+            height = U.json_get(p, 'height', true),
+            width = U.json_get(p, 'width', true),
+            quality = U.json_get(p, 'quality'),
+            -- Refer to 0.9+ script for the description of "versionProg".
+            vprog = tonumber(U.json_get(p, 'versionProg')),
+            vcode = U.json_get(p, 'versionCode'),
+            mtype = U.json_get(p, 'mediaType'),
+            url = g
+        }
+        table.insert(r,t)
     end
-    return t
+    return r
 end
 
-function Arte.iter_lang_formats(lang_config, t, U)
-
-    local p = '<video id="(%d+)" lang="(%w+)"'
-           .. '.-<name>(.-)<'
-           .. '.-<firstThumbnailUrl>(.-)<'
-           .. '.-<dateExpiration>(.-)<'
-           .. '.-<dateVideo>(.-)<'
+function Arte.get_config(self)
+    local p = quvi.fetch(self.page_url)
 
-    local config = lang_config.config
+    local u = p:match('arte_vp_url="(.-)">')
+                  or error('no match: config URL')
 
-    local id,lang,title,thumb,exp,date = config:match(p)
-    if not id then error("no match: media id, etc.") end
+    local c = quvi.fetch(u, {fetch_type='config'})
+    local U = require 'quvi/util'
 
-    if lang ~= lang_config.lang then
-        error("no match: lang")
+    local e = U.json_get(c, 'VRU')
+    if #e >0 and Arte.has_expired(U, e) then
+        error('media no longer available (expired)')
     end
 
-    if Arte.has_expired(exp, U) then
-        error('error: media no longer available (expired)')
-    end
+    return c,U
+end
 
-    local urls = config:match('<urls>(.-)</urls>')
-                  or error('no match: urls')
+function Arte.has_expired(U, s)
+    local d, mo, y, h, m, sc =
+              s:match('(%d+)/(%d+)/(%d+) (%d+):(%d+):(%d+)')
 
-    for q,u in urls:gmatch('<url quality="(%w+)">(.-)<') do
---        print(q,u)
-        table.insert(t, {lang=lang,   quality=q,   url=u,
-                         thumb=thumb, title=title, id=id})
-    end
-end
+    local t = os.time({ year = y, month = mo, day = d,
+                        hour = h, min = m, sec = sc })
 
-function Arte.iter_formats(config, U)
-    local t = {}
-    for _,v in pairs(config) do
-        Arte.iter_lang_formats(v, t, U)
-    end
-    return t
+    return (t - os.time()) < 0
 end
 
-function Arte.has_expired(s, U)
-    return U.to_timestamp(s) - os.time() < 0
+function Arte.is_best(a,b)
+    -- Select the default language version rather than the alternative.
+    -- refer to 0.9+ script for versionProg description.
+    if b.vprog ==2 and a.vprog ~= 2 then
+        return true
+    end
+    -- Select the default language version rather than the original.
+    if a.vprog < b.vprog then
+        return true
+    end
+    -- Otherwise, compare the resolution and the bitrate properties.
+    return a.height >b.height
+                or (a.height ==b.height and a.bitrate >b.bitrate)
 end
 
-function Arte.choose_best(formats) -- Whatever matches 'hd' first
-    local r
-    for _,v in pairs(formats) do
-        if Arte.to_s(v):match('hd') then
-            return v
+function Arte.choose_best(t)
+    local r = t[1]
+    for _,v in pairs(t) do
+        if Arte.is_best(v, r) then
+            r = v
         end
     end
     return r
 end
 
-function Arte.choose_default(formats) -- Whatever matches 'sd' first
-    local r
-    for _,v in pairs(formats) do
-        if Arte.to_s(v):match('sd') then
-            return v
+function Arte.choose_default(t)
+    for _,v in pairs(t) do
+        if Arte.to_id(v):match('sd') and t.mtype == 'rtmp' then
+            return v  -- Anything that matches 'SD'.
         end
     end
-    return r
+    return t[1]  -- Or whatever was returned as the first stream.
 end
 
-function Arte.to_s(t)
-    return string.format("%s_%s", t.quality, t.lang)
+function Arte.to_id(t)
+    local s = (#t.mtype ==0) and 'http' or t.mtype
+    return string.format('%s_%s_%s', t.quality, s, t.vcode)
+                          :gsub('%s?%-%s?', '_'):lower()
 end
 
 -- vim: set ts=4 sw=4 tw=72 expandtab:
diff -Nru libquvi-scripts-0.4.19/share/lua/website/beeg.lua libquvi-scripts-0.4.21/share/lua/website/beeg.lua
--- libquvi-scripts-0.4.19/share/lua/website/beeg.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/beeg.lua	2013-11-30 16:53:31.000000000 +0100
@@ -48,7 +48,7 @@
 
     local p = quvi.fetch(self.page_url)
 
-    self.title = p:match('<meta name="description" content="(.-)%.')
+    self.title = p:match('<title>(.-)%s+%-%s+beeg')
                   or error("no match: media title")
 
     self.url = {p:match("'file': '(http://.-)'")
diff -Nru libquvi-scripts-0.4.19/share/lua/website/canalplus.lua libquvi-scripts-0.4.21/share/lua/website/canalplus.lua
--- libquvi-scripts-0.4.19/share/lua/website/canalplus.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/canalplus.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,5 +1,6 @@
 
--- libquvi-scripts v0.4.19
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2013 Toni Gundogdu <legatvs@gmail.com>
 -- Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
 --
 -- This file is part of libquvi-scripts <http://quvi.googlecode.com/>.
@@ -23,40 +24,34 @@
 
 -- Identify the script.
 function ident(self)
+    local domains= {"canalplus%.fr", "d17%.tv", "d8%.tv"}
     package.path = self.script_dir .. '/?.lua'
     local C      = require 'quvi/const'
-    local r      = {}
-    r.domain     = "canalplus%.fr"
-    r.formats    = "default|best"
-    r.categories = C.proto_rtmp
     local U      = require 'quvi/util'
-    r.handles    = U.handles(self.page_url, {r.domain}, {"/pid%d",
-                    -- presidentielle2012.canalplus.fr
-                    "/emissions", "/candidats", "/debats",
-                    -- canalstreet.canalplus.fr
-                    "/musique", "/actu", "/humour", "/tendances", "/sport", "/arts", "/danse"})
-
+    local B      = require 'quvi/bit'
+    local r      = {
+        handles    = U.handles(self.page_url, domains, {"/pid%d+"}),
+        categories = B.bit_or(C.proto_http, C.proto_rtmp),
+        domain     = table.concat(domains, '|'),
+        formats    = "default|best"
+    }
     return r
 end
 
 -- Query available formats.
 function query_formats(self)
-    local config  = CanalPlus.get_config(self)
-
-    if #self.redirect_url >0 then
-        return self
-    end
+    local r = CanalPlus.rest_new(self)
+    local U = require 'quvi/util'
 
-    local U       = require 'quvi/util'
-    local formats = CanalPlus.iter_formats(self, config, U)
+    local s = CanalPlus.iter_streams(U, r)
+    local r = {}
 
-    local t = {}
-    for _,v in pairs(formats) do
-        table.insert(t, CanalPlus.to_s(v))
+    for _,v in pairs(s) do
+        table.insert(r, CanalPlus.to_s(v))
     end
 
-    table.sort(t)
-    self.formats = table.concat(t, "|")
+    table.sort(r)
+    self.formats = table.concat(r, "|")
 
     return self
 end
@@ -65,20 +60,19 @@
 function parse(self)
     self.host_id  = 'canalplus'
 
-    local config  = CanalPlus.get_config(self)
+    local r = CanalPlus.rest_new(self)
+    local U = require 'quvi/util'
 
-    if #self.redirect_url >0 then
-        return self
-    end
+    self.thumbnail_url = U.xml_get(r, 'PETIT', false)
+    self.title         = U.xml_get(r, 'TITRE', true)
+    self.id            = U.xml_get(r, 'ID', false)
+
+    local s = CanalPlus.iter_streams(U, r)
+
+    local c = U.choose_format(self, s, CanalPlus.choose_best,
+                              CanalPlus.choose_default, CanalPlus.to_s)
 
-    local U       = require 'quvi/util'
-    local formats = CanalPlus.iter_formats(self, config, U)
-    local format  = U.choose_format(self, formats,
-                                    CanalPlus.choose_best,
-                                    CanalPlus.choose_default,
-                                    CanalPlus.to_s)
-                        or error("unable to choose format")
-    self.url           = {format.url or error("no match: media url")}
+    self.url = {c.url or error("no match: media stream URL")}
 
     return self
 end
@@ -87,74 +81,42 @@
 -- Utility functions
 --
 
-function CanalPlus.get_config(self)
-    local t    = {}
-    local page = quvi.fetch(self.page_url)
-
-    local u = page:match('"og:video" content="(.-)"')
-    if u and not u:match('canalplus%.fr') then
-        self.redirect_url = u -- Media is hosted elsewhere, e.g. YouTube.
-        return
-    end
+function CanalPlus.rest_new(self)
+    self.id = self.page_url:match('vid=(%d+)')
+                  or error('no match: media ID')
 
-    -- canalplus.fr
-    self.title = page:match('videoTitre%s-=%s-"(.-)"')
-    if not self.title then
-      -- presidentielle2012.canalplus.fr
-      self.title = page:match('property="og:title"%s+content="(.-)"')
-                    or error('no match: media title')
-    end
+    local c = self.page_url:match('http://www%.(%w+)%.%w+/')
+                  or error('unable to determine the second-level domain')
 
-    self.id = page:match('videoId=(%d+)')
-                or page:match('videoId%s+=%s+"(%d+)"')
-                or error('no match: media ID')
+    c = c:gsub('canalplus', 'cplus')
 
-    local u = "http://service.canal-plus.com/video/rest/getVideosLiees/cplus/";
-                .. self.id
+    local t = {
+        'http://service.canal-plus.com/video/rest/getVideos/',
+        c, '/', self.id, '/?format=xml'
+    }
 
-    return quvi.fetch(u, {fetch_type = 'config'})
+    return quvi.fetch(table.concat(t), {fetch_type = 'config'})
 end
 
-function CanalPlus.iter_formats(self, config, U)
-
-    local id = config:match('<ID>(.-)</ID>')
-    if id and id == '-1' then
-        error('Media is no longer available (expired)')
+function CanalPlus.iter_streams(U, r)
+    local m = U.xml_get(r, 'MEDIA')
+    local v = U.xml_get(m, 'VIDEOS')
+    local r = {}
+    for id,uri in v:gmatch('<(%w+)>(.-)</%1>') do
+        table.insert(r, {quality=id:lower(), url=uri})
     end
-
-    local p = '<ID>' .. self.id .. '</ID>'
-           .. '.-<INFOS>'
-           .. '.-<TITRAGE>'
-           .. '.-<MEDIA>'
-           .. '.-<IMAGES>'
-           .. '.-<PETIT>(.-)<'
-           .. '.-<VIDEOS>'
-           .. '.-<BAS_DEBIT>(.-)<'
-           .. '.-<HAUT_DEBIT>(.-)<'
-           .. '.-<HD>(.-)<'
-
-    -- sd = low definition flv
-    -- hd = high definition flv
-    -- hq = high definition mp4
-
-    local thumb,sd_url,hd_url,hq_url = config:match(p)
-    if not sd_url then error("no match: media url") end
-
-    self.thumbnail_url = thumb or ''
-
-    local t = {}
-    table.insert(t, {url=sd_url, quality="sd"})
-    table.insert(t, {url=hd_url, quality="hd"})
-    table.insert(t, {url=hq_url, quality="hq"})
-    return t
+    if #r ==0 then
+        error('failed to find any media stream URLs')
+    end
+    return r
 end
 
 function CanalPlus.choose_default(t)
-    return t[1] -- Presume the first to be the 'default'.
+    return t[1]
 end
 
 function CanalPlus.choose_best(t)
-    return t[#t] -- Presume the last to be the 'best'.
+    return CanalPlus.choose_default(t)
 end
 
 function CanalPlus.to_s(t)
diff -Nru libquvi-scripts-0.4.19/share/lua/website/cbsnews.lua libquvi-scripts-0.4.21/share/lua/website/cbsnews.lua
--- libquvi-scripts-0.4.19/share/lua/website/cbsnews.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/cbsnews.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,6 +1,6 @@
 
--- libquvi-scripts v0.4.19
--- Copyright (C) 2010-2012  Toni Gundogdu <legatvs@gmail.com>
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2010-2012,2013  Toni Gundogdu <legatvs@gmail.com>
 --
 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
 --
@@ -26,29 +26,21 @@
 function ident(self)
     package.path = self.script_dir .. '/?.lua'
     local C      = require 'quvi/const'
-    local r      = {}
-    r.domain     = "cbsnews%.com"
-    r.formats    = "default|best"
-    r.categories = C.proto_http
     local U      = require 'quvi/util'
-    r.handles    = U.handles(self.page_url, {r.domain}, {"/video/watch/"})
+    local B      = require 'quvi/bit'
+    local d      = 'cbsnews%.com'
+    local r      = {
+        handles    = U.handles(self.page_url, {d}, {"/videos/.-/?"}),
+        categories = B.bit_or(C.proto_http, C.proto_rtmp),
+        formats   = 'default',
+        domain    = d
+    }
     return r
 end
 
 -- Query available formats.
 function query_formats(self)
-    local U       = require 'quvi/util'
-    local config  = CBSNews.get_config(self)
-    local formats = CBSNews.iter_formats(config)
-
-    local t = {}
-    for k,v in pairs(formats) do
-        table.insert(t, CBSNews.to_s(v))
-    end
-
-    table.sort(t)
-    self.formats = table.concat(t, "|")
-
+    self.formats = 'default'
     return self
 end
 
@@ -56,88 +48,28 @@
 function parse(self)
     self.host_id = "cbsnews"
 
-    local c = CBSNews.get_config(self)
-
-    self.title = c:match('<Title>.-CDATA%[(.-)%]')
-                  or error ("no match: media title")
-
-    local formats = CBSNews.iter_formats(c)
-    local U       = require 'quvi/util'
-    local format  = U.choose_format(self, formats,
-                                     CBSNews.choose_best,
-                                     CBSNews.choose_default,
-                                     CBSNews.to_s)
-                        or error("unable to choose format")
-    self.url      = {format.url or error("no match: media url")}
-    return self
-end
-
---
--- Utility functions
---
-
-function CBSNews.get_config(self)
     local p = quvi.fetch(self.page_url)
 
-    -- Need "? because some videos have the " and some don't
-    self.id = p:match('CBSVideo.setVideoId%("?(.-)"?%);')
-                or error("no match: media id")
+    local d = p:match("data%-cbsvideoui%-options='(.-)'")
+                  or error('no match: player options')
 
-    local s_fmt =
-      "http://api.cnet.com/restApi/v1.0/videoSearch?videoIds=%s";
-       .. "&iod=videoMedia"
+    local U = require 'quvi/util'
 
-    local c_url = string.format(s_fmt, self.id)
+    self.thumbnail_url =
+        U.slash_unescape(d:match('"image":{"path":"(.-)"') or '')
 
-    return quvi.fetch(c_url, {fetch_type='config'})
-end
+    self.title = d:match('"title":"(.-)"')
+                    or error('no match: media ID')
 
-function CBSNews.iter_formats(config) -- Iterate available formats
-    local p = '<Width>(%d+)<'
-           .. '.-<Height>(%d+)<'
-           .. '.-<BitRate>(%d+)<'
-           .. '.-<DeliveryUrl>.-'
-           .. 'CDATA%[(.-)%]'
-    local t = {}
-    for w,h,b,u in config:gmatch(p) do
-        local s = u:match('%.(%w+)$')
---        print(w,h,b,s,u)
-        table.insert(t,
-            {width=tonumber(w),
-             height=tonumber(h),
-             bitrate=tonumber(b),
-             url=u,
-             container=s})
-    end
-    return t
-end
+    self.id = d:match('"id":"(.-)"')
+                  or error('no match: media ID')
 
-function CBSNews.choose_best(formats) -- Highest quality available
-    local r = {width=0, height=0, bitrate=0, url=nil}
-    local U = require 'quvi/util'
-    for _,v in pairs(formats) do
-        if U.is_higher_quality(v,r) then
-            r = v
-        end
-    end
---    for k,v in pairs(r) do print(k,v) end
-    return r
-end
+    local u = d:match('"desktop":.-"uri":"(.-)"')
+                  or error('no match: media stream URL')
 
-function CBSNews.choose_default(t) -- Lowest quality available
-    local r = {width=0xffff, height=0xffff, bitrate=0xffff, url=nil}
-    local U = require 'quvi/util'
-    for _,v in pairs(t) do
-        if U.is_lower_quality(v,r) then
-            r = v
-        end
-    end
---    for k,v in pairs(r) do print(k,v) end
-    return r
-end
+    self.url = {U.slash_unescape(u)}
 
-function CBSNews.to_s(t)
-    return string.format("%s_%sk_%sp", t.container, t.bitrate, t.height)
+    return self
 end
 
 -- vim: set ts=4 sw=4 tw=72 expandtab:
diff -Nru libquvi-scripts-0.4.19/share/lua/website/collegehumor.lua libquvi-scripts-0.4.21/share/lua/website/collegehumor.lua
--- libquvi-scripts-0.4.19/share/lua/website/collegehumor.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/collegehumor.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,6 +1,6 @@
 
--- libquvi-scripts v0.4.19
--- Copyright (C) 2012  Toni Gundogdu <legatvs@gmail.com>
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2012,2013  Toni Gundogdu <legatvs@gmail.com>
 -- Copyright (C) 2010-2011  Lionel Elie Mamane <lionel@mamane.lu>
 --
 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
@@ -21,40 +21,23 @@
 -- 02110-1301  USA
 --
 
-local CollegeHumor = {} -- Utility functions unique to this script
-
 -- Identify the script.
 function ident(self)
     package.path = self.script_dir .. '/?.lua'
     local C      = require 'quvi/const'
     local r      = {}
-    local domains= {"collegehumor%.com", "dorkly%.com"}
-    r.domain     = table.concat(domains, "|")
-    r.formats    = "default|best"
+    r.domain     = "collegehumor%.com"
+    r.formats    = "default"
     r.categories = C.proto_http
     local U      = require 'quvi/util'
-    r.handles    = U.handles(self.page_url, domains,
-                    {"/video[:/]%d+/?", "/embed/%d+"})
+    r.handles    = U.handles(self.page_url, {r.domain},
+                                {"/video/%d+/", "/embed/%d+/"})
     return r
 end
 
 -- Query formats.
 function query_formats(self)
-    if CollegeHumor.redirect_if_embed(self) then
-        return self
-    end
-
-    local config  = CollegeHumor.get_config(self)
-    local formats = CollegeHumor.iter_formats(config)
-
-    local t = {}
-    for k,v in pairs(formats) do
-        table.insert(t, CollegeHumor.to_s(v))
-    end
-
-    table.sort(t)
-    self.formats = table.concat(t, "|")
-
+    self.formats = 'default'
     return self
 end
 
@@ -62,102 +45,30 @@
 function parse(self)
     self.host_id  = "collegehumor"
 
-    if CollegeHumor.redirect_if_embed(self) then
-        return self
-    end
-
-    local c = CollegeHumor.get_config(self)
+    local p = quvi.fetch(self.page_url)
 
-    self.title = c:match('<caption>.-%[.-%[(.-)%]%]')
-                  or error("no match: media title")
+    local u = p:match('source type=.- src="(.-)"')
+                  or error('no match: media stream URL')
 
-    self.thumbnail_url = c:match('<thumbnail><!%[.-%[(.-)%]') or ''
-
-    local formats = CollegeHumor.iter_formats(c)
-    local U       = require 'quvi/util'
-    local format  = U.choose_format(self, formats,
-                                     CollegeHumor.choose_best,
-                                     CollegeHumor.choose_default,
-                                     CollegeHumor.to_s)
-                        or error("unable to choose format")
-    self.url      = {format.url or error("no match: media URL")}
-    return self
-end
-
---
--- Utility functions
---
-
-function CollegeHumor.redirect_if_embed(self) -- dorkly embeds YouTube videos
-    if self.page_url:match('/embed/%d+') then
-        local p = quvi.fetch(self.page_url)
-        local s = p:match('youtube.com/embed/([%w-_]+)')
-        if s then
-            -- Hand over to youtube.lua
-            self.redirect_url = 'http://youtube.com/watch?v=' .. s
-            return true
-        end
+    if u:match('%.%w+$') then
+        self.url = {u}
+    else
+        self.redirect_url = u -- Affiliate content.
+        return self           -- Pass the new page URL back to the library.
     end
-    return false
-end
 
-function CollegeHumor.get_media_id(self)
-    local U = require 'quvi/url'
-    local domain = U.parse(self.page_url).host:gsub('^www%.', '', 1)
+    self.duration =
+      tonumber(p:match('"video:duration" content="(%d+)"') or 0) *1000
 
-    self.host_id = domain:match('^(.+)%.[^.]+$') or error("no match: domain")
+    self.thumbnail_url = p:match('"og:image" content="(.-)"') or ''
 
-    self.id = self.page_url:match('/video[/:](%d+)')
-                or error("no match: media ID")
+    self.title = p:match('"og:title" content="(.-)"')
+                    or error('no match: media title')
 
-    return domain
-end
-
-function CollegeHumor.get_config(self)
-    local domain = CollegeHumor.get_media_id(self)
-
-    -- quvi normally checks the page URL for a redirection to another
-    -- URL. Disabling this check (QUVIOPT_NORESOLVE) breaks the support
-    -- which is why we do this manually here.
-    local r = quvi.resolve(self.page_url)
-
-    -- Make a note of the use of the quvi.resolve returned string.
-    local u = string.format("http://www.%s/moogaloop/video%s%s";,
-                              domain, (#r > 0) and ':' or '/', self.id)
-
-    return quvi.fetch(u, {fetch_type='config'})
-end
-
-function CollegeHumor.iter_formats(config)
-    local sd_url = config:match('<file><!%[.-%[(.-)%]')
-    local hq_url = config:match('<hq><!%[.-%[(.-)%]')
-    local hq_avail = (hq_url and #hq_url > 0) and 1 or 0
-
-    local t = {}
-
-    local s = sd_url:match('%.(%w+)$')
-    table.insert(t, {quality='sd', url=sd_url, container=s})
-
-    if hq_avail == 1 and hq_url then
-        local s = hq_url:match('%.(%w+)$')
-        table.insert(t, {quality='hq', url=hq_url, container=s})
-    end
-
-    return t
-end
-
-function CollegeHumor.choose_best(formats) -- Assume last is best.
-    local r
-    for _,v in pairs(formats) do r = v end
-    return r
-end
-
-function CollegeHumor.choose_default(formats) -- Whatever is found first.
-    for _,v in pairs(formats) do return v end
-end
-
-function CollegeHumor.to_s(t)
-    return string.format('%s_%s', t.container, t.quality)
+    self.id = self.page_url:match('/video/(%d+)/')
+                  or self.page_url:match('/embed/(%d+)/')
+                      or error('no match: media ID')
+    return self
 end
 
 -- vim: set ts=4 sw=4 tw=72 expandtab:
diff -Nru libquvi-scripts-0.4.19/share/lua/website/dorkly.lua libquvi-scripts-0.4.21/share/lua/website/dorkly.lua
--- libquvi-scripts-0.4.19/share/lua/website/dorkly.lua	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/share/lua/website/dorkly.lua	2013-11-30 16:53:31.000000000 +0100
@@ -0,0 +1,90 @@
+
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2013  Toni Gundogdu <legatvs@gmail.com>
+--
+-- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
+--
+-- This library is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU Lesser General Public
+-- License as published by the Free Software Foundation; either
+-- version 2.1 of the License, or (at your option) any later version.
+--
+-- This library is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-- Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public
+-- License along with this library; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+-- 02110-1301  USA
+--
+
+local Dorkly = {} -- Utility functions unique to this script
+
+-- Identify the script.
+function ident(self)
+    package.path = self.script_dir .. '/?.lua'
+    local C      = require 'quvi/const'
+    local r      = {}
+    r.domain     = "dorkly%.com"
+    r.formats    = "default"
+    r.categories = C.proto_http
+    local U      = require 'quvi/util'
+    r.handles    = U.handles(self.page_url, {r.domain},
+                    {"/video/%d+/", "/embed/%d+/"})
+    return r
+end
+
+-- Query formats.
+function query_formats(self)
+    self.formats = 'default'
+    return self
+end
+
+-- Parse media URL.
+function parse(self)
+    self.host_id  = "dorkly"
+
+    self.id = self.page_url:match('/video/(%d+)/')
+                  or self.page_url:match('/embed/(%d+)/')
+                      or error('no match: media ID')
+
+    if Dorkly.is_affiliate(self) then
+      return self
+    end
+
+    local t = {'http://www.dorkly.com/moogaloop/video/', self.id}
+    local x = quvi.fetch(table.concat(t), {fetch_type='config'})
+
+    local U = require 'quvi/util'
+
+    self.duration = tonumber(U.xml_get(x, 'duration', false))
+
+    self.thumbnail_url = U.xml_get(x, 'thumbnail', true)
+
+    self.title = U.xml_get(x, 'caption', true)
+
+    self.url = { U.xml_get(x, 'file', true) }
+
+    return self
+end
+
+--
+-- Utility functions
+--
+
+function Dorkly.is_affiliate(self)
+    if not self.page_url:match('/embed/') then
+        return false
+    end
+    local p = quvi.fetch(self.page_url)
+    local u = p:match('iframe.-src="(.-)"') or error('no match: iframe: src')
+    if not u:match('^http%:') then    -- If the URL scheme is malformed...
+        u = table.concat({'http:',u}) -- ... Try to fix it.
+    end
+    self.redirect_url = u
+    return true
+end
+
+-- vim: set ts=4 sw=4 tw=72 expandtab:
diff -Nru libquvi-scripts-0.4.19/share/lua/website/imdb.lua libquvi-scripts-0.4.21/share/lua/website/imdb.lua
--- libquvi-scripts-0.4.19/share/lua/website/imdb.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/imdb.lua	2013-11-30 16:53:31.000000000 +0100
@@ -59,9 +59,12 @@
     self.host_id = 'imdb'
 
     self.id = self.page_url:match('/video/%w+/(vi%d-)/')
+                  or error('no match: media ID')
 
     local page = quvi.fetch(self.page_url)
+
     self.title = page:match('<title>(.-) %- IMDb</title>')
+                  or error('no match: title')
 
     --
     -- Format codes (for most videos):
@@ -82,14 +85,20 @@
 
     local url = 'http://www.imdb.com' .. format.path
     local iframe = quvi.fetch(url, {fetch_type = 'config'})
+
     local file = iframe:match('so%.addVariable%("file", "(.-)"%);')
+                    or error('no match: file')
+
     file = U.unescape(file)
 
     if file:match('^http.-') then
         self.url = {file}
     else
         local path  = iframe:match('so%.addVariable%("id", "(.-)"%);')
+                          or error('no match: path')
+
         path = U.unescape(path)
+
         self.url = {file .. path}
     end
 
diff -Nru libquvi-scripts-0.4.19/share/lua/website/publicsenat.lua libquvi-scripts-0.4.21/share/lua/website/publicsenat.lua
--- libquvi-scripts-0.4.19/share/lua/website/publicsenat.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/publicsenat.lua	2013-11-30 16:53:31.000000000 +0100
@@ -28,7 +29,7 @@
     r.formats    = "default"
     r.categories = C.proto_http
     local U      = require 'quvi/util'
-    r.handles    = U.handles(self.page_url, {r.domain}, {"/vod"})
+    r.handles    = U.handles(self.page_url, {r.domain}, {"/vod/.-/%d+$"})
     return r
 end
 
@@ -42,24 +43,26 @@
 function parse(self)
     self.host_id = "publicsenat"
 
+    self.id = self.page_url:match("/vod/.-/(%d+)$")
+                  or error('no match: media ID')
+
     local p = quvi.fetch(self.page_url)
 
-    self.title = p:match('<title>(.-)%s+%|') or error("no match: media title")
+    self.title = p:match('<title>(.-)%s+%|')
+                    or error("no match: media title")
+
+    local u = p:match('id="dmcloudUrlEmissionSelect" value="(.-)"')
+                  or error('no match: emission URL')
+
+    local e = quvi.fetch(u, {fetch_type='config'})
 
-    self.id = self.page_url:match(".-idE=(%d+)$")
-              or self.page_url:match(".-/(%d+)$")
-              or error("no match: media ID")
-
-    local t = p:match('id="imgEmissionSelect" value="(.-)"') or ''
-    if #t >0 then
-      self.thumbnail_url = 'http://publicsenat.fr' .. t
-    end
+    local d = e:match('info = (.-);')
+                  or error('no match: info')
 
-    local u = "http://videos.publicsenat.fr/vodiFrame.php?idE="; ..self.id
-    local c = quvi.fetch(u, {fetch_type='config'})
+    self.thumbnail_url = d:match('"thumbnail_url": "(.-)"') or ''
 
-    self.url = {c:match('id="flvEmissionSelect" value="(.-)"')
-                or error("no match: media stream URL")}
+    self.url = {d:match('"mp4_url": "(.-)"')
+                    or error('no match: media stream URL')}
 
     return self
 end
diff -Nru libquvi-scripts-0.4.19/share/lua/website/quvi/util.lua libquvi-scripts-0.4.21/share/lua/website/quvi/util.lua
--- libquvi-scripts-0.4.19/share/lua/website/quvi/util.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/quvi/util.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,6 +1,6 @@
 
--- libquvi-scripts v0.4.19
--- Copyright (C) 2010-2011  Toni Gundogdu <legatvs@gmail.com>
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2010,2011,2013  Toni Gundogdu <legatvs@gmail.com>
 --
 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
 --
@@ -187,6 +187,21 @@
                     hour=hh,min=mm,sec=ss}) + offset
 end
 
+-- For very simple XML value extraction.
+function M.xml_get(d, e, is_cdata)
+    local p = is_cdata and '.-%w+%[(.-)%].-' or '(.-)'
+    local t = {'<',e,'>', p, '</',e,'>'}
+    return d:match(table.concat(t))
+              or error(table.concat({'no match: element: ',e}))
+end
+
+-- For very simple JSON value extraction.
+function M.json_get(p, e, is_num)
+  local c = is_num and '(%d+)' or '"(.-)"'
+  local t = {'"',e,'":',c}
+  return p:match(table.concat(t)) or ((is_num) and 0 or '')
+end
+
 return M
 
 -- vim: set ts=4 sw=4 tw=72 expandtab:
diff -Nru libquvi-scripts-0.4.19/share/lua/website/redtube.lua libquvi-scripts-0.4.21/share/lua/website/redtube.lua
--- libquvi-scripts-0.4.19/share/lua/website/redtube.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/redtube.lua	2013-11-30 16:53:31.000000000 +0100
@@ -58,7 +58,7 @@
     self.thumbnail_url =
         p:match('<img src=%"(.-)%" .- id=%"vidImgPoster%"') or ''
 
-    self.url = {p:match('(http://videos.mp4.redtubefiles.com/.-)\'')
+    self.url = {p:match("src='(.-)' type='video/")
                   or error("no match: media stream URL")}
 
     return self
diff -Nru libquvi-scripts-0.4.19/share/lua/website/senat.lua libquvi-scripts-0.4.21/share/lua/website/senat.lua
--- libquvi-scripts-0.4.19/share/lua/website/senat.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/senat.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,8 +1,9 @@
 
--- libquvi-scripts v0.4.19
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2013  Toni Gundogdu <legatvs@gmail.com>
 -- Copyright (C) 2012 Raphaël Droz.
 --
--- This file is part of quvi <http://quvi.googlecode.com/>.
+-- This file is part of quvi <http://quvi.sourceforge.net/>.
 --
 -- This library is free software; you can redistribute it and/or
 -- modify it under the terms of the GNU Lesser General Public
@@ -50,10 +51,16 @@
     self.title = p:match('<title>(.-)</title>')
                   or error("no match: media title")
 
-    self.thumbnail_url = p:match('image=(.-)&') or ''
+    local v = (p:match('"flashvars" value="(.-)"')
+                  or error('no match: flashvars'))
+                      :gsub('&amp;','&'):gsub(';','')
 
-    self.url = {p:match('name="flashvars" value=".-file=(.-flv)')
-                  or error("no match: media stream URL") }
+    local U = require 'quvi/util'
+    local d = U.decode(v)
+
+    self.url = {d.file or error("no match: media stream URL")}
+
+    self.thumbnail_url = d.image or ''
 
     return self
 end
diff -Nru libquvi-scripts-0.4.19/share/lua/website/spankwire.lua libquvi-scripts-0.4.21/share/lua/website/spankwire.lua
--- libquvi-scripts-0.4.19/share/lua/website/spankwire.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/spankwire.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,6 +1,6 @@
 
--- libquvi-scripts v0.4.19
--- Copyright (C) 2011-2012  quvi project
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2011-2013  quvi project
 --
 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
 --
@@ -20,6 +20,8 @@
 -- 02110-1301  USA
 --
 
+local Spankwire = {}
+
 -- Identify the script.
 function ident(self)
     package.path = self.script_dir .. '/?.lua'
@@ -35,7 +37,17 @@
 
 -- Query available formats.
 function query_formats(self)
-    self.formats = 'default'
+    local p = quvi.fetch(self.page_url)
+    local U = require 'quvi/util'
+
+    local r = {}
+    for _,v in pairs(Spankwire.iter_streams(U,p)) do
+        table.insert(r, v.id)
+    end
+
+    table.sort(r)
+    self.formats = table.concat(r,'|')
+
     return self
 end
 
@@ -45,21 +57,49 @@
 
     local p = quvi.fetch(self.page_url)
 
-    self.title = p:match('id="vidTitle">.-<h1>(.-)</')
-                  or error('no match: media title')
+    self.thumbnail_url = p:match('image_url%s+=%s+"(.-)"') or ''
 
-    self.id = p:match('ArticleId:%s+(%d+)')
-                or error('no match: media ID')
+    self.title = p:match('<title>(.-)%s+%-%s+Sp')
+                    or error('no match: media title')
 
-    local s = p:match('videoPath=(.-)"')
-                or error('no match: video path')
+    self.id = self.page_url:match('/video(%d+)/$')
+                  or error('no match: media ID')
 
-    local c = quvi.fetch(self.page_url .. s, {fetch_type='config'})
+    local U = require 'quvi/util'
 
-    self.url    = {c:match('<url>(.-)</url>')
-                    or error('no match: media URL')}
+    local c = U.choose_format(self, Spankwire.iter_streams(U,p),
+                              Spankwire.choose_best, Spankwire.choose_default,
+                              Spankwire.to_id)
+
+    self.url = {c.url or error('no match: media stream URL')}
 
     return self
 end
 
+--
+-- Utility functions
+--
+
+function Spankwire.iter_streams(U, p)
+    local r = {}
+    for id,u in p:gmatch('flashvars%.(quality_%d+p)%s+=%s"(.-)"') do
+        if #u >0 then
+            table.insert(r, {url=U.unescape(u),id=id})
+        end
+    end
+    return r
+end
+
+function Spankwire.choose_best(t)
+    return t[#t]
+end
+
+function Spankwire.choose_default(t)
+    return Spankwire.choose_best(t)
+end
+
+function Spankwire.to_id(t)
+    return t.id
+end
+
 -- vim: set ts=4 sw=4 tw=72 expandtab:
diff -Nru libquvi-scripts-0.4.19/share/lua/website/tcmag.lua libquvi-scripts-0.4.21/share/lua/website/tcmag.lua
--- libquvi-scripts-0.4.19/share/lua/website/tcmag.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/tcmag.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,5 +1,6 @@
 
--- libquvi-scripts v0.4.19
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2013  Toni Gundogdu <legatvs@gmail.com>
 -- Copyright (C) 2011  quvi project
 --
 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
@@ -52,38 +53,23 @@
 --
 
 function TCMag.check_external_content(self)
-    local page = quvi.fetch(self.page_url)
+    local p = quvi.fetch(self.page_url)
 
-    local article = page:match('<article id="article">(.-)</article>')
-                        or error("no match: article")
+    self.url = {p:match("file: '(.-)'")
+                  or error("no match: media stream URL")}
 
-    local s = article:match('http://.*youtube.com/embed/([^/]-)"')
-    if s then -- Hand over to youtube.lua
-        self.redirect_url = 'http://youtube.com/watch?v=' .. s
+    if self.url[1]:match('%.%w+$') then
+        -- Self-hosted content.
+        self.title = p:match('<h1>(.-)</h1>')
+                        or error ("no match: media title")
+        self.id = self.url[1]:match("/%d+/%d+/(.-)/sizes/")
+                        or error ("no match: media id")
+        self.thumbnail_url = p:match('"og:image" content="(.-)"') or ''
+    else -- Affiliate content.
+        self.redirect_url = self.url[1]
         return self
     end
 
-    local s = article:match('http://.*vimeo.com/video/([0-9]+)')
-    if s then -- Hand over to vimeo.lua
-        self.redirect_url = 'http://vimeo.com/video/' .. s
-        return self
-    end
-
-    local s = article:match('http://.*liveleak.com/e/([%w_]+)')
-    if s then -- Hand over to liveleak.lua
-        self.redirect_url = 'http://liveleak.com/e/' .. s
-        return self
-    end
-
-    self.title = article:match('<h1>(.-)</h1>')
-                    or error ("no match: media title")
-
-    self.url = {article:match("'file': '(.-)',")
-                or error("no match: media url")}
-
-    self.id = self.url[1]:match("/%d+/%d+/(.-)/sizes/")
-                or error ("no match: media id")
-
     return self
 end
 
diff -Nru libquvi-scripts-0.4.19/share/lua/website/vimeo.lua libquvi-scripts-0.4.21/share/lua/website/vimeo.lua
--- libquvi-scripts-0.4.19/share/lua/website/vimeo.lua	2013-10-04 16:04:57.000000000 +0200
+++ libquvi-scripts-0.4.21/share/lua/website/vimeo.lua	2013-11-30 16:53:31.000000000 +0100
@@ -1,6 +1,6 @@
 
--- libquvi-scripts v0.4.19
--- Copyright (C) 2010-2012  Toni Gundogdu <legatvs@gmail.com>
+-- libquvi-scripts v0.4.21
+-- Copyright (C) 2010-2013  Toni Gundogdu <legatvs@gmail.com>
 --
 -- This file is part of libquvi-scripts <http://quvi.sourceforge.net/>.
 --
@@ -41,12 +41,12 @@
 
 -- Query available formats.
 function query_formats(self)
-    local config  = Vimeo.get_config(self)
-    local formats = Vimeo.iter_formats(self, config)
+    local c = Vimeo.get_config(self)
+    local s = Vimeo.iter_streams(c)
 
     local t = {}
-    for _,v in pairs(formats) do
-        table.insert(t, Vimeo.to_s(v))
+    for _,v in pairs(s) do
+        table.insert(t, Vimeo.to_id(v))
     end
 
     table.sort(t)
@@ -60,25 +60,27 @@
     self.host_id  = "vimeo"
 
     local c = Vimeo.get_config(self)
-
-    local s = c:match('"title":(.-),') or error("no match: media title")
     local U = require 'quvi/util'
-    self.title = U.slash_unescape(s):gsub('^"',''):gsub('"$','')
 
-    self.duration = (tonumber(c:match('"duration":(%d+)')) or 0) * 1000
+    local s = c:match('"title":"(.-)",') or error('no match: media title')
+    self.title = U.slash_unescape(s)
 
-    local s = c:match('"thumbnail":"(.-)"') or ''
-    if #s >0 then
-      self.thumbnail_url = U.slash_unescape(s)
+    self.duration = U.json_get(c, 'duration', true) * 1000
+
+    local t = c:match('"thumbs":({.-})')
+    if t and #t >0 then
+        local r = {}
+        for u in t:gmatch('"%d+":"(.-)"') do
+            table.insert(r,u)
+        end
+        self.thumbnail_url = r[#r] or ''
     end
 
-    local formats = Vimeo.iter_formats(self, c)
-    local format  = U.choose_format(self, formats,
-                                     Vimeo.choose_best,
-                                     Vimeo.choose_default,
-                                     Vimeo.to_s)
-                        or error("unable to choose format")
-    self.url      = {format.url or error("no match: media stream URL")}
+    local c = U.choose_format(self, Vimeo.iter_streams(c),
+                              Vimeo.choose_best, Vimeo.choose_default,
+                              Vimeo.to_id)
+
+    self.url = {c.url or error("no match: media stream URL")}
     return self
 end
 
@@ -98,64 +100,52 @@
     self.id = self.page_url:match('vimeo.com/(%d+)')
                 or error("no match: media ID")
 
-    local c_url = "http://vimeo.com/"; .. self.id
-    local c = quvi.fetch(c_url, {fetch_type='config'})
+    local s = self.page_url:match('^(%w+)://') or 'http'
+    local t = {s, '://player.vimeo.com/video/', self.id}
+
+    local c = quvi.fetch(table.concat(t), {fetch_type='config'})
 
     if c:match('<error>') then
         local s = c:match('<message>(.-)[\n<]')
         error( (not s) and "no match: error message" or s )
     end
 
-    return c
+    return c:match('b=(.-);') or error('no match: b')
 end
 
-function Vimeo.iter_formats(self, config)
-    local t = {}
-    local qualities = config:match('"qualities":%[(.-)%]')
-                        or error('no match: qualities')
-    for q in qualities:gmatch('"(.-)"') do
-        Vimeo.add_format(self, config, t, q)
-    end
-    return t
+function Vimeo.iter_streams(c)
+      local p =
+          '"(%w+)":{"profile".-"url":"(.-)","height":(%d+).-"bitrate":(%d+)'
+      local r = {}
+      for q,url,h,br in c:gmatch(p) do
+          local t = {
+              bitrate = tonumber(br) or 0,
+              height  = tonumber(h) or 0,
+              quality = q,
+              url = url
+          }
+          t.id = Vimeo.to_id(t)
+          table.insert(r,t)
+      end
+      return r
 end
 
-function Vimeo.add_format(self, config, t, quality)
-    table.insert(t, {quality=quality,
-                     url=Vimeo.to_url(self, config, quality)})
+function Vimeo.to_id(t)
+    return string.format("%s_%dk_%dp", t.quality, t.height, t.bitrate)
 end
 
-function Vimeo.choose_best(t) -- First 'hd', then 'sd' and 'mobile' last.
+function Vimeo.choose_best(t)
+    local r = t[1]
     for _,v in pairs(t) do
-        local f = Vimeo.to_s(v)
-        for _,q in pairs({'hd','sd','mobile'}) do
-            if f == q then return v end
+        if v.height > r.height then
+            r = v
         end
     end
-    return Vimeo.choose_default(t)
+    return r
 end
 
 function Vimeo.choose_default(t)
-  for _,v in pairs(t) do
-      if Vimeo.to_s(v) == 'sd' then return v end -- Default to 'sd'.
-  end
-  return t[1] -- Or whatever is the first.
-end
-
-function Vimeo.to_url(self, config, quality)
-    local sign = config:match('"signature":"(.-)"')
-                  or error("no match: request signature")
-
-    local exp = config:match('"timestamp":(%d+)')
-                  or error("no match: request timestamp")
-
-    local s = "http://player.vimeo.com/play_redirect?clip_id=%s";
-              .. "&sig=%s&time=%s&quality=%s&type=moogaloop_local"
-
-    return string.format(s, self.id, sign, exp, quality)
-end
-
-function Vimeo.to_s(t)
-    return string.format("%s", t.quality)
+    return Vimeo.choose_best(t)
 end
 
 -- vim: set ts=4 sw=4 tw=72 expandtab:
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/canalplus.json libquvi-scripts-0.4.21/tests/data/format/default/canalplus.json
--- libquvi-scripts-0.4.19/tests/data/format/default/canalplus.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/canalplus.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,14 @@
+{
+  "host": "canalplus",
+  "page_title": "Premier League - 12ème journée",
+  "page_url": "http://www.canalplus.fr/c-sport/c-football/c-angleterre/pid3479-c-videos-premier-league.html?vid=977451";,
+  "id": "977451",
+  "format_requested": "default",
+  "thumbnail_url": "http://media.canal-plus.com/wwwplus/image/1/5/8/FOOTBALL_PREMIERSHIP_131124_CAN_385080_image_L.jpg";,
+  "link": [
+    {
+      "id": "1",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/cbsnews.json libquvi-scripts-0.4.21/tests/data/format/default/cbsnews.json
--- libquvi-scripts-0.4.19/tests/data/format/default/cbsnews.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/cbsnews.json	2013-11-30 16:50:25.000000000 +0100
@@ -1,15 +1,16 @@
 {
   "host": "cbsnews",
   "page_title": "48 Hours Live to Tell: Full Moon",
-  "page_url": "http://www.cbsnews.com/video/watch/?id=7118769n";,
-  "id": "50096912",
+  "page_url": "http://www.cbsnews.com/videos/48-hours-live-to-tell-full-moon/";,
+  "id": "674917c0-8bdf-11e2-9400-029118418759",
   "format_requested": "default",
+  "thumbnail_url": "http://cbsnews1.cbsistatic.com/hub/i/r/2010/12/04/b4733738-3ab3-11e3-a4cb-047d7b15b92e/thumbnail/140x90/48_1204_FULLMOON.jpg?hash=c648488e529d5d009d7112ace95527ba";,
   "link": [
     {
       "id": "1",
-      "length_bytes": "105048222",
-      "content_type": "video/x-m4v",
-      "file_suffix": "m4v",
+      "length_bytes": "257876782",
+      "content_type": "video/x-flv",
+      "file_suffix": "flv",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/collegehumor.json libquvi-scripts-0.4.21/tests/data/format/default/collegehumor.json
--- libquvi-scripts-0.4.19/tests/data/format/default/collegehumor.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/collegehumor.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,18 @@
+{
+  "host": "collegehumor",
+  "page_title": "GTA 5 is So Realistic It's Boring",
+  "page_url": "http://www.collegehumor.com/video/6919684/gta-5-is-so-realistic-its-boring";,
+  "id": "6919684",
+  "format_requested": "default",
+  "thumbnail_url": "http://0.media.collegehumor.cvcdn.com/57/71/c426d0ed5f4f725cfd00c5e7c0c93bfb-gta-5-is-so-realistic-its-boring.jpg";,
+  "duration": "121000",
+  "link": [
+    {
+      "id": "1",
+      "length_bytes": "10667224",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/d17.json libquvi-scripts-0.4.21/tests/data/format/default/d17.json
--- libquvi-scripts-0.4.19/tests/data/format/default/d17.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/d17.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,14 @@
+{
+  "host": "canalplus",
+  "page_title": "Top D17",
+  "page_url": "http://www.d17.tv/musique/pid6282-les-tops.html?vid=976488";,
+  "id": "976488",
+  "format_requested": "default",
+  "thumbnail_url": "http://media.canal-plus.com/wwwplus/image/48/2/5/VIGNETTE_AUTO_497105_L.jpg";,
+  "link": [
+    {
+      "id": "1",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/d8.json libquvi-scripts-0.4.21/tests/data/format/default/d8.json
--- libquvi-scripts-0.4.19/tests/data/format/default/d8.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/d8.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,14 @@
+{
+  "host": "canalplus",
+  "page_title": "Very Bad Blagues - Saison 2",
+  "page_url": "http://www.d8.tv/c-divertissement/d8-palmashow/pid5036-vbb-saison-2.html?vid=776533";,
+  "id": "776533",
+  "format_requested": "default",
+  "thumbnail_url": "http://media.canal-plus.com/wwwplus/image/38/3/4/PALMASHOW_VBB_-_SAISON_2_121210_CAN_301258_image_L.jpg";,
+  "link": [
+    {
+      "id": "1",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/dorkly.json libquvi-scripts-0.4.21/tests/data/format/default/dorkly.json
--- libquvi-scripts-0.4.19/tests/data/format/default/dorkly.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/dorkly.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,18 @@
+{
+  "host": "dorkly",
+  "page_title": "Ice World Problems",
+  "page_url": "http://www.dorkly.com/video/48596/ice-world-problems";,
+  "id": "48596",
+  "format_requested": "default",
+  "thumbnail_url": "http://0.media.dorkly.cvcdn.com/49/16/717059ee647f7cf5aefaabd676678808-ice-world-problems.jpg";,
+  "duration": "86000",
+  "link": [
+    {
+      "id": "1",
+      "length_bytes": "25317087",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/fixme/collegehumor.json libquvi-scripts-0.4.21/tests/data/format/default/fixme/collegehumor.json
--- libquvi-scripts-0.4.19/tests/data/format/default/fixme/collegehumor.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/fixme/collegehumor.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-{
-  "host": "collegehumor",
-  "page_title": "Porn Tech Support (with Kunal Nayyar)",
-  "page_url": "http://www.collegehumor.com/video:1942317";,
-  "id": "1942317",
-  "format_requested": "default",
-  "thumbnail_url": "http://9.media.collegehumor.cvcdn.com/36/45/24755184b1d36ab5dda4153df1d88377.jpg";,
-  "link": [
-    {
-      "id": "1",
-      "length_bytes": "11679239",
-      "content_type": "video/mp4",
-      "file_suffix": "mp4",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/fixme/imdb.json libquvi-scripts-0.4.21/tests/data/format/default/fixme/imdb.json
--- libquvi-scripts-0.4.19/tests/data/format/default/fixme/imdb.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/fixme/imdb.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,17 @@
+{
+  "host": "imdb",
+  "page_title": "The Dark Knight Rises Trailer (No. 1)",
+  "page_url": "http://www.imdb.com/video/imdb/vi2823134745/";,
+  "id": "vi2823134745",
+  "format_requested": "default",
+  "thumbnail_url": "http://ia.media-imdb.com/images/M/MV5BMTg1ODYxODAyNF5BMl5BanBnXkFtZTcwMDMyODY2Nw@@._V1_.jpg";,
+  "link": [
+    {
+      "id": "1",
+      "length_bytes": "47220147",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/fixme/justintv.json libquvi-scripts-0.4.21/tests/data/format/default/fixme/justintv.json
--- libquvi-scripts-0.4.19/tests/data/format/default/fixme/justintv.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/fixme/justintv.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,17 @@
+{
+  "host": "justintv",
+  "page_title": "TSM Dyrus 2200+ Smurf NA",
+  "page_url": "http://www.twitch.tv/tsm_dyrus/b/325011119";,
+  "id": "325011119",
+  "format_requested": "default",
+  "thumbnail_url": "http://static-cdn.jtvnw.net/jtv.thumbs/archive-325011119-150x113.jpg";,
+  "link": [
+    {
+      "id": "1",
+      "length_bytes": "967914356",
+      "content_type": "video/x-flv",
+      "file_suffix": "flv",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/fixme/wdrmaus_es.json libquvi-scripts-0.4.21/tests/data/format/default/fixme/wdrmaus_es.json
--- libquvi-scripts-0.4.19/tests/data/format/default/fixme/wdrmaus_es.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/fixme/wdrmaus_es.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,14 @@
+{
+  "host": "wdrmaus",
+  "page_title": "Anke tanzt Zootiere",
+  "page_url": "http://www.wdrmaus.de/elefantenseite/#/anke_tanzt_zooztiere";,
+  "id": "anke_tanzt_zooztiere",
+  "format_requested": "default",
+  "thumbnail_url": "http://www.wdr.de/bilder/mediendb/elefant_online/images/Kinderseiten/Filme/Anke/a207_anke_tanzt_zoo.jpg";,
+  "link": [
+    {
+      "id": "1",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/fixme/wdrmaus_kbbs.json libquvi-scripts-0.4.21/tests/data/format/default/fixme/wdrmaus_kbbs.json
--- libquvi-scripts-0.4.19/tests/data/format/default/fixme/wdrmaus_kbbs.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/fixme/wdrmaus_kbbs.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,14 @@
+{
+  "host": "wdrmaus",
+  "page_title": "Käpt&#8217;n Blaubärs kuriose Kombüsenküche: Marzipankartoffel",
+  "page_url": "http://www.wdrmaus.de/kaeptnblaubaerseite/baerchen/tv.php5?mid=1&dslSrc=rtmp://gffstream.fcod.llnwd.net/a792/e2/blaubaer/flash/oink_web-m.flv&isdnSrc=rtmp://gffstream.fcod.llnwd.net/a792/e2/blaubaer/flash/oink_web-s.flv";,
+  "id": "oink_web-s.flv",
+  "format_requested": "default",
+  "thumbnail_url": "http://www.wdrmaus.de/kaeptnblaubaerseite/baerchen/img/icon_film_03.gif";,
+  "link": [
+    {
+      "id": "1",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/fixme/wdrmaus_sg.json libquvi-scripts-0.4.21/tests/data/format/default/fixme/wdrmaus_sg.json
--- libquvi-scripts-0.4.19/tests/data/format/default/fixme/wdrmaus_sg.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/format/default/fixme/wdrmaus_sg.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,13 @@
+{
+  "host": "wdrmaus",
+  "page_title": "40. MausGeburtstag",
+  "page_url": "http://www.wdrmaus.de/sachgeschichten/sachgeschichten/sachgeschichte.php5?id=2702";,
+  "id": "2702",
+  "format_requested": "default",
+  "link": [
+    {
+      "id": "1",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/ignore/length_bytes/ted.json libquvi-scripts-0.4.21/tests/data/format/default/ignore/length_bytes/ted.json
--- libquvi-scripts-0.4.19/tests/data/format/default/ignore/length_bytes/ted.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/ignore/length_bytes/ted.json	2013-11-30 16:50:25.000000000 +0100
@@ -1,6 +1,6 @@
 {
   "host": "ted",
-  "page_title": "Eythor Bender demos human exoskeletons",
+  "page_title": "Eythor Bender: Human exoskeletons -- for war and healing",
   "page_url": "http://www.ted.com/talks/eythor_bender_demos_human_exoskeletons.html";,
   "id": "1104",
   "format_requested": "default",
@@ -8,7 +8,7 @@
   "link": [
     {
       "id": "1",
-      "length_bytes": "15904785",
+      "length_bytes": "23724573",
       "content_type": "video/mp4",
       "file_suffix": "mp4",
       "url": ""
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/imdb.json libquvi-scripts-0.4.21/tests/data/format/default/imdb.json
--- libquvi-scripts-0.4.19/tests/data/format/default/imdb.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/imdb.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-{
-  "host": "imdb",
-  "page_title": "The Dark Knight Rises Trailer (No. 1)",
-  "page_url": "http://www.imdb.com/video/imdb/vi2823134745/";,
-  "id": "vi2823134745",
-  "format_requested": "default",
-  "thumbnail_url": "http://ia.media-imdb.com/images/M/MV5BMTg1ODYxODAyNF5BMl5BanBnXkFtZTcwMDMyODY2Nw@@._V1_.jpg";,
-  "link": [
-    {
-      "id": "1",
-      "length_bytes": "47220147",
-      "content_type": "video/mp4",
-      "file_suffix": "mp4",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/justintv.json libquvi-scripts-0.4.21/tests/data/format/default/justintv.json
--- libquvi-scripts-0.4.19/tests/data/format/default/justintv.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/justintv.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-{
-  "host": "justintv",
-  "page_title": "TSM Dyrus 2200+ Smurf NA",
-  "page_url": "http://www.twitch.tv/tsm_dyrus/b/325011119";,
-  "id": "325011119",
-  "format_requested": "default",
-  "thumbnail_url": "http://static-cdn.jtvnw.net/jtv.thumbs/archive-325011119-150x113.jpg";,
-  "link": [
-    {
-      "id": "1",
-      "length_bytes": "967914356",
-      "content_type": "video/x-flv",
-      "file_suffix": "flv",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/nsfw/redtube.json libquvi-scripts-0.4.21/tests/data/format/default/nsfw/redtube.json
--- libquvi-scripts-0.4.19/tests/data/format/default/nsfw/redtube.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/nsfw/redtube.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,13 +4,13 @@
   "page_url": "http://www.redtube.com/179914";,
   "id": "179914",
   "format_requested": "default",
-  "thumbnail_url": "http://img01.redtubefiles.com/_thumbs/0000179/0179914/0179914_003i.jpg";,
+  "thumbnail_url": "http://img03.redtubefiles.com/_thumbs/0000179/0179914/0179914_003i.jpg";,
   "link": [
     {
       "id": "1",
       "length_bytes": "220142123",
-      "content_type": "application/octet-stream",
-      "file_suffix": "flv",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/nsfw/spankwire.json libquvi-scripts-0.4.21/tests/data/format/default/nsfw/spankwire.json
--- libquvi-scripts-0.4.19/tests/data/format/default/nsfw/spankwire.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/nsfw/spankwire.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,6 +4,7 @@
   "page_url": "http://www.spankwire.com/tess-ellen-dancing/video284158/";,
   "id": "284158",
   "format_requested": "default",
+  "thumbnail_url": "http://cdn1.image.spankwire.phncdn.com/201107/02/284158/320X240/4.jpg";,
   "link": [
     {
       "id": "1",
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/nsfw/tcmag.json libquvi-scripts-0.4.21/tests/data/format/default/nsfw/tcmag.json
--- libquvi-scripts-0.4.19/tests/data/format/default/nsfw/tcmag.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/nsfw/tcmag.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,6 +4,7 @@
   "page_url": "http://www.tcmag.com/magazine/so_beautiful_it_hurts/";,
   "id": "mxwgmnU3x0FcAwd8",
   "format_requested": "default",
+  "thumbnail_url": "http://www.tcmag.com/images/thumbnails/960/reckt_op_een_truck_2__large.jpg";,
   "link": [
     {
       "id": "1",
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/publicsenat-2.json libquvi-scripts-0.4.21/tests/data/format/default/publicsenat-2.json
--- libquvi-scripts-0.4.19/tests/data/format/default/publicsenat-2.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/publicsenat-2.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-{
-  "host": "publicsenat",
-  "page_title": "Public Sénat",
-  "page_url": "http://www.publicsenat.fr/cms/video-a-la-demande/vod.html?idE=119298";,
-  "id": "119298",
-  "format_requested": "default",
-  "thumbnail_url": "http://publicsenat.fr/photo/vignettes/424265audition_20120530_1030-500k-150100.jpg";,
-  "link": [
-    {
-      "id": "1",
-      "length_bytes": "475067700",
-      "content_type": "video/x-flv",
-      "file_suffix": "flv",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/publicsenat.json libquvi-scripts-0.4.21/tests/data/format/default/publicsenat.json
--- libquvi-scripts-0.4.19/tests/data/format/default/publicsenat.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/publicsenat.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,13 +4,13 @@
   "page_url": "http://www.publicsenat.fr/vod/un-monde-de-bulles/speciale-journal-de-spirou/67141";,
   "id": "67141",
   "format_requested": "default",
-  "thumbnail_url": "http://publicsenat.fr/photo/vignettes/424265bulles_20101217-500k-250100.jpg";,
+  "thumbnail_url": "http://static.dmcloud.net/522497e194a6f650d300002d/5270069706361d7401000014/jpeg_thumbnail_source-1383069857.jpeg";,
   "link": [
     {
       "id": "1",
-      "length_bytes": "138643826",
-      "content_type": "video/x-flv",
-      "file_suffix": "flv",
+      "length_bytes": "101479883",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/ted.json libquvi-scripts-0.4.21/tests/data/format/default/ted.json
--- libquvi-scripts-0.4.19/tests/data/format/default/ted.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/ted.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-{
-  "host": "ted",
-  "page_title": "Daniel Kahneman: The riddle of experience vs. memory",
-  "page_url": "http://www.ted.com/talks/daniel_kahneman_the_riddle_of_experience_vs_memory.html";,
-  "id": "779",
-  "format_requested": "default",
-  "thumbnail_url": "http://images.ted.com/images/ted/152920_389x292.jpg";,
-  "link": [
-    {
-      "id": "1",
-      "length_bytes": "68798683",
-      "content_type": "video/mp4",
-      "file_suffix": "mp4",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/vimeo.json libquvi-scripts-0.4.21/tests/data/format/default/vimeo.json
--- libquvi-scripts-0.4.19/tests/data/format/default/vimeo.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/vimeo.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,12 +4,12 @@
   "page_url": "http://vimeo.com/42605731";,
   "id": "42605731",
   "format_requested": "default",
-  "thumbnail_url": "http://b.vimeocdn.com/ts/328/038/328038708_960.jpg";,
+  "thumbnail_url": "http://b.vimeocdn.com/ts/328/038/328038708_640.jpg";,
   "duration": "230000",
   "link": [
     {
       "id": "1",
-      "length_bytes": "24893958",
+      "length_bytes": "75757171",
       "content_type": "video/mp4",
       "file_suffix": "mp4",
       "url": ""
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/wdrmaus_es.json libquvi-scripts-0.4.21/tests/data/format/default/wdrmaus_es.json
--- libquvi-scripts-0.4.19/tests/data/format/default/wdrmaus_es.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/wdrmaus_es.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,14 +0,0 @@
-{
-  "host": "wdrmaus",
-  "page_title": "Anke tanzt Zootiere",
-  "page_url": "http://www.wdrmaus.de/elefantenseite/#/anke_tanzt_zooztiere";,
-  "id": "anke_tanzt_zooztiere",
-  "format_requested": "default",
-  "thumbnail_url": "http://www.wdr.de/bilder/mediendb/elefant_online/images/Kinderseiten/Filme/Anke/a207_anke_tanzt_zoo.jpg";,
-  "link": [
-    {
-      "id": "1",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/wdrmaus_kbbs.json libquvi-scripts-0.4.21/tests/data/format/default/wdrmaus_kbbs.json
--- libquvi-scripts-0.4.19/tests/data/format/default/wdrmaus_kbbs.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/wdrmaus_kbbs.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,14 +0,0 @@
-{
-  "host": "wdrmaus",
-  "page_title": "Käpt&#8217;n Blaubärs kuriose Kombüsenküche: Marzipankartoffel",
-  "page_url": "http://www.wdrmaus.de/kaeptnblaubaerseite/baerchen/tv.php5?mid=1&dslSrc=rtmp://gffstream.fcod.llnwd.net/a792/e2/blaubaer/flash/oink_web-m.flv&isdnSrc=rtmp://gffstream.fcod.llnwd.net/a792/e2/blaubaer/flash/oink_web-s.flv";,
-  "id": "oink_web-s.flv",
-  "format_requested": "default",
-  "thumbnail_url": "http://www.wdrmaus.de/kaeptnblaubaerseite/baerchen/img/icon_film_03.gif";,
-  "link": [
-    {
-      "id": "1",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/wdrmaus_sg.json libquvi-scripts-0.4.21/tests/data/format/default/wdrmaus_sg.json
--- libquvi-scripts-0.4.19/tests/data/format/default/wdrmaus_sg.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/wdrmaus_sg.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,13 +0,0 @@
-{
-  "host": "wdrmaus",
-  "page_title": "40. MausGeburtstag",
-  "page_url": "http://www.wdrmaus.de/sachgeschichten/sachgeschichten/sachgeschichte.php5?id=2702";,
-  "id": "2702",
-  "format_requested": "default",
-  "link": [
-    {
-      "id": "1",
-      "url": ""
-    }
-  ]
-}
diff -Nru libquvi-scripts-0.4.19/tests/data/format/default/youtube.json libquvi-scripts-0.4.21/tests/data/format/default/youtube.json
--- libquvi-scripts-0.4.19/tests/data/format/default/youtube.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/format/default/youtube.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,14 +4,14 @@
   "page_url": "http://www.youtube.com/watch?v=9dgSa4wmMzk";,
   "id": "9dgSa4wmMzk",
   "format_requested": "default",
-  "thumbnail_url": "http://i2.ytimg.com/vi/9dgSa4wmMzk/default.jpg";,
+  "thumbnail_url": "http://i1.ytimg.com/vi/9dgSa4wmMzk/default.jpg";,
   "duration": "130000",
   "link": [
     {
       "id": "1",
-      "length_bytes": "18479570",
-      "content_type": "video/webm",
-      "file_suffix": "webm",
+      "length_bytes": "36405064",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_101greatgoals-1.json libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_101greatgoals-1.json
--- libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_101greatgoals-1.json	1970-01-01 01:00:00.000000000 +0100
+++ libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_101greatgoals-1.json	2013-11-30 16:50:25.000000000 +0100
@@ -0,0 +1,18 @@
+{
+  "host": "youtube",
+  "page_title": "Mourinho on his haircut: 'I did it myself, it's nice and cheap'",
+  "page_url": "http://www.youtube.com/embed/K3XDDBfODqA?rel=0";,
+  "id": "K3XDDBfODqA",
+  "format_requested": "default",
+  "thumbnail_url": "http://i1.ytimg.com/vi/K3XDDBfODqA/default.jpg";,
+  "duration": "37000",
+  "link": [
+    {
+      "id": "1",
+      "length_bytes": "11271005",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
+      "url": ""
+    }
+  ]
+}
diff -Nru libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_101greatgoals.json libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_101greatgoals.json
--- libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_101greatgoals.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_101greatgoals.json	2013-11-30 16:50:25.000000000 +0100
@@ -9,9 +9,9 @@
   "link": [
     {
       "id": "1",
-      "length_bytes": "2804005",
-      "content_type": "video/x-flv",
-      "file_suffix": "flv",
+      "length_bytes": "2308237",
+      "content_type": "video/webm",
+      "file_suffix": "webm",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_bikeradar.json libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_bikeradar.json
--- libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_bikeradar.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_bikeradar.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,14 +4,14 @@
   "page_url": "http://www.youtube.com/v/6iaG4eCGw_Y";,
   "id": "6iaG4eCGw_Y",
   "format_requested": "default",
-  "thumbnail_url": "http://i3.ytimg.com/vi/6iaG4eCGw_Y/default.jpg";,
+  "thumbnail_url": "http://i1.ytimg.com/vi/6iaG4eCGw_Y/default.jpg";,
   "duration": "141000",
   "link": [
     {
       "id": "1",
-      "length_bytes": "16623496",
-      "content_type": "video/webm",
-      "file_suffix": "webm",
+      "length_bytes": "33445284",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_dorkly.json libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_dorkly.json
--- libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_dorkly.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_dorkly.json	2013-11-30 16:50:25.000000000 +0100
@@ -1,17 +1,17 @@
 {
   "host": "youtube",
   "page_title": "Battlefield: Bad Company 2 - Supply Ownage",
-  "page_url": "http://youtube.com/watch?v=v9PALCGjxsE";,
+  "page_url": "http://www.youtube.com/embed/v9PALCGjxsE?rel=0";,
   "id": "v9PALCGjxsE",
   "format_requested": "default",
-  "thumbnail_url": "http://i3.ytimg.com/vi/v9PALCGjxsE/default.jpg";,
+  "thumbnail_url": "http://i1.ytimg.com/vi/v9PALCGjxsE/default.jpg";,
   "duration": "189000",
   "link": [
     {
       "id": "1",
-      "length_bytes": "7324273",
-      "content_type": "video/x-flv",
-      "file_suffix": "flv",
+      "length_bytes": "49297410",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_liveleak.json libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_liveleak.json
--- libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_liveleak.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_liveleak.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,14 +4,14 @@
   "page_url": "http://www.youtube.com/embed/C2hk6d_8Gt4?rel=0";,
   "id": "C2hk6d_8Gt4",
   "format_requested": "default",
-  "thumbnail_url": "http://i4.ytimg.com/vi/C2hk6d_8Gt4/default.jpg";,
+  "thumbnail_url": "http://i1.ytimg.com/vi/C2hk6d_8Gt4/default.jpg";,
   "duration": "44000",
   "link": [
     {
       "id": "1",
-      "length_bytes": "6943044",
-      "content_type": "video/webm",
-      "file_suffix": "webm",
+      "length_bytes": "11645264",
+      "content_type": "video/mp4",
+      "file_suffix": "mp4",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_ted.json libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_ted.json
--- libquvi-scripts-0.4.19/tests/data/resolve/redirect_url_ted.json	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/data/resolve/redirect_url_ted.json	2013-11-30 16:50:25.000000000 +0100
@@ -4,14 +4,14 @@
   "page_url": "https://www.youtube.com/embed/9APO9_yNbcg?autoplay=1&enablejsapi=1&fs=1&iv_load_policy=1&modestbranding=1&origin=http%3A%2F%2Fwww.ted.com%2F&rel=0&showinfo=0";,
   "id": "9APO9_yNbcg",
   "format_requested": "default",
-  "thumbnail_url": "https://i2.ytimg.com/vi/9APO9_yNbcg/default.jpg";,
+  "thumbnail_url": "https://i1.ytimg.com/vi/9APO9_yNbcg/default.jpg";,
   "duration": "1016000",
   "link": [
     {
       "id": "1",
-      "length_bytes": "61568690",
-      "content_type": "video/x-flv",
-      "file_suffix": "flv",
+      "length_bytes": "49386785",
+      "content_type": "video/webm",
+      "file_suffix": "webm",
       "url": ""
     }
   ]
diff -Nru libquvi-scripts-0.4.19/tests/t/expire.t libquvi-scripts-0.4.21/tests/t/expire.t
--- libquvi-scripts-0.4.19/tests/t/expire.t	2013-10-04 12:51:36.000000000 +0200
+++ libquvi-scripts-0.4.21/tests/t/expire.t	2013-11-30 16:50:25.000000000 +0100
@@ -35,11 +35,11 @@
 $ua->env_proxy;
 
 my %h = (
-  "http://videos.arte.tv"; => sub {
+  "http://www.arte.tv/guide/fr/plus7.json"; => sub {
     my ($p) = @_;
-    my $q = qr|<h2><a href="/(\w\w)/videos/(.*?)"|;
+    my $q = qr|"url":"(.*?)"|;
     my @l;
-    push @l, "http://videos.arte.tv/$1/videos/$2";  while $p =~ /$q/g;
+    push @l, "http://www.arte.tv$1";  while $p =~ /$q/g;
     my $n = ceil(scalar @l/2);
     $l[$n];
   },

Reply to: