並列損失とロスレス音楽コレクションを維持

並列損失とロスレス音楽コレクションを維持

私は巨大な音楽コレクションを持っています。それらのいくつかはロスレスファイルであり、いくつかは損失のあるファイルです。

元のコレクションの損失ファイルと、元のコレクションのロスレスファイルの損失のトランスコードを含むコレクションのコピーを維持したいと思います。

いくつかの仮定:

  • 私はffmpegを使ってflacをopusファイルに変換する方法を知っています。
  • 変換する必要があるflacファイルのみがあり、wavまたはalacコーデックはありません。
  • 損失ファイルはopus、vorbis、またはmp3です。

私が欲しい:

  • 最小限のストレージを使用して新しい音楽コレクションを保存します。つまり、適切な場合は元の損失ファイルに再接続されます。
  • 元のファイルに失われたファイルとロスレスファイルを追加するか、メタデータを更新するので、コレクションを最新の状態に保ちます。
  • 変更されていないロスレスファイルを再トランスコードする必要はありません。

これを行うには、いくつかのカスタムスクリプトを使用する必要があるようですが、多くの時間を費やす前に誰もが提案やヒントを持っている場合は永遠に感謝します。

答え1

私はMakefileが好きではありません(同意することもできます)これ男);ただし、makeデフォルトでは必要に応じて行われます。

.opusたとえば、すべてのソースファイル.flacに対してファイルを希望するルールを定義します。

Makefile、私の心から

TARGETDIR=/path/to/compressed/library
%.opus: %.flac
    ffmpeg -ffmpegflags -and -stuff -i "$<" -o "$@"
$(TARGETDIR)/%.opus: %.opus
    cp --reflink=always "$<" "$@"

これにより、ツリー内のすべてのFLACがOPUSに変換されます。 .opusファイルがまだ存在しない場合、またはFLACの最後の変更より古い場合にのみこれを実行します。

私はそれがツリー内で発生するので気に入らない。つまり、きれいな「オリジナルのみ」ディレクトリでは終わりません。少なくともcp参照リンクをサポートするファイルシステムを使用してコピーを浅くし、実際にスペースを必要としないようにしてください。私の考えでは、サブディレクトリも正常に処理できないようです。

それなら正直に言って make がすることは実際には次のようになります。

各ワイルドカードソースファイル(%.flac)に対して結果(同じファイル.opus)がビルドされていることを確認し、そうでない場合(またはビルドがソースファイルより古い)ビルドします。

これはやや逆になっており、Makeに頼る必要があるほど複雑ではありません。だから、シェルスクリプト。 zshを使用しています。私が書いた内容をテストしませんが、これについてコメントしました。

#!/usr/bin/zsh
# Copyright 2022 Marcus Müller
# SPDX-License-Identifier: BSD-3-Clause
# Find the license text under https://spdx.org/licenses/BSD-3-Clause.html

# set options:
setopt null_glob    # Don't fail if there's no file matching a pattern
setopt no_case_glob # Don't care about case in matching

TARGET_DIR=../compressed_library

make_containing_dir() {
  target_dir="${1:h}"
  if [[ ! -d "${target_dir}" ]] ; then
    logger -p user.debug "Creating directory ${target_dir}"
    mkdir -p "${target_dir}" || logger -p user.err "can't mkdir ${target_dir}"
}

for compressed_source in **/*.{mp3,opus,vorbis,mp4} ; do
  if [[ -d "${compressed_source}" ]]; then
    continue # skip directories that happen to have a matching suffix
  fi

  logger -p user.debug "dealing with compressed source ${compressed_source}"
  
  target_file="${TARGET_DIR}/${compressed_source}"
  make_containing_dir "${target_file}"

  # -h : check whether target exists and is symlink
  if [[ ! -h "${target_file}" ]] ; then
   ln -s "$(pwd)/${compressed_source}" "${target_file}" \
     || logger -p user.err "copying ${compressed_source} failed"
  fi

done

for uncompressed_source in **/*.flac ; do
  if [[ -d "${uncompressed_source}" ]]; then
    continue # skip directories that happen to have a matching suffix
  fi

  logger -p user.debug "dealing with uncompressed source ${compressed_source}"

  target_file="${TARGET_DIR}/${uncompressed_source%%.flac}.opus"
  #                                               ^ strip the .flac suffix
  make_containing_dir "${target_file}"

  #         /-- compare source file for "older than"
  #         |   target file; this returns !=0 if the source file
  #         |   is newer, or the target file nonexisting
  #         \--------------------\
  #                              |
  if [[ "${uncompressed_source}" -ot "${target_file}" ]]; then
    ffmpeg -loglevel=fatal \
           -i "${uncompressed_source}" \
           -b:a 96k \
           "${target_file}" \ 
      || logger -p user.err "transcoding ${uncompressed_source} failed"
  fi

done

これは非常にテストされていませんが、少なくともシステムログに記録されます(journalctl -xefあなたの友達です)。

関連情報