1.21 jigowatts

Great Scott!

VoiceText Web APIで遊んでみた

概要

PowerShellでVoiceText Web APIを使って遊んでみようと思い立ち、Visual Studio Code(以下VSCode)でスクリプトを書いてみました(・∀・)

f:id:sh_yoshida:20180414131937p:plain

環境

Windows10
PowerShell 5.1

VoiceText Web API

モヤさまのナレータでおなじみですね。
cloud.voicetext.jp

規約読んで利用登録してAPIキーを取得しましょう。
VSCodeを立ち上げスクリプトを書いて実行したら、わけわからんことしゃべってる?なんで?って颯爽と詰まる。

理由は日本語をしゃべらせようとして、ファイルのエンコードUTF-8のためスクリプトに書いた文字列が文字化けしたからですね。

f:id:sh_yoshida:20180414132046p:plain

PowerShell ISEで書いたスクリプトVSCodeで開いたらUTF-8 with BOMとなっていたので、スクリプトの中で日本語を書くときはUTF-8 with BOMにしておけば良さそう。あとShift JISでも大丈夫でした。

モジュール化してみた

エンコードUTF-8でもコマンドレットの引数で渡すんであれば行けたのでモジュール化してみました。
環境変数VoiceTextAPI_KEYという名前でAPIキーを登録しておきます。

■voiceTextModule.psm1

. $PSScriptRoot\voiceConverter.ps1

function ConvertTo-Voice {
    param(
        [Parameter(Mandatory)]
        [ValidateSet('show', 'haruka', 'hikari', 'takeru', 'santa', 'bear')]
        [string] $name,
        [Parameter(Mandatory)]
        [string] $text
        )
    begin{
    }
    process {
        $Speaker = [Speaker]::new($name, $text);
        $Speaker.Speak();
    }
    end {
    }
}

■voiceConverter.ps1
バージョン5からクラス構文も書けるようになったんすね。

Write-Host 'Loading...'

class Speaker {
    [string]$Name;
    [string]$Text;
    [string]$Uri = "https://api.voicetext.jp/v1/tts";
    
    Speaker ($name, $text) {
        $this.Name = $name;
        $this.Text = $text;
    }

    [string] GetAuthorization() {
        $t = $env:VoiceTextAPI_KEY + ":";
        return "Basic " `
            + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($t))
    }

    [void] Speak() {
        $outFile = ".\voicetext.wav"
        if (Test-Path $outFile){
            Remove-Item $outFile;
        }
    
        Invoke-RestMethod -Uri $this.Uri `
                    -Method POST `
                    -Headers @{Authorization=$this.GetAuthorization()} `
                    -Body @{text=$this.Text; speaker=$this.Name;} `
                    -OutFile $outFile;

        $player = New-Object System.Media.SoundPlayer -ArgumentList $outFile
        $player.Play()
    }
}

あとはモジュールをインポートして実行するだけ(^q^)b

PS> Import-Module .\voiceTextModule
PS> ConvertTo-Voice -name show -text 本当にありがとうございます。

実行ポリシーについて

概要

PowerShellスクリプトを実行したらなんか実行が無効だってエラーが出たよ!それは実行ポリシーのせい。ありがたいけど、ちょっと面倒な実行ポリシーについてです。

> .\hoge.ps1
.\hoge.ps1 : このシステムではスクリプトの実行が無効になっているため、ファイル C:\src\hoge.ps1
 を読み込むことができません。詳細については、「about_Execution_Policies」(https://go.microsoft.com/fwlink/?LinkID=135170) を参照してください。
発生場所 行:1 文字:1
+ .\hoge.ps1
+ ~~~~~~~~~~
    + CategoryInfo          : セキュリティ エラー: (: ) []、PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

実行ポリシーについて

スクリプトを実行する際の条件設定が以下の6種類存在する。デフォルトではRestrictedとなっているためスクリプトを実行することができない。誤操作防止的な理由ってことかな。

  • Restricted: 構成ファイルの読み込みやスクリプトの実行を行いません。既定値は "Restricted" です。
  • AllSigned: すべてのスクリプトと構成ファイルが信頼された発行元によって署名されていることを要求します (ユーザーがローカル コンピューターに書き込むスクリプトを含む)。
  • RemoteSigned: インターネットからダウンロードされたすべてのスクリプトおよび構成ファイルが、信頼された発行元によって署名されていることを要求します。
  • Unrestricted: すべての構成ファイルを読み込み、すべてのスクリプトを実行します。インターネットからダウンロードされた署名されていないスクリプトを実行する場合、スクリプトを実行する前に確認を求められます。
  • Bypass: 何もブロックされず、警告もメッセージも表示されません。
  • Undefined: 現在のスコープから現在割り当てられている実行ポリシーを削除します。このパラメーターは、グループ ポリシー スコープ内で設定された実行ポリシーは削除しません。
https://technet.microsoft.com/ja-JP/library/dd347628.aspx

実行ポリシーの確認

現在の実行ポリシーを確認するには以下のコマンドレットを実行する。-Listパラメータを渡すと優先順で実行ポリシーの一覧が取得できるぞ。

> Get-ExecutionPolicy
Bypass
> Get-ExecutionPolicy -List

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process          Bypass
  CurrentUser    RemoteSigned
 LocalMachine      Restricted

実行ポリシーのスコープはProcessはメモリに、CurrentUserLocalMachineレジストリに格納される。また、グループポリシーでも設定することができる。

実行ポリシーの設定

実行ポリシーを変更したい場合は、管理者権限でPowerShellを起動しSet-ExecutionPolicyコマンドレットで変更することができる。ただ、ポリシー的に実行後に設定を戻しておいたほうがいいかも。
後でだと結構忘れちゃうんで-Scopeパラメータで特定のセッションに対してのみ変更をするほうがよさげ。これなら管理者権限でなくても変更できるし: )

> Set-ExecutionPolicy -Scope Process RemoteSigned -Force

PowerShell起動時に-ExecutionPolicyパラメータで指定してもOK。設定したポリシーは閉じるときに削除される。以下はコマンドプロンプトからスクリプトを実行する例。

CMD> PowerShell -ExecutionPolicy Bypass -file .\hello.ps1

実行ポリシーはひと手間かかるけど、間違えて.batファイルを実行して血の気が引く思いをするよりかはマシかも?

タスクスケジューラで時間のかかるタスクを待つ

tips

タスクスケジューラに登録したタスクを実行!

Start-ScheduledTask <タスク名>

そこそこ時間のかかるタスクで、終了を検知したかったので仕方なくポーリングすることに。
最初はschtasksコマンドでバッチ書いてたけどメンドクサってなったのでPowerShellです。

■task.ps1

Start-ScheduledTask simpletask

while ((Get-ScheduledTask simpletask).State -eq 'Running'){
    Write-Host 'Running...'
    Start-Sleep 1
}

Write-Host 'Complete!'