From 9b70ba0eb9ea4130895660fbcd4605bb4c3a8659 Mon Sep 17 00:00:00 2001 From: Todd Courtnage Date: Wed, 14 Jan 2015 20:24:47 -0700 Subject: [PATCH 1/5] Fix for the check of the Inetref on TTVDB. Now it properly finds tv shows based on the inetref. --- myth2kodi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myth2kodi.py b/myth2kodi.py index 24d5845..96b9a1b 100644 --- a/myth2kodi.py +++ b/myth2kodi.py @@ -930,7 +930,7 @@ def read_recordings(): # branch on inetref type if args.show_status is False: result = False - generic_inetref = ('ttvdvb' not in inetref or 'tmdb' not in inetref) + generic_inetref = ('ttvdb' not in inetref and 'tmdb' not in inetref) if generic_inetref is True: log.warning('Inetref provided is neither TTVDB or TMDB... trying each to find a match...') From 4789a8bd301ddd202a5a4c19338f7d42f8d4fe50 Mon Sep 17 00:00:00 2001 From: Todd Courtnage Date: Wed, 14 Jan 2015 20:59:09 -0700 Subject: [PATCH 2/5] If some (but not all) of the art is missing, download what's available. --- myth2kodi.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/myth2kodi.py b/myth2kodi.py index 96b9a1b..02875a3 100644 --- a/myth2kodi.py +++ b/myth2kodi.py @@ -406,27 +406,29 @@ def new_series_from_ttvdb(title, title_safe, inetref, category, directory): fanart_text = series.find('fanart').text if poster_text is None: log.warning('Poster image info could not be retrieved') + else: + log.info('Downloading poster...') + poster_url = ttvdb_banners_url + series.find('poster').text + if not download_file(poster_url, os.path.join(directory, 'poster.jpg')): + return False + if banner_text is None: log.warning('Banner image info could not be retrieved') + else: + log.info('Downloading banner...') + banner_url = ttvdb_banners_url + series.find('banner').text + if not download_file(banner_url, os.path.join(directory, 'banner.jpg')): + return False + if fanart_text is None: log.warning('Fanart image info could not be retrieved') - if poster_text is None or banner_text is None or fanart_text is None: - return False - - poster_url = ttvdb_banners_url + series.find('poster').text - banner_url = ttvdb_banners_url + series.find('banner').text - fanart_url = ttvdb_banners_url + series.find('fanart').text - - log.info('Downloading poster...') - if not download_file(poster_url, os.path.join(directory, 'poster.jpg')): - return False - - log.info('Downloading banner...') - if not download_file(banner_url, os.path.join(directory, 'banner.jpg')): - return False + else: + log.info('Downloading fanart...') + fanart_url = ttvdb_banners_url + series.find('fanart').text + if not download_file(fanart_url, os.path.join(directory, 'fanart.jpg')): + return False - log.info('Downloading fanart...') - if not download_file(fanart_url, os.path.join(directory, 'fanart.jpg')): + if poster_text is None and banner_text is None and fanart_text is None: return False return True From b7b3bf9cb3bd2cdcace65af437ad4c2779a17dda Mon Sep 17 00:00:00 2001 From: Todd Courtnage Date: Sat, 24 Jan 2015 17:30:22 -0700 Subject: [PATCH 3/5] Allow either hardlink or symlinks. --- config.py | 5 ++++- myth2kodi.py | 43 +++++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/config.py b/config.py index f4aa1b7..2028470 100644 --- a/config.py +++ b/config.py @@ -7,8 +7,11 @@ # A list of MythTV recording directories, full paths in quotes, separated by commas mythtv_recording_dirs = ["/pool/mythtv/recordings-kids/"] +# Can be "symlink", "hardlink" +target_type = "hardlink" + # Path to write symlinks -symlinks_dir = "/pool/myth2kodi/recordings/" +destination_dir = "/pool/myth2kodi/recordings/" # API key for TheTVDB ttvdb_key = "" diff --git a/myth2kodi.py b/myth2kodi.py index 02875a3..e1d0b53 100644 --- a/myth2kodi.py +++ b/myth2kodi.py @@ -9,7 +9,7 @@ Description: A script for generating a library of MythTV show recordings for Kodi(XBMC). The key feature of this script is that "Specials" (episodes with the same series title, but missing show and episode info) are grouped together under the - **same series** for easy navigation in Kodi. To generate the library, recordings are symlinked, and metadata and + **same series** for easy navigation in Kodi. To generate the library, recordings are linked, and metadata and image links (posters, fanart, and banners) for each series are pulled from either TheTVDB or TheMovieDB depending on the "inetref" value in MythTV. Commercial detection is done with comskip. --------------------------- @@ -61,15 +61,15 @@ parser.add_argument('--add-all', dest='add_all', action='store_true', default=False, help='Add all MythTV recordings that are missing.') parser.add_argument('--show-status', dest='show_status', action='store_true', default=False, - help='Print the output status showing total and new series, episodes, and specials. This will not write any new symlinks or files.') + help='Print the output status showing total and new series, episodes, and specials. This will not write any new links or files.') parser.add_argument('--comskip', dest='comskip', action='store', metavar='', help="Full path to file name of MythTV recording, used to comskip just a single recording.") parser.add_argument('--comskip-all', dest='comskip_all', action='store_true', default=False, - help='Run comskip on all video files found recursively in the "symlinks_dir" path from config.py.') + help='Run comskip on all video files found recursively in the "destination_dir" path from config.py.') parser.add_argument('--comskip-off', dest='comskip_off', action='store_true', default=False, help='Turn off comskip when adding a single recording with --add.') parser.add_argument('--comskip-status', dest='comskip_status', action='store_true', default=False, - help='Report sym-linked recordings with missing comskip files.') + help='Report linked recordings with missing comskip files.') parser.add_argument('--add-match-title', dest='add_match_title', action='store', metavar='', help='Process only recordings with titles that contain the given query.') parser.add_argument('--add-match-programid', dest='add_match_programid', action='store', metavar='<programid match', @@ -91,7 +91,7 @@ parser.add_argument('--refresh-nfos', dest='refresh_nfos', action='store_true', default=False, help='Refresh nfo files. Can be combined with --add to refresh specific nfo file.') parser.add_argument('--clean', dest='clean', action='store_true', default=False, - help='Perform cleanup operations on symlink directory.') + help='Perform cleanup operations on destination directory.') # TODO: handle arguments refresh nfos # TODO: clean up symlinks, nfo files, and directories when MythTV recordings are deleted @@ -559,7 +559,7 @@ def print_config(): print ' hostname: ' + unicode(config.hostname) print ' host_port: ' + unicode(config.host_port) print ' myth_recording_dirs: ' + unicode(config.mythtv_recording_dirs) - print ' symlinks_dir: ' + unicode(config.symlinks_dir) + print ' destination_dir: ' + unicode(config.destination_dir) print ' ttvdb_key: ' + unicode(config.ttvdb_key) print ' ttvdb_zips_dir: ' + unicode(config.ttvdb_zips_dir) print ' tmdb_key: ' + unicode(config.tmdb_key) @@ -644,7 +644,7 @@ def comskip_all(): print('No missing comskip files were found.') else: log.info('Running comskip on ' + str(count) + ' recordings with missing comskip files...') - for root, dirs, files in os.walk(config.symlinks_dir): + for root, dirs, files in os.walk(config.destination_dir): # print root # path = root.split('/') # print path @@ -658,7 +658,7 @@ def comskip_all(): def comskip_status(return_missing_count=False): comskip_missing_lib = [] - for root, dirs, files in os.walk(config.symlinks_dir): + for root, dirs, files in os.walk(config.destination_dir): # print root # path = root.split('/') # print path @@ -697,10 +697,10 @@ def clean(): cleaned_file_exists = os.path.exists(cleaned_file) if args.clean is True or not cleaned_file_exists: if args.clean is True: - log.info('Cleaning symlink directory per argument --clean') + log.info('Cleaning destination directory per argument --clean') else: - log.info('cleaned file was not found, will now perform a cleaning operation on the symlink directory...') - for root, dirs, files in os.walk(config.symlinks_dir): + log.info('cleaned file was not found, will now perform a cleaning operation on the destination directory...') + for root, dirs, files in os.walk(config.destination_dir): for file in files: # print os.path.join(root, file) result = re.sub(r'(.*) - [\d]{4}-[\d]{2}-[\d]{2}(.*)', r'\1\2', file) @@ -729,7 +729,7 @@ def read_recordings(): image_error_list = [] updated_nfos_lib = [] - # make sure all files in the symlink directory are in the right format + # make sure all files in the destination directory are in the right format clean() recording_list = get_recording_list() @@ -871,7 +871,7 @@ def read_recordings(): episode_count += 1 # set target link dir - target_link_dir = os.path.join(config.symlinks_dir, title_safe) + target_link_dir = os.path.join(config.destination_dir, title_safe) link_file = os.path.join(target_link_dir, episode_name) + file_extension # print 'LINK FILE = ' + link_file @@ -889,8 +889,8 @@ def read_recordings(): # skip if link already exists (unless we're updating nfo files) if os.path.exists(link_file) or os.path.islink(link_file): if args.show_status is False and args.refresh_nfos is False: - print 'Symlink already exists: ' + link_file - log.info('Symlink already exists: ' + link_file) + print 'Link already exists: ' + link_file + log.info('Link already exists: ' + link_file) if args.add is not None and args.refresh_nfos is False: continue @@ -906,8 +906,8 @@ def read_recordings(): if source_dir is None: # could not find file! - # print ("Cannot create symlink for " + episode_name + ", no valid source directory. Skipping.") - log.error('Cannot create symlink for ' + episode_name + ', no valid source directory. Skipping.') + # print ("Cannot create link for " + episode_name + ", no valid source directory. Skipping.") + log.error('Cannot create link for ' + episode_name + ', no valid source directory. Skipping.') continue # this is a new recording (or we're just refreshing nfo files), so check if we're just checking the status for now @@ -961,12 +961,15 @@ def read_recordings(): log.warning('Link file is: ' + link_file) # continue - # create symlink + # create link # print "Linking " + source_file + " ==> " + link_file if args.show_status is False and args.import_recording_list is None and args.refresh_nfos is False: if not os.path.exists(link_file) or not os.path.islink(link_file): log.info('Linking ' + source_file + ' ==> ' + link_file) - os.symlink(source_file, link_file) + if config.target_type == "symlink": + os.symlink(source_file, link_file) + elif config.target_type == "hardlink": + os.link(source_file, link_file) # write the episode nfo if args.show_status is False or args.refresh_nfos is True: @@ -1022,7 +1025,7 @@ def read_recordings(): if args.show_status is True: if len(series_new_lib) > 0 or len(episode_new_lib) > 0 or len(special_new_lib) > 0: print '' - print ' THESE SYMLINKS ARE NOT YET CREATED:' + print ' THESE LINKS ARE NOT YET CREATED:' print ' ----------------------------------' if len(series_new_lib) > 0: print ' New Series:' From a8ca8cead43f15e30565ff7b0950ff78acc60a7c Mon Sep 17 00:00:00 2001 From: Todd Courtnage <todd@courtnage.ca> Date: Sun, 25 Jan 2015 09:49:18 -0700 Subject: [PATCH 4/5] Not sure, git diff doesn't show anything different. --- myth2kodi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myth2kodi.py b/myth2kodi.py index e1d0b53..0aee8f2 100644 --- a/myth2kodi.py +++ b/myth2kodi.py @@ -18,6 +18,7 @@ import httplib import os +import shutil import xml.etree.cElementTree as ET from lxml import etree as ET2 import xml.dom.minidom as dom @@ -719,7 +720,6 @@ def read_recordings(): """ global log - print '' series_lib = [] series_new_lib = [] episode_count = 0 From ea03cda28a67389520772e56fa520b8ef8f75852 Mon Sep 17 00:00:00 2001 From: Todd Courtnage <todd@courtnage.ca> Date: Sun, 25 Jan 2015 10:32:14 -0700 Subject: [PATCH 5/5] Make symlink the default, for backwards compatibility. --- config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.py b/config.py index 2028470..c7e6725 100644 --- a/config.py +++ b/config.py @@ -8,7 +8,7 @@ mythtv_recording_dirs = ["/pool/mythtv/recordings-kids/"] # Can be "symlink", "hardlink" -target_type = "hardlink" +target_type = "symlink" # Path to write symlinks destination_dir = "/pool/myth2kodi/recordings/"