Browse Source

implement support for twitch.tv (closes #5)

Helmut Pozimski 6 years ago
parent
commit
9396ca45d0
5 changed files with 114 additions and 5 deletions
  1. 1 1
      lib_stov/program.py
  2. 4 0
      lib_stov/subscription.py
  3. 102 0
      lib_stov/twitch.py
  4. 4 3
      lib_stov/yt_noapi.py
  5. 3 1
      lib_stov/zdf_mediathek.py

+ 1 - 1
lib_stov/program.py

@@ -498,7 +498,7 @@ def initialize_sites(database):
     :param database: database object
     :type database: lib_stov.database.Db
     """
-    supported_sites = ["youtube", "zdf_mediathek"]
+    supported_sites = ["youtube", "zdf_mediathek", "twitch"]
     sites = database.get_sites()
     for site in supported_sites:
         site_found = False

+ 4 - 0
lib_stov/subscription.py

@@ -21,6 +21,7 @@
 from lib_stov import stov_exceptions
 from lib_stov import yt_noapi
 from lib_stov import zdf_mediathek
+from lib_stov import twitch
 
 
 class Sub(object):
@@ -56,6 +57,9 @@ class Sub(object):
         elif site == "zdf_mediathek":
             self._connector = zdf_mediathek.Connector(self._type, self._name,
                                                       self._conf)
+        elif site == "twitch":
+            self._connector = twitch.Connector(self._type, self._name,
+                                               self._conf, self._search)
         else:
             raise stov_exceptions.SiteUnsupported()
 

+ 102 - 0
lib_stov/twitch.py

@@ -0,0 +1,102 @@
+#
+#   This file is part of stov, written by Helmut Pozimski 2012-2017.
+#
+#   stov is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, version 2 of the License.
+#
+#   stov is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with stov.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# -*- coding: utf8 -*-
+
+""" This module implements support for subscriptions from twitch.tv"""
+
+import urllib.parse
+import urllib.request
+import urllib.error
+import logging
+
+from lib_stov import stov_exceptions
+from lib_stov import yt_noapi
+
+LOGGER = logging.getLogger("stov")
+
+
+class Connector(yt_noapi.Connector):
+    """ Connector class, performing calls to youtube-dl to retrieve
+        information about videos from twitch.tv
+    """
+    def __init__(self, subscription_type, name, conf, search=""):
+        """Populates the object with all necessary data."""
+        yt_noapi.Connector.__init__(self, subscription_type, name,
+                                    conf, search)
+
+    def _construct_url(self):
+        """ Constructs the URL for the subscription to retrieve
+        data from.
+        """
+        if self._type == "user":
+            self._url = "https://www.twitch.tv/%s/videos/all" \
+                        % urllib.parse.quote(self._name)
+        elif self._type == "search":
+            raise stov_exceptions.TypeNotSupported()
+        elif self._type == "playlist":
+            raise stov_exceptions.TypeNotSupported()
+        LOGGER.debug(_("Constructed URL for subscription: %s"), self._url)
+
+    def _fetch_title(self):
+        """Sets the title of a subscription"""
+        self._title = self._name
+        if self._search != "":
+            self._title += _(" search %s") % self._search
+
+    @staticmethod
+    def construct_video_url(ytid):
+        """
+        Resturns the URL to a specified twitch video
+
+        :param ytid: Twitch ID of the video
+        :type ytid: str
+        :return: Video URL
+        :rtype: str
+        """
+        ytid = ytid.split("v")[1]
+        url = "https://www.twitch.tv/videos/%s" % ytid
+        return url
+
+    @staticmethod
+    def get_quality_parameter(config):
+        """Determines which itag value results from codec and resolution
+        settings and returns it
+
+        :param config: configuration object
+        :type config: lib_stov.configuration.Conf
+        :return: itag value
+        :rtype: str
+        """
+        LOGGER.debug(_("Trying to determine the itag value for youtube-dl from"
+                       " your quality and codec settings."))
+        quality_value = 0
+        if config.values["videocodec"] == "mp4":
+            if config.values["maxresolution"] == "360p":
+                quality_value = "360p"
+            elif config.values["maxresolution"] == "480p":
+                quality_value = "480p"
+            elif config.values["maxresolution"] == "720p":
+                quality_value = "720p"
+            elif config.values["maxresolution"] == "1080p":
+                quality_value = "1080p"
+        if quality_value:
+            LOGGER.debug(_("Found value: %s."), quality_value)
+            return quality_value
+        else:
+            LOGGER.debug(_("Could not determine an itag value "
+                           "from the configuration"))
+            return "1080p"

+ 4 - 3
lib_stov/yt_noapi.py

@@ -34,7 +34,9 @@ LOGGER = logging.getLogger("stov")
 
 class YtChannel(object):
     """Stores the relevant attributes of a youtube channel."""
-    def __init__(self, _type, title, videos=[]):
+    def __init__(self, _type, title, videos=None):
+        if videos is None:
+            videos = []
         self.type = _type
         self.title = title
         self.videos = videos
@@ -135,8 +137,7 @@ class Connector(object):
                 if not video_exists:
                     try:
                         video_title = youtubedl_wrapper.get_title(
-                            self._conf, "https://www.youtube.com/watch?v=%s"
-                                        % video_id)
+                            self._conf, self.construct_video_url(video_id))
                     except subprocess.CalledProcessError:
                         raise stov_exceptions.YoutubeDlCallFailed()
                     else:

+ 3 - 1
lib_stov/zdf_mediathek.py

@@ -30,7 +30,9 @@ LOGGER = logging.getLogger("stov")
 
 class ZDFChannel(object):
     """Stores the relevant attributes of a ZDF Mediathek channel"""
-    def __init__(self, title, videos=[]):
+    def __init__(self, title, videos=None):
+        if videos is None:
+            videos = []
         self.title = title
         self.videos = videos
         self.type = "channel"