Shell: Select all
{
// test comment line
/* test comment line */
def maps = include "P:/FileBot/config.groovy"
def map = maps['DEFAULTS'] + maps['TV'], root = any{map['root']}{root}{}
def groups = allOf{map['shows']}{map['groups'].join('|')}{anime}.join('|')
def slashes = /(?:\\|\/)/, tmdbid = any{tmdbid}{"XXX"}, tvdbid = any{tvdbid}{"XXX"}, imdbid = any{imdbid}{"ttXXX"}
def folders = map['folders'], anime = (any{anime}{} ? (map['anime'] ? map['anime'] : null) :null)
def mediaID = any{"{imdb=${imdbid}}"}{"{tmdb=${tmdbid}}"}{"{tvdb=${tvdbid}}"}{}
def talkshows = (map['talkshows'] !== true ? map['talkshows'] : 'TALK' )
def franchises = map['franchises'], franchise = any{getMatch(franchises)}{}, fap = getMatch(map.faps)
rlRegex=/(tmdb${tmdbid}|tvdb${tvdbid}|${imdbid})([^0-9]|$)/
rlRegex=/(tmdb${tmdbid}|tvdb${tvdbid}|${imdbid})/
def regex = [
'root': /^([a-z]:\\?|\/)/,
'folders': folders.values().join('|'),
'keys': folders.keySet().join('|'),
]
// Functions
def theValue(k,p,r) { if (fn =~ r || n =~ r || /^${imdbid}$/ =~r || /^tmdb${tmdbid}$/ =~r || /^tvdb${tvdbid}$/ =~r ) return [group:k, path:p, regex:r, IDs:[imdb:imdbid,tmdb:tmdbid,tvdb:tvdbid] ] }
def getMatch(array) { array.findResult{ k, v -> v.findResult{ p="", a -> (any{a.length()}{} ? ( theValue((k),(p),a) ) : a.findResult{ r -> return theValue((k),(p),r) } ) } } }
def getRoot(root, path) { return ( any{path.match(/^([a-z]:|\/)/)}{} ? path : root ) }
def rootPath(root, path) { return ( any{path.match(/^([a-z]:|\/)/)}{} ? path : "${root}/${path}" ) }
def validateName(name) { return name.colon(' - ').replaceAll('/','; ').replaceAll(/\.\.\.+/,'…').validateFileName() }
def validatePath(name) { return name.colon(' - ').replaceAll(/\.\.\.+/,'…').validateFileName() }
def customFind(map) { return map.find{k,v -> fn=~v} }
def fpm(path,regex) { return path.match(/(?<=\\|\/)(${regex})(?=\\|\/)/) }
def readLines(file) {
def col = /(tt|tmdb|tvdb)[0-9]+/
def one = any{lines(config+'/'+file).find{ it =~ "^${rlRegex}" }.after(/\t/).before(/[#\t*]/)}{}
def two = any{lines(config+'/'+file).find{ it =~ rlRegex }.before(col).before(/\t/)}{}
return any{one}{two}{}
return "(( ${file} || ${imdbid} || ${rlRegex} || ${one} || ${two} ))"
}
def original=any{original}{fn}, source=any{source.upper()}{}, ac=any{ac.match(/^.{1,6}$/)}{}, vc1=any{vc}{}
def dir=any{readLines(map['collections']).find{ it =~ findRegex }.after(/^(tt|tmdb|tvdb)\d+\s+/).before(/[#\t*]/)}{}
def year=any{readLines(map['overrides'])}{y}{d.year}{episodelist[0].airdate.year}{'0000'}
def vc=any{video[0].codec.tokenize('/')[0].lower().match(/^v_mpeg.$/).replaceAll(/^v_mpeg4$/,'x264').replaceAll(/^v_mpegh$/,'HEVC')}{vc}{}
def s=any{s}{file.path.match(/s\d+e\d+[-. ]/).match(/(?<=s)\d+/)}{00}, s00e00=any{s00e00.match(/S\d+E\d+.*/)}{"S${s.pad(2)}E${e.pad(2)}"}{}
def name=n.removeAll(/\s*\((00|19|20)\d\d\)\s*$/).colon(' - ').validateFileName(), show="${name} (${year})", ep=s00e00.lower()
def group=any{group}{"${any{original}{fn}}".match(/(?:-)(<?=\.[a-zA-Z\d]{1,15})([a-zA-Z\d]{1,15})(\.\[[a-z\d]{8}\])?$/)}{}
def meta=allOf{allOf{original.upper().matchAll(/(?<=\.)(internal|multi|proper|repack)(?=.)/).unique().join('.')}{orig}{source}{vf}{vc}{ac}.join('.')}{group}.join('-')
def title=allOf{"${episode}".after(/${n}/).after(/-[\dx& ]*/).after(/(Special [\d ]*)?[ -]*/).replaceAll('/','; ').replaceAll(/\.\.\.+/,'…')}{meta}.join('.')
def dest=any{fap.path.match(regex['root'])}{folders[fpm(file.path,regex['keys'])]}{fpm(file.path,regex['folders'])}{folders[map['dd']]}{map['dd']}, full=any{dest.match(regex['root'])}{}
def TV=(any{fap.path}{} ? fap.path: any{franchise}{file.path.match(/${root}${slashes}(?:${regex['folders']}|{$groups})${slashes}/)}{readLines(map['collections'])}{anime?'Anime':map['shows']} )
//return allOf{0}{dest}{1}{regex['folders']}{2}{}{3}{file.path}{4}{file.path.match(/(?<=\\|\/)(${regex['keys']})(?=\\|\/)/)}{5}
def path=[
root: allOf{full?"":root}{dest}.join('/'),
tv: TV,
folder: allOf{any{dir}{show}}{mediaID}.join(' '),
season: "Season ${(episode.special || episode.special == 0 ? '00':s.pad(2))}",
name: allOf{allOf{show}{ep}{title}.join(' - ')}{".[${crc32}]"}{subt}.join('').colon(' - ').validateFileName()
]
if (any{genres.toString().match(/(?i)Talk ?Shows?/)}{file.path.match(/(?i)(\\(_ )?TALK(SHOWS?)?\\)/)})
{ path['season']=airdate.format('yyyy-MM MMMM'); ep=airdate; path['tv']=(talkshows?"TALK":path['tv']); show=name.removeAll(/^The /); path['folder']=any{dir}{show} }
return path.values().join('/')
}Groovy: Select all
[
"DEFAULTS":[
"root":"P:/",
"dd":"08",
"collections":"collections.txt",
"overrides":"overrides.txt",
"folders":[
"01":"_01",
"02":"_02",
"03":"_03",
"04":"_04",
"05":"_05",
"06":"_06",
"08":"_08",
"E1":"_E1",
"E2":"_E2",
"E3":"_E3",
"E4":"_E4",
"26":"_E4",
],
],
"TV":[
"shows": "TV",
"talkshows":true,
"anime":false,
"franchises":[
"DC": [
"Superman .+",
"Lois and Clark.+",
],
"StarTrek": "^1Star ?Trek|tt0112178|74550",
"StarWars": "^(Star ?Wars|(The ?)?Mandelorian|Obi-?Wan ?Kenobi)",
],
// FAPS = File Alternate Path Structure
// Fapping let's you choose destinations based on filename or title association.
//
// Formats:
// "faps" = [group:[path:"single regex query"]]
// "faps" = [group:[path:[multiple regex queries, comma separated]]]
// Group is a title to identify what the paths/patters are for.
// Path is alternative path (relative or static) to use.
// Regex to pattern to match. Filename, IMDb (tt prefixed), and TVDb (tvdb prefixed) supported.
//
// Note: Starting the path with a letter/colon, or with a forward slash, will make it the static path instead of a relative one.
// This will override the value used for "shows" above.
//
"faps":[
"Marvel":[
'Marvel/': /^(The Amazing Spider-Man)/,
],
"DC":[
'DC/': [
"^(Arrow|tt2193021)", "^(The Flash|tt0098798|tt3107288)", "^(DC'?s Legends of Tomorrow|tt4532368)",
"^(Batwoman|tt8712204)", "^(Supergirl|tt4016454)", "^(Black Lightning|tt6045840)",
"^(Superman ?(and|&) ?Lois|tt11192306)",
]
],
],
"groups":[
"DC(shows)?",
"Marvel(TV)?",
"Star ?Trek",
],
],
"MOVIES":[
"dd":"06",
"films": "MOVIES",
"collectionsFolder":"_",
"editions":[
// IMDbID || TMDbID
// ID: [ mins:edition name ]
"tt0078346":[
"188": "Extended",
"151": "Special",
],
"tt2975590":[
"182": "Ultimate",
"151": "Theatrical",
],
],
]
]