I write this to convert my old, multiple GiB, multimedia files to formats that are smaller in size and royalty free.

remove_extension() {
  sed -E 's/^(.+)\.[^.]+$/\1/'
}

get_extension() {
  sed -E '/^\.?[^.]+$/d; s/^.+\.([^.]*)$/\1/'
}

ffmpeg_av1_opus() {
  if [ "$#" -lt 4 ]; then
    return
  fi
  ffmpeg -n -i "$4" -c:v libsvtav1 -preset "$1" -crf "$2" -c:a libopus -vbr:a 1 -b:a "$3" "${5:-"$(echo "$4" | remove_extension)_ffmpeg_av1_$1_$2_opus_$3.mkv"}"
}

ffmpeg_av1_lossless_flac() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  ffmpeg -n -i "$1" -c:v libsvtav1 -svtav1-params lossless=1 -preset -2 -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_av1_lossless_flac.mkv"}"
}

ffmpeg_opus() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -n -i "$2" -c:a libopus -vbr:a 1 -b:a "$1" "${3:-"$(echo "$2" | remove_extension)_ffmpeg_opus_$1.opus"}"
}

ffmpeg_flac() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  ffmpeg -n -i "$1" -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_flac.flac"}"
}

ffmpeg_segment() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -n -i "$2" -c copy -map 0 -segment_time "$1" -f segment -reset_timestamps 1 "${3:-"$(echo "$2" | remove_extension)_ffmpeg_%04d.$(echo "$2" | get_extension)"}"
}

ffmpeg_concat_auto() {
  local files=()
  if [ "$#" -eq 0 ]; then
    for f in *; do
      test -f "$f" && files+=("$f")
    done
  else
    files=("$@")
  fi
  ffmpeg -n -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${files[@]}") -c copy "$(echo "${files[0]}" | remove_extension | sed -E 's/_ffmpeg_[0-9]+$//').$(echo "${files[0]}" | get_extension)"
}

ffmpeg_concat() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -n -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${@:2}") -c copy "$1"
}

echo_non_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*) ;;
      *)
        echo "$f"
        ;;
    esac
  done < <(find . -type f -print0)
}

remove_non_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*) ;;
      *)
        rm -f -- "$f"
        ;;
    esac
  done < <(find . -type f -print0)
}

echo_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*)
        echo "$f"
        ;;
      *) ;;
    esac
  done < <(find . -type f -print0)
}

remove_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*)
        rm -f -- "$f"
        ;;
      *) ;;
    esac
  done < <(find . -type f -print0)
}

jxl_lossy() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  cjxl -j 0 -e 10 -d "$1" "$2" "${3:-"$(echo "$2" | remove_extension).jxl"}"
}

jxl_lossless() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  cjxl -j 1 -e 10 -d 0 "$1" "${2:-"$(echo "$1" | remove_extension).jxl"}"
}

multimedia_convert() {
  (
    shopt -s globstar nullglob
    for f in **/*; do
      [[ -f $f ]] || continue
      local file=${f##*/}
      local dir=${f%/*}
      [[ $dir == "$f" ]] && dir=.
      case ${file,,} in
        *.gif)
          if [[ ${file##*.} != gif ]]; then
            if [[ -e "${f%.*}.gif" ]]; then
              printf 'Skipping: output exists: %s\n' "$f" >&2
              continue
            fi
            mv -- "$f" "${f%.*}.gif"
          fi
          ;;
        *.flac)
          if [[ ${file##*.} != flac ]]; then
            if [[ -e "${f%.*}.flac" ]]; then
              printf 'Skipping: output exists: %s\n' "$f" >&2
              continue
            fi
            mv -- "$f" "${f%.*}.flac"
          fi
          ;;
        *.jpg | *.jpeg | *.png)
          local jxl="${file%.*}.jxl"
          if [[ -e "$dir/$jxl" ]]; then
            printf 'Skipping: output exists: %s\n' "$f" >&2
            continue
          fi
          (
            cd "$dir" &&
              jxl_lossy 1 "./$file" "./$jxl" &&
              rm -- "$file"
          )
          ;;
        *.avif | *.bmp | *.heic | *.ico | *.jp2 | *.tif | *.webp)
          local png="${file%.*}.png"
          if [[ -e "$dir/$png" ]]; then
            printf 'Skipping: intermediate png exists: %s\n' "$f" >&2
            continue
          fi
          local jxl="${file%.*}.jxl"
          if [[ -e "$dir/$jxl" ]]; then
            printf 'Skipping: output exists: %s\n' "$f" >&2
            continue
          fi
          (
            cd "$dir" &&
              magick "./$file" "./$png" && {
              jxl_lossy 1 "./$png" "./$jxl" &&
                rm -- "$file" ||
                true
            } &&
              rm -f -- "$png"
          )
          ;;
        *.3gp | *.mov | *.vob | *.wmv)
          (
            cd "$dir" &&
              ffmpeg_av1_opus 4 40 24k "./$file" &&
              rm -- "$file"
          )
          ;;
        *.avi | *.mkv | *.mp4)
          (
            cd "$dir" &&
              ffmpeg_av1_opus 4 32 72k "./$file" &&
              rm -- "$file"
          )
          ;;
        *.aac | *.mp3 | *.m4a | *.ogg)
          (
            cd "$dir" &&
              ffmpeg_opus 96k "./$file" &&
              rm -- "$file"
          )
          ;;
        *.wav)
          (
            cd "$dir" &&
              ffmpeg_flac "./$file" &&
              rm -- "$file"
          )
          ;;
        *)
          continue
          ;;
      esac
    done
  )
}
[–] 3 points 1 week ago (1 child)

I block system update immediately when I heard this. Though I could use Shizuku, who knows when they will block loop back ADB. And the recent CVE-2026-43499 exploits are another reason to keep me holding my kernel version. BTW, I now have 0 app are my phone that receives update from Google Play or those OEMs stores now. Some still use APKPure over Obtainium or Aurora Store, but most are FOSS.

  • source
  • [–] [S] 1 point 1 week ago (1 child)

    -vbr 0 means CBR (constant bitrate), 1 means normal VBR (variable bitrate), 2 means constrained VBR, and 1 is the default for most build I think.

    -ac is audio channel. 1 is mono, 2 is stereo, 6/8 are 5.1/7.1 surround, so I think I'll keep it unspecified since some movies or Dolby Atmos things use >2 channels.

  • source
  • parent
  • context
  • [–] [S] 1 point 1 week ago (1 child)

    Thanks for your recommendation.

    Regarding lossless encoding, I find flac much smaller than wav, another lossless format, while lossless AV1 is quite huge in size when converting from H264/H265.

    ~/a $ du -sh *
    10308   file_example_WAV_10MG.wav
    2924    file_example_WAV_10MG_ffmpeg_flac.flac
    2016    file_example_WAV_10MG_ffmpeg_opus_256k.opus
    ~/a $ declare -f ffmpeg_flac ffmpeg_opus
    ffmpeg_flac ()
    {
        if [ "$#" -eq 0 ]; then
            return;
        fi;
        ffmpeg -i "$1" -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_flac.flac"}"
    }
    ffmpeg_opus ()
    {
        if [ "$#" -lt 2 ]; then
            return;
        fi;
        ffmpeg -i "$2" -c:a libopus -vbr:a 1 -ac 2 -b:a "$1" "${3:-"$(echo "$2" | remove_extension)_ffmpeg_opus_$1.opus"}"
    }
    
  • source
  • parent
  • context
  • submitted 1 week ago* (last edited 6 days ago) by to c/ffmpeg@programming.dev
     
    remove_extension() {
      sed -E 's/^(.+)\.[^.]+$/\1/'
    }
    
    get_extension() {
      sed -E '/^\.?[^.]+$/d; s/^.+\.([^.]*)$/\1/'
    }
    
    ffmpeg_av1_opus() {
      if [ "$#" -lt 4 ]; then
        return
      fi
      ffmpeg -i "$4" -c:v libsvtav1 -preset "$1" -crf "$2" -c:a libopus -vbr:a 1 -b:a "$3" "${5:-"$(echo "$4" | remove_extension)_ffmpeg_av1_$1_$2_opus_$3.mkv"}"
    }
    
    ffmpeg_av1_lossless_flac() {
      if [ "$#" -eq 0 ]; then
        return
      fi
      ffmpeg -i "$1" -c:v libsvtav1 -svtav1-params lossless=1 -preset -2 -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_av1_lossless_flac.mkv"}"
    }
    
    ffmpeg_opus() {
      if [ "$#" -lt 2 ]; then
        return
      fi
      ffmpeg -i "$2" -c:a libopus -vbr:a 1 -b:a "$1" "${3:-"$(echo "$2" | remove_extension)_ffmpeg_opus_$1.opus"}"
    }
    
    ffmpeg_flac() {
      if [ "$#" -eq 0 ]; then
        return
      fi
      ffmpeg -i "$1" -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_flac.flac"}"
    }
    
    ffmpeg_segment() {
      if [ "$#" -lt 2 ]; then
        return
      fi
      ffmpeg -i "$2" -c copy -map 0 -segment_time "$1" -f segment -reset_timestamps 1 "${3:-"$(echo "$2" | remove_extension)_ffmpeg_%04d.$(echo "$2" | get_extension)"}"
    }
    
    ffmpeg_concat_auto() {
      local files=()
      if [ "$#" -eq 0 ]; then
        for f in *; do
          test -f "$f" && files+=("$f")
        done
      else
        files=("$@")
      fi
      ffmpeg -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${files[@]}") -c copy "$(echo "${files[0]}" | remove_extension | sed -E 's/_ffmpeg_[0-9]+$//').$(echo "${files[0]}" | get_extension)"
    }
    
    ffmpeg_concat() {
      if [ "$#" -lt 2 ]; then
        return
      fi
      ffmpeg -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${@:2}") -c copy "$1"
    }
    
    echo_non_ffmpeg() {
      while IFS= read -r -d '' f; do
        case "$f" in
          *ffmpeg_*) ;;
          *)
            echo "$f"
            ;;
        esac
      done < <(find . -type f -print0)
    }
    
    remove_non_ffmpeg() {
      while IFS= read -r -d '' f; do
        case "$f" in
          *ffmpeg_*) ;;
          *)
            rm -f "$f"
            ;;
        esac
      done < <(find . -type f -print0)
    }
    
    echo_ffmpeg() {
      while IFS= read -r -d '' f; do
        case "$f" in
          *ffmpeg_*)
            echo "$f"
            ;;
          *) ;;
        esac
      done < <(find . -type f -print0)
    }
    
    remove_ffmpeg() {
      while IFS= read -r -d '' f; do
        case "$f" in
          *ffmpeg_*)
            rm -f "$f"
            ;;
          *) ;;
        esac
      done < <(find . -type f -print0)
    }
    
    mv_space_underscore() {
      while IFS= read -r -d '' f; do
        new="${f// /_}"
        [[ -e "$new" ]] && {
          echo "skipping '$f', '$new' exists"
          continue
        }
        mv -- "$f" "$new"
      done < <(find . -depth -name '* *' -print0)
    }
    
    mv_space_hyphen() {
      while IFS= read -r -d '' f; do
        new="${f// /-}"
        [[ -e "$new" ]] && {
          echo "skipping '$f', '$new' exists"
          continue
        }
        mv -- "$f" "$new"
      done < <(find . -depth -name '* *' -print0)
    }
    

    Edit: Add -vbr:a 1 to opus, thanks to exdor.

    [–] 4 points 1 week ago

    Ι stick with KDE Plasma after trying GNOME, KDE, and Cinnamon. In GNOME, many settings are not available in GUI (I don't remember which they are now), while they are available in KDE. And back when I used Cinnamon it didn't support Wayland while some of my apps (especially Waydroid) needs Wayland. But I mostly use CLI for daily tasks for automation and easier copy-pasting forum answers, asking LLM, and sharing to GitHub, so I may not be a representative DE user.

  • source
  • [–] 2 points 1 week ago

    If containers, VMs, and dual-boot are banned in the workspace I kinda feel the fear of things not work is legit. When I'm forced to code on a Windows computer without WSL at university's Programming course in electrical engineering department. Everything I'm used to, bash, cat, cd, ls, nvim, sed, grep, ..., simply don't exist. And I end up find it easier to code in the small text box of the site they provide than any of the slow, non-Vim mode, IDEs.

  • source
  • parent
  • context
  • [–] 2 points 1 week ago

    I am a Ubuntu to user now. However, I find myself reading Arch wiki far more and a bit Debian's but barely Ubuntu's. But I agree that Ubuntu is the industry standard and it's acceptable to distribute a deb and test it on Ubuntu LTS and call it a day. Other distros can simply dig into it and make it work. Containers and sandboxes are great, but I hate the concept to only distribute things that way. Snap Flatpak LXC Incus Docker Podman etc. stuff don't work on some restricted/weird environment.

  • source
  • parent
  • context
  • [–] 1 point 2 weeks ago

    Installing Linux is just so easy while it genuinely took me a long while to (re)install Windows alongside Linux cuz the driver they provide is an exe and the install process wants some format else, and I ended up found a Github repo that provides decompressed driver files.

  • source
  • [–] 3 points 2 weeks ago

    VPN is a shifting of trust from your ISP to your VPN provider. If you already trust your ISP, you don't need a VPN (except for accessing content that can only be accessed from another country). BTW, I think that Mullvad, Windscribe, and AirVPN are probably some good options if for privacy and security.

  • source
  • view more: next ›