joqrag.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import datetime as dt
  2. import urllib.parse
  3. from .common import InfoExtractor
  4. from ..utils import (
  5. clean_html,
  6. datetime_from_str,
  7. unified_timestamp,
  8. urljoin,
  9. )
  10. class JoqrAgIE(InfoExtractor):
  11. IE_DESC = '超!A&G+ 文化放送 (f.k.a. AGQR) Nippon Cultural Broadcasting, Inc. (JOQR)'
  12. _VALID_URL = [r'https?://www\.uniqueradio\.jp/agplayer5/(?:player|inc-player-hls)\.php',
  13. r'https?://(?:www\.)?joqr\.co\.jp/ag/',
  14. r'https?://(?:www\.)?joqr\.co\.jp/qr/ag(?:daily|regular)program/?(?:$|[#?])']
  15. _TESTS = [{
  16. 'url': 'https://www.uniqueradio.jp/agplayer5/player.php',
  17. 'info_dict': {
  18. 'id': 'live',
  19. 'title': str,
  20. 'channel': '超!A&G+',
  21. 'description': str,
  22. 'live_status': 'is_live',
  23. 'release_timestamp': int,
  24. },
  25. 'params': {
  26. 'skip_download': True,
  27. 'ignore_no_formats_error': True,
  28. },
  29. }, {
  30. 'url': 'https://www.uniqueradio.jp/agplayer5/inc-player-hls.php',
  31. 'only_matching': True,
  32. }, {
  33. 'url': 'https://www.joqr.co.jp/ag/article/103760/',
  34. 'only_matching': True,
  35. }, {
  36. 'url': 'http://www.joqr.co.jp/qr/agdailyprogram/',
  37. 'only_matching': True,
  38. }, {
  39. 'url': 'http://www.joqr.co.jp/qr/agregularprogram/',
  40. 'only_matching': True,
  41. }]
  42. def _extract_metadata(self, variable, html):
  43. return clean_html(urllib.parse.unquote_plus(self._search_regex(
  44. rf'var\s+{variable}\s*=\s*(["\'])(?P<value>(?:(?!\1).)+)\1',
  45. html, 'metadata', group='value', default=''))) or None
  46. def _extract_start_timestamp(self, video_id, is_live):
  47. def extract_start_time_from(date_str):
  48. dt_ = datetime_from_str(date_str) + dt.timedelta(hours=9)
  49. date = dt_.strftime('%Y%m%d')
  50. start_time = self._search_regex(
  51. r'<h3[^>]+\bclass="dailyProgram-itemHeaderTime"[^>]*>[\s\d:]+–\s*(\d{1,2}:\d{1,2})',
  52. self._download_webpage(
  53. f'https://www.joqr.co.jp/qr/agdailyprogram/?date={date}', video_id,
  54. note=f'Downloading program list of {date}', fatal=False,
  55. errnote=f'Failed to download program list of {date}') or '',
  56. 'start time', default=None)
  57. if start_time:
  58. return unified_timestamp(f'{dt_.strftime("%Y/%m/%d")} {start_time} +09:00')
  59. return None
  60. start_timestamp = extract_start_time_from('today')
  61. if not start_timestamp:
  62. return None
  63. if not is_live or start_timestamp < datetime_from_str('now').timestamp():
  64. return start_timestamp
  65. else:
  66. return extract_start_time_from('yesterday')
  67. def _real_extract(self, url):
  68. video_id = 'live'
  69. metadata = self._download_webpage(
  70. 'https://www.uniqueradio.jp/aandg', video_id,
  71. note='Downloading metadata', errnote='Failed to download metadata')
  72. title = self._extract_metadata('Program_name', metadata)
  73. if not title or title == '放送休止':
  74. formats = []
  75. live_status = 'is_upcoming'
  76. release_timestamp = self._extract_start_timestamp(video_id, False)
  77. msg = 'This stream is not currently live'
  78. if release_timestamp:
  79. msg += (' and will start at '
  80. + dt.datetime.fromtimestamp(release_timestamp).strftime('%Y-%m-%d %H:%M:%S'))
  81. self.raise_no_formats(msg, expected=True)
  82. else:
  83. m3u8_path = self._search_regex(
  84. r'<source\s[^>]*\bsrc="([^"]+)"',
  85. self._download_webpage(
  86. 'https://www.uniqueradio.jp/agplayer5/inc-player-hls.php', video_id,
  87. note='Downloading player data', errnote='Failed to download player data'),
  88. 'm3u8 url')
  89. formats = self._extract_m3u8_formats(
  90. urljoin('https://www.uniqueradio.jp/', m3u8_path), video_id)
  91. live_status = 'is_live'
  92. release_timestamp = self._extract_start_timestamp(video_id, True)
  93. return {
  94. 'id': video_id,
  95. 'title': title,
  96. 'channel': '超!A&G+',
  97. 'description': self._extract_metadata('Program_text', metadata),
  98. 'formats': formats,
  99. 'live_status': live_status,
  100. 'release_timestamp': release_timestamp,
  101. }