separate cli and gui application in own python packages. provide database schema as python package.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
|
||||
from cement import Controller, ex
|
||||
from cement.utils.version import get_version_banner
|
||||
from ..core.version import get_version
|
||||
|
||||
VERSION_BANNER = """
|
||||
Kontor CLI %s
|
||||
%s
|
||||
""" % (get_version(), get_version_banner())
|
||||
|
||||
|
||||
class CliBase(Controller):
|
||||
class Meta:
|
||||
label = 'clibase'
|
||||
|
||||
# text displayed at the top of --help output
|
||||
description = 'Kontor CLI'
|
||||
|
||||
# text displayed at the bottom of --help output
|
||||
epilog = 'Usage: kontor command1 --foo bar'
|
||||
|
||||
# controller level arguments. ex: 'kontor --version'
|
||||
arguments = [
|
||||
### add a version banner
|
||||
( [ '-v', '--version' ],
|
||||
{ 'action' : 'version',
|
||||
'version' : VERSION_BANNER } ),
|
||||
]
|
||||
|
||||
|
||||
def _default(self):
|
||||
"""Default action if no sub-command is passed."""
|
||||
|
||||
self.app.args.print_help()
|
||||
|
||||
|
||||
@ex(
|
||||
help='example sub command1',
|
||||
|
||||
# sub-command level arguments. ex: 'kontor command1 --foo bar'
|
||||
arguments=[
|
||||
### add a sample foo option under subcommand namespace
|
||||
( [ '-f', '--foo' ],
|
||||
{ 'help' : 'notorious foo option',
|
||||
'action' : 'store',
|
||||
'dest' : 'foo' } ),
|
||||
],
|
||||
)
|
||||
def command1(self):
|
||||
"""Example sub-command."""
|
||||
|
||||
data = {
|
||||
'foo' : 'bar',
|
||||
}
|
||||
|
||||
### do something with arguments
|
||||
if self.app.pargs.foo is not None:
|
||||
data['foo'] = self.app.pargs.foo
|
||||
|
||||
self.app.render(data, 'command1.jinja2')
|
||||
@@ -0,0 +1,51 @@
|
||||
from cement import Controller, ex
|
||||
from kontor_schema import KontorDB
|
||||
|
||||
|
||||
class Database(Controller):
|
||||
|
||||
class Meta:
|
||||
label = 'database'
|
||||
stacked_type = 'nested'
|
||||
stacked_on = 'clibase'
|
||||
|
||||
@ex(
|
||||
help='export database to given file',
|
||||
arguments=[
|
||||
(['-f', '--file'],
|
||||
{'help': 'file to store database content',
|
||||
'action': 'store',
|
||||
'dest': 'db_file'})
|
||||
],
|
||||
)
|
||||
def export(self):
|
||||
data = {
|
||||
'db_file': 'data.json',
|
||||
'export_type': 'JSON',
|
||||
}
|
||||
if self.app.pargs.db_file is not None:
|
||||
data['db_file'] = self.app.pargs.db_file
|
||||
kontor_db = KontorDB(self.app.engine, self.app.config, self.app.log)
|
||||
kontor_db.export_db(data['export_type'], data['db_file'])
|
||||
self.app.render(data, 'command1.jinja2')
|
||||
|
||||
@ex(
|
||||
label='import',
|
||||
help='import data from file into database',
|
||||
arguments=[
|
||||
(['-f', '--file'],
|
||||
{'help': 'file to read data',
|
||||
'action': 'store',
|
||||
'dest': 'db_file'})
|
||||
],
|
||||
)
|
||||
def import_cmd(self):
|
||||
data = {
|
||||
'db_file': 'data.json',
|
||||
'data_type': 'JSON',
|
||||
}
|
||||
if self.app.pargs.db_file is not None:
|
||||
data['db_file'] = self.app.pargs.db_file
|
||||
kontor_db = KontorDB(self.app.engine, self.app.config, self.app.log)
|
||||
self.app.render(data, 'import.jinja2')
|
||||
kontor_db.import_db(data['db_file'], self.app.pargs.dry_run)
|
||||
@@ -0,0 +1,81 @@
|
||||
from cement import Controller, ex
|
||||
from kontor_schema import KontorDB
|
||||
from kontor_video import VideoLink
|
||||
|
||||
class Media(Controller):
|
||||
|
||||
class Meta:
|
||||
label = 'media'
|
||||
stacked_type = 'nested'
|
||||
stacked_on = 'clibase'
|
||||
|
||||
@ex(
|
||||
label='update',
|
||||
help='update title for mediafiles',
|
||||
)
|
||||
def update_title(self):
|
||||
kontor_db = KontorDB(self.app.engine, self.app.log)
|
||||
kontor_db.update_title(self.app.pargs.dry_run)
|
||||
|
||||
@ex(
|
||||
label='download',
|
||||
help='download all marked videos',
|
||||
arguments=[
|
||||
(['-d', '--dir'],
|
||||
{'help': 'directory to store videos',
|
||||
'action': 'store',
|
||||
'dest': 'media_dir'})
|
||||
],
|
||||
)
|
||||
def download(self):
|
||||
data = {
|
||||
'media_dir': '/data/media',
|
||||
}
|
||||
if self.app.pargs.media_dir is not None:
|
||||
data['media_dir'] = self.app.pargs.media_dir
|
||||
kontor_db = KontorDB(self.app.engine, self.app.log)
|
||||
downloads = kontor_db.get_download_list()
|
||||
for download in downloads:
|
||||
link = VideoLink(download, download_dir=data['media_dir'])
|
||||
link.download()
|
||||
|
||||
@ex(
|
||||
help='add url to database',
|
||||
arguments=[
|
||||
(['-u', '--url'],
|
||||
{'help': 'link to downloadable video',
|
||||
'action': 'store',
|
||||
'dest': 'link'})
|
||||
],
|
||||
)
|
||||
def add(self):
|
||||
data = {
|
||||
'link_url': None
|
||||
}
|
||||
if self.app.pargs.link is not None:
|
||||
data['link_url'] = self.app.pargs.link
|
||||
if self.app.pargs.dry_run:
|
||||
print(f"add url {data['link_url']} to database")
|
||||
kontor_db = KontorDB(self.app.engine, self.app.log)
|
||||
kontor_db.add_link(self.app.pargs.link, self.app.pargs.dry_run)
|
||||
|
||||
else:
|
||||
print("no url was given.")
|
||||
|
||||
@ex(
|
||||
help='check files if existing',
|
||||
arguments=[
|
||||
(['-d', '--dir'],
|
||||
{'help': 'directory to store videos',
|
||||
'action': 'store',
|
||||
'dest': 'media_dir'})
|
||||
],
|
||||
)
|
||||
def check(self):
|
||||
data = {
|
||||
'media_dir': '/data/media',
|
||||
}
|
||||
if self.app.pargs.media_dir is not None:
|
||||
data['media_dir'] = self.app.pargs.media_dir
|
||||
kontor_db = KontorDB(self.app.engine, self.app.log)
|
||||
kontor_db.check_files()
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
class KontorError(Exception):
|
||||
"""Generic errors."""
|
||||
pass
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
from cement.utils.version import get_version as cement_get_version
|
||||
|
||||
VERSION = (0, 0, 1, 'alpha', 0)
|
||||
|
||||
def get_version(version=VERSION):
|
||||
return cement_get_version(version)
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
from cement import App, TestApp, init_defaults
|
||||
from cement.core.exc import CaughtSignal
|
||||
from kontor_schema.base import Base
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from .core.exc import KontorError
|
||||
from .controllers.base import CliBase
|
||||
from .controllers.database import Database
|
||||
from .controllers.media import Media
|
||||
|
||||
# configuration defaults
|
||||
CONFIG = init_defaults('kontor', 'mariadb', 'media')
|
||||
CONFIG['kontor']['foo'] = 'bar'
|
||||
CONFIG['mariadb']['user'] = 'kontor'
|
||||
CONFIG['mariadb']['password'] = 'kontor'
|
||||
CONFIG['mariadb']['host'] = '127.0.0.1'
|
||||
CONFIG['mariadb']['port'] = '3306'
|
||||
CONFIG['mariadb']['database'] = 'kontor'
|
||||
CONFIG['media']['yt-dlp'] = '/home/tpeetz/bin/yt-dlp'
|
||||
CONFIG['media']['dir'] = '/data/media'
|
||||
|
||||
def extend_sqlalchemy(app):
|
||||
app.log.info('extending kontor application with sqlalchemy')
|
||||
connect_string = ('mariadb+mariadbconnector://{}:{}@{}:{}/{}'.format(
|
||||
app.config.get('mariadb', 'user'),
|
||||
app.config.get('mariadb', 'password'),
|
||||
app.config.get('mariadb', 'host'),
|
||||
app.config.get('mariadb', 'port'),
|
||||
app.config.get('mariadb', 'database')
|
||||
))
|
||||
# engine = create_engine(connect_string, echo=True)
|
||||
engine = create_engine(connect_string)
|
||||
Base.metadata.create_all(bind=engine, checkfirst=True)
|
||||
__session__ = sessionmaker(bind=engine)
|
||||
app.extend('engine', engine)
|
||||
|
||||
|
||||
class Kontor(App):
|
||||
"""Kontor CLI primary application."""
|
||||
|
||||
class Meta:
|
||||
label = 'kontor'
|
||||
|
||||
# configuration defaults
|
||||
config_defaults = CONFIG
|
||||
|
||||
# call sys.exit() on close
|
||||
exit_on_close = True
|
||||
|
||||
# load additional framework extensions
|
||||
extensions = [
|
||||
'yaml',
|
||||
'colorlog',
|
||||
'jinja2',
|
||||
]
|
||||
|
||||
# configuration handler
|
||||
config_handler = 'yaml'
|
||||
|
||||
# configuration file suffix
|
||||
config_file_suffix = '.yml'
|
||||
|
||||
# set the log handler
|
||||
log_handler = 'colorlog'
|
||||
|
||||
# set the output handler
|
||||
output_handler = 'jinja2'
|
||||
|
||||
hooks = [
|
||||
('post_setup', extend_sqlalchemy),
|
||||
]
|
||||
|
||||
# register handlers
|
||||
handlers = [
|
||||
CliBase,
|
||||
Database,
|
||||
Media,
|
||||
]
|
||||
|
||||
|
||||
class KontorTest(TestApp,Kontor):
|
||||
"""A sub-class of Kontor that is better suited for testing."""
|
||||
|
||||
class Meta:
|
||||
label = 'kontor'
|
||||
|
||||
|
||||
def main():
|
||||
with Kontor() as app:
|
||||
try:
|
||||
app.run()
|
||||
|
||||
except AssertionError as e:
|
||||
print('AssertionError > %s' % e.args[0])
|
||||
app.exit_code = 1
|
||||
|
||||
if app.debug is True:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
except KontorError as e:
|
||||
print('KontorError > %s' % e.args[0])
|
||||
app.exit_code = 1
|
||||
|
||||
if app.debug is True:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
except CaughtSignal as e:
|
||||
# Default Cement signals are SIGINT and SIGTERM, exit 0 (non-error)
|
||||
print('\n%s' % e)
|
||||
app.exit_code = 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
Example Template (templates/command1.jinja2)
|
||||
|
||||
Foo => {{ foo }}
|
||||
Reference in New Issue
Block a user