mirror of
https://github.com/foo-dogsquared/dotfiles.git
synced 2025-01-31 04:57:57 +00:00
Revise album-related scripts
This commit is contained in:
parent
37036a1e2c
commit
f3c4e2082d
18
bin/convert-opml-to-newsboat-urls
Executable file
18
bin/convert-opml-to-newsboat-urls
Executable 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 " "))
|
@ -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']}"
|
||||||
}
|
}
|
||||||
|
@ -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}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user