Revise album-related scripts

This commit is contained in:
Gabriel Arazas 2021-04-16 23:25:24 +08:00
parent 37036a1e2c
commit f3c4e2082d
3 changed files with 66 additions and 26 deletions

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python
# TODO:
# Given a OPML file, convert the OPML into a `urls` file compatible for newsboat.
# It could also accept an OPML through stdin.
import itertools
from pathlib import Path
import sys
import xml.etree.ElementTree as ET
filename = sys.argv[1]
opml = ET.parse(filename)
for outline in opml.findall("body/outline"):
categories = [category.strip("/") for category in outline.get("category", "").split(",") if category]
print('{xmlUrl} "~{text}" {category}'.format(xmlUrl = outline.get("xmlUrl"),
text = outline.get("text"),
category = " ".join([ f'"{tag}"' for tag in categories ]) if len(categories) else " "))

View File

@ -4,6 +4,13 @@
# It can only detect certain files and write the metadata with a certain program. # It can only detect certain files and write the metadata with a certain program.
# For the argument, it needs the path of the files to be moved. # For the argument, it needs the path of the files to be moved.
# Dependencies:
# * Oil shell v0.8.8
# * vorbis-tools v1.4.2
# * exiftool v12.16
# * file 5.38
# * coreutils 8.32
shopt --set strict:all shopt --set strict:all
var help_section = "A script for embedding metadata and renaming them files. var help_section = "A script for embedding metadata and renaming them files.
@ -36,7 +43,7 @@ while test $# -gt 0 {
case $1 { case $1 {
-h|--help) -h|--help)
echo $help_section echo $help_section
shift exit 0
;; ;;
-a|--author) -a|--author)
set author = $2 set author = $2
@ -94,6 +101,7 @@ proc file_parse(path, :out) {
set file['dir'] = $(dirname $path) set file['dir'] = $(dirname $path)
set file['name'] = $(basename $path | sed --regexp-extended "s|(.+)${extension_regex}|\\1|") set file['name'] = $(basename $path | sed --regexp-extended "s|(.+)${extension_regex}|\\1|")
set file['ext'] = $(basename $path | sed --regexp-extended "s|.+(${extension_regex})|\\1|") set file['ext'] = $(basename $path | sed --regexp-extended "s|.+(${extension_regex})|\\1|")
set file['mime_type'] = $(file --mime-type --brief $path)
setref out = file setref out = file
} }
@ -115,7 +123,8 @@ if (not skip) {
# We'll use exiftool as a catch-all since it supports the most out of... 15 file types I considered. # We'll use exiftool as a catch-all since it supports the most out of... 15 file types I considered.
case $(file --mime-type --brief $path) { case $(file --mime-type --brief $path) {
"audio/ogg") "audio/ogg")
vorbiscomment --write $path --tag "TITLE=${title}" --tag "ARTIST=${author}" --tag "DATE=${pub_date}" vorbiscomment --write $path --tag "TITLE=${title}" --tag "ARTIST=${author}" --tag "DATE=${pub_date}" ||
opustags $path --in-place --delete-all --add "TITLE=${title}" --add "ARTIST=${author}" --add "DATE=${pub_date}"
;; ;;
*) *)
exiftool -title="${title}" -author="${author}" -date="${pub_date}" ${path} exiftool -title="${title}" -author="${author}" -date="${pub_date}" ${path}
@ -134,5 +143,5 @@ if (json_data) {
} }
if (move) { if (move) {
mv $path "${file_info['dir']}/$(kebab-case $title).${file_info['ext']}" mv $path "${file_info['dir']}/$(kebab-case $title)${file_info['ext']}"
} }

View File

@ -6,7 +6,7 @@
# * coreutils v8.32 # * coreutils v8.32
# * file 5-32 # * file 5-32
# * ffmpeg v4.3.1 # * ffmpeg v4.3.1
# * ripgrep v12.1.1 with SIMD runtime # * ripgrep v12.1.1
shopt --set strict:all shopt --set strict:all
@ -16,7 +16,7 @@ split-album [options...] -tf \$TIMESTAMP_FILE -af \$ALBUM_FILE
Options: Options:
-h, --help Show the help section. -h, --help Show the help section.
--descriptive-help Show a helpful tutorial-esque description of the program. --tutorial Show a helpful tutorial-esque description of the program.
-af, --audio-file [file] Set the audio file to be split. -af, --audio-file [file] Set the audio file to be split.
-tf, --timestamp-file [file] Set the timestamp file to be used for splitting. -tf, --timestamp-file [file] Set the timestamp file to be used for splitting.
-t, --title [title] Set the title of the album. -t, --title [title] Set the title of the album.
@ -32,24 +32,29 @@ Environment variables:
When any of the required metadata is missing (i.e., title, date, author), it will be prompted. When any of the required metadata is missing (i.e., title, date, author), it will be prompted.
" "
const show_descriptive_help = "Split an album with a timestamp file. const show_descriptive_help = "This script splits an album with a timestamp file.
The timestamp file contains a starting timestamp (any format that ffmpeg accepts in seeking but it is recommended in HH:MM:SS) and the title of the chapter/track. You're always going to see using this script like the following:
split-album -af \$AUDIO_FILE -tf \$TIMESTAMP_FILE
The timestamp file contains a starting timestamp (in HH:MM:SS[.MS]) and the title of the chapter/track.
For more information, see https://trac.ffmpeg.org/wiki/Seeking. For more information, see https://trac.ffmpeg.org/wiki/Seeking.
Lines starting with '#' and empty lines will be ignored. Lines starting with '#' and empty lines will be ignored.
It's for the best and you don't want some future migraines. :)
The following is an example of the content of a timestamp file. The following is an example of the content of a timestamp file.
\`\`\` \`\`\`
00:00:00 Introduction 00:00:00 Introduction
00:03:54 It's the R-rated scene 00:03:54 It's the R-rated scene
00:05:43 Boring exposition at the cafe 00:25:43 Boring exposition at the cafe
00:16:54 Expedition time 00:36:54 Expedition time
00:21:51 Fighting time 00:41:51 Fighting time
00:22:22 Shower scene 00:42:22 Shower scene
\`\`\` \`\`\`
You can also create a timestamp file in JSON format. You can also create a timestamp file in JSON format.
It is the equivalent of '.chapters' from the JSON output (i.e., '--json'). It is the equivalent of the 'chapters' key from the JSON output (i.e., '--json').
The equivalent JSON of the previous example would be this: The equivalent JSON of the previous example would be this:
\`\`\` \`\`\`
@ -63,19 +68,19 @@ The equivalent JSON of the previous example would be this:
\"title\": \"It's the R-rated scene\" \"title\": \"It's the R-rated scene\"
}, },
{ {
\"timestamp\": \"00:05:43\", \"timestamp\": \"00:25:43\",
\"title\": \"Boring exposition at the cafe\" \"title\": \"Boring exposition at the cafe\"
}, },
{ {
\"timestamp\": \"00:16:54\", \"timestamp\": \"00:36:54\",
\"title\": \"Expedition time\" \"title\": \"Expedition time\"
}, },
{ {
\"timestamp\": \"00:21:51\", \"timestamp\": \"00:41:51\",
\"title\": \"Fighting time\" \"title\": \"Fighting time\"
}, },
{ {
\"timestamp\": \"00:22:22\", \"timestamp\": \"00:42:22\",
\"title\": \"Shower scene\" \"title\": \"Shower scene\"
} }
] ]
@ -85,7 +90,7 @@ There will be a folder created with the safe name of the album (in kebab-case) c
The original file will be kept, do what you want with it. The original file will be kept, do what you want with it.
" "
const EXTENSION = ${EXTENSION:-"ogg"} const EXTENSION = ${EXTENSION:-"opus"}
var audio_file = '' var audio_file = ''
var timestamp_file = '' var timestamp_file = ''
@ -103,7 +108,7 @@ while test $len(ARGV) -gt 0 {
write -- $show_help write -- $show_help
exit exit
;; ;;
--descriptive-help) --tutorial)
write -- $show_descriptive_help write -- $show_descriptive_help
exit exit
;; ;;
@ -170,16 +175,22 @@ test $pub_date || prompt "When is the album published?" :pub_date
const output_data = {} const output_data = {}
set output_data['file'] = $audio_file set output_data['file'] = $audio_file
set output_data['chapters'] = [] set output_data['chapters'] = []
set output_data['album'] = $album
set output_data['author'] = $author
set output_data['date'] = $pub_date
set output_data['extension'] = $EXTENSION
const timestamp_regex = / %start digit{2,} ':' digit{2} ':' digit{2} %end / const timestamp_regex = / %start digit{2,} ':' digit{2} ':' digit{2} <'.' digit+>? %end /
var has_error = false var has_error = false
# Also cleans up the timestamp file with comments and empty lines.
# I just want to improve the timestamp format (a little bit).
case $(file --mime-type --brief $timestamp_file) { case $(file --mime-type --brief $timestamp_file) {
"application/json") "application/json")
json read :output_data['chapters'] < $audio_file json read :chapters < $timestamp_file
set output_data['chapters'] = chapters
;; ;;
# Also cleans up the timestamp file with comments and empty lines.
# I just want to improve the timestamp format (a little bit).
"text/plain") "text/plain")
cat $timestamp_file | sed --regexp-extended --expression '/^\s*$/d' --expression '/^#/d' | while read --line { cat $timestamp_file | sed --regexp-extended --expression '/^\s*$/d' --expression '/^#/d' | while read --line {
var chapter = {} var chapter = {}
@ -200,6 +211,7 @@ case $(file --mime-type --brief $timestamp_file) {
if (strict_mode and has_error) { exit 1 } if (strict_mode and has_error) { exit 1 }
const title_slug = $(kebab-case $album) const title_slug = $(kebab-case $album)
set output_data['directory'] = title_slug
mkdir -p $title_slug mkdir -p $title_slug
const chapter_len = len(output_data['chapters']) const chapter_len = len(output_data['chapters'])
@ -208,13 +220,14 @@ for index in @(seq $[chapter_len]) {
set chapter = output_data['chapters'][Int(index) - 1] set chapter = output_data['chapters'][Int(index) - 1]
var start = chapter['timestamp'] var start = chapter['timestamp']
var end = output_data['chapters'][Int(index)]['timestamp'] if Int(index) != chapter_len else null var end = output_data['chapters'][Int(index)]['timestamp'] if Int(index) != chapter_len else null
var filename = $(printf "%s/%.2d-%s.%s" $title_slug $index $(kebab-case ${chapter['title']}) $EXTENSION) var filename = $(printf "%.2d-%s.%s" $index $(kebab-case ${chapter['title']}) $EXTENSION)
set output_data['chapters'][Int(index) - 1]['file'] = filename
warnf "[%d/%d] %s\\r" ${index} ${chapter_len} ${chapter['title']} warnf "[%d/%d] %s" ${index} ${chapter_len} ${chapter['title']}
if (Int(index) != chapter_len) { if (Int(index) != chapter_len) {
ffmpeg -loglevel quiet -nostdin -i $audio_file -ss $start -to $end $filename ffmpeg -loglevel quiet -nostdin -i $audio_file -ss $start -to $end "${title_slug}/${filename}"
} else { } else {
ffmpeg -loglevel quiet -nostdin -i $audio_file -ss $start $filename ffmpeg -loglevel quiet -nostdin -i $audio_file -ss $start "${title_slug}/${filename}"
} }
} }