merging json config file changes to master
This commit is contained in:
commit
0a8d5ceba3
|
@ -2,7 +2,7 @@
|
|||
__pycache__
|
||||
|
||||
# local configuration
|
||||
config
|
||||
config.json
|
||||
|
||||
# local testing
|
||||
deploy.sh
|
||||
|
|
13
README.md
13
README.md
|
@ -52,21 +52,22 @@ These are the none standard Python libraries in use in this project:
|
|||
Or use `pip` to install all the requirements:
|
||||
`pip install -r requirements.txt`
|
||||
|
||||
### config file:
|
||||
Duplicate the config.sample file to a file named *config* and set the following variables:
|
||||
### config json file:
|
||||
Duplicate the config.sample.json file to a file named *config.json* and set the following variables:
|
||||
#### media
|
||||
* `tv_downpath`: Folder path where the tv episodes get downloaded to.
|
||||
* `movie_downpath`: Folder path where the movie files get downloaded to.
|
||||
* `sortpath`: Empty folder the media_organizer can use as a temporary sort path.
|
||||
* `moviepath`: Root folder where the organized movie files will go.
|
||||
* `tvpath`: Root folder where the organized tv episodes will go.
|
||||
* `ext`: A space separated list of valid media file extensions to easily filter out none media related files.
|
||||
* `ext`: A list of valid media file extensions to easily filter out none media related files.
|
||||
* `log_path`: Path to a folder to output all renaming done to keep track and check for any errors and safe csv files.
|
||||
* `movie_db_api`: Register and get your themoviedb.com **API Key (v3 auth)** acces from [here](https://www.themoviedb.org/settings/api).
|
||||
|
||||
*Emby integration:*
|
||||
#### Emby integration
|
||||
* `emby_url`: url where your emby API is reachable
|
||||
* `emby_user_id`: user id of your emby user
|
||||
* `emby_api_key`: api key for your user on emby
|
||||
|
||||
*Trailer download:*
|
||||
Arguments under the [ydl_opts] section will get passed in to youtube-dl. Check out the documentation for details.
|
||||
#### ydl_opts *Trailer download:*
|
||||
Arguments under the [ydl_opts] section will get passed in to youtube-dl for *trailers*. Check out the documentation for details.
|
|
@ -1,20 +0,0 @@
|
|||
[media]
|
||||
tv_downpath = /media/movie/download/tv
|
||||
movie_downpath = /media/movie/download/movie
|
||||
sortpath = /media/movie/movie/temp
|
||||
moviepath = /media/movie/movie-archive
|
||||
tvpath = /media/movie/tv
|
||||
ext = mp4 mkv avi m4v
|
||||
log_folder = /home/user/logs/media_organize
|
||||
movie_db_api = aaaabbbbccccdddd1111222233333444
|
||||
|
||||
[emby]
|
||||
emby_url = http://media.local:8096/emby
|
||||
emby_user_id = aaaa1111bbbb2222cccc3333dddd4444
|
||||
emby_api_key = eeee5555ffff6666gggg7777hhhh8888
|
||||
|
||||
[ydl_opts]
|
||||
format = bestvideo[height<=1080]+bestaudio/best[height<=1080]
|
||||
merge_output_format = mkv
|
||||
external_downloader = aria2c
|
||||
geo_bypass = True
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"media": {
|
||||
"tv_downpath": "/media/movie/download/tv",
|
||||
"movie_downpath": "/media/movie/download/movie",
|
||||
"sortpath": "/media/movie/movie/temp",
|
||||
"moviepath": "/media/movie/movie/movie-archive",
|
||||
"tvpath": "/media/movie/movie/tv",
|
||||
"ext": ["mp4", "mkv", "avi", "m4v"],
|
||||
"log_folder": "/home/user/logs/media_organize",
|
||||
"movie_db_api": "aaaabbbbccccdddd1111222233333444"
|
||||
},
|
||||
"emby": {
|
||||
"emby_url": "http://media.local:8096/emby",
|
||||
"emby_user_id": "aaaa1111bbbb2222cccc3333dddd4444",
|
||||
"emby_api_key": "eeee5555ffff6666gggg7777hhhh8888"
|
||||
},
|
||||
"ydl_opts": {
|
||||
"format": "bestvideo[height<=1080]+bestaudio/best[height<=1080]",
|
||||
"merge_output_format": "mkv",
|
||||
"external_downloader": "aria2c",
|
||||
"geo_bypass": true
|
||||
}
|
||||
}
|
52
interface.py
52
interface.py
|
@ -2,7 +2,7 @@
|
|||
""" curses interface to lunch moviesort and tvsort """
|
||||
|
||||
import curses
|
||||
import configparser
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from os import path
|
||||
|
@ -22,45 +22,23 @@ def get_config():
|
|||
root_folder = path.dirname(sys.argv[0])
|
||||
if root_folder == '/sbin':
|
||||
# running interactive
|
||||
config_path = 'config'
|
||||
config_path = 'config.json'
|
||||
else:
|
||||
config_path = path.join(root_folder, 'config')
|
||||
config_path = path.join(root_folder, 'config.json')
|
||||
# parse
|
||||
config_parser = configparser.ConfigParser()
|
||||
config_parser.read(config_path)
|
||||
# build dict
|
||||
config = {}
|
||||
config["tv_downpath"] = config_parser.get('media', 'tv_downpath')
|
||||
config["movie_downpath"] = config_parser.get('media', 'movie_downpath')
|
||||
config["sortpath"] = config_parser.get('media', 'sortpath')
|
||||
config["moviepath"] = config_parser.get('media', 'moviepath')
|
||||
config["tvpath"] = config_parser.get('media', 'tvpath')
|
||||
config["log_folder"] = config_parser.get('media', 'log_folder')
|
||||
config["movie_db_api"] = config_parser.get('media', 'movie_db_api')
|
||||
# ext
|
||||
ext_str = config_parser.get('media', 'ext')
|
||||
config["ext"] = ['.' + i for i in ext_str.split()]
|
||||
# emby
|
||||
config["emby_url"] = config_parser.get('emby', 'emby_url')
|
||||
config["emby_user_id"] = config_parser.get('emby', 'emby_user_id')
|
||||
config["emby_api_key"] = config_parser.get('emby', 'emby_api_key')
|
||||
# youtubedl_ops
|
||||
ydl_opts = dict(config_parser.items('ydl_opts'))
|
||||
# dedect string literals, is there a better way to do that?
|
||||
for key, value in ydl_opts.items():
|
||||
if value.isdigit():
|
||||
ydl_opts[key] = int(value)
|
||||
elif value.lower() in ['true', 'false']:
|
||||
ydl_opts[key] = bool(value)
|
||||
config['ydl_opts'] = ydl_opts
|
||||
with open(config_path, 'r') as config_file:
|
||||
data = config_file.read()
|
||||
config = json.loads(data)
|
||||
return config
|
||||
|
||||
|
||||
def get_pending_all(config):
|
||||
""" figure out what needs to be done """
|
||||
movie_downpath = config['media']['movie_downpath']
|
||||
tv_downpath = config['media']['tv_downpath']
|
||||
# call subfunction to collect pending
|
||||
pending_movie = moviesort.get_pending(config['movie_downpath'])
|
||||
pending_tv = tvsort.get_pending(config['tv_downpath'])
|
||||
pending_movie = moviesort.get_pending(movie_downpath)
|
||||
pending_tv = tvsort.get_pending(tv_downpath)
|
||||
pending_trailer = len(trailers.get_pending(config))
|
||||
pending_movie_fix = len(id_fix.get_pending(config))
|
||||
pending_total = pending_movie + pending_tv + pending_trailer + pending_movie_fix
|
||||
|
@ -74,9 +52,8 @@ def get_pending_all(config):
|
|||
return pending
|
||||
|
||||
|
||||
def print_menu(stdscr, current_row_idx, menu, config, pending):
|
||||
def print_menu(stdscr, current_row_idx, menu, pending):
|
||||
""" print menu with populated pending count """
|
||||
|
||||
# build stdscr
|
||||
h, w = stdscr.getmaxyx()
|
||||
longest = len(max(menu))
|
||||
|
@ -137,7 +114,7 @@ def curses_main(stdscr, menu, config):
|
|||
curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_WHITE)
|
||||
current_row_idx = 0
|
||||
pending = get_pending_all(config)
|
||||
print_menu(stdscr, current_row_idx, menu, config, pending)
|
||||
print_menu(stdscr, current_row_idx, menu, pending)
|
||||
# endless loop
|
||||
while True:
|
||||
# wait for exit signal
|
||||
|
@ -157,7 +134,7 @@ def curses_main(stdscr, menu, config):
|
|||
# exit curses and do something
|
||||
return menu_item
|
||||
# print
|
||||
print_menu(stdscr, current_row_idx, menu, config, pending)
|
||||
print_menu(stdscr, current_row_idx, menu, pending)
|
||||
stdscr.refresh()
|
||||
except KeyboardInterrupt:
|
||||
# clean exit on ctrl + c
|
||||
|
@ -169,7 +146,8 @@ def main():
|
|||
# setup
|
||||
menu = ['All', 'Movies', 'TV shows', 'DB export', 'Trailer download', 'Fix Movie Names', 'Exit']
|
||||
config = get_config()
|
||||
log_file = path.join(config["log_folder"], 'rename.log')
|
||||
log_folder = config['media']['log_folder']
|
||||
log_file = path.join(log_folder, 'rename.log')
|
||||
logging.basicConfig(filename=log_file,level=logging.INFO,format='%(asctime)s:%(message)s')
|
||||
# endless loop
|
||||
while True:
|
||||
|
|
|
@ -7,9 +7,9 @@ import requests
|
|||
|
||||
def get_items(config):
|
||||
""" get json from emby """
|
||||
emby_url = config['emby_url']
|
||||
emby_user_id = config['emby_user_id']
|
||||
emby_api_key = config['emby_api_key']
|
||||
emby_url = config['emby']['emby_url']
|
||||
emby_user_id = config['emby']['emby_user_id']
|
||||
emby_api_key = config['emby']['emby_api_key']
|
||||
# movies
|
||||
url = (f'{emby_url}/Users/{emby_user_id}/Items?api_key={emby_api_key}' +
|
||||
'&Recursive=true&IncludeItemTypes=Movie' +
|
||||
|
@ -89,7 +89,7 @@ def parse_movies(all_movies):
|
|||
|
||||
def write_movie_files(movie_info_csv, movie_tech_csv, movie_seen, config):
|
||||
""" writes the csv files to disk """
|
||||
log_folder = config['log_folder']
|
||||
log_folder = config['media']['log_folder']
|
||||
|
||||
# movie info
|
||||
movie_info_sorted = sorted(movie_info_csv, key=lambda k: k['movie_name'])
|
||||
|
@ -196,7 +196,7 @@ def parse_episodes(all_episodes):
|
|||
|
||||
def write_episode_files(episode_info_csv, episode_tech_csv, episode_seen, config):
|
||||
""" writes the csv files to disk """
|
||||
log_folder = config['log_folder']
|
||||
log_folder = config['media']['log_folder']
|
||||
# episode info
|
||||
episode_info_sorted = sorted(episode_info_csv, key=lambda k: k['file_id'])
|
||||
for i in episode_info_sorted:
|
||||
|
|
|
@ -9,9 +9,9 @@ from time import sleep
|
|||
|
||||
def get_emby_list(config):
|
||||
""" get current emby movie list """
|
||||
emby_url = config['emby_url']
|
||||
emby_user_id = config['emby_user_id']
|
||||
emby_api_key = config['emby_api_key']
|
||||
emby_url = config['emby']['emby_url']
|
||||
emby_user_id = config['emby']['emby_user_id']
|
||||
emby_api_key = config['emby']['emby_api_key']
|
||||
|
||||
url = (emby_url + '/Users/' + emby_user_id + '/Items?api_key=' + emby_api_key +
|
||||
'&Recursive=True&IncludeItemTypes=Movie&Fields=Path,PremiereDate')
|
||||
|
@ -57,7 +57,7 @@ def compare_list(movie_list):
|
|||
def rename(config, errors_list):
|
||||
""" rename files with correct names """
|
||||
print(f'renaming {len(errors_list)} movies.')
|
||||
moviepath = config['moviepath']
|
||||
moviepath = config['media']['moviepath']
|
||||
skipped = []
|
||||
for movie in errors_list:
|
||||
old_year = movie[0]['year']
|
||||
|
|
|
@ -22,9 +22,11 @@ def move_to_sort(movie_downpath, sortpath, ext):
|
|||
for dirpath, _, filenames in os.walk(movie_downpath):
|
||||
for filename in filenames:
|
||||
path = os.path.join(dirpath, filename)
|
||||
_, extenstion = os.path.splitext(path)
|
||||
_, extension = os.path.splitext(path)
|
||||
extension = extension.lstrip('.').lower()
|
||||
f_size = os.stat(path).st_size
|
||||
if extenstion.lower() in ext and 'sample' not in filename and f_size > 50000000:
|
||||
# TODO: set f_size in config.json
|
||||
if extension 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)
|
||||
|
@ -197,7 +199,6 @@ def move_to_archive(sortpath, moviepath):
|
|||
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':
|
||||
|
@ -236,11 +237,11 @@ def cleanup(movie_downpath, sortpath, renamed):
|
|||
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']
|
||||
movie_downpath = config['media']['movie_downpath']
|
||||
sortpath = config['media']['sortpath']
|
||||
moviepath = config['media']['moviepath']
|
||||
ext = config['media']['ext']
|
||||
movie_db_api = config['media']['movie_db_api']
|
||||
# check if pending
|
||||
pending = get_pending(movie_downpath)
|
||||
if not pending:
|
||||
|
|
|
@ -11,7 +11,7 @@ from time import sleep
|
|||
|
||||
def incomplete(config):
|
||||
""" search for incomplete downloads and trash them """
|
||||
sortpath = config['sortpath']
|
||||
sortpath = config['media']['sortpath']
|
||||
file_list = os.listdir(sortpath)
|
||||
trashed = False
|
||||
for file_name in file_list:
|
||||
|
@ -28,8 +28,8 @@ def incomplete(config):
|
|||
|
||||
def get_local_trailers(config):
|
||||
""" gets a list of existing trailers on filesystem """
|
||||
emby_url = config['emby_url']
|
||||
emby_api_key = config['emby_api_key']
|
||||
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()
|
||||
|
@ -51,8 +51,8 @@ def get_local_trailers(config):
|
|||
|
||||
def get_remote_trailers(config):
|
||||
""" get a list of available trailers on emby """
|
||||
emby_url = config['emby_url']
|
||||
emby_api_key = config['emby_api_key']
|
||||
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&' +
|
||||
|
@ -73,8 +73,9 @@ def get_remote_trailers(config):
|
|||
|
||||
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(config['log_folder'], 'trailers')
|
||||
log_file = os.path.join(log_folder, 'trailers')
|
||||
# check if log file exists
|
||||
if not os.path.isfile(log_file):
|
||||
# create empty file
|
||||
|
@ -100,7 +101,8 @@ def compare_download(local_trailer_list, remote_trailers_list, config):
|
|||
|
||||
def dl_pending(pending, config):
|
||||
""" download pending trailers """
|
||||
sortpath = config['sortpath']
|
||||
sortpath = config['media']['sortpath']
|
||||
log_folder = config['media']['loc_folder']
|
||||
ydl_opts = config['ydl_opts']
|
||||
# loop thrugh list
|
||||
downloaded = []
|
||||
|
@ -119,7 +121,7 @@ def dl_pending(pending, config):
|
|||
except:
|
||||
if i == 4:
|
||||
# giving up
|
||||
log_file = os.path.join(config['log_folder'], 'trailers')
|
||||
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
|
||||
|
@ -134,8 +136,8 @@ def dl_pending(pending, config):
|
|||
|
||||
def archive(config):
|
||||
""" move downloaded trailers to movie archive """
|
||||
sortpath = config['sortpath']
|
||||
moviepath = config['moviepath']
|
||||
sortpath = config['media']['sortpath']
|
||||
moviepath = config['media']['moviepath']
|
||||
|
||||
new_trailers = os.listdir(sortpath)
|
||||
# loop through new trailers
|
||||
|
@ -176,6 +178,7 @@ def main(config):
|
|||
else:
|
||||
downloaded = False
|
||||
print('no missing trailers found')
|
||||
return
|
||||
# move to archive
|
||||
if downloaded:
|
||||
new_trailers = archive(config)
|
||||
|
|
|
@ -16,9 +16,10 @@ def move_to_sort(tv_downpath, sortpath, ext):
|
|||
for dirpath, _, filenames in os.walk(tv_downpath):
|
||||
for filename in filenames:
|
||||
path = os.path.join(dirpath, filename)
|
||||
_, extenstion = os.path.splitext(path)
|
||||
_, extension = os.path.splitext(path)
|
||||
extension = extension.lstrip('.').lower()
|
||||
f_size = os.stat(path).st_size
|
||||
if extenstion.lower() in ext and 'sample' not in filename and f_size > 50000000:
|
||||
if extension in ext and 'sample' not in filename and f_size > 50000000:
|
||||
move_to = os.path.join(sortpath, filename)
|
||||
os.rename(path, move_to)
|
||||
if os.listdir(sortpath):
|
||||
|
@ -61,17 +62,16 @@ def clean_up(sortpath, tv_downpath):
|
|||
def main(config, tvsort_id):
|
||||
""" main function to sort tv shows """
|
||||
# parse config
|
||||
tv_downpath = config['tv_downpath']
|
||||
tvpath = config['tvpath']
|
||||
sortpath = config['sortpath']
|
||||
ext = config['ext']
|
||||
tv_downpath = config['media']['tv_downpath']
|
||||
tvpath = config['media']['tvpath']
|
||||
sortpath = config['media']['sortpath']
|
||||
ext = config['media']['ext']
|
||||
# stop here if nothing to do
|
||||
pending = get_pending(tv_downpath)
|
||||
if not pending:
|
||||
print('no tv shows to sort')
|
||||
sleep(2)
|
||||
return
|
||||
|
||||
# move files
|
||||
to_sort = move_to_sort(tv_downpath, sortpath, ext)
|
||||
if to_sort:
|
||||
|
|
|
@ -222,7 +222,7 @@ def get_episode_name(file_details, show_id):
|
|||
|
||||
def episode_rename(config):
|
||||
""" loops through all files in sortpath """
|
||||
sortpath = config['sortpath']
|
||||
sortpath = config['media']['sortpath']
|
||||
# poor man's cache
|
||||
cache = {}
|
||||
cache['last_show_name'] = None
|
||||
|
|
Loading…
Reference in New Issue