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 | |
| } |
