|
param([int]$port = 18180) |
|
$url = "http://localhost:$port/" |
|
|
|
function Invoke-ITunesServer { |
|
param([Parameter(Mandatory)][string]$Url) |
|
$iTunesApplication = Get-ITunesApplication |
|
$iTunesPlaylists = $iTunesApplication.LibrarySource.Playlists |
|
$listener = New-Object Net.HttpListener |
|
$listener.Prefixes.Add($Url) |
|
Write-Host "Listening... at $Url" |
|
Write-Host "Press Ctrl-C to quit." |
|
$listener.Start() |
|
try { |
|
while ($true) { |
|
$contextTask = $listener.GetContextAsync() |
|
while (-not $contextTask.AsyncWaitHandle.WaitOne(200)) { } |
|
$context = $contextTask.GetAwaiter().GetResult() |
|
$request = $context.Request |
|
$response = $context.Response |
|
Write-Host $request.RawUrl |
|
$localPath = $request.Url.LocalPath |
|
if ($localPath -eq "/start") { |
|
if (($id = $request.QueryString.Get("id")) -and "$id".Length -eq 16) { |
|
Start-Playlist $id ("shuffle" -in $request.QueryString.Keys) ("repeat" -in $request.QueryString.Keys) |
|
} |
|
else { |
|
$response.StatusCode = 403 |
|
} |
|
} |
|
elseif ($localPath -eq "/stop") { |
|
Stop-Playing |
|
} |
|
elseif ($localPath -eq "/volume") { |
|
if ($add = $request.QueryString.Get("add") -as [int]) { |
|
Add-SoundVolume $add |
|
} |
|
} |
|
elseif ($localPath -eq "/playlists") { |
|
$content = [System.Text.Encoding]::UTF8.GetBytes((Get-All-UserPlaylists | ConvertTo-Json -Compress)) |
|
$response.ContentType = "application/json" |
|
$response.OutputStream.Write($content, 0, $content.Length) |
|
} |
|
elseif ($localPath -eq "/") { |
|
$content = [System.Text.Encoding]::UTF8.GetBytes((Get-Html (Get-All-UserPlaylists | ConvertTo-Json -Compress))) |
|
$response.ContentType = "text/html" |
|
$response.OutputStream.Write($content, 0, $content.Length) |
|
} |
|
else { |
|
$response.StatusCode = 404 |
|
} |
|
$response.Close() |
|
} |
|
} |
|
finally { |
|
$listener.Close() |
|
Write-Verbose "release-comobject at end" |
|
while ([Runtime.Interopservices.Marshal]::ReleaseComObject($iTunesPlaylists)) { Write-Verbose "retry release playlists" } |
|
$iTunesPlaylists = $null |
|
while ([Runtime.Interopservices.Marshal]::ReleaseComObject($iTunesApplication)) { Write-Verbose "retry release itunesapplication" } |
|
$iTunesApplication = $null |
|
[GC]::Collect() |
|
} |
|
} |
|
function Get-ITunesApplication { |
|
New-Object -ComObject iTunes.Application |
|
} |
|
function Get-All-UserPlaylists { |
|
$iTunesPlaylists | ForEach-Object { |
|
if ($_.SpecialKind -in 0, 4, 6) { |
|
#0:No special kind,4:Folder playlist,6:Music playlist |
|
[pscustomobject] @{ |
|
Name = $_.Name |
|
Kind = @{0 = 0; 1 = 1; 5 = 2; 7 = 3; }[$_.SpecialKind + [bool]$_.Smart] #0:List,1:Smart,2:Folder,3:AllMusic |
|
Id = $iTunesApplication.ITObjectPersistentIDHigh($_).ToString("X8") ` |
|
+ $iTunesApplication.ITObjectPersistentIDLow($_).ToString("X8") |
|
} |
|
} |
|
[void][Runtime.Interopservices.Marshal]::ReleaseComObject($_) |
|
} |
|
[void][Runtime.Interopservices.Marshal]::ReleaseComObject($iTunesPlaylists) |
|
} |
|
function Start-Playlist { |
|
param( |
|
[Parameter(Mandatory)][ValidateLength(16, 16)][string]$PersistentId, |
|
[bool]$ForceShuffle = $false, |
|
[bool]$ForceRepeat = $false |
|
) |
|
$playlist = $iTunesPlaylists.ItemByPersistentID( |
|
"0x$($persistentId.Substring(0,8))", "0x$($persistentId.Substring(8,8))" |
|
) |
|
if ($playlist) { |
|
if ($ForceShuffle) { |
|
Write-Verbose "set shuffle" |
|
$playlist.Shuffle = $true #$true,$false |
|
} |
|
if ($ForceRepeat) { |
|
Write-Verbose "set repeat" |
|
$playlist.SongRepeat = 2 #0:play once,1:track repeat,2:playlist repeat |
|
} |
|
$playlist.PlayFirstTrack() |
|
[void][Runtime.Interopservices.Marshal]::ReleaseComObject($playlist) |
|
$playlist = $null |
|
} |
|
} |
|
function Add-SoundVolume { |
|
param([int]$Add = 10 ) |
|
$volume = $iTunesApplication.SoundVolume + $Add |
|
$iTunesApplication.SoundVolume = |
|
if ($volume -le 0) { 0 } |
|
elseif ($volume -ge 100) { 100 } |
|
else { $volume } |
|
$iTunesApplication.SoundVolume |
|
} |
|
function Stop-Playing { |
|
$iTunesApplication.Pause() |
|
} |
|
function Get-Html { |
|
param ([string]$json = "[]") |
|
@' |
|
<!doctype html> |
|
<meta charset="utf-8"> |
|
<title>iTunes Server Setting</title> |
|
<style type="text/css"> |
|
*{box-sizing:border-box}body{max-width:60em;padding:1em;margin:auto;font:1em/1.6 sans-serif}table,textarea{width:100%}input[type=text]{padding:.5em;border:solid #eee;width:100%}td,th{padding:.5em;text-align:left;border-bottom:solid #eee}tr.checked>td{border-bottom-color:#fa0}td.up{width:4em}tr.checked:nth-child(n+2)>td.up:before{content:"\01F53A"} |
|
</style> |
|
|
|
<h1>🎵Select playlists to display in Stormworks</h1> |
|
<textarea></textarea> |
|
<form><table><thead><tr><th> ✅ Playlist<th>Display Name (only ASCII characters)<th><tbody></table></form> |
|
<script type="application/json" id="json-playlists"> |
|
%json% |
|
</script> |
|
<script> |
|
const e=(e,t=document)=>t.querySelector(e),t=(e,t=document)=>t.querySelectorAll(e),n=["📝","🔅","📁","🎶"],c=JSON.parse(e("#json-playlists").textContent),a=e("tbody"),r=e("form"),o=()=>{e("textarea").value=[...new FormData(r).entries()].map(([e,t])=>`${t},${e}`).join(",")};c.forEach(({Name:e,Kind:t,Id:c},r)=>a.insertAdjacentHTML("beforeend",`<tr name="${r}"><td><label><input type="checkbox">${n[t]+e}</label><td><input type="text" name="${c}" pattern="[!-~]+" value="${(e.replace(/[^\x21-\x7e]+/g,"")||"list"+r).toUpperCase()}" disabled><td class="up">`)),t('input[type="checkbox"]',a).forEach(n=>n.addEventListener("change",n=>((n,c=!0)=>{const r=e('input[type="text"]',n);if(e('input[type="checkbox"]',n).checked)n.classList.add("checked"),r.disabled=!1,a.insertBefore(n,e("tr:not(.checked)",a)),c&&r.focus();else{n.classList.remove("checked"),e('input[type="text"]',n).disabled=!0,$notcheck=t("tr:not(.checked)",a);const c=n.getAttribute("name")-0;let r=null;for(let e=0;e<$notcheck.length;++e)if($notcheck[e].getAttribute("name")-0>c){r=$notcheck[e];break}a.insertBefore(n,r)}})(n.target.parentElement.parentElement.parentElement))),t("td.up").forEach(e=>e.addEventListener("click",e=>{const t=e.target.parentElement;t.classList.contains("checked")&&t.previousSibling&&(a.insertBefore(t,t.previousSibling),o())})),r.addEventListener("change",e=>o()),r.addEventListener("submit",e=>e.preventDefault()) |
|
</script> |
|
'@ -replace "%json%", $json |
|
} |
|
|
|
if ($MyInvocation.InvocationName -ne ".") { |
|
# $VerbosePreference = 'Continue' |
|
# Write-Host $url |
|
# $iTunesApplication = Get-ITunesApplication |
|
# $iTunesPlaylists = $iTunesApplication.LibrarySource.Playlists |
|
# Get-All-UserPlaylists | ConvertTo-Json -Compress |
|
# Start-Playlist "8F84264DF04A814B" $true $true |
|
# Add-SoundVolume 0 |
|
# Stop-Playing |
|
# [Runtime.Interopservices.Marshal]::ReleaseComObject($iTunesPlaylists) |
|
# $iTunesPlaylists = $null |
|
# [GC]::Collect() |
|
# [Runtime.Interopservices.Marshal]::ReleaseComObject($iTunesApplication) |
|
# $iTunesApplication = $null |
|
# [GC]::Collect() |
|
Invoke-ITunesServer $url |
|
} |
Invoke-Expression
で実行するスクリプトファイルの引数の与え方別の方法があれば教えてください。