#!/bin/mksh # -*- mode: sh -*- #- # Copyright © 2007, 2008, 2011, 2012, 2013, 2014, 2018, 2019, # 2020, 2021, 2022, 2023 # mirabilos # # Provided that these terms and disclaimer and all copyright notices # are retained or reproduced in an accompanying document, permission # is granted to deal in this work without restriction, including un‐ # limited rights to use, publicly perform, distribute, sell, modify, # merge, give away, or sublicence. # # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to # the utmost extent permitted by applicable law, neither express nor # implied; without malicious intent or gross negligence. In no event # may a licensor, author or contributor be held liable for indirect, # direct, other damage, loss, or other issues arising in any way out # of dealing in the work, even if advised of the possibility of such # damage or existence of a defect, except proven that it results out # of said person’s immediate fault when using the work as intended. #- # cf. $(dirname "$0")/push-music unset LANGUAGE export LC_ALL=C.UTF-8 export TZ=UTC unset UNZIP me=$(realpath "$0") if [[ -z $DISPLAY ]]; then print -ru2 -- "E: re-run with DISPLAY set, need X11" exit 1 fi usage() { print -r -- "E: Usage: $0 [±23 cmd] [-FfnrU] [-c file ...] [-- mscore-args]" print -r -- "N: -c convert only given files (cannot be mixed with other opts)" print -r -- "N: -f do only fonts, -n don’t upload, ±r run mscore (+=2 -=3)" print -r -- "N: -U add UI font + skip tmp cfg/~ for ±r; -F skip MP3/MXL" exit ${1:-1} } function saveFilename { REPLY=${1//+([ - ]|…| | | | | | | | | | | | | |
|
| | | )/ } REPLY=${REPLY%%+( )} REPLY=${REPLY##+( )} REPLY=${REPLY// /_} REPLY=${REPLY//ä/ae} REPLY=${REPLY//ö/oe} REPLY=${REPLY//ü/ue} REPLY=${REPLY//ß/ss} REPLY=${REPLY//Ä/Ae} REPLY=${REPLY//Ö/Oe} REPLY=${REPLY//Ü/Ue} REPLY=${REPLY//♭/b} REPLY=${REPLY//♯/#} REPLY=${REPLY//[\\/:*?\"<>|]/_} } function dumparr { nameref arr=$1 local el for el in "${arr[@]}"; do REPLY+=" ${el@Q}" done REPLY="${1@Q}=(${REPLY:1})" } function try_mscore { local have=0 cmd vchk=$1 exe chroot dv=$2 nameref arr=$dv vsnv=v$dv shift 2 while [[ $1 != . ]]; do exe=$1; chroot=$2 shift 2 set -A cmd -- schroot -prc "$chroot" -- "$exe" [[ -n $chroot ]] || set -A cmd -- "$exe" [[ $("${cmd[@]}" --version 2>/dev/null) = \ MuseScore*" $vchk"* ]] || continue vsnv=$("${cmd[@]}" --long-version 2>&1) vsnv=${vsnv#*'; Version '} vsnv=${vsnv%'; Build '*} if [[ $( if [[ -n $chroot ]]; then schroot -prc "$chroot" -- mksh -c \ 'file $(realpath $(which '"${exe@Q}))" else file $(realpath $(which "$exe")) fi ) = *32-bit*x86-64* ]]; then # x32 binary, prefer others (often slightly buggy) (( have )) || set -A arr -- "${cmd[@]}" have=1 else set -A arr -- "${cmd[@]}" break fi done set +x try_sf "$dv" "${arr[@]}" } function try_sf { local cmd nameref sfa=sf${1#mscore}; shift if [[ $1 = schroot ]]; then set -A cmd -- schroot -prc "$3" -- mksh -c else set -A cmd -- mksh -c fi set -A sfa -- "$("${cmd[@]}" \ 'realpath /usr/share/sounds/sf3/MuseScore_General.sf3')" sfa[1]=$("${cmd[@]}" "python3 - -i ${sfa@Q}" <"${me%/*}"/riffedit.py) sfa=${sfa##/usr/share/sounds/?(sf?/)} } try_mscore 2.3.2 mscore2 \ musescore '' \ musescore bullseye \ musescore buster \ musescore stretch \ . try_mscore 3. mscore3 \ musescore3 '' \ musescore3 bullseye \ musescore3 buster \ musescore-snapshot '' \ . onlyfont=0 onlyconvert=0 domscore=0 doupload=1 doUI=0 dofast=0 while getopts "2:3:cFfhnrU" ch; do case $ch { (2|3) nameref cmd=mscore$ch set -A cmd -- "$OPTARG" try_sf $ch "${cmd[@]}" ;; (+2|+3) set -o noglob nameref cmd=mscore${ch#'+'} set -A cmd -- $OPTARG set +o noglob try_sf $ch "${cmd[@]}" ;; (c) onlyconvert=1 ;; (F) dofast=1 ;; (+F) dofast=0 ;; (f) onlyfont=1 ;; (+f) onlyfont=0 ;; (h) usage 0 ;; (n) doupload=0 ;; (+n) doupload=2 ;; (r) domscore=3 ;; (+r) domscore=2 ;; (U) doUI=1 ;; (+U) doUI=0 ;; (*) usage ;; } done shift $((OPTIND - 1)) theremote=${1:-origin} if (( dofast )); then allexts='mscz pdf mid' else allexts='mscz pdf mp3 mid xml' fi function sfid { nameref sfa=sf$1 print -r -- "${sfa[1]}" | \ tr '\377' '\0' | \ grep -z -a -e ^INAM -e ^ICOP | \ tr '\376\0' ':\n' } print -ru2 -- "D: ${|dumparr mscore2;} $(sfid 2)" print -ru2 -- "D: ${|dumparr mscore3;} $(sfid 3)" sleep 1 set -x set -e set -o inherit-xtrace set -o pipefail . "${me%/*}"/push.inc owd=$PWD cd "$(realpath "$0/../../..")" wd=$(realpath .) mkdir -p .git/t-push T=$(realpath .git/t-push) rm -rf "$T/home" mkdir "$T/home" "$T/home/.config" "$T/home/cfg" "$T/home/cfg/MuseScore" ohome=$(realpath ~) cat >"$T/home/.config/QtProject.conf" <"$T/home/cfg/MuseScore/MuseScore2.ini" <<\EOF [General] alsaDevice=default alsaFragments=3 alsaPeriodSize=1024 alsaSampleRate=48000 checkExtensionsUpdateStartup=false checkUpdateStartup=false enableMidiInput=false exportAudioSampleRate=48000 exportMp3BitRate=128 exportPdfDpi=360 iconHeight=22 iconWidth=22 language=system mixerVisible=false nativeDialogs=true pngResolution=360 pngTransparent=true sessionStart=empty showNavigator=false showPlayPanel=false showSplashScreen=false showStartcenter1=false showStatusBar=true synthControlVisible=false twosided=true useAlsaAudio=true useJackAudio=false useJackMidi=false useJackTransport=false useMidiRemote=false useOsc=false usePortaudioAudio=false usePulseAudio=false workspace=Advanced [MainWindow] showInspector=false showPanel=false showPianoKeyboard=false showSelectionWindow=false EOF cat >"$T/home/cfg/MuseScore/MuseScore3.ini" <<\EOF [General] mixerVisible=false synthControlVisible=false [MainWindow] showInspector=false showPanel=false showPianoKeyboard=false showSelectionWindow=false [application] keyboardLayout=US - International playback\playRepeats=true startup\firstStart=false startup\sessionStart=@Variant(\0\0\0\x7f\0\0\0\x11Ms::SessionStart\0\0\0\0\0) workspace=Advanced [export] audio\normalize=true audio\sampleRate=48000 mp3\bitRate=128 pdf\dpi=360 png\resolution=360 png\useTransparency=true [io] alsa\device=default alsa\fragments=3 alsa\periodSize=1024 alsa\sampleRate=48000 alsa\useAlsaAudio=true jack\useJackAudio=false jack\useJackMIDI=false jack\useJackTransport=false midi\enableInput=false osc\useRemoteControl=false portAudio\usePortAudio=false pulseAudio\usePulseAudio=false [ui] application\language=system application\showStatusBar=true application\startup\checkUpdate=false application\startup\showNavigator=false application\startup\showPlayPanel=false application\startup\showSplashScreen=false application\startup\showStartCenter=false application\startup\showTours=false application\useNativeDialogs=true theme\fontFamily=Fira Sans Medium theme\fontSize=10 theme\iconHeight=16 theme\iconWidth=16 EOF (( doUI )) || HOME=$T/home : "${XAUTHORITY:=$ohome/.Xauthority}" export XAUTHORITY # RFC 2396 and some optional characters _plus_ apostrophe # -> escapes all shell meta-characters as well # minus / function p_uri_escape { print -nr -- "$@" | sed --posix -e ' s.%.%25.g s.;.%3B.g s.?.%3F.g s.:.%3A.g s.@.%40.g s.&.%26.g s.=.%3D.g s.+.%2B.g s.\$.%24.g s.,.%2C.g s. .%09.g s. .%20.g s.<.%3C.g s.>.%3E.g s.#.%23.g s.".%22.g s.{.%7B.g s.}.%7D.g s.|.%7C.g s.\\.%5C.g s.\^.%5E.g s.\[.%5B.g s.\].%5D.g s.`.%60.g s.'\''.%27.g ' } # escape XHTML characters (three mandatory XML ones plus double quotes, # the latter in an XML safe fashion numerically though) function xhtml_escape { if (( $# )); then print -nr -- "$@" else cat fi | sed --posix \ -e 's&\&g' \ -e 's<\<g' \ -e 's>\>g' \ -e 's"\"g' } # same as valsub avoiding fork function xhtml_fesc { REPLY=${1//'&'/'&'} REPLY=${REPLY//'<'/'<'} REPLY=${REPLY//'>'/'>'} REPLY=${REPLY//'"'/'"'} } function utf16hex_escape { # note: UTF-16 needs surrogates for astral planes codepoints! print -nr -- "$1" | iconv -t utf-16be | hexdump -ve '1/1 "%02X"' } if (( !onlyconvert )); then rm -rf .git/t-fonts mkdir -p .git/t-fonts/{conf,fnts,cache,x} sed --posix \ -e "s@fontdir@$(realpath .git/t-fonts/fnts | xhtml_escape)" \ -e "s@cachedir@$(realpath .git/t-fonts/cache | xhtml_escape)" \ .git/t-fonts/conf/fonts.conf for archive in music/resources/Gentium*.zip \ music/resources/GentiumPlus-* \ music/resources/UnifrakturMaguntia*.zip \ ; do archive=$(realpath "$archive") ( cd .git/t-fonts/x case $archive { (*.zip) unzip -- "$archive" ;; (*.t[gx]z|*.tar.[gx]z) tar -xaf "$archive" ;; (*) print -ru2 -- "E: unknown type: $archive"; exit 1 ;; } ) done fntdir=$(realpath .git/t-fonts/fnts) (cd /usr/share/fonts/truetype/freefont; pax -rw -l \ Free{Sans,Serif{,Bold}{,Italic}}.ttf "$fntdir/") (cd .git/t-fonts/x/Gentium-*/; pax -rw -l Gentium-*ttf "$fntdir/") for x in .git/t-fonts/x/GentiumPlus-*; do (cd "$x"; pax -rw -l GentiumPlus*.ttf "$fntdir/") done (cd .git/t-fonts/x/UnifrakturMaguntia*/; pax -rw -l UnifrakturMaguntia.ttf "$fntdir/") rm -r .git/t-fonts/x (cd music/resources/; pax -rw -l *.?tf "$fntdir/") # not suitable for embedding rm -f .git/t-fonts/fnts/Inconsolatazi4varl_qu-Bold.otf fi fntdir=$(realpath .git/t-fonts/fnts) export FC_CONFIG_FILE=$(realpath .git/t-fonts/conf/fonts.conf) export FC_CONFIG_DIR=$(realpath .git/t-fonts/conf) export FONTCONFIG_FILE=$FC_CONFIG_FILE FONTCONFIG_PATH=$FC_CONFIG_DIR fc-list | sort (( !onlyfont )) || exit 0 set -A cfgdir -- -c "$T/home/cfg" -a alsa #-b 160 (( doUI )) && set -A cfgdir #empty if (( domscore )); then firadir=/usr/share/texlive/texmf-dist/fonts/opentype/public/fira [[ -e $firadir/FiraSans-Medium.otf ]] || \ firadir=~/.local/share/fonts (( doUI )) && if [[ -s $firadir/FiraSans-Medium.otf ]]; then print -ru2 -- "N: adding Fira Sans as UI font" (cd "$firadir"; pax -rw -l FiraSans-*.otf "$fntdir/") else print -ru2 -- "W: Fira Sans missing, read usage" fi cd "$owd" cp $wd/music/Mscore$domscore/shortcuts.xml "$T/home/cfg/shortcuts.xml" nameref cmd=mscore$domscore exec "${cmd[@]}" "${cfgdir[@]}" "$@" fi if ! command -v gs >/dev/null 2>&1; then print -ru2 -- "E: install ghostscript" exit 1 fi if ! command -v pdfattach >/dev/null 2>&1; then print -ru2 -- "E: install poppler-utils" exit 1 fi if ! command -v qpdf >/dev/null 2>&1; then print -ru2 -- "E: install qpdf" exit 1 fi # remove target dir unless we’re converting individual files only (( onlyconvert )) || rm -rf .git/t-music # XML-encoded d_mscx='MuseScore (uncompressed)' d_mscz='MuseScore' d_mid='Standard MIDI' d_xml='MusicXML' d_pdf='PDF' d_mp3='MPEG (1 or 2) layer Ⅲ audio' d_metajson='mu͒.com backend data extract' t_mscx=mscx t_mscz=mscz t_mid=SMF t_xml=MusicXML t_pdf=PDF t_mp3=MP3 t_metajson=mu͒3.metajson set -A renamef set -A renamet nrename=0 function cvtf2meta { set +x local V=$1 name=$2 f=$3 pdflist x local bn=${name%.*} parts part partf shift 3 nameref tpdf=to_pdf$nmischk set -A tpdf print -r -- '' # sadly still not useful :||print -r -- ' ]>' print -r -- "" mainpartname=$(xmlstarlet <"$f" sel -T -t \ --if 'boolean(//museScore/Score/name)' \ -v //museScore/Score/name -b \ -n) for x in "$@"; do nameref d=d_$x t=t_$x if [[ $x = pdf && -n $mainpartname ]]; then part=$mainpartname partx=${|xhtml_fesc "$part";} renamef[nrename]="$bn.pdf" renamet[nrename]="$bn [$part].pdf" let ++nrename tpdf+=("$bn [$part].pdf") print -r -- " part" \ "PDF for: $partx" continue fi [[ $x = pdf ]] && tpdf+=("$bn.$x") print -r -- " $d" done # xmlstarlet errors out silently if its output is empty; # write a newline (-n) in the “no parts” case to prevent # that (the $() removes trailing newlines) parts=$(xmlstarlet <"$f" sel -T -t \ --if 'boolean(//museScore/Score/Score)' \ -m //museScore/Score/Score/name -v . -o '' -b \ --else -n -b) while [[ -n $parts ]]; do part=${parts%%*} parts=${parts#*} partf=${|saveFilename "$part";} partx=${|xhtml_fesc "$part";} if [[ $partf != "$part" ]]; then renamef[nrename]="$bn [$partf].pdf" renamet[nrename]="$bn [$part].pdf" let ++nrename fi tpdf+=("$bn [$part].pdf") print -r -- " part" \ "PDF for: $partx" done if [[ $name = *.mscz ]]; then x=$t_mscz else x=$t_mscx fi print -r -- " " xmlstarlet <"$f" tr "${me%/*}"/xlyrics.xsl | sed --posix \ -e '/^" cat print -r -- "" } set -A to_mischk set -A mv_mischk nmischk=0 function cvtf { local name=$1 exts fv set -A exts # analyse file local f=$name V if [[ $f = *.mscz ]]; then f=$(unzip -p -- "$name" META-INF/container.xml | \ xmlstarlet sel -T -t -m //rootfile -v @full-path -n) unzip -p -- "$name" "${f@/[[*?]/[$KSH_MATCH]}" \ >"$T/tmp-analyse" f=$T/tmp-analyse fi fv=$(xmlstarlet <"$f" sel -T -t -m /museScore -v @version -n) if [[ $fv = 2.* ]]; then V=2 elif [[ $fv = 3.* ]]; then V=3 else print -ru2 -- "E: unknown score version in $name" print -ru2 -- "N: version: ${fv@Q}" print -ru2 -- "N: line:" $(fgrep '"$T/tmp-meta" xmlstarlet <"$T/tmp-meta" fo -e UTF-8 -t - >"$db.meta.xml" mv_mischk[nmischk]=$V to_mischk[nmischk++]="${name%.msc[xz]}" } function mischk { local basename name meta rv=0 idx=-1 pdflist pdfname myv rm -f "$T/tmp-analyse" "$T/tmp-meta" "$T/tmp-pdf"* runalltrans while (( ++idx < nmischk )); do nameref thisv=vmscore${mv_mischk[idx]} myv=${thisv##[1-9]*([0-9])*(.[1-9]*([0-9]))} myv=${thisv%"$myv"} basename=${to_mischk[idx]} meta=.git/t-music/"$basename".meta.xml if [[ ! -s $meta ]]; then print -ru2 -- "E: ${meta@Q} missing!" rv=1 continue fi nameref pdflist=to_pdf$idx for name in "${pdflist[@]}"; do for name in .git/t-music/"$name"; do if [[ ! -s $name ]]; then print -ru2 -- "E: ${name@Q} missing!" rv=1 continue fi if ! gs -q -dNOPAUSE -dBATCH -dSAFER \ -sDEVICE=txtwrite -o "$T/tmp-pdf.txt" "$name"; then print -ru2 -- "E: cannot pdf2txt" rv=1 continue fi if grep -Paq '\x00' <"$T/tmp-pdf.txt"; then print -ru2 -- "W: missing glyphs in $name" misglyph+=("$name") rv=1 continue fi if ! gs -q -dNOPAUSE -dBATCH -dSAFER \ -sDEVICE=pdfwrite -sOutputFile="$T/tmp-pdf1.pdf" \ -dEmbedAllFonts=true -dSubsetFonts=true \ -dCompatibilityLevel=1.3 -f "$name"; then print -ru2 -- "E: cannot pdf2pdf13" rv=1 continue fi if ! pdfattach "$T/tmp-pdf1.pdf" "$meta" "$T/tmp-pdf.pdf"; then print -ru2 -- "E: cannot pdfattach" rv=1 continue fi if ! qpdf --remove-unreferenced-resources=yes \ --qdf --min-version=1.3 \ "$T/tmp-pdf.pdf" "$T/tmp-pdf.qdf"; then print -ru2 -- "E: cannot pdf2qdf" rv=1 continue fi pdfname=${name##*/} pdfname=${pdfname%.pdf} pdfname=${pdfname/ -- / — } pdfname=$(utf16hex_escape "$pdfname") if ! pdftitle="${pdfname:+"/Title "}" \ pdfcrtr="/Creator (MuseScore $myv)" perl -ni -e ' next if /^ \/(CreationDate|ModDate|Producer) /; $_ = $ENV{"pdftitle"} if /^ \/Title /; $_ = $ENV{"pdfcrtr"} if /^ \/Creator /; print $_; ' "$T/tmp-pdf.qdf"; then print -ru2 -- "E: cannot munge QDF file" rv=1 continue fi if ! fix-qdf <"$T/tmp-pdf.qdf" >"$T/tmp-pdf2.qdf"; then print -ru2 -- "E: cannot fixup QDF file" rv=1 continue fi if ! qpdf --decode-level=specialized \ --recompress-flate --compression-level=9 \ --remove-unreferenced-resources=yes \ --min-version=1.3 --deterministic-id \ "$T/tmp-pdf2.qdf" "$T/tmp-pdf.pdf"; then print -ru2 -- "E: cannot qdf2pdf" rv=1 continue fi mv "$T/tmp-pdf.pdf" "$name" done done name=.git/t-music/"$basename" if [[ -s $name.mid ]]; then rm -f "$name.csv" midicsv "$name.mid" "$name.csv" ed -s "$name.csv" <<-EOF /Start_track\$/;.t. .,.t. s//Text_t, "/ ka .r !xmlstarlet <${meta@Q} sel -t -m /MirScoreMetadata/score -e MirseScoreMIDI -a mscore-version -v '../mscore-version' -b -c 'node()' -b -b | LC_ALL=C sed --posix $'s/^\t*; s/[^ -~]/sprintf "\\\\\\%03o", ord(\$&)/eg; s/"/""/g; print;' && echo \\" 'a,'a+1j .-1s/Start_track\$/Copyright_t, "/ ka .r !xmlstarlet <${meta@Q} sel -T -t -c '/MirScoreMetadata/score/metaTag[@name="copyright"]' | LC_ALL=C perl -0777 -e '\$_ = <>; s/\n/; /g; s/C⃠/(PD)/g; s/F⃠/(unpermissive)/g; s/€⃠/(non-commercial)/g; s/©/(c)/g; s/Ä/Ae/g; s/Ö/Oe/g; s/Ü/Ue/g; s/ß/sz/g; s/â/a/g; s/ä/ae/g; s/é/e/g; s/ñ/n/g; s/ö/oe/g; s/ü/ue/g; s/ / /g; s/‐/-/g; s/‑/-/g; s/‒/-/g; s/–/-/g; s/—/-/g; s/’/'\''/g; s/€/EUR/g; s/№/No./g; s/℗/(P)/g; s/Ⓕ/(Copyfree)/g; s/⓪/(CC0)/g; s/🄯/(Copyleft)/g; s/[^ -~]/sprintf "\\\\\\%03o", ord(\$&)/eg; s/"/""/g; print;' && echo \\" 'a,'a+1j w q EOF #" csvmidi "$name.csv" "$name.mid" rm "$name.csv" fi name=.git/t-music/"$basename".mp3 if [[ $dofast = 0 && -s $name ]]; then LC_ALL=C.UTF-8 eyeD3 --no-config -P classic \ -2 --to-v2.4 --remove-v1 --encoding=utf8 \ -t "${basename##*/}" -c "$(<"$meta")" \ "$name" fi name=.git/t-music/"$basename".xml [[ $dofast = 0 && -s $name ]] && \ if fgrep -q '/-1r !echo ' ' && xmlstarlet <${meta@Q} sel -t -m /MirScoreMetadata/score/metaTag -e miscellaneous-field -a name -v '@name' -b -c 'node()' -b -n -b | sed --posix 's/^' w q EOF fi done hack_links .git/t-music (( rv )) || return 0 set +x (( ${#misglyph[*]} )) || exit 1 print -ru2 -- "E: missing glyphs found; check them with:" for name in "${misglyph[@]}"; do print -ru2 -- "N: mutool draw -o - -F txt ${PWD@Q}/${name@Q} | less \$'+/\xEF\xBF\xBD'" done print -ru2 -- 'N: or: gs -q -dSAFER -sDEVICE=txtwrite -o - "$name" | jupp -mold dosrch,quote,\"@\",rtn,rtn -' exit 1 } mkdir -p .git/t-music [[ -d .git/t-music/. ]] set -A misglyph rm -f "$T"/t*.{jsn,xml} set +x function do_soundfont { local x y z set -o noglob print -r -- " ${|xhtml_fesc "$1";}" shift print -r -- " " IFS=$'\xFF' set -A y -- $2 for x in "${y[@]}"; do IFS=$'\xFE' set -A z -- $x set -A rs x='$z" done IFS=$' \t\n' print -r -- ' ' } do_soundfont "$vmscore2" "${sf2[@]}" >"$T"/t2.xml do_soundfont "$vmscore3" "${sf3[@]}" >"$T"/t3.xml set -x # escape string into JSON string (with surrounding quotes) function json_escape { set +x # requires mksh R51 set -U local o=\" s if (( $# )); then read -raN-1 s <<<"$*" unset s[${#s[*]}-1] else read -raN-1 s fi local -i i=0 n=${#s[*]} wc local -Uui16 -Z7 x local -i1 ch while (( i < n )); do (( ch = x = wc = s[i++] )) case $wc { (8) o+=\\b ;; (9) o+=\\t ;; (10) o+=\\n ;; (12) o+=\\f ;; (13) o+=\\r ;; (34) o+=\\\" ;; (92) o+=\\\\ ;; (*) if (( wc < 0x20 || wc > 0xFFFD || \ (wc >= 0xD800 && wc <= 0xDFFF) || \ (wc > 0x7E && wc < 0xA0) )); then o+=\\u${x#16#} else o+=${ch#1#} fi ;; } done REPLY="$o\"" } function addtransA { local v=$1 from=$2 toJSN=$3 nameref tlast=tlast$v local f=$T/t$v.jsn print -r -- "${tlast:-[}{\"in\":${|json_escape "$from";},\"out\":$toJSN}" \ >>"$f" tlast=, } function runalltrans { local f for f in $T/t*.jsn; do [[ -s $f ]] || continue runtrans "${f##*/t}" done cd "$wd/.git/t-music" while (( nrename-- )); do mv "${renamef[nrename]}" "${renamet[nrename]}" done cd "$wd" } function runtrans { local V=${1%.jsn} local v=${V::1} nameref cmd=mscore$v local f=$T/t$V.jsn local p= [[ $V = *p* ]] && p=-P print ']' >>"$f" "${cmd[@]}" "${cfgdir[@]}" $p -j "$f" rm -f "$f" } if (( onlyconvert )); then rv=0 for name in "$@"; do name=$(cd "$owd" && realpath "$name") if [[ -s "$name" ]]; then cvtf "${name#"$wd/"}" else print -ru2 -- "E: file \"$name\" does not exist" rv=1 fi done mischk exit $rv fi git find -name \*.mscx -o -name \*.mscz -print0 |& while IFS= read -r -p -d '' name; do checkskip push "$name" || continue cvtf "$name" done mischk rv=0 cd "$wd/.git/t-music" for x in \ 'music/free/Michel -- Macht hoch die Tür + Hosianna [Gemeinde].pdf' \ 'music/free/Monk -- Eventide (Abide with me) [open score].pdf' \ ; do test -s "$x" && continue print -ru2 -- "E: missing: $x" rv=1 done cd "$wd" (( doupload && !rv )) || exit $rv print -u2 '\a' (( doupload < 2 )) || read dummy?'Press Enter to actually upload…' remote=$(git remote get-url --push "$theremote") rhost=${remote%%:*} rpath=${remote#*:} rm -rf "$T/path" ssh -n "$rhost" "${rpath@Q}/mir/push-music" noclean >"$T/path" cat "$T/path" rwdir=$(sed --posix -n '/^THE_WORKTREE=/s/^THE_WORKTREE=\(.*\)$/\1/p' \ <"$T/path") test -n "$rwdir" [[ $rwdir = /* ]] rm -f "$T/path" ssh -n "$rhost" "${rpath@Q}/mir/push-music" rsync -zavPH --numeric-ids -S --stats '--rsh=ssh -T' \ .git/t-music/ "$rhost:$rwdir/" exit $rv