#!/usr/bin/python """ Update cache or -n (--noupdate) and search cache for rec_ids: surlatablo.py -q search_pattern Update cache with new recording and deletions surlatablo.py Search for recordings and convert them surlatablo.py -n -q search_pattern -c Use option --help for detailed usage. """ SLT_GLOBAL = {} # Note, maybe more should go into SLT_GLOBAL? SLT_GLOBAL['PGM_VERSION'] = '0.3' # Sur la Tablo (on the Tablo) SLT_GLOBAL['PGM_NAME'] = 'surlatablo' # License SLT_GLOBAL['PGM_LICENSE'] = 'GPLv2' ### PROGRAM LOCATIONS # Replace with full path location of your programs FFMPEG = '/usr/bin/ffmpeg' CCEXTRACTOR = '/usr/local/bin/ccextractor' ### IMPORTANT LOCAL SETTINGS SURLATABLO_ROOT = '/SurLaTablo' # Cache db goes here TABLO_IPS = ['192.168.1.73'] # Should we detect? # Use a python list of Tablo IPs. LOCAL_TIMEZONE = 'US/Central' # Your current timezone # DIRECTORY AND FILE CREATION PATTERNS # Patterns for output handling by meta_type (e.g. TV, Sports, Movie, Manual) # Patterns can contain meta information made by this program using # ${meta-name}. Just like TabloTV, this programs metadata is non-uniform # by media type (aka meta_type) # BASE_DIRS={'Default':'./${meta_type}', 'Sports':'./${meta_type}/${sport_type}/Season ${season_number}', 'TV':'./${meta_type}/${series}/Season ${season_number}', 'Movie':'./${meta_type}/${title} (${release_year})' } # Everything but the final extension of the final transcoded file. See FFMPEG_OPTS last element. FILENAME_PATS={'Default':'${title}', 'TV':'${series} - s${plex_season_number}e${plex_episode_number} - ${title}', 'Sports':'${sport_type} - s${plex_season_number}e${plex_episode_number} - ${title}', 'Movie':'${title} (${release_year})' } # CHANGELOG # #Sat Jan 17 14:24:17 CST 2015 # 0.3 - New metatype, sort_title, which is the title minus leading # a/an/the article. Added a sanitizeFilename function, mainly for # Windows. #Thu Jan 15 00:00:26 CST 2015 # 0.2 - Defined some timezone stuff for when there is no pytz. Doesn't handle # everything. Handle escapes like \n, \t in -Q. Check for ability to # create SURLATABLO_ROOT and exit with a message instead of fail with stack # trace. New meta-type, friendly_title, added to make it easier to use # friendly_title~='Series - s01' for easy season selection. ##### # Note, I plan to redo how command options and running, etc. are done. So # pretty much from here down I recommend you do not change... for now. ##### ### COMMAND OPTIONS (Note: to be redone) # Use semicolon for argument separation. Mainly because semicolon # is rarely used in commands. # # FFMPEG options # The last argument is the extension (and usually conversion identifier) that # will be on the ouput filename. The output filename is computed, but see # FILENAME_PATS below (which handles everything but the extension). # Note, I really do not like how I have chosen to handle this. Assume *_OPTS # will all change shortly. FFMPEG_OPTS={'Default':'${FFMPEG}${ts_itsoffset};-i;${tsfilename}${srtsubtitle};-bsf:a;aac_adtstoasc${wcrop}${srtmovtext};.mp4'} # CCEXTRACTOR options CCEXTRACTOR_OPTS={'Default':'${CCEXTRACTOR}'} ### OTHER MODIFIER (Note: to be redone) # CCOFFSET options # Results in setting an itsoffet (ts_itsoffset) parameter to ffmpeg on the # video stream (for adjusting subtitle/ccaption) Note: ffmpeg does not # allow itsoffset to work on subtitle streams which is why it's done of # the Tablo .ts file instead. CCOFFSET={'Default':'', 'Sports':'4' } # Enter cropping types for -W. Suppled default is for a 480i widescreen crop. # It is possible (rare) that a HD channel could present a 480p style # widescreen show, in which case you might define a crop appropriate for # that (e.g. -W 720p, etc.). # # Note, if -w suppied, then Default is used. -W allows you to override the # Default or choose a different value (if supplied) from the dictionary below. # # Note, specifying -w or -W results in a full transcode, which will be slower. WCROP_VALUES={'Default':'720:360:0:60'} # Tablo url templates TABLO_SEGS='http://${tablo_ip}:18080/pvr/${rec_id}/segs' TABLO_REC_IDS='http://${tablo_ip}:18080/plex/rec_ids' TABLO_CHAN_IDS='http://${tablo_ip}:18080/plex/ch_ids' TABLO_CHAN_INFO='http://${tablo_ip}:18080/plex/ch_info?id={}' TABLO_REC_INFO='http://${tablo_ip}:18080/plex/rec_info?id={}' # Some defaults (to be redone) options = { 'wcrop': ';-c:v;copy;-c:a;copy', 'debug': False, 'keepdir': '', 'noclobber' : True, 'ccaption' : False, 'ffmpegopts' : FFMPEG_OPTS['Default'], 'ccaptionopts' : CCEXTRACTOR_OPTS['Default'], 'srtsubtitle' : '', 'srtmovtext' : '', 'ccoffset' : '' } # Mapping of 2char lang to 3char lang. # Assumes that Gracenote/Tribune data even knows about all of these. lang3 = { 'ab': 'abk', 'aa': 'aar', 'af': 'afr', 'ak': 'aka', 'sq': 'sqi', 'am': 'amh', 'ar': 'ara', 'an': 'arg', 'hy': 'hye', 'as': 'asm', 'av': 'ava', 'ae': 'ave', 'az': 'aze', 'bm': 'bam', 'ba': 'bak', 'eu': 'eus', 'be': 'bel', 'bn': 'ben', 'bh': 'bih', 'bi': 'bis', 'bs': 'bos', 'br': 'bre', 'bg': 'bul', 'my': 'mya', 'ca': 'cat', 'ch': 'cha', 'ce': 'che', 'ny': 'nya', 'zh': 'zho', 'cv': 'chv', 'kw': 'cor', 'co': 'cos', 'cr': 'cre', 'hr': 'hrv', 'cs': 'ces', 'da': 'dan', 'dv': 'div', 'nl': 'nld', 'dz': 'dzo', 'en': 'eng', 'eo': 'epo', 'et': 'est', 'ee': 'ewe', 'fo': 'fao', 'fj': 'fij', 'fi': 'fin', 'fr': 'fra', 'ff': 'ful', 'gl': 'glg', 'ka': 'kat', 'de': 'deu', 'el': 'ell', 'gn': 'grn', 'gu': 'guj', 'ht': 'hat', 'ha': 'hau', 'he': 'heb', 'hz': 'her', 'hi': 'hin', 'ho': 'hmo', 'hu': 'hun', 'ia': 'ina', 'id': 'ind', 'ie': 'ile', 'ga': 'gle', 'ig': 'ibo', 'ik': 'ipk', 'io': 'ido', 'is': 'isl', 'it': 'ita', 'iu': 'iku', 'ja': 'jpn', 'jv': 'jav', 'kl': 'kal', 'kn': 'kan', 'kr': 'kau', 'ks': 'kas', 'kk': 'kaz', 'km': 'khm', 'ki': 'kik', 'rw': 'kin', 'ky': 'kir', 'kv': 'kom', 'kg': 'kon', 'ko': 'kor', 'ku': 'kur', 'kj': 'kua', 'la': 'lat', 'lb': 'ltz', 'lg': 'lug', 'li': 'lim', 'ln': 'lin', 'lo': 'lao', 'lt': 'lit', 'lu': 'lub', 'lv': 'lav', 'gv': 'glv', 'mk': 'mkd', 'mg': 'mlg', 'ms': 'msa', 'ml': 'mal', 'mt': 'mlt', 'mi': 'mri', 'mr': 'mar', 'mh': 'mah', 'mn': 'mon', 'na': 'nau', 'nv': 'nav', 'nd': 'nde', 'ne': 'nep', 'ng': 'ndo', 'nb': 'nob', 'nn': 'nno', 'no': 'nor', 'ii': 'iii', 'nr': 'nbl', 'oc': 'oci', 'oj': 'oji', 'cu': 'chu', 'om': 'orm', 'or': 'ori', 'os': 'oss', 'pa': 'pan', 'pi': 'pli', 'fa': 'fas', 'pl': 'pol', 'ps': 'pus', 'pt': 'por', 'qu': 'que', 'rm': 'roh', 'rn': 'run', 'ro': 'ron', 'ru': 'rus', 'sa': 'san', 'sc': 'srd', 'sd': 'snd', 'se': 'sme', 'sm': 'smo', 'sg': 'sag', 'sr': 'srp', 'gd': 'gla', 'sn': 'sna', 'si': 'sin', 'sk': 'slk', 'sl': 'slv', 'so': 'som', 'st': 'sot', 'es': 'spa', 'su': 'sun', 'sw': 'swa', 'ss': 'ssw', 'sv': 'swe', 'ta': 'tam', 'te': 'tel', 'tg': 'tgk', 'th': 'tha', 'ti': 'tir', 'bo': 'bod', 'tk': 'tuk', 'tl': 'tgl', 'tn': 'tsn', 'to': 'ton', 'tr': 'tur', 'ts': 'tso', 'tt': 'tat', 'tw': 'twi', 'ty': 'tah', 'ug': 'uig', 'uk': 'ukr', 'ur': 'urd', 'uz': 'uzb', 've': 'ven', 'vi': 'vie', 'vo': 'vol', 'wa': 'wln', 'cy': 'cym', 'wo': 'wol', 'fy': 'fry', 'xh': 'xho', 'yi': 'yid', 'yo': 'yor', 'za': 'zha', 'zu': 'zul' } def detailedHelp(): helpstring = """ ${PGM_NAME} ${PGM_VERSION} ${PGM_LICENSE} FIRST THINGS ------------ Edit this program and change the values for (near top of file): # Location of your ffmpeg program (optional if you won't convert to mp4) FFMPEG = '/usr/bin/ffmpeg' # Location of your ccextractor program (optional) CCEXTRACTOR = '/usr/local/bin/ccextractor' # Location directory where meta db caches go SURLATABLO_ROOT = '/SurLaTablo' # List of your Tablo IPs, this program does not auto detect today TABLO_IPS = ['192.168.1.73'] UPDATE AND SEARCH ----------------- Update cache db (need metadata db to do anything) (typically you do this first, first run will take a bit) surlatablo.py Update and search db surlatablo.py --query Green\ Acres Do not update cache, just search db (note matches Green Acres anywhere in the metadata) surlatablo.py --noupdate --query Green\ Acres Search db by metadata # Find all for TV series called Green Acres surlatablo.py --noupdate --query series~=Green\ Acres # Find all Sports records surlatablo.py --noupdate --query meta_type~=Sports Use a query format string to change output # Find all TV shows and user a query format for output # (note --queryformat will not do anything combined with --convert) surlatablo.py --noupdate --query meta_type~=TV --queryformat '${lair_date}\t${rec_id}\t${series}\t${title}' Display full TabloTV metadata for a specific recording id. # (note --rec_id can be used with --convert) surlatablo.py --noupdate --rec_id 28191 Note: You can easily force a full refresh of local cached data by removing the files at SULATABLO_ROOT/Tablo_IP/* CONVERT OR PREVIEW CONVERT (ADD SUBTITLES/CC, MP4 METADATA, CROP) ----------------------------------------------------------------- Locate a particular recording, convert with close captioning done as a subtitle. Sample interative output also shown. surlatablo.py --noupdate --query Fuji\ falls --convert --ccaption --clobber Working on: [./TV/McHale's Navy/Season 3/McHale's Navy - s03e15 - Fuji's Big Romance.mp4] Retrieving Tablo Data (28191): [####################] 100% Extracting CC as Subtitle: [####################] 100% Transcoding: [####################] 100% Locate all sports and use default season of game_year and use supplied episode start number by sport_type. Defaulting starting with episode number 1 for unspecified types. surlatablo.py --noupdate --query meta_type~=Sports -E "NFL Football::3,NBA Basketball::5,1" --convert Use the --debug (probably misnamed) to show what surlatablo.py would do, but don't do it (option to be combined with --convert) surlatablo.py --noupdate --query Fuji\ falls --convert --ccaption --clobber --debug [ ./TV/McHale's Navy/Season 3/McHale's Navy - s03e15 - Fuji's Big Romance.mp4 ] [ http://192.168.1.73:18080/pvr/28191/segs -> /tmp/TabloE1_zkh.ts] ['/usr/local/bin/ccextractor', '/tmp/TabloE1_zkh.ts', '--gui_mode_reports', '-o', '/tmp/TabloZdkhvf.srt'] ['/usr/bin/ffmpeg', '-i', '/tmp/TabloE1_zkh.ts', '-f', 'srt', '-i', '/tmp/TabloZdkhvf.srt', '-bsf:a', 'aac_adtstoasc', '-c:v', 'copy', '-c:a', 'copy', '-c:s', 'mov_text', '-metadata:s:s:0', 'language=eng', '-metadata:s:a:0', 'language=eng', '-metadata', "title=Fuji's Big Romance", '-metadata', 'date=1964-12-25', '-metadata', 'network=Antenna', '-metadata', "album=McHale's Navy", '-metadata', "show=McHale's Navy", '-metadata', 'genre=Sitcom', '-metadata', 'episode_id=s03e15', '-metadata', "synopsis=Fuji falls in love with a native chief's daughter.", '-metadata', "description=Fuji falls in love with a native chief's daughter.", '-metadata', "comment=Fuji falls in love with a native chief's daughter.", '-y', "./TV/McHale's Navy/Season 3/McHale's Navy - s03e15 - Fuji's Big Romance.mp4"] Note: Better, full output of an actual --convert can be captured simply be redirecting output to a file instead of to screen/terminal. Useful for when things aren't working (bugs in the software). Note: Program uses Python tempfile functions. To adjust your temporary directory place: tempfile.tempdir = '/path-to/my-tempdir' For other notes on how Python finds your temporary file location, see Python documentation. BASIC CONVERT OPTIONS (for use with --convert) --------------------- --ccaption = Pull closed captioning off of Tablo recording and convert it to subtitle format for inclusion with final transcode. --clobber = By default, this program will not convert if the target end result filename already exists. --keepdir = Instead of deleting intermediate temporary files (e.g. the Tablo .ts file, the subtitle .srt file), keep them here. --wcrop = Crop (assumes 480i) to a widecreen format. For example, a widescreen movie shown on a 480i channel. This does result in a slow full transcode of the media. ADVANCED CONVERT OPTIONS ------------------------ As with query formats, you may use metadata keys inside of the paths here. --sportsepisode = Format of the form: [::] Use episode_number starting with start_number and incrementing by one for every match. Different start_numbers can be specified for the different sport_types. --sportsseason = Format of the form: [::] Override using the game_date and use supplied season_number as the season for the sporting event, a different season can be specified by each sport_type. --basedir = Format of the form: ::,.. Base directory location for final converted mp4 file based on meta_type. Predefines are (BASE_DIRS): Default = ./${meta_type} (e.g. ./Movie, ./Manual) Sports = ./${meta_type}/${sport_type}/Season ${season_number} (e.g. ./Sports/NFL Football/Season 2014) (remember, you can override the season_number for Sports on the command line with -S) TV = ./${meta_type}/${series}/Season ${season_number} --filename = Format of the form: ::,... (minus the file extension) Predefines are (FILENAME_PATS): Default = ${title} TV = ${series} - s${plex_season_number}e${plex_episode_number} - ${title} Sports = ${sport_type} - s${plex_season_number}e${plex_episode_number} - ${title} Movie = ${title} (${release_year}) Note: The Default applies only in cases where there is no meta_type match. So if we wanted to override the location for a TV show. We could override with, --basedir TV::. --filename TV::MyOwnFilename The output then would simply be placed at ./MyOwnFilename.mp4. If we want Movies to stored inside of directory instead of flat inside of the Default basedir, we could use, --basedir Movie::./${meta_type}/${title} (${release_year}) You can alter the values of BASE_DIRS and FILENAME_PATS in this program to make your own "default" settings persistent. COMMAND LINE SWITCH SUMMARY WITH SHORTCUTS ------------------------------------------ -h, --help = Print this very long help. -v, --version = Print this program version. -d, --debug = Turn on "debug" output, which is really just a show without execution flag for --convert. -c, --convert = Attempt to transcode a matching query set or --rec_id value. -C, --ccaption = Extract subtitle .srt file from closed captioning and insert subtitle stream into final ouput file. -y, --clobber = Overwrite final destination file. Normally, program exits if final output file exists. -w, --wcrop = Crop recordings for 4:3, 480i channels to a widescreen format (fully transcodes, slow). -n, --noupdate = Do not process new or deletions off Tablo unit, just go off existing cached data. -i, --rec_id = Show TabloTV/Tribune full metadata for supplied id. -k, --keepdir = Keep temporary files used in --convert at this directory location. -q, --query = Query the meta db, in particular format can be of the form metakey~=Value. -b, --basedir = Comma separted list of basedir format patterns, [ = Formatted pattern to produce final name (without extension). -S, --sportsseason = Format is [::]season-number instead of using game_year. -E, --sportsepisode = Format is [::]episode-number. -Q, --queryformat = Format is re string (matches across full record) or re string patterned automatically. -W, --cropformat = (this may all change, recommend that you not use this) -O, --ccoffset