mostly new music stuff
[distro-setup] / nav2beet
1 #!/bin/bash
2
3 f=/usr/local/lib/err;test -r $f || { echo "error: $0 no $f" >&2;exit 1;}; . $f
4
5
6 plist_only=false
7 dry_run=false
8 while (( $# )); do
9 case $1 in
10 plist)
11 plist_only=true
12 ;;
13 dry)
14 dry_run=true
15 ;;
16 esac
17 done
18
19 m ()
20 {
21 printf "%s\n" "$*" >&2
22 if $dry_run && [[ $1 == beet && $2 == modify ]]; then
23 echo "dry run: $*"
24 else
25 "$@"
26 fi
27 }
28
29 tmpf=$(mktemp)
30
31
32 if ! $plist_only; then
33 echo begin star rating import from navidrome to beets
34
35 declare -A navirating
36 tmpdir=$(mktemp -d)
37 cd $tmpdir
38 if [[ $HOSTNAME != kd ]]; then
39 ssh_prefix="ssh b8.nz"
40 ssh b8.nz '
41 install -m 700 -d /tmp/nav2beet
42 for r in 1 2 3 4 5; do
43 sqlite3 /i/navidrome/navidrome.db ".output /tmp/nav2beet/$r" "select path from annotation inner join media_file on item_id = id where rating = $r;"
44 done
45 tar cz -C /tmp nav2beet
46 ' | tar xz
47 cd nav2beet
48 else
49 for r in 1 2 3 4 5; do
50 sqlite3 /i/navidrome/navidrome.db ".output $r" "select path from annotation inner join media_file on item_id = id where rating = $r;"
51 done
52 fi
53 declare -A flacs
54
55 # todo: consider if this is a problem: file removed/renamed in main
56 # collection, but not yet updated navidrome, we want to skip it not
57 # die.
58
59 while read -r l; do
60 flacs[$l]=t
61 done < <($ssh_prefix find /i/m -type f -name '*.flac')
62 for r in 1 2 3 4 5; do
63 while read -r path; do
64 beetpath="/i/m${path#/i/converted}"
65 flac="${beetpath%.mp3}.flac"
66 if [[ ${flacs[$flac]} ]]; then
67 beetpath="$flac"
68 fi
69 navirating[$beetpath]=$r
70 done <$r
71 done
72 cd
73 rm -rf $tmpdir
74 declare -A beetrating
75 for r in 1 2 3 4 5; do
76 m beet ls -f '$path' rating:$r >$tmpf
77 while read -r path; do
78 beetrating[$path]=$r
79 done <$tmpf
80 done
81
82 for path in "${!navirating[@]}"; do
83 r="${navirating[$path]}"
84 if [[ $r != "${beetrating[$path]}" ]]; then
85 # note: this assumes there are no cases like filea.mp3 filea.mp3.mp3, which would affect both files.
86 echo "$r != ${beetrating[$path]}, beet modify -y path:$path rating=$r"
87 beet modify -y "path:$path" "rating=$r"
88 fi
89 done
90 # end star rating import from navidrome to beets:
91 fi
92
93 echo begin import navidrome playlists as flexible attribute with value t.
94 # These are only the playlists listed in the beets config.yaml
95 # "subsonicplaylist:" and then duplicated here:
96
97
98 plists=(
99 # these are useful tags
100 expl
101 gimicky
102 sad
103 # these are normal playlists
104 love
105 pump1
106 pumprap
107 rend
108 run
109 )
110 # this puts the navidrome playlists into a smart attribute
111 # subsonic_playlist
112 m beet subsonicplaylist
113
114 beet ls -f '$id $subsonic_playlist' subsonic_playlist::. | sed 's/;/ /g' >$tmpf
115
116 # for debugging
117 #m head $tmpf
118
119 navlists=()
120 while read -r id id_plists; do
121 navlists[id]="$id_plists"
122 done <$tmpf
123
124 for plist in ${plists[@]}; do
125 echo "processing $plist"
126 for id in $(beet ls -f '$id' $plist:t ^genre:spoken-w ^genre:skit ^rating:1); do
127 found=false
128 newnavlist=()
129 for navlist in ${navlists[id]}; do
130 if [[ $navlist == "$plist" ]]; then
131 found=true
132 else
133 newnavlist+=($navlist)
134 fi
135 done
136 if $found; then
137 navlists[id]="${newnavlist[*]}"
138 else
139 # exists in beets, but not navidrome so we must have removed
140 # it from the playlist in navidrome.
141 m beet modify -y "id:$id" "$plist!"
142 fi
143 done
144 done
145 # The ones we didnt find and remove are ones we added
146 # in navidrome.
147 for id in ${!navlists[@]}; do
148 [[ ${navlists[id]} ]] || continue
149 m beet modify -y "id:$id" ${navlists[id]// /=t }=t
150 done
151
152 # old way of doing it which sets everything. this doesnt
153 # account for removed tracks in navidrome, and it will
154 # be slower for handling many playlists.
155 # while read -r id plists; do
156 # plists="${plists#;}"
157 # m beet modify -y "id:$id" ${plists//;/=t }
158 # done < <(beet ls -f '$id $subsonic_playlist' subsonic_playlist::.)
159
160 # if we remove a track from a playlist in navidrome,
161 # beet subsonicplaylist won't remove corresponding beet
162 # smart attribute, so clear them all here.
163
164 m beet modify -y subsonic_playlist::. 'subsonic_playlist!'