砂漠の旅人(たびと)

UNIX / MS-DOS 時代から電脳砂漠を旅しています

【C#】YouTube からビデオとオーディオをダウンロードするアプリを作ってみる - その4

こんにちは、たびとです。

コロナワクチンを接種して、39.4 度の熱を出してダウンしました。 お手軽 YouTube ダウンローダー TubeEater を月末までに完成させるために、 テストが盛り沢山なのに、これは予想外でした。

さて、今回は TubeEater の機能について、一番の売りである自動化について、 その方式について簡単に説明したいと思います。

それと、先週急に思いついた多言語対応、 テストしている中で発見したこと、 インストーラを作る中で注意すべきこと等を説明したいと思います。

この記事の対象者

  • YouTube からビデオをダウンロードすることに興味のある方
  • .NET 6 の C# でアプリケーションを作ってみたい方
  • お手軽 YouTube ダウンローダー TubeEater 開発の裏側を知りたい方

TubeEater の自動化

前回、TubeEater の最大の特徴である自動化について説明しました。 TubeEater の使い方は、起動して自動化ボタンを押すだけです。

起動時は、自動ダウンロードアイコンが表示されています。

TubeEater 起動時の自動化ボタンの状態の画面
TubeEater 起動時の自動化ボタンの状態

自動ダウンロードボタンを押すと、アイコンがチェックマークに変化します。

TubeEater の自動ダウンロード状態の画面
TubeEater の自動ダウンロード状態

これで TubeEater 側の操作は終わりです。 後は、好きなブラウザで YouTube を開き、好きなタイミングでURLをコピーするだけです。

この実現方式を解説します。

YouTube URL の自動受付

これは、タイマーを使ってクリップボードを監視することで実現しています。

具体的には、DispatcherTimer を約 0.1 秒に設定し、毎回 Clipboard.GetDataObject() を使って、 クリップボードの状態を監視しています。 URLを取得した場合、それが YouTube の URL であれば、ConcurrentQueue のダウンロード予約キューに受け付けます。

ダウンロードのタスク実行

ダウンロード予約キューから 1件取り出して、ダウンロードをタスク(Task)で実行します。 このとき、非同期で実行しないとダウンロードするまで固まるため、次の予約を受け付けできなくなります。

ダウンロードのタスク完了

ダウンロードのタスク(Task)が完了したら、ファイルとデータベースに結果を書き込みます。 このとき、プログレスバーとかの後処理も実施します。

多言語対応

先週、ブログを書く前に思いついて実装し始めた多言語対応ですが、 後から言語追加を容易に実装できるようにしたいと考えました。

実装方式

まずは、対応するメッセージをすべて Key=Value 形式にし、 Dictionay に格納するようにします。 言語クラス LangData を作成し、この Dictionay を持たせます。

これに、ComboBox で切り替えるときに利用する名前と、言語を判定するロケールと、 日付を追加します。

public class LangData
{
    public string Name { get; set; } = String.Empty;                        // 言語
    public string Locale { get; set; } = CultureInfo.CurrentCulture.Name;   // ロケール(ja-JP)
    public DateTime Update { get; set; }                                    // DB格納日時
    public Dictionary<string, string> Messages { get; set; } = new();       // メッセージ集
}

これをJSON形式のファイルから取り込めるようにします。 取り込んだ言語ファイルは、データベースに格納します。 データベースに登録した日付を格納することで、 言語ファイルに変更があった時だけ、取り込むようにします。

これを言語ファイル分、List<LangData> に格納し、ComboBox の言語切り替えと紐づけます。

多言語利用時のトラブル対応

内部には、日本語と英語の2言語を格納しておきます。 日本語環境の場合は、日本語を使い、それ以外の環境では、英語を使います。

この理由は、追加した言語ファイルのメッセージ番号が存在しなかったとき、 内部のメッセージ番号を使うからです。

また、日本語環境以外のとき、日本語は文字化けする可能性と読めない可能性があるため、 英語を使うように実装しています。

ダウンロードテスト

もう、ダウンロードした回数を記憶できないぐらいダウンロードしてみました。 とりあえず、YouTube のジャンルからランダムに URL をコピーして、ガンガン予約してみました。 ここで、エラーも多発し、修正してはダウンロードの繰り返しが続きます。

既知の問題

VideoLibrary が YouTube からダウンロードするエンジンですが、これには問題があって、 たまに日本語が正しく取得できない場合があります。 たびとが遭遇したのは、著者が韓国語になってしまう例です。 こればかりは、ライブラリ側の問題なので手の打ちようがありません。

あと、AAC の取得が MP4 の数倍遅いです。 サイズは AAC の方が小さいのに、なぜか取得に時間が掛かります。

同じタイトルかつ同じ著者

同じ著者が同じタイトルのコンテンツをアップロードしているケースがあります。 著者ファルダを作成するため、同じタイトルが複数存在しても問題ありませんが、 どちらも同じだと困った現象が発生します。

それは、既にダウンロードしてファイル化している場合、スキップする機能を実装しているため、 ダウンロード済みとみなしてスキップしてしまう現象が発生してしまいます。

これもどうすか悩みましたが、ダウンロード前に履歴を検索し、YouTube ID が一致するかを確認し、 ID が一致していればスキップ、IDが不一致であればファイル名の末尾に ID を付けて保存するように変更しました。

ライブ配信は対象外

VideoLibrary はライブ配信のURLを指定すると、例外を返します。 これをこのまま実装すると、ライブ配信を指定するたびに、エラーメッセージが表示されて、 OKボタンを押すことになるため、使い勝手が下がります。

このため、ライブ配信の例外の場合は、メッセージは表示するけど、 OKボタンは押さなくてもいいように修正しました。

インストーラについて

インストーラは、Visual Studio Installer Projects 2022 を使いました。 かなり昔にインストーラは使ったことがありましたが、最近のインストーラって、 同一プロジェクト内に追加して作るタイプになっていて驚きました。

一般権限でのインストール

インストール先を Program Files にすると、管理者権限が必要なので、 ユーザー (Users) 配下にインストールするように変更します。

インストール時には管理者権限が必要なのでこれも外します。 これは、「PostBuildEvent」を以下のように書き換えます。 MsiInfo.exe の場所は適宜確認してください。

"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\MsiInfo.exe" "$(BuiltOuputPath)" /W 10

以下のサイトを参考にしました。

qiita.com

まとめ

今回は、自動化の実現方式、多言語化、テストによる不具合の対処、インストーラの実装に関して説明しました。 やはり開発していると、色々と問題が続出するモノです。 これをどう対処するのかが、面白くもあるのですが、 まだまだ知らないことが多いと実感させられることばかりです。

最後に参考サイトを掲載しておきます。 では、皆さん、よい旅を。

次回へのリンクはこちら。

sabakunotabito.hatenablog.com

参考サイト