Skip to content

Instantly share code, notes, and snippets.

@YukariChiba
Last active October 23, 2025 03:21
Show Gist options
  • Select an option

  • Save YukariChiba/923d9e5beb432945615eb340be15866a to your computer and use it in GitHub Desktop.

Select an option

Save YukariChiba/923d9e5beb432945615eb340be15866a to your computer and use it in GitHub Desktop.
netease-cloud-music-gtk export downloaded musics script
#!/bin/bash
function checkcmd() {
cmdpkg=$1
[ -z "$2" ] || cmdpkg="$1 (in $2)"
command -v $1 > /dev/null || { echo "error: $cmdpkg is required"; exit 1; }
}
checkcmd jq
checkcmd file
checkcmd magick ImageMagick
checkcmd metaflac flac
checkcmd ffmpeg
checkcmd mid3v2 mutagen
checkcmd bc
checkcmd mediainfo
cachedir=$(realpath ~/.cache/netease-cloud-music-gtk4)
[ -d $cachedir ] || { echo "error: cache dir ($cachedir) not found"; exit 1; }
destdir=$(realpath ~/Music/netease-cloud-music-gtk4)
mkdir -p $destdir
function musicextract() {
m_meta=$1
m_id="$(jq -r '.id | select (.!=null)' $m_meta)"
m_title="$(jq -r '.name | select (.!=null)' $m_meta)"
m_artist="$(jq -r '.singer | select (.!=null)' $m_meta)"
m_album="$(jq -r '.album | select (.!=null)' $m_meta)"
m_album_id="$(jq -r '.album_id | select (.!=null)' $m_meta)"
m_duration="$(jq -r '.duration | select (.!=null)' $m_meta)"
m_pic_url="$(jq -r '.pic_url | select (.!=null)' $m_meta)"
m_rate=$(find $cachedir -name "music_${m_id}_*" | rev | cut -f1 -d '_' | rev | sort -nr | head -n 1)
m_file="$cachedir/music_${m_id}_${m_rate}"
[ -f "$m_file" ] || return
[ -z "$(find $destdir -name $m_id-$m_rate.*)" ] || return
f_duration=$(mediainfo --Inform='Audio;%Duration%' $m_file)
if [ "$f_duration" -lt "$m_duration" ]; then
echo "Warning: skip potential partial music: $m_title - $m_album [$f_duration < $m_duration] ($m_album_id/$m_id)"
return
fi
m_type="$(file -ib $m_file | cut -f1 -d ';')"
m_pic=$(mktemp)
curl -s $m_pic_url --output $m_pic
m_pic_type=$(file -ib $m_pic | cut -f1 -d ';')
if [ "$m_pic_type" == "image/png" ]; then
magick -quiet $m_pic -quality 95% $m_pic.jpg
m_pic=$m_pic.jpg
m_pic_type=image/jpeg
fi
m_destdir="$destdir/${m_album_id}"
mkdir -p $m_destdir
m_dest="$m_destdir/$m_id-$m_rate"
m_lrc="$cachedir/$m_id.tlrc"
a_meta=$cachedir/album_$m_album_id.meta.json
if [ -f $a_meta ]; then
a_time="$(jq -r '.publish_time | select (.!=null)' $a_meta)"
a_time="$(date -d @$(echo "$a_time / 1000" | bc) +%Y-%m-%d)"
a_artist="$(jq -r '.artist_name | select (.!=null)' $a_meta)"
m_order="$(jq -r ".songs | map(.id == $m_id) | index(true) | select (.!=null) + 1" $a_meta)"
fi
case $m_type in
"audio/flac")
m_dest=$m_dest.flac
cp $m_file $m_dest
metaflac \
--set-tag=ALBUM="$m_album" \
--set-tag=ARTIST="$m_artist" \
--set-tag=TITLE="$m_title" \
--import-picture-from="|$m_pic_type|||$m_pic" \
$m_dest > /dev/null
[ ! -f $a_meta ] || \
metaflac \
--set-tag=ALBUMARTIST="$a_artist" \
--set-tag=TRACKNUMBER="$m_order" \
--set-tag=DATE="$a_time" \
$m_dest > /dev/null
[ ! -f $m_lrc ] || \
metaflac \
--set-tag-from-file=LYRICS=$m_lrc \
$m_dest > /dev/null
;;
"audio/mpeg")
[ ! -f $m_lrc ] || cp $m_lrc $m_dest.lrc
m_dest=$m_dest.mp3
cp $m_file $m_dest
mid3v2 -a "$m_artist" -t "$m_title" -A "$m_album" -p $m_pic $m_dest > /dev/null
[ ! -f $a_meta ] || \
mid3v2 --TPE2 "$a_artist" -T "$m_order" --date "$a_time" $m_dest > /dev/null
;;
esac
echo "New song added: $m_title - $m_album [$m_type] ($m_album_id/$m_id)"
}
export -f musicextract
export cachedir destdir
find $cachedir -name "music_*.meta.json" | xargs -P 4 -I @ bash -c "musicextract @"
echo "Done!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment