
The best solution is to have Transmission call FileBot on completed downloads. Here's the setup instructions for that:
viewtopic.php?f=4&t=215#p3380
Please give me 1 or more example file names / paths I can test with.
Code: Select all
\b(DVD|DVD5|DVD9|DVDRip)\b
Code: Select all
cd "D:\Google Download Stuff\Series\"
get-childItem 'D:\Google Download Stuff\Series\*.mp4' | filebot -non-strict -rename '*' --db TheTVDB --conflict auto --filter "'s' - 'e'" --format 'D:/Google Download Stuff/Media/Series/{plex[1]} ({y})/Season {s}/{plex.name}' --output 'By Series' --mode interactive
cd "D:\Google Download Stuff\Movies\"
<This section>
get-childItem 'D:\Google Download Stuff\Movies\*.mp4'| filebot -non-strict -rename '*' --mode interactive --db TheMovieDB --conflict auto --format 'D:/Google Download Stuff/Media/Movies/{n0 = n.charAt(0); n0.isDigit() ? "0-9" : n0}/{plex[1]}/{plex.name}' --output 'By First Letter'
</This section>
pause
Code: Select all
D:\Google Download Stuff>PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& 'D:\Google Download Stuff\Scripts\Move.ps1'"
<Ignore this, Series folder is empty>
Illegal Argument: java.nio.file.InvalidPathException: Illegal char <*> at index 0: * (*)
Rename episodes using [TheTVDB]
No media files: [*]
Failure (°_°)
</Ignore this, Series folder is empty>
Rename movies using [TheMovieDB]
Auto-detect movie from context: [D:\Google Download Stuff\Movies\Red Dawn.mp4]
[MOVE] from [D:\Google Download Stuff\Movies\Red Dawn.mp4] to [D:\Google Download Stuff\Media\Movies\R\Red Dawn (1984)\R
ed Dawn (1984).mp4]
Processed 1 files
Press Enter to continue...:
Code: Select all
filebot -rename --db TheMovieDB *.mp4 --filter "y > 2000"
Code: Select all
Rename movies using [TheMovieDB]
Auto-detect movie from context: [Red Dawn.mp4]
Apply filter [y > 2000] on [12] items
Include [Red Dawn (2012)]
Include [Red Dawn (2011)]
Include [Red (2008)]
Include [Red (2002)]
Include [RED (2010)]
Include [Rockin' at the Red Dog: The Dawn of Psychedelic Rock (2005)]
Include [Assembly (2007)]
[MOVE] from [Red Dawn.mp4] to [Red Dawn (2012).mp4]
Processed 1 files
Code: Select all
{
def sPath = "";
def mHDRCol = ["BT.709" : "NO", "BT.2020" : "YES"];
def mWebSrc = ["AMZN" : "AMZN", "NF" : "NF", "HBO" : "HBO"];
def hiResPath = "";
boolean isHDR = false;
if(self.video[0].bitdepth != null && self.bitdepth >= 10 && self.video[0].colourprimaries != null && mHDRCol.get(self.video[0].colourprimaries) == "YES") isHDR = true;
if(vf =~ /2160p/) hiResPath = '4k/' + video[0].Format.replace('AVC', 'x264').replace('HEVC', 'x265');
if(isHDR == true){ hiResPath += "(HDR)/" } else {hiResPath += "/"};
def VInfo = " - (FI " + vf + " ";
mWebSrc.any { k, v -> if(f.toString().contains(k)) VInfo += v + " "};
if(self.source =~ 'Remux') VInfo += fn.match(/BluRay/) else if(self.source != null) VInfo += self.source;
VInfo += " [" + video[0].Format.replace('AVC', 'x264').replace('HEVC', 'x265');
VInfo += " ";
if(isHDR == true) VInfo += " HDR " + self.bitdepth + "bit ";
if(isHDR == true && self.video[0].colourprimaries != null) VInfo += self.video[0].colourprimaries.replace(".","") + " ";
VInfo += "]";
sPath + hiResPath + plex + VInfo;
}
{def ADef = 0;
def ADefScore = 100;
def ACurrent = 100;
def ABest = 100;
def ABestIndex;
def ACnt = audio.size;
def iCnt = 0;
//map of scoring, Codec + FormatProfile with '+' and '/' stripped
def mAudioScore =[
"DTS-HDXMACore" : 10, "DTS-HDMACore" : 20, "DTS-HDMAES MatrixCore" : 20, "DTSES DiscreteCore" : 25, "DTS" : 30, "DTS-HDHRACore" : 25,
"TrueHDTrueHDAtmosTrueHD" : 10, "TrueHD" : 18,
"AC3" : 30, "AC3+" : 20, "AAC" : 50, "AAC LCLC" : 45, "AAC LC-SBRHE-AACLC" : 40,
"MPA1L3Layer 3" : 60, "MPA1L2Layer 2" : 70,
"Vorbis" : 65,
"PCM" : 90, "Qclp" : 90, "161" : 90];
//map of Codec + FormatProfile made nice for file name
def mAFP = [
"DTS-HDXMACore" : "DTS-HDMA(DTS-X)", "DTS-HDMACore" : "DTS-HDMA", "DTS" : "DTS", "DTS-HDMAES MatrixCore" : "DTS-HDMA", "DTSES DiscreteCore" : "DTS-ES", "DTS-HDHRACore" : "DTS-HDHRA",
"TrueHDTrueHDAtmosTrueHD" : "TrueHD(Atmos)", "TrueHD" : "TrueHD",
"AC3" : "AC3", "AC3+" : "DDP",
"AAC LCLC" : "AAC",
"MPA1L3Layer 3" : "MP3", "MPA1L2Layer 2" : "MP2",
"PCM" : "PCM", "Qclp" : "Qclp", "161" : "161"];
//map of Audio Channels(minus the slash) to pretty name
def mACH = [
"Object Based10" : "OB+10Ch",
"Object Based8" : "OB+8Ch", "Object Based86" : "OB+8Ch",
"Object Based6" : "OB+6Ch",
"Object Based" : "OBCh",
"9" : "9Ch",
"8" : "8Ch", "86" : "8Ch", "876" : "8Ch",
"7" : "7Ch", "76" : "7Ch",
"6" : "6Ch",
"5" : "5Ch",
"4" : "4Ch", "3" : "3Ch", "2" : "2Ch", "1" : "1Ch" ];
//Intermederia used to make finding missing strings from the maps
def CmACH = { if(mACH.get(it) != null) mACH.get(it) else " (mACH:" + it + " NOT FOUND)"};
def CmAFP = { if(mAFP.get(it) != null) mAFP.get(it) else " (mAFP:" + it + " NOT FOUND)"};
def CmAudioScore = { if(mAudioScore.get(it) != null) mAudioScore.get(it) else " (mAudioScore:" + it + " NOT FOUND)"};
//simple functions for creating audio text for file name
def GetFPSafe = {if(self.audio[it].FormatProfile != null) audio[it].FormatProfile.slash('').replace("+","") else ""};
//def GetAText = {mAFP.get( audio[it].codec + GetFPSafe(it)) + " " + mACH.get( audio[it].channels.slash('') ) };
def GetAText = {CmAFP( audio[it].codec + GetFPSafe(it)) + " " + CmACH( audio[it].channels.slash('') ) };
//Get index # that the default audio is using (only expecting 1 default audio)
audio.eachWithIndex{ a, idx -> if(call{a.default} == "Yes") ADef = idx};
//Get score for default audio
ADefScore = CmAudioScore(self.audio[ADef].codec + GetFPSafe(ADef))
//ADefScore = 50; //for your testing
//Check all audio streams, rank them against one another, get best score
for (iCnt = 0; iCnt < ACnt; iCnt++){
ACurrent = CmAudioScore(self.audio[iCnt].codec + GetFPSafe(iCnt))
if(ACurrent != null && ACurrent.toInteger() < ABest) ABestIndex = iCnt;
if(ACurrent != null && ACurrent.toInteger() < ABest) ABest = ACurrent.toInteger();
};
//end
if(ADefScore.toInteger() == ABest) GetAText(ABestIndex) + ")" else GetAText(ADef) + " [BA " + GetAText(ABestIndex) + "]" + ")";
}
Code: Select all
{
def mHDRCol = ["BT.709" : "NO", "BT.2020" : "YES"];
if(bitdepth >= 10 && mHDRCol.get(self.video[0].colourprimaries) == "YES" ) '(HDR)/' else '(NonHDR)/';
}
and extraDTS-HDMA (mACH:86 NOT FOUND))
here is my audio format:+ ")"
Code: Select all
{
def ChannelString = any{(0.0+audio.'ChannelPositionsString2'*.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')*.split(' / ')*.collect{ it.split('/')*.toBigDecimal().sum() }*.max().max()).toString()}{channels};
def codecSubVersion = any{audio.any{ a -> call{a.FormatProfile} =~ 'HRA' } ? '.HRA' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'MA / Core' } ? '.MA' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'ES Matrix / Core' } ? '-ES' : null}{null};
def codecVersion = any{audio.Codec.join().match(/DTS-HD/)+codecSubVersion+'.'+audio.Codec.join().match(/TrueHD/)}{audio.Codec.join().match(/DTS-HD/)+codecSubVersion}{audio.Codec.join().match(/TrueHD/)}{audio.Codec.join().match(/DTS/)+codecSubVersion.replaceAll(/null/)}{ac};
(allOf{'.'+codecVersion.replaceAll(/null/)}
{if( ((ac == 'AAC'||ac == 'MP3') && (channels != '2.0' || ChannelString != channels) ) || ( (ac == 'AC3'||ac == 'DTS'||ac == 'TrueHD') && (channels != '5.1' || ChannelString != channels) ) ) return {any{ChannelString}{channels}}}
{aco.match(/Atmos/)}).join('.')
}
Code: Select all
//map of scoring, Codec + FormatProfile with + and / stripped
def mAudioScore =[ "DTS-HDXMACore" : 10, "DTS-HDMACore" : 20, "DTS" : 30, "TrueHDTrueHDAtmosTrueHD" : 10, "TrueHD" : 18, "AC3" : 40, "AAC" : 50, "AAC LCLC" : 50, "MPA1L3Layer 3" : 60,"MPA1L2Layer 2" : 70];
//map of Codec + FormatProfile made nice for file name
def mAFP = [ "DTS-HDXMACore" : "DTS-HDMA(DTS-X)", "DTS-HDMACore" : "DTS-HDMA", "DTS" : "DTS", "TrueHDTrueHDAtmosTrueHD" : "TrueHD(Atmos)", "TrueHD" : "TrueHD", "AC3" : "AC3", "AAC LCLC" : "AAC", "MPA1L3Layer 3" : "MP3", "MPA1L2Layer 2" : "MP2" ];
//map of Audio Channels(minus the slash) to pretty name
def mACH = [ "Object Based10" : "OB+10Ch", "Object Based8" : "OB+8Ch", "Object Based86" : "OB+8Ch", "Object Based6" : "OB+6Ch", "Object Based" : "OBCh", "9" : "9Ch", "8" : "8Ch", "86" : "8Ch", "7" : "7Ch", "6" : "6Ch", "5" : "5Ch", "4" : "4Ch", "3" : "3Ch", "2" : "2Ch", "1" : "1Ch" ];
Code: Select all
if(self.video[0].bitdepth != null && self.bitdepth == 10 && self.video[0].colourprimaries != null && mHDRCol.get(self.video[0].colourprimaries) == "YES") isHDR = "YES";
Yours works well with my Atmos and everything else but it does not identify the other object based format, DTS-X.
Code: Select all
{
def ChannelString = any{(0.0+audio.'ChannelPositionsString2'*.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')*.split(' / ')*.collect{ it.split('/')*.toBigDecimal().sum() }*.max().max()).toString()}{channels};
def codecSubVersion = any{audio.any{ a -> call{a.FormatProfile} =~ 'HRA' } ? '.HRA' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'X / MA / Core' } ? '.X' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'MA / Core' } ? '.MA' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'ES Matrix / Core' } ? '-ES' : null}{null};
def codecVersion = any{audio.Codec.join().match(/DTS-HD/)+codecSubVersion+'.'+audio.Codec.join().match(/TrueHD/)}{audio.Codec.join().match(/DTS-HD/)+codecSubVersion}{audio.Codec.join().match(/TrueHD/)}{audio.Codec.join().match(/DTS/)+codecSubVersion.replaceAll(/null/)}{ac};
(allOf{'.'+codecVersion.replaceAll(/null/)}
{if( ((ac == 'AAC'||ac == 'MP3') && (channels != '2.0' || ChannelString != channels) ) || ( (ac == 'AC3'||ac == 'DTS'||ac == 'TrueHD') && (channels != '5.1' || ChannelString != channels) ) ) return {any{ChannelString}{channels}}}
{aco.match(/Atmos/)}).join('.')
}
Code: Select all
{
def ChannelString = any{(0.0+audio.'ChannelPositionsString2'*.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')*.split(' / ')*.collect{ it.split('/')*.toBigDecimal().sum() }*.max().max()).toString()}{channels};
def codecSubVersion = any{audio.any{ a -> call{a.FormatProfile} =~ 'HRA' } ? '.HRA' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'X / MA / Core' } ? '-X' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'MA / Core' } ? '.MA' : null}{audio.any{ a -> call{a.FormatProfile} =~ 'ES Matrix / Core' } ? '-ES' : null}{null};
def codecVersion = any{audio.Codec.join().match(/DTS-HD/)+codecSubVersion+'.'+audio.Codec.join().match(/TrueHD/)}{audio.Codec.join().match(/DTS-HD/) && codecSubVersion == '-X' ? 'DTS-X' : null}{audio.Codec.join().match(/DTS-HD/)+codecSubVersion}{audio.Codec.join().match(/TrueHD/)}{audio.Codec.join().match(/DTS/)+codecSubVersion.replaceAll(/null/)}{ac};
(allOf{'.'+codecVersion.replaceAll(/null/)}
{if( ((ac == 'AAC'||ac == 'MP3') && (channels != '2.0' || ChannelString != channels) ) || ( (ac == 'AC3'||ac == 'DTS'||ac == 'TrueHD') && (channels != '5.1' || ChannelString != channels) ) ) return {any{ChannelString}{channels}}}
{aco.match(/Atmos/)}).join('.')
}
it still use this to lookup movieDTS-MA.5.1
also what about 1, 4 and 8ch + DTS-ES, DTS-HD-HRA and DTS-X + without separator e.g. DTSHD ?+5+1
if so change to something like this:[12457][.]?[01]
to [12457]\.[01]
this is how filebot see it, yes (with the \b) ?\b(FLAC|AAC|AC3|MP3|MP4|DTS|DD|TrueHD|Atmos)(.?HD)?(.?ES|.?MA|.?X|.?HRA)?(.?[12457]\.[01])?\b|\b[12468]ch\b
[M0]?(720|1080)[pi]
test on:\b(FLAC|AAC|AC3|MP3|MP4|DTS|DD[P+]?|TrueHD|Atmos)(.?HD)?(.?ES|.?MA|.?X|.?HRA)?(.?[124567][.]?[01])?\b|\b[124678]ch\b|\b[2|3]?Audio\b|\bDualAudio\b
NEW:some.movie.2000.DTS.MA.5.1
some.movie.2000.DTS.MA.7.1
some.movie.2000.DTS.MA.6ch
some.movie.2000.DTS-HD.MA.5.1
some.movie.2000.DTS-HD.MA.7.1
some.movie.2000.DTS-HD.MA.6ch
some.movie.2000.DTS-HD.MA.8ch
some.movie.2000.DTSHDMA.5.1
some.movie.2000.DTSHDMA.7.1
some.movie.2000.DTS-X.5.1
some.movie.2000.DTS-X.7.1
some.movie.2000.DTS-X.6ch
some.movie.2000.DTS-X.8ch
some.movie.2000.DTS-HD-HRA.7.1
some.movie.2000.DTS-ES.6.1
some.movie.2000.DTS.1.0
some.movie.2000.DTS.2.0
some.movie.2000.DTS.5.1
some.movie.2000.DTS.6.1
some.movie.2000.DTS.7.1
some.movie.2000.DTS.1ch
some.movie.2000.DTS.2ch
some.movie.2000.DTS.6ch
some.movie.2000.DTS.7ch
some.movie.2000.DTS.8ch
some.movie.2000.DTS
some.movie.2000.DTSMA.2Audio
some.movie.2000.DTS.Audio
some.movie.2000.Dtshd Audio
some.movie.2000.Dts Dualaudio
some.movie.2000.DTSES6.1.3Audio
some.movie.2000.AC3.2Audio
some.movie.2000.FLAC.DD51.DualAudio
some.movie.2000.TrueHD.5.1
some.movie.2000.TrueHD.7.1
some.movie.2000.TrueHD.Atmos.5.1
some.movie.2000.TrueHD.Atmos.7.1
some.movie.2000.DTS-HD.TrueHD.7.1.Atmos
some.movie.2000.AC3.1.0
some.movie.2000.AC3.2.0
some.movie.2000.AC3.4.0
some.movie.2000.AC3.5.1
some.movie.2000.AC3.1ch
some.movie.2000.AC3.2ch
some.movie.2000.AC3.4ch
some.movie.2000.AC3.6ch
some.movie.2000.DD.1.0
some.movie.2000.DD.2.0
some.movie.2000.DD.4.0
some.movie.2000.DD.5.1
some.movie.2000.DDP.1.0
some.movie.2000.DDP.2.0
some.movie.2000.DDP.4.0
some.movie.2000.DDP.5.1
some.movie.2000.DD+.1.0
some.movie.2000.DD+.2.0
some.movie.2000.DD+.4.0
some.movie.2000.DD+.5.1
some.movie.2000.DDP1.0
some.movie.2000.DDP2.0
some.movie.2000.DDP4.0
some.movie.2000.DDP5.1
some.movie.2000.DD.5.1
some.movie.2000.DD.7.1
some.movie.2000.MP3.1.0
some.movie.2000.AAC.5.1