aboutsummaryrefslogtreecommitdiffstats
path: root/tagopus
blob: 165cdda9ab67731129994f02d51c5bd925f8aee2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/bin/sh

usage() {
    cat >&2 <<'EOF'
Usage: tagopus [OPTIONS] FILE...

Options:
  -a ARTIST   Set artist
  -b ALBUM    Set album
  -y DATE     Set date (year)
  -D          Infer artist/album from directory structure (artist/album/NN title.opus)
              Explicit -a/-b flags override inferred values.

Track number and title are inferred from each filename's leading numeric prefix.
EOF
    exit 1
}

artist=
album=
date=
infer_dirs=0

while getopts 'a:b:y:D' opt; do
    case $opt in
        a) artist=$OPTARG ;;
        b) album=$OPTARG ;;
        y) date=$OPTARG ;;
        D) infer_dirs=1 ;;
        *) usage ;;
    esac
done
shift $((OPTIND - 1))

[ $# -eq 0 ] && usage

# Validate fields that must come from flags and are always required
err=0
[ -z "$date" ] && { printf 'Error: date is required (-y)\n' >&2; err=1; }

# Without -D, artist/album must be supplied via flags
if [ $infer_dirs -eq 0 ]; then
    [ -z "$artist" ] && { printf 'Error: artist is required (-a or -D)\n' >&2; err=1; }
    [ -z "$album" ]  && { printf 'Error: album is required (-b or -D)\n' >&2;  err=1; }
fi

[ $err -eq 1 ] && exit 1

numtracks=$#

for f in "$@"; do
    base=$(basename "$f")
    name="${base%.opus}"

    # Extract leading numeric prefix as track number (variable width)
    tracknum=$(printf '%s' "$name" | sed -n 's/^\([0-9][0-9]*\).*/\1/p')
    if [ -z "$tracknum" ]; then
        printf 'Error: cannot parse track number from filename: %s\n' "$f" >&2
        exit 1
    fi

    # Title is everything after the numeric prefix and any whitespace
    title=$(printf '%s' "$name" | sed 's/^[0-9][0-9]*[[:space:]]*//')
    if [ -z "$title" ]; then
        printf 'Error: cannot parse title from filename: %s\n' "$f" >&2
        exit 1
    fi

    # Start with flag values; fill in from directory structure if -D and not already set
    file_artist=$artist
    file_album=$album

    if [ $infer_dirs -eq 1 ]; then
        album_dir=$(pwd)
        artist_dir=$(dirname "$album_dir")
        [ -z "$file_album" ]  && file_album=$(basename "$album_dir")
        [ -z "$file_artist" ] && file_artist=$(basename "$artist_dir")
    fi

    # Final check — -D may have been given but paths might not resolve usefully
    err=0
    [ -z "$file_artist" ] && { printf 'Error: could not determine artist for: %s\n' "$f" >&2; err=1; }
    [ -z "$file_album" ]  && { printf 'Error: could not determine album for: %s\n' "$f" >&2;  err=1; }
    [ $err -eq 1 ] && exit 1

    opustags -i "$f" \
        -s "artist=$file_artist" \
        -s "album=$file_album" \
        -s "date=$date" \
        -s "tracknumber=$tracknum" \
        -s "tracktotal=$numtracks" \
        -s "title=$title"
done