Răsfoiți Sursa

add fallback code to subscribe to Youtube channels that are not users (fixes #9)

Helmut Pozimski 6 ani în urmă
părinte
comite
2613b627a5
5 a modificat fișierele cu 57 adăugiri și 9 ștergeri
  1. 1 1
      lib_stov/configuration.py
  2. 8 0
      lib_stov/database.py
  3. 30 5
      lib_stov/noapi.py
  4. 12 0
      lib_stov/stov_exceptions.py
  5. 6 3
      stov

+ 1 - 1
lib_stov/configuration.py

@@ -53,7 +53,7 @@ class Conf(object):
             "youtube-dl": "",
             "notify": "yes",
             "config_version": "9",
-            "db_version": "3",
+            "db_version": "4",
             "videocodec": "mp4",
             "maxresolution": "1080p",
             "maxfails": 50,

+ 8 - 0
lib_stov/database.py

@@ -99,6 +99,14 @@ class Db(object):
                                     " disabled INTEGER DEFAULT 0;")
             self._execute_statement("UPDATE subscriptions SET disabled=0;")
             self.__version = 3
+        if int(self.__version) == 3:
+            """
+            Pseudo version without changes to the database structure,
+            converts existing channel subscriptions into user ones.
+            """
+            self._execute_statement("UPDATE subscriptions SET type='user' "
+                                    "WHERE type='channel'")
+            self.__version = 4
 
     def get_version(self):
         """Simple getter method, returns the DB version"""

+ 30 - 5
lib_stov/noapi.py

@@ -21,10 +21,11 @@ youtubeAPI module earlier."""
 
 import subprocess
 import sys
-import lxml.html
 import urllib.parse
 import urllib.request
+import urllib.error
 
+import lxml.html
 from lib_stov import stov_exceptions
 
 
@@ -61,9 +62,12 @@ class Connector(object):
         """Constructs the URL to request from youtube-dl according to the
         subscription type and the given parameters.
         """
-        if self._type == "channel":
+        if self._type == "user":
             self._url = "https://www.youtube.com/user/%s" \
                         % urllib.parse.quote(self._name)
+        elif self._type == "channel":
+            self._url = "https://www.youtube.com/channel/%s" \
+                        % urllib.parse.quote(self._name)
         elif self._type == "search":
             self._url = "https://www.youtube.com/results?search_query=%s"\
                         % urllib.parse.quote(self._search)
@@ -74,7 +78,28 @@ class Connector(object):
     def _fetch_title(self):
         """Retrieves the title of the HTML page to use as a title for the
         subscription."""
-        data = urllib.request.urlopen(self._url)
+        try:
+            data = urllib.request.urlopen(self._url)
+        except urllib.error.HTTPError as err:
+            if err.code == 404 and self._type == "user":
+                self._type = "channel"
+                self._construct_url()
+                try:
+                    data = urllib.request.urlopen(self._url)
+                except urllib.error.HTTPError:
+                    raise stov_exceptions.ChannelNotFound()
+                else:
+                    self._parse_title(data)
+            else:
+                raise stov_exceptions.ChannelNotFound()
+        else:
+            self._parse_title(data)
+
+    def _parse_title(self, data):
+        """ Parses the title from a HTML document
+        :param data: HTTP connection to the document
+        :type data: http.client.HTTPResponse
+        """
         parsed_html = lxml.html.parse(data)
         data.close()
         i = 0
@@ -82,7 +107,7 @@ class Connector(object):
             if i == 0:
                 self._title = item.text_content().strip().replace("\n", "")
             i += 1
-        if self._search != "" and self._type == "channel":
+        if self._search != "" and self._type == "user":
             self._title += _(" search %s") % self._search
 
     def _fetch_videos(self, existing_videos):
@@ -92,7 +117,7 @@ class Connector(object):
             stderr = sys.stderr
         else:
             stderr = open("/dev/null", "w")
-        if self._type == "channel" and self._search != "":
+        if self._type == "user" and self._search != "":
             try:
                 video_ids = subprocess.check_output([
                     self._conf.values["youtube-dl"],

+ 12 - 0
lib_stov/stov_exceptions.py

@@ -200,3 +200,15 @@ class YoutubeDlCallFailed(Exception):
 
     def __str__(self):
         return self._message
+
+
+class ChannelNotFound(Exception):
+    """ Will be raised when a specific user or channel cannot be found on
+    the site.
+    """
+    def __init__(self):
+        super(ChannelNotFound, self).__init__()
+        self._message = _("Channel not found on video site")
+
+    def __str__(self):
+        return self._message

+ 6 - 3
stov

@@ -300,6 +300,7 @@ else:
             LOGGER.debug(_("Created initial database tables."))
 
 try:
+    CONF = configuration.Conf()
     LOGGER.debug(_("Comparing current and running database version."))
     if not CONF.check_db():
         LOGGER.info(_("Your database needs to be updated, performing update "
@@ -356,10 +357,10 @@ run the corresponding code
 """
 if OPTIONS.add is True:
     if OPTIONS.channel is not None and OPTIONS.searchparameter is None:
-        NEW_SUBSCRIPTION = subscription.Sub(subscription_type="channel",
+        NEW_SUBSCRIPTION = subscription.Sub(subscription_type="user",
                                             name=OPTIONS.channel, conf=CONF)
     elif OPTIONS.channel is not None and OPTIONS.searchparameter is not None:
-        NEW_SUBSCRIPTION = subscription.Sub(subscription_type="channel",
+        NEW_SUBSCRIPTION = subscription.Sub(subscription_type="user",
                                             name=OPTIONS.channel,
                                             search=OPTIONS.searchparameter,
                                             conf=CONF)
@@ -385,6 +386,9 @@ if OPTIONS.add is True:
     except stov_exceptions.DBWriteAccessFailedException as error:
         LOGGER.error(error)
         sys.exit(1)
+    except stov_exceptions.ChannelNotFound as error:
+        LOGGER.error(error)
+        sys.exit(1)
     else:
         LOGGER.debug(_("Subscription sucessfully inserted into database."))
     try:
@@ -406,7 +410,6 @@ if OPTIONS.add is True:
                                    "database."), video.title)
     LOGGER.info(_("New subscription ") + NEW_SUBSCRIPTION.get_title()
                 + _(" successfully added"))
-
 elif OPTIONS.list is True:
     LIST_OF_SUBSCRIPTIONS = DB.get_subscriptions(CONF)
     SUB_STATE = None