Re: Recordings filename pattern (use the custom label)
Posted: Sat Sep 26, 2020 9:34 pm
If it works like I think it does, an option to use the Service Callsign as Service Name and/or Call Sign might be nice.
The Best Place To Come For All Your Windows Media Center Needs
https://www.thegreenbutton.tv/forums/
Not quite that simple, but of course doable. The MergedChannel, which is what is displayed on the left side of the client, consists of a primary channel and any number of secondary channels. At the end of a TV Setup scan, the primary channel is the tuner channel from the "Scanned Lineup". When guide listings are assigned to the merged channel, the listings take the primary channel position and the tuner channel gets moved to the secondary channels. If that is all that is done with your setup, it can be done fairly easily.
Code: Select all
# Version: 20200928.1-alpha
# Status: alpha
# Standard file system locations
# Folder: C:\ProgramData\GaRyan2\epg123
# PS Script File: custom_callSign_serviceName.ps1
# JSON Data File: custom_callSign_serviceName.json
# Dry Run CFG File: custom_callSign_serviceName.Dry_Run.cfg
# Development environment:
# Windows 8.1 Pro w/Media Center
# PowerShell: 4.0
# SiliconDust: HDHomeRun CONNECT, Model: HDHR4-2US, Firmware: 20200907
# Criteria to use
$Dry_Run = $true # Save to $EPG_Data_Dir'\custom_callSign_serviceName.Dry_Run.cfg'
$ChLineUp = 'USA-OTA-97007' # Channel line up associated with HDHomeRun device
$EPG_Service = 'EPG123' # EPG service name
$EPG_Data_Dir = 'C:\ProgramData\GaRyan2\epg123' # Fully qualified EPG data dir path (without trailing slash)
$CFG_File = 'epg123.cfg' # EPG config file
$MXF_File = 'epg123.mxf' # EPG MXF file
$Custom_CallSign_flag = $true # Set/Replace (true), Remove (false) custom channel call sign
$Custom_Service_Name_flag = $true # Set/Replace (true), Remove (false) custom channel service name
# Can be used standalone with guide name and number JSON data: ex: [{"GuideNumber":"10.4","GuideName":"OPBKids"}]
$Retrive_Data_From_Device = $true # Retrieve channels & names from HDHomeRun device
$Device_Channel_Dectection_Scan = $false # Perform HDHomeRun device channel detection scan
#$Device_ID = '1040dddd' # HDHomeRun device ID (only for client utility scan)
$Device_Address = '192.168.2.202' # HDHomeRun device address
$Show = 'found' # HDHomeRun device channel line up query: all, found, favorites
# End Criteria to use
function Invoke-Main {
Get-Channels_Service_Name_Data
Edit-Configuration
}
#
# Retrieve PSIP VCT short name from HDHomeRun device. Or use default/fallback channel names.
#
function Get-Channels_Service_Name_Data {
if ($Retrive_Data_From_Device) {
$webclient = new-object System.Net.WebClient
$lineup_json_url = 'http://'+$Device_Address+'/lineup.json?show='+$Show
if ($Device_Channel_Dectection_Scan) {
Invoke-Device_Channel_Dectection_Scan_Web
# Invoke-Device_Channel_Dectection_Scan_Utility # SliconDust hdhomerun_config.exe
} else {
$json = $webclient.DownloadString($lineup_json_url)
}
}
try {
$vPSObject = $json | ConvertFrom-Json -ErrorAction Stop;
'Using data retrieved from device ('+$Device_Address+')'
'' # Blank line
# Save device retrieved, guide number and guide name abbreviated, json for default/fallback, don't overwrite existing
if (!(Test-Path $EPG_Data_Dir'\custom_callSign_serviceName.json')) {
$json = $json -Replace '\[\{', "[`r`n{" -Replace '},{', "},`r`n{" -Replace '}]', "}`r`n]" # Line-ized
$json = $json -Replace "({`"GuideNumber.*?GuideName`":`".*?`").*(},*)", "`$1`$2" # Only GuideNumber and GuideName
$json | Set-Content -Path $EPG_Data_Dir'\custom_callSign_serviceName.json'
}
} catch {
# Channel GuideNumber and GuideName json.
# Use in place of (retrieve from device false) or if HDHomeRun device query fails.
if (Test-Path $EPG_Data_Dir'\custom_callSign_serviceName.json') {
$json_fallback = Get-Content -path $EPG_Data_Dir'\custom_callSign_serviceName.json' -Raw
$vPSObject = $json_fallback | ConvertFrom-Json
'Using default/fallback data: '
$EPG_Data_Dir+'\custom_callSign_serviceName.json'
'' # Blank line
} else {
'Default/Fallback data not found: '
$EPG_Data_Dir+'\custom_callSign_serviceName.json'
'' # Blank line
pause
exit
}
}
$script:vPSObject = $vPSObject
}
#
# Set/Remove/Replace epg123.cfg customServiceName and customCallSign fields
#
function Edit-Configuration {
$epg123_cfg = Get-Content -path $EPG_Data_Dir'\'$CFG_File -Raw
$epg123_mxf = Get-Content -path $EPG_Data_Dir'\output\'$MXF_File -Raw
"Channel`tName`tSign`tSta ID`tLineup`tSrv ID"
foreach ($ch in $vPSObject) {
$ChNumber = $ch.GuideNumber.Split('.')
$ChName = $ch.GuideName
$ChCallSign = $ch.GuideName
# Get EPG channel lineup station ID, and perform Set/Remove/Replace
if ( $epg123_mxf -match `
"<Channel uid=`"!Channel!$ChLineUp!(?<station_id>[0-9]*)_"+$ChNumber[0]+"_"+$ChNumber[1]+"`" lineup=`"(?<lineup_id>l[0-9]*)`" " + `
"service=`"(?<service_id>.*?)`" number=`""+$ChNumber[0]+"`" subNumber=`""+$ChNumber[1]+"`" />" ) {
$station_id = $matches['station_id']; $RegexEscaped_station_id = [Regex]::Escape($station_id)
$lineup_id = $matches['lineup_id']; $RegexEscaped_lineup_id = [Regex]::Escape($lineup_id)
$service_id = $matches['service_id']; $RegexEscaped_service_id = [Regex]::Escape($service_id)
# Get existing custom service name string
$cSN = ( $epg123_cfg -match "<StationID CallSign=`".*?`".*?(?<Existing_customServiceName> customServiceName=`".*?`").*?>$RegexEscaped_station_id</StationID>" )
$Existing_customServiceName = $matches['Existing_customServiceName']; $RegexEscaped_Existing_customServiceName = [Regex]::Escape($Existing_customServiceName)
# Get existing custom call sign string
$cCS = ( $epg123_cfg -match "<StationID CallSign=`".*?`".*?(?<Existing_customCallSign> customCallSign=`".*?`").*?>$RegexEscaped_station_id</StationID>" )
$Existing_customCallSign = $matches['Existing_customCallSign']; $RegexEscaped_Existing_customCallSign = [Regex]::Escape($Existing_customCallSign)
if ($Custom_Service_Name_flag) { $customServiceName = " customServiceName=`"$ChName`"" }
if ($Custom_CallSign_flag) { $customCallSign = " customCallSign=`"$ChCallSign`"" }
# Set/Remove/Replace custom service name
$epg123_cfg = $epg123_cfg -replace `
"<StationID CallSign=`"(.*?)`"(.*?)$RegexEscaped_Existing_customServiceName(.*?)>$RegexEscaped_station_id</StationID>", `
"<StationID CallSign=`"`$1`"`$2$customServiceName`$3>$station_id</StationID>"
# Set/Remove/Replace custom call sign
$epg123_cfg = $epg123_cfg -replace `
"<StationID CallSign=`"(.*?)`"(.*?)$RegexEscaped_Existing_customCallSign(.*?)>$RegexEscaped_station_id</StationID>", `
"<StationID CallSign=`"`$1`"`$2$customCallSign`$3>$station_id</StationID>"
$ChNumber[0]+'.'+$ChNumber[1]+"`t"+$ChName+"`t"+$ChCallSign+"`t"+$station_id+"`t"+$lineup_id+"`t"+$service_id
}
}
'' # Blank line
'Customized epg123.cfg saved to: '
if ($Dry_Run) {
$EPG_Data_Dir+'\custom_callSign_serviceName.Dry_Run.cfg'
$epg123_cfg.TrimEnd() | Set-Content -Encoding UTF8 -Path $EPG_Data_Dir'\custom_callSign_serviceName.Dry_Run.cfg'
} else {
$EPG_Data_Dir+'\'+$CFG_File
$epg123_cfg.TrimEnd() | Set-Content -Encoding UTF8 -Path $EPG_Data_Dir'\'$CFG_File
}
}
#
# Run HDHomeRun device channel scan (web based)
#
function Invoke-Device_Channel_Dectection_Scan_Web {
$status_json_url = 'http://'+$Device_Address+'/lineup_status.json'
$scan_status = $webclient.DownloadString($status_json_url) | ConvertFrom-Json
if ($scan_status.ScanInProgress -eq 0) {
if ($scan_status.ScanPossible -eq 1) {
'Channel Detection: '
' Scanning device ('+$Device_Address+')...'
$lineup_scan_start_url = 'http://'+$Device_Address+'/lineup.post?scan=start&source='+$scan_status.Source
# Invoke-WebRequest -Uri $lineup_scan_start_url -Method POST
$webclient.UploadString($lineup_scan_start_url,'')
} else { 'Scan not possible. May not be an available tuner.' }
} else { 'Channel detection scan already in progress...' }
# While scanning...
Do {
$scan_status = $webclient.DownloadString($status_json_url) | ConvertFrom-Json
if ($scan_status.ScanInProgress -ge 1) {
$status = 'Found '+$scan_status.Found+' programs ('+$scan_status.Progress+'%)'
Write-Host "`r"$status -NoNewLine
Start-Sleep 1
}
} While ( $scan_status.ScanInProgress -eq 1)
$json = $webclient.DownloadString($lineup_json_url)
# Final status
$Found = ($json | ConvertFrom-Json).length; $Progress = 100
$status = "Found "+$Found+" programs ("+$Progress+"%)"
Write-Host "`r"$status
'' # Blank line
$script:json = $json
}
#
# Run HDHomeRun device channel scan; Return GuideNumber and GuideName JSON string (client utility based)
#
function Invoke-Device_Channel_Dectection_Scan_Utility {
$tuner0 = & 'C:\Program Files\Silicondust\HDHomeRun\hdhomerun_config.exe' $Device_ID get /tuner0/status
$tuner1 = & 'C:\Program Files\Silicondust\HDHomeRun\hdhomerun_config.exe' $Device_ID get /tuner1/status
"Scanning device $Device_ID for channels..."
if ($tuner0 -match "lock=none") {
$channel_scan = & 'C:\Program Files\Silicondust\HDHomeRun\hdhomerun_config.exe' $Device_ID 'scan' '/tuner0'
$Device_Channel_Dectection_Scan_Status = & 'C:\Program Files\Silicondust\HDHomeRun\hdhomerun_config.exe' $Device_ID 'get' '/lineup/scan'
} elseif ($tuner1 -match "lock=none") {
$channel_scan = & 'C:\Program Files\Silicondust\HDHomeRun\hdhomerun_config.exe' $Device_ID 'scan' '/tuner1'
$Device_Channel_Dectection_Scan_Status = & 'C:\Program Files\Silicondust\HDHomeRun\hdhomerun_config.exe' $Device_ID 'get' '/lineup/scan'
} else {
"No Tuner Available"
}
if ($Device_Channel_Dectection_Scan_Status -match "state=complete") {
$json = '['
$lines = $channel_scan.split("`r`n")
foreach ($line in $lines) {
$matched = $line -match "PROGRAM *[0-9]*: *(?<GuideNumber>[0-9]{1,2}\.[0-9]*) *(?<GuideName>.*)"
if ($matched) {
$json += '{"GuideNumber":"'+$matches['GuideNumber']+'","GuideName":"'+$matches['GuideName']+'"},'
}
}
$json = $json.TrimEnd(',')
$json += ']'
}
# Sort by ascending GuideNumber
$array = $json | ConvertFrom-Json
$array_sorted = $array | Sort-Object { [float]$_.GuideNumber }
$json = $array_sorted | ConvertTo-Json
$json = $json -Replace "[`r`n]","" -Replace " *{ *","{" -Replace " *} *", "}" -Replace "`": *`"","`":`"" -Replace "`", *`"","`",`""
$script:json = $json
}
Invoke-Main
'' # Blank line
pause # Wait for user to exit/close PS window
# NOTE:
# $json = Invoke-WebRequest http://$Device_Address/lineup.json?show=found # Doesn't work with UTF8 encoding
# Workaround A
# $json = Invoke-WebRequest -Uri 'http://$Device_Address/lineup.json?show=found' -Outfile $EPG_Data_Dir'\hdhrlineup.json'
# $json = Get-Content -Path $EPG_Data_Dir'\hdhrlineup.json' -Encoding UTF8 -Raw
# Remove-Item -Path $EPG_Data_Dir'\hdhrlineup.json' -Force
# Workaround B
# $webclient = new-object System.Net.WebClient
# $json = $webclient.DownloadString("http://$Device_Address/lineup.json?show=$Show")
Code: Select all
[
{"GuideNumber":"2.1","GuideName":"KATU"},
{"GuideNumber":"2.2","GuideName":"MeTV"},
{"GuideNumber":"2.3","GuideName":"Comet"},
{"GuideNumber":"2.4","GuideName":"Stadium"},
{"GuideNumber":"6.1","GuideName":"KOIN-HD"},
{"GuideNumber":"6.2","GuideName":"GetTV"},
{"GuideNumber":"6.3","GuideName":"Bounce"},
{"GuideNumber":"8.1","GuideName":"KGW"},
{"GuideNumber":"8.2","GuideName":"Crime"},
{"GuideNumber":"8.3","GuideName":"Quest"},
{"GuideNumber":"8.10","GuideName":"KGW"},
{"GuideNumber":"8.20","GuideName":"Crime"},
{"GuideNumber":"8.30","GuideName":"Quest"},
{"GuideNumber":"10.1","GuideName":"OPB"},
{"GuideNumber":"10.2","GuideName":"OPBPlus"},
{"GuideNumber":"10.3","GuideName":"OPBKids"},
{"GuideNumber":"10.4","GuideName":"OPB-FM"},
{"GuideNumber":"12.1","GuideName":"FOX 12"},
{"GuideNumber":"12.2","GuideName":"COZI"},
{"GuideNumber":"12.3","GuideName":"LAFF"},
{"GuideNumber":"12.4","GuideName":"DABL"},
{"GuideNumber":"22.1","GuideName":"ION"},
{"GuideNumber":"22.2","GuideName":"qubo"},
{"GuideNumber":"22.3","GuideName":"IONPlus"},
{"GuideNumber":"22.4","GuideName":"Shop"},
{"GuideNumber":"22.5","GuideName":"QVC"},
{"GuideNumber":"22.6","GuideName":"HSN"},
{"GuideNumber":"22.7","GuideName":"TLMD"},
{"GuideNumber":"24.1","GuideName":"TBN HD"},
{"GuideNumber":"24.2","GuideName":"Hilsong"},
{"GuideNumber":"24.3","GuideName":"SMILE"},
{"GuideNumber":"24.4","GuideName":"Enlace"},
{"GuideNumber":"24.5","GuideName":"POSITIV"},
{"GuideNumber":"26.1","GuideName":"SBN TV"},
{"GuideNumber":"26.2","GuideName":"Shop LC"},
{"GuideNumber":"26.3","GuideName":"ACE TV"},
{"GuideNumber":"26.4","GuideName":"Heartla"},
{"GuideNumber":"32.1","GuideName":"KRCW"},
{"GuideNumber":"32.2","GuideName":"Antenna"},
{"GuideNumber":"32.3","GuideName":"Courttv"},
{"GuideNumber":"32.4","GuideName":"TBD"},
{"GuideNumber":"47.1","GuideName":"KUNP-LD"},
{"GuideNumber":"47.2","GuideName":"TBD"},
{"GuideNumber":"47.3","GuideName":"Charge"},
{"GuideNumber":"49.1","GuideName":"Fox12+"},
{"GuideNumber":"49.2","GuideName":"Escape"},
{"GuideNumber":"49.3","GuideName":"Bounce"},
{"GuideNumber":"49.4","GuideName":"Grit"},
{"GuideNumber":"49.20","GuideName":"Escape"},
{"GuideNumber":"49.40","GuideName":"Grit"}
]
Code: Select all
Client Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040nnnn' -Device_Channel_Detection_Scan 'client' -Device_IP_Address ''
Default: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Retrieve_Data_From_Device $false
No Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.2.202' -Device_Channel_Detection_Scan 'none'
Verbose: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040nnnn' -Device_Channel_Detection_Scan 'client' -Device_IP_Address '' -Verbose $true
Web Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.2.202' -Device_Channel_Detection_Scan 'web'
Code: Select all
# Before using see observed issues, change log and development environment information at bottom.
# Version: 20201106.1-alpha
# Status: alpha
# Typical file system locations
# Folder: C:\ProgramData\GaRyan2\epg123
# PS Script File: custom_callSign_serviceName.ps1
# JSON Data File: custom_callSign_serviceName.json
# Dry Run CFG File: custom_callSign_serviceName.Dry_Run.cfg
# Criteria to use parameters (must be first line of script)
param(`
$Dry_Run = $true, ` # Save to $EPG_Data_Dir'\custom_callSign_serviceName.Dry_Run.cfg'
$CHLineUP = 'USA-OTA-97007', ` # Channel line up associated with HDHomeRun device
$EPG_Service = 'EPG123', ` # EPG service name
$EPG_Data_Dir = 'C:\ProgramData\GaRyan2\epg123', ` # Fully qualified EPG data dir path (without trailing slash)
$CFG_File = 'epg123.cfg', ` # EPG config file
$MXF_File = 'epg123.mxf', ` # EPG MXF file
$Custom_Service_Name_flag = $true, ` # Set/Replace (true), Remove (false) custom channel service name
$Custom_CallSign_flag = $true, ` # Set/Replace (true), Remove (false) custom channel call sign
# Can be used standalone with guide name and number JSON data: ex: [{"GuideNumber":"10.4","GuideName":"OPBKids"}]
$Retrieve_Data_From_Device = $true, ` # Retrieve channels & names from HDHomeRun device
$Device_Channel_Detection_Scan = 'none', ` # Perform HDHomeRun device channel detection scan: web, client, none
# HD HomeRun Web Utility Settings
# A web utility channel detection scan...
# 1) updates the device stored channel lineup
# 2) interrupts viewing and recording
$Device_IP_Address = '192.168.2.202', ` # HDHomeRun device IP address (required for web scan)
$Show = 'found', ` # HDHomeRun device channel line up web query: all, found, favorites
# HD HomeRun Client Utility Settings
# A client utility channel detection scan...
# 1) does not update the device stored channel lineup
# 2) may append a status comment to the channel name. ex: '(control)', '(encrypted)', '(no data)' Unknown what effects this may have.
$HDHR_Prog_Dir = 'C:\Program Files\Silicondust\HDHomeRun', ` # HDHomeRund installation folder path (without trailing slash)
$HDHR_Client_Utility = 'hdhomerun_config.exe', ` # HDHomeRun client configuration utility executable
$Device_ID = '1040nnnn', ` # Needed only for device without IP address
$Verbose = $false ` # Client utility verbose output
)
# End Criteria to use parameters
#
# Genesis
#
function Invoke-Main {
Get-Channels_Guide_Name_Data
Edit-Configuration
}
#
# Retrieve PSIP VCT short name from HDHomeRun device. Or use default/fallback channel names.
#
function Get-Channels_Guide_Name_Data {
if ($Retrieve_Data_From_Device) {
$webclient = new-object System.Net.WebClient
$lineup_json_url = 'http://'+$Device_IP_Address+'/lineup.json?show='+$Show
if ($Device_Channel_Detection_Scan -eq 'web') {
Invoke-Device_Channel_Detection_Scan_Web
} elseif ($Device_Channel_Detection_Scan -eq 'client') {
Invoke-Device_Channel_Detection_Scan_Utility # SliconDust hdhomerun_config.exe
} else {
Get-Device_Information 'web'
$json = $webclient.DownloadString($lineup_json_url)
$Device_Address = $Device_IP_Address
}
}
try {
$vPSObject = $json | ConvertFrom-Json -ErrorAction Stop;
'Using data retrieved from device ('+$Device_Address+')'
'' # Blank line
# Save device retrieved, guide number and guide name abbreviated, json for default/fallback, don't overwrite existing
if (!(Test-Path $EPG_Data_Dir'\custom_callSign_serviceName.json')) {
$json = $json -Replace '\[\{', "[`r`n{" -Replace '},{', "},`r`n{" -Replace '}]', "}`r`n]" # Line-ized (each channel)
$json = $json -Replace "({`"GuideNumber.*?GuideName`":`".*?`").*(},*)", "`$1`$2" # Only GuideNumber and GuideName
$json | Set-Content -Path $EPG_Data_Dir'\custom_callSign_serviceName.json'
}
} catch {
# Channel GuideNumber and GuideName json.
# Use in place of (retrieve from device false) or if HDHomeRun device query fails.
if (Test-Path $EPG_Data_Dir'\custom_callSign_serviceName.json') {
$json_fallback = Get-Content -path $EPG_Data_Dir'\custom_callSign_serviceName.json' -Raw
$vPSObject = $json_fallback | ConvertFrom-Json
'Using default/fallback data: '
$EPG_Data_Dir+'\custom_callSign_serviceName.json'
'' # Blank line
} else {
'Default/Fallback data not found: '
$EPG_Data_Dir+'\custom_callSign_serviceName.json'
'' # Blank line
pause; exit;
}
}
$script:vPSObject = $vPSObject
}
#
# Set/Remove/Replace epg123.cfg customServiceName and customCallSign fields
#
function Edit-Configuration {
$epg123_cfg = Get-Content -path $EPG_Data_Dir'\'$CFG_File -Raw
$epg123_mxf = Get-Content -path $EPG_Data_Dir'\output\'$MXF_File -Raw
"Channel`tName`tSign`tSta ID`tLineup`tSrv ID"
foreach ($ch in $vPSObject) {
$ChNumber = $ch.GuideNumber.Split('.')
$ChName = $ch.GuideName
$ChCallSign = $ch.GuideName
# Get EPG channel lineup station ID, and perform Set/Remove/Replace
if ( $epg123_mxf -match `
"<Channel uid=`"!Channel!$ChLineUp!(?<station_id>[0-9]*)_"+$ChNumber[0]+"_"+$ChNumber[1]+"`" lineup=`"(?<lineup_id>l[0-9]*)`" " + `
"service=`"(?<service_id>.*?)`" number=`""+$ChNumber[0]+"`" subNumber=`""+$ChNumber[1]+"`" />" ) {
$station_id = $matches['station_id']; $RegexEscaped_station_id = [Regex]::Escape($station_id)
$lineup_id = $matches['lineup_id']; $RegexEscaped_lineup_id = [Regex]::Escape($lineup_id)
$service_id = $matches['service_id']; $RegexEscaped_service_id = [Regex]::Escape($service_id)
# Get existing custom service name string
$cSN = ( $epg123_cfg -match "<StationID CallSign=`".*?`".*?(?<Existing_customServiceName> customServiceName=`".*?`").*?>$RegexEscaped_station_id</StationID>" )
$Existing_customServiceName = $matches['Existing_customServiceName']; $RegexEscaped_Existing_customServiceName = [Regex]::Escape($Existing_customServiceName)
# Get existing custom call sign string
$cCS = ( $epg123_cfg -match "<StationID CallSign=`".*?`".*?(?<Existing_customCallSign> customCallSign=`".*?`").*?>$RegexEscaped_station_id</StationID>" )
$Existing_customCallSign = $matches['Existing_customCallSign']; $RegexEscaped_Existing_customCallSign = [Regex]::Escape($Existing_customCallSign)
if ($Custom_Service_Name_flag) { $customServiceName = " customServiceName=`"$ChName`"" } else { $ChName = '' }
if ($Custom_CallSign_flag) { $customCallSign = " customCallSign=`"$ChCallSign`"" } else { $ChCallSign = '' }
# Set/Remove/Replace custom service name
$epg123_cfg = $epg123_cfg -replace `
"<StationID CallSign=`"(.*?)`"(.*?)$RegexEscaped_Existing_customServiceName(.*?)>$RegexEscaped_station_id</StationID>", `
"<StationID CallSign=`"`$1`"`$2$customServiceName`$3>$station_id</StationID>"
# Set/Remove/Replace custom call sign
$epg123_cfg = $epg123_cfg -replace `
"<StationID CallSign=`"(.*?)`"(.*?)$RegexEscaped_Existing_customCallSign(.*?)>$RegexEscaped_station_id</StationID>", `
"<StationID CallSign=`"`$1`"`$2$customCallSign`$3>$station_id</StationID>"
$ChNumber[0]+'.'+$ChNumber[1]+"`t"+$ChName+"`t"+$ChCallSign+"`t"+$station_id+"`t"+$lineup_id+"`t"+$service_id
}
}
'' # Blank line
'Customized epg123.cfg saved to: '
if ($Dry_Run) {
$EPG_Data_Dir+'\custom_callSign_serviceName.Dry_Run.cfg'
$epg123_cfg.TrimEnd() | Set-Content -Encoding UTF8 -Path $EPG_Data_Dir'\custom_callSign_serviceName.Dry_Run.cfg'
} else {
$EPG_Data_Dir+'\'+$CFG_File
$epg123_cfg.TrimEnd() | Set-Content -Encoding UTF8 -Path $EPG_Data_Dir'\'$CFG_File
}
}
#
# Run HDHomeRun device channel detection scan (web utility)
#
function Invoke-Device_Channel_Detection_Scan_Web {
Get-Device_Information 'web'
$status_json_url = 'http://'+$Device_IP_Address+'/lineup_status.json'
$scan_status = $webclient.DownloadString($status_json_url) | ConvertFrom-Json
if ($scan_status.ScanInProgress -eq 0) {
if ($scan_status.ScanPossible -eq 1) {
'Channel Detection: '
' Scanning device ('+$Device_IP_Address+')...'
$lineup_scan_start_url = 'http://'+$Device_IP_Address+'/lineup.post?scan=start&source='+$scan_status.Source
# Invoke-WebRequest -Uri $lineup_scan_start_url -Method POST
$webclient.UploadString($lineup_scan_start_url,'')
} else { 'Scan not possible. May not be an available tuner.' }
} else { 'Channel detection scan already in progress...' }
# While scanning...
Do {
$scan_status = $webclient.DownloadString($status_json_url) | ConvertFrom-Json
if ($scan_status.ScanInProgress -ge 1) {
$status = ' Found '+$scan_status.Found+' programs ('+$scan_status.Progress+'%)'
Write-Host "`r"$status -NoNewLine
Start-Sleep 1
}
} While ( $scan_status.ScanInProgress -eq 1)
$json = $webclient.DownloadString($lineup_json_url)
# Final status
$found = ($json | ConvertFrom-Json).length; $progress = 100
$status = ' Found '+$found+' programs ('+$progress+'%) '
Write-Host "`r"$status
'' # Blank line
$Script:json = $json; $Script:Device_Address = $Device_IP_Address
}
#
# Run HDHomeRun device channel detection scan; Return GuideNumber and GuideName JSON (client utility)
#
function Invoke-Device_Channel_Detection_Scan_Utility {
# Get Device ID from discover.json URL
if (!$Device_ID) {
if ($Device_IP_Address) {
# $Device = $webclient.DownloadString($discover_json_url) | ConvertFrom-Json
$Device = $webclient.DownloadString('http://'+$Device_IP_Address+'/discover.json') | ConvertFrom-Json
$Device_ID = $Device.DeviceID
} else {
'Device not found'
'' # Blank line
pause; exit;
}
}
Get-Device_Information 'client'
# Find/Select available tuner
for ($tuner = 0; $tuner -le 64; $tuner++) { # Loop depth failsafe (64)
$tuner_lockkey = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Device_ID get /tuner$tuner/lockkey
if ($tuner_lockkey -match "none" -Or $tuner_lockkey -match "ERROR") {
break
}
}
if ($tuner_lockkey -notmatch "none") {
' No Tuner Available'
'' # Blank line
pause; exit;
}
$channel_map = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Device_ID 'get' "/tuner$tuner/channelmap"
'Channel Detection: '
' Scanning device ('+$Device_ID+')... Tuner: '+$tuner+' '+$channel_map
'' # Blank line
& "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Device_ID 'scan' "/tuner$tuner" | ForEach-Object -Process { $found = 0; $progress = 0 } {
$matched = $_ -match "PROGRAM *[0-9]*: *(?<GuideNumber>[0-9]{1,2}\.[0-9]*) *(?<GuideName>.*)"
if ($matched) {
$matches['GuideName'] = $matches['GuideName'] -Replace "(.*?) \(control\)(.*)", "`$1`$2"
$matches['GuideName'] = $matches['GuideName'] -Replace "(.*?) \(encrypted\)(.*)", "`$1`$2"
$matches['GuideName'] = $matches['GuideName'] -Replace "(.*?) \(no data\)(.*)", "`$1`$2"
$json += '{"GuideNumber":"'+$matches['GuideNumber']+'","GuideName":"'+$matches['GuideName']+'"},'
$found++
}
$matched = $_ -match "SCANNING: .*? \(${channel_map}:(?<channel_number>[0-9]*)\).*"
if ($matched) {
$channel_number = $matches['channel_number']
if (!$total_channels) { $total_channels = $channel_number }
$status = ' Found '+$found+' programs ('+$progress+'%) Ch. '+$channel_number+' '
$progress = [int]((($total_channels - $channel_number + 1 ) / ($total_channels - 1)) * 100)
if (!$Verbose) {
Write-Host "`r"$status -NoNewLine
}
}
if ($Verbose) {
Write-Host $_
}
}
if ($Verbose) {
'' # Blank line
}
# Final Status
$status = ' Found '+$found+' programs ('+$progress+'%) '
Write-Host "`r"$status
'' # Blank line
if ($json) {
$json = $json.TrimEnd(',')
$json = '['+$json+']' # As array
# Sort by ascending GuideNumber
$array = $json | ConvertFrom-Json
$array_sorted = $array | Sort-Object { [Version]$_.GuideNumber }
$json = $array_sorted | ConvertTo-Json -Compress
}
$Script:json = $json; $Script:Device_Address = $Device_ID
}
#
# Get Device Information
#
function Get-Device_Information ($method){
if ($method -eq 'web') {
$discover_json_url = 'http://'+$Device_IP_Address+'/discover.json'
$Device = $webclient.DownloadString($discover_json_url) | ConvertFrom-Json
$Device.FriendlyName
'Model: '+$Device.ModelNumber
'Firmware: '+$Device.FirmwareVersion
'Device ID: '+$Device.DeviceID
'Device IP Address: '+$Device_IP_Address
} elseif ($method -eq 'client') {
$ModelNumber = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Device_ID get /sys/hwmodel
$FirmwareVersion = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Device_ID get /sys/version
'' # Blank line
'Model: '+$ModelNumber
'Firmware: '+$FirmwareVersion
'Device ID: '+$Device_ID
'Device IP Address: '+$Device_IP_Address
}
'' # Blank line
}
Invoke-Main
'' # Blank line
pause; exit; # Wait for user to exit/close PS window
# NOTE:
# $json = Invoke-WebRequest http://$Device_IP_Address/lineup.json?show=found # Doesn't work with UTF8 encoding
# Workaround A
# $json = Invoke-WebRequest -Uri 'http://$Device_IP_Address/lineup.json?show=found' -Outfile $EPG_Data_Dir'\hdhrlineup.json'
# $json = Get-Content -Path $EPG_Data_Dir'\hdhrlineup.json' -Encoding UTF8 -Raw
# Remove-Item -Path $EPG_Data_Dir'\hdhrlineup.json' -Force
# Workaround B
# $webclient = new-object System.Net.WebClient
# $json = $webclient.DownloadString("http://$Device_IP_Address/lineup.json?show=$Show")
# Development Environment
# Windows 8.1 Pro w/Media Center
# PowerShell: 4.0
# SiliconDust: HDHomeRun CONNECT, Model: HDHR4-2US, Firmware: 20200907
# Observed Issues
# Running a channel detection scan (web) interrupts in process viewing/recording signal.
# Running a channel detection scan (client) may append a status comment to the channel name. ex: '(control)', '(encrypted)', '(no data)' Unknown what effects this may have.
# Change Log
# Version: 20201106.1-alpha
# Learned to select channel detection scan method (web/client/none) from variable setting.
# Learned to retrieve device information (model, firmware, ID)
# Learned how not to be verbose (client utility)
# Learned to dynamically find and select from more than two tuners (0/1) (client utility)
# Learned to override settings with parameters passed on command line
# Example command line shortcuts
# Client Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040nnnn' -Device_Channel_Detection_Scan 'client' -Device_IP_Address ''
# Default: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Retrieve_Data_From_Device $false
# No Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.2.202' -Device_Channel_Detection_Scan 'none'
# Verbose: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040nnnn' -Device_Channel_Detection_Scan 'client' -Device_IP_Address '' -Verbose $true
# Web Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.2.202' -Device_Channel_Detection_Scan 'web'
# Version: 20200928.1-alpha
# Learned how to run HDHomeRun device channel detection scan
# Learned to operate standalone (without a HDHR device) using guide number and name JSON data.
# Learned to do a dry run
# Factored into functions
# Version: 20200926.1-alpha
# Genesis
Code: Select all
[
{"GuideNumber":"2.1","GuideName":"KATU"},
{"GuideNumber":"2.2","GuideName":"MeTV"},
{"GuideNumber":"2.3","GuideName":"Comet"},
{"GuideNumber":"2.4","GuideName":"Stadium"},
{"GuideNumber":"6.1","GuideName":"KOIN-HD"},
{"GuideNumber":"6.2","GuideName":"GetTV"},
{"GuideNumber":"6.3","GuideName":"Bounce"},
{"GuideNumber":"8.1","GuideName":"KGW"},
{"GuideNumber":"8.2","GuideName":"Crime"},
{"GuideNumber":"8.3","GuideName":"Quest"},
{"GuideNumber":"8.10","GuideName":"KGW"},
{"GuideNumber":"8.20","GuideName":"Crime"},
{"GuideNumber":"8.30","GuideName":"Quest"},
{"GuideNumber":"10.1","GuideName":"OPB"},
{"GuideNumber":"10.2","GuideName":"OPBPlus"},
{"GuideNumber":"10.3","GuideName":"OPBKids"},
{"GuideNumber":"10.4","GuideName":"OPB-FM"},
{"GuideNumber":"12.1","GuideName":"FOX 12"},
{"GuideNumber":"12.2","GuideName":"COZI"},
{"GuideNumber":"12.3","GuideName":"LAFF"},
{"GuideNumber":"12.4","GuideName":"DABL"},
{"GuideNumber":"22.1","GuideName":"ION"},
{"GuideNumber":"22.2","GuideName":"qubo"},
{"GuideNumber":"22.3","GuideName":"IONPlus"},
{"GuideNumber":"22.4","GuideName":"Shop"},
{"GuideNumber":"22.5","GuideName":"QVC"},
{"GuideNumber":"22.6","GuideName":"HSN"},
{"GuideNumber":"22.7","GuideName":"TLMD"},
{"GuideNumber":"24.1","GuideName":"TBN HD"},
{"GuideNumber":"24.2","GuideName":"Hilsong"},
{"GuideNumber":"24.3","GuideName":"SMILE"},
{"GuideNumber":"24.4","GuideName":"Enlace"},
{"GuideNumber":"24.5","GuideName":"POSITIV"},
{"GuideNumber":"26.1","GuideName":"SBN TV"},
{"GuideNumber":"26.2","GuideName":"Shop LC"},
{"GuideNumber":"26.3","GuideName":"ACE TV"},
{"GuideNumber":"26.4","GuideName":"Heartla"},
{"GuideNumber":"32.1","GuideName":"KRCW"},
{"GuideNumber":"32.2","GuideName":"Antenna"},
{"GuideNumber":"32.3","GuideName":"Courttv"},
{"GuideNumber":"32.4","GuideName":"TBD"},
{"GuideNumber":"47.1","GuideName":"KUNP-LD"},
{"GuideNumber":"47.2","GuideName":"TBD"},
{"GuideNumber":"47.3","GuideName":"Charge"},
{"GuideNumber":"49.1","GuideName":"Fox12+"},
{"GuideNumber":"49.2","GuideName":"Escape"},
{"GuideNumber":"49.3","GuideName":"Bounce"},
{"GuideNumber":"49.4","GuideName":"Grit"},
{"GuideNumber":"49.20","GuideName":"Escape"},
{"GuideNumber":"49.40","GuideName":"Grit"}
]
Code: Select all
--- custom_callSign_serviceName.org.ps1 2020-11-06 21:04:39.000000000 -0800
+++ custom_callSign_serviceName.ps1 2021-01-11 17:02:34.000000000 -0800
@@ -3 +3 @@
-# Version: 20201106.1-alpha
+# Version: 20210111.1-alpha
@@ -127 +127 @@
- "service=`"(?<service_id>.*?)`" number=`""+$ChNumber[0]+"`" subNumber=`""+$ChNumber[1]+"`" />" ) {
+ "service=`"(?<service_id>.*?)`" matchName=`"(?<matchName>.*?)`" number=`""+$ChNumber[0]+"`" subNumber=`""+$ChNumber[1]+"`" />" ) {
@@ -360,0 +361,3 @@
+
+# Version: 20210111.1-alpha
+# Accommodate the "matchName" field in "epg123.mxf"
Code: Select all
--- custom_callSign_serviceName.org.ps1 2021-01-11 17:02:34.000000000 -0800
+++ custom_callSign_serviceName.ps1 2021-02-28 15:39:16.000000000 -0800
@@ -3 +3 @@
-# Version: 20210111.1-alpha
+# Version: 20210228.1-alpha
@@ -117 +117 @@
- "Channel`tName`tSign`tSta ID`tLineup`tSrv ID"
+ "Channel`tCl Sign`tcName`tcSign`tSta ID`tLineup`tSrv ID"
@@ -140,0 +141,4 @@
+ # Get station call sign string
+ $oCS = ( $epg123_cfg -match "<StationID CallSign=`"(?<Existing_stationCallSign>.*?)`".*?>$RegexEscaped_station_id</StationID>" )
+ $Existing_stationCallSign = $matches['Existing_stationCallSign']; $RegexEscaped_Existing_stationCallSign = [Regex]::Escape($Existing_stationCallSign)
+
@@ -154 +158 @@
- $ChNumber[0]+'.'+$ChNumber[1]+"`t"+$ChName+"`t"+$ChCallSign+"`t"+$station_id+"`t"+$lineup_id+"`t"+$service_id
+ $ChNumber[0]+'.'+$ChNumber[1]+"`t"+$Existing_stationCallSign+"`t"+$ChName+"`t"+$ChCallSign+"`t"+$station_id+"`t"+$lineup_id+"`t"+$service_id
@@ -360,0 +365,3 @@
+
+# Version: 20210228.1-alpha
+# Include station call sign in display output.
Code: Select all
Client Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040xxxx' -Device_Channel_Detection_Scan 'client' -Device_IP_Address ''
Default: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Retrieve_Data_From_Device $false
No Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.x.x' -Device_Channel_Detection_Scan 'none'
Verbose: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040xxxx' -Device_Channel_Detection_Scan 'client' -Device_IP_Address '' -Verbose $true
Web Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.x.x' -Device_Channel_Detection_Scan 'web'
Code: Select all
# Before using see observed issues, change log and development environment information at bottom.
# Version: 20220922.3-alpha
# Status: alpha
# Typical file system locations
# Folder: C:\ProgramData\GaRyan2\epg123
# PS Script File: custom_callSign_serviceName.ps1
# JSON Data File: custom_callSign_serviceName.json
# Dry Run CFG File: custom_callSign_serviceName.Dry_Run.cfg
# Criteria to use parameters (must be first line of script)
param(`
$Dry_Run = $true, ` # Save to $EPG_Data_Dir'\custom_callSign_serviceName.Dry_Run.cfg'
$CHLineUP = 'USA-OTA-97xxx', ` # Channel line up associated with HDHomeRun device
$EPG_Service = 'EPG123', ` # EPG service name
$EPG_Data_Dir = 'C:\ProgramData\GaRyan2\epg123', ` # Fully qualified EPG data dir path (without trailing slash)
$CFG_File = 'epg123.cfg', ` # EPG config file
$MXF_File = 'epg123.mxf', ` # EPG MXF file
$Custom_Service_Name_flag = $true, ` # Set/Replace (true), Remove (false) custom channel service name
$Custom_CallSign_flag = $true, ` # Set/Replace (true), Remove (false) custom channel call sign
# Can be used standalone with guide name and number JSON data: ex: [{"GuideNumber":"10.4","GuideName":"OPBKids"}]
$Retrieve_Data_From_Device = $true, ` # Retrieve channels & names from HDHomeRun device
$Device_Channel_Detection_Scan = 'none', ` # Perform HDHomeRun device channel detection scan: web, client, none
# HD HomeRun Web Utility Settings
# A web utility channel detection scan...
# 1) updates the device stored channel lineup
# 2) interrupts viewing and recording
$Device_IP_Address = '192.168.x.x', ` # HDHomeRun device IP address (required for web scan)
$Show = 'found', ` # HDHomeRun device channel line up web query: all, found, favorites
# HD HomeRun Client Utility Settings
# A client utility channel detection scan...
# 1) does not update the device stored channel lineup
# 2) may append a status comment to the channel name. ex: '(control)', '(encrypted)', '(no data)' Unknown what effects this may have.
$HDHR_Prog_Dir = 'C:\Program Files\Silicondust\HDHomeRun', ` # HDHomeRund installation folder path (without trailing slash)
$HDHR_Client_Utility = 'hdhomerun_config.exe', ` # HDHomeRun client configuration utility executable
$Device_ID = '1040xxxx', ` # Needed only for device without IP address
$Verbose = $false ` # Client utility verbose output
)
# End Criteria to use parameters
#
# Genesis
#
function Invoke-Main {
Get-Channels_Guide_Name_Data
Edit-Configuration
}
#
# Retrieve PSIP VCT short name from HDHomeRun device. Or use default/fallback channel names.
#
function Get-Channels_Guide_Name_Data {
if ($Retrieve_Data_From_Device) {
$webclient = new-object System.Net.WebClient
$lineup_json_url = 'http://'+$Device_IP_Address+'/lineup.json?show='+$Show+'&tuning'
if ($Device_Channel_Detection_Scan -eq 'web') {
Invoke-Device_Channel_Detection_Scan_Web
} elseif ($Device_Channel_Detection_Scan -eq 'client') {
Invoke-Device_Channel_Detection_Scan_Utility # SliconDust hdhomerun_config.exe
} else {
Get-Device_Information 'web'
$json = $webclient.DownloadString($lineup_json_url)
$Device_Address = $Device_IP_Address
}
}
try {
$vPSObject = $json | ConvertFrom-Json -ErrorAction Stop;
'Using data retrieved from device ('+$Device_Address+')'
'' # Blank line
# Save device retrieved, guide number and guide name abbreviated, json for default/fallback, don't overwrite existing
if (!(Test-Path $EPG_Data_Dir'\custom_callSign_serviceName.json')) {
$json = $json -Replace '\[\{', "[`r`n{" -Replace '},{', "},`r`n{" -Replace '}]', "}`r`n]" # Line-ized (each channel)
$json = $json -Replace "({`"GuideNumber.*?GuideName`":`".*?`").*(},*)", "`$1`$2" # Only GuideNumber and GuideName
$json | Set-Content -Path $EPG_Data_Dir'\custom_callSign_serviceName.json'
}
} catch {
# Channel GuideNumber and GuideName json.
# Use in place of (retrieve from device false) or if HDHomeRun device query fails.
if (Test-Path $EPG_Data_Dir'\custom_callSign_serviceName.json') {
$json_fallback = Get-Content -path $EPG_Data_Dir'\custom_callSign_serviceName.json' -Raw
$vPSObject = $json_fallback | ConvertFrom-Json
'Using default/fallback data: '
$EPG_Data_Dir+'\custom_callSign_serviceName.json'
'' # Blank line
} else {
'Default/Fallback data not found: '
$EPG_Data_Dir+'\custom_callSign_serviceName.json'
'' # Blank line
pause; exit;
}
}
$script:vPSObject = $vPSObject
}
#
# Set/Remove/Replace epg123.cfg customServiceName and customCallSign fields
#
function Edit-Configuration {
$epg123_cfg = Get-Content -path $EPG_Data_Dir'\'$CFG_File -Raw
$epg123_mxf = Get-Content -path $EPG_Data_Dir'\output\'$MXF_File -Raw
"B-Cast`tDisplay`tStation`tCustom`tCustom`tStation`tLineup`tService"
"Channel`tChannel`tSign`tName`tSign`tID`tID`tID"
"-------`t-------`t-------`t-------`t-------`t-------`t-------`t-------"
foreach ($ch in $vPSObject) {
$PhyChNumber = $ch.ChannelNumber
$ChNumber = $ch.GuideNumber.Split('.')
$ChName = $ch.GuideName
$ChCallSign = $ch.GuideName
if ($ch.CustomGuideName) {
$ChName = $ch.CustomGuideName
$ChCallSign = $ch.CustomGuideName
}
# Get EPG channel lineup station ID, and perform Set/Remove/Replace
if ( $epg123_mxf -match `
"<Channel uid=`"!Channel!$ChLineUp!(?<station_id>[0-9]*)_"+$ChNumber[0]+"_"+$ChNumber[1]+"`" lineup=`"(?<lineup_id>l[0-9]*)`" " + `
"service=`"(?<service_id>.*?)`" matchName=`"(?<matchName>.*?)`" number=`""+$ChNumber[0]+"`" subNumber=`""+$ChNumber[1]+"`" />" ) {
$station_id = $matches['station_id']; $RegexEscaped_station_id = [Regex]::Escape($station_id)
$lineup_id = $matches['lineup_id']; $RegexEscaped_lineup_id = [Regex]::Escape($lineup_id)
$service_id = $matches['service_id']; $RegexEscaped_service_id = [Regex]::Escape($service_id)
# Get existing custom service name string
$cSN = ( $epg123_cfg -match "<StationID CallSign=`".*?`".*?(?<Existing_customServiceName> customServiceName=`".*?`").*?>$RegexEscaped_station_id</StationID>" )
$Existing_customServiceName = $matches['Existing_customServiceName']; $RegexEscaped_Existing_customServiceName = [Regex]::Escape($Existing_customServiceName)
# Get existing custom call sign string
$cCS = ( $epg123_cfg -match "<StationID CallSign=`".*?`".*?(?<Existing_customCallSign> customCallSign=`".*?`").*?>$RegexEscaped_station_id</StationID>" )
$Existing_customCallSign = $matches['Existing_customCallSign']; $RegexEscaped_Existing_customCallSign = [Regex]::Escape($Existing_customCallSign)
# Get station call sign string
$sCS = ( $epg123_cfg -match "<StationID CallSign=`"(?<Existing_stationCallSign>.*?)`".*?>$RegexEscaped_station_id</StationID>" )
$Existing_stationCallSign = $matches['Existing_stationCallSign']; $RegexEscaped_Existing_stationCallSign = [Regex]::Escape($Existing_stationCallSign)
if ($Custom_Service_Name_flag) { $customServiceName = " customServiceName=`"$ChName`"" } else { $ChName = '' }
if ($Custom_CallSign_flag) { $customCallSign = " customCallSign=`"$ChCallSign`"" } else { $ChCallSign = '' }
# Set/Remove/Replace custom service name
$epg123_cfg = $epg123_cfg -replace `
"<StationID CallSign=`"(.*?)`"(.*?)$RegexEscaped_Existing_customServiceName(.*?)>$RegexEscaped_station_id</StationID>", `
"<StationID CallSign=`"`$1`"`$2$customServiceName`$3>$station_id</StationID>"
# Set/Remove/Replace custom call sign
$epg123_cfg = $epg123_cfg -replace `
"<StationID CallSign=`"(.*?)`"(.*?)$RegexEscaped_Existing_customCallSign(.*?)>$RegexEscaped_station_id</StationID>", `
"<StationID CallSign=`"`$1`"`$2$customCallSign`$3>$station_id</StationID>"
# Display Channel Info
$PhyChNumber+"`t"+$ChNumber[0]+'.'+$ChNumber[1]+"`t"+$Existing_stationCallSign+"`t"+$ChName+"`t"+$ChCallSign+"`t"+$station_id+"`t"+$lineup_id+"`t"+$service_id
}
}
'' # Blank line
'Customized epg123.cfg saved to: '
if ($Dry_Run) {
$EPG_Data_Dir+'\custom_callSign_serviceName.Dry_Run.cfg'
$epg123_cfg.TrimEnd() | Set-Content -Encoding UTF8 -Path $EPG_Data_Dir'\custom_callSign_serviceName.Dry_Run.cfg'
} else {
$EPG_Data_Dir+'\'+$CFG_File
$epg123_cfg.TrimEnd() | Set-Content -Encoding UTF8 -Path $EPG_Data_Dir'\'$CFG_File
}
}
#
# Run HDHomeRun device channel detection scan (web utility)
#
function Invoke-Device_Channel_Detection_Scan_Web {
Get-Device_Information 'web'
$status_json_url = 'http://'+$Device_IP_Address+'/lineup_status.json'
$scan_status = $webclient.DownloadString($status_json_url) | ConvertFrom-Json
if ($scan_status.ScanInProgress -eq 0) {
if ($scan_status.ScanPossible -eq 1) {
'Channel Detection: '
' Scanning device ('+$Device_IP_Address+')...'
$lineup_scan_start_url = 'http://'+$Device_IP_Address+'/lineup.post?scan=start&source='+$scan_status.Source
# Invoke-WebRequest -Uri $lineup_scan_start_url -Method POST
$webclient.UploadString($lineup_scan_start_url,'')
} else { 'Scan not possible. May not be an available tuner.' }
} else { 'Channel detection scan already in progress...' }
# While scanning...
Do {
$scan_status = $webclient.DownloadString($status_json_url) | ConvertFrom-Json
if ($scan_status.ScanInProgress -ge 1) {
$status = ' Found '+$scan_status.Found+' programs ('+$scan_status.Progress+'%)'
Write-Host "`r"$status -NoNewLine
Start-Sleep 1
}
} While ( $scan_status.ScanInProgress -eq 1)
# $json = $webclient.DownloadString($lineup_json_url)
$Channel_Frequency_Map = @{
'57000000' = '2'
'63000000' = '3'
'69000000' = '4'
'79000000' = '5'
'85000000' = '6'
'177000000' = '7'
'183000000' = '8'
'189000000' = '9'
'195000000' = '10'
'201000000' = '11'
'207000000' = '12'
'213000000' = '13'
'473000000' = '14'
'579000000' = '15'
'485000000' = '16'
'491000000' = '17'
'497000000' = '18'
'503000000' = '19'
'509000000' = '20'
'515000000' = '21'
'521000000' = '22'
'527000000' = '23'
'533000000' = '24'
'539000000' = '25'
'545000000' = '26'
'551000000' = '27'
'557000000' = '28'
'563000000' = '29'
'569000000' = '30'
'575000000' = '31'
'581000000' = '32'
'587000000' = '33'
'593000000' = '34'
'599000000' = '35'
'605000000' = '36'
}
foreach ($ch in ($webclient.DownloadString($lineup_json_url) | ConvertFrom-Json)) {
$key = $ch.Frequency.ToString()
$channel_number = $Channel_Frequency_Map[$key]
$json += '{"ChannelNumber":"'+$channel_number+'","GuideNumber":"'+$ch.GuideNumber+'","GuideName":"'+$ch.GuideName+'"},'
# $json += '{"ChannelNumber":"'+$channel_number+'","GuideNumber":"'+$ch.GuideNumber+'","GuideName":"'+$ch.GuideName+'","CustomGuideName":""},'
$found++
}
# Final status
# $found = ('['+$json.TrimEnd(',')+']' | ConvertFrom-Json).length
$progress = 100
$status = ' Found '+$found+' programs ('+$progress+'%) '
Write-Host "`r"$status
'' # Blank line
if ($json) {
$json = $json.TrimEnd(',')
$json = '['+$json+']' # As array
# Sort by ascending GuideNumber
$array = $json | ConvertFrom-Json
$array_sorted = $array | Sort-Object { [Version]$_.GuideNumber }
$json = $array_sorted | ConvertTo-Json -Compress
}
$Script:json = $json; $Script:Device_Address = $Device_IP_Address
}
#
# Run HDHomeRun device channel detection scan; Return GuideNumber and GuideName JSON (client utility)
#
function Invoke-Device_Channel_Detection_Scan_Utility {
# Get Device ID from discover.json URL
if (!$Device_ID) {
if ($Device_IP_Address) {
# $Device = $webclient.DownloadString($discover_json_url) | ConvertFrom-Json
$Device = $webclient.DownloadString('http://'+$Device_IP_Address+'/discover.json') | ConvertFrom-Json
$Device_ID = $Device.DeviceID
} else {
'Device not found'
'' # Blank line
pause; exit;
}
}
# Use the device IP Address to avoid LAN broadcast
if ($Device_IP_Address) {
$Utility_Device_Address = $Device_IP_Address
} else {
$Utility_Device_Address = $Device_ID
}
Get-Device_Information 'client'
# Find/Select available tuner
for ($tuner = 0; $tuner -le 64; $tuner++) { # Loop depth failsafe (64)
$tuner_lockkey = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Utility_Device_Address get /tuner$tuner/lockkey
if ($tuner_lockkey -match "none" -Or $tuner_lockkey -match "ERROR") {
break
}
}
if ($tuner_lockkey -notmatch "none") {
' No Tuner Available'
'' # Blank line
pause; exit;
}
$channel_map = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Utility_Device_Address 'get' "/tuner$tuner/channelmap"
'Channel Detection: '
' Scanning device ('+$Device_ID+')... Tuner: '+$tuner+' '+$channel_map
'' # Blank line
& "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Utility_Device_Address 'scan' "/tuner$tuner" | ForEach-Object -Process { $found = 0; $progress = 0 } {
$matched = $_ -match "SCANNING: .*? \(${channel_map}:(?<channel_number>[0-9]*)\).*"
if ($matched) {
$channel_number = $matches['channel_number']
if (!$total_channels) { $total_channels = $channel_number }
$status = ' Found '+$found+' programs ('+$progress+'%) Ch. '+$channel_number+' '
$progress = [int]((($total_channels - $channel_number + 1 ) / ($total_channels - 1)) * 100)
if (!$Verbose) {
Write-Host "`r"$status -NoNewLine
}
}
$matched = $_ -match "PROGRAM *[0-9]*: *(?<GuideNumber>[0-9]{1,2}\.[0-9]*) *(?<GuideName>.*)"
if ($matched) {
$matches['GuideName'] = $matches['GuideName'] -Replace "(.*?) \(control\)(.*)", "`$1`$2"
$matches['GuideName'] = $matches['GuideName'] -Replace "(.*?) \(encrypted\)(.*)", "`$1`$2"
$matches['GuideName'] = $matches['GuideName'] -Replace "(.*?) \(no data\)(.*)", "`$1`$2"
$json += '{"ChannelNumber":"'+$channel_number+'","GuideNumber":"'+$matches['GuideNumber']+'","GuideName":"'+$matches['GuideName']+'"},'
# $json += '{"ChannelNumber":"'+$channel_number+'","GuideNumber":"'+$matches['GuideNumber']+'","GuideName":"'+$matches['GuideName']+'","CustomGuideName":""},'
$found++
}
if ($Verbose) {
Write-Host $_
}
}
# Clear the tuner channel
& "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Utility_Device_Address 'set' "/tuner$tuner/channel" "none"
if ($Verbose) {
'' # Blank line
}
# Final Status
$status = ' Found '+$found+' programs ('+$progress+'%) '
Write-Host "`r"$status
'' # Blank line
if ($json) {
$json = $json.TrimEnd(',')
$json = '['+$json+']' # As array
# Sort by ascending GuideNumber
$array = $json | ConvertFrom-Json
$array_sorted = $array | Sort-Object { [Version]$_.GuideNumber }
$json = $array_sorted | ConvertTo-Json -Compress
}
$Script:json = $json; $Script:Device_Address = $Device_ID
}
#
# Get Device Information
#
function Get-Device_Information ($method){
if ($method -eq 'web') {
$discover_json_url = 'http://'+$Device_IP_Address+'/discover.json'
$Device = $webclient.DownloadString($discover_json_url) | ConvertFrom-Json
$Device.FriendlyName
'Model: '+$Device.ModelNumber
'Firmware: '+$Device.FirmwareVersion
'Device ID: '+$Device.DeviceID
'Device IP Address: '+$Device_IP_Address
} elseif ($method -eq 'client') {
$ModelNumber = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Utility_Device_Address get /sys/hwmodel
$FirmwareVersion = & "$HDHR_Prog_Dir\$HDHR_Client_Utility" $Utility_Device_Address get /sys/version
'' # Blank line
'Model: '+$ModelNumber
'Firmware: '+$FirmwareVersion
'Device ID: '+$Device_ID
'Device IP Address: '+$Device_IP_Address
}
'' # Blank line
}
Invoke-Main
'' # Blank line
pause; exit; # Wait for user to exit/close PS window
# NOTE:
# $json = Invoke-WebRequest http://$Device_IP_Address/lineup.json?show=found # Doesn't work with UTF8 encoding
# Workaround A
# $json = Invoke-WebRequest -Uri 'http://$Device_IP_Address/lineup.json?show=found' -Outfile $EPG_Data_Dir'\hdhrlineup.json'
# $json = Get-Content -Path $EPG_Data_Dir'\hdhrlineup.json' -Encoding UTF8 -Raw
# Remove-Item -Path $EPG_Data_Dir'\hdhrlineup.json' -Force
# Workaround B
# $webclient = new-object System.Net.WebClient
# $json = $webclient.DownloadString("http://$Device_IP_Address/lineup.json?show=$Show")
# Development Environment
# Windows 8.1 Pro w/Media Center
# PowerShell: 4.0
# SiliconDust: HDHomeRun CONNECT, Model: HDHR4-2US, Firmware: 20200907
# Observed Issues
# Running a channel detection scan (web) interrupts in process viewing/recording signal.
# Running a channel detection scan (client) may append a status comment to the channel name. ex: '(control)', '(encrypted)', '(no data)' Unknown what effects this may have.
# Change Log
# Version: 20220922.3-alpha
# Clear the tuner channel after scan.
# Version: 20220922.2-alpha
# Use optional CustomGuideName field in JSON.
# Version: 20220922.1-alpha
# Use IP address for Utility_Device_Address (to avoid LAN broadcast when using device ID).
# Version: 20210719.1-alpha
# Include broadcast channel in display output and JSON.
# Version: 20210228.1-alpha
# Include station call sign in display output.
# Version: 20210111.1-alpha
# Accommodate the "matchName" field in "epg123.mxf"
# Version: 20201106.1-alpha
# Learned to select channel detection scan method (web/client/none) from variable setting.
# Learned to retrieve device information (model, firmware, ID)
# Learned how not to be verbose (client utility)
# Learned to dynamically find and select from more than two tuners (0/1) (client utility)
# Learned to override settings with parameters passed on command line
# Example command line shortcuts
# Client Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040xxxx' -Device_Channel_Detection_Scan 'client' -Device_IP_Address ''
# Default: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Retrieve_Data_From_Device $false
# No Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.x.x' -Device_Channel_Detection_Scan 'none'
# Verbose: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_ID '1040xxxx' -Device_Channel_Detection_Scan 'client' -Device_IP_Address '' -Verbose $true
# Web Scan: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\ProgramData\GaRyan2\epg123\custom_callSign_serviceName.ps1" -Device_IP_Address '192.168.x.x' -Device_Channel_Detection_Scan 'web'
# Version: 20200928.1-alpha
# Learned how to run HDHomeRun device channel detection scan
# Learned to operate standalone (without a HDHR device) using guide number and name JSON data.
# Learned to do a dry run
# Factored into functions
# Version: 20200926.1-alpha
# Genesis
Code: Select all
[
{"ChannelNumber":"24","GuideNumber":"2.1","GuideName":"KATU"},
{"ChannelNumber":"24","GuideNumber":"2.2","GuideName":"Charge!"},
{"ChannelNumber":"24","GuideNumber":"2.3","GuideName":"Comet"},
{"ChannelNumber":"24","GuideNumber":"2.4","GuideName":"TBD"},
{"ChannelNumber":"11","GuideNumber":"3.1","GuideName":"KVDO","CustomGuideName":"QVC"},
{"ChannelNumber":"25","GuideNumber":"6.1","GuideName":"KOIN-HD"},
{"ChannelNumber":"25","GuideNumber":"6.2","GuideName":"GetTV"},
{"ChannelNumber":"25","GuideNumber":"6.3","GuideName":"Rewind"},
{"ChannelNumber":"26","GuideNumber":"8.1","GuideName":"KGW"},
{"ChannelNumber":"26","GuideNumber":"8.2","GuideName":"Crime"},
{"ChannelNumber":"26","GuideNumber":"8.3","GuideName":"Quest"},
{"ChannelNumber":"26","GuideNumber":"8.4","GuideName":"Twist"},
{"ChannelNumber":"26","GuideNumber":"8.5","GuideName":"ThisTV"},
{"ChannelNumber":"26","GuideNumber":"8.6","GuideName":"TheGrio"},
{"ChannelNumber":"10","GuideNumber":"10.1","GuideName":"OPB"},
{"ChannelNumber":"10","GuideNumber":"10.2","GuideName":"OPBPlus"},
{"ChannelNumber":"10","GuideNumber":"10.3","GuideName":"OPBKids"},
{"ChannelNumber":"10","GuideNumber":"10.4","GuideName":"OPB-FM"},
{"ChannelNumber":"12","GuideNumber":"12.1","GuideName":"FOX 12"},
{"ChannelNumber":"12","GuideNumber":"12.2","GuideName":"COZI"},
{"ChannelNumber":"12","GuideNumber":"12.3","GuideName":"DABL"},
{"ChannelNumber":"12","GuideNumber":"12.4","GuideName":"FUTURE"},
{"ChannelNumber":"11","GuideNumber":"17.1","GuideName":"KWVT","CustomGuideName":"YTA"},
{"ChannelNumber":"20","GuideNumber":"20.1","GuideName":"KOXI-CD","CustomGuideName":"JewelryTV"},
{"ChannelNumber":"20","GuideNumber":"20.2","GuideName":"KOXI-CD","CustomGuideName":"NTD"},
{"ChannelNumber":"20","GuideNumber":"20.3","GuideName":"KOXI-CD","CustomGuideName":"BUZZR"},
{"ChannelNumber":"20","GuideNumber":"20.4","GuideName":"KOXI-CD","CustomGuideName":"TELEMUNDO"},
{"ChannelNumber":"20","GuideNumber":"20.5","GuideName":"KOXI-CD","CustomGuideName":"ShopLC"},
{"ChannelNumber":"20","GuideNumber":"20.6","GuideName":"KOXI-CD","CustomGuideName":"LX"},
{"ChannelNumber":"20","GuideNumber":"20.7","GuideName":"KOXI-CD","CustomGuideName":"MeTV"},
{"ChannelNumber":"22","GuideNumber":"22.1","GuideName":"ION"},
{"ChannelNumber":"22","GuideNumber":"22.2","GuideName":"Bounce"},
{"ChannelNumber":"22","GuideNumber":"22.3","GuideName":"Laff"},
{"ChannelNumber":"22","GuideNumber":"22.4","GuideName":"Defy TV"},
{"ChannelNumber":"22","GuideNumber":"22.5","GuideName":"TruReal"},
{"ChannelNumber":"22","GuideNumber":"22.6","GuideName":"NEWSY"},
{"ChannelNumber":"22","GuideNumber":"22.7","GuideName":"QVC"},
{"ChannelNumber":"22","GuideNumber":"22.8","GuideName":"HSN"},
{"ChannelNumber":"23","GuideNumber":"23.1","GuideName":"CRIME"},
{"ChannelNumber":"23","GuideNumber":"23.2","GuideName":"QVC"},
{"ChannelNumber":"23","GuideNumber":"23.3","GuideName":"HSN"},
{"ChannelNumber":"23","GuideNumber":"23.4","GuideName":"QVC2"},
{"ChannelNumber":"23","GuideNumber":"23.5","GuideName":"HSN2"},
{"ChannelNumber":"32","GuideNumber":"24.1","GuideName":"TBN HD"},
{"ChannelNumber":"32","GuideNumber":"24.2","GuideName":"inspire"},
{"ChannelNumber":"32","GuideNumber":"24.3","GuideName":"SMILE"},
{"ChannelNumber":"32","GuideNumber":"24.4","GuideName":"Enlace"},
{"ChannelNumber":"32","GuideNumber":"24.5","GuideName":"POSITIV"},
{"ChannelNumber":"11","GuideNumber":"27.1","GuideName":"KSLM","CustomGuideName":"theDove"},
{"ChannelNumber":"29","GuideNumber":"29.1","GuideName":"KJYY-LD","CustomGuideName":"TELEMUNDO"},
{"ChannelNumber":"29","GuideNumber":"29.2","GuideName":"TXitos"},
{"ChannelNumber":"29","GuideNumber":"29.3","GuideName":"MeTV"},
{"ChannelNumber":"29","GuideNumber":"29.4","GuideName":"AceTV"},
{"ChannelNumber":"29","GuideNumber":"29.5","GuideName":"HSN"},
{"ChannelNumber":"29","GuideNumber":"29.6","GuideName":"ShopLC"},
{"ChannelNumber":"29","GuideNumber":"29.7","GuideName":"Sonlife","CustomGuideName":"SBN"},
{"ChannelNumber":"31","GuideNumber":"31.1","GuideName":"KBLN-DT","CustomGuideName":"3ABN"},
{"ChannelNumber":"31","GuideNumber":"31.2","GuideName":"BLBN-2","CustomGuideName":"Better Health TV"},
{"ChannelNumber":"31","GuideNumber":"31.3","GuideName":"BLBN-3","CustomGuideName":"HOPE"},
{"ChannelNumber":"31","GuideNumber":"31.4","GuideName":"BLBN-4","CustomGuideName":"ESPRNZA"},
{"ChannelNumber":"24","GuideNumber":"32.1","GuideName":"KRCW","CustomGuideName":"CW"},
{"ChannelNumber":"25","GuideNumber":"32.2","GuideName":"Antenna"},
{"ChannelNumber":"25","GuideNumber":"32.3","GuideName":"Grit"},
{"ChannelNumber":"25","GuideNumber":"32.4","GuideName":"TBD"},
{"ChannelNumber":"11","GuideNumber":"37.1","GuideName":"Azteca"},
{"ChannelNumber":"21","GuideNumber":"42.1","GuideName":"KPXG-LD","CustomGuideName":"Daystar"},
{"ChannelNumber":"21","GuideNumber":"42.2","GuideName":"KPXG-ES","CustomGuideName":"Daystar-ES"},
{"ChannelNumber":"21","GuideNumber":"42.3","GuideName":"KPXG-LD","CustomGuideName":"Daystar"},
{"ChannelNumber":"34","GuideNumber":"47.1","GuideName":"KUNP-LD","CustomGuideName":"Univision"},
{"ChannelNumber":"34","GuideNumber":"47.2","GuideName":"Stadium"},
{"ChannelNumber":"34","GuideNumber":"47.3","GuideName":"Charge!"},
{"ChannelNumber":"12","GuideNumber":"49.1","GuideName":"Fox12+"},
{"ChannelNumber":"26","GuideNumber":"49.2","GuideName":"Mystery"},
{"ChannelNumber":"12","GuideNumber":"49.3","GuideName":"Circle"},
{"ChannelNumber":"26","GuideNumber":"49.4","GuideName":"CourtTV"}
]