Re: How about sharing our format expressions?
Posted: 28 Sep 2018, 20:13
I don't use MusicBrainz....sorry.
Greg
Greg
The ultimate TV and Movie Renamer
https://www.filebot.net/forums/
Code: Select all
$set(title,$replace(%title%,...,…))
$set(album,$replace(%album%,...,…))
$set(artist,$replace(%artist%,...,…))
$set(albumartist,$replace(%albumartist%,...,…))
$if(%originaldate%,$set(date,%originaldate%))
$set(filename,%_filename%)
$set(foldername,%_dirname%)
$if($in(%title%,Live),$set(_misctype,Live))
$if($in(%title%,Demo),$set(_misctype,Demos))
$if($in(%title%,Acoustic),$set(_misctype,Acoustic))
$if($in(%title%,Unplugged),$set(_misctype,Acoustic))
$if($in(%title%,Remix),$set(_misctype,Remixes))
$if($in($lower(%_dirname%),album),$if($not(%discsubtitle%),$set(disctitle,Album)))
$if($in(%_dirname%,Bonus),$if($not(%discsubtitle%),$set(disctitle,Bonus Disc)))
$if($gte($matchedtracks(),$div(%totaltracks%,2)),$set(_miscorincomplete,Incomplete),$set(_miscorincomplete,Misc))
$if($gte($matchedtracks(),%totaltracks%),$unset(_miscorincomplete) $unset(_misctype))
$if($lte($sub(%totaltracks%,$matchedtracks()),1),$set(_numberofmissingtracks,$sub(%totaltracks%,$matchedtracks())$unset(_pluaralmissingtracks)))
$if($gt($sub(%totaltracks%,$matchedtracks()),1),$set(_numberofmissingtracks,$sub(%totaltracks%,$matchedtracks())$set(_pluaralmissingtracks,s)))
$if($in(%album%,Tribute),$set(_tribute,Tributes))
$if($in(%album%,tribute),$set(_tribute,Tributes))
$if($eq(%releasetype%,compilation),$set(releasetype,[Compilation Albums]))
$if($eq(%releasetype%,remix),$set(releasetype,[Remixes]) $set(tributetype,[Remixes]))
$if($eq(%releasetype%,soundtrack),$set(releasetype,[Soundtracks]))
$if($eq(%releasetype%,album),$set(releasetype,[Studio Albums]))
$if($eq(%releasetype%,live),$set(releasetype,[Live Albums]))
$if($eq(%releasetype%,single),$set(releasetype,[Singles]))
$if($eq(%releasetype%,ep),$set(releasetype,[EPs]))
$if(%_releasecomment%, $set(_releasecomment,\(%_releasecomment%\)),$noop())
$if($and($eq(%releasecountry%,JP),$not($in(%_releasecomment%,Japan))),$set(_releasecomment,%_releasecomment% \(Japan Import\)))
$if($and($eq(%releasecountry%,RU),$not($in(%_releasecomment%,Russia))),$set(_releasecomment,%_releasecomment% \(Russian Import\)))
$if($and($eq(%releasecountry%,XE),$not($in(%_releasecomment%,Europe))),$set(_releasecomment,%_releasecomment% \(European Import\)))
$if($and($eq(%releasecountry%,AU),$not($in(%_releasecomment%,Australia))),$set(_releasecomment,%_releasecomment% \(Australian Import\)))
$if($and($eq(%releasecountry%,DE),$not($in(%_releasecomment%,German))),$set(_releasecomment,%_releasecomment% \(German Import\)))
$if($and($eq(%releasecountry%,FI),$not($in(%_releasecomment%,Finland))),$set(_releasecomment,%_releasecomment% \(Finland Import\)))
$if($and($eq(%releasecountry%,FR),$not($in(%_releasecomment%,France))),$set(_releasecomment,%_releasecomment% \(France Import\)))
$if($in(%album%, Punk ),$set(tributetype,Punk))
$if($in(%album%, Rock ),$set(tributetype,Rock))
$if($in(%album%, Metal ),$set(tributetype,Metal))
$if($in(%album%, Bluegrass ),$set(tributetype,Bluegrass))
$if($in(%album%, Acoustic ),$set(tributetype,[Acoustic]))
$if($in(%album%,Gothic Acoustic),$set(tributetype,[Gothic Acoustic Series]))
$if($in(%album%,Pickin' On ),$set(tributetype,[Pickin' On Series]))
$if($in(%album%, Industrial ),$set(tributetype,Industrial))
$if($in(%album%, Techno ),$set(tributetype,Techno))
$if($in(%album%,Tribute),$set(_tribute,Tributes))
$if($in(%album%, Quartet ),$set(tributetype,[String Quartet Series]))
$if($in(%album%,Remix),$set(tributetype,[Remixes]))
$if($in(%album%,Symphonic),$set(_tribute,Tributes))
$if($in(%album%,Symphonic),$set(tributetype,[Symphonic]))
$if($in(%album%, Lullaby Renditions),$set(_tribute,Tributes))
$if($in(%album%, Lullaby Renditions),$set(tributetype,[Lullaby Renditions]))
$if($in(%album%, Piano ),$set(_tribute,Tributes))
$if($in(%album%, Piano ),$set(tributetype,[Piano Series]))
$if($not(%tributetype%),$set(tributetype,[Various Artists]))
$if($in(%releasetype%,[Soundtracks]),$set(_tribute,Soundtracks)$unset(tributetype))
$replace($replace($replace($replace($replace($replace($replace($replace($replace(
$if($eq(%compilation%,1),
$if(%_tribute%,[%_tribute%]/
$if(%tributetype%,%tributetype%)/
$if(%date%, [$left(%date%,4)]) - %album%
$if(%_releasecomment%, %_releasecomment%)
$if($and($ne(%totaldiscs%,1),$not($in(%totaldiscs%,1))),\(%totaldiscs% Disc Set\),$noop())
$if($gt(%totaldiscs%,1),/Disc $num(%discnumber%,2)
$if(%discsubtitle%, - \(%discsubtitle%\)))/
$num(%tracknumber%,2) - %artist% - %title%
$if(%discsubtitle%,\(%discsubtitle%\)))
$if($eq(%albumartist%,Various Artists),
$if($not(%_tribute%),Various Artists/%releasetype%/
$if(%date%, [$left(%date%,4)]) - %album%
$if(%_releasecomment%, %_releasecomment%)
$if($and($ne(%totaldiscs%,1),$not($in(%totaldiscs%,1))),\(%totaldiscs% Disc Set\),$noop())
$if($gt(%totaldiscs%,1),/Disc $num(%discnumber%,2)
$if(%discsubtitle%, - \(%discsubtitle%\)))/
$num(%tracknumber%,2) - %artist% - %title%
$if(%discsubtitle%,\(%discsubtitle%\))))
$if($not($eq(%albumartist%,Various Artists)),
$if($not(%_tribute%),Various Artists/%releasetype%/
$if(%date%, [$left(%date%,4)]) - %album%
$if(%_releasecomment%, %_releasecomment%)
$if($and($ne(%totaldiscs%,1),$not($in(%totaldiscs%,1))),\(%totaldiscs% Disc Set\),$noop())
$if($gt(%totaldiscs%,1),/Disc $num(%discnumber%,2)
$if(%discsubtitle%, - \(%discsubtitle%\)))/
$num(%tracknumber%,2) - %artist% - %title%
$if(%discsubtitle%,\(%discsubtitle%\)))))
,*,[x]),?,),:, -),",'),_, ),|, ),<,[),>,]), , )
$replace($replace($replace($replace($replace($replace($replace($replace($replace(
$if($not($eq(%compilation%,1)),
$if(%_tribute%,[%_tribute%]/
$if(%tributetype%,%tributetype%)/
$if(%date%, [$left(%date%,4)]) - %album%$if($ne(%originalyear%,$left(%date%,4)),
$if(%originalyear%, \(%originalyear% Reissue\)))
$if(%_releasecomment%, %_releasecomment%)
$if($and($ne(%totaldiscs%,1),$not($in(%totaldiscs%,1))),\(%totaldiscs% Discs\),$noop())
$if($gt(%totaldiscs%,1),/Disc $num(%discnumber%,2)
$if(%discsubtitle%, - \(%discsubtitle%\)))/
%artist% - $num(%tracknumber%,2) - %title%
$if(%discsubtitle%,\(%discsubtitle%\)))
$if($not(%_tribute%),
$if(%_miscorincomplete%,
$if($eq(%_miscorincomplete%,Misc),
$if2(%grouping%,Unknown)/$if2(%genre%,Unknown)/
$if2(%albumartistsort%,%artistsort%,%albumartist%,%artist%)/
$if(%_misctype%,[%_misctype%]/,[Misc]/)
%artist% -$if(%album%, %album% -) $num(%tracknumber%,2) - %title%)
$if($eq(%_miscorincomplete%,Incomplete),
$if2(%grouping%,Unknown)/$if2(%genre%,Unknown)/
$if2(%albumartistsort%,%artistsort%,%albumartist%,%artist%)/
$if(%_miscorincomplete%, [Incomplete Albums]/)
$if(%date%, [$left(%date%,4)]) - %album% $if(%_numberofmissingtracks%, \($num(%_numberofmissingtracks%,2) Track$if(%_pluaralmissingtracks%,%_pluaralmissingtracks%) Missing\))
$if($ne(%originalyear%,$left(%date%,4)),
$if(%originalyear%, \(%originalyear% Reissue\)))
$if(%_releasecomment%, %_releasecomment%)
$if($and($ne(%totaldiscs%,1),$not($in(%totaldiscs%,1))),\(%totaldiscs% Discs\),$noop())
$if($gt(%totaldiscs%,1),/Disc $num(%discnumber%,2)
$if(%discsubtitle%, - \(%discsubtitle%\)))/
%artist% - $num(%tracknumber%,2) - %title%
$if(%discsubtitle%,\(%discsubtitle%\)))))
$if($not(%_miscorincomplete%),
$if2(%grouping%,Unknown)/$if2(%genre%,Unknown)/
$if2(%albumartistsort%,%artistsort%,%albumartist%,%artist%)/
$if(%releasetype%, %releasetype%/)
$if(%date%, [$left(%date%,4)]) - %album%
$if($ne(%originalyear%,$left(%date%,4)),
$if(%originalyear%, \(%originalyear% Reissue\)))
$if(%_releasecomment%, %_releasecomment%)
$if($and($ne(%totaldiscs%,1),$not($in(%totaldiscs%,1))),\(%totaldiscs% Discs\),$noop())
$if($gt(%totaldiscs%,1),/Disc $num(%discnumber%,2) $if(%disctitle%, - \(%disctitle%\))
$if(%discsubtitle%, - \(%discsubtitle%\)))/
%artist% - $num(%tracknumber%,2) - %title%
$if(%discsubtitle%,\(%discsubtitle%\))))
,*,[x]),?,),:, -),",'),_, ),|, ),<,[),>,]), , )
Code: Select all
{y}/{primaryTitle}{if (n != primaryTitle) {primaryTitle.isLatin() ? " (${n})" : " (${primaryTitle.ascii()}) (${n})"}}/{fn}
nothinghere wrote: ↑13 Jul 2014, 18:57 The ones I am using. Major thanks to Ithiel and Rednoah for some of the parts.
Movies:
I am using the original title if it the alphabet used is latin based. If the original title is not the same as the english title, and the first spoken language is not Swedish, Norwegian or Danish I will add the English title as part of the filename. This way I can keep the original titles which I prefer, but still have a chance to find them/connect them to the English titles most commonly used when talking to people. The Nordic stuff is because I live there so I know which movies they are.Code: Select all
{norm={it.upperInitial().lowerTrail().replaceTrailingBrackets().replaceAll(/\u0022/, '\'').replaceAll(/[:|]/, '.').replaceAll(/\?/, '!').replaceAll(/[*\s\.,]+/, '.').replaceAll(/\b[IiVvXx]+\b/, { it.upper() }).replaceAll(/[0-9](th|nd|rd)/, { it.lower() })};isLatin = {java.text.Normalizer.normalize(it, java.text.Normalizer.Form.NFD).replaceAll(/\p{InCombiningDiacriticalMarks}+/, '') ==~ /^\p{InBasicLatin}+$/}; isLatin(info.OriginalName) ? norm(info.OriginalName) : norm(primaryTitle) }.({y}){if(isLatin(info.OriginalName) && info.OriginalName != primaryTitle && !(info.SpokenLanguages[0] ==~ /(sv|da|no)/)) '.'+ norm(primaryTitle) }{'.'+vf}{'.'+source}{fn.contains('3D') || fn.contains('3-D') ? '.3D':''}{'.'+fn.replace(/(?i)\.DC\./, '.directors.cut.').replaceAll(/director\'?s|theatrical|ultimate/,'$0.Cut').matchAll(/UNCENSORED|UNRATED|REMASTERED|EXTENDED|UNCUT|DIRECTOR\'?S.CUT|THEATRICAL.CUT|ULTIMATE.CUT|FINAL.CUT|SPECIAL.EDITION/)*.upperInitial()*.lowerTrail().sort().join('.')}{'.'+fn.matchAll(/PROPER|REPACK/)*.upper().sort().join('.')}{'.'+vc.replace('Microsoft', 'VC-1')}{'.'+ac.replace('MPEG Audio', 'MP3')}{audio.FormatProfile =~ /MA Core/ ? '-HD.MA' : ''}{audio.FormatProfile =~ /ES/ ? '-ES' : ''}{audio.FormatProfile =~ /Pro/ ? '-Pro' : ''}{'.'+af.replace('8 6ch', '7.1').replace('7 6ch', '6.1').replace('6ch', '5.1').replace('3ch', '2.1').replace('2ch','2.0').replace('1ch','1.0')}{def g = c{group}; def m = c{fn.match(/(?:(?<=[-])[a-z0-9]+$)|(?:^[a-z0-9]+(?=[-]))/)}; if(g==null && m!=null) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null && m!=null && m.lower()!=g.lower()) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null) return '-'+g;}
If you want to use the format but don't want the special hack for Nordic stuff remove the text: "&& !(info.SpokenLanguages[0] ==~ /(sv|da|no)/)"
The audio/movie codecs are hacked a bit to be named by their real/common names instead of the ones defined by mediainfo. I.e. DTS-HD MA, MP3, VC-1 instead of DTS MA Core, MPEG Audio and Microsoft respectively.
Examples:I would have loved to figure out how to keep the transliterated names, but using {transliterate(info.OriginalTitle)}did not work perfectly, which meant a bunch of titles missed when doing searched.Kôkaku.Kidôtai.2.0.(2008).Ghost.In.The.Shell.2.0.720p.REPACK.x264.DTS.5.1-timeshift.mkv // Latin characters but added english name
Jagten.(2012).1080p.BluRay.x264.DTS-HD.MA-GRYM.mkv // Original name only, primary language is Danish
My.Sassy.Girl.(2001).720p.BluRay.x264.AC3.5.1-EbP.mkv // Actual name is 엽기적인 그녀, or transliterated to Yeopgijeogin Geunyeo
For my sassy girl the transliteration was something like Yeobgi-jeogin Geunyeo or the like, which is really close, but far away to miss some lookups.
NOTE: I do not care for multipart files so I do not support them. I rip my movies as single files without any splits.
Series is a bit simpler as I only care about the name we get from TheTVDB (I have long since abandoned any hope that they'll change their mind and structure series as they were intended instead of simply how they where broadcasted):
NOTE: I do not pad the season numbering (i.e. I use Season 1, Season 2 instead of Season 01, Season 02).Code: Select all
{n}/{episode.special ? 'Specials' : 'Season '+s}/{norm={it.upperInitial().lowerTrail().replaceTrailingBrackets().replaceAll(/\u0022/, '\'').replaceAll(/[:|]/, '.').replaceAll(/\?/, '!').replaceAll(/[*\s\.]+/, '.').replaceAll(/\b[IiVvXx]+\b/, { it.upper() }).replaceAll(/[0-9](th|nd|rd)/, { it.lower() })};norm(n) }.{episode.special ? 'S00E'+special.pad(2) : s00e00}.{norm(t)}{'.'+vf}{'.'+source}{'.'+fn.matchAll(/PROPER|REPACK/)*.upper().sort().join('.')}{'.'+vc.replace('Microsoft', 'VC-1')}{'.'+ac.replace('MPEG Audio', 'MP3')}{audio.FormatProfile =~ /MA Core/ ? '-HD.MA' : ''}{audio.FormatProfile =~ /ES/ ? '-ES' : ''}{audio.FormatProfile =~ /Pro/ ? '-Pro' : ''}{'.'+af.replace('8 6ch', '7.1').replace('7 6ch', '6.1').replace('6ch', '5.1').replace('3ch', '2.1').replace('2ch','2.0').replace('1ch','1.0')}{def g = c{group}; def m = c{fn.match(/(?:(?<=[-])[a-z0-9]+$)|(?:^[a-z0-9]+(?=[-]))/)}; if(g==null && m!=null) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null && m!=null && m.lower()!=g.lower()) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null) return '-'+g;}
Specials end up in a /Specials folder instead. Same thing for video/audio as movies have.
Examples:Coupling\Season 1\Coupling.S01E01.Flushed.360p.DVDRip.x264.AAC.mkv
Doctor Horrible's Sing-Along Blog\Season 1\Doctor.Horrible's.Sing-Along.Blog.S01E01.Act.I.1080p.BluRay.x264.DTS-DIMENSION.mkv
If anyone wants to copy my thing entirely the script I use to sort everything is:NOTE: Remember to update the paths to your series/movies and downloads.Code: Select all
filebot -script fn:amc "x:/downloads" --log-file d:\amc-run.log --output "//nas/" --action move --conflict skip -non-strict --def clean=y --def "movieFormat=Movies/{norm={it.upperInitial().lowerTrail().replaceTrailingBrackets().replaceAll(/\u0022/, '\'').replaceAll(/[:|]/, '.').replaceAll(/\?/, '!').replaceAll(/[*\s\.,]+/, '.').replaceAll(/\b[IiVvXx]+\b/, { it.upper() }).replaceAll(/[0-9](th|nd|rd)/, { it.lower() })};isLatin = {java.text.Normalizer.normalize(it, java.text.Normalizer.Form.NFD).replaceAll(/\p{InCombiningDiacriticalMarks}+/, '') ==~ /^\p{InBasicLatin}+$/}; isLatin(info.OriginalName) ? norm(info.OriginalName) : norm(primaryTitle) }.({y}){if(isLatin(info.OriginalName) && info.OriginalName != primaryTitle && !(info.SpokenLanguages[0] ==~ /(sv|da|no)/)) '.'+ norm(primaryTitle) }{'.'+vf}{'.'+source}{fn.contains('3D') || fn.contains('3-D') ? '.3D':''}{'.'+fn.replace(/(?i)\.DC\./, '.directors.cut.').replaceAll(/director\'?s|theatrical|ultimate/,'$0.Cut').matchAll(/UNCENSORED|UNRATED|REMASTERED|EXTENDED|UNCUT|DIRECTOR\'?S.CUT|THEATRICAL.CUT|ULTIMATE.CUT|FINAL.CUT|SPECIAL.EDITION/)*.upperInitial()*.lowerTrail().sort().join('.')}{'.'+fn.matchAll(/PROPER|REPACK/)*.upper().sort().join('.')}{'.'+vc.replace('Microsoft', 'VC-1')}{'.'+ac.replace('MPEG Audio', 'MP3')}{audio.FormatProfile =~ /MA Core/ ? '-HD.MA' : ''}{audio.FormatProfile =~ /ES/ ? '-ES' : ''}{audio.FormatProfile =~ /Pro/ ? '-Pro' : ''}{'.'+af.replace('8 6ch', '7.1').replace('7 6ch', '6.1').replace('6ch', '5.1').replace('3ch', '2.1').replace('2ch','2.0').replace('1ch','1.0')}{def g = c{group}; def m = c{fn.match(/(?:(?<=[-])[a-z0-9]+$)|(?:^[a-z0-9]+(?=[-]))/)}; if(g==null && m!=null) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null && m!=null && m.lower()!=g.lower()) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null) return '-'+g;}" --def "seriesFormat=TV Shows/{n}/{episode.special ? 'Specials' : 'Season '+s}/{norm={it.upperInitial().lowerTrail().replaceTrailingBrackets().replaceAll(/\u0022/, '\'').replaceAll(/[:|]/, '.').replaceAll(/\?/, '!').replaceAll(/[*\s\.]+/, '.').replaceAll(/\b[IiVvXx]+\b/, { it.upper() }).replaceAll(/[0-9](th|nd|rd)/, { it.lower() })};norm(n) }.{episode.special ? 'S00E'+special.pad(2) : s00e00}.{norm(t)}{'.'+vf}{'.'+source}{'.'+fn.matchAll(/PROPER|REPACK/)*.upper().sort().join('.')}{'.'+vc.replace('Microsoft', 'VC-1')}{'.'+ac.replace('MPEG Audio', 'MP3')}{audio.FormatProfile =~ /MA Core/ ? '-HD.MA' : ''}{audio.FormatProfile =~ /ES/ ? '-ES' : ''}{audio.FormatProfile =~ /Pro/ ? '-Pro' : ''}{'.'+af.replace('8 6ch', '7.1').replace('7 6ch', '6.1').replace('6ch', '5.1').replace('3ch', '2.1').replace('2ch','2.0').replace('1ch','1.0')}{def g = c{group}; def m = c{fn.match(/(?:(?<=[-])[a-z0-9]+$)|(?:^[a-z0-9]+(?=[-]))/)}; if(g==null && m!=null) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null && m!=null && m.lower()!=g.lower()) return '-'+m.replace(/^tpz$/, 'TOPAZ'); if(g!=null) return '-'+g;}"
Paste everything into a file called amc.cmd or something and double click it to run it.
Code: Select all
I:/TV/{n}{' '+any{"[$certification]"}{"["+$imdb.certification+"]" }.replaceAll('N A','').replaceAll(/^ \d+$/, 'PG-$0')}{" [$rating" + "★]"}/{regular ? 'Season ' + s.pad(1) : 'Specials'}/
{
def space = call{' '};
def dir_root = 'I/TV/'+
call{hd.matches(/(?i)SD/) ? '480p-720p/' : ' '}+
call{hd.matches(/(?i)HD/) ? '720p-1080p/' : ' '}+
call{hd.matches(/(?i)UHD/) ? '4k/' : ' '};
// Main Title e.g.
// 1408 (2007) (Director's Cut) 1080p HD Blu-ray non-HDR x264 DTS5.1ch_SiNNERS
// 300 (2007) 720p HD BRRip non-HDR x265 DTS 5.1ch_ESiR
// Deadpool (2016) 2160p UHD WEB-DL non-HDR AVC DTS-HD MA 7.1ch_DDR
// Deadpool 2 (2018) (Super Duper Cut) 2160p UHD Blu-ray REMUX HDR10bit ATEME TrueHD Atmos 13Obj 7.1ch_EPSiLON
def main_title = call{n}+
space + call{s00e00}+
space + '-'+
space + call{t}+
space + call{fn.matches(/(?i).+\b25th.+?anniv.+/) ? '(25th Anniv. Edition)' : ' '}+
space + call{fn.matches(/(?i).+\b\(limited\b.*?\).+/) ? '(Limited Edition)' : ' '}+
space + call{fn.matches(/(?i).+\b\(uncut\b.*?\).+/) ? '(Uncut)' : ' '}+
space + call{fn.matches(/(?i).+\bcollector.+?s.+?edition\b.+/) ? '(Collector\'s Edition)' : ' '}+
space + call{fn.matches(/(?i).+\bdirect.+?cut\b.+/) ? '(Director\'s Cut)' : ' '}+
space + call{fn.matches(/(?i).+\bextended.+?\b.+/) ? '(Extended)' : ' '}+
space + call{fn.matches(/(?i).+\bextended.+?edit\b.+/) ? '(Extended Edition)' : ' '}+
space + call{fn.matches(/(?i).+\bimax\b.+/) ? '(IMAX Edition)' : ' '}+
space + call{fn.matches(/(?i).+\blimited\b.+/) ? '(Limited)' : ' '}+
space + call{fn.matches(/(?i).+\bremastered\b.+/) ? '(Remastered)' : ' '}+
space + call{fn.matches(/(?i).+\bsuper.+duper.+cut\b.+/) ? '(Super Duper Cut)' : ' '}+
space + call{fn.matches(/(?i).+\btheatrical\b.+/) ? '(Theatrical)' : ' '}+
space + call{fn.matches(/(?i).+\bunrated\b.+/) ? '(Unrated)' : ' '}+
space + call{any{fn.match(/\([^\()+?[^\d]+?\)\s*/)} {' '}{' '}}+
space + '['+ call{self.vf ? self.vf : self.hpi}+
space + call{hd}+
space + call{source.matches(/(?i)blu.*ray/) ? 'BluRay' : {source} ?: 'WEB-DL'}+
space + call{fn.matches(/(?i).+\bremux\b.+/) ? 'REMUX' : ' '}+
space + call{fn.matches(/(?i).+\bwebrip\b.+/) ? 'WEBRip' : ' '}+
space + call{fn.matches(/(?i).+\bhevc.+?\b.+/) ? '(x265)' : ' '}+
space + call{fn.matches(/(?i).+\bx265\b.+/) ? '(x265)' : ' '}+
space + call{fn.matches(/(?i).+\b264\b.+/) ? '(x264)' : ' '}+
// Only calls {hdr} if it's not SD else non-HDR
space + call{if (hd =~ 'HD') {any{hdr + bitdepth + 'bit'}{'non-HDR'}}}+
space + call{vc}+
space +
// Call audio
// Thread here where I got the base code: https://www.filebot.net/forums/viewtopic.php?f=5&t=5285
call {
def mCFP =
[
'AAC LC SBR PS' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC' : 'AAC',
'AC 3 Dep' : 'E-AC3',
'AC 3' : 'AC3',
'DTS 96 24' : 'DTS 96-24',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS ES XXCH' : 'DTS-ES',
'DTS ES' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS XLL X' : 'DTS X',
'DTS XLL' : 'DTS-HD MA',
'DTS' : 'DTS',
'E AC 3 JOC' : 'EAC3 Atmos',
'E AC 3' : 'EAC3',
'MLP FBA 16 ch' : 'TrueHD Atmos',
'MLP FBA' : 'TrueHD',
'MP3' : 'MP3',
'MPEG Audio' : 'MP2',
'PCM' : 'PCM'
];
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') };
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6/,'5.1').replaceAll(/8/,'7.1') };
def audioCollection = audio.collect
{ au ->
def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) };
def dynChannel = {au['NumberOfDynamicObjects'] + 'Obj'};
def ch = channels.tokenize('\\/').take(3)*.toDouble().inject(0, { a, b -> a + b }).findAll { it > 0 }.max().toString() + 'ch';
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] });
def format_profile = { ( au['Format_AdditionalFeatures'] != null) ? audioClean(au['Format_AdditionalFeatures']) : '' };
def combined = allOf{codec}{format_profile}.join(' ');
def stream = allOf { mCFP.get(combined, 'UNKNOWN_FORMAT--'+combined+'--') } { dynChannel } { ch };
};
return audioCollection[0].join( ' ' )
} +
'_'+
// Group
call{any{"$group"}{fn.match(/(?<=[_-])[^\s_-]+?$/)}{'NA'}.replaceAll(/[-_\[\]]\s*|\.\w{3}$/, '')};
// Language
def lang = call{any{'.'+lang}{lang}}+{fn.matches(/(?i).+sdh.+/) ? '_SDH' : ''}{any{fn.match(/(?i)\(foreignpartsonly\)/)}{''}};
// Extension
def ext = call{'.'+ext};
// Call all the bindings to create the result
(call(main_title).replace(':', ';') + call(lang)).replaceAll(/null/,'')
}[{runtime} Min]
Code: Select all
I:/Movies/{n}{' '+any{"[$certification]"}{"["+$imdb.certification+"]" }.replaceAll('N A','').replaceAll(/^ \d+$/, 'PG-$0')}{" [$rating" + "★]"}/
{
def space = call{' '};
def dir_root = 'I/Movies/'+
call{hd.matches(/(?i)SD/) ? '480p-720p/' : ' '}+
call{hd.matches(/(?i)HD/) ? '720p-1080p/' : ' '}+
call{hd.matches(/(?i)UHD/) ? '4k/' : ' '};
// Main Title e.g.
// 1408 (2007) (Director's Cut) 1080p HD Blu-ray non-HDR x264 DTS5.1ch_SiNNERS
// 300 (2007) 720p HD BRRip non-HDR x265 DTS 5.1ch_ESiR
// Deadpool (2016) 2160p UHD WEB-DL non-HDR AVC DTS-HD MA 7.1ch_DDR
// Deadpool 2 (2018) (Super Duper Cut) 2160p UHD Blu-ray REMUX HDR10bit ATEME TrueHD Atmos 13Obj 7.1ch_EPSiLON
def main_title = call{n}+
space + call{fn.matches(/(?i).+\b25th.+?anniv.+/) ? '(25th Anniv. Edition)' : ' '}+
space + call{fn.matches(/(?i).+\b\(limited\b.*?\).+/) ? '(Limited Edition)' : ' '}+
space + call{fn.matches(/(?i).+\b\(uncut\b.*?\).+/) ? '(Uncut)' : ' '}+
space + call{fn.matches(/(?i).+\bcollector.+?s.+?edition\b.+/) ? '(Collector\'s Edition)' : ' '}+
space + call{fn.matches(/(?i).+\bdirect.+?cut\b.+/) ? '(Director\'s Cut)' : ' '}+
space + call{fn.matches(/(?i).+\bextended.+?\b.+/) ? '(Extended)' : ' '}+
space + call{fn.matches(/(?i).+\bextended.+?edit\b.+/) ? '(Extended Edition)' : ' '}+
space + call{fn.matches(/(?i).+\bimax\b.+/) ? '(IMAX Edition)' : ' '}+
space + call{fn.matches(/(?i).+\blimited\b.+/) ? '(Limited)' : ' '}+
space + call{fn.matches(/(?i).+\bremastered\b.+/) ? '(Remastered)' : ' '}+
space + call{fn.matches(/(?i).+\bsuper.+duper.+cut\b.+/) ? '(Super Duper Cut)' : ' '}+
space + call{fn.matches(/(?i).+\btheatrical\b.+/) ? '(Theatrical)' : ' '}+
space + call{fn.matches(/(?i).+\bunrated\b.+/) ? '(Unrated)' : ' '}+
space + call{any{fn.match(/\([^\()+?[^\d]+?\)\s*/)} {' '}{' '}}+
space + '['+ call{self.vf ? self.vf : self.hpi}+
space + call{hd}+
space + call{source.matches(/(?i)blu.*ray/) ? 'BluRay' : {source} ?: 'WEB-DL'}+
space + call{fn.matches(/(?i).+\bremux\b.+/) ? 'REMUX' : ' '}+
space + call{fn.matches(/(?i).+\bwebrip\b.+/) ? 'WEBRip' : ' '}+
space + call{fn.matches(/(?i).+\bhevc.+?\b.+/) ? '(x265)' : ' '}+
space + call{fn.matches(/(?i).+\bx265\b.+/) ? '(x265)' : ' '}+
space + call{fn.matches(/(?i).+\b264\b.+/) ? '(x264)' : ' '}+
// Only calls {hdr} if it's not SD else non-HDR
space + call{if (hd =~ 'HD') {any{hdr + bitdepth + 'bit'}{'non-HDR'}}}+
space + call{vc}+
space +
// Call audio
// Thread here where I got the base code: https://www.filebot.net/forums/viewtopic.php?f=5&t=5285
call {
def mCFP =
[
'AAC LC SBR PS' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC' : 'AAC',
'AC 3 Dep' : 'E-AC3',
'AC 3' : 'AC3',
'DTS 96 24' : 'DTS 96-24',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS ES XXCH' : 'DTS-ES',
'DTS ES' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS XLL X' : 'DTS X',
'DTS XLL' : 'DTS-HD MA',
'DTS' : 'DTS',
'E AC 3 JOC' : 'EAC3 Atmos',
'E AC 3' : 'EAC3',
'MLP FBA 16 ch' : 'TrueHD Atmos',
'MLP FBA' : 'TrueHD',
'MP3' : 'MP3',
'MPEG Audio' : 'MP2',
'PCM' : 'PCM'
];
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') };
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6/,'5.1').replaceAll(/8/,'7.1') };
def audioCollection = audio.collect
{ au ->
def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) };
def dynChannel = {au['NumberOfDynamicObjects'] + 'Obj'};
def ch = channels.tokenize('\\/').take(3)*.toDouble().inject(0, { a, b -> a + b }).findAll { it > 0 }.max().toString() + 'ch';
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] });
def format_profile = { ( au['Format_AdditionalFeatures'] != null) ? audioClean(au['Format_AdditionalFeatures']) : '' };
def combined = allOf{codec}{format_profile}.join(' ');
def stream = allOf { mCFP.get(combined, 'UNKNOWN_FORMAT--'+combined+'--') } { dynChannel } { ch };
};
return audioCollection[0].join( ' ' )
} +
'_'+
space+
// Group
call{any{"$group"}{fn.match(/(?<=[_-])[^\s_-]+?$/)}{'NA'}.replaceAll(/[-_\[\]]\s*|\.\w{3}$/, '')};
// Language
def lang = call{any{'.'+lang}{lang}}+{fn.matches(/(?i).+sdh.+/) ? '_SDH' : ''}{any{fn.match(/(?i)\(foreignpartsonly\)/)}{''}};
// Extension
def ext = call{'.'+ext};
// Call all the bindings to create the result
(call(main_title).replace(':', ';') + call(lang)).replaceAll(/null/,'')
}[{runtime} Min]
Before:
D:/MakeMkv/The.Handmaids.Tale.S03E07.Under.His.Eye.1080p.HULU.WEBRip.AAC2.0.H264/The.Handmaids.Tale.S03E07.Under.His.Eye.1080p.HULU.WEB-DL.AAC2.0.H.264-NTb
After
I:/TV/The Handmaid's Tale [TV-MA] [8.9★]/Season 3/The Handmaid's Tale S03E07 - Under His Eye [1080p HD WEB-DL non-HDR AVC AAC 2.0ch_NTb[55 Min]
Before:
D:/MakeMkv/Rick and Morty S01 Season 1 1080p TrueHD [MAX Quality]/S01E02.Lawnmower.Dog.mkv
After:
I:/TV/Rick and Morty [TV-MA] [9.3★]/Season 1/Rick and Morty S01E02 - Lawnmower Dog [1080p HD non-HDR Microsoft TrueHD 5.1ch_NA[25 Min]
Before:
D:/MakeMkv/Stranger.Things.S01.2160p.BluRay.REMUX.HEVC.DD5.1-FGT/Stranger.Things.S01E01.Chapter.One.The.Vanishing.Of.Will.Byers.2160p.BluRay.REMUX.HEVC.DD5.1-FGT
After:
I:/TV/Stranger Things [TV-14] [9.2★]/Season 1/Stranger Things S01E01 - Chapter One; The Vanishing of Will Byers [2160p UHD BluRay REMUX (x265) non-HDR ATEME AC3 5.1ch_FGT[50 Min]
Code: Select all
space + call{fn.matches(/(?i).+\bhevc.+?\b.+/) ? '(x265)' : ' '}+
space + call{fn.matches(/(?i).+\bx265\b.+/) ? '(x265)' : ' '}+
space + call{fn.matches(/(?i).+\b264\b.+/) ? '(x264)' : ' '}+
Code: Select all
{'(' + any{vc.match(/x26[45]/)}{vc} + ')'}
Code: Select all
{n.replace(':','.').replace('?','!').replace('*','@')} -
{s00e00} -
{t.replace(':','.').replace('?','!').replace('*','@')}
[{"$vf, $vc, $af"},
{(audio.language)},
{text.language},
{airdate},
{source==null ? 'NA' : source},
{group==null ? 'NA' : group}]
Code: Select all
{audioLanguages.ISO2.joining('-', '(', ')')}
Code: Select all
(en-ja)
Code: Select all
{any{source}{'NA'}}
Code: Select all
NA
but this returns nothing
rednoah wrote: ↑14 Dec 2019, 21:32 1.Code: Select all
{audioLanguages.ISO2.joining('-', '(', ')')}
Code: Select all
(en-ja)
Code: Select all
{n} - {'s'+s.pad(2)}{'e'+e.pad(2)}{episode.special ? ('s00e'+special.pad(2)) : null } - {t}
please set user varsformat expression wrote: /path/to/media/tv/or/movies/{plex.derive{' ['}{allOf{vf}{vs}{vc}{ac}{hdr}.join(' ').lower()}{' '+fn.matchAll(/proper|repack|rerip/).join('.').lower()}{']-'}{group}.tail}
deluge-postprocess.sh wrote: #!/bin/sh -xu
# plex compatiable filebot rename script w/ extra quality info
# TV: /path/to/media/tv/Firefly/Season 01/Firefly - S01E01 - Serenity [1080p web-dl avc eac3 repack]-NTG.mkv
# MOVIES: /path/to/media/movies/Avatar (2009)/Avatar (2009) [1080p bluray x264 dts]-EVO.mkv
# Input Parameters
ARG_PATH="$3/$2"
ARG_NAME="$2"
ARG_LABEL="N/A"
ARG_SAVE_PATH="$3"
# user vars
movie_dl_dir="flexget-mv" # where deluge downloads movies to (must be different from tv_dl_dir)
tv_dl_dir="flexget-tv" # where deluge downloads tv to (must be different from movie_dl_dir)
exclude_list="/home/ivagsjw/logs/amc.excludes" # this is required or u will get banned. it stores previously processed file list
log_file="/home/ivagsjw/logs/amc.log"
files_out_movies="/data/ivagsjw/f/media/movies"
files_out_tv="/data/ivagsjw/f/media/tv"
files_out_base="/data/ivagsjw/f/media" # base of your media folder with tv and movies dest folder (for fixing chmod permissions)
#### end user vars ###
# check movie or tv
what_label=Series
if [ $(basename "$ARG_SAVE_PATH") = "$movie_dl_dir" ]
then
what_label=Movie
fi
if [ $(basename "$ARG_SAVE_PATH") = "$tv_dl_dir" ] || [ $(basename "$ARG_SAVE_PATH") = "$movie_dl_dir" ]
then
/usr/bin/filebot -script fn:amc --conflict skip --action hardlink -non-strict --log-file "$log_file" --def clean=y ut_dir="$ARG_PATH" ut_kind="multi" ut_title="$ARG_NAME" ut_label="$what_label" "exec=chmod -R a+rwX,o-w $files_out_base" deleteAfterExtract=n excludeList="$exclude_list" movieFormat="$files_out_movies/{plex.derive{' ['}{allOf{vf}{vs}{vc}{ac}{hdr}.join(' ').lower()}{' '+fn.matchAll(/proper|repack|rerip/).join('.').lower()}{']-'}{group}.tail}" seriesFormat="$files_out_tv/{plex.derive{' ['}{allOf{vf}{vs}{vc}{ac}{hdr}.join(' ').lower()}{' '+fn.matchAll(/proper|repack|rerip/).join('.').lower()}{']-'}{group}.tail}"
fi
Code: Select all
E:/{fn =~ /3D/ ? 'Films 3D' : 'Films'}/{norm = {it.upperInitial().replaceTrailingBrackets().replaceAll(/[`´‘’ʻ""“”]/, "'").replaceAll(/[:|]/, " - ").replaceAll(/[?]/, "!").replaceAll(/[*\s]+/, " ").replaceAll(/\b[IiVvXx]+\b/, { it.upper() }).replaceAll(/\b[0-9](?i:th|nd|rd)\b/, { it.lower() })}; {info.OriginalLanguage != /en/ ? norm(n) : norm(primaryTitle)}}{info.OriginalName != n && ! (info.OriginalLanguage ==~ /(en|fr)/) ? ' ('+norm(primaryTitle)+')' :""}{fn.contains('3D') || fn.contains('3-D') ? ' '+'3D':""} ({y}){' ['+vf.match(/720[pP]|1080[pP]/)+']'}{video.CodecID =~ /hev1|hevc|HEVC/ ? ' [HEVC]' : ''}/{info.OriginalLanguage != /en/ ? norm(n) : norm(primaryTitle)}{info.OriginalName != n && ! (info.OriginalLanguage ==~ /(en|fr)/) ? ' ('+norm(primaryTitle)+')' :""}{fn.contains('3D') || fn.contains('3-D') ? ' '+'3D':""} ({y}){' [' + fn.matchAll(/UNCENSORED|UNRATED|REMASTERED|EXTENDED|UNCUT|DIRECTOR\'?S[ ._-]CUT|THEATRICAL[ ._-]CUT|ULTIMATE[ ._-]CUT|FINAL[ ._-]CUT|SPECIAL[ ._-]EDITION/)*.upper().sort().join(' ').replaceAll(/[.]/, " ") + ']'}{' ['+vs.match(/BluRay/)+']'}{' ['+vf.match(/720[pP]|1080[pP]/)+']'}{video.CodecID =~ /hev1|hevc|HEVC/ ? ' [HEVC]' : ''}{if (bitdepth == 10) ' [10bit]'}{if (af == (/6ch/)) ' [5.1]'}{" CD$pi"}{'.'+lang}{if (dc > 1) " ($di)"}
Still trying to figure out having collections and movies with a single expressionE:/Films/E.T. The Extra-Terrestrial (1982) [1080p]/E.T. The Extra-Terrestrial (1982) [BluRay] [1080p] [5.1]
E:/Films/Entre Les Murs (2008)/Entre Les Murs (2008)
E:/Films/Four Weddings And A Funeral (1994) [1080p] [HEVC]/Four Weddings And A Funeral (1994) [REMASTERED] [BluRay] [1080p] [HEVC] [10bit] [5.1]
E:/Films/Four Weddings And A Funeral (1994) [1080p] [HEVC]/Four Weddings And A Funeral (1994) [REMASTERED] [BluRay] [1080p] [HEVC] [10bit] [5.1].eng (1)
E:/Films/Four Weddings And A Funeral (1994) [1080p] [HEVC]/Four Weddings And A Funeral (1994) [REMASTERED] [BluRay] [1080p] [HEVC] [10bit] [5.1].eng (2)
E:/Films 3D/How To Train Your Dragon 3D (2010) [1080p]/How To Train Your Dragon 3D (2010) [BluRay] [1080p] [5.1]
Code: Select all
{['F:', 'G:', 'I:', 'J:', 'L:', 'V:', 'W:', 'Y:'].collect{ (it+'/Movies') as File }.sort{ a, b -> a.exists() <=> b.exists() ?: a.diskSpace <=> b.diskSpace }.last()} ({vf})\{n} ({y}){' ['+fn.replaceAll(/(?i)directors|theatrical|ultimate/,'$0 Cut').matchAll(/OPEN.MATTE|UNRATED|REMASTERED|EXTENDED|UNCUT|DIRECTORS.CUT|THEATRICAL.CUT|ULTIMATE.CUT|SPECIAL.EDITION/).join('][').upperInitial().lowerTrail()+']'} [{vf}] [{ac}{fn.match("-HD.MA.")+af}]/{n} ({y}) {vc}{" (CD$pi)"}{' '+lang}
Code: Select all
Movie Categorie\Name in french (year) - (director) (VO name if different from french) [Languages] [Resolution, video code, audio codec]
Code: Select all
Films/renamed/{any{genres[0]}{"Unknown"}}/
{any{localize.fr.n}{n}}
{(pn >= 2) ? " cd$pi" : ""}
{"($y)"}
- {"($director)"}
{localize.fr.n == primaryTitle ? "" : "(${primaryTitle})"}
{"[${fn.lower().match(/- fr|- vostfr|- multi|\[fr\]|\[vostfr\]|\[multi\]|multi|vostfr/).replace('- ', '')}]"}
{allOf{"$vf"}{"$vc"}{"$ac"}}
Code: Select all
The.Invisible.Man.2020.MULTi.TRUEFRENCH.1080p.HDLight.x264.AC3-EXTREME.mkv
Code: Select all
renamed\Thriller\Invisible Man (2020) - (Leigh Whannell) (The Invisible Man) [multi] [1080p, x264, AC3]
Code: Select all
TV show\TV Show Season Number\TV Show - SxE - Episode name [languages] [resolution] [codes]
Code: Select all
Renamed/{n}/{n} Saison {s.pad(2)}/{n} - {sxe} - {t} {"[vostfr]"} {"[$vf]"} {allOf{"$vc"}{"$ac"}}
Code: Select all
Brooklyn.Nine-Nine.S07E01.MULTi.720p.WEB.H264-CiELOS.mkv
Code: Select all
Renamed\Brooklyn Nine-Nine\Brooklyn Nine-Nine Saison 07\Brooklyn Nine-Nine - 7x01 - Manhunter [vostfr] [720p] [AVC, AAC].mkv
Code: Select all
{any{textLanguages =~ /fra/ ? 'vostfr' : ''}{fn.match(/VOSTFR|Vostfr|vostFR|VostFR|vostfr/).lower()}}
Code: Select all
'<>:"/\\|?*'.replace(
'<' : '﹤',
'>' : '﹥',
':' : 'ː',
'"' : '“',
'/' : '⁄',
'|' : '⼁',
'?' : '?',
'*' : '﹡',
'\\': '∖'
)
My groovy format file now uses the raw value like this, and I always manually check the result as inbuilt checks are bypassed:Top-level bindings such as {t} strip / slash implicitly, among other sanitation operations. However, you can use {episode.title} to access the raw value, which may contain / slash, may be infinitely long, etc.
Code: Select all
{sxe} {episode.title.replace(
'<' : '﹤',
'>' : '﹥',
':' : 'ː',
'"' : '“',
'/' : '⁄',
'|' : '⼁',
'?' : '?',
'*' : '﹡',
'\\': '∖'
)}