zdf_mediathek.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #
  2. # This file is part of stov, written by Helmut Pozimski 2012-2017.
  3. #
  4. # stov is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, version 2 of the License.
  7. #
  8. # stov is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with stov. If not, see <http://www.gnu.org/licenses/>.
  15. # -*- coding: utf8 -*-
  16. """ This module implements support for subscriptions from the ZDF Mediathek"""
  17. import json
  18. import logging
  19. import urllib.request
  20. from datetime import datetime, timedelta
  21. from lib_stov import stov_exceptions
  22. from lib_stov import configuration
  23. LOGGER = logging.getLogger("stov")
  24. class ZDFChannel(object):
  25. """Stores the relevant attributes of a ZDF Mediathek channel"""
  26. def __init__(self, title, videos=None):
  27. if videos is None:
  28. videos = []
  29. self.title = title
  30. self.videos = videos
  31. self.type = "channel"
  32. class ZDFVideo(object):
  33. """Stores the relevant attributes of a single video in the ZDF
  34. Mediathek
  35. """
  36. def __init__(self, title, url):
  37. self.title = title
  38. self.video_id = url
  39. class Connector(object):
  40. """Connector class performing operations against the API"""
  41. def __init__(self, subscription_type, name, search=""):
  42. if subscription_type == "user":
  43. self._type = "channel"
  44. else:
  45. self._type = subscription_type
  46. self._name = name
  47. self._conf = configuration.Conf.get_instance()
  48. self._search = search
  49. if self._type != "channel":
  50. raise stov_exceptions.TypeNotSupported()
  51. def _fetch_videos(self, existing_videos):
  52. """ Fetches the videos of the day before from the ZDF API and returns
  53. a list of newly added videos.
  54. :param existing_videos: videos that already exist in the database
  55. :type existing_videos: list
  56. :return: List of all newly retrieved videos
  57. :rtype: list
  58. """
  59. name_found = False
  60. videos_list = []
  61. new_videos = []
  62. today = datetime.today()
  63. for i in range(7, -1, -1):
  64. connection = urllib.request.urlopen(
  65. "https://zdf-cdn.live.cellular.de/mediathekV2/broadcast-"
  66. "missed/%s"
  67. % (today-timedelta(days=i)).strftime("%Y-%m-%d"))
  68. data = connection.read().decode("utf-8")
  69. response = json.loads(data)
  70. for cluster in response["broadcastCluster"]:
  71. for broadcast in cluster["teaser"]:
  72. try:
  73. name_found = self._name in broadcast["brandTitle"]
  74. except KeyError:
  75. name_found = self._name in broadcast["headline"]
  76. if name_found:
  77. if self._search:
  78. if self._search in broadcast["titel"]:
  79. new_videos.append((broadcast["sharingUrl"],
  80. broadcast["titel"]))
  81. else:
  82. new_videos.append((broadcast["sharingUrl"],
  83. broadcast["titel"]))
  84. if new_videos:
  85. for broadcast in new_videos:
  86. video_exists = False
  87. if existing_videos:
  88. for existing_video in existing_videos:
  89. if broadcast[0] == existing_video.site_id:
  90. video_exists = True
  91. break
  92. if not video_exists:
  93. videos_list.append(ZDFVideo(broadcast[1], broadcast[0]))
  94. return videos_list
  95. def parse_api_data(self, existing_videos):
  96. """ Takes the existing videos passed to it and wraps them into a
  97. channel object.
  98. :param existing_videos: list of existing_videos
  99. :type existing_videos: list
  100. :return: Channel object
  101. :rtype: ZDFChannel
  102. """
  103. videos = self._fetch_videos(existing_videos)
  104. channel = ZDFChannel(self._name, videos)
  105. return channel
  106. @staticmethod
  107. def construct_video_url(url):
  108. """
  109. Compatibility method, just returns the url
  110. :param url: The url to return
  111. :type url: str
  112. :return: url
  113. :rtype: str
  114. """
  115. return url
  116. @staticmethod
  117. def get_quality_parameter(config):
  118. """
  119. Determines which quality value results from codec and resolution
  120. settings and returns it
  121. :param config: configuration object
  122. :type config: lib_stov.configuration.Conf
  123. :return: itag value
  124. :rtype: str
  125. """
  126. LOGGER.debug(_("Trying to determine the itag value for youtube-dl from"
  127. " your quality and codec settings."))
  128. quality_value = ""
  129. if config.values["videocodec"] == "flv":
  130. if config.values["maxresolution"] == "480p":
  131. quality_value = "hds-1489"
  132. elif config.values["videocodec"] == "mp4":
  133. if config.values["maxresolution"] == "720p":
  134. quality_value = "hls-3286"
  135. if quality_value:
  136. LOGGER.debug(_("Found value: %s."), quality_value)
  137. return quality_value + "/" + config.values["videocodec"]
  138. LOGGER.debug(_("Could not determine an itag value "
  139. "from the configuration"))
  140. return "hls-3286" + "/" + config.values["videocodec"]