diff --git a/.gitignore b/.gitignore index 2a7da2d1c..e4514e4a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.pyc bazarr.db cachefile.dbm +*.log +*.log.* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..2645cb9ac --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:latest + +# Update +RUN apk add --update python py-pip + +# Install app dependencies +RUN pip install -r requirements.txt + +EXPOSE 6767 +CMD ["python", "/src/bazarr.py"] \ No newline at end of file diff --git a/bazarr.db b/bazarr.db index 92b5a6f7f..fdf6f98d1 100644 Binary files a/bazarr.db and b/bazarr.db differ diff --git a/bazarr.py b/bazarr.py index 840610352..f1fab7704 100644 --- a/bazarr.py +++ b/bazarr.py @@ -25,6 +25,44 @@ from list_subtitles import * from get_subtitle import * from utils import * +import logging +from logging.handlers import TimedRotatingFileHandler +logger = logging.getLogger('waitress') +db = sqlite3.connect('bazarr.db') +c = db.cursor() +c.execute("SELECT log_level FROM table_settings_general") +log_level = c.fetchone() +log_level = log_level[0] +if log_level is None: + log_level = "WARNING" +log_level = getattr(logging, log_level) +c.close() + +class OneLineExceptionFormatter(logging.Formatter): + def formatException(self, exc_info): + """ + Format an exception so that it prints on a single line. + """ + result = super(OneLineExceptionFormatter, self).formatException(exc_info) + return repr(result) # or format into one line however you want to + + def format(self, record): + s = super(OneLineExceptionFormatter, self).format(record) + if record.exc_text: + s = s.replace('\n', '') + '|' + return s + +def configure_logging(): + fh = TimedRotatingFileHandler('bazarr.log', when="midnight", interval=1, backupCount=7) + f = OneLineExceptionFormatter('%(asctime)s|%(levelname)s|%(message)s|', + '%d/%m/%Y %H:%M:%S') + fh.setFormatter(f) + root = logging.getLogger() + root.setLevel(log_level) + root.addHandler(fh) + +configure_logging() + @route('/static/:path#.+#', name='static') def static(path): return static_file(path, root='static') @@ -48,7 +86,7 @@ def series(): c.execute("SELECT code2, name FROM table_settings_languages WHERE enabled = 1") languages = c.fetchall() c.close() - output = template('series', rows=data, languages=languages, url_sonarr_short=url_sonarr_short) + output = template('series', rows=data, languages=languages) return output @route('/edit_series/', method='POST') @@ -74,6 +112,8 @@ def edit_series(no): conn.commit() c.close() + list_missing_subtitles(no) + redirect('/') @route('/update_series') @@ -88,6 +128,12 @@ def update_all_episodes_list(): redirect('/') +@route('/add_new_episodes') +def add_new_episodes_list(): + add_new_episodes() + + redirect('/') + @route('/episodes/', method='GET') def episodes(no): conn = sqlite3.connect('bazarr.db') @@ -97,14 +143,30 @@ def episodes(no): series_details = [] series_details = c.execute("SELECT title, overview, poster, fanart, hearing_impaired FROM table_shows WHERE sonarrSeriesId LIKE ?", (str(no),)).fetchone() - episodes = c.execute("SELECT title, path_substitution(path), season, episode, subtitles, sonarrSeriesId, missing_subtitles, sonarrEpisodeId FROM table_episodes WHERE sonarrSeriesId LIKE ?", (str(no),)).fetchall() + episodes = c.execute("SELECT title, path_substitution(path), season, episode, subtitles, sonarrSeriesId, missing_subtitles, sonarrEpisodeId FROM table_episodes WHERE sonarrSeriesId LIKE ? ORDER BY episode ASC", (str(no),)).fetchall() episodes = reversed(sorted(episodes, key=operator.itemgetter(2))) seasons_list = [] for key,season in itertools.groupby(episodes,operator.itemgetter(2)): seasons_list.append(list(season)) c.close() - return template('episodes', details=series_details, seasons=seasons_list, url_sonarr_short=url_sonarr_short) + return template('episodes', no=no, details=series_details, seasons=seasons_list, url_sonarr_short=url_sonarr_short) + +@route('/scan_disk/', method='GET') +def scan_disk(no): + ref = request.environ['HTTP_REFERER'] + + series_scan_subtitles(no) + + redirect(ref) + +@route('/search_missing_subtitles/', method='GET') +def search_missing_subtitles(no): + ref = request.environ['HTTP_REFERER'] + + series_download_subtitles(no) + + redirect(ref) @route('/history') def history(): @@ -141,11 +203,28 @@ def wanted(): offset = (int(page) - 1) * 15 max_page = (missing_count / 15) + 1 - c.execute("SELECT table_shows.title, table_episodes.season || 'x' || table_episodes.episode, table_episodes.title, table_episodes.missing_subtitles, table_episodes.sonarrSeriesId, path_substitution(table_episodes.path), table_shows.hearing_impaired, table_episodes.sonarrEpisodeId FROM table_episodes INNER JOIN table_shows on table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId WHERE table_episodes.missing_subtitles != '[]' LIMIT 15 OFFSET ?", (offset,)) + c.execute("SELECT table_shows.title, table_episodes.season || 'x' || table_episodes.episode, table_episodes.title, table_episodes.missing_subtitles, table_episodes.sonarrSeriesId, path_substitution(table_episodes.path), table_shows.hearing_impaired, table_episodes.sonarrEpisodeId FROM table_episodes INNER JOIN table_shows on table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId WHERE table_episodes.missing_subtitles != '[]' ORDER BY table_episodes._rowid_ DESC LIMIT 15 OFFSET ?", (offset,)) data = c.fetchall() c.close() return template('wanted', rows=data, missing_count=missing_count, page=page, max_page=max_page) +@route('/wanted_search_missing_subtitles') +def wanted_search_missing_subtitles(): + ref = request.environ['HTTP_REFERER'] + + db = sqlite3.connect('bazarr.db') + db.create_function("path_substitution", 1, path_replace) + c = db.cursor() + + c.execute("SELECT path_substitution(path) FROM table_episodes WHERE table_episodes.missing_subtitles != '[]'") + data = c.fetchall() + c.close() + + for episode in data: + wanted_download_subtitles(episode[0]) + + redirect(ref) + @route('/settings') def settings(): db = sqlite3.connect('bazarr.db') @@ -169,11 +248,12 @@ def save_settings(): settings_general_ip = request.forms.get('settings_general_ip') settings_general_port = request.forms.get('settings_general_port') settings_general_baseurl = request.forms.get('settings_general_baseurl') + settings_general_loglevel = request.forms.get('settings_general_loglevel') settings_general_sourcepath = request.forms.getall('settings_general_sourcepath') settings_general_destpath = request.forms.getall('settings_general_destpath') settings_general_pathmapping = [] settings_general_pathmapping.extend([list(a) for a in zip(settings_general_sourcepath, settings_general_destpath)]) - c.execute("UPDATE table_settings_general SET ip = ?, port = ?, base_url = ?, path_mapping = ?", (settings_general_ip, settings_general_port, settings_general_baseurl, str(settings_general_pathmapping))) + c.execute("UPDATE table_settings_general SET ip = ?, port = ?, base_url = ?, path_mapping = ?, log_level = ?", (settings_general_ip, settings_general_port, settings_general_baseurl, str(settings_general_pathmapping), settings_general_loglevel)) settings_sonarr_ip = request.forms.get('settings_sonarr_ip') settings_sonarr_port = request.forms.get('settings_sonarr_port') @@ -205,17 +285,22 @@ def system(): db = sqlite3.connect('bazarr.db') c = db.cursor() c.execute("SELECT * FROM table_scheduler") - data = c.fetchall() + tasks = c.fetchall() c.close() - return template('system', rows=data) -@route('/remove_subtitles', method='GET') + logs = [] + for line in reversed(open('bazarr.log').readlines()): + logs.append(line.rstrip()) + + return template('system', tasks=tasks, logs=logs) + +@route('/remove_subtitles', method='POST') def remove_subtitles(): - episodePath = request.GET.episodePath - language = request.GET.language - subtitlesPath = request.GET.subtitlesPath - sonarrSeriesId = request.GET.sonarrSeriesId - sonarrEpisodeId = request.GET.sonarrEpisodeId + episodePath = request.forms.get('episodePath') + language = request.forms.get('language') + subtitlesPath = request.forms.get('subtitlesPath') + sonarrSeriesId = request.forms.get('sonarrSeriesId') + sonarrEpisodeId = request.forms.get('sonarrEpisodeId') try: os.remove(subtitlesPath) @@ -224,18 +309,17 @@ def remove_subtitles(): except OSError: pass store_subtitles(episodePath) - list_missing_subtitles() - redirect('/episodes/' + sonarrSeriesId) - -@route('/get_subtitle', method='GET') + list_missing_subtitles(sonarrSeriesId) + +@route('/get_subtitle', method='POST') def get_subtitle(): ref = request.environ['HTTP_REFERER'] - episodePath = request.GET.episodePath - language = request.GET.language - hi = request.GET.hi - sonarrSeriesId = request.GET.sonarrSeriesId - sonarrEpisodeId = request.GET.sonarrEpisodeId + episodePath = request.forms.get('episodePath') + language = request.forms.get('language') + hi = request.forms.get('hi') + sonarrSeriesId = request.forms.get('sonarrSeriesId') + sonarrEpisodeId = request.forms.get('sonarrEpisodeId') db = sqlite3.connect('bazarr.db') c = db.cursor() @@ -252,7 +336,7 @@ def get_subtitle(): if result is not None: history_log(1, sonarrSeriesId, sonarrEpisodeId, result) store_subtitles(episodePath) - list_missing_subtitles() + list_missing_subtitles(sonarrSeriesId) redirect(ref) except OSError: redirect(ref + '?error=2') diff --git a/create_db.sql b/create_db.sql new file mode 100644 index 000000000..68642c0dd --- /dev/null +++ b/create_db.sql @@ -0,0 +1,64 @@ +BEGIN TRANSACTION; +CREATE TABLE "table_shows" ( + `tvdbId` INTEGER NOT NULL UNIQUE, + `title` TEXT NOT NULL, + `path` TEXT NOT NULL UNIQUE, + `languages` TEXT, + `hearing_impaired` TEXT, + `sonarrSeriesId` INTEGER NOT NULL UNIQUE, + `overview` TEXT, + `poster` TEXT, + `fanart` TEXT, + PRIMARY KEY(`tvdbId`) +); +CREATE TABLE "table_settings_sonarr" ( + `ip` TEXT NOT NULL, + `port` INTEGER NOT NULL, + `base_url` TEXT, + `ssl` INTEGER, + `apikey` TEXT +); +INSERT INTO `table_settings_sonarr` (ip,port,base_url,ssl,apikey) VALUES ('127.0.0.1',8989,'/','False',Null); +CREATE TABLE "table_settings_providers" ( + `name` TEXT NOT NULL UNIQUE, + `enabled` INTEGER, + PRIMARY KEY(`name`) +); +CREATE TABLE "table_settings_languages" ( + `code3` TEXT NOT NULL UNIQUE, + `code2` TEXT, + `name` TEXT NOT NULL, + `enabled` INTEGER, + PRIMARY KEY(`code3`) +); +CREATE TABLE "table_settings_general" ( + `ip` TEXT NOT NULL, + `port` INTEGER NOT NULL, + `base_url` TEXT, + `path_mapping` TEXT +); +INSERT INTO `table_settings_general` (ip,port,base_url,path_mapping) VALUES ('0.0.0.0',6767,'/',Null); +CREATE TABLE `table_scheduler` ( + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, + `name` TEXT NOT NULL, + `frequency` TEXT NOT NULL +); +CREATE TABLE "table_history" ( + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, + `action` INTEGER NOT NULL, + `sonarrSeriesId` INTEGER NOT NULL, + `sonarrEpisodeId` INTEGER NOT NULL, + `timestamp` INTEGER NOT NULL, + `description` TEXT NOT NULL +); +CREATE TABLE "table_episodes" ( + `sonarrSeriesId` INTEGER NOT NULL, + `sonarrEpisodeId` INTEGER NOT NULL UNIQUE, + `title` TEXT NOT NULL, + `path` TEXT NOT NULL UNIQUE, + `season` INTEGER NOT NULL, + `episode` INTEGER NOT NULL, + `subtitles` TEXT, + `missing_subtitles` TEXT +); +COMMIT; diff --git a/create_db.sql.old b/create_db.sql.old deleted file mode 100644 index 2c88fac02..000000000 --- a/create_db.sql.old +++ /dev/null @@ -1,49 +0,0 @@ -CREATE TABLE `table_shows` ( - `tvdbId` INTEGER NOT NULL PRIMARY KEY UNIQUE, - `title` TEXT NOT NULL, - `path` TEXT NOT NULL UNIQUE, - `languages` TEXT, - `hearing_impaired` TEXT -); -CREATE TABLE `table_settings_subliminal` ( - `age` TEXT, - `max-workers` INTEGER -); -CREATE TABLE `table_settings_providers` ( - `name` TEXT NOT NULL UNIQUE, - `username` TEXT, - `password` TEXT, - `enabled` INTEGER, - PRIMARY KEY(`name`) -); -CREATE TABLE `table_settings_languages` ( - `code` TEXT NOT NULL UNIQUE, - `name` TEXT NOT NULL, - `enabled` INTEGER, - PRIMARY KEY(`code`) -); -CREATE TABLE `table_settings_general` ( - `ip` TEXT NOT NULL, - `port` INTEGER NOT NULL, - `base_url` TEXT, - `ssl` INTEGER -); -INSERT INTO `table_settings_general` (ip,port,base_url,ssl) VALUES ('0.0.0.0',6767,NULL,NULL); -CREATE TABLE `table_settings_connect` ( - `ip` TEXT NOT NULL, - `port` INTEGER NOT NULL, - `base_url` TEXT, - `ssl` INTEGER, - `apikey` TEXT NOT NULL -); -CREATE TABLE `table_scheduler` ( - `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, - `name` TEXT NOT NULL, - `frequency` TEXT NOT NULL -); -CREATE TABLE `table_history` ( - `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, - `timestamp` TEXT NOT NULL, - `file` TEXT NOT NULL, - `provider` TEXT NOT NULL -); diff --git a/get_episodes.py b/get_episodes.py index 6f9846cc9..24ffee633 100644 --- a/get_episodes.py +++ b/get_episodes.py @@ -1,6 +1,7 @@ import sqlite3 import requests +from get_general_settings import * from list_subtitles import * def update_all_episodes(): @@ -20,7 +21,12 @@ def update_all_episodes(): else: base_url_sonarr = "/" + config_sonarr[2].strip("/") + # Get current episodes id in DB + current_episodes_db = c.execute('SELECT sonarrEpisodeId FROM table_episodes').fetchall() + current_episodes_db_list = [x[0] for x in current_episodes_db] + # Get sonarrId for each series from database + current_episodes_sonarr = [] c.execute("SELECT sonarrSeriesId FROM table_shows") seriesIdList = c.fetchall() for seriesId in seriesIdList: @@ -29,20 +35,88 @@ def update_all_episodes(): r = requests.get(url_sonarr_api_episode) for episode in r.json(): if episode['hasFile']: + # Add shows in Sonarr to current shows list + current_episodes_sonarr.append(episode['id']) + try: c.execute('''INSERT INTO table_episodes(sonarrSeriesId, sonarrEpisodeId, title, path, season, episode) VALUES (?, ?, ?, ?, ?, ?)''', (episode['seriesId'], episode['id'], episode['title'], episode['episodeFile']['path'], episode['seasonNumber'], episode['episodeNumber'])) except sqlite3.Error: - test = c.execute('''UPDATE table_episodes SET sonarrSeriesId = ?, sonarrEpisodeId = ?, title = ?, path = ?, season = ?, episode = ? WHERE path = ?''', (episode['seriesId'], episode['id'], episode['title'], episode['episodeFile']['path'], episode['seasonNumber'], episode['episodeNumber'], episode['episodeFile']['path'])) + c.execute('''UPDATE table_episodes SET sonarrSeriesId = ?, sonarrEpisodeId = ?, title = ?, path = ?, season = ?, episode = ? WHERE sonarrEpisodeId = ?''', (episode['seriesId'], episode['id'], episode['title'], episode['episodeFile']['path'], episode['seasonNumber'], episode['episodeNumber'], episode['id'])) else: continue continue + # Delete episodes not in Sonarr anymore + deleted_items = [] + for item in current_episodes_db_list: + if item not in current_episodes_sonarr: + deleted_items.append(tuple([item])) + c.executemany('DELETE FROM table_episodes WHERE sonarrEpisodeId = ?',deleted_items) + # Commit changes to database table db.commit() # Close database connection c.close() + # Store substitles for all episodes + full_scan_subtitles() + list_missing_subtitles() + +def add_new_episodes(): + # Open database connection + db = sqlite3.connect('bazarr.db') + c = db.cursor() + + # Get Sonarr API URL from database config table + c.execute('''SELECT * FROM table_settings_sonarr''') + config_sonarr = c.fetchone() + if config_sonarr[3] == 1: + protocol_sonarr = "https" + else: + protocol_sonarr = "http" + if config_sonarr[2] == "": + base_url_sonarr = "" + else: + base_url_sonarr = "/" + config_sonarr[2].strip("/") + + # Get current episodes in DB + current_episodes_db = c.execute('SELECT sonarrEpisodeId FROM table_episodes').fetchall() + current_episodes_db_list = [x[0] for x in current_episodes_db] + current_episodes_sonarr = [] + + # Get sonarrId for each series from database + c.execute("SELECT sonarrSeriesId FROM table_shows") + seriesIdList = c.fetchall() + for seriesId in seriesIdList: + # Get episodes data for a series from Sonarr + url_sonarr_api_episode = protocol_sonarr + "://" + config_sonarr[0] + ":" + str(config_sonarr[1]) + base_url_sonarr + "/api/episode?seriesId=" + str(seriesId[0]) + "&apikey=" + config_sonarr[4] + r = requests.get(url_sonarr_api_episode) + + for episode in r.json(): + if episode['hasFile']: + # Add shows in Sonarr to current shows list + current_episodes_sonarr.append(episode['id']) + + try: + c.execute('''INSERT INTO table_episodes(sonarrSeriesId, sonarrEpisodeId, title, path, season, episode) VALUES (?, ?, ?, ?, ?, ?)''', (episode['seriesId'], episode['id'], episode['title'], episode['episodeFile']['path'], episode['seasonNumber'], episode['episodeNumber'])) + except: + pass + db.commit() + + # Delete episodes not in Sonarr anymore + deleted_items = [] + for item in current_episodes_db_list: + if item not in current_episodes_sonarr: + deleted_items.append(tuple([item])) + c.executemany('DELETE FROM table_episodes WHERE sonarrEpisodeId = ?',deleted_items) + + # Commit changes to database table + db.commit() + + # Close database connection + c.close() + # Store substitles from episodes we've just added new_scan_subtitles() list_missing_subtitles() diff --git a/get_general_settings.py b/get_general_settings.py index b7599083e..b1871d4dd 100644 --- a/get_general_settings.py +++ b/get_general_settings.py @@ -16,7 +16,10 @@ db.close() ip = general_settings[0] port = general_settings[1] base_url = general_settings[2] -path_mappings = ast.literal_eval(general_settings[3]) +if general_settings[3] is None: + path_mappings = [] +else: + path_mappings = ast.literal_eval(general_settings[3]) def path_replace(path): for path_mapping in path_mappings: diff --git a/get_general_settings.pyc b/get_general_settings.pyc index da21bc29f..8593d559f 100644 Binary files a/get_general_settings.pyc and b/get_general_settings.pyc differ diff --git a/get_series.py b/get_series.py index e487a4f34..c8dba939f 100644 --- a/get_series.py +++ b/get_series.py @@ -11,7 +11,6 @@ def update_series(): # Get shows data from Sonarr url_sonarr_api_series = url_sonarr + "/api/series?apikey=" + apikey_sonarr - r = requests.get(url_sonarr_api_series) shows_list = [] @@ -35,15 +34,13 @@ def update_series(): fanart = show['images'][0]['url'].split('?')[0] except: fanart = "" - + # Add shows in Sonarr to current shows list current_shows_sonarr.append(show['tvdbId']) # Update or insert shows list in database table - try: - c.execute('''UPDATE table_shows SET title = ?, path = ?, tvdbId = ?, sonarrSeriesId = ?, overview = ?, poster = ?, fanart = ? WHERE tvdbid = ?''', (show["title"],show["path"],show["tvdbId"],show["id"],overview,poster,fanart,show["tvdbId"])) - except: - print show["title"] + result = c.execute('''UPDATE table_shows SET title = ?, path = ?, tvdbId = ?, sonarrSeriesId = ?, overview = ?, poster = ?, fanart = ? WHERE tvdbid = ?''', (show["title"],show["path"],show["tvdbId"],show["id"],overview,poster,fanart,show["tvdbId"])) + if result.rowcount == 0: c.execute('''INSERT INTO table_shows(title, path, tvdbId, languages,`hearing_impaired`, sonarrSeriesId, overview, poster, fanart) VALUES (?,?,?,(SELECT languages FROM table_shows WHERE tvdbId = ?),(SELECT `hearing_impaired` FROM table_shows WHERE tvdbId = ?), ?, ?, ?, ?)''', (show["title"],show["path"],show["tvdbId"],show["tvdbId"],show["tvdbId"],show["id"],overview,poster,fanart)) # Delete shows not in Sonarr anymore diff --git a/get_sonarr_settings.pyc b/get_sonarr_settings.pyc index 3dc844f3d..8063bc4a8 100644 Binary files a/get_sonarr_settings.pyc and b/get_sonarr_settings.pyc differ diff --git a/get_subtitle.py b/get_subtitle.py index 0d525d4df..b51b49cdc 100644 --- a/get_subtitle.py +++ b/get_subtitle.py @@ -1,7 +1,12 @@ import os +import sqlite3 +import ast from babelfish import * from subliminal import * from pycountry import * +from get_general_settings import * +from list_subtitles import * +from utils import * # configure the cache region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'}) @@ -20,3 +25,43 @@ def download_subtitle(path, language, hi, providers): return message except: return None + +def series_download_subtitles(no): + conn_db = sqlite3.connect('bazarr.db') + c_db = conn_db.cursor() + episodes_details = c_db.execute("SELECT path, missing_subtitles, sonarrEpisodeId FROM table_episodes WHERE path = ?", (no,)).fetchall() + series_details = c_db.execute("SELECT hearing_impaired FROM table_shows WHERE sonarrSeriesId = ?", (no,)).fetchone() + enabled_providers = c_db.execute("SELECT name FROM table_settings_providers WHERE enabled = 1").fetchall() + c_db.close() + + providers_list = [] + for provider in enabled_providers: + providers_list.append(provider[0]) + + for episode in episodes_details: + for language in ast.literal_eval(episode[1]): + message = download_subtitle(path_replace(episode[0]), str(pycountry.languages.lookup(language).alpha_3), series_details[0], providers_list) + if message is not None: + store_subtitles(path_replace(episode[0])) + history_log(1, no, episode[2], message) + list_missing_subtitles(no) + +def wanted_download_subtitles(path): + conn_db = sqlite3.connect('bazarr.db') + c_db = conn_db.cursor() + episodes_details = c_db.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, table_episodes.sonarrEpisodeId, table_episodes.sonarrSeriesId, table_shows.hearing_impaired FROM table_episodes INNER JOIN table_shows on table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId WHERE table_episodes.path = ? AND missing_subtitles != '[]'", (path_replace_reverse(path),)).fetchall() + enabled_providers = c_db.execute("SELECT name FROM table_settings_providers WHERE enabled = 1").fetchall() + c_db.close() + + providers_list = [] + for provider in enabled_providers: + providers_list.append(provider[0]) + + for episode in episodes_details: + for language in ast.literal_eval(episode[1]): + message = download_subtitle(path_replace(episode[0]), str(pycountry.languages.lookup(language).alpha_3), episode[4], providers_list) + if message is not None: + store_subtitles(path_replace(episode[0])) + list_missing_subtitles(episode[3]) + history_log(1, episode[3], episode[2], message) + diff --git a/list_subtitles.py b/list_subtitles.py index c3bbe6803..743fa6171 100644 --- a/list_subtitles.py +++ b/list_subtitles.py @@ -65,10 +65,15 @@ def store_subtitles(file): return actual_subtitles -def list_missing_subtitles(): +def list_missing_subtitles(*no): + query_string = '' + try: + query_string = " WHERE table_episodes.sonarrSeriesId = " + str(no[0]) + except: + pass conn_db = sqlite3.connect('bazarr.db') c_db = conn_db.cursor() - episodes_subtitles = c_db.execute("SELECT table_episodes.sonarrEpisodeId, table_episodes.subtitles, table_shows.languages FROM table_episodes INNER JOIN table_shows on table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId").fetchall() + episodes_subtitles = c_db.execute("SELECT table_episodes.sonarrEpisodeId, table_episodes.subtitles, table_shows.languages FROM table_episodes INNER JOIN table_shows on table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId" + query_string).fetchall() missing_subtitles_global = [] @@ -101,6 +106,17 @@ def full_scan_subtitles(): for episode in episodes: store_subtitles(path_replace(episode[0])) + +def series_scan_subtitles(no): + conn_db = sqlite3.connect('bazarr.db') + c_db = conn_db.cursor() + episodes = c_db.execute("SELECT path FROM table_episodes WHERE sonarrSeriesId = ?", (no,)).fetchall() + c_db.close() + + for episode in episodes: + store_subtitles(path_replace(episode[0])) + + list_missing_subtitles(no) def new_scan_subtitles(): conn_db = sqlite3.connect('bazarr.db') diff --git a/list_subtitles.pyc b/list_subtitles.pyc index eb427fce1..bb5e3e330 100644 Binary files a/list_subtitles.pyc and b/list_subtitles.pyc differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..221f6b2bb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +babelfish +bottle +bottle-fdsend +dogpile.cache +enzyme +py-pretty +pycountry +requests +subliminal +urllib3 +waitress \ No newline at end of file diff --git a/scheduler.py b/scheduler.py new file mode 100644 index 000000000..87b16683a --- /dev/null +++ b/scheduler.py @@ -0,0 +1,12 @@ +import datetime, threading, time + +def foo(): + next_call = time.time() + while True: + print datetime.datetime.now() + next_call = next_call+1; + time.sleep(next_call - time.time()) + +timerThread = threading.Thread(target=foo) +timerThread.daemon = True +timerThread.start() diff --git a/views/episodes.tpl b/views/episodes.tpl index 335aa1c0a..9227bc74b 100644 --- a/views/episodes.tpl +++ b/views/episodes.tpl @@ -156,7 +156,7 @@ %if actual_languages is not None: %for language in actual_languages: %if language[1] is not None: - + {{language[0]}} @@ -172,7 +172,7 @@ %missing_languages = ast.literal_eval(episode[6]) %if missing_languages is not None: %for language in missing_languages: - + {{language}} @@ -189,4 +189,52 @@ %end - \ No newline at end of file + + + \ No newline at end of file diff --git a/views/history.tpl b/views/history.tpl index ce8528927..86c1854c9 100644 --- a/views/history.tpl +++ b/views/history.tpl @@ -123,12 +123,12 @@
@@ -153,16 +153,23 @@ \ No newline at end of file diff --git a/views/system.tpl b/views/system.tpl index 40732ff1a..215f565bd 100644 --- a/views/system.tpl +++ b/views/system.tpl @@ -34,6 +34,7 @@ border-radius: 0px; box-shadow: 0px 0px 5px 5px #ffffff; margin-top: 32px; + margin-bottom: 3em; padding: 1em; } @@ -80,21 +81,85 @@ Tasks
- Logs +
+ + + + + + + + + + %import time + %import datetime + %import pretty + %for log in logs: + %line = [] + %line = log.split('|') + + + + + + %end + +
MessageTime
{{line[2]}}{{pretty.date(int(time.mktime(datetime.datetime.strptime(line[0], "%d/%m/%Y %H:%M:%S").timetuple())))}}
+
About
+ + \ No newline at end of file