rewrote trailers.py into dedicated TrailerHandler class

This commit is contained in:
simon 2021-05-16 15:27:23 +07:00
parent 77ee691cb7
commit 634b56ca07
2 changed files with 142 additions and 162 deletions

View File

@ -20,7 +20,7 @@ def get_pending_all(config):
# call subfunction to collect pending
pending_movie = moviesort.MovieHandler().pending
pending_tv = tvsort.TvHandler().pending
pending_trailer = len(trailers.get_pending(config))
pending_trailer = len(trailers.TrailerHandler().pending)
pending_movie_fix = len(id_fix.get_pending(config))
pending_total = pending_movie + pending_tv + pending_trailer + pending_movie_fix
# build dict
@ -75,7 +75,7 @@ def sel_handler(menu_item, config):
moviesort.main()
tvsort.main()
db_export.main(config)
trailers.main(config)
trailers.main()
id_fix.main(config)
elif menu_item == 'Movies':
moviesort.main()
@ -84,7 +84,7 @@ def sel_handler(menu_item, config):
elif menu_item == 'DB export':
db_export.main(config)
elif menu_item == 'Trailer download':
trailers.main(config)
trailers.main()
elif menu_item == 'Fix Movie Names':
id_fix.main(config)

View File

@ -2,184 +2,164 @@
import os
import re
import requests
import subprocess
import youtube_dl
from time import sleep
import requests
import youtube_dl
def incomplete(config):
""" search for incomplete downloads and trash them """
sortpath = config['media']['sortpath']
file_list = os.listdir(sortpath)
trashed = False
for file in file_list:
if file.endswith('.part') or file.endswith('.ytdl'):
trashed = True
file_path = os.path.join(sortpath, file)
os.path.isfile(file_path)
subprocess.call(['trash', file_path])
if not file_list and not trashed:
new_trailers = archive(config)
print(f'moved {len(new_trailers)} into archive')
return trashed
from src.config import get_config
def get_local_trailers(config):
""" gets a list of existing trailers on filesystem """
emby_url = config['emby']['emby_url']
emby_api_key = config['emby']['emby_api_key']
url = (emby_url + '/Trailers?api_key=' + emby_api_key +
'&Recursive=True&Fields=Path,MediaStreams')
r = requests.get(url).json()
local_trailer_list = []
for movie in r['Items']:
trailer_name = movie['Name']
trailing_pattern = re.compile(r'(.*_)([0-9a-zA-Z-_]{11})(-trailer)$')
youtube_id = trailing_pattern.findall(trailer_name)[0][1]
movie_name = movie['Path'].split('/')[-2]
media_streams = movie['MediaSources'][0]['MediaStreams']
video_stream = list(filter(lambda stream: stream['Type'] == 'Video', media_streams))
width = video_stream[0]['Width']
height = video_stream[0]['Height']
trailer_details = {'movie_name': movie_name, 'youtube_id': youtube_id,
'width': width, 'height': height}
local_trailer_list.append(trailer_details)
return local_trailer_list
class TrailerHandler():
""" holds the trailers """
CONFIG = get_config()
def get_remote_trailers(config):
""" get a list of available trailers on emby """
emby_url = config['emby']['emby_url']
emby_api_key = config['emby']['emby_api_key']
# remote trailer urls
url = (emby_url + '/Items?api_key=' + emby_api_key +
'&Recursive=True&Fields=LocalTrailerCount,RemoteTrailers,Path&' +
'IncludeItemTypes=Movie')
r = requests.get(url).json()
remote_trailers_list = []
for movie in r['Items']:
movie_name = movie['Path'].split('/')[-2]
movie_path = '/'.join(movie['Path'].split('/')[-3:-1])
local_trailer_count = movie['LocalTrailerCount']
remote_trailers = movie['RemoteTrailers']
trailer_details = {'movie_name': movie_name, 'movie_path': movie_path,
'local_trailer_count': local_trailer_count,
'remote_trailers': remote_trailers}
remote_trailers_list.append(trailer_details)
return remote_trailers_list
def __init__(self):
self.pending = self.get_pending()
def get_local_trailers(self):
""" gets a list of existing trailers on filesystem """
emby_url = self.CONFIG['emby']['emby_url']
emby_api_key = self.CONFIG['emby']['emby_api_key']
url = (emby_url + '/Trailers?api_key=' + emby_api_key
+ '&Recursive=True&Fields=Path')
request = requests.get(url).json()
local_trailer_list = []
for movie in request['Items']:
trailer_name = movie['Name']
trailing_reg = r'(.*_)([0-9a-zA-Z-_]{11})(-trailer)$'
trailing_pattern = re.compile(trailing_reg)
youtube_id = trailing_pattern.findall(trailer_name)[0][1]
movie_name = movie['Path'].split('/')[-2]
trailer_details = {'movie_name': movie_name,
'youtube_id': youtube_id}
local_trailer_list.append(trailer_details)
return local_trailer_list
def compare_download(local_trailer_list, remote_trailers_list, config):
""" figure out which trailers need downloading """
log_folder = config['media']['log_folder']
# failed before
log_file = os.path.join(log_folder, 'trailers')
# check if log file exists
if not os.path.isfile(log_file):
# create empty file
open(log_file, 'a').close()
failed_ids = []
else:
with open(log_file, 'r') as f:
lines = f.readlines()
failed_ids = [i.split()[0] for i in lines]
# ids already downloaded
local_ids = [i['youtube_id'] for i in local_trailer_list]
# find pending
pending = []
for movie in remote_trailers_list:
movie_name = movie['movie_name']
for trailer in movie['remote_trailers']:
vid_id = trailer['Url'].split('?v=')[1]
def get_remote_trailers(self):
""" get a list of available trailers on emby """
emby_url = self.CONFIG['emby']['emby_url']
emby_api_key = self.CONFIG['emby']['emby_api_key']
# remote trailer urls
url = (emby_url + '/Items?api_key=' + emby_api_key +
'&Recursive=True&Fields=RemoteTrailers,Path' +
'&IncludeItemTypes=Movie')
request = requests.get(url).json()
remote_trailers_list = []
for movie in request['Items']:
movie_name = movie['Path'].split('/')[-2]
remote_trailers = movie['RemoteTrailers']
for remote_trailer in remote_trailers:
url = remote_trailer['Url']
youtube_id = url.split('?v=')[1]
trailer_details = {'movie_name': movie_name,
'youtube_id': youtube_id}
remote_trailers_list.append(trailer_details)
return remote_trailers_list
if vid_id not in failed_ids and vid_id not in local_ids:
pending.append((vid_id, movie_name))
return pending
def get_ignore_trailers(self):
""" read log file to get list of trailers to ignore """
log_folder = self.CONFIG['media']['log_folder']
log_file = os.path.join(log_folder, 'trailers')
with open(log_file, 'r') as log_file:
trailer_lines = log_file.readlines()
ignore_trailer_list = []
for trailer_line in trailer_lines:
youtube_id = trailer_line.split()[0]
movie_name = trailer_line.lstrip(youtube_id).strip()
trailer_details = {'movie_name': movie_name,
'youtube_id': youtube_id}
ignore_trailer_list.append(trailer_details)
return ignore_trailer_list
def get_pending(self):
""" compare have and pending """
remote_trailers_list = self.get_remote_trailers()
local_trailer_list = self.get_local_trailers()
ignore_trailer_list = self.get_ignore_trailers()
# add local and ignore list together
have_trailers = ([i['youtube_id'] for i in local_trailer_list]
+ [i['youtube_id'] for i in ignore_trailer_list])
# add to pending if missing
pending = []
for remote_trailer in remote_trailers_list:
youtube_id = remote_trailer['youtube_id']
if youtube_id not in have_trailers:
pending.append(remote_trailer)
return pending
def dl_pending(pending, config):
""" download pending trailers """
sortpath = config['media']['sortpath']
log_folder = config['media']['log_folder']
ydl_opts = config['ydl_opts']
# loop thrugh list
downloaded = []
for trailer in pending:
to_down_id = trailer[0]
movie_name = trailer[1]
filename = os.path.join(sortpath, movie_name + '_' + to_down_id + '-trailer.mkv')
ydl_opts['outtmpl'] = filename
# try up to 5 times
for i in range(5):
try:
print(f'[{i}] {to_down_id} {movie_name}')
youtube_dl.YoutubeDL(ydl_opts).download(['https://www.youtube.com/watch?v=' + to_down_id])
except KeyboardInterrupt:
return False
except:
if i == 4:
# giving up
log_file = os.path.join(log_folder, 'trailers')
with open(log_file, 'a') as f:
f.write(f'{to_down_id} {movie_name}\n')
break
else:
def dl_pending(self):
""" download pending trailers """
sortpath = self.CONFIG['media']['sortpath']
log_folder = self.CONFIG['media']['log_folder']
ydl_opts = self.CONFIG['ydl_opts']
# loop thrugh list
trailers_downloaded = []
for trailer in self.pending:
youtube_id = trailer['youtube_id']
movie_name = trailer['movie_name']
filename = f'{movie_name}_{youtube_id}-trailer.mkv'
filepath = os.path.join(sortpath, filename)
ydl_opts['outtmpl'] = filepath
# try up to 5 times
for i in range(5):
try:
print(f'[{i}] {youtube_id} {movie_name}')
url = 'https://www.youtube.com/watch?v=' + youtube_id
youtube_dl.YoutubeDL(ydl_opts).download([url])
except KeyboardInterrupt:
return False
except Exception:
if i == 4:
# giving up
log_file = os.path.join(log_folder, 'trailers')
with open(log_file, 'a') as f:
f.write(f'{youtube_id} {movie_name}\n')
break
sleep((i + 1) ** 2)
continue
else:
downloaded.append(to_down_id)
break
return downloaded
else:
trailers_downloaded.append(trailer)
break
return trailers_downloaded
def archive(self):
""" move downloaded trailers to movie archive """
sortpath = self.CONFIG['media']['sortpath']
moviepath = self.CONFIG['media']['moviepath']
new_trailers = os.listdir(sortpath)
# loop through new trailers
for trailer in new_trailers:
# build path
year_pattern = re.compile(r'(\()([0-9]{4})(\))')
trailing_reg = r'(.*_)([0-9a-zA-Z-_]{11})(-trailer)$'
trailing_pattern = re.compile(trailing_reg)
movie_name = trailing_pattern.findall(trailer)[0][0]
year = year_pattern.findall(trailer)[0][1]
movie_folder = os.path.join(moviepath, year, movie_name)
# move if all good
if os.path.isdir(movie_folder):
old_file = os.path.join(sortpath, trailer)
new_file = os.path.join(movie_folder, trailer)
os.rename(old_file, new_file)
return new_trailers
def archive(config):
""" move downloaded trailers to movie archive """
sortpath = config['media']['sortpath']
moviepath = config['media']['moviepath']
new_trailers = os.listdir(sortpath)
# loop through new trailers
for trailer in new_trailers:
# build path
year_pattern = re.compile(r'(\()([0-9]{4})(\))')
trailing_pattern = re.compile(r'(.*)(_[0-9a-zA-Z-_]{11}-trailer\.mkv)$')
movie_name = trailing_pattern.findall(trailer)[0][0]
year = year_pattern.findall(trailer)[0][1]
movie_folder = os.path.join(moviepath, year, movie_name)
# move if all good
if os.path.isdir(movie_folder):
old_file = os.path.join(sortpath, trailer)
new_file = os.path.join(movie_folder, trailer)
os.rename(old_file, new_file)
return new_trailers
def get_pending(config):
""" get a list of pending trailers """
local_trailer_list = get_local_trailers(config)
remote_trailers_list = get_remote_trailers(config)
pending = compare_download(local_trailer_list, remote_trailers_list, config)
return pending
def main(config):
""" main function to download pending trailers """
# check for clean folder
trashed = incomplete(config)
# look for trailer
if not trashed:
pending = get_pending(config)
# download if needed
if pending:
print(f'downloading {len(pending)} trailers')
downloaded = dl_pending(pending, config)
def main():
""" check and download missing trailers """
handler = TrailerHandler()
if handler.pending:
print(f'downloading {len(handler.pending)} trailers')
sleep(2)
downloaded = handler.dl_pending()
else:
print('no missing trailers found')
sleep(2)
return
# move to archive
if downloaded:
new_trailers = archive(config)
new_trailers = handler.archive()
print(f'downloaded {len(new_trailers)} new trailers')
sleep(2)
sleep(2)