logo

oasis-root

Compiled tree of Oasis Linux based on own branch at <https://hacktivis.me/git/oasis/> git clone https://anongit.hacktivis.me/git/oasis-root.git

rtp.py (4184B)


  1. import base64
  2. import json
  3. import re
  4. import urllib.parse
  5. from .common import InfoExtractor
  6. from ..utils import js_to_json
  7. class RTPIE(InfoExtractor):
  8. _VALID_URL = r'https?://(?:www\.)?rtp\.pt/play/(?:(?:estudoemcasa|palco|zigzag)/)?p(?P<program_id>[0-9]+)/(?P<id>[^/?#]+)'
  9. _TESTS = [{
  10. 'url': 'http://www.rtp.pt/play/p405/e174042/paixoes-cruzadas',
  11. 'md5': 'e736ce0c665e459ddb818546220b4ef8',
  12. 'info_dict': {
  13. 'id': 'e174042',
  14. 'ext': 'mp3',
  15. 'title': 'Paixões Cruzadas',
  16. 'description': 'As paixões musicais de António Cartaxo e António Macedo',
  17. 'thumbnail': r're:^https?://.*\.jpg',
  18. },
  19. }, {
  20. 'url': 'https://www.rtp.pt/play/zigzag/p13166/e757904/25-curiosidades-25-de-abril',
  21. 'md5': '9a81ed53f2b2197cfa7ed455b12f8ade',
  22. 'info_dict': {
  23. 'id': 'e757904',
  24. 'ext': 'mp4',
  25. 'title': '25 Curiosidades, 25 de Abril',
  26. 'description': 'Estudar ou não estudar - Em cada um dos episódios descobrimos uma curiosidade acerca de como era viver em Portugal antes da revolução do 25 de abr',
  27. 'thumbnail': r're:^https?://.*\.jpg',
  28. },
  29. }, {
  30. 'url': 'http://www.rtp.pt/play/p831/a-quimica-das-coisas',
  31. 'only_matching': True,
  32. }, {
  33. 'url': 'https://www.rtp.pt/play/estudoemcasa/p7776/portugues-1-ano',
  34. 'only_matching': True,
  35. }, {
  36. 'url': 'https://www.rtp.pt/play/palco/p13785/l7nnon',
  37. 'only_matching': True,
  38. }]
  39. _RX_OBFUSCATION = re.compile(r'''(?xs)
  40. atob\s*\(\s*decodeURIComponent\s*\(\s*
  41. (\[[0-9A-Za-z%,'"]*\])
  42. \s*\.\s*join\(\s*(?:""|'')\s*\)\s*\)\s*\)
  43. ''')
  44. def __unobfuscate(self, data, *, video_id):
  45. if data.startswith('{'):
  46. data = self._RX_OBFUSCATION.sub(
  47. lambda m: json.dumps(
  48. base64.b64decode(urllib.parse.unquote(
  49. ''.join(self._parse_json(m.group(1), video_id)),
  50. )).decode('iso-8859-1')),
  51. data)
  52. return js_to_json(data)
  53. def _real_extract(self, url):
  54. video_id = self._match_id(url)
  55. webpage = self._download_webpage(url, video_id)
  56. title = self._html_search_meta(
  57. 'twitter:title', webpage, display_name='title', fatal=True)
  58. f, config = self._search_regex(
  59. r'''(?sx)
  60. (?:var\s+f\s*=\s*(?P<f>".*?"|{[^;]+?});\s*)?
  61. var\s+player1\s+=\s+new\s+RTPPlayer\s*\((?P<config>{(?:(?!\*/).)+?})\);(?!\s*\*/)
  62. ''', webpage,
  63. 'player config', group=('f', 'config'))
  64. config = self._parse_json(
  65. config, video_id,
  66. lambda data: self.__unobfuscate(data, video_id=video_id))
  67. f = config['file'] if not f else self._parse_json(
  68. f, video_id,
  69. lambda data: self.__unobfuscate(data, video_id=video_id))
  70. formats = []
  71. if isinstance(f, dict):
  72. f_hls = f.get('hls')
  73. if f_hls is not None:
  74. formats.extend(self._extract_m3u8_formats(
  75. f_hls, video_id, 'mp4', 'm3u8_native', m3u8_id='hls'))
  76. f_dash = f.get('dash')
  77. if f_dash is not None:
  78. formats.extend(self._extract_mpd_formats(f_dash, video_id, mpd_id='dash'))
  79. else:
  80. formats.append({
  81. 'format_id': 'f',
  82. 'url': f,
  83. 'vcodec': 'none' if config.get('mediaType') == 'audio' else None,
  84. })
  85. subtitles = {}
  86. vtt = config.get('vtt')
  87. if vtt is not None:
  88. for lcode, lname, url in vtt:
  89. subtitles.setdefault(lcode, []).append({
  90. 'name': lname,
  91. 'url': url,
  92. })
  93. return {
  94. 'id': video_id,
  95. 'title': title,
  96. 'formats': formats,
  97. 'description': self._html_search_meta(['description', 'twitter:description'], webpage),
  98. 'thumbnail': config.get('poster') or self._og_search_thumbnail(webpage),
  99. 'subtitles': subtitles,
  100. }