mirror of
https://github.com/bbilly1/media_organizer.git
synced 2024-08-02 16:53:34 +00:00
263 lines
9.3 KiB
Python
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)
|