I have some files like this
Hooligans (BDrip (1080).mkv
Hocus Pocus [DIVX - ITA] - Walt Disney - HQ-.avi
Ho Cercato Il Tuo Nome h265.avi
Ho Cercato Il Tuo Nome 720.rar
Halloween 2 - Il Signore Della Morte.avi
Highlander 2 1080p.mkv
Heartbreakers - Vizio di famiglia.avi
Il cavaliere oscuro.mkv
Il cavaliere oscuro - il ritorno 1080p.mkv
In the same directory I have a text file (movielist.txt
) that is formatted always in this way: name year.
Year is always from 19**-20**
and is inside brackets
Hooligans (1995)
Hocus Pocus (1993)
Ho cercato il tuo nome (2012)
Halloween 2 – Il signore della morte (1981)
Highlander 2 – Il ritorno (1990)
Heartbreakers – Vizio di famiglia (2001)
Il cavaliere oscuro (2008)
Il cavaliere oscuro - Il ritorno (2012)
... other text
I try to rename files so:
Hooligans (1995).mkv
Hocus Pocus (1993).avi
Ho cercato il tuo nome (2012).avi
Ho cercato il tuo nome (2012).rar
Halloween 2 – Il signore della morte (1981).avi
Highlander 2 – Il ritorno (1990).mkv
Heartbreakers – Vizio di famiglia (2001).avi
Il cavaliere oscuro (2008).mkv
Il cavaliere oscuro - il ritorno (2012).mkv
Note: the number of files to be renamed is not the same as the number of lines in the text file. In the text file there can be 100 lines while the number of files to rename could be 50.
There are two ways to do but are insufficient to perform that I request
1st
$movieList = Get-Content movielist.txt
# enumerate all movies
:outer foreach($file in Get-ChildItem "C:\Users\Peter\Desktop\test skript\test2" -File) {
$bn = $file.BaseName
# enumerate all lines of the movies to rename file
foreach($movie in $movieList) {
# if the Base Name is contained in the movie to rename, ie:
# 'Young Devils (1999)' -like '*young Devils*'
if($movie -like "*$bn*") {
# rename the file using the movie the file's extension, ie:
# Young Devils (1999) .mkv
Rename-Item -LiteralPath $file.FullName -NewName ($movie $file.Extension)
# no need to keep comparing this file, if we're here
# we can continue with next file
continue outer
}
}
}
2nd:
$rootFolder = "C:\Users\Peter\Desktop\test skript\test1"
$files = Get-ChildItem -Path $rootFolder -File
$filesNames = Get-Content -Path "$rootFolder\movielist.txt"
foreach ($name in $filesNames)
{
$files | Where-Object -FilterScript {
$name -match [Regex]::Escape($_.BaseName)
} | ForEach-Object -Process {
$ext = $_.Extension
Rename-Item -LiteralPath $_.FullName -NewName "$name$ext" -EA 0
}
}
Any idea on how to rename the files of my example?
CodePudding user response:
I took the liberty of using your long lists of files and 'movielist.txt' from your previous question, because in there it shows there are lots of extra characters in the names that complicate things..
Not only the (year)
in the desired names, but also some files have dots instead of spaces in their names, non-ascii hyphens (en-dashes) etc.
To do what you want you will need to
- create a title Hashtable to store the actual value from the movielist.tst file as value, but also have a cleaned-up version of that to do the comparison with
- extend each FileInfo object in the files array with an extra property (I call 'SearchName') that stores a cleaned-up version of the actual file's BaseName to compare against.
$titles = Get-Content -Path 'D:\Test\movielist.txt' -Encoding UTF8 | Select-Object -Unique
# first create a Hashtable with searchable (cleaned-up) titles and the actual title you want as filename
$titleMap = @{}
foreach ($title in $titles) {
#$null = New-Item -Path 'd:\test' -Name $title -ItemType File
# remove everything after a square bracket, remove the year in between brackets,
# remove all non-ascii characters and trim trailing spaces
$search = ($title -replace '(\(\d{4}\)|\[.*|\s*)$' -replace '[^\x00-\x7F] ' -replace '\.|\s ', ' ').Trim()
$titleMap[$search] = $title
}
# next, get an array of these search titels, sorted on Length reversed
# to avoid bad renames on ambiguous names like 'Il cavaliere oscuro' and 'Il cavaliere oscuro - Il ritorno'
$searchTitles = $titleMap.Keys | Sort-Object Length -Descending
# get the list of files in the foler
$files = Get-ChildItem -LiteralPath 'D:\Test' -File -Exclude 'movielist.txt'
foreach ($file in $files) {
$search = ($file.BaseName -replace '(\(\d{4}\)|\[.*|\s*)$' -replace '[^\x00-\x7F] ' -replace '\.|\s ', ' ').Trim()
# extend each object with a cleaned-up searchable name
$file | Add-Member -MemberType NoteProperty -Name 'SearchName' -Value $search
}
# now loop through the search titles and try to find matching filenames from the files
foreach ($title in $searchTitles) {
$files | Where-Object { $_.SearchName -like "*$title*" } | ForEach-Object {
# use '-ErrorAction SilentlyContinue' to avoid errors on files that have already been renamed
Rename-Item -LiteralPath $_.FullName -NewName ('{0}{1}' -f $titleMap[$title], $_.Extension) -ErrorAction SilentlyContinue
}
}
CodePudding user response:
No fancy regex here other than making an array of movie names and years
$filmTextList = @()
get-content -path $rootFolder\movielist.txt | %{$filmTextList = [PSCustomObject]@{Name=($_ -split "(\(\d{4}\))")[0];Year=($_ -split "(\(\d{4}\))")[1]}}
$filmFiles = get-childitem -path C:\Users\Peter\Desktop\test skript\test1
foreach ($film in $filmTextList){
try{
$matchedFilm = Get-Item ([WildcardPattern]::Escape($filmFiles.FullName -match $film.Name))
Rename-Item -LiteralPath $matchedFilm.FullName -NewName "$($film.Name) $($film.Year)$($matchedFilm.Extension)" -ErrorAction SilentlyContinue
}catch{}
}
Otherwise here's a working version of your 2nd attempt:
$rootFolder = "C:\Users\Peter\Desktop\test skript\test1"
$files = Get-ChildItem -Path $rootFolder -File
$filmTextList = @()
get-content -path $rootFolder\movielist.txt | %{$filmTextList = [PSCustomObject]@{Name=($_ -split "(\(\d{4}\))")[0];Year=($_ -split "(\(\d{4}\))")[1]}}
foreach ($film in $filmTextList)
{
$files | Where-Object {
$_.BaseName -match $film.name
} | ForEach-Object {
$ext = $_.Extension
Rename-Item -LiteralPath $_.FullName -NewName "$($film.name)$($film.year)$ext" -EA 0
}
}