You might know about my most favourite add-in for Microsoft Excel called Fuzzy Lookup. It’s the best, most accurate and fastest tool to compare a string of text against a table of data. For example, I can have a table of songs (my entire music library of 12K+ songs), then in another table I can have a list of songs that a radio station has played over the past week – for example. With Fuzzy lookup, I can compare the two tables. Table A which contains songs played on a radio station and Table B which represents my library. For each song in the Table A, give me the closest match of a song from Table B. It works beautifully and provides me a match score so I know how different the match was.
Trying to automate this using PowerShell has been challenging. I have an example here of a PowerShell which I wrote and pieced together. Some of the PowerShell functions I got from here, but not all. The rest of the script I wrote myself…
It does the following:
- Runs through (2 radio stations as an example) on a continuous loop and captures the now playing song from their website. It has some smarts though for each time it’s run:
- if its the same song, skip it
- if the song has changed, capture it and do other things, keep reading…
- The song just played is cleaned up a little bit using some regular expressions (RegEx). The clean up process is to help with a successful match.
- The just played song is checked against a master library of my existing songs in Azure blob storage by using the various functions to do a Fuzzy Match.
- Once a match is found, three things are written to Azure Table Storage:
- the score of the match
- the song captured from the radio station exactly – the just played song
- the result of the song matched from my library
The screenshot below is taken from a list of songs in my Azure table storage account, the songs on the left are songs just played Vs songs on the right which are songs matched from my library. I have pointed to a few examples.
As you can see, it’s pretty accurate.
By the way, the tool used to access Azure storage accounts (including Azure Blob / Azure Tables / Azure Files) is the free Azure Storage Explorer.
$RadioFormat = 'Kiis' | |
$WritetoTableStorage = 'Yes' | |
$TableName = "JustPlayedKiis" | |
#Define the storage account and context. | |
$StorageAccountName = "StorageAccountName" | |
$StorageAccountKey = "StorageAccountKey" | |
$Ctx = New-AzureStorageContext $StorageAccountName –StorageAccountKey $StorageAccountKey | |
#region Clear the cache (variables) | |
$kiis1065result = @() | |
$kiis1011result = @() | |
#endregion | |
Function CheckSong ($song){ | |
$Global:Results = @() | |
$1stResults = @() | |
$2ndResults = @() | |
$Global:Library | % { | |
$h = new-object psObject | select DistanceNumber,Song | |
$h.DistanceNumber = (Get-LongestCommonSubstring $song ($_ -replace '\(.*\)','')).length | |
$h.Song = $_ | |
$1stResults += $h | |
} | |
($1stResults | sort DistanceNumber | select –Last 50).song | % { | |
$x = new-object psObject | select DistanceNumber,Song | |
$x.DistanceNumber = Get-FuzzyMatchScore $song ($_ -replace '\(.*\)','') | |
$x.Song = $_ | |
$2ndResults += $x | |
} | |
if((($2ndResults | sort –Descending DistanceNumber)[0]).DistanceNumber -lt '1600'){ | |
$null = (($song -split ' – ')[0]) -match '[0-9A-Za-z\x2d]+';$artist = $matches[0] | |
$title = (($song -split ' – ')[1]) | |
foreach($2ndresult in $2ndResults){ | |
if(($2ndresult.Song -split ' – ')[0] -match $artist -and ($2ndresult.Song -split ' – ')[1] -match $title) | |
{$Global:Results = $2ndresult} | |
} | |
} | |
if((!($Global:Results))) {$Global:Results = $2ndResults} | |
} | |
Function Get-ExistingSongLibrary ($Ctx) { | |
#$Containers = Get-AzureStorageContainer -Context $Ctx -ErrorAction SilentlyContinue | |
$RawLibrary = Get-AzureStorageBlob –Container music –Context $Ctx | ? {$_.Name -like '*.mp3'} | |
$Global:Library = @() | |
foreach($lib in $RawLibrary){ | |
$Global:Library += ($Lib.Name).Split('/') -replace '.mp3' | select –Last 1 | |
} | |
} | |
Function MissingSongsTable ($song, $songrequest, $RadioFormat, $DistanceNumber){ | |
$MissingTableName = "MissingSongs" | |
#Retrieve the table if it already exists. | |
$table = Get-AzureStorageTable –Name $MissingTableName –Context $Ctx –ErrorAction Ignore | |
#Create a new table if it does not exist. | |
if ($table -eq $null) | |
{ | |
Do{$table = New-AzureStorageTable –Name $MissingTableName –Context $Ctx; Start-Sleep –Seconds 2} until((Get-AzureStorageTable –Name $MissingTableName –Context $Ctx –ErrorAction Ignore) -ne $null) | |
} | |
#query table entities | |
#Create a table query. | |
$query = New-Object Microsoft.WindowsAzure.Storage.Table.TableQuery | |
$datenow = (Get-Date).Year.ToString() + (Get-Date).DayOfYear.ToString() + ((Get-Date).DayOfWeek).ToString() | |
$dateyesterday = (Get-Date).AddDays(-1).Year.ToString() + (Get-Date).AddDays(-1).DayOfYear.ToString() + ((Get-Date).AddDays(-1).DayOfWeek).ToString() | |
$filterString = "(PartitionKey eq '$datenow' or PartitionKey eq '$dateyesterday')" | |
$query.FilterString = $filterString | |
#Execute the query. | |
$entities = $table.CloudTable.ExecuteQuery($query) | |
$time = Get-Date –Format yyyyMMdd–HH:mm:ss | |
$PartitionKey = (Get-Date).Year.ToString() + (Get-Date).DayOfYear.ToString() + ((Get-Date).DayOfWeek).ToString() | |
# Row Number Variable | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -eq $PartitionKey){ | |
$rowNumber = ($entities | sort Timestamp | select –Last 1).RowKey -replace("Row");$rowNumber = [INT]$rowNumber;$rowNumber++} | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -ne $PartitionKey){$rowNumber = 1} | |
# ID number Variable | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -eq $PartitionKey){ | |
$ID = ($entities | sort Timestamp | select –Last 1).Properties.ID.PropertyAsObject;$ID++} | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -ne $PartitionKey){$ID = 1} | |
$entity = New-Object –TypeName Microsoft.WindowsAzure.Storage.Table.DynamicTableEntity –ArgumentList $partitionKey, "Row$rowNumber" | |
$entity.Properties.Add("SongPlayed", $song) | |
$entity.Properties.Add("SongLookup", $songrequest) | |
$entity.Properties.Add("DistanceNumber", $DistanceNumber) | |
$entity.Properties.Add("RadioFormat", $RadioFormat) | |
$entity.Properties.Add("ID", $id) | |
$entity.Properties.Add("Time", $time) | |
$table.CloudTable.Execute([Microsoft.WindowsAzure.Storage.Table.TableOperation]::Insert($entity)) | |
} | |
Function SongsTable ($songrequest, $song, $RadioFormat, $DistanceNumber){ | |
#Create a table query. | |
$query = New-Object Microsoft.WindowsAzure.Storage.Table.TableQuery | |
$datenow = (Get-Date).Year.ToString() + (Get-Date).DayOfYear.ToString() + ((Get-Date).DayOfWeek).ToString() | |
$dateyesterday = (Get-Date).AddDays(-1).Year.ToString() + (Get-Date).AddDays(-1).DayOfYear.ToString() + ((Get-Date).AddDays(-1).DayOfWeek).ToString() | |
$filterString = "(PartitionKey eq '$datenow' or PartitionKey eq '$dateyesterday')" | |
$query.FilterString = $filterString | |
#Execute the query. | |
$entities = $table.CloudTable.ExecuteQuery($query) | |
$time = Get-Date –Format yyyyMMdd–HH:mm:ss | |
$PartitionKey = (Get-Date).Year.ToString() + (Get-Date).DayOfYear.ToString() + ((Get-Date).DayOfWeek).ToString() | |
# Row Number Variable | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -eq $PartitionKey){ | |
$rowNumber = ($entities | sort Timestamp | select –Last 1).RowKey -replace("Row");$rowNumber = [INT]$rowNumber;$rowNumber++} | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -ne $PartitionKey){$rowNumber = 1} | |
# ID number Variable | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -eq $PartitionKey){ | |
$ID = ($entities | sort Timestamp | select –Last 1).Properties.ID.PropertyAsObject;$ID++} | |
if(($entities | sort Timestamp | select –Last 1).PartitionKey -ne $PartitionKey){$ID = 1} | |
$entity = New-Object –TypeName Microsoft.WindowsAzure.Storage.Table.DynamicTableEntity –ArgumentList $partitionKey, "Row$rowNumber" | |
$entity.Properties.Add("SongPlayed", $song) | |
$entity.Properties.Add("SongLookup", $songrequest) | |
$entity.Properties.Add("DistanceNumber", $DistanceNumber) | |
$entity.Properties.Add("RadioFormat", $RadioFormat) | |
$entity.Properties.Add("ID", $id) | |
$entity.Properties.Add("Time", $time) | |
$table.CloudTable.Execute([Microsoft.WindowsAzure.Storage.Table.TableOperation]::Insert($entity)) | |
} | |
function Get-FuzzyMatchScore { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Position = 0)] | |
[string] $Search, | |
[Parameter(Position = 1)] | |
[string] $String | |
) | |
$score = 100 | |
# Use approximate string matching to get some values needed to calculate the score of the result | |
$longestCommonSubstring = Get-LongestCommonSubstring –String1 $String –String2 $Search | |
$levenshteinDistance = Get-LevenshteinDistance –String1 $String –String2 $Search | |
$commonPrefix = Get-CommonPrefix –String1 $String –String2 $Search | |
# By running the result through this regex pattern we get the length of the match as well as the | |
# the index of where the match starts. The shorter the match length and the index, the more | |
# score will be added for the match. | |
$regexMatchFilter = $Search.ToCharArray() -join '.*?' | |
$match = Select-String –InputObject $String –Pattern $regexMatchFilter –AllMatches | |
$matchLength = ($match.Matches | Sort-Object Length | Select-Object –First 1).Value.Length | |
$matchIndex = ($match.Matches | Sort-Object Length | Select-Object –First 1).Index | |
# Calculate score | |
$score = $score – $levenshteinDistance | |
$score = $score * $longestCommonSubstring.Length | |
$score = $score – $matchLength | |
$score = $score – $matchIndex | |
if ($commonPrefix) { | |
$score = $score + $commonPrefix.Length | |
} | |
Write-Output $score | |
} | |
function Get-HammingDistance { | |
<# | |
.SYNOPSIS | |
Get the Hamming Distance between two strings or two positive integers. | |
.DESCRIPTION | |
The Hamming distance between two strings of equal length is the number of positions at which the | |
corresponding symbols are different. In another way, it measures the minimum number of substitutions | |
required to change one string into the other, or the minimum number of errors that could have | |
transformed one string into the other. Note! Even though the original Hamming algorithm only works for | |
strings of equal length, this function supports strings of unequal length as well. | |
The function also calculates the Hamming distance between two positive integers (considered as binary | |
values); that is, it calculates the number of bit substitutions required to change one integer into | |
the other. | |
.EXAMPLE | |
Get-HammingDistance 'karolin' 'kathrin' | |
Calculate the Hamming distance between the two strings. The result is 3. | |
.EXAMPLE | |
Get-HammingDistance 'karolin' 'kathrin' -NormalizedOutput | |
Calculate the normalized Hamming distance between the two strings. The result is 0.571428571428571. | |
.EXAMPLE | |
Get-HammingDistance -Int1 61 -Int2 15 | |
Calculate the hamming distance between 61 and 15. The result is 3. | |
.LINK | |
http://en.wikipedia.org/wiki/Hamming_distance | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.PASM | |
.NOTES | |
Author: Øyvind Kallstad | |
Date: 03.11.2014 | |
Version: 1.0 | |
#> | |
[CmdletBinding(DefaultParameterSetName = 'String')] | |
param ( | |
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'String')] | |
[ValidateNotNullOrEmpty()] | |
[string] $String1, | |
[Parameter(Position = 1, Mandatory = $true, ParameterSetName = 'String')] | |
[ValidateNotNullOrEmpty()] | |
[string] $String2, | |
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Integer')] | |
[ValidateNotNullOrEmpty()] | |
[uint32] $Int1, | |
[Parameter(Position = 1, Mandatory = $true, ParameterSetName = 'Integer')] | |
[ValidateNotNullOrEmpty()] | |
[uint32] $Int2, | |
# Makes matches case-sensitive. By default, matches are not case-sensitive. | |
[Parameter(ParameterSetName = 'String')] | |
[switch] $CaseSensitive, | |
# Normalize the output value. When the output is not normalized the maximum value is the length of the longest string, and the minimum value is 0, | |
# meaning that a value of 0 is a 100% match. When the output is normalized you get a value between 0 and 1, where 1 indicates a 100% match. | |
[Parameter(ParameterSetName = 'String')] | |
[switch] $NormalizeOutput | |
) | |
try { | |
if ($PSCmdlet.ParameterSetName -eq 'String') { | |
# handle case insensitivity | |
if (-not($CaseSensitive)) { | |
$String1 = $String1.ToLowerInvariant() | |
$String2 = $String2.ToLowerInvariant() | |
} | |
# set initial distance | |
$distance = 0 | |
# get max and min length of the input strings | |
$maxLength = [Math]::Max($String1.Length,$String2.Length) | |
$minLength = [Math]::Min($String1.Length,$String2.Length) | |
# calculate distance for the length of the shortest string | |
for ($i = 0; $i -lt $minLength; $i++) { | |
if (-not($String1[$i] -ceq $String2[$i])) { | |
$distance++ | |
} | |
} | |
# add the remaining length to the distance | |
$distance = $distance + ($maxLength – $minLength) | |
if ($NormalizeOutput) { | |
Write-Output (1 – ($distance / $maxLength)) | |
} | |
else { | |
Write-Output $distance | |
} | |
} | |
else { | |
$distance = 0 | |
$value = $Int1 -bxor $Int2 | |
while ($value -ne 0) { | |
$distance++ | |
$value = $value -band ($value – 1) | |
} | |
Write-Output $distance | |
} | |
} | |
catch { | |
Write-Warning $_.Exception.Message | |
} | |
} | |
function Get-LevenshteinDistance { | |
<# | |
.SYNOPSIS | |
Get the Levenshtein distance between two strings. | |
.DESCRIPTION | |
The Levenshtein Distance is a way of quantifying how dissimilar two strings (e.g., words) are to one another by counting the minimum number of operations required to transform one string into the other. | |
.EXAMPLE | |
Get-LevenshteinDistance 'kitten' 'sitting' | |
.LINK | |
http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C.23 | |
http://en.wikipedia.org/wiki/Edit_distance | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.PASM | |
.NOTES | |
Author: Øyvind Kallstad | |
Date: 07.11.2014 | |
Version: 1.0 | |
#> | |
[CmdletBinding()] | |
param( | |
[Parameter(Position = 0)] | |
[string]$String1, | |
[Parameter(Position = 1)] | |
[string]$String2, | |
# Makes matches case-sensitive. By default, matches are not case-sensitive. | |
[Parameter()] | |
[switch] $CaseSensitive, | |
# A normalized output will fall in the range 0 (perfect match) to 1 (no match). | |
[Parameter()] | |
[switch] $NormalizeOutput | |
) | |
if (-not($CaseSensitive)) { | |
$String1 = $String1.ToLowerInvariant() | |
$String2 = $String2.ToLowerInvariant() | |
} | |
$d = New-Object 'Int[,]' ($String1.Length + 1), ($String2.Length + 1) | |
try { | |
for ($i = 0; $i -le $d.GetUpperBound(0); $i++) { | |
$d[$i,0] = $i | |
} | |
for ($i = 0; $i -le $d.GetUpperBound(1); $i++) { | |
$d[0,$i] = $i | |
} | |
for ($i = 1; $i -le $d.GetUpperBound(0); $i++) { | |
for ($j = 1; $j -le $d.GetUpperBound(1); $j++) { | |
$cost = [Convert]::ToInt32((-not($String1[$i–1] -ceq $String2[$j–1]))) | |
$min1 = $d[($i–1),$j] + 1 | |
$min2 = $d[$i,($j–1)] + 1 | |
$min3 = $d[($i–1),($j–1)] + $cost | |
$d[$i,$j] = [Math]::Min([Math]::Min($min1,$min2),$min3) | |
} | |
} | |
$distance = ($d[$d.GetUpperBound(0),$d.GetUpperBound(1)]) | |
if ($NormalizeOutput) { | |
Write-Output (1 – ($distance) / ([Math]::Max($String1.Length,$String2.Length))) | |
} | |
else { | |
Write-Output $distance | |
} | |
} | |
catch { | |
Write-Warning $_.Exception.Message | |
} | |
} | |
function Get-LongestCommonSubstring { | |
<# | |
.SYNOPSIS | |
Get the longest common substring of two strings. | |
.DESCRIPTION | |
Get the longest common substring of two strings. | |
.EXAMPLE | |
Get-LongestCommonSubstring 'Karolin' 'kathrin' -CaseSensitive | |
.LINK | |
https://fuzzystring.codeplex.com/ | |
http://en.wikipedia.org/wiki/Longest_common_substring_problem | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.PASM | |
.NOTES | |
Adapted to PowerShell from code by Kevin Jones (https://fuzzystring.codeplex.com/) | |
Author: Øyvind Kallstad | |
Date: 03.11.2014 | |
Version: 1.0 | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Position = 0)] | |
[string] $String1, | |
[Parameter(Position = 1)] | |
[string] $String2, | |
[Parameter()] | |
[switch] $CaseSensitive | |
) | |
if (-not($CaseSensitive)) { | |
$String1 = $String1.ToLowerInvariant() | |
$String2 = $String2.ToLowerInvariant() | |
} | |
$array = New-Object 'Object[,]' $String1.Length, $String2.Length | |
$stringBuilder = New-Object System.Text.StringBuilder | |
$maxLength = 0 | |
$lastSubsBegin = 0 | |
for ($i = 0; $i -lt $String1.Length; $i++) { | |
for ($j = 0; $j -lt $String2.Length; $j++) { | |
if ($String1[$i] -cne $String2[$j]) { | |
$array[$i,$j] = 0 | |
} | |
else { | |
if (($i -eq 0) -or ($j -eq 0)) { | |
$array[$i,$j] = 1 | |
} | |
else { | |
$array[$i,$j] = 1 + $array[($i – 1),($j – 1)] | |
} | |
if ($array[$i,$j] -gt $maxLength) { | |
$maxLength = $array[$i,$j] | |
$thisSubsBegin = $i – $array[$i,$j] + 1 | |
if($lastSubsBegin -eq $thisSubsBegin) { | |
[void]$stringBuilder.Append($String1[$i]) | |
} | |
else { | |
$lastSubsBegin = $thisSubsBegin | |
$stringBuilder.Length = 0 | |
[void]$stringBuilder.Append($String1.Substring($lastSubsBegin, (($i + 1) – $lastSubsBegin))) | |
} | |
} | |
} | |
} | |
} | |
Write-Output $stringBuilder.ToString() | |
} | |
function Get-CommonPrefix { | |
<# | |
.SYNOPSIS | |
Find the common prefix of two strings. | |
.DESCRIPTION | |
This function will get the common prefix of two strings; that is, all | |
the letters that they share, starting from the beginning of the strings. | |
.EXAMPLE | |
Get-CommonPrefix 'Card' 'Cartoon' | |
Will get the common prefix of both string. Should output 'car'. | |
.LINK | |
https://communary.wordpress.com/ | |
https://github.com/gravejester/Communary.PASM | |
.INPUTS | |
System.String | |
.OUTPUTS | |
System.String | |
.NOTES | |
Author: Øyvind Kallstad | |
Date: 03.11.2014 | |
Version 1.1 | |
Dependencies: none | |
#> | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory = $true, Position = 0)] | |
[ValidateNotNullOrEmpty()] | |
[string]$String1, | |
[Parameter(Mandatory = $true, Position = 1)] | |
[ValidateNotNullOrEmpty()] | |
[string]$String2, | |
# Maximum length of the returned prefix. | |
[Parameter()] | |
[int]$MaxPrefixLength, | |
# Makes matches case-sensitive. By default, matches are not case-sensitive. | |
[Parameter()] | |
[switch] $CaseSensitive | |
) | |
if (-not($CaseSensitive)) { | |
$String1 = $String1.ToLowerInvariant() | |
$String2 = $String2.ToLowerInvariant() | |
} | |
$outputString = New-Object 'System.Text.StringBuilder' | |
$shortestStringLength = [Math]::Min($String1.Length,$String2.Length) | |
# Let the maximum prefix length be the same as the length of the shortest of | |
# the two input strings, unless defined by the MaxPrefixLength parameter. | |
if (($shortestStringLength -lt $MaxPrefixLength) -or ($MaxPrefixLength -eq 0)) { | |
$MaxPrefixLength = $shortestStringLength | |
} | |
# Loop from the start and add any characters found that are equal | |
for ($i = 0; $i -lt $MaxPrefixLength; $i++) { | |
if ($String1[$i] -ceq $String2[$i]) { | |
[void]$outputString.Append($String1[$i]) | |
} | |
else { break } | |
} | |
Write-Output $outputString.ToString() | |
} | |
function FinalActions ($song, $RadioFormat, $eJukeboxHost) { | |
$songrequest = (($Global:Results | sort –Descending DistanceNumber)[0]).Song | |
$DistanceNumber = (($Global:Results | sort –Descending DistanceNumber)[0]).DistanceNumber | |
Write-Host –NoNewline "Song from Lookup: " –ForegroundColor Green; Write-Host $songrequest –ForegroundColor Magenta | |
Write-Host –NoNewline "Distance Number from Lookup: " –ForegroundColor Green; Write-Host $DistanceNumber –ForegroundColor Magenta | |
# Song Might be missing, add to Missing Songs Table | |
if($DistanceNumber -lt '1000'){ | |
if($WritetoTableStorage -eq 'Yes'){MissingSongsTable $song $songrequest $RadioFormat $DistanceNumber} | |
} else { # Request the song | |
if($WritetoTableStorage -eq 'Yes'){SongsTable $songrequest $song $RadioFormat $DistanceNumber} | |
} | |
} | |
while ($true){ | |
Get-ExistingSongLibrary $Ctx | |
#endregion | |
##################################### | |
#region Capture Kiis Australia (Sydney/Melbourne) | |
#Kiis 1065 – Sydney | |
$matches = @() | |
Start-Sleep –Seconds 1 | |
Write-Host "Kiis 1065" | |
$kiis1065listsong = @() | |
$uri = (Invoke-WebRequest 'http://media.arn.com.au/xml/mix1065_now.xml').content | |
Start-Sleep –Seconds 1 | |
$null = $uri -match '<now_playing>(.|\n)*artist><!\[CDATA\[([^]]*)\]\]></artist(.|\n)*</now_playing>';$artist = $matches[2] | |
$null = $uri -match '<now_playing>(.|\n)*title\sgeneric="False"><!\[CDATA\[([^]]*)\]\]></title(.|\n)*</now_playing>';$title = $matches[2] | |
$kiis1065song = "{0} – {1}" -f $artist, $title | |
Write-Host –NoNewline "Now playing on Kiis 1065 " –ForegroundColor Cyan;Write-Host $kiis1065song –ForegroundColor Yellow | |
if((!($kiis1065result -eq $kiis1065song)) -and ` | |
($kiis1065song -notmatch "Kiis") -and ` | |
($kiis1065song -match "..\s-\s..") -and ` | |
($kiis1065song -notmatch "Audio Type Changed")){ | |
$kiis1065result = $kiis1065song | |
#Write to table | |
$song = $kiis1065song | |
#query table entities | |
#Region Do stuff with the song http://www.ascii-code.com/ | |
$Cleansong = $kiis1065song -replace '\(.*\)',' ' -replace("&","&") -replace ' ',' ' -replace ' feat. ',' ' ` | |
-replace ' ft. ',' ' -replace ' ft ',' ' ` | |
-replace '[\xC0-\xC5]','A' -replace '[\xC8-\xCB]','E' -replace '[\xCC-\xCF]','I' ` | |
-replace '[\xD2-\xD6]','O' -replace '[\xD9-\xDC]','U' -replace '[\xe8-\xEB]','e' ` | |
-replace '[\xEC-\xEF]','i' -replace '[\xF2-\xF6]','o' -replace '[\xF9-\xFC]','u' ` | |
-replace '[\xE0-\xE5]','o' -replace '[\xD1]','N' -replace '[\x91\x92\x60]','\x27' ` | |
-replace '[\x93\x94]','\x22' -replace '[^\x30-\x39\x41-\x5A\x61-\x7A\x20\x2D\x26\x27\x22\x2E\x2C]+',' ' ` | |
-replace ' ',' ' -replace 'The ','' | |
CheckSong $Cleansong | |
FinalActions $song $RadioFormat $eJukeboxHost | |
} | |
##################################### | |
##################################### | |
#Kiis 1011 – Melbourne | |
$matches = @() | |
Start-Sleep –Seconds 1 | |
Write-Host "Kiis 1011" | |
$kiis1011listsong = @() | |
$uri = (Invoke-WebRequest 'http://media.arn.com.au/xml/KIIS1011_now.xml').content | |
Start-Sleep –Seconds 1 | |
$null = $uri -match '<now_playing>(.|\n)*artist><!\[CDATA\[([^]]*)\]\]></artist(.|\n)*</now_playing>';$artist = $matches[2] | |
$null = $uri -match '<now_playing>(.|\n)*title\sgeneric="False"><!\[CDATA\[([^]]*)\]\]></title(.|\n)*</now_playing>';$title = $matches[2] | |
$kiis1011song = "{0} – {1}" -f $artist, $title | |
Write-Host –NoNewline "Now playing on Kiis 1011 " –ForegroundColor Cyan;Write-Host $kiis1011song –ForegroundColor Yellow | |
if((!($kiis1011result -eq $kiis1011song)) -and ` | |
($kiis1011song -notmatch "Kiis") -and ` | |
($kiis1011song -match "..\s-\s..") -and ` | |
($kiis1011song -notmatch "Audio Type Changed")){ | |
$kiis1011result = $kiis1011song | |
#Write to table | |
$song = $kiis1011song | |
#query table entities | |
#Region Do stuff with the song http://www.ascii-code.com/ | |
$Cleansong = $kiis1011song -replace '\(.*\)',' ' -replace("&","&") -replace ' ',' ' -replace ' feat. ',' ' ` | |
-replace ' ft. ',' ' -replace ' ft ',' ' ` | |
-replace '[\xC0-\xC5]','A' -replace '[\xC8-\xCB]','E' -replace '[\xCC-\xCF]','I' ` | |
-replace '[\xD2-\xD6]','O' -replace '[\xD9-\xDC]','U' -replace '[\xe8-\xEB]','e' ` | |
-replace '[\xEC-\xEF]','i' -replace '[\xF2-\xF6]','o' -replace '[\xF9-\xFC]','u' ` | |
-replace '[\xE0-\xE5]','o' -replace '[\xD1]','N' -replace '[\x91\x92\x60]','\x27' ` | |
-replace '[\x93\x94]','\x22' -replace '[^\x30-\x39\x41-\x5A\x61-\x7A\x20\x2D\x26\x27\x22\x2E\x2C]+',' ' ` | |
-replace ' ',' ' -replace 'The ','' | |
CheckSong $Cleansong | |
FinalActions $song $RadioFormat $eJukeboxHost | |
} | |
##################################### | |
#endregion | |
} |