174 lines
6.6 KiB
Python
174 lines
6.6 KiB
Python
""" download trailers found in emby with youtube-dl """
|
|
|
|
import os
|
|
import re
|
|
|
|
from time import sleep
|
|
|
|
import requests
|
|
import yt_dlp as youtube_dl
|
|
|
|
from src.config import get_config
|
|
|
|
|
|
class TrailerHandler:
|
|
""" holds the trailers """
|
|
|
|
CONFIG = get_config()
|
|
|
|
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 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
|
|
|
|
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', encoding='utf-8') 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(self):
|
|
# pylint: disable=broad-except
|
|
""" 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', encoding='utf-8') as f:
|
|
f.write(f'{youtube_id} {movie_name}\n')
|
|
break
|
|
sleep((i + 1) ** 2)
|
|
continue
|
|
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.mkv)$'
|
|
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 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:
|
|
downloaded = False
|
|
print('no missing trailers found')
|
|
sleep(2)
|
|
return
|
|
if downloaded:
|
|
new_trailers = handler.archive()
|
|
print(f'downloaded {len(new_trailers)} new trailers')
|
|
sleep(2)
|