Gadający PowerShell
Dotnetowa klasa System.Speech.Synthesis.SpeechSynthesizer pozwala uzyskać dostęp do silnika syntezy mowy.
Utworzony z niej obiekt posiada między innymi metodę Speak, za pomocą której komputer może przemówić ludzkim głosem. Do czego to się może przydać? Tak naprawdę, to pojęcia nie mam. Ale hipotetycznie, jeśli ktoś chciałby usłyszeć ostatnie tytuły artykułów z jakiegoś feeda, mógłby napisać:
Add-Type -AssemblyName System.Speech
$mouth = [Speech.Synthesis.SpeechSynthesizer]::new()
Invoke-RestMethod z3s.pl/feed | % {
$mouth.Speak($_.title)
}
Synchronicznie czy asynchronicznie - oto jest pytanie
Powyższy przykład może zwłaszcza stwarzać problemy przy dłuższych tekstach, ponieważ metoda Speak działa synchronicznie, a więc nie zwraca sterowania dopóki odtwarzanie mowy się nie zakończy. Słabo. Całe szczęście, możemy użyć asynchronicznej wersji - SpeakAsync. Zaktualizowany kod mógłby wyglądać jak poniżej:
Add-Type -AssemblyName System.Speech
$mouth = [Speech.Synthesis.SpeechSynthesizer]::new()
Invoke-RestMethod z3s.pl/feed | % {
try {
$speaker = $mouth.SpeakAsync($_.title)
while(!$speaker.IsCompleted) {}
} finally {
$mouth.SpeakAsyncCancelAll()
}
}
SpeakAsync zwraca nam natychmiast sterowanie, a żeby sprawdzić czy mowa się zakończyła, czekamy w pustej pętli aż właściwość IsCompleted zwróconego obiektu zwróci prawdę. Kiedy wciśniemy ^C, zostanie wywołany wyjątek, co z kolei spowoduje natychmiastowe przejście do bloku finally {...}, w którym dokonujemy małego sprzątania. Nie jest to idealne rozwiązanie, ale na pewno lepsze od tego pierwszego. Myślę, że najlepszym rozwiązaniem byłaby obsługa eventów, ale to już troszkę komplikuje cały skrypt. Dla ambitnych, wersję z obsługą eventów zaprezentowałem na konferencji Confidence 2023: alphasec.pl/confi23.