X-Git-Url: https://iankelling.org/git/?a=blobdiff_plain;f=nav2beet;h=e7bdec0b4641e2c8ed7cc09a32b81163f1f64862;hb=refs%2Fheads%2Fmaster;hp=b0ffcd5698a294086c69d0cf06846ca7b104528a;hpb=563cc41a1f3ddb95bedf595cc249f53aea6629c1;p=distro-setup diff --git a/nav2beet b/nav2beet index b0ffcd5..e7bdec0 100755 --- a/nav2beet +++ b/nav2beet @@ -1,17 +1,52 @@ #!/bin/bash +# I, Ian Kelling, follow the GNU license recommendations at +# https://www.gnu.org/licenses/license-recommendations.en.html. They +# recommend that small programs, < 300 lines, be licensed under the +# Apache License 2.0. This file contains or is part of one or more small +# programs. If a small program grows beyond 300 lines, I plan to switch +# its license to GPL. -f=/usr/local/lib/err;test -r $f || { echo "error: $0 no $f" >&2;exit 1;}; . $f +# Copyright 2024 Ian Kelling +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +set -e; . /usr/local/lib/bash-bear; set +e + +source /a/bin/ds/beet-data +source /b/bash_unpublished/source-semi-priv + +declare -A genre_a +for g in ${all_genres[@]}; do + genre_a[$g]=t +done + +# these options are mainly for debugging / developing quickly. plist_only=false dry_run=false while (( $# )); do case $1 in plist) plist_only=true + shift ;; dry) dry_run=true + shift + ;; + *) + echo "error. unexpected arg read script" + exit 1 ;; esac done @@ -19,7 +54,7 @@ done m () { printf "%s\n" "$*" >&2 - if $dry_run && [[ $1 == beet && $2 == modify ]]; then + if $dry_run; then echo "dry run: $*" else "$@" @@ -28,37 +63,34 @@ m () tmpf=$(mktemp) +declare -A flacs -if ! $plist_only; then - echo begin star rating import from navidrome to beets +declare -A navirating +tmpdir=$(mktemp -d) +cd $tmpdir +# the code here is duplicated later for non ssh context. +if [[ $HOSTNAME != kd ]]; then - declare -A navirating - tmpdir=$(mktemp -d) - cd $tmpdir - if [[ $HOSTNAME != kd ]]; then - ssh_prefix="ssh b8.nz" - ssh b8.nz ' + ssh b8.nz bash -s "$(md5sum $tmpf while read -r path; do beetrating[$path]=$r @@ -81,8 +112,16 @@ tar cz -C /tmp nav2beet for path in "${!navirating[@]}"; do r="${navirating[$path]}" + if [[ ! "${beetrating[$path]}" ]]; then + if [[ -e $path ]]; then + echo "$0: ERROR: $path exists but we have no rating for it" + exit 1 + else + echo "$0: WARNING: $path exists in navidrome but not beets" + continue + fi + fi if [[ $r != "${beetrating[$path]}" ]]; then - # note: this assumes there are no cases like filea.mp3 filea.mp3.mp3, which would affect both files. echo "$r != ${beetrating[$path]}, beet modify -y path:$path rating=$r" beet modify -y "path:$path" "rating=$r" fi @@ -91,74 +130,67 @@ tar cz -C /tmp nav2beet fi echo begin import navidrome playlists as flexible attribute with value t. -# These are only the playlists listed in the beets config.yaml -# "subsonicplaylist:" and then duplicated here: - - -plists=( - # these are useful tags - expl - gimicky - sad - # these are normal playlists - love - pump1 - pumprap - rend - run -) -# this puts the navidrome playlists into a smart attribute -# subsonic_playlist -m beet subsonicplaylist - -beet ls -f '$id $subsonic_playlist' subsonic_playlist::. | sed 's/;/ /g' >$tmpf - -# for debugging -#m head $tmpf - -navlists=() -while read -r id id_plists; do - navlists[id]="$id_plists" -done <$tmpf - -for plist in ${plists[@]}; do - echo "processing $plist" - for id in $(beet ls -f '$id' $plist:t ^genre:spoken-w ^genre:skit ^rating:1); do - found=false - newnavlist=() - for navlist in ${navlists[id]}; do - if [[ $navlist == "$plist" ]]; then - found=true - else - newnavlist+=($navlist) - fi - done - if $found; then - navlists[id]="${newnavlist[*]}" + +shopt -s nullglob +for path in 2genre/*/*; do + id="${path#*/}" + id="${id%/*}" + filename="${path##*/}" + tmp="${filename%%[^0-9-]*}" + genre="${filename#"$tmp"}" + if [[ ${genre_a[$genre]} ]]; then + is_genre=true + else + # Some playlists we create with random names to remind us to do something + # with these tracks later once we are at a computer. + is_genre=false + fi + while read -r path; do + flac="${path%.mp3}.flac" + if [[ ${flacs[$flac]} ]]; then + path="$flac" + fi + if $is_genre; then + m beet modify -y "path:$path" "genre=$genre" else - # exists in beets, but not navidrome so we must have removed - # it from the playlist in navidrome. - m beet modify -y "id:$id" "$plist!" + m beet modify -y "path:$path" "$genre=t" fi - done -done -# The ones we didnt find and remove are ones we added -# in navidrome. -for id in ${!navlists[@]}; do - [[ ${navlists[id]} ]] || continue - m beet modify -y "id:$id" ${navlists[id]// /=t }=t + done <"$path" + # how i figured this out: + # s tcpdump -i any -w /tmp/tcpdump port 4533 + # then delete a test playlist in client. + # made some sense out of it with: http://www.subsonic.org/pages/api.jsp + # open file in wireshard, right click "Hypertext Transfer Protocol", copy, as printable text, put into file /tmp/headers + # /a/opt/h2c/h2c p + while read -r path; do + flac="${path%.mp3}.flac" + if [[ ${flacs[$flac]} ]]; then + path="$flac" + fi + m beet modify -y "path:$path" "$plist!" + # files unique to tmpf are in beets not navidrome + done < <(comm -23 p $plist) + while read -r path; do + flac="${path%.mp3}.flac" + if [[ ${flacs[$flac]} ]]; then + path="$flac" + fi + m beet modify -y "path:$path" $plist=t + # files unique to plist are in navidrome not beets + done < <(comm -13 p $plist) + +done -m beet modify -y subsonic_playlist::. 'subsonic_playlist!' +cd +rm -rf $tmpdir