# 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 . # -*- coding: utf8 -*- """This file takes care of reading, storing and updating the configuration of stov, the configuration file is expected to be in json format and reside in ~/.stov/stov.json. """ import os import subprocess import json import logging from lib_stov import stov_exceptions class Conf(object): """This class is used to create the object which is responsible for all configuration operations. """ def __init__(self): """Constructor Constructs the conf object with some reasonable default values which should work on most systems, existence of a local mail server is assumed. """ self.values = { "database": "stov.sqlite", "downloaddir": str(os.environ['HOME']) + "/stov", "maxvideos": "25", "mailhost": "localhost", "mailto": "root", "mailfrom": "stov@localhost", "smtpport": "25", "auth_needed": "no", "user_name": "", "password": "", "youtube-dl": "", "notify": "yes", "config_version": "9", "db_version": "6", "videocodec": "mp4", "maxresolution": "1080p", "maxfails": 50, "check_title": "no" } self.__explanations = { "database": _("the name of your database file"), "downloaddir": _("the directory where downloaded videos are " "saved"), "maxvideos": _("the maximum number of videos to retrieve for each " "subscription"), "mailhost": _("the host name of your mail server"), "mailto": _("the address used for notifications"), "mailfrom": _("the sender address of notification e-mails"), "smtpport": _("the port to use on your mail server"), "auth_needed": _("if your mail server requires authentication"), "user_name": _("the user name used to authenticate to your mail " "server"), "password": _("the password used to authenticate to your mail " "server"), "youtube-dl": _("the path to your youtube-dl installation"), "notify": _("if you want to be notified via e-mail about new " "videos"), "videocodec": _("which video codec you prefer (h264, webm or " "flv)"), "maxresolution": _("which resolution you prefer (360p, 480p, 720p " "or 1080p)"), "check_title": _("if you want to compare the title of a video " "with the subscription search string") } self.dbpath = str(os.environ['HOME']) + "/.stov/" + \ self.values["database"] self.outputlevel = "default" def write_config(self): """Writes the configuration from the dictionary into the configuration file for stov. The configuration is written into the home directory of the user by default. """ try: configfile = open(str(os.environ['HOME']) + "/.stov/stov.json", "w") except IOError: raise stov_exceptions.ConfigFileWriteErrorException() else: json.dump(self.values, configfile, indent=0) configfile.close() def initialize(self): """Creates the necessary directory for the stov configuration and calls the internal methods to create the database and the configuration file. """ try: os.mkdir(str(os.environ['HOME']) + "/.stov", 0o750) except os.error: raise stov_exceptions.DirectoryCreationFailedException() else: process = subprocess.Popen(["which", "youtube-dl"], stdout=subprocess.PIPE) self.values["youtube-dl"] = \ process.communicate()[0].strip().decode("utf-8") self.write_config() def read_old_config(self): """Reads the existing plain text configuration file and places the values in the dictionary. Existing values (such as default values) are overwritten. """ try: configfile = open(str(os.environ['HOME']) + "/.stov/stov.config", "r") except IOError: raise stov_exceptions.ConfigFileReadErrorException() for lines in configfile: tmpline = lines.strip() tmplist = tmpline.split("=") self.values[tmplist[0].lower()] = tmplist[1] configfile.close() self.dbpath = str(os.environ['HOME']) + "/.stov/" + \ self.values["database"] def read_config(self): """Reads the existing json configuration files and loads the values in the dictionary. """ try: configfile = open(str(os.environ['HOME']) + "/.stov/stov.json", "r") except IOError: raise stov_exceptions.ConfigFileReadErrorException() else: self.values.update(json.load(configfile)) configfile.close() def check_config(self): """Checks if the configuration is up-to-date with the running stov version. """ try: currentversion = int(self.values["config_version"]) except ValueError: raise stov_exceptions.InvalidConfigurationVersionException() self.values["config_version"] = "0" self.read_config() if self.values["config_version"] == "0" \ or int(self.values["config_version"]) < currentversion: self.values["config_version"] = str(currentversion) return False else: self.values["config_version"] = currentversion return True def update_config(self): """Update the configuration to the latest version""" versionbuffer = self.values["config_version"] self.read_config() self.values["config_version"] = versionbuffer self.write_config() def check_db(self): """Checks the database if it is up-to-date""" currentdbversion = int(self.values["db_version"]) self.values["db_version"] = "0" self.read_config() if self.values["db_version"] == "0" or \ int(self.values["db_version"]) <\ int(currentdbversion): self.values["db_version"] = str(currentdbversion) return False else: self.values["db_version"] = str(currentdbversion) return True def get_youtube_parameter(self): """Determines which itag value results from codec and resolution settings and returns it """ itag_value = 0 if self.values["videocodec"] == "flv": if self.values["maxresolution"] == "240p": itag_value = 5 elif self.values["maxresolution"] == "270p": itag_value = 6 elif self.values["maxresolution"] == "360p": itag_value = 34 elif self.values["maxresolution"] == "480p": itag_value = 35 elif self.values["videocodec"] == "webm": if self.values["maxresolution"] == "360p": itag_value = 43 elif self.values["maxresolution"] == "480p": itag_value = 44 elif self.values["maxresolution"] == "720p": itag_value = 45 elif self.values["maxresolution"] == "1080p": itag_value = 46 elif self.values["videocodec"] == "mp4": if self.values["maxresolution"] == "360p": itag_value = 18 elif self.values["maxresolution"] == "720p": itag_value = 22 elif self.values["maxresolution"] == "1080p": itag_value = 37 elif self.values["maxresolution"] == "3072p": itag_value = 38 return itag_value def assist(self): """ Ask the user to set all required configuration parameters """ print(_("This assistant will help you to perform the initial " "configuration of stov. \nThe default value will be " "displayed in brackets.\n" "Please specify now :\n")) for value in self.__explanations: print(self.__explanations[value] + " [" + self.values[value] + "]:" + " ") user_input = input() if user_input != "": self.values[value] = user_input self.dbpath = str(os.environ['HOME']) + "/.stov/" + \ self.values["database"] def migrate_config(self): """Migrates the configuration from the old plain text config to the new and shiny json configuration file. """ try: self.read_old_config() self.write_config() except stov_exceptions.ConfigFileReadErrorException: raise stov_exceptions.ConfigurationMigrationFailed() except stov_exceptions.ConfigFileWriteErrorException: raise stov_exceptions.ConfigurationMigrationFailed else: os.remove(str(os.environ['HOME']) + "/.stov/stov.config") def configure_logging(self, verbose=False, quiet=False): """ Sets up logging for stov and returns a logger object :param verbose: whether to use verbose mode :type verbose: bool :param quiet: whether to use quiet mode :type quiet: bool :return: logger object :rtype: logging.Logger """ logger = logging.getLogger("stov") # verbose takes precedence if verbose: logger.setLevel(logging.DEBUG) self.outputlevel = "verbose" elif quiet: logger.setLevel(logging.ERROR) self.outputlevel = "quiet" else: logger.setLevel(logging.INFO) console_handler = logging.StreamHandler() logger.addHandler(console_handler) return logger