### # Allgemeine Parameter param( [Parameter(Mandatory=$true)][string]$chat_file ) [array]$csv_content_chat = Import-Csv $chat_file [array]$content = $null [string]$curDate = $null [string]$oldDate = $null [string]$chat_partner_name = $null [string]$msg_status = $null # Teste auf leere Chat-CSV-Datei If ($csv_content_chat.Length -eq 0){ Write-Host "Chat-Datei hat keinen Inhalt." Exit 1 } Try { # Teste auf Vorhandensein der Umfrage-Dateien [array]$csv_content_ballot = Import-Csv "ballot.csv" [array]$csv_content_bvote = Import-Csv "ballot_vote.csv" [array]$csv_content_bchoice = Import-Csv "ballot_choice.csv" } Catch { Write-Host "Nicht alle ""ballot*""-Dateien (für Umfragen) gefunden!" Exit 3 } Try { # Teste auf Vorhandensein der Kontakte- und Gruppen-Datei [array]$csv_content_contacts = Import-Csv "contacts.csv" [array]$csv_content_groups = Import-Csv "groups.csv" } Catch { Write-Host "Datei ""contacts.csv"" oder ""groups.csv"" nicht gefunden!" Exit 2 } # Prüfe auf Gruppe oder Einzelchat/Kanal #If ($csv_content_chat[0].PSObject.Properties.Name[2] -eq "identity"){ If (($csv_content_chat[0] | Get-Member -Name identity).Name -eq "identity"){ [bool]$isGroup = $true [string]$chat_id = (Get-ChildItem $chat_file).BaseName.Split("_")[2].Split("-")[0] } Else { [bool]$isGroup = $false # Teste auf Kanal, ansonsten Einzelchat If ((Get-ChildItem $chat_file).BaseName.Split("_").Count -eq 3){ [string]$chat_id = (Get-ChildItem $chat_file).BaseName.Split("_")[2] } Else { [string]$chat_id = (Get-ChildItem $chat_file).BaseName.Split("_")[1] } } # Wenn Kanal (mit * beginnend), dann setze den in der ID auch bitte If ($chat_id.Length -eq 7){ $chat_id = "*"+$chat_id } # Medienordner mit "gc_" oder "id_" beginnend If ($isGroup){ [string]$chat_id_folder = "gc_"+$chat_id [string]$chat_id_identity = $chat_id } Else { [string]$chat_id_folder = "id_"+$chat_id.Replace("*", "_") [string]$chat_id_identity = $chat_id.Replace("*", "_") } # Funktion zum Konvertieren der Sekunden-Zeitstempel Function ConvertUnixTime ([string]$msg_timestamp_unix, [bool]$fulldatetime){ $msg_timestamp_unix = $msg_timestamp_unix.Substring(0, 10) If ($fulldatetime -eq $false){ (([datetime]'1/1/1970 01:00').AddSeconds($msg_timestamp_unix)).ToString("dd.MM.yyyy") } Else { (([datetime]'1/1/1970 01:00').AddSeconds($msg_timestamp_unix)).ToString("dd.MM.yyyy, HH:mm:ss") } } # Funktion zum Auslesen des Kontaktnamens Function GetContactName ($ask_chat_id, $group_not_user, $memyself_word){ If ($group_not_user){ # Test auf Gruppe For ([long]$i=0; $i -lt $csv_content_groups.Count; $i++){ If ($csv_content_groups[$i].id -eq $ask_chat_id){ # Gebe Gruppenname zurück Return $csv_content_groups[$i].groupname } } } Else { # Einzelchat oder Erwähnung # Alle in einer Gruppe If ($ask_chat_id -eq "@@@@@@@@"){Return "alle"} For ([long]$i=0; $i -lt $csv_content_contacts.Count; $i++){ If ($csv_content_contacts[$i].identity -eq $ask_chat_id){ If ($csv_content_contacts[$i].firstname -ne "" -And $csv_content_contacts[$i].lastname -ne ""){ # Gebe vollständigen Namen zurück, wenn Vor- und Nachname gesetzt sind $tmp_fullname = $csv_content_contacts[$i].firstname + " " + $csv_content_contacts[$i].lastname Return $tmp_fullname } ElseIf ($csv_content_contacts[$i].firstname -ne ""){ # Gebe nur den Vornamen zurück, wenn Nachname nicht gesetzt ist Return $csv_content_contacts[$i].firstname } ElseIf ($csv_content_contacts[$i].lastname -ne ""){ # Gebe nur den Nachnamen zurück, wenn Vorname nicht gesetzt ist Return $csv_content_contacts[$i].lastname } ElseIf ($csv_content_contacts[$i].nick_name -ne ""){ # Gebe den Nicknamen zurück, wenn Vor- und Nachname nicht gesetzt sind Return $csv_content_contacts[$i].nick_name } Else { # Gebe die ID zurück, wenn keinerlei Name gesetzt ist Return $ask_chat_id } } } # Kein Treffer? Gebe die übergebene Variable zurück (für eigene Zitate, ...) Return $memyself_word } } # Funktion zum Verarbeiten der Nachricht in die HTML-Datei Function WriteMessage ($msg_content){ # allgemeine, temporäre Parameter in dieser Funktion $tmp_quotecontact_id = $null $tmp_quotecontact_name = $null $tmp_content = $null $tmp_content_from_user = $null $tmp_msg_content = $null $tmp_array = @() $msg_content.body = $msg_content.body.Replace("<", "<") # Ersetze < Zeichen, um den HTML-Code nicht zu zerstören If ($isGroup){ # Test auf Gruppe $tmp_group_user_id = $msg_content.identity # Hole die ID des Senders $tmp_group_user_name = GetContactName $tmp_group_user_id $false "Ich" # Setze den Namen zur Sender-ID $tmp_filename = "group_message_media_"+$msg_content.uid # Setze mögliche Medien-ID $tmp_filename_thumbnail = "group_message_thumbnail_"+$msg_content.uid # Setze mögliche Medien-ID zum Vorschaubild } Else { $tmp_filename = "message_media_"+$msg_content.uid # Setze mögliche Medien-ID für Einzelchat (auch Kanal?) $tmp_filename_thumbnail = "message_thumbnail_"+$msg_content.uid # Setze mögliche Medien-ID für Einzelchat (auch Kanal?) zum Vorschaubild } # Wenn Nachrichtenempfang in einer Gruppe: setze Name und ID vorweg If ($msg_content.isoutbox -eq 0 -And $msg_content.identity -ne "" -And $isGroup){ $tmp_content_from_user = ""+$tmp_group_user_name+" ("+$tmp_group_user_id+"):
" } # Verarbeitung je nach Nachrichtentyp Switch ($msg_content.type){ "TEXT" { # Ersetze Erwähnungen: @[ABCD1234] While ($msg_content.body | Select-String -CaseSensitive "@\[........\]"){ $tmp_at_index = $msg_content.body.IndexOf("@[") $tmp_at_full = $msg_content.body.Substring($tmp_at_index, 11) $tmp_at_user_id = $msg_content.body.Substring($tmp_at_index + 2, 8) $tmp_at_user_name = GetContactName $tmp_at_user_id $false "Du" If ($tmp_at_user_id -eq "@@@@@@@@"){ $msg_content.body = $msg_content.body.Replace($tmp_at_full, "@" + $tmp_at_user_name + "") } Else { $msg_content.body = $msg_content.body.Replace($tmp_at_full, "@" + $tmp_at_user_name + " (" + $tmp_at_user_id + ")") } } # Teste auf Zitat If ($msg_content.body -like "> ????????: *"){ $tmp_quotecontact_id = $msg_content.body.Substring(2, 8) $tmp_quotecontact_name = GetContactName $tmp_quotecontact_id $false "mir" $tmp_content += "`t
`r`n`t`t

" $msg_content_split = $msg_content.body.Split("`n") $msg_content_split[0] = $msg_content_split[0].Replace("> "+$tmp_quotecontact_id+": ", "Zitat von "+$tmp_quotecontact_name+" ("+$tmp_quotecontact_id+"):
") $tmp_content += $msg_content_split[0] $tmp_quote_closed = $false For ([long]$i=1; $i -lt $msg_content_split.Count; $i++){ If ($msg_content_split[$i].StartsWith("> ") -eq $true){ $tmp_content += "
"+$msg_content_split[$i].Replace("> ", "") } ElseIf ($tmp_quote_closed -And $i -lt $msg_content_split.Count){ If ($i -lt $msg_content_split.Count){ $tmp_content += $msg_content_split[$i]+"
" } Else { $tmp_content += $msg_content_split[$i] } } Else { $tmp_content += "

`r`n`t
`r`n" $tmp_content += "`t

"+$tmp_content_from_user $tmp_quote_closed = $true } } $tmp_content += "

" } Else { If ($isGroup -And $msg_content.isoutbox -eq 0){ $tmp_content += "`t

"+$tmp_content_from_user+$msg_content.body.Replace("`n", "
")+"

" } Else { $tmp_content += "`t

"+$msg_content.body.Replace("`n", "
")+"

" } } break} "IMAGE" { If ($msg_content.caption -like "?*"){ $tmp_msg_content = "
"+$msg_content.caption.Replace("`n", "
") } If (Test-Path -Path $tmp_filename){ # Teste ob Datei vorhanden $tmp_content = "`t

"+$tmp_content_from_user+"
"+$tmp_msg_content+"

" Move-Item $tmp_filename $chat_id_folder/$tmp_filename Remove-Item $tmp_filename_thumbnail 2>$null } ElseIf (Test-Path -Path $tmp_filename_thumbnail){ # Teste ob Thumbnail vorhanden $tmp_content = "`t

"+$tmp_content_from_user+"
"+$tmp_msg_content+"

" Move-Item $tmp_filename_thumbnail $chat_id_folder/$tmp_filename_thumbnail } Else { $tmp_content = "`t

"+$tmp_content_from_user+"Bild nicht gefunden.
"+$tmp_msg_content+"

" } break} "AUDIO" { If (Test-Path -Path $tmp_filename){ # Teste ob Datei vorhanden $tmp_content = "`t

"+$tmp_content_from_user+"

" Move-Item $tmp_filename $chat_id_folder/$tmp_filename } Else { $tmp_content = "`t

"+$tmp_content_from_user+"Audio nicht gefunden.

" } break} "VIDEO" { If ($msg_content.caption -like "?*"){ $tmp_msg_content = "
"+$msg_content.caption.Replace("`n", "
") } If (Test-Path -Path $tmp_filename){ # Teste ob Datei vorhanden $tmp_content = "`t

"+$tmp_content_from_user+"

" Move-Item $tmp_filename $chat_id_folder/$tmp_filename Remove-Item $tmp_filename_thumbnail 2>$null } ElseIf (Test-Path -Path $tmp_filename_thumbnail){ # Teste ob Thumbnail vorhanden $tmp_content = "`t

"+$tmp_content_from_user+"Video nicht gefunden. Gespeichertes Vorschaubild:

"+$tmp_msg_content+"

" Move-Item $tmp_filename_thumbnail $chat_id_folder/$tmp_filename_thumbnail } Else { $tmp_content = "`t

"+$tmp_content_from_user+"Video nicht gefunden.
"+$tmp_msg_content+"

" } break} "FILE" { $fileinfo = $msg_content.body.Replace("[","").Replace("]","").Split(",") $filemime = $fileinfo[2] Switch -Wildcard ($filemime){ """audio/*""" { $tmp_new_msg_content = $msg_content $tmp_new_msg_content.type = "AUDIO" WriteMessage $tmp_new_msg_content break } """image/*""" { $tmp_new_msg_content = $msg_content $tmp_new_msg_content.type = "IMAGE" WriteMessage $tmp_new_msg_content break } """video/*""" { $tmp_new_msg_content = $msg_content $tmp_new_msg_content.type = "VIDEO" WriteMessage $tmp_new_msg_content break } default { If ($msg_content.caption -like "?*"){ $tmp_msg_content = "
"+$msg_content.caption.Replace("`n", "
") } $tmp_array = $msg_content.body.Replace("[", "").Replace("]", "").Replace("""", "").Split(",") If (Test-Path -Path $tmp_filename){ # Teste ob Datei vorhanden $tmp_content = "`t

"+$tmp_content_from_user+"Datei: "+$tmp_array[4]+"
"+$tmp_msg_content+"

" Move-Item $tmp_filename $chat_id_folder/$tmp_filename Remove-Item $tmp_filename_thumbnail 2>$null } ElseIf (Test-Path -Path $tmp_filename_thumbnail){ # Teste ob Thumbnail vorhanden $tmp_content = "`t

"+$tmp_content_from_user+"Bild/Video nicht gefunden. Gespeichertes Vorschaubild:

"+$tmp_msg_content+"

" Move-Item $tmp_filename_thumbnail $chat_id_folder/$tmp_filename_thumbnail } Else { $tmp_content = "`t

"+$tmp_content_from_user+"Datei nicht gefunden.
"+$tmp_array[4]+"
"+$tmp_msg_content+"

" } break} } break} "BALLOT" { $newballot = $msg_content.body.Replace("[","").Replace("]","").Split(",") For ([long]$i=0; $i -lt $csv_content_ballot.Count; $i++){ If ($csv_content_ballot[$i].id -eq $newballot[1]){ # neue Umfrage If ($newballot[0] -eq "1"){ $tmp_content += "`t

Umfrage """+$csv_content_ballot[$i].name+""" begonnen:

`n" For ([long]$j=0; $j -lt $csv_content_bchoice.Count; $j++){ If ($csv_content_bchoice[$j].ballot -eq $csv_content_ballot[$i].aid+"-"+$csv_content_ballot[$i].creator){ $tmp_content += "`t

"+$csv_content_bchoice[$j].name+"

" } } # Umfrage geschlossen } ElseIf ($newballot[0] -eq "3"){ $tmp_content += "`t

Umfrage """+$csv_content_ballot[$i].name+""" geschlossen:

`n" $ballotchoices = @() For ([long]$j=0; $j -lt $csv_content_bchoice.Count; $j++){ If ($csv_content_bchoice[$j].ballot -eq $csv_content_ballot[$i].aid+"-"+$csv_content_ballot[$i].creator){ $ballotchoices += $csv_content_bchoice[$j].aid, $csv_content_bchoice[$j].name, "" } } For ([long]$k=0; $k -lt $csv_content_bvote.Count; $k++){ If ($csv_content_bvote[$k].ballot_uid -eq $csv_content_ballot[$i].aid+"-"+$csv_content_ballot[$i].creator){ If ($csv_content_bvote[$k].choice -eq 1){ For ($l=0; $l -lt $ballotchoices.Count; $l+=3){ If ($ballotchoices[$l] -eq $csv_content_bvote[$k].choice_uid){ $tmp_username = GetContactName $csv_content_bvote[$k].identity $false "Ich" $ballotchoices[$l+2] += ", "+$tmp_username } } } } } For ($n=0; $n -lt $ballotchoices.Count; $n+=3){ If ($ballotchoices[$n+2].Length -gt 2){ $ballotchoices[$n+2] = $ballotchoices[$n+2].Substring(2) } } For ($m=0; $m -lt $ballotchoices.Count; $m+=3){ $tmp_content += "`t

"+$ballotchoices[$m+1]+": "+$ballotchoices[$m+2]+"

" } } $msg_timestamp_readable = ConvertUnixTime $csv_content_ballot[$i].created_at $true } } break} "LOCATION" { $tmp_array = $msg_content.body.Replace("[", "").Replace("]", "").Split(",") $tmp_content = "`t

"+$tmp_content_from_user+"Standort:
"+$msg_content.caption.Replace("`n", "
").Replace("*", "")+"

" break} } $tmp_content } # Lege neuen Ordner für Medien an New-Item -ItemType Directory $chat_id_folder >$null 2>$null $chat_partner_name = GetContactName $chat_id $isGroup 0 # Kurze Rückmeldung, um welchen Chat es sich handelt If ($isGroup){ Write-Host "Konvertiere den Gruppenchat ""$chat_partner_name""..." } Else { Write-Host "Konvertiere den Chat mit $chat_partner_name ($chat_id)..." } # HTML Anfang $content = "" $content += "" # Setze den Seitentitel If ($isGroup -eq $true){ $tmp_filename = "group_avatar_"+(Get-ChildItem $chat_file).BaseName.Split("_")[2] Move-Item $tmp_filename $chat_id_folder/$tmp_filename 2>$null $content += "`tThreema Gruppenchat: "+$chat_partner_name+"" } Else { $tmp_filename = "contact_profile_pic_"+(Get-ChildItem $chat_file).BaseName.Split("_")[1] If (Test-Path -Path $tmp_filename){ $content += "`tThreema Chat: "+$chat_partner_name+" ("+$chat_id+")" } ElseIf ($chat_id_identity.StartsWith("_")){ $tmp_filename = "contact_avatar_"+$chat_id_identity $content += "`tThreema Kanal: "+$chat_partner_name+" ("+$chat_id+")" } Else { $tmp_filename = "contact_avatar_"+$chat_id_identity $content += "`tThreema Chat: "+$chat_partner_name+" ("+$chat_id+")" } Move-Item $tmp_filename $chat_id_folder/$tmp_filename 2>$null } # Setze das Chatfoto $content += "`t" # Schreibe das Layout $content += "" $content += "" $content += "" # Verarbeite jede einzelne Nachricht aus der Backup CSV Datei For ([long]$i=0; $i -lt $csv_content_chat.Count; $i++){ # Setze Statusicon If ($isGroup -eq $false){ Switch ($csv_content_chat[$i].messagestae){ "SENT" {$msg_status = "✉"; break} "DELIVERED" {$msg_status = "📩"; break} "READ" {$msg_status = "👁"; break} "CONSUMED" {$msg_status = "👂"; break} "USERACK" {$msg_status = "👍"; break} "USERDEC" {$msg_status = "👎"; break} "FAILED" {$msg_status = "❌"; break} } } # Prüfe Datum und füge Tagesbanner ein $curDate = ConvertUnixTime $csv_content_chat[$i].posted_at $false If ($curDate -ne $oldDate){ If ($i -ne 0){ $content += "" } $content += "

"+$curDate+"

" $oldDate = $curDate } # Teste ob Nachricht gesendet oder empfangen If ($csv_content_chat[$i].isoutbox -eq 0){ If ($csv_content_chat[$i].identity -eq ""){ $content += "
" $content += WriteMessage $csv_content_chat[$i] } Else { $content += "
" $content += WriteMessage $csv_content_chat[$i] $msg_timestamp_readable = ConvertUnixTime $csv_content_chat[$i].posted_at $true If ($msg_status -ne ""){$msg_status = " "+$msg_status} $content += "`t

"+$msg_timestamp_readable+$msg_status+"

" } } Else { $content += "
" $content += WriteMessage $csv_content_chat[$i] If ($csv_content_chat[$i].modified_at -eq ""){ $senttime = $csv_content_chat[$i].posted_at } Else { $senttime = $csv_content_chat[$i].modified_at } $msg_timestamp_readable = ConvertUnixTime $senttime $true If ($isGroup -eq $true){ $content += "`t

"+$msg_timestamp_readable+"

" } Else { $content += "`t

"+$msg_status+" "+$msg_timestamp_readable+"

" } } $msg_status = $null $content += "
" } # HTML Ende $content += "
" $content += "" $content += "" # Verschiebe CSV Datei in Medienordner Move-Item $chat_file $chat_id_folder/ # Entferne weitestgehend alle nicht-alphanumerische Zeichen aus dem Dateinamen für die HTML $chat_partner_name = $chat_partner_name -Replace "[^a-zA-Z0-9äöüß.-_ ]" -Replace "[\\/]" # Aktuelles Datum und Uhrzeit für Dateinamen [string]$nowDate = Get-Date -Format "yyyy-MM-dd.HHmm" # Schreibe die HTML Datei / Gruppe oder nicht If ($isGroup){ $out_filename = ".\Chatgruppe $chat_partner_name $nowDate.html" } Else { $out_filename = ".\Chat mit $chat_partner_name ($chat_id_identity) $nowDate.html" } $content | Out-File -FilePath $out_filename -Encoding UTF8 ### # Change log # # 2022-01-21 # - angehört-Status (CONSUMED) bei Sprachnachrichten # - Dateiendungen: Änderung von 2020-05-19 wieder entfernt (brachte Fehler ab Ende 2020) # - Skript ein wenig aufgeräumt durch weggefallene Funktion # # 2020-05-19 # - Ergänze Dateiendung von Medien bei bekannten Dateitypen # # 2020-05-06 # - Entferne auch / und \ aus dem Namen des Kontakts/der Gruppe # - Datum und Uhrzeit ohne eckige Klammern, um neuen Fehler zu vermeiden # # 2020-05-05 # - Kleine Anpassung für PowerShell 2.0 Versionen # - Datum und Uhrzeit der Konvertierung in Dateinamen # -> Einfacher "Überschreibunsschutz" :) # # 2020-04-20 # - Verschiebe die Chat-CSV-Datei nach Konvertierung in den Medienordner # - Test auf leere Chat-CSV-Datei # # 2020-04-01 # - Erste Implementation von Audio/Bild/Video, die "Als Datei" oder per interner Kamera-App (FILE) geschickt wurden # # 2020-03-31 # - Medienordner mit vorangestelltem "gc_" oder "id_" # # 2020-03-30 # - Chat mit nur einer Nachricht wird nun auch konvertiert (Array-Typ für Variable gesetzt) # # 2020-03-27 # - Neuer HTML-Dateiname # - Verwende (wenn vorhanden) Vorschaubild (Thumbnail), wenn Original nicht mehr vorhanden # - Lösche das Vorschaubild, wenn Original zusätzlich vorhanden # - Verwende ID als Name, wenn der Kontakt keinen einzigen Namen gesetzt hat # - Entferne fast alle nicht-alphanumerische Zeichen aus dem Dateinamen der HTML # - Einzelchat als Chat (kein Kanal) bezeichnen, selbst wenn kein Avatar gefunden wurde # # 2020-03-26 # - Ein Change log! # - created_at -> posted_at, außer für Umfragen # - ConvertUnixTime: Um 1 Stunde verschoben - PowerShell rechnet die UTC-Sekunden wohl anders # - Entferne " ():" im Einzelchat nach einem Zitat # - Ersetze das < Zeichen mit HTML Code / kein Ersetzen von > wegen der Zitatprüfung # - Kleinere Anpassungen zum Unterschied Gruppen-/Einzelchat/Kanal # - AUDIO Typ implementiert # - Alter auskommentierter Code entfernt # - Einige (neue) Kommentare ### # TODO/Bugs/Notizen # - ... ###