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

ccma.py (7050B)


  1. from .common import InfoExtractor
  2. from ..utils import (
  3. clean_html,
  4. determine_ext,
  5. int_or_none,
  6. parse_duration,
  7. parse_resolution,
  8. try_get,
  9. unified_timestamp,
  10. url_or_none,
  11. )
  12. class CCMAIE(InfoExtractor):
  13. IE_DESC = '3Cat, TV3 and Catalunya Ràdio'
  14. _VALID_URL = r'https?://(?:www\.)?3cat\.cat/(?:3cat|tv3/sx3)/[^/?#]+/(?P<type>video|audio)/(?P<id>\d+)'
  15. _TESTS = [{
  16. # ccma.cat/tv3/alacarta/ URLs redirect to 3cat.cat/3cat/
  17. 'url': 'https://www.3cat.cat/3cat/lespot-de-la-marato-de-tv3/video/5630208/',
  18. 'md5': '7296ca43977c8ea4469e719c609b0871',
  19. 'info_dict': {
  20. 'id': '5630208',
  21. 'ext': 'mp4',
  22. 'title': 'L\'espot de La Marató 2016: Ictus i les lesions medul·lars i cerebrals traumàtiques',
  23. 'description': 'md5:f12987f320e2f6e988e9908e4fe97765',
  24. 'timestamp': 1478608140,
  25. 'upload_date': '20161108',
  26. 'age_limit': 0,
  27. 'alt_title': 'EsportMarató2016WEB_PerPublicar',
  28. 'duration': 79,
  29. 'thumbnail': 'https://img.3cat.cat/multimedia/jpg/4/6/1478536106664.jpg',
  30. 'series': 'Dedicada a l\'ictus i les lesions medul·lars i cerebrals traumàtiques',
  31. 'categories': ['Divulgació'],
  32. },
  33. }, {
  34. # ccma.cat/catradio/alacarta/ URLs redirect to 3cat.cat/3cat/
  35. 'url': 'https://www.3cat.cat/3cat/el-consell-de-savis-analitza-el-derbi/audio/943685/',
  36. 'md5': 'fa3e38f269329a278271276330261425',
  37. 'info_dict': {
  38. 'id': '943685',
  39. 'ext': 'mp3',
  40. 'title': 'El Consell de Savis analitza el derbi',
  41. 'description': 'md5:e2a3648145f3241cb9c6b4b624033e53',
  42. 'upload_date': '20161217',
  43. 'timestamp': 1482011700,
  44. 'vcodec': 'none',
  45. 'categories': ['Esports'],
  46. 'series': 'Tot gira',
  47. 'duration': 821,
  48. 'thumbnail': 'https://img.3cat.cat/multimedia/jpg/8/9/1482002602598.jpg',
  49. },
  50. }, {
  51. 'url': 'https://www.3cat.cat/3cat/crims-josep-tallada-lespereu-me-part-1/video/6031387/',
  52. 'md5': '27493513d08a3e5605814aee9bb778d2',
  53. 'info_dict': {
  54. 'id': '6031387',
  55. 'ext': 'mp4',
  56. 'title': 'T1xC5 - Josep Talleda, l\'"Espereu-me" (part 1)',
  57. 'description': 'md5:7cbdafb640da9d0d2c0f62bad1e74e60',
  58. 'timestamp': 1582577919,
  59. 'upload_date': '20200224',
  60. 'subtitles': 'mincount:1',
  61. 'age_limit': 13,
  62. 'series': 'Crims',
  63. 'thumbnail': 'https://img.3cat.cat/multimedia/jpg/1/9/1582564376991.jpg',
  64. 'duration': 3203,
  65. 'categories': ['Divulgació'],
  66. 'alt_title': 'Crims - 5 - Josep Talleda, l\'"Espereu-me" (1a part) - Josep Talleda, l\'"Espereu-me" (part 1)',
  67. 'episode_number': 5,
  68. 'episode': 'Episode 5',
  69. },
  70. }, {
  71. 'url': 'https://www.3cat.cat/tv3/sx3/una-mosca-volava-per-la-llum/video/5759227/',
  72. 'info_dict': {
  73. 'id': '5759227',
  74. 'ext': 'mp4',
  75. 'title': 'Una mosca volava per la llum',
  76. 'alt_title': '17Z004Ç UNA MOSCA VOLAVA PER LA LLUM',
  77. 'description': 'md5:9ab64276944b0825336f4147f13f7854',
  78. 'series': 'Mic',
  79. 'upload_date': '20180411',
  80. 'timestamp': 1523440105,
  81. 'duration': 160,
  82. 'age_limit': 0,
  83. 'thumbnail': 'https://img.3cat.cat/multimedia/jpg/6/1/1524071667216.jpg',
  84. 'categories': ['Música'],
  85. },
  86. }]
  87. def _real_extract(self, url):
  88. media_type, media_id = self._match_valid_url(url).group('type', 'id')
  89. media = self._download_json(
  90. 'http://api-media.3cat.cat/pvideo/media.jsp', media_id, query={
  91. 'media': media_type,
  92. 'idint': media_id,
  93. 'format': 'dm',
  94. })
  95. formats = []
  96. media_url = media['media']['url']
  97. if isinstance(media_url, list):
  98. for format_ in media_url:
  99. format_url = url_or_none(format_.get('file'))
  100. if not format_url:
  101. continue
  102. if determine_ext(format_url) == 'mpd':
  103. formats.extend(self._extract_mpd_formats(
  104. format_url, media_id, mpd_id='dash', fatal=False))
  105. continue
  106. label = format_.get('label')
  107. f = parse_resolution(label)
  108. f.update({
  109. 'url': format_url,
  110. 'format_id': label,
  111. })
  112. formats.append(f)
  113. else:
  114. formats.append({
  115. 'url': media_url,
  116. 'vcodec': 'none' if media_type == 'audio' else None,
  117. })
  118. informacio = media['informacio']
  119. title = informacio['titol']
  120. durada = informacio.get('durada') or {}
  121. duration = int_or_none(durada.get('milisegons'), 1000) or parse_duration(durada.get('text'))
  122. tematica = try_get(informacio, lambda x: x['tematica']['text'])
  123. data_utc = try_get(informacio, lambda x: x['data_emissio']['utc'])
  124. timestamp = unified_timestamp(data_utc)
  125. subtitles = {}
  126. subtitols = media.get('subtitols') or []
  127. if isinstance(subtitols, dict):
  128. subtitols = [subtitols]
  129. for st in subtitols:
  130. sub_url = st.get('url')
  131. if sub_url:
  132. subtitles.setdefault(
  133. st.get('iso') or st.get('text') or 'ca', []).append({
  134. 'url': sub_url,
  135. })
  136. thumbnails = []
  137. imatges = media.get('imatges', {})
  138. if imatges:
  139. thumbnail_url = imatges.get('url')
  140. if thumbnail_url:
  141. thumbnails = [{
  142. 'url': thumbnail_url,
  143. 'width': int_or_none(imatges.get('amplada')),
  144. 'height': int_or_none(imatges.get('alcada')),
  145. }]
  146. age_limit = None
  147. codi_etic = try_get(informacio, lambda x: x['codi_etic']['id'])
  148. if codi_etic:
  149. codi_etic_s = codi_etic.split('_')
  150. if len(codi_etic_s) == 2:
  151. if codi_etic_s[1] == 'TP':
  152. age_limit = 0
  153. else:
  154. age_limit = int_or_none(codi_etic_s[1])
  155. return {
  156. 'id': media_id,
  157. 'title': title,
  158. 'description': clean_html(informacio.get('descripcio')),
  159. 'duration': duration,
  160. 'timestamp': timestamp,
  161. 'thumbnails': thumbnails,
  162. 'subtitles': subtitles,
  163. 'formats': formats,
  164. 'age_limit': age_limit,
  165. 'alt_title': informacio.get('titol_complet'),
  166. 'episode_number': int_or_none(informacio.get('capitol')),
  167. 'categories': [tematica] if tematica else None,
  168. 'series': informacio.get('programa'),
  169. }