병렬 손실 및 무손실 음악 컬렉션 유지

병렬 손실 및 무손실 음악 컬렉션 유지

나는 거대한 음악 컬렉션을 가지고 있습니다. 그 중 일부는 무손실 파일이고 일부는 손실이 있는 파일입니다.

원본 컬렉션의 손실 파일과 원본 컬렉션의 무손실 파일에 대한 손실 트랜스코딩이 포함된 컬렉션의 복사본을 유지하고 싶습니다.

몇 가지 가정:

  • 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당신의 친구입니다).

관련 정보