1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

nushell でフォルダ内にある複数の動画の総再生時間を取得する

Posted at

動機

あるフォルダの中に複数の動画ファイルがあり、その再生時間の合計を取得する必要があったので nushell を使って取得してみました。

環境

Windows 11 24H2
nushell 0.108.0
ffmpeg version 8.0-full_build-www.gyan.dev

解説

nushell とは

JSON や CSV のような構造化されたデータをパイプラインで扱えるのが特徴のシェルです。従来のシェルならあるコマンドの出力を正規表現でパースして…なんてことをやると思いますが、nushell は様々なデータ形式に対応しているのでデータの扱いが簡単になります。

ffprobe とは

ffmpeg に付属のツールで、動画ファイルなどの情報を収集し読み取りやすいデータにして出力してくれます。JSON にも対応しているので、その出力を nushell に渡します。

下記のコマンドを実行すると JSON 形式で動画の情報が出力されます。

> ffprobe -v quiet -show_format -show_streams -print_format json /path/to/movie.mp4
{
    "streams": [
        {
            "index": 0,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "High",
            "codec_type": "video",
            "codec_tag_string": "avc1",
            "codec_tag": "0x31637661",
            "width": 1920,
            "height": 1080,
            // 省略
        },
        {
            "index": 1,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            // 省略
        }
    ],
    "format": {
        "filename": "movie.mp4",
        // 省略
        "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
        "format_long_name": "QuickTime / MOV",
        "start_time": "0.000000",
        "duration": "101.358345",
        "size": "217176161",
        "bit_rate": "17141255",
        // 省略
}

nushell で JSON をパースする

nushell のfrom jsonというコマンドにパイプラインで JSON の文字列を渡すだけです。nushell では構造化されたデータは下記のようにテーブルで表示されます。

> ffprobe -v quiet -show_format -show_streams -print_format json /path/to/movie.mp4 | from json
╭─────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│         │ ╭───┬────────────┬───────────────────────────────────────────┬─────────┬────────────┬──────────────────┬──────────┬─────╮ │
│ streams │ │ # │ codec_name │              codec_long_name              │ profile │ codec_type │ codec_tag_string │ codec_ta │ ... │ │
│         │ │   │            │                                           │         │            │                  │ g        │     │ │
│         │ ├───┼────────────┼───────────────────────────────────────────┼─────────┼────────────┼──────────────────┼──────────┼─────┤ │
│         │ │ 0 │ h264       │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 │ High    │ video      │ avc1             │ 0x316376 │ ... │ │
│         │ │   │            │                                           │         │            │                  │ 61       │     │ │
│         │ │ 1 │ aac        │ AAC (Advanced Audio Coding)               │ LC      │ audio      │ mp4a             │ 0x613470 │ ... │ │
│         │ │   │            │                                           │         │            │                  │ 6d       │     │ │
│         │ ╰───┴────────────┴───────────────────────────────────────────┴─────────┴────────────┴──────────────────┴──────────┴─────╯ │
│         │ ╭──────────────────┬───────────────────────────────────────────────────────────────────────────╮                          │
│ format  │ │ filename         │ movie.mp4                                                                 │                          │
│         │ │ format_name      │ mov,mp4,m4a,3gp,3g2,mj2                                                   │                          │
│         │ │ format_long_name │ QuickTime / MOV                                                           │                          │
│         │ │ start_time       │ 0.000000                                                                  │                          │
│         │ │ duration         │ 101.358345                                                                │                          │
│         │ │ size             │ 217176161                                                                 │                          │
│         │ │ bit_rate         │ 17141255                                                                  │                          │
│         │ ╰──────────────────┴───────────────────────────────────────────────────────────────────────────╯                          │
╰─────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

ビデオストリーム(streams の #0)の詳細を確認したいのであれば、パイプラインでget streams.0をつなげます。

❯ ffprobe -v quiet -show_format -show_streams -print_format json /path/to/movie.mp4 | from json | get streams.0
╭─────────────────────┬────────────────────────────────────────────────────────────────────────────────────╮
│ index               │ 0                                                                                  │
│ codec_name          │ h264                                                                               │
│ codec_long_name     │ H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10                                          │
│ profile             │ High                                                                               │
│ codec_type          │ video                                                                              │
│ codec_tag_string    │ avc1                                                                               │
│ codec_tag           │ 0x31637661                                                                         │
│ width               │ 1920                                                                               │
│ height              │ 1080                                                                               │
│ coded_width         │ 1920                                                                               │
│ coded_height        │ 1080                                                                               │
│ has_b_frames        │ 1                                                                                  │
│ pix_fmt             │ yuv420p                                                                            │
# 以下諸略

nushell で関数定義

動画の情報を取得するのにffprobe | from jsonの一連のコマンドを毎回書くのは面倒なので、nushell の関数として定義しておきます。関数定義は Windows 環境であれば~\Appdata\Roaming\nushell\config.nuに書きます。config nuコマンドでも上記ファイルを開けますが、その前にデフォルトのエディタを指定する必要があります。下記を nushell 上で実行するか、config.nuファイルに書き込んでおいてください。

$env.config.buffer_editor = "hx"
# vim, notepad などお好きなエディタを指定

関数定義はdef 関数名 [引数名1: 型, 引数名2: 型, ...] { /* 処理 */ }という風に書きます。今回の例では下記のようになります。

config.nu
def video [arg: string] {
  ffprobe -v quiet -show_format -show_streams -print_format json $arg | from json
}

nushell を再起動して下記コマンドを実行できるか確認しましょう。

> video /path/to/movie.mp4

特定のファイルの再生時間を取得するなら下記のようになります。

> video /path/to/movie.mp4 | get format.duration
101.358345

XX min XX sec XX ms のようにヒューマンリーダブルな表示にしたいですか?その場合は下記のようになります。

> video /path/to/movie.mp4 | get format.duration | into duration --unit sec
1min 41sec 358ms 345µs

再生時間を取得する関数もconfig.nuで定義しておきます。

config.nu
def video-duration [arg: string] {
  video $arg | get format.duration | into duration --unit sec
}

これでvideo-duration関数を実行すれば特定の動画の再生時間が取得できます。

> video-duration /path/to/movie.mp4
1min 41sec 358ms 345µs

フォルダ内のファイルの列挙

nushell にもlsコマンドがありますが、POSIX 互換ではなく構造化されたテーブルとして表示されます。

> ls
╭───┬────────────┬──────┬──────────┬─────────────╮
│ # │    name    │ type │   size   │  modified   │
├───┼────────────┼──────┼──────────┼─────────────┤
│ 0 │ movie1.mp4 │ file │   3.0 GB │ 6 years ago │
│ 1 │ movie2.mp4 │ file │   4.2 GB │ 6 years ago │
│ 2 │ movie3.mp4 │ file │   4.2 GB │ 6 years ago │
│ 3 │ movie4.mp4 │ file │ 615.1 MB │ 6 years ago │
│ 4 │ movie5.mp4 │ file │  14.5 MB │ 6 years ago │
│ 5 │ movie6.mp4 │ file │ 690.0 MB │ 6 years ago │
╰───┴────────────┴──────┴──────────┴─────────────╯

ファイル名だけを取得したいならget nameをパイプラインでつなぎます。

> ls | get name
╭───┬────────────╮
│ 0 │ movie1.mp4 │
│ 1 │ movie2.mp4 │
│ 2 │ movie3.mp4 │
│ 3 │ movie4.mp4 │
│ 4 │ movie5.mp4 │
│ 5 │ movie6.mp4 │
╰───┴────────────╯

再生時間の合計を計算する

各動画ファイルの再生時間を取得してみましょう。eachコマンドを使います。

> ls | get name | each {|n| video-duration $n}
╭───┬─────────────────────────╮
│ 0 │       34min 12sec 608ms │
│ 1 │ 47min 39sec 373ms 178µs │
│ 2 │ 47min 40sec 690ms 678µs │
│ 3 │        6min 50sec 784ms │
│ 4 │              9sec 568ms │
│ 5 │        7min 39sec 520ms │
╰───┴─────────────────────────╯

describeコマンドを使うとデータの型を表示することができます。

> ls | get name | each {|n| video-duration $n} | describe
list<duration> (stream)

list<duration>型はmath sumコマンドのインプットに渡せるようですね。

> ls | get name | each {|n| video-duration $n} | math sum
2hr 24min 12sec 543ms 856µs

これで再生時間の合計が計算できました!

まとめ

nushell は便利なのでちょっと触ってみてはいかがでしょうか :blush:

config.nu の設定例
$env.config.buffer_editor = "hx"
$env.config.show_banner = false

def video [arg: string] {
  ffprobe -v quiet -print_format json -show_format -show_streams $arg | from json
}

def video-duration [arg: string] {
  video $arg | get format.duration | into duration --unit sec
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?