media_organizer/src/moviesort.py

263 lines
9.3 KiB
Python

""" sort and rename downloaded movies """
import logging
import os
import re
import requests
import subprocess
from time import sleep
def get_pending(movie_downpath):
"""
return how many movies are pending
return 0 when nothing to do
"""
pending = len(os.listdir(movie_downpath))
return pending
def move_to_sort(movie_downpath, sortpath, ext):
""" moves movies to sortpath """
for dirpath, _, filenames in os.walk(movie_downpath):
for filename in filenames:
path = os.path.join(dirpath, filename)
_, extenstion = os.path.splitext(path)
f_size = os.stat(path).st_size
if extenstion.lower() in ext and 'sample' not in filename and f_size > 50000000:
move_to = os.path.join(sortpath, filename)
os.rename(path, move_to)
pending = os.listdir(sortpath)
return pending
def split_filename(filename):
""" split the filename into moviename, year, file_ext """
print(filename)
file_ext = os.path.splitext(filename)[1]
year_id_pattern = re.compile(r'\d{4}')
year_list = year_id_pattern.findall(filename)
# remove clear false
for year in year_list:
if year == '1080':
# there were no movies back in 1080
year_list.remove(year)
file_split = filename.split(year)
if len(file_split[0]) == 0:
year_list.remove(year)
if len(year_list) != 1:
print('year extraction failed for: ' + filename)
year = input('whats the year?\n')
else:
year = year_list[0]
moviename = filename.split(year)[0].rstrip('.')
return moviename, year, file_ext
def get_results(movie_db_api, moviename, year = None):
""" return results from api call """
moviename_encoded = moviename.lower().replace("its", "")\
.replace(" ", "%20").replace(".", "%20").replace("'", "%20")
# call api with year passed or not
if year:
request = requests.get('https://api.themoviedb.org/3/search/movie?api_key=' +
movie_db_api + '&query=' + moviename_encoded + '&year=' +
year + '&language=en-US&include_adult=false').json()
else:
request = requests.get('https://api.themoviedb.org/3/search/movie?api_key=' +
movie_db_api + '&query=' + moviename_encoded +
'&language=en-US&include_adult=false').json()
try:
results = len(request['results'])
except KeyError:
results = 0
if results == 0:
# try again without last word of string
moviename_encoded = '%20'.join(moviename_encoded.split('%20')[0:-1])
request = requests.get('https://api.themoviedb.org/3/search/movie?api_key=' +
movie_db_api + '&query=' + moviename_encoded + '&year=' +
year + '&language=en-US&include_adult=false').json()
results = len(request['results'])
# return
return results, request
def search_for(movie_db_api, moviename, filename, year = None):
"""
takes the moviename and year from the filename
and returns clean name and year
"""
# get results from API
results, request = get_results(movie_db_api, moviename, year)
# clear when only one result
if results == 1:
selection = 0
# select for more than 0 result
elif results > 0:
short_list = []
long_list = []
counter = 0
for item in request['results']:
movie_title = item['title']
movie_date = item['release_date']
movie_year = movie_date.split('-')[0]
movie_desc = item['overview']
short_list_str = f'[{str(counter)}] {movie_title} - {movie_year}'
long_list_str = f'{short_list}\n{movie_desc}'
short_list.append(short_list_str)
long_list.append(long_list_str)
counter = counter + 1
short_list.append('[?] show more')
# print short menu
print('\nfilename: ' + filename)
for line in short_list:
print(line)
selection = input('select input: ')
# print long menu
if selection == '?':
for line in long_list:
print(line)
selection = input('select input: ')
# no result, try again
else:
return None, None
# get and return title and year
movie_title = request['results'][int(selection)]['title']
movie_year = request['results'][int(selection)]['release_date'].split('-')[0]
return movie_title, movie_year
def movie_rename(sortpath, movie_db_api):
""" renames the movie file """
to_rename = os.listdir(sortpath)
# os.chdir(sortpath)
for filename in to_rename:
# split up
moviename, year, file_ext = split_filename(filename)
# try to figure things out
while True:
# first try
movie_title, movie_year = search_for(movie_db_api, moviename, filename, year, )
if movie_title and movie_year:
break
# second try with - 1 year
movie_title, movie_year = search_for(movie_db_api, moviename, filename, str(int(year) - 1), )
if movie_title and movie_year:
break
# third try with + 1 year
movie_title, movie_year = search_for(movie_db_api, moviename, filename, str(int(year) + 1), )
if movie_title and movie_year:
break
# last try without year
movie_title, movie_year = search_for(movie_db_api, moviename, filename)
if movie_title and movie_year:
break
# manual overwrite
print(filename + '\nNo result found, search again with:')
moviename = input('movie name: ')
year = input('year: ')
movie_title, movie_year = search_for(moviename, year, filename)
break
if not movie_title or not movie_year:
# last check
return False
else:
# clean invalid chars
movie_title = movie_title.replace('/', '-')
# do it
rename_to = movie_title + ' (' + movie_year + ')' + file_ext
old_file = os.path.join(sortpath, filename)
new_file = os.path.join(sortpath, rename_to)
os.rename(old_file, new_file)
logging.info('movie:from [{}] to [{}]'.format(filename,rename_to))
return True
def move_to_archive(sortpath, moviepath):
""" moves renamed movie to archive,
returns list for further processing """
new_movies = []
to_move = os.listdir(sortpath)
if to_move:
print()
for i in to_move:
print(i)
_ = input('\ncontinue?')
to_move = os.listdir(sortpath)
for movie in to_move:
movie_name = os.path.splitext(movie)[0]
year_pattern = re.compile(r'(\()([0-9]{4})(\))')
year = year_pattern.findall(movie_name)[0][1]
old_file = os.path.join(sortpath, movie)
new_folder = os.path.join(moviepath, year, movie_name)
new_file = os.path.join(new_folder, movie)
try:
os.makedirs(new_folder)
except FileExistsError:
print(f'{movie_name}\nalready exists in archive')
double = input('[o]: overwrite, [s]: skip and ignore\n')
if double == 'o':
import subprocess
subprocess.call(["trash", new_folder])
os.makedirs(new_folder)
elif double == 's':
continue
else:
pass
finally:
pass
os.rename(old_file, new_file)
new_movies.append(movie_name)
return new_movies
# clean up
def cleanup(movie_downpath, sortpath, renamed):
""" cleans up the movie_downpath folder """
if renamed:
# renamed without errors
to_clean_list = os.listdir(movie_downpath)
for to_clean in to_clean_list:
to_trash = os.path.join(movie_downpath, to_clean)
subprocess.call(["trash", to_trash])
to_clean_list = os.listdir(sortpath)
for to_clean in to_clean_list:
to_trash = os.path.join(sortpath, to_clean)
subprocess.call(["trash", to_trash])
else:
# failed to rename
move_back = os.listdir(sortpath)
for movie in move_back:
old_path = os.path.join(sortpath, movie)
new_path = os.path.join(movie_downpath, movie)
os.rename(old_path, new_path)
def main(config):
""" main to sort movies """
# read config
movie_downpath = config['movie_downpath']
sortpath = config['sortpath']
moviepath = config['moviepath']
ext = config['ext']
movie_db_api = config['movie_db_api']
# check if pending
pending = get_pending(movie_downpath)
if not pending:
print('no movies to sort')
sleep(2)
return
# move to sort folder
pending = move_to_sort(movie_downpath, sortpath, ext)
if not pending:
print('no movies to sort')
sleep(2)
return
movie_renamed = movie_rename(sortpath, movie_db_api)
if movie_renamed:
renamed = move_to_archive(sortpath, moviepath)
# clean folders
cleanup(movie_downpath, sortpath, renamed)