You can find duplicate files and filter out one copy of each set into a new directory, leaving behind all the copies. This is possible thanks to the PowerShell Community Extension modules PSCX get-hash cmdlet.
(Note: I've created a more extensive script utilizing get-hash and taglib. Click here for a more comprehensive music filter technique)
1. Download the PSCX zipped folder and copy it's contents into your PowerShell modules folder ($env:psmodulepath). I used version 3.0 to run in PowerShell 3.0.
2. Import-module pscx; careful using help. I've had my shell lock up several times when asking for command help -- no matter the command. Run update-help to fix this problem.
3. Go to a populated folder and type get-hash .\*.* to ensure the module and get-hash command are working. You'll see path and hashstring objects for each file.
4. Create a destination folder for your filtered files (i.e. e:\test\hash)
5. Run the following command from the root of the folder structure you wish to examine.
getchild-item -file -recurse|get-hash|sort hashstring -unique|%{move $_.path e:\test\path}
#BTW the -file option for GCI is new for PowerShell 3.0 otherwise you'd
#have to put in the |?{!$_.psiscontainer}| section after the gci to exclude
#subfolders
You now have one copy of each file in your new filtered folder. All other copies are left in their original locations.
Obviously you can alter the command line to create subfolders, move based on various properties, etc., but basically your work is done.
If you have problems with duplicate file names when moving them to the new folder, you can have your filename duplicates create subfolders based on their hashstring, which will be unique, and be placed into them.
if ((gci -ea 0 e:\test\hash\($_.path('\')[-1]))){md -ea 0 e:\test\hash\$_.hashstring;move $_.path e:\test\hash\$_.hashstring}
PS C:\Scripts>Write-host "The Best Way To Predict The Future" -foreground white The Best Way To Predict The Future PS C:\Scripts>"is to create it!"|for-each {write-host $_.toupper() -foreground white} IS TO CREATE IT!
Sunday, February 24, 2013
PowerShell: Create contractions or input apostrophes
If you've ever needed to recreate contractions due to aprostrophe's being stripped from values or filenames, then read on:
Download my contractions.csv file (Thank you Enchanted Learning)
The contractions.csv has three columns to suit your needs. Column one is the root words used to create the contraction. Column two is the contraction without the apostrophe. Column three is the resulting contraction.
$contractions = import-csv "c:\powershell\contractions.csv" -header ("Words","NoApostrophe","Contraction")
# I've assigned $file with a file name missing an apostrophe
$file = gci "it s a gas".txt
#Now we read each row of the CSV file searching for the word combination needed
#to add an apostrophe to the name. Once found, assign a new filename variable, save the file
#with the new name and break out of the loop
Download my contractions.csv file (Thank you Enchanted Learning)
The contractions.csv has three columns to suit your needs. Column one is the root words used to create the contraction. Column two is the contraction without the apostrophe. Column three is the resulting contraction.
$contractions = import-csv "c:\powershell\contractions.csv" -header ("Words","NoApostrophe","Contraction")
# I've assigned $file with a file name missing an apostrophe
$file = gci "it s a gas".txt
#Now we read each row of the CSV file searching for the word combination needed
#to add an apostrophe to the name. Once found, assign a new filename variable, save the file
#with the new name and break out of the loop
foreach($c in $contractions){if ($file.name -like ("*" + $c.noapostroph
e + "*")){
$newfile = $file.name.replace($c.noapostrophe,$c.contraction);ren $file $newfile;break}}
#to rename a variable string value:
$songtitle = "it s a gas"
foreach($c in $contractions){if ($songtitle -like ("*" + $c.noapostrophe + "*")){$songtitle = $songtitle -replace ($c.noapostrophe,$c.contraction);break}}
Seeding the Universe: Jason Silva
I am constantly amazed by this man's recollection of his readings. He quotes paragraphs and intertwines them with his visions epitomizing a euphoric video experience that shouts "Epiphany!" Brilliant man. The amount of tangents they must have talked about during this hike.
PowerShell: ID3 Tag Editing via Taglib-sharp.dll and Discogs API
First of all, I've been searching for a good way to read, manipulate, then write values to the ID3 and other extended file information properties. TagLib is perfect. It integrates easily into scripts and doesn't have any problems other than trying to read a wrongly-named MP3 file. It'll throw an error and I haven't found a way of suppressing or sending the error value to a variable other than to set $erroractionpreference = ignore, which sets the action for the whole script.
(Note: I've created a new script using taglib and get-hash to filter out duplicate files. Click here)
Getting started:
Download the latest taglib: http://download.banshee.fm/taglib-sharp/
Download the most current version and look for the taglib-sharp.dll file in the libraries folder.
Windows 7+ has security protecting the system from "foreign" dlls. Right-click on the taglib-sharp.dll file and click on the "unblock" button. This will allow you to load the file into PowerShell.
#Create a variable for the tag-lib dll file
$taglib = "C:\PowerShell\taglib\libraries\taglib-sharp.dll"
#Load it into Powershell
[system.reflection.assembly]::loadfile($taglib)
#Find an MP3 and either assign it to a variable or put it's name into the create field
$media = [taglib.file]::create("e:\test\body.mp3")
#Now you can view, edit, and save ID3 information
PS E:\test> $media.properties
Codecs : {TagLib.Mpeg.AudioHeader}
Duration : 00:05:12.3120000
MediaTypes : Audio
Description : MPEG Version 1 Audio, Layer 3
AudioBitrate : 128
AudioSampleRate : 44100
BitsPerSample : 0
AudioChannels : 2
VideoWidth : 0
VideoHeight : 0
PhotoWidth : 0
PhotoHeight : 0
PhotoQuality : 0
Compare Taglib field entries to Windows Explorers Detail tab:
PS E:\test> $media.tag
StartTag : TagLib.NonContainer.StartTag
EndTag : TagLib.NonContainer.EndTag
TagTypes : Id3v1, Id3v2
Tags : {, }
Title : Body
Performers : {Bush}
PerformersSort : {}
AlbumArtistsSort : {}
AlbumArtists : {Bush}
Composers : {Gavin Rossdale}
ComposersSort : {}
TitleSort :
AlbumSort :
Album : Sixteen Stone
Comment :
Genres : {Alternative}
Year : 1994
Track : 6
TrackCount : 0
Disc : 1
DiscCount : 1
Lyrics :
Grouping :
BeatsPerMinute : 0
Conductor :
Copyright :
MusicBrainzArtistId :
MusicBrainzReleaseId :
MusicBrainzReleaseArtistId :
MusicBrainzTrackId :
MusicBrainzDiscId :
MusicIpId :
AmazonId :
MusicBrainzReleaseStatus :
MusicBrainzReleaseType :
MusicBrainzReleaseCountry :
Pictures : {}
IsEmpty : False
Artists : {Bush}
FirstArtist : Bush
FirstAlbumArtist : Bush
FirstAlbumArtistSort :
FirstPerformer : Bush
FirstPerformerSort :
FirstComposerSort :
FirstComposer : Gavin Rossdale
FirstGenre : Alternative
JoinedArtists : Bush
JoinedAlbumArtists : Bush
JoinedPerformers : Bush
JoinedPerformersSort :
JoinedComposers : Gavin Rossdale
JoinedGenres : Alternative
PS E:\test> $media.properties.duration
Days : 0
Hours : 0
Minutes : 5
Seconds : 12
Milliseconds : 312
Ticks : 3123120000
TotalDays : 0.00361472222222222
TotalHours : 0.0867533333333333
TotalMinutes : 5.2052
TotalSeconds : 312.312
TotalMilliseconds : 312312
#An example of how I load variables from my music files
$filename = $file.basename
$fileextension = $file.name.split('.')[1]
$filetitle = $media.tag.title
$fileperformers = $media.tag.performers
$filealbumartists = $media.tag.albumartists
$filealbum = $media.tag.album
$filegenres = $media.tag.genres
$fileyear = $media.tag.year
$filetrack = $media.tag.track
$filetrackcount = $media.tag.trackcount
$fileaudiobitrate = $media.properties.audiobitrate
$fileconductor = $media.tag.conductor
$filecomposers = $media.tag.Composers
$fileBPM = $media.tag.BeatsPerMinute
$filedurationminutes = $media.properties.duration.minutes
$filedurationseconds = $media.properties.duration.seconds
$filedurationtotalseconds = $media.properties.duration.totalseconds
#Here's a way to clean the title tag. It cleans the annoying buggy brackets
#then it restricts all characters except the ranges inside the brackets
#Lifted clip explaining some regex expressions:
# Expression:
# ([0-9a-zA-Z\.]+) --> Gets all chars, numbers and '.'. Discard comma and others.
if ($filetitle){
$filetitle = $filetitle -replace ("\[","")
$filetitle = $filetitle -replace ("\]","")
$filetitle = $filetitle -replace ("[^0-9a-zA-Z-&\']"," ")}
#inserting Album Photo:
#(requires PowerShell 3.0 for this album photo catching section)
#To populate the picture tag, I call upon Discogs API via Invoke-Restmethod
#Please refer to the Discogs developer pages for information how to search for your music
#In this example, I used the weighted results and select the first hit for my album search
$filealbum = $media.tag.album
$apialbum = $filealbum -replace (' ','%20')
$albumfound = (invoke-restmethod http://api.discogs.com/database/search?title=$apialbum).results[0]
$thumb = $currentfolder + "\" + $albumfound.thumb.split('/')[-1]
invoke-webrequest -uri $albumfound.thumb -outfile $thumb
$pic = $pic + [taglib.picture]::createfrompath("$thumb")
#writing back to the file
$media.tag.title = [string]$filetitle
$media.tag.performers = [string]$fileperformers
$media.tag.albumartists = [string]$filealbumartists
$media.tag.album = [string]$filealbum
$media.tag.genres = [string]$filegenres
$media.tag.year = $fileyear
$media.tag.track = [string]$filetrack
$media.tag.trackcount = [string]$filetrackcount
$media.tag.conductor = [string]$fileconductor
$media.tag.composers = [string]$filecomposers
$media.tag.BeatsPerMinute = [string]$filebpm
$media.tag.pictures = $pic
$media.save()
References:
http://www.powershell.nu/2009/09/04/scripting-mp3-metadata-through-powershell/
http://vallery.net/2012/04/27/organizing-your-music-with-powershell/
Subscribe to:
Posts (Atom)