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