123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- # 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 contains several functions that are necessary to set up
- the application. """
- import gettext
- import os
- import sys
- import signal
- import argparse
- import logging
- from distutils.spawn import find_executable
- from lib_stov import stov_exceptions
- from lib_stov import configuration
- from lib_stov import database
- LOGGER = logging.getLogger("stov")
- def initialize_gettext():
- """
- Installs gettext so localization can be used if necessary.
- """
- # Determine the path where the stov files are for localization
- locale_path = os.path.join(sys.path[0] + "/locale")
- if gettext.find("stov", locale_path) is None:
- base_path = os.path.split(sys.path[0])[0]
- if "share" in base_path:
- locale_path = os.path.join(base_path, "locale")
- else:
- locale_path = os.path.join(base_path, "share/locale")
- # Initialize gettext to support translation of the program
- try:
- trans = gettext.translation("stov", locale_path)
- except IOError:
- gettext.install("stov")
- if os.environ["LANG"] != "C" and os.environ["LANGUAGE"] != "C":
- print(_("The translation files could not be found, localization "
- "won't be available"), file=sys.stderr)
- else:
- trans.install()
- def sighandler(signum, frame):
- """Handler function for signals caught by stov."""
- if signum == 2:
- print(_("STRG+C has been pressed, quitting..."), file=sys.stderr)
- elif signum == 15:
- print(_("Received SIGTERM, quitting..."), file=sys.stderr)
- os.killpg(os.getpid(), 1)
- remove_lock()
- sys.exit(0)
- def setup_sighandler():
- """
- Installs a signal handler to catch external signals
- """
- signal.signal(signal.SIGTERM, sighandler)
- signal.signal(signal.SIGINT, sighandler)
- def parse_arguments():
- """
- Uses the argument parser to parse command line arguments and return them
- :return: parsed arguments
- :rtype: argparser.ArgumentParser
- """
- parser = argparse.ArgumentParser(conflict_handler="resolve")
- parser.add_argument("-h", "--help", action="store_true", dest="help",
- help=_("show this help message and exit"))
- parser.add_argument("-a", "--add", dest="add", action="store_true",
- help=_("Add a new subscription (requires either \
- --search, --channel or --playlist)"))
- parser.add_argument("-p", "--playlist", dest="playlist",
- help=_("Add a new Playlist subscription (requires "
- "add)"))
- parser.add_argument("-l", "--lssubs", action="store_true", dest="list",
- help=_("List the currently available subscriptions"))
- parser.add_argument("-r", "--remove", type=int, dest="deleteid",
- help=_("remove a subscription"))
- parser.add_argument("-u", "--update", action="store_true", dest="update",
- help=_(
- "update the information about the available "
- "videos"))
- parser.add_argument("-d", "--download", action="store_true",
- dest="download", help=_("download all available "
- "videos which haven't already"
- " been downloaded"))
- parser.add_argument("-s", "--search", dest="searchparameter",
- help=_("optionally add a search string to a new "
- "channel subscription or create a new search"
- " subscription (requires --add)"))
- parser.add_argument("-l", "--lsvids", type=int, dest="subscriptionid",
- help=_("Print all videos from a subscription"))
- parser.add_argument("-c", "--catchup", dest="catchup",
- help=_("Mark all videos from one channel as read \
- (requires subscription-id as argument)"))
- parser.add_argument("-c", "--channel", dest="channel",
- help=_("specify a channel for a new subscription "
- "(requires --add)"))
- parser.add_argument("-l", "--license", dest="license", action="store_true",
- help=_("show the license of the program"))
- parser.add_argument("-v", "--version", dest="version", action="store_true",
- help=_("show the current running version number"))
- parser.add_argument("-q", "--quiet", dest="quiet", action="store_true",
- help=_("Suppress all output"))
- parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
- help=_("Be verbose and print also diagnostic "
- "messages"))
- parser.add_argument("-c", "--clean-database", dest="cleanup",
- action="store_true",
- help=_("Clean the database of entries "
- "no longer listed in the current API response"))
- parser.add_argument("-e", "--enable", type=int, dest="enableid",
- help=_("enables the subscription with the "
- "provided ID"))
- parser.add_argument("--disable", type=int, dest="disableid",
- help=_("disables the subscription with the "
- "provided ID"))
- parser.add_argument("-s", "--site", dest="site",
- help=_("specify the site to work with (for --add)"))
- parser.add_argument("--lssites", dest="lssites", action="store_true",
- help=_("list the supported sites"))
- return parser
- def create_lock():
- """
- Creates the lock file for stov.
- """
- if os.access("/tmp/stov.lock", os.F_OK):
- try:
- lock_file = open("/tmp/stov.lock", "r")
- except IOError:
- LOGGER.error(_("The lock file could not be opened, please "
- "check that it exists and is readable, "
- "quitting now"))
- sys.exit(1)
- old_pid = lock_file.read().strip()
- if os.access("/proc/" + old_pid, os.F_OK):
- LOGGER.error(_("The lock file already exists, probably another "
- "instance of this program is already running\n"
- "if you are sure this is not the case, delete it "
- "manually and try again!"))
- sys.exit(1)
- lock_file.close()
- if not os.access("/proc/" + old_pid, os.F_OK):
- try:
- os.remove("/tmp/stov.lock")
- except os.error:
- LOGGER.error(_("The old lock file could not be deleted!"))
- try:
- LOCK_FILE = open("/tmp/stov.lock", "w")
- LOCK_FILE.write(str(os.getpid()))
- LOCK_FILE.close()
- except IOError:
- print(_("The lock file could not be created, please check that /tmp"
- " is writable and properly configured, quitting now."),
- file=sys.stderr)
- sys.exit(1)
- def remove_lock():
- """
- Removes the lock file when exiting the application.
- """
- try:
- os.remove("/tmp/stov.lock")
- sys.exit(0)
- except os.error:
- LOGGER.error(_("Could not delete the lock file. Please check what "
- "went wrong and clean up manually!"))
- sys.exit(1)
- def setup_configuration(args):
- """
- Reads the configuration and sets it up to be used within the application.
- :param args: command line arguments
- :return: configuration object
- :rtype: lib_stov.configuration.Conf
- """
- if not os.access(os.environ['HOME'] + "/.stov", os.F_OK & os.W_OK):
- print(_("This seems to be the first time you run the programm, do "
- "you want to run the interactive assistant? (yes/no)"))
- conf = configuration.Conf()
- logger = conf.configure_logging(args.verbose, args.quiet)
- temp_input = input()
- if temp_input == "yes":
- conf.assist()
- try:
- conf.initialize()
- except stov_exceptions.ConfigFileWriteErrorException as error:
- logger.error(error)
- else:
- logger.info(_("Writing initial configuration according to "
- "your input, have fun!"))
- else:
- logger.info(_("Writing initial configuration according to default"
- " values."))
- logger.debug(_("Creating hidden directory in home for "
- "configuration and database."))
- try:
- conf.initialize()
- except stov_exceptions.DirectoryCreationFailedException as error:
- logger.error(error)
- except stov_exceptions.ConfigFileWriteErrorException as error:
- logger.error(error)
- else:
- conf = configuration.Conf()
- logger = conf.configure_logging(args.verbose, args.quiet)
- if os.access(str(os.environ['HOME']) + "/.stov/stov.config", os.F_OK):
- logger.debug(_("Migrating configuration from plain text to json."))
- conf.migrate_config()
- try:
- logger.debug(
- _("Comparing current and running configuration version."))
- check_result = conf.check_config()
- except stov_exceptions.ConfigFileReadErrorException as error:
- logger.error(error)
- sys.exit(1)
- except stov_exceptions.InvalidConfigurationVersionException as error:
- logger.error(error)
- sys.exit(1)
- else:
- if not check_result:
- logger.info(
- _("Your configuration needs to be updated, performing"
- " update now."))
- try:
- conf.update_config()
- except stov_exceptions.ConfigFileReadErrorException as error:
- logger.error(error)
- sys.exit(1)
- except stov_exceptions.ConfigFileWriteErrorException as error:
- logger.error(error)
- sys.exit(1)
- return conf
- def setup_database(conf):
- """ Sets up the database and provides a DB object to talk to the database
- in the application.
- :param conf: configuration object
- :type conf: lib_stov.configuration.Conf
- :return: database object
- :rtype: lib_stov.database.Db
- """
- if os.access(conf.dbpath, os.F_OK):
- try:
- db = database.Db(path=conf.dbpath,
- version=conf.values["db_version"])
- except stov_exceptions.DBConnectionFailedException as error:
- LOGGER.error(error)
- sys.exit(1)
- else:
- try:
- db = database.Db(path=conf.dbpath,
- version=conf.values["db_version"])
- except stov_exceptions.DBConnectionFailedException as error:
- LOGGER.error(error)
- sys.exit(1)
- else:
- try:
- db.populate()
- except stov_exceptions.DBWriteAccessFailedException as error:
- LOGGER.error(error)
- sys.exit(1)
- 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 "
- "now."))
- db.update()
- conf.values["db_version"] = db.get_version()
- LOGGER.debug("Opening configuration file.")
- try:
- conf.write_config()
- except stov_exceptions.ConfigFileWriteErrorException as error:
- LOGGER.error(error)
- except stov_exceptions.DBWriteAccessFailedException as error:
- LOGGER.error(error)
- sys.exit(1)
- return db
- def find_youtubedl(conf):
- """
- Tries to find youtube-dl and writes it's path to the configuration file
- :param conf: configuration object
- :type conf: lib_stov.configuration.Conf
- """
- if conf.values["youtube-dl"] == "":
- youtubedl_path = find_executable("youtube-dl")
- conf.values["youtube-dl"] = youtubedl_path
- if os.access(conf.values["youtube-dl"], os.F_OK & os.R_OK & os.X_OK):
- LOGGER.info(_("Found youtube-dl, writing it's path to the "
- "configuration file."))
- LOGGER.debug("Opening configuration file.")
- try:
- conf.write_config()
- except stov_exceptions.ConfigFileWriteErrorException as error:
- LOGGER.error(error)
- sys.exit(1)
- else:
- LOGGER.error(
- _("Could not find youtube-dl, it either does not exist, "
- "is not readable or not executable. Please note that "
- "youtube-dl is not needed for the program to run but "
- "is needed to use the download option which won't work "
- "otherwise. If youtube-dl isn't found automatically, "
- "you may also enter the path to it in the configuration"
- " file."))
|