mirror of
https://github.com/morpheus65535/bazarr.git
synced 2024-12-29 02:51:24 +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
|
||||
bazarr.db
|
||||
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.
130
bazarr.py
130
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/<no:int>', 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/<no:int>', 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/<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')
|
||||
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')
|
||||
|
|
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 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()
|
||||
|
|
|
@ -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:
|
||||
|
|
Binary file not shown.
|
@ -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
|
||||
|
|
Binary file not shown.
|
@ -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)
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
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:
|
||||
%for language in actual_languages:
|
||||
%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]}}
|
||||
<i class="delete icon"></i>
|
||||
</a>
|
||||
|
@ -172,7 +172,7 @@
|
|||
%missing_languages = ast.literal_eval(episode[6])
|
||||
%if missing_languages is not None:
|
||||
%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}}
|
||||
<i style="margin-left:3px; margin-right:0px" class="search icon"></i>
|
||||
</a>
|
||||
|
@ -189,4 +189,52 @@
|
|||
%end
|
||||
</div>
|
||||
</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="center aligned column">
|
||||
<i class="\\
|
||||
%if page == "1":
|
||||
%if page == '1':
|
||||
disabled\\
|
||||
%end
|
||||
fast backward icon"></i>
|
||||
<i class="\\
|
||||
%if page == "1":
|
||||
%if page == '1':
|
||||
disabled\\
|
||||
%end
|
||||
backward icon"></i>
|
||||
|
@ -153,16 +153,23 @@
|
|||
|
||||
|
||||
<script>
|
||||
$('a').click(function(){
|
||||
if (sessionStorage.scrolly) {
|
||||
$(window).scrollTop(sessionStorage.scrolly);
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
$('a, i').click(function(){
|
||||
sessionStorage.scrolly=$(window).scrollTop();
|
||||
|
||||
$('#loader').addClass('active');
|
||||
})
|
||||
|
||||
$('.fast.backward').click(function(){
|
||||
location.href="?page=1";
|
||||
})
|
||||
$('.backward').click(function(){
|
||||
location.href="?page={{int(page)-1}}";
|
||||
})
|
||||
$('.fast.backward').click(function(){
|
||||
location.href="?page=1";
|
||||
})
|
||||
$('.forward').click(function(){
|
||||
location.href="?page={{int(page)+1}}";
|
||||
})
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
<div class="ui basic buttons">
|
||||
<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="add_new_episodes" class="ui button"><i class="wait icon"></i>Add New Episodes</button>
|
||||
</div>
|
||||
|
||||
<table id="tableseries" class="ui very basic selectable sortable table">
|
||||
|
@ -97,7 +98,7 @@
|
|||
%import ast
|
||||
%import os
|
||||
%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>
|
||||
{{row[2]}}
|
||||
|
@ -120,7 +121,7 @@
|
|||
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>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -131,6 +132,7 @@
|
|||
</div>
|
||||
|
||||
<div class="ui small modal">
|
||||
<i class="close icon"></i>
|
||||
<div class="header">
|
||||
<div id="series_title"></div>
|
||||
</div>
|
||||
|
@ -188,7 +190,7 @@
|
|||
|
||||
$('table').tablesort();
|
||||
|
||||
$('a, button').click(function(){
|
||||
$('a, button:not(.cancel)').click(function(){
|
||||
$('#loader').addClass('active');
|
||||
})
|
||||
|
||||
|
@ -206,6 +208,10 @@
|
|||
window.location = '/update_all_episodes';
|
||||
})
|
||||
|
||||
$('#add_new_episodes').click(function(){
|
||||
window.location = '/add_new_episodes';
|
||||
})
|
||||
|
||||
$('.config').click(function(){
|
||||
sessionStorage.scrolly=$(window).scrollTop();
|
||||
|
||||
|
|
|
@ -124,6 +124,22 @@
|
|||
</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>
|
||||
|
||||
|
@ -131,7 +147,11 @@
|
|||
<div class="twelve wide column">
|
||||
<div class="ui grid">
|
||||
%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):
|
||||
% path = []
|
||||
% try:
|
||||
|
@ -165,6 +185,9 @@
|
|||
<div class="ui container"><button class="ui blue right floated button">Save</button></div>
|
||||
<br>
|
||||
<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="ui grid">
|
||||
<div class="middle aligned row">
|
||||
|
@ -230,6 +253,9 @@
|
|||
<br>
|
||||
<div class="ui dividing header">Subtitles providers</div>
|
||||
<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="middle aligned row">
|
||||
<div class="right aligned four wide column">
|
||||
|
@ -294,11 +320,14 @@
|
|||
$("#sonarr_ssl_div").checkbox('uncheck');
|
||||
}
|
||||
|
||||
$('#settings_loglevel').dropdown('clear');
|
||||
$('#settings_loglevel').dropdown('set selected','{{!settings_general[4]}}');
|
||||
$('#settings_providers').dropdown('clear');
|
||||
$('#settings_providers').dropdown('set selected',{{!enabled_providers}});
|
||||
$('#settings_languages').dropdown('clear');
|
||||
$('#settings_languages').dropdown('set selected',{{!enabled_languages}});
|
||||
|
||||
$('#settings_loglevel').dropdown();
|
||||
$('#settings_providers').dropdown();
|
||||
$('#settings_languages').dropdown();
|
||||
</script>
|
|
@ -34,6 +34,7 @@
|
|||
border-radius: 0px;
|
||||
box-shadow: 0px 0px 5px 5px #ffffff;
|
||||
margin-top: 32px;
|
||||
margin-bottom: 3em;
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
|
@ -80,21 +81,85 @@
|
|||
Tasks
|
||||
</div>
|
||||
<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 class="ui bottom attached tab segment" data-tab="about">
|
||||
About
|
||||
</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>
|
||||
</html>
|
||||
|
||||
|
||||
<script>
|
||||
$('.modal')
|
||||
.modal({
|
||||
autofocus: false
|
||||
})
|
||||
;
|
||||
|
||||
$('.menu .item')
|
||||
.tab()
|
||||
;
|
||||
|
||||
$('.log').click(function(){
|
||||
$("#message").html($(this).data("message"));
|
||||
$("#exception").html($(this).data("exception"));
|
||||
$('.small.modal').modal('show');
|
||||
})
|
||||
|
||||
$('a.menu').click(function(){
|
||||
$('#loader').addClass('active');
|
||||
})
|
||||
|
|
|
@ -35,7 +35,10 @@
|
|||
box-shadow: 0px 0px 5px 5px #ffffff;
|
||||
margin-top: 32px;
|
||||
margin-bottom: 3em;
|
||||
padding: 3em;
|
||||
padding: 2em 3em 2em 3em;
|
||||
}
|
||||
#tablehistory {
|
||||
padding-top: 2em;
|
||||
}
|
||||
.fast.backward, .backward, .forward, .fast.forward {
|
||||
cursor: pointer;
|
||||
|
@ -77,6 +80,9 @@
|
|||
</div>
|
||||
|
||||
<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">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -101,7 +107,7 @@
|
|||
%missing_languages = ast.literal_eval(row[3])
|
||||
%if missing_languages is not None:
|
||||
%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}}
|
||||
<i style="margin-left:3px; margin-right:0px" class="search icon"></i>
|
||||
</a>
|
||||
|
@ -147,7 +153,7 @@
|
|||
|
||||
|
||||
<script>
|
||||
$('a').click(function(){
|
||||
$('a, button').click(function(){
|
||||
$('#loader').addClass('active');
|
||||
})
|
||||
|
||||
|
@ -163,4 +169,29 @@
|
|||
$('.fast.forward').click(function(){
|
||||
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>
|
Loading…
Reference in a new issue