mirror of
https://github.com/morpheus65535/bazarr.git
synced 2025-01-01 12:32:25 +08:00
Continuig development
This commit is contained in:
parent
546c3ac066
commit
edb46d9115
22 changed files with 554 additions and 99 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
bazarr.db
|
bazarr.db
|
||||||
cachefile.dbm
|
cachefile.dbm
|
||||||
|
*.log
|
||||||
|
*.log.*
|
||||||
|
|
10
Dockerfile
Normal file
10
Dockerfile
Normal file
|
@ -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"]
|
BIN
bazarr.db
BIN
bazarr.db
Binary file not shown.
128
bazarr.py
128
bazarr.py
|
@ -25,6 +25,44 @@ from list_subtitles import *
|
||||||
from get_subtitle import *
|
from get_subtitle import *
|
||||||
from utils 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')
|
@route('/static/:path#.+#', name='static')
|
||||||
def static(path):
|
def static(path):
|
||||||
return static_file(path, root='static')
|
return static_file(path, root='static')
|
||||||
|
@ -48,7 +86,7 @@ def series():
|
||||||
c.execute("SELECT code2, name FROM table_settings_languages WHERE enabled = 1")
|
c.execute("SELECT code2, name FROM table_settings_languages WHERE enabled = 1")
|
||||||
languages = c.fetchall()
|
languages = c.fetchall()
|
||||||
c.close()
|
c.close()
|
||||||
output = template('series', rows=data, languages=languages, url_sonarr_short=url_sonarr_short)
|
output = template('series', rows=data, languages=languages)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
@route('/edit_series/<no:int>', method='POST')
|
@route('/edit_series/<no:int>', method='POST')
|
||||||
|
@ -74,6 +112,8 @@ def edit_series(no):
|
||||||
conn.commit()
|
conn.commit()
|
||||||
c.close()
|
c.close()
|
||||||
|
|
||||||
|
list_missing_subtitles(no)
|
||||||
|
|
||||||
redirect('/')
|
redirect('/')
|
||||||
|
|
||||||
@route('/update_series')
|
@route('/update_series')
|
||||||
|
@ -88,6 +128,12 @@ def update_all_episodes_list():
|
||||||
|
|
||||||
redirect('/')
|
redirect('/')
|
||||||
|
|
||||||
|
@route('/add_new_episodes')
|
||||||
|
def add_new_episodes_list():
|
||||||
|
add_new_episodes()
|
||||||
|
|
||||||
|
redirect('/')
|
||||||
|
|
||||||
@route('/episodes/<no:int>', method='GET')
|
@route('/episodes/<no:int>', method='GET')
|
||||||
def episodes(no):
|
def episodes(no):
|
||||||
conn = sqlite3.connect('bazarr.db')
|
conn = sqlite3.connect('bazarr.db')
|
||||||
|
@ -97,14 +143,30 @@ def episodes(no):
|
||||||
series_details = []
|
series_details = []
|
||||||
series_details = c.execute("SELECT title, overview, poster, fanart, hearing_impaired FROM table_shows WHERE sonarrSeriesId LIKE ?", (str(no),)).fetchone()
|
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)))
|
episodes = reversed(sorted(episodes, key=operator.itemgetter(2)))
|
||||||
seasons_list = []
|
seasons_list = []
|
||||||
for key,season in itertools.groupby(episodes,operator.itemgetter(2)):
|
for key,season in itertools.groupby(episodes,operator.itemgetter(2)):
|
||||||
seasons_list.append(list(season))
|
seasons_list.append(list(season))
|
||||||
c.close()
|
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/<no:int>', method='GET')
|
||||||
|
def scan_disk(no):
|
||||||
|
ref = request.environ['HTTP_REFERER']
|
||||||
|
|
||||||
|
series_scan_subtitles(no)
|
||||||
|
|
||||||
|
redirect(ref)
|
||||||
|
|
||||||
|
@route('/search_missing_subtitles/<no:int>', method='GET')
|
||||||
|
def search_missing_subtitles(no):
|
||||||
|
ref = request.environ['HTTP_REFERER']
|
||||||
|
|
||||||
|
series_download_subtitles(no)
|
||||||
|
|
||||||
|
redirect(ref)
|
||||||
|
|
||||||
@route('/history')
|
@route('/history')
|
||||||
def history():
|
def history():
|
||||||
|
@ -141,11 +203,28 @@ def wanted():
|
||||||
offset = (int(page) - 1) * 15
|
offset = (int(page) - 1) * 15
|
||||||
max_page = (missing_count / 15) + 1
|
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()
|
data = c.fetchall()
|
||||||
c.close()
|
c.close()
|
||||||
return template('wanted', rows=data, missing_count=missing_count, page=page, max_page=max_page)
|
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')
|
@route('/settings')
|
||||||
def settings():
|
def settings():
|
||||||
db = sqlite3.connect('bazarr.db')
|
db = sqlite3.connect('bazarr.db')
|
||||||
|
@ -169,11 +248,12 @@ def save_settings():
|
||||||
settings_general_ip = request.forms.get('settings_general_ip')
|
settings_general_ip = request.forms.get('settings_general_ip')
|
||||||
settings_general_port = request.forms.get('settings_general_port')
|
settings_general_port = request.forms.get('settings_general_port')
|
||||||
settings_general_baseurl = request.forms.get('settings_general_baseurl')
|
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_sourcepath = request.forms.getall('settings_general_sourcepath')
|
||||||
settings_general_destpath = request.forms.getall('settings_general_destpath')
|
settings_general_destpath = request.forms.getall('settings_general_destpath')
|
||||||
settings_general_pathmapping = []
|
settings_general_pathmapping = []
|
||||||
settings_general_pathmapping.extend([list(a) for a in zip(settings_general_sourcepath, settings_general_destpath)])
|
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_ip = request.forms.get('settings_sonarr_ip')
|
||||||
settings_sonarr_port = request.forms.get('settings_sonarr_port')
|
settings_sonarr_port = request.forms.get('settings_sonarr_port')
|
||||||
|
@ -205,17 +285,22 @@ def system():
|
||||||
db = sqlite3.connect('bazarr.db')
|
db = sqlite3.connect('bazarr.db')
|
||||||
c = db.cursor()
|
c = db.cursor()
|
||||||
c.execute("SELECT * FROM table_scheduler")
|
c.execute("SELECT * FROM table_scheduler")
|
||||||
data = c.fetchall()
|
tasks = c.fetchall()
|
||||||
c.close()
|
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():
|
def remove_subtitles():
|
||||||
episodePath = request.GET.episodePath
|
episodePath = request.forms.get('episodePath')
|
||||||
language = request.GET.language
|
language = request.forms.get('language')
|
||||||
subtitlesPath = request.GET.subtitlesPath
|
subtitlesPath = request.forms.get('subtitlesPath')
|
||||||
sonarrSeriesId = request.GET.sonarrSeriesId
|
sonarrSeriesId = request.forms.get('sonarrSeriesId')
|
||||||
sonarrEpisodeId = request.GET.sonarrEpisodeId
|
sonarrEpisodeId = request.forms.get('sonarrEpisodeId')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.remove(subtitlesPath)
|
os.remove(subtitlesPath)
|
||||||
|
@ -224,18 +309,17 @@ def remove_subtitles():
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
store_subtitles(episodePath)
|
store_subtitles(episodePath)
|
||||||
list_missing_subtitles()
|
list_missing_subtitles(sonarrSeriesId)
|
||||||
redirect('/episodes/' + sonarrSeriesId)
|
|
||||||
|
|
||||||
@route('/get_subtitle', method='GET')
|
@route('/get_subtitle', method='POST')
|
||||||
def get_subtitle():
|
def get_subtitle():
|
||||||
ref = request.environ['HTTP_REFERER']
|
ref = request.environ['HTTP_REFERER']
|
||||||
|
|
||||||
episodePath = request.GET.episodePath
|
episodePath = request.forms.get('episodePath')
|
||||||
language = request.GET.language
|
language = request.forms.get('language')
|
||||||
hi = request.GET.hi
|
hi = request.forms.get('hi')
|
||||||
sonarrSeriesId = request.GET.sonarrSeriesId
|
sonarrSeriesId = request.forms.get('sonarrSeriesId')
|
||||||
sonarrEpisodeId = request.GET.sonarrEpisodeId
|
sonarrEpisodeId = request.forms.get('sonarrEpisodeId')
|
||||||
|
|
||||||
db = sqlite3.connect('bazarr.db')
|
db = sqlite3.connect('bazarr.db')
|
||||||
c = db.cursor()
|
c = db.cursor()
|
||||||
|
@ -252,7 +336,7 @@ def get_subtitle():
|
||||||
if result is not None:
|
if result is not None:
|
||||||
history_log(1, sonarrSeriesId, sonarrEpisodeId, result)
|
history_log(1, sonarrSeriesId, sonarrEpisodeId, result)
|
||||||
store_subtitles(episodePath)
|
store_subtitles(episodePath)
|
||||||
list_missing_subtitles()
|
list_missing_subtitles(sonarrSeriesId)
|
||||||
redirect(ref)
|
redirect(ref)
|
||||||
except OSError:
|
except OSError:
|
||||||
redirect(ref + '?error=2')
|
redirect(ref + '?error=2')
|
||||||
|
|
64
create_db.sql
Normal file
64
create_db.sql
Normal file
|
@ -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;
|
|
@ -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
|
|
||||||
);
|
|
|
@ -1,6 +1,7 @@
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from get_general_settings import *
|
||||||
from list_subtitles import *
|
from list_subtitles import *
|
||||||
|
|
||||||
def update_all_episodes():
|
def update_all_episodes():
|
||||||
|
@ -20,7 +21,12 @@ def update_all_episodes():
|
||||||
else:
|
else:
|
||||||
base_url_sonarr = "/" + config_sonarr[2].strip("/")
|
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
|
# Get sonarrId for each series from database
|
||||||
|
current_episodes_sonarr = []
|
||||||
c.execute("SELECT sonarrSeriesId FROM table_shows")
|
c.execute("SELECT sonarrSeriesId FROM table_shows")
|
||||||
seriesIdList = c.fetchall()
|
seriesIdList = c.fetchall()
|
||||||
for seriesId in seriesIdList:
|
for seriesId in seriesIdList:
|
||||||
|
@ -29,14 +35,82 @@ def update_all_episodes():
|
||||||
r = requests.get(url_sonarr_api_episode)
|
r = requests.get(url_sonarr_api_episode)
|
||||||
for episode in r.json():
|
for episode in r.json():
|
||||||
if episode['hasFile']:
|
if episode['hasFile']:
|
||||||
|
# Add shows in Sonarr to current shows list
|
||||||
|
current_episodes_sonarr.append(episode['id'])
|
||||||
|
|
||||||
try:
|
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']))
|
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:
|
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:
|
else:
|
||||||
continue
|
continue
|
||||||
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
|
# Commit changes to database table
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@ db.close()
|
||||||
ip = general_settings[0]
|
ip = general_settings[0]
|
||||||
port = general_settings[1]
|
port = general_settings[1]
|
||||||
base_url = general_settings[2]
|
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):
|
def path_replace(path):
|
||||||
for path_mapping in path_mappings:
|
for path_mapping in path_mappings:
|
||||||
|
|
Binary file not shown.
|
@ -11,7 +11,6 @@ def update_series():
|
||||||
|
|
||||||
# Get shows data from Sonarr
|
# Get shows data from Sonarr
|
||||||
url_sonarr_api_series = url_sonarr + "/api/series?apikey=" + apikey_sonarr
|
url_sonarr_api_series = url_sonarr + "/api/series?apikey=" + apikey_sonarr
|
||||||
|
|
||||||
r = requests.get(url_sonarr_api_series)
|
r = requests.get(url_sonarr_api_series)
|
||||||
shows_list = []
|
shows_list = []
|
||||||
|
|
||||||
|
@ -40,10 +39,8 @@ def update_series():
|
||||||
current_shows_sonarr.append(show['tvdbId'])
|
current_shows_sonarr.append(show['tvdbId'])
|
||||||
|
|
||||||
# Update or insert shows list in database table
|
# Update or insert shows list in database table
|
||||||
try:
|
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"]))
|
||||||
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:
|
||||||
except:
|
|
||||||
print show["title"]
|
|
||||||
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))
|
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
|
# Delete shows not in Sonarr anymore
|
||||||
|
|
Binary file not shown.
|
@ -1,7 +1,12 @@
|
||||||
import os
|
import os
|
||||||
|
import sqlite3
|
||||||
|
import ast
|
||||||
from babelfish import *
|
from babelfish import *
|
||||||
from subliminal import *
|
from subliminal import *
|
||||||
from pycountry import *
|
from pycountry import *
|
||||||
|
from get_general_settings import *
|
||||||
|
from list_subtitles import *
|
||||||
|
from utils import *
|
||||||
|
|
||||||
# configure the cache
|
# configure the cache
|
||||||
region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})
|
region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})
|
||||||
|
@ -20,3 +25,43 @@ def download_subtitle(path, language, hi, providers):
|
||||||
return message
|
return message
|
||||||
except:
|
except:
|
||||||
return None
|
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)
|
||||||
|
|
||||||
|
|
|
@ -65,10 +65,15 @@ def store_subtitles(file):
|
||||||
|
|
||||||
return actual_subtitles
|
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')
|
conn_db = sqlite3.connect('bazarr.db')
|
||||||
c_db = conn_db.cursor()
|
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 = []
|
missing_subtitles_global = []
|
||||||
|
|
||||||
|
@ -102,6 +107,17 @@ def full_scan_subtitles():
|
||||||
for episode in episodes:
|
for episode in episodes:
|
||||||
store_subtitles(path_replace(episode[0]))
|
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():
|
def new_scan_subtitles():
|
||||||
conn_db = sqlite3.connect('bazarr.db')
|
conn_db = sqlite3.connect('bazarr.db')
|
||||||
c_db = conn_db.cursor()
|
c_db = conn_db.cursor()
|
||||||
|
|
Binary file not shown.
11
requirements.txt
Normal file
11
requirements.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
babelfish
|
||||||
|
bottle
|
||||||
|
bottle-fdsend
|
||||||
|
dogpile.cache
|
||||||
|
enzyme
|
||||||
|
py-pretty
|
||||||
|
pycountry
|
||||||
|
requests
|
||||||
|
subliminal
|
||||||
|
urllib3
|
||||||
|
waitress
|
12
scheduler.py
Normal file
12
scheduler.py
Normal file
|
@ -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()
|
|
@ -156,7 +156,7 @@
|
||||||
%if actual_languages is not None:
|
%if actual_languages is not None:
|
||||||
%for language in actual_languages:
|
%for language in actual_languages:
|
||||||
%if language[1] is not None:
|
%if language[1] is not None:
|
||||||
<a href="/remove_subtitles?episodePath={{episode[1]}}&subtitlesPath={{path_replace(language[1])}}&language={{pycountry.languages.lookup(str(language[0])).alpha_3}}&sonarrSeriesId={{episode[5]}}&sonarrEpisodeId={{episode[7]}}" class="ui tiny label">
|
<a data-episodePath="{{episode[1]}}" data-subtitlesPath="{{path_replace(language[1])}}" data-language="{{pycountry.languages.lookup(str(language[0])).alpha_3}}" data-sonarrSeriesId={{episode[5]}} data-sonarrEpisodeId={{episode[7]}} class="remove_subtitles ui tiny label">
|
||||||
{{language[0]}}
|
{{language[0]}}
|
||||||
<i class="delete icon"></i>
|
<i class="delete icon"></i>
|
||||||
</a>
|
</a>
|
||||||
|
@ -172,7 +172,7 @@
|
||||||
%missing_languages = ast.literal_eval(episode[6])
|
%missing_languages = ast.literal_eval(episode[6])
|
||||||
%if missing_languages is not None:
|
%if missing_languages is not None:
|
||||||
%for language in missing_languages:
|
%for language in missing_languages:
|
||||||
<a href="/get_subtitle?episodePath={{episode[1]}}&language={{pycountry.languages.lookup(str(language)).alpha_3}}&hi={{details[4]}}&sonarrSeriesId={{episode[5]}}&sonarrEpisodeId={{episode[7]}}" class="ui tiny label">
|
<a data-episodePath="{{episode[1]}}" data-language="{{pycountry.languages.lookup(str(language)).alpha_3}}" data-hi="{{details[4]}}" data-sonarrSeriesId={{episode[5]}} data-sonarrEpisodeId={{episode[7]}} class="get_subtitle ui tiny label">
|
||||||
{{language}}
|
{{language}}
|
||||||
<i style="margin-left:3px; margin-right:0px" class="search icon"></i>
|
<i style="margin-left:3px; margin-right:0px" class="search icon"></i>
|
||||||
</a>
|
</a>
|
||||||
|
@ -190,3 +190,51 @@
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$('#scan_disk').click(function(){
|
||||||
|
window.location = '/scan_disk/{{no}}';
|
||||||
|
})
|
||||||
|
|
||||||
|
$('#search_missing_subtitles').click(function(){
|
||||||
|
window.location = '/search_missing_subtitles/{{no}}';
|
||||||
|
})
|
||||||
|
|
||||||
|
$('.remove_subtitles').click(function(){
|
||||||
|
var values = {
|
||||||
|
episodePath: $(this).attr("data-episodePath"),
|
||||||
|
language: $(this).attr("data-language"),
|
||||||
|
subtitlesPath: $(this).attr("data-subtitlesPath"),
|
||||||
|
sonarrSeriesId: $(this).attr("data-sonarrSeriesId"),
|
||||||
|
sonarrEpisodeId: $(this).attr("data-sonarrEpisodeId")
|
||||||
|
};
|
||||||
|
$.ajax({
|
||||||
|
url: "/remove_subtitles",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
data: values
|
||||||
|
});
|
||||||
|
$('#loader').addClass('active');
|
||||||
|
})
|
||||||
|
|
||||||
|
$('.get_subtitle').click(function(){
|
||||||
|
var values = {
|
||||||
|
episodePath: $(this).attr("data-episodePath"),
|
||||||
|
language: $(this).attr("data-language"),
|
||||||
|
hi: $(this).attr("data-hi"),
|
||||||
|
sonarrSeriesId: $(this).attr("data-sonarrSeriesId"),
|
||||||
|
sonarrEpisodeId: $(this).attr("data-sonarrEpisodeId")
|
||||||
|
};
|
||||||
|
$.ajax({
|
||||||
|
url: "/get_subtitle",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
data: values
|
||||||
|
});
|
||||||
|
$('#loader').addClass('active');
|
||||||
|
})
|
||||||
|
|
||||||
|
$(document).ajaxStop(function(){
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -123,12 +123,12 @@
|
||||||
<div class="column"></div>
|
<div class="column"></div>
|
||||||
<div class="center aligned column">
|
<div class="center aligned column">
|
||||||
<i class="\\
|
<i class="\\
|
||||||
%if page == "1":
|
%if page == '1':
|
||||||
disabled\\
|
disabled\\
|
||||||
%end
|
%end
|
||||||
fast backward icon"></i>
|
fast backward icon"></i>
|
||||||
<i class="\\
|
<i class="\\
|
||||||
%if page == "1":
|
%if page == '1':
|
||||||
disabled\\
|
disabled\\
|
||||||
%end
|
%end
|
||||||
backward icon"></i>
|
backward icon"></i>
|
||||||
|
@ -153,16 +153,23 @@
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$('a').click(function(){
|
if (sessionStorage.scrolly) {
|
||||||
|
$(window).scrollTop(sessionStorage.scrolly);
|
||||||
|
sessionStorage.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
$('a, i').click(function(){
|
||||||
|
sessionStorage.scrolly=$(window).scrollTop();
|
||||||
|
|
||||||
$('#loader').addClass('active');
|
$('#loader').addClass('active');
|
||||||
})
|
})
|
||||||
|
|
||||||
$('.fast.backward').click(function(){
|
|
||||||
location.href="?page=1";
|
|
||||||
})
|
|
||||||
$('.backward').click(function(){
|
$('.backward').click(function(){
|
||||||
location.href="?page={{int(page)-1}}";
|
location.href="?page={{int(page)-1}}";
|
||||||
})
|
})
|
||||||
|
$('.fast.backward').click(function(){
|
||||||
|
location.href="?page=1";
|
||||||
|
})
|
||||||
$('.forward').click(function(){
|
$('.forward').click(function(){
|
||||||
location.href="?page={{int(page)+1}}";
|
location.href="?page={{int(page)+1}}";
|
||||||
})
|
})
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
<div class="ui basic buttons">
|
<div class="ui basic buttons">
|
||||||
<button id="update_series" class="ui button"><i class="refresh icon"></i>Update Series</button>
|
<button id="update_series" class="ui button"><i class="refresh icon"></i>Update Series</button>
|
||||||
<button id="update_all_episodes" class="ui button"><i class="refresh icon"></i>Update All Episodes</button>
|
<button id="update_all_episodes" class="ui button"><i class="refresh icon"></i>Update All Episodes</button>
|
||||||
|
<button id="add_new_episodes" class="ui button"><i class="wait icon"></i>Add New Episodes</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="tableseries" class="ui very basic selectable sortable table">
|
<table id="tableseries" class="ui very basic selectable sortable table">
|
||||||
|
@ -97,7 +98,7 @@
|
||||||
%import ast
|
%import ast
|
||||||
%import os
|
%import os
|
||||||
%for row in rows:
|
%for row in rows:
|
||||||
<tr class="selectable">
|
<tr class="selectable" {{!"style='background-color: yellow;'" if row[4] == None else ""}}>
|
||||||
<td><a href="/episodes/{{row[5]}}">{{row[1]}}</a></td>
|
<td><a href="/episodes/{{row[5]}}">{{row[1]}}</a></td>
|
||||||
<td>
|
<td>
|
||||||
{{row[2]}}
|
{{row[2]}}
|
||||||
|
@ -120,7 +121,7 @@
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
%>
|
%>
|
||||||
<div class="ui inverted basic compact icon" data-tooltip="Edit series" data-inverted="" data-tvdbid="{{row[0]}}" data-title="{{row[1]}}" data-poster="{{row[6]}}" data-languages="{{!subs_languages_list}}" data-hearing-impaired="{{row[4]}}">
|
<div class="config ui inverted basic compact icon" data-tooltip="Edit series" data-inverted="" data-tvdbid="{{row[0]}}" data-title="{{row[1]}}" data-poster="{{row[6]}}" data-languages="{{!subs_languages_list}}" data-hearing-impaired="{{row[4]}}">
|
||||||
<i class="ui black configure icon"></i>
|
<i class="ui black configure icon"></i>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -131,6 +132,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal">
|
<div class="ui small modal">
|
||||||
|
<i class="close icon"></i>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div id="series_title"></div>
|
<div id="series_title"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -188,7 +190,7 @@
|
||||||
|
|
||||||
$('table').tablesort();
|
$('table').tablesort();
|
||||||
|
|
||||||
$('a, button').click(function(){
|
$('a, button:not(.cancel)').click(function(){
|
||||||
$('#loader').addClass('active');
|
$('#loader').addClass('active');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -206,6 +208,10 @@
|
||||||
window.location = '/update_all_episodes';
|
window.location = '/update_all_episodes';
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$('#add_new_episodes').click(function(){
|
||||||
|
window.location = '/add_new_episodes';
|
||||||
|
})
|
||||||
|
|
||||||
$('.config').click(function(){
|
$('.config').click(function(){
|
||||||
sessionStorage.scrolly=$(window).scrollTop();
|
sessionStorage.scrolly=$(window).scrollTop();
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,22 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="middle aligned row">
|
||||||
|
<div class="right aligned four wide column">
|
||||||
|
<label>Log Level</label>
|
||||||
|
</div>
|
||||||
|
<div class="eleven wide column">
|
||||||
|
<select name="settings_general_loglevel" id="settings_loglevel" class="ui fluid selection dropdown">
|
||||||
|
<option value="">Log Level</option>
|
||||||
|
<option value="DEBUG">Debug</option>
|
||||||
|
<option value="INFO">Info</option>
|
||||||
|
<option value="WARNING">Warning</option>
|
||||||
|
<option value="ERROR">Error</option>
|
||||||
|
<option value="CRITICAL">Critical</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -131,7 +147,11 @@
|
||||||
<div class="twelve wide column">
|
<div class="twelve wide column">
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
%import ast
|
%import ast
|
||||||
%path_substitutions = ast.literal_eval(settings_general[3])
|
%if settings_general[3] is not None:
|
||||||
|
% path_substitutions = ast.literal_eval(settings_general[3])
|
||||||
|
%else:
|
||||||
|
% path_substitutions = []
|
||||||
|
%end
|
||||||
%for x in range(0, 5):
|
%for x in range(0, 5):
|
||||||
% path = []
|
% path = []
|
||||||
% try:
|
% try:
|
||||||
|
@ -165,6 +185,9 @@
|
||||||
<div class="ui container"><button class="ui blue right floated button">Save</button></div>
|
<div class="ui container"><button class="ui blue right floated button">Save</button></div>
|
||||||
<br>
|
<br>
|
||||||
<div class="ui dividing header">Sonarr settings</div>
|
<div class="ui dividing header">Sonarr settings</div>
|
||||||
|
<div class="ui negative message">
|
||||||
|
<p>These changes require that you restart Bazarr.</p>
|
||||||
|
</div>
|
||||||
<div class="twelve wide column">
|
<div class="twelve wide column">
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<div class="middle aligned row">
|
<div class="middle aligned row">
|
||||||
|
@ -230,6 +253,9 @@
|
||||||
<br>
|
<br>
|
||||||
<div class="ui dividing header">Subtitles providers</div>
|
<div class="ui dividing header">Subtitles providers</div>
|
||||||
<div class="twelve wide column">
|
<div class="twelve wide column">
|
||||||
|
<div class="ui negative message">
|
||||||
|
<p>Be aware that the more providers you enable, the longer it will take everytime you search for a subtitles.</p>
|
||||||
|
</div>
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<div class="middle aligned row">
|
<div class="middle aligned row">
|
||||||
<div class="right aligned four wide column">
|
<div class="right aligned four wide column">
|
||||||
|
@ -294,11 +320,14 @@
|
||||||
$("#sonarr_ssl_div").checkbox('uncheck');
|
$("#sonarr_ssl_div").checkbox('uncheck');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#settings_loglevel').dropdown('clear');
|
||||||
|
$('#settings_loglevel').dropdown('set selected','{{!settings_general[4]}}');
|
||||||
$('#settings_providers').dropdown('clear');
|
$('#settings_providers').dropdown('clear');
|
||||||
$('#settings_providers').dropdown('set selected',{{!enabled_providers}});
|
$('#settings_providers').dropdown('set selected',{{!enabled_providers}});
|
||||||
$('#settings_languages').dropdown('clear');
|
$('#settings_languages').dropdown('clear');
|
||||||
$('#settings_languages').dropdown('set selected',{{!enabled_languages}});
|
$('#settings_languages').dropdown('set selected',{{!enabled_languages}});
|
||||||
|
|
||||||
|
$('#settings_loglevel').dropdown();
|
||||||
$('#settings_providers').dropdown();
|
$('#settings_providers').dropdown();
|
||||||
$('#settings_languages').dropdown();
|
$('#settings_languages').dropdown();
|
||||||
</script>
|
</script>
|
|
@ -34,6 +34,7 @@
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
box-shadow: 0px 0px 5px 5px #ffffff;
|
box-shadow: 0px 0px 5px 5px #ffffff;
|
||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
|
margin-bottom: 3em;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -80,21 +81,85 @@
|
||||||
Tasks
|
Tasks
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached tab segment" data-tab="logs">
|
<div class="ui bottom attached tab segment" data-tab="logs">
|
||||||
Logs
|
<div class="content">
|
||||||
|
<table class="ui very basic selectable table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="collapsing"></th>
|
||||||
|
<th>Message</th>
|
||||||
|
<th class="collapsing">Time</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
%import time
|
||||||
|
%import datetime
|
||||||
|
%import pretty
|
||||||
|
%for log in logs:
|
||||||
|
%line = []
|
||||||
|
%line = log.split('|')
|
||||||
|
<tr class='log' data-message='{{line[2]}}' data-exception='{{line[3].replace("\\n", "<br />")}}'>
|
||||||
|
<td class="collapsing"><i class="\\
|
||||||
|
%if line[1] == 'INFO':
|
||||||
|
blue info circle \\
|
||||||
|
%elif line[1] == 'WARNING':
|
||||||
|
yellow warning circle \\
|
||||||
|
%elif line[1] == 'ERROR':
|
||||||
|
red bug \\
|
||||||
|
%end
|
||||||
|
icon"></i></td>
|
||||||
|
<td>{{line[2]}}</td>
|
||||||
|
<td title='{{line[0]}}' class="collapsing">{{pretty.date(int(time.mktime(datetime.datetime.strptime(line[0], "%d/%m/%Y %H:%M:%S").timetuple())))}}</td>
|
||||||
|
</tr>
|
||||||
|
%end
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached tab segment" data-tab="about">
|
<div class="ui bottom attached tab segment" data-tab="about">
|
||||||
About
|
About
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="ui small modal">
|
||||||
|
<i class="close icon"></i>
|
||||||
|
<div class="header">
|
||||||
|
<div>Details</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
Message
|
||||||
|
<div id='message' class="ui segment">
|
||||||
|
<p></p>
|
||||||
|
</div>
|
||||||
|
Exception
|
||||||
|
<div id='exception' class="ui segment">
|
||||||
|
<p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<button class="ui cancel button" >Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
$('.modal')
|
||||||
|
.modal({
|
||||||
|
autofocus: false
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
$('.menu .item')
|
$('.menu .item')
|
||||||
.tab()
|
.tab()
|
||||||
;
|
;
|
||||||
|
|
||||||
|
$('.log').click(function(){
|
||||||
|
$("#message").html($(this).data("message"));
|
||||||
|
$("#exception").html($(this).data("exception"));
|
||||||
|
$('.small.modal').modal('show');
|
||||||
|
})
|
||||||
|
|
||||||
$('a.menu').click(function(){
|
$('a.menu').click(function(){
|
||||||
$('#loader').addClass('active');
|
$('#loader').addClass('active');
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,7 +35,10 @@
|
||||||
box-shadow: 0px 0px 5px 5px #ffffff;
|
box-shadow: 0px 0px 5px 5px #ffffff;
|
||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
margin-bottom: 3em;
|
margin-bottom: 3em;
|
||||||
padding: 3em;
|
padding: 2em 3em 2em 3em;
|
||||||
|
}
|
||||||
|
#tablehistory {
|
||||||
|
padding-top: 2em;
|
||||||
}
|
}
|
||||||
.fast.backward, .backward, .forward, .fast.forward {
|
.fast.backward, .backward, .forward, .fast.forward {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -77,6 +80,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="fondblanc" class="ui container">
|
<div id="fondblanc" class="ui container">
|
||||||
|
<div class="ui right floated basic buttons">
|
||||||
|
<button id="wanted_search_missing_subtitles" class="ui button"><i class="download icon"></i>Download wanted subtitles</button>
|
||||||
|
</div>
|
||||||
<table id="tablehistory" class="ui very basic selectable table">
|
<table id="tablehistory" class="ui very basic selectable table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -101,7 +107,7 @@
|
||||||
%missing_languages = ast.literal_eval(row[3])
|
%missing_languages = ast.literal_eval(row[3])
|
||||||
%if missing_languages is not None:
|
%if missing_languages is not None:
|
||||||
%for language in missing_languages:
|
%for language in missing_languages:
|
||||||
<a href="/get_subtitle?episodePath={{row[5]}}&language={{pycountry.languages.lookup(str(language)).alpha_3}}&hi={{row[6]}}&sonarrSeriesId={{row[4]}}&sonarrEpisodeId={{row[7]}}" class="ui tiny label">
|
<a data-episodePath="{{row[5]}}" data-language="{{pycountry.languages.lookup(str(language)).alpha_3}}" data-hi="{{row[6]}}" data-sonarrSeriesId={{row[4]}} data-sonarrEpisodeId={{row[7]}} class="get_subtitle ui tiny label">
|
||||||
{{language}}
|
{{language}}
|
||||||
<i style="margin-left:3px; margin-right:0px" class="search icon"></i>
|
<i style="margin-left:3px; margin-right:0px" class="search icon"></i>
|
||||||
</a>
|
</a>
|
||||||
|
@ -147,7 +153,7 @@
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$('a').click(function(){
|
$('a, button').click(function(){
|
||||||
$('#loader').addClass('active');
|
$('#loader').addClass('active');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -163,4 +169,29 @@
|
||||||
$('.fast.forward').click(function(){
|
$('.fast.forward').click(function(){
|
||||||
location.href="?page={{int(max_page)}}";
|
location.href="?page={{int(max_page)}}";
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$('#wanted_search_missing_subtitles').click(function(){
|
||||||
|
window.location = '/wanted_search_missing_subtitles';
|
||||||
|
})
|
||||||
|
|
||||||
|
$('.get_subtitle').click(function(){
|
||||||
|
var values = {
|
||||||
|
episodePath: $(this).attr("data-episodePath"),
|
||||||
|
language: $(this).attr("data-language"),
|
||||||
|
hi: $(this).attr("data-hi"),
|
||||||
|
sonarrSeriesId: $(this).attr("data-sonarrSeriesId"),
|
||||||
|
sonarrEpisodeId: $(this).attr("data-sonarrEpisodeId")
|
||||||
|
};
|
||||||
|
$.ajax({
|
||||||
|
url: "/get_subtitle",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
data: values
|
||||||
|
});
|
||||||
|
$('#loader').addClass('active');
|
||||||
|
})
|
||||||
|
|
||||||
|
$(document).ajaxStop(function(){
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
Loading…
Reference in a new issue