patternshellMinor
Normalize video filenames and move files to destination directory
Viewed 0 times
normalizedestinationdirectoryvideomovefilesandfilenames
Problem
I have written a powershell script that will scan a directory for any
-
If Name exists (if not create it)
-
If season number exists (if not create it)
-
Once both these checks have been performed move the file to the destination dir
This syntax works for my purpose, but it is slow... I am lower than a beginner when it comes to powershell (is there such a thing?) - And would like any helpful hints or code mods that the more experienced programmers can provide.
```
$fileDirectory = "C:\Test\"
foreach ($file in Get-ChildItem $fileDirectory | where {($_.extension -eq '.mkv') -or ($_.extension -eq '.avi') -or ($_.extension -eq '.mp4')}){
#Setting parent dir to check
$ParentDir = "\\C:\TV Shows\"
#setting param to split
$parts =$file.Name -split '\.'
#capturing variables
$ShowName = $parts[0].Trim()
$SeasonNumber = $parts[1].substring(0,3)
$EpisodeNumber = $parts[1].substring(3,3)
#Converting numeric season value to text
switch ($SeasonNumber){
S01
{
$SeasonNumber = "Season 01";
break
}
S02
{
$SeasonNumber = "Season 02"
break
}
S03
{
$SeasonNumber = "Season 03"
break
}
S04
{
$SeasonNumber = "Season 04"
break
}
S05
{
$SeasonNumber = "Season 05"
break
}
S06
{
$SeasonNumber = "Season 06"
break
}
S07
{
$SeasonNumber = "Season 07"
break
}
S08
{
$SeasonNumber = "Season 08"
break
}
S09
{
$SeasonNumber = "Season 09"
break
}
S10
{
$SeasonNumber = "Season 10"
break
}
default {"Something else happened"; break}
}
#Setting path variables
$ShowDir =
mkv, .mp4, *.avi files, and will parse the filename to get Name, Season Number, Episode number. Then will check against destination directory to determine-
If Name exists (if not create it)
-
If season number exists (if not create it)
-
Once both these checks have been performed move the file to the destination dir
This syntax works for my purpose, but it is slow... I am lower than a beginner when it comes to powershell (is there such a thing?) - And would like any helpful hints or code mods that the more experienced programmers can provide.
```
$fileDirectory = "C:\Test\"
foreach ($file in Get-ChildItem $fileDirectory | where {($_.extension -eq '.mkv') -or ($_.extension -eq '.avi') -or ($_.extension -eq '.mp4')}){
#Setting parent dir to check
$ParentDir = "\\C:\TV Shows\"
#setting param to split
$parts =$file.Name -split '\.'
#capturing variables
$ShowName = $parts[0].Trim()
$SeasonNumber = $parts[1].substring(0,3)
$EpisodeNumber = $parts[1].substring(3,3)
#Converting numeric season value to text
switch ($SeasonNumber){
S01
{
$SeasonNumber = "Season 01";
break
}
S02
{
$SeasonNumber = "Season 02"
break
}
S03
{
$SeasonNumber = "Season 03"
break
}
S04
{
$SeasonNumber = "Season 04"
break
}
S05
{
$SeasonNumber = "Season 05"
break
}
S06
{
$SeasonNumber = "Season 06"
break
}
S07
{
$SeasonNumber = "Season 07"
break
}
S08
{
$SeasonNumber = "Season 08"
break
}
S09
{
$SeasonNumber = "Season 09"
break
}
S10
{
$SeasonNumber = "Season 10"
break
}
default {"Something else happened"; break}
}
#Setting path variables
$ShowDir =
Solution
Get-ChildItem -include .ext1, .ext2instead ofWhere
- Use pipelining via
|(in direct fashion, that is without storing the results in intermediate variables) instead offoreachstatement so that the processing starts immediately without waiting for the entire directory to be enumerated first (or use the advanced method of non-blocking IO.DirectoryInfo enumeration in a foreach statement).
Join-Path 'dir' *to construct the path for Get-ChildItem instead of relying on the trailing backslash
-LiteralPathinstead of-Path, otherwise PowerShell will fail on paths that contain square brackets as it treats[]as a wildcard specifier.
- string concatenation instead of
switch
And my personal preferences:
- Use regex to split the file name - it'll make the structure more obvious (if you know regex)
- Use
mkdirinstead ofNew-Item -ItemType Directory(I think it's overly verbose to the point of being obfuscatingly so)
- Simply create the directory without checking its existence: the operating system does it anyway, and the code is less "noisy" this way.
$fileDirectory = "C:\Test"
$ParentDir = "c:\TV Shows"
Join-Path $fileDirectory * | Get-ChildItem -include *.mkv, *.avi, *.mp4 | ForEach {
if ($_.BaseName -notmatch '^\s*(.*?)\s*\.S(\d\d)E(\d\d)') {
return
# return is used because we're in a function-like ScriptBlock context
}
$ShowDir = Join-Path $ParentDir ($matches[1])
$SeasonDir = Join-Path $ShowDir ('Season ' + $matches[2])
# $matches is an internal object set automatically by -match or -notmatch operator
mkdir $ShowDir -Force >$null
mkdir $SeasonDir -Force >$null
# mkdir outputs the directory object so we ignore it
Move -LiteralPath $_.FullName -Destination $SeasonDir
}Code Snippets
$fileDirectory = "C:\Test"
$ParentDir = "c:\TV Shows"
Join-Path $fileDirectory * | Get-ChildItem -include *.mkv, *.avi, *.mp4 | ForEach {
if ($_.BaseName -notmatch '^\s*(.*?)\s*\.S(\d\d)E(\d\d)') {
return
# return is used because we're in a function-like ScriptBlock context
}
$ShowDir = Join-Path $ParentDir ($matches[1])
$SeasonDir = Join-Path $ShowDir ('Season ' + $matches[2])
# $matches is an internal object set automatically by -match or -notmatch operator
mkdir $ShowDir -Force >$null
mkdir $SeasonDir -Force >$null
# mkdir outputs the directory object so we ignore it
Move -LiteralPath $_.FullName -Destination $SeasonDir
}Context
StackExchange Code Review Q#155022, answer score: 5
Revisions (0)
No revisions yet.