1# -*- coding: utf-8 -*-
2#
3# gPodder - A media aggregator and podcast client
4# Copyright (c) 2005-2018 The gPodder Team
5#
6# gPodder is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or
9# (at your option) any later version.
10#
11# gPodder is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18#
19
20#
21#  gpodder.vimeo - Vimeo download magic
22#  Thomas Perl <thp@gpodder.org>; 2012-01-03
23#
24
25
26import json
27import logging
28import re
29
30import gpodder
31from gpodder import registry, util
32
33_ = gpodder.gettext
34
35logger = logging.getLogger(__name__)
36
37
38VIMEOCOM_RE = re.compile(r'http[s]?://vimeo\.com/(channels/[^/]+|\d+)$', re.IGNORECASE)
39VIMEOCOM_VIDEO_RE = re.compile(r'http[s]?://vimeo.com/channels/(?:[^/])+/(\d+)$', re.IGNORECASE)
40MOOGALOOP_RE = re.compile(r'http[s]?://vimeo\.com/moogaloop\.swf\?clip_id=(\d+)$', re.IGNORECASE)
41SIGNATURE_RE = re.compile(r'"timestamp":(\d+),"signature":"([^"]+)"')
42
43# List of qualities, from lowest to highest
44FILEFORMAT_RANKING = ['270p', '360p', '720p', '1080p']
45
46FORMATS = tuple((x, x) for x in FILEFORMAT_RANKING)
47
48
49class VimeoError(BaseException): pass
50
51
52@registry.download_url.register
53def vimeo_real_download_url(config, episode, allow_partial):
54    fmt = config.vimeo.fileformat if config else None
55    res = get_real_download_url(episode.url, preferred_fileformat=fmt)
56    return None if res == episode.url else res
57
58
59def get_real_download_url(url, preferred_fileformat=None):
60    video_id = get_vimeo_id(url)
61
62    if video_id is None:
63        return url
64
65    data_config_url = 'https://player.vimeo.com/video/%s/config' % (video_id,)
66
67    def get_urls(data_config_url):
68        data_config_data = util.urlopen(data_config_url).read().decode('utf-8')
69        data_config = json.loads(data_config_data)
70        for fileinfo in list(data_config['request']['files'].values()):
71            if not isinstance(fileinfo, list):
72                continue
73
74            for item in fileinfo:
75                yield (item['quality'], item['url'])
76
77    fileformat_to_url = dict(get_urls(data_config_url))
78
79    if preferred_fileformat is not None and preferred_fileformat in fileformat_to_url:
80        logger.debug('Picking preferred format: %s', preferred_fileformat)
81        return fileformat_to_url[preferred_fileformat]
82
83    def fileformat_sort_key_func(fileformat):
84        if fileformat in FILEFORMAT_RANKING:
85            return FILEFORMAT_RANKING.index(fileformat)
86
87        return 0
88
89    for fileformat in sorted(fileformat_to_url, key=fileformat_sort_key_func, reverse=True):
90        logger.debug('Picking best format: %s', fileformat)
91        return fileformat_to_url[fileformat]
92
93    return url
94
95
96def get_vimeo_id(url):
97    result = MOOGALOOP_RE.match(url)
98    if result is not None:
99        return result.group(1)
100
101    result = VIMEOCOM_RE.match(url)
102    if result is not None:
103        return result.group(1)
104
105    result = VIMEOCOM_VIDEO_RE.match(url)
106    if result is not None:
107        return result.group(1)
108
109    return None
110
111
112def is_video_link(url):
113    return (get_vimeo_id(url) is not None)
114
115
116def get_real_channel_url(url):
117    result = VIMEOCOM_RE.match(url)
118    if result is not None:
119        return 'http://vimeo.com/%s/videos/rss' % result.group(1)
120
121    return url
122
123
124def get_real_cover(url):
125    return None
126