|
$originalDebugPreference = $DebugPreference |
|
$DebugPreference = "SilentlyContinue" # Continue SilentlyContinue |
|
|
|
### read setting.json file |
|
set-variable -name SETTING_JSON_FILE -value ".\setting.json" -option constant |
|
if (Test-Path $SETTING_JSON_FILE) { |
|
$settingJson = ConvertFrom-Json -InputObject (Get-Content $SETTING_JSON_FILE -Encoding UTF8 -Raw) |
|
} |
|
else { |
|
$settingJson = [PSCustomObject] @{ |
|
PhotoPath = $env:USERPROFILE + "\Pictures\VRChat"; |
|
logPath = $env:LOCALAPPDATA + "Low\VRChat\vrchat"; |
|
MakeWorldInfoFile = $TRUE; |
|
WithTweetText = $TRUE; |
|
IncludeTweetWldLink = $TRUE; |
|
IncludeTweetText = "#VRChat_world紹介 #MadeWithVRChat"; |
|
} |
|
} |
|
|
|
### ser GUI Form |
|
[void][reflection.assembly]::LoadWithPartialName("Microsoft.VisualBasic") |
|
Add-Type -AssemblyName PresentationFramework |
|
Add-Type -AssemblyName System.Windows.Forms |
|
|
|
[xml]$xaml = @' |
|
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|
Title="VRCHat Photo Selector" Height="330" Width="640" MinWidth="640" MinHeight="330"> |
|
<Grid Margin="0,0,0,0"> |
|
<Grid.RowDefinitions> |
|
<RowDefinition Height="50"/> |
|
<RowDefinition Height="50"/> |
|
<RowDefinition Height="50"/> |
|
<RowDefinition Height="100*"/> |
|
</Grid.RowDefinitions> |
|
<Grid.ColumnDefinitions> |
|
<ColumnDefinition Width="75*"/> |
|
<ColumnDefinition Width="150*"/> |
|
<ColumnDefinition Width="75*"/> |
|
</Grid.ColumnDefinitions> |
|
|
|
<Label x:Name="lblPhotoPath" Content="Photos filepath" Margin="10,15,18,0" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" Height="26" /> |
|
<TextBox x:Name="txtPhotoPath" Text="" Height="25" VerticalAlignment="Top" Grid.Row="0" Grid.Column="1" Margin="10,15,16,0" /> |
|
<Button x:Name="btnSelectPhotoPath" Content="Select" Margin="10,15,10,0" VerticalAlignment="Top" Height="25" Grid.Row="0" Grid.Column="2" /> |
|
|
|
<Label x:Name="lblFilePath" Content="Log filepath" Margin="10,15,18,0" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" Height="26" /> |
|
<TextBox x:Name="txtLogPath" Text="" Height="25" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" Margin="10,15,16,0" /> |
|
<Button x:Name="btnSelectLogPath" Content="Select" Margin="10,15,10,0" VerticalAlignment="Top" Height="25" Grid.Row="1" Grid.Column="2" /> |
|
|
|
<Label x:Name="lblLogFile" Content="Logfile" Margin="10,16,18,0" Grid.Row="2" Grid.Column="0" VerticalAlignment="Top" Height="24"/> |
|
<ComboBox x:Name="cmbLogFile" Height="25" VerticalAlignment="Top" Margin="10,15,16,0" Grid.Row="2" Grid.Column="1" /> |
|
|
|
<Button x:Name="btnRun" Content="Run" Margin="10,15,10,10" Grid.Row="2" Grid.Column="2" Grid.RowSpan="2"/> |
|
|
|
<CheckBox x:Name="cbMakeWorldInfoFile" Content="Make world information textfile." Grid.Column="1" HorizontalAlignment="Left" Margin="10,15,0,0" Grid.Row="3" VerticalAlignment="Top" IsChecked="True"/> |
|
|
|
<Button x:Name="btnExit" Content="Exit" Margin="10,10,10,10" VerticalAlignment="Bottom" Height="37" Grid.Row="3" Grid.Column="0" /> |
|
|
|
<CheckBox x:Name="cbWithTweetText" Content="Make world tweet text." Grid.Column="1" HorizontalAlignment="Left" Margin="10,35,0,0" Grid.Row="3" VerticalAlignment="Top" IsChecked="True"/> |
|
<CheckBox x:Name="cbIncludeTweetWldLink" Content="With VRChat world-url/link." Grid.Column="1" HorizontalAlignment="Left" Margin="30,60,0,0" Grid.Row="3" VerticalAlignment="Top" /> |
|
<Label x:Name="lblIncludeTweetText" Content="Tweet text/hashtags" Margin="28,75,0,0" Grid.Column="1" Grid.Row="3"/> |
|
<TextBox x:Name="txtIncludeTweetText" Text="" Height="25" Width="270" Grid.Column="1" HorizontalAlignment="Left" Margin="30,95,10,10" Grid.Row="3" VerticalAlignment="Top" /> |
|
</Grid> |
|
</Window> |
|
'@ |
|
|
|
$reader = New-Object System.Xml.XmlNodeReader $xaml |
|
$frm = [System.Windows.Markup.XamlReader]::Load($reader) |
|
|
|
# exit button |
|
$frmBtnExit = $frm.FindName("btnExit") |
|
$frmBtnExit.Add_Click( { |
|
#save setting.json |
|
$frmPhotoPath = $frm.FindName("txtPhotoPath") |
|
$frmLogPath = $frm.FindName("txtLogPath") |
|
$frmMakeWorldInfoFile = $frm.FindName("cbMakeWorldInfoFile") |
|
$frmWithTweetText = $frm.FindName("cbWithTweetText") |
|
$frmIncludeTweetWldLink = $frm.FindName("cbIncludeTweetWldLink") |
|
$frmIncludeTweetText = $frm.FindName("txtIncludeTweetText") |
|
|
|
$settingJson = @{ |
|
PhotoPath = $frmPhotoPath.text; |
|
logPath = $frmLogPath.text |
|
MakeWorldInfoFile = $frmMakeWorldInfoFile.IsChecked; |
|
WithTweetText = $frmWithTweetText.IsChecked; |
|
IncludeTweetWldLink = $frmIncludeTweetWldLink.IsChecked |
|
IncludeTweetText = $frmIncludeTweetText.text; |
|
} |
|
$settingJson | ConvertTo-Json | Out-File $SETTING_JSON_FILE -Encoding UTF8 |
|
|
|
$frm.close() |
|
}) |
|
|
|
# text PhotoPath |
|
$frmPhotoPath = $frm.FindName("txtPhotoPath") |
|
$frmPhotoPath.text = $settingJson.PhotoPath |
|
|
|
#select-button PhotoPath |
|
$frmBtnSelectPhotoPath = $frm.FindName("btnSelectPhotoPath") |
|
$frmBtnSelectPhotoPath.Add_Click( { |
|
$frmPhotoPath = $frm.FindName("txtPhotoPath") |
|
|
|
$dialog = New-Object System.Windows.Forms.OpenFileDialog |
|
$dialog.Filter = "PNG File (*.png)|*.png|All Files (*.*)|*.*" |
|
$dialog.InitialDirectory = $frmPhotoPath.text |
|
$dialog.Title = "Select VRChat Photo Folder" |
|
|
|
if ($dialog.ShowDialog() -eq "OK") { |
|
$path = Split-Path -Parent $dialog.FileName |
|
$frmPhotoPath.text = $path |
|
} |
|
}) |
|
|
|
# text LogPath |
|
$logPath = $settingJson.logPath |
|
$frmLogPath = $frm.FindName("txtLogPath") |
|
$frmLogPath.text = $logPath |
|
|
|
function setLogFilesName($Path) { |
|
$frmCmbLogFile = $frm.FindName("cmbLogFile") |
|
$frmCmbLogFile.Items.Clear(); |
|
|
|
Get-ChildItem $Path | |
|
Sort-Object LastWriteTime -Descending | |
|
Where-Object { $_.Extension -eq ".txt" } | |
|
ForEach-Object { |
|
$filename = $_.Name + "`t" + "[Updated:" + $(Get-ItemProperty $_.FullName).LastWriteTime + "]" |
|
[void]$frmCmbLogFile.Items.Add($filename) |
|
} |
|
} |
|
setLogFilesName($logPath) |
|
|
|
#select-button LogPath |
|
$frmBtnSelectLogPath = $frm.FindName("btnSelectLogPath") |
|
$frmBtnSelectLogPath.Add_Click( { |
|
$frmLogPath = $frm.FindName("txtLogPath") |
|
|
|
$dialog = New-Object System.Windows.Forms.OpenFileDialog |
|
$dialog.Filter = "Text File (*.txt)|*.txt|All Files (*.*)|*.*" |
|
$dialog.InitialDirectory = $frmLogPath.text |
|
$dialog.Title = "Select VRChat Logfile" |
|
|
|
if ($dialog.ShowDialog() -eq "OK") { |
|
$path = Split-Path -Parent $dialog.FileName |
|
$frmLogPath.text = $path |
|
|
|
# select combobox item |
|
$frmCmbLogFile = $frm.FindName("cmbLogFile") |
|
setLogFilesName($path) |
|
$filename = [System.IO.Path]::GetFileName($dialog.FileName) |
|
for ($i = 0; $i -lt $frmCmbLogFile.Items.Count; $i++) { |
|
$tmpName = $frmCmbLogFile.Items[$i].ToString().split(" ") |
|
if ($tmpName[0] -eq $filename) { |
|
$frmCmbLogFile.SelectedIndex = $i |
|
} |
|
} |
|
} |
|
}) |
|
|
|
# checkbox cbMakeWorldInfoFile |
|
$frmMakeWorldInfoFile = $frm.FindName("cbMakeWorldInfoFile") |
|
$frmMakeWorldInfoFile.IsChecked = $settingJson.MakeWorldInfoFile |
|
|
|
# checkbox cbWithTweetText |
|
$frmWithTweetText = $frm.FindName("cbWithTweetText") |
|
$frmWithTweetText.IsChecked = $settingJson.WithTweetText |
|
|
|
# checkbox cbIncludeTweetWldLink |
|
$frmIncludeTweetWldLink = $frm.FindName("cbIncludeTweetWldLink") |
|
$frmIncludeTweetWldLink.IsChecked = $settingJson.IncludeTweetWldLink |
|
|
|
# textbox txtIncludeTweetText |
|
$frmIncludeTweetText = $frm.FindName("txtIncludeTweetText") |
|
$frmIncludeTweetText.text = $settingJson.IncludeTweetText |
|
|
|
# button RUN |
|
$frmBtnRun = $frm.FindName("btnRun") |
|
$frmBtnRun.Add_Click( { |
|
$frmLogPath = $frm.FindName("txtLogPath") |
|
$frmCmbLogFile = $frm.FindName("cmbLogFile") |
|
|
|
if ($frmCmbLogFile.SelectedIndex -lt 0) { |
|
[System.Windows.Forms.MessageBox]::Show("VRCHat logfile is not select.", "Error") |
|
return |
|
} |
|
|
|
$tmpName = $frmCmbLogFile.Items[$frmCmbLogFile.SelectedIndex].ToString().split("`t") |
|
$logfile = $frmLogPath.text + "\" + $tmpName[0] |
|
if (Test-Path $logfile) { |
|
} |
|
else { |
|
[System.Windows.Forms.MessageBox]::Show("VRCHat logfile is not found.", "Error") |
|
return |
|
} |
|
|
|
$frmPhotoPath = $frm.FindName("txtPhotoPath") |
|
$photodir = $frmPhotoPath.text |
|
if (Test-Path $photodir) { |
|
} |
|
else { |
|
[System.Windows.Forms.MessageBox]::Show("VRCHat Photos Folder is not found.", "Error") |
|
return |
|
} |
|
|
|
$enc = [System.Text.Encoding]::UTF8 |
|
$parser = New-Object -TypeName Microsoft.VisualBasic.FileIO.TextFieldParser $logfile, $enc |
|
|
|
$parser.TextFieldType = [Microsoft.VisualBasic.FileIO.FieldType]::FixedWidth |
|
$parser.SetFieldWidths(20, 11, 3, -1) |
|
|
|
## Parse VRChat Logfile. |
|
$target = "" |
|
$dtEnd = "" |
|
$isInRoom = $FALSE |
|
$listWorlds = @{ } |
|
While ($parser.EndOfData -eq $false) { |
|
try { |
|
$fields = $parser.ReadFields() |
|
|
|
# skip brankline |
|
if ($fields -eq "") { |
|
continue |
|
} |
|
|
|
$dateTime = [System.Datetime]::Parse($fields[0].Trim()) # Date Time |
|
$loglevel = $fields[1].Trim() # log level |
|
$dummy = $fields[2] # |
|
$text = $fields[3].Trim() # text |
|
|
|
Write-Debug ("text(fields[3]): " + $text) |
|
} |
|
catch { |
|
continue |
|
} |
|
|
|
if ($text.StartsWith("[")) { |
|
$target = $text.Substring(1, $text.IndexOf("]") - 1) |
|
Write-Debug ("(target)" + $target) |
|
} |
|
|
|
# check into room |
|
if ($text.Contains("Entering world")) { |
|
$isInRoom = $TRUE |
|
} |
|
Write-Debug ("isInRoom: " + $isInRoom) |
|
|
|
# RoomManager |
|
if ("RoomManager" -eq $target -Or $isInRoom -eq $TRUE) { |
|
# Join room |
|
$keyword = "Entering Room:" |
|
if ($text.Contains($keyword)) { |
|
$dtBegin = $dateTime |
|
Write-Debug ("EnteringRoom(text): " + $text) |
|
|
|
$posFrom = $text.IndexOf($keyword) + $keyword.Length |
|
$length = $text.Length - $posFrom |
|
$worldTitle = $text.Substring($posFrom, $length).Trim() |
|
Write-Debug ("EnteringRoom(dateTime):" + $dateTime) |
|
Write-Debug ("EnteringRoom(target):" + $target) |
|
Write-Debug ("EnteringRoom(worldTitle):" + $worldTitle) |
|
} |
|
|
|
# World ID |
|
$keyword = "Joining" |
|
if ($text.Contains("Joining wrld_") ) { |
|
$dtBegin = $dateTime |
|
|
|
$posFrom = $text.IndexOf($keyword) + $keyword.Length |
|
|
|
$posEnd = $text.IndexOf(":") |
|
$length = $posEnd - $posFrom |
|
|
|
$worldTempId = $text.Substring($posFrom, $length).Trim() |
|
if ($worldTempId.Substring(0, 4) -eq "wrld") { |
|
$worldId = $worldTempId |
|
Write-Debug ("Joining(worldID): " + $worldId) |
|
} |
|
} |
|
|
|
# leave room |
|
$keyword = "Successfully left room" |
|
if ($text.Contains($keyword)) { |
|
$dtEnd = $dateTime |
|
|
|
Write-Debug ("Action log: " + $dtBegin + ", " + $dateTime + ", " + $worldTitle + "," + $worldId ) |
|
$listWorlds.Add($listWorlds.Count, @($dtBegin, $dtEnd, $worldTitle, $worldId)) |
|
$dtEnd = "" |
|
|
|
$isInRoom = $FALSE |
|
} |
|
} |
|
} |
|
if ($dtEnd -eq "") { |
|
Write-Debug ("Action log: " + $dtBegin + ", " + $dateTime + ", " + $worldTitle + "," + $worldId ) |
|
$listWorlds.Add($listWorlds.Count, @($dtBegin, $dateTime, $worldTitle, $worldId)) |
|
} |
|
|
|
$listWorlds |
|
|
|
$frmCbMakeWorldInfoFile = $frm.FindName("cbMakeWorldInfoFile") |
|
$isMakeWorldFile = $frmCbMakeWorldInfoFile.IsChecked |
|
|
|
$frmCbWithTweetText = $frm.FindName("cbWithTweetText") |
|
$isWithTweetText = $frmCbWithTweetText.IsChecked |
|
|
|
$frmIncludeTweetWldLink = $frm.FindName("cbIncludeTweetWldLink") |
|
$isIncludeTweetWldLink = $frmIncludeTweetWldLink.IsChecked |
|
|
|
$frmIncludeTweetText = $frm.FindName("txtIncludeTweetText") |
|
$txtIncludeTweetText = $frmIncludeTweetText.text |
|
|
|
Write-Debug ("isMakeWorldFile = " + $isMakeWorldFile) |
|
Write-Debug ("isWithTweetText = " + $isWithTweetText) |
|
Write-Debug ("isIncludeTweetWldLink = " + $isIncludeTweetWldLink) |
|
Write-Debug ("txtIncludeTweetText = " + $txtIncludeTweetText) |
|
Write-Debug ("listWorlds.Count = " + $listWorlds.Count) |
|
|
|
# pickup photo files |
|
$photoFiles = @() |
|
$photoFiles += Get-ChildItem $photodir | Where-Object { ! $_.PSIsContainer } # photo directory(-2021-09) |
|
$photoFiles += Get-ChildItem -Recurse $photodir | Where-Object { (! $_.PSIsContainer) -And ($_.Directory.Name -match "20[0-9]{2}-[0|1][0-9]") } # photo directory(2021-10, yyyy-mm) |
|
|
|
for ($i = 0; $i -lt $listWorlds.Count; $i++) { |
|
Write-Debug([string]::Concat($i, ",", $listWorlds[$i][0], "~", $listWorlds[$i][1], ", ", $listWorlds[$i][3], ", ", $listWorlds[$i][2])) |
|
|
|
$isSetTextfile = $FALSE |
|
|
|
$photoFiles | |
|
Where-Object { ($_.LastWriteTime -ge $listWorlds[$i][0]) -and ($_.LastWriteTime -le $listWorlds[$i][1]) } | |
|
ForEach-Object { |
|
Write-Debug ("Target photo file: " + $_.Name + ", " + $_.LastWriteTime) |
|
|
|
if ( $_.Directory.Name -match "20[0-9]{2}-[0|1][0-9]" ) { |
|
$dirname = $_.Directory.Name + "\" + $listWorlds[$i][0].ToString("yyyyMMdd-HHmmss") + " " + $listWorlds[$i][2].Replace('>', '>').Replace('<', '<').Replace('\', '\').Replace('|', '|') |
|
} |
|
else { |
|
$dirname = $listWorlds[$i][0].ToString("yyyyMMdd-HHmmss") + " " + $listWorlds[$i][2].Replace('>', '>').Replace('<', '<').Replace('\', '\').Replace('|', '|') |
|
} |
|
|
|
if (Test-Path ($photodir + "\" + $dirname)) { |
|
} |
|
else { |
|
New-Item ($photodir + "\" + $dirname) -ItemType Directory |
|
} |
|
|
|
if ($isSetTextfile -eq $FALSE) { |
|
$textValue = "" |
|
|
|
if ($isMakeWorldFile -eq $TRUE) { |
|
$textValue = "Joined at " + $listWorlds[$i][0] + "`r`n", |
|
"Leaved at " + $listWorlds[$i][1] + "`r`n", |
|
"`r`n", |
|
"World name : " + $listWorlds[$i][2] + "`r`n", |
|
"World ID : " + $listWorlds[$i][3] + "`r`n" |
|
$textValue = $textValue + "`r`n" |
|
} |
|
|
|
if ($isWithTweetText -eq $TRUE) { |
|
if ($textValue -ne "") { |
|
$textValue = $textValue + "`r`n" + "-----------------" + "`r`n" |
|
} |
|
|
|
$textValue = $textValue + $listWorlds[$i][2] + "`r`n" |
|
|
|
if ($txtIncludeTweetText -ne "") { |
|
$textValue = $textValue + $txtIncludeTweetText + "`r`n" |
|
} |
|
if ($isIncludeTweetWldLink -eq $TRUE) { |
|
$textValue = $textValue + "https://vrchat.com/home/launch?worldId=" + $listWorlds[$i][3] + "`r`n" |
|
} |
|
} |
|
|
|
if ($textValue -ne "") { |
|
|
|
$worldFileName = $photodir + "\" + $dirname + "\World_" + $listWorlds[$i][0].ToString("yyyyMMdd-HHmmss") |
|
|
|
$textValue = $textValue -replace "`r`n ", "`r`n" |
|
$worldTextName = $worldFileName + ".txt" |
|
Write-Debug ("world text file: " + $worldTextName) |
|
Set-Content -Path $worldTextName -Encoding UTF8 -Value $textValue |
|
|
|
# $listWorlds[$i] | ConvertTo-Json | Out-File -LiteralPath ($worldFileName + ".json") -Encoding utf8 |
|
} |
|
} |
|
|
|
$isSetTextfile = $TRUE |
|
if (Test-Path ($_.FullName)) { |
|
Write-Debug ("Move file: " + ($_.FullName) + " → " + ($photodir + "\" + $dirname)) |
|
Move-Item ($_.FullName) ($photodir + "\" + $dirname) |
|
} |
|
else { |
|
Write-Debug ("Error photo: " + $_.FullName) |
|
} |
|
} |
|
} |
|
[System.Windows.Forms.MessageBox]::Show("Selected photos", "Finish") |
|
}) |
|
|
|
$result = $frm.ShowDialog() |
|
$DebugPreference = $originalDebugPreference |