#!/usr/bin/env bash scriptVersion="1.0.3" if [ -z "$lidarrUrl" ] || [ -z "$lidarrApiKey" ]; then lidarrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" if [ "$lidarrUrlBase" == "null" ]; then lidarrUrlBase="" else lidarrUrlBase="/$(echo "$lidarrUrlBase" | sed "s/\///g")" fi lidarrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" lidarrAgentInstanceId="$(echo "$lidarrApiKey" | cut -c1-10)" lidarrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" lidarrUrl="http://localhost:${lidarrPort}${lidarrUrlBase}" fi agent="lidarr-extended ( https://github.com/RandomNinjaAtk/docker-lidarr-extended )" musicbrainzMirror=https://musicbrainz.org musicbrainzSleep=5 # Debugging settings #addRelatedArtists="true" #addDeezerTopArtists="true" #addDeezerTopAlbumArtists="true" #addDeezerTopTrackArtists="true" #topLimit="3" #addRelatedArtists="true" #numberOfRelatedArtistsToAddPerArtist="1" #lidarrSearchForMissing=false touch "/config/logs/AutoArtistAdder.txt" chmod 666 "/config/logs/AutoArtistAdder.txt" exec &> >(tee -a "/config/logs/AutoArtistAdder.txt") sleepTimer=0.5 log () { m_time=`date "+%F %T"` echo $m_time" :: AutoArtistAdder :: $scriptVersion :: "$1 } NotifyWebhook () { if [ "$webHook" ] then content="$1: $2" curl -s -X POST "{$webHook}" -H 'Content-Type: application/json' -d '{"event":"'"$1"'", "message":"'"$2"'", "content":"'"$content"'"}' fi } AddDeezerTopArtists () { getDeezerArtistsIds=$(curl -s "https://api.deezer.com/chart/0/artists?limit=$1" | jq -r ".data[].id") getDeezerArtistsIdsCount=$(echo "$getDeezerArtistsIds" | wc -l) getDeezerArtistsIds=($(echo "$getDeezerArtistsIds")) sleep $sleepTimer description="Top Artists" AddDeezerArtistToLidarr } AddDeezerTopAlbumArtists () { getDeezerArtistsIds=$(curl -s "https://api.deezer.com/chart/0/albums?limit=$1" | jq -r ".data[].artist.id") getDeezerArtistsIdsCount=$(echo "$getDeezerArtistsIds" | wc -l) getDeezerArtistsIds=($(echo "$getDeezerArtistsIds")) sleep $sleepTimer description="Top Album Artists" AddDeezerArtistToLidarr } AddDeezerTopTrackArtists () { getDeezerArtistsIds=$(curl -s "https://api.deezer.com/chart/0/tracks?limit=$1" | jq -r ".data[].artist.id") getDeezerArtistsIdsCount=$(echo "$getDeezerArtistsIds" | wc -l) getDeezerArtistsIds=($(echo "$getDeezerArtistsIds")) sleep $sleepTimer description="Top Track Artists" AddDeezerArtistToLidarr } AddDeezerArtistToLidarr () { lidarrArtistsData="$(curl -s "$lidarrUrl/api/v1/artist?apikey=${lidarrApiKey}")" lidarrArtistIds="$(echo "${lidarrArtistsData}" | jq -r ".[].foreignArtistId")" deezerArtistsUrl=$(echo "${lidarrArtistsData}" | jq -r ".[].links | .[] | select(.name==\"deezer\") | .url") deezerArtistIds="$(echo "$deezerArtistsUrl" | grep -o '[[:digit:]]*' | sort -u)" log "Finding $description..." log "$getDeezerArtistsIdsCount $description Found..." for id in ${!getDeezerArtistsIds[@]}; do currentprocess=$(( $id + 1 )) deezerArtistId="${getDeezerArtistsIds[$id]}" deezerArtistName="$(curl -s https://api.deezer.com/artist/$deezerArtistId | jq -r .name)" sleep $sleepTimer log "$currentprocess of $getDeezerArtistsIdsCount :: $deezerArtistName :: Searching Musicbrainz for Deezer artist id ($deezerArtistId)" if echo "$deezerArtistIds" | grep "^${deezerArtistId}$" | read; then log "$currentprocess of $getDeezerArtistsIdsCount :: $deezerArtistName :: $deezerArtistId already in Lidarr..." continue fi query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22https://www.deezer.com/artist/${deezerArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") if [ "$count" == "0" ]; then sleep $musicbrainzSleep query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22http://www.deezer.com/artist/${deezerArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") sleep $musicbrainzSleep fi if [ "$count" == "0" ]; then query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22http://deezer.com/artist/${deezerArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") sleep $musicbrainzSleep fi if [ "$count" == "0" ]; then query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22https://deezer.com/artist/${deezerArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") fi if [ "$count" != "0" ]; then musicbrainz_main_artist_id=$(echo "$query_data" | jq -r '.urls[]."relation-list"[].relations[].artist.id' | head -n 1) sleep $musicbrainzSleep artist_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/artist/$musicbrainz_main_artist_id?fmt=json") artist_sort_name="$(echo "$artist_data" | jq -r '."sort-name"')" artist_formed="$(echo "$artist_data" | jq -r '."begin-area".name')" artist_born="$(echo "$artist_data" | jq -r '."life-span".begin')" gender="$(echo "$artist_data" | jq -r ".gender")" matched_id=true data=$(curl -s "$lidarrUrl/api/v1/search?term=lidarr%3A$musicbrainz_main_artist_id" -H "X-Api-Key: $lidarrApiKey" | jq -r ".[]") artistName="$(echo "$data" | jq -r ".artist.artistName")" foreignId="$(echo "$data" | jq -r ".foreignId")" importListExclusionData=$(curl -s "$lidarrUrl/api/v1/importlistexclusion" -H "X-Api-Key: $lidarrApiKey" | jq -r ".[].foreignId") if echo "$importListExclusionData" | grep "^${foreignId}$" | read; then log "$currentprocess of $getDeezerArtistsIdsCount :: $deezerArtistName :: ERROR :: Artist is on import exclusion block list, skipping...." continue fi data=$(curl -s "$lidarrUrl/api/v1/rootFolder" -H "X-Api-Key: $lidarrApiKey" | jq -r ".[]") path="$(echo "$data" | jq -r ".path")" path=$(echo $path | cut -d' ' -f1) qualityProfileId="$(echo "$data" | jq -r ".defaultQualityProfileId")" qualityProfileId=$(echo $qualityProfileId | cut -d' ' -f1) metadataProfileId="$(echo "$data" | jq -r ".defaultMetadataProfileId")" metadataProfileId=$(echo $metadataProfileId | cut -d' ' -f1) data="{ \"artistName\": \"$artistName\", \"foreignArtistId\": \"$foreignId\", \"qualityProfileId\": $qualityProfileId, \"metadataProfileId\": $metadataProfileId, \"monitored\":true, \"monitor\":\"all\", \"rootFolderPath\": \"$path\", \"addOptions\":{\"searchForMissingAlbums\":$lidarrSearchForMissing} }" if echo "$lidarrArtistIds" | grep "^${musicbrainz_main_artist_id}$" | read; then log "$currentprocess of $getDeezerArtistsIdsCount :: $deezerArtistName :: Already in Lidarr ($musicbrainz_main_artist_id), skipping..." continue fi log "$currentprocess of $getDeezerArtistsIdsCount :: $deezerArtistName :: Adding $artistName to Lidarr ($musicbrainz_main_artist_id)..." LidarrTaskStatusCheck lidarrAddArtist=$(curl -s "$lidarrUrl/api/v1/artist" -X POST -H 'Content-Type: application/json' -H "X-Api-Key: $lidarrApiKey" --data-raw "$data") else log "$currentprocess of $getDeezerArtistsIdsCount :: $deezerArtistName :: Artist not found in Musicbrainz, please add \"https://deezer.com/artist/${deezerArtistId}\" to the correct artist on Musicbrainz" NotifyWebhook "ArtistError" "Artist not found in Musicbrainz, please add to the correct artist on Musicbrainz" fi LidarrTaskStatusCheck done } AddDeezerRelatedArtists () { log "Begin adding Lidarr related Artists from Deezer..." lidarrArtistsData="$(curl -s "$lidarrUrl/api/v1/artist?apikey=${lidarrApiKey}")" lidarrArtistTotal=$(echo "${lidarrArtistsData}"| jq -r '.[].sortName' | wc -l) lidarrArtistList=($(echo "${lidarrArtistsData}" | jq -r ".[].foreignArtistId")) lidarrArtistIds="$(echo "${lidarrArtistsData}" | jq -r ".[].foreignArtistId")" lidarrArtistLinkDeezerIds="$(echo "${lidarrArtistsData}" | jq -r ".[] | .links[] | select(.name==\"deezer\") | .url" | grep -o '[[:digit:]]*')" log "$lidarrArtistTotal Artists Found" deezerArtistsUrl=$(echo "${lidarrArtistsData}" | jq -r ".[].links | .[] | select(.name==\"deezer\") | .url") deezerArtistIds="$(echo "$deezerArtistsUrl" | grep -o '[[:digit:]]*' | sort -u)" for id in ${!lidarrArtistList[@]}; do artistNumber=$(( $id + 1 )) musicbrainzId="${lidarrArtistList[$id]}" lidarrArtistData=$(echo "${lidarrArtistsData}" | jq -r ".[] | select(.foreignArtistId==\"${musicbrainzId}\")") lidarrArtistName="$(echo "${lidarrArtistData}" | jq -r " .artistName")" deezerArtistUrl=$(echo "${lidarrArtistData}" | jq -r ".links | .[] | select(.name==\"deezer\") | .url") deezerArtistIds=($(echo "$deezerArtistUrl" | grep -o '[[:digit:]]*' | sort -u)) lidarrArtistMonitored=$(echo "${lidarrArtistData}" | jq -r ".monitored") log "$artistNumber of $lidarrArtistTotal :: $wantedAlbumListSource :: $lidarrArtistName :: Adding Related Artists..." if [ "$lidarrArtistMonitored" == "false" ]; then log "$artistNumber of $lidarrArtistTotal :: $wantedAlbumListSource :: $lidarrArtistName :: Artist is not monitored :: skipping..." continue fi for dId in ${!deezerArtistIds[@]}; do deezerArtistId="${deezerArtistIds[$dId]}" deezerRelatedArtistData=$(curl -sL --fail "https://api.deezer.com/artist/$deezerArtistId/related?limit=$numberOfRelatedArtistsToAddPerArtist"| jq -r ".data | sort_by(.nb_fan) | reverse | .[]") sleep $sleepTimer getDeezerArtistsIds=($(echo $deezerRelatedArtistData | jq -r .id)) getDeezerArtistsIdsCount=$(echo $deezerRelatedArtistData | jq -r .id | wc -l) description="$lidarrArtistName Related Artists" AddDeezerArtistToLidarr done done } LidarrTaskStatusCheck () { alerted=no until false do taskCount=$(curl -s "$lidarrUrl/api/v1/command?apikey=${lidarrApiKey}" | jq -r .[].status | grep -v completed | grep -v failed | wc -l) if [ "$taskCount" -ge "1" ]; then if [ "$alerted" == "no" ]; then alerted=yes log "STATUS :: LIDARR BUSY :: Pausing/waiting for all active Lidarr tasks to end..." fi sleep $musicbrainzSleep else break fi done } AddTidalRelatedArtists () { log "Begin adding Lidarr related Artists from Tidal..." lidarrArtistsData="$(curl -s "$lidarrUrl/api/v1/artist?apikey=${lidarrApiKey}")" lidarrArtistTotal=$(echo "${lidarrArtistsData}"| jq -r '.[].sortName' | wc -l) lidarrArtistList=($(echo "${lidarrArtistsData}" | jq -r ".[].foreignArtistId")) lidarrArtistIds="$(echo "${lidarrArtistsData}" | jq -r ".[].foreignArtistId")" lidarrArtistLinkTidalIds="$(echo "${lidarrArtistsData}" | jq -r ".[] | .links[] | select(.name==\"tidal\") | .url" | grep -o '[[:digit:]]*' | sort -u)" log "$lidarrArtistTotal Artists Found" for id in ${!lidarrArtistList[@]}; do artistNumber=$(( $id + 1 )) musicbrainzId="${lidarrArtistList[$id]}" lidarrArtistData=$(echo "${lidarrArtistsData}" | jq -r ".[] | select(.foreignArtistId==\"${musicbrainzId}\")") lidarrArtistName="$(echo "${lidarrArtistData}" | jq -r " .artistName")" serviceArtistUrl=$(echo "${lidarrArtistData}" | jq -r ".links | .[] | select(.name==\"tidal\") | .url") serviceArtistIds=($(echo "$serviceArtistUrl" | grep -o '[[:digit:]]*' | sort -u)) lidarrArtistMonitored=$(echo "${lidarrArtistData}" | jq -r ".monitored") log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: Adding Related Artists..." if [ "$lidarrArtistMonitored" == "false" ]; then log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: Artist is not monitored :: skipping..." continue fi for Id in ${!serviceArtistIds[@]}; do serviceArtistId="${serviceArtistIds[$Id]}" serviceRelatedArtistData=$(curl -sL --fail "https://api.tidal.com/v1/pages/single-module-page/ae223310-a4c2-4568-a770-ffef70344441/4/b4b95795-778b-49c5-a34f-59aac055b662/1?artistId=$serviceArtistId&countryCode=$tidalCountryCode&deviceType=BROWSER" -H 'x-tidal-token: CzET4vdadNUFQ5JU' | jq -r .rows[].modules[].pagedList.items[]) sleep $sleepTimer serviceRelatedArtistsIds=($(echo $serviceRelatedArtistData | jq -r .id)) serviceRelatedArtistsIdsCount=$(echo $serviceRelatedArtistData | jq -r .id | wc -l) log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: $serviceArtistId :: Found $serviceRelatedArtistsIdsCount Artists, adding $numberOfRelatedArtistsToAddPerArtist..." AddTidalArtistToLidarr done done } AddTidalArtistToLidarr () { currentprocess=0 for id in ${!serviceRelatedArtistsIds[@]}; do currentprocess=$(( $id + 1 )) if [ $currentprocess -gt $numberOfRelatedArtistsToAddPerArtist ]; then break fi serviceArtistId="${serviceRelatedArtistsIds[$id]}" serviceArtistName="$(echo "$serviceRelatedArtistData"| jq -r "select(.id==$serviceArtistId) | .name")" log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: $currentprocess of $numberOfRelatedArtistsToAddPerArtist :: $serviceArtistName :: Searching Musicbrainz for Tidal artist id ($serviceArtistId)" if echo "$lidarrArtistLinkTidalIds" | grep "^${serviceArtistId}$" | read; then log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: $currentprocess of $numberOfRelatedArtistsToAddPerArtist :: $serviceArtistName :: $serviceArtistId already in Lidarr..." continue fi query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22https://listen.tidal.com/artist/${serviceArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") if [ "$count" == "0" ]; then sleep $musicbrainzSleep query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22http://listen.tidal.com/artist/${serviceArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") fi if [ "$count" == "0" ]; then sleep $musicbrainzSleep query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22https://tidal.com/artist/${serviceArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") fi if [ "$count" == "0" ]; then sleep $musicbrainzSleep query_data=$(curl -s -A "$agent" "https://musicbrainz.org/ws/2/url?query=url:%22http://tidal.com/artist/${serviceArtistId}%22&fmt=json") count=$(echo "$query_data" | jq -r ".count") fi if [ "$count" != "0" ]; then musicbrainz_main_artist_id=$(echo "$query_data" | jq -r '.urls[]."relation-list"[].relations[].artist.id' | head -n 1) data=$(curl -s "$lidarrUrl/api/v1/search?term=lidarr%3A$musicbrainz_main_artist_id" -H "X-Api-Key: $lidarrApiKey" | jq -r ".[]") artistName="$(echo "$data" | jq -r ".artist.artistName")" foreignId="$(echo "$data" | jq -r ".foreignId")" importListExclusionData=$(curl -s "$lidarrUrl/api/v1/importlistexclusion" -H "X-Api-Key: $lidarrApiKey" | jq -r ".[].foreignId") if echo "$importListExclusionData" | grep "^${foreignId}$" | read; then log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: $currentprocess of $numberOfRelatedArtistsToAddPerArtist :: $serviceArtistName :: ERROR :: Artist is on import exclusion block list, skipping...." continue fi data=$(curl -s "$lidarrUrl/api/v1/rootFolder" -H "X-Api-Key: $lidarrApiKey" | jq -r ".[]") path="$(echo "$data" | jq -r ".path")" path=$(echo $path | cut -d' ' -f1) qualityProfileId="$(echo "$data" | jq -r ".defaultQualityProfileId")" qualityProfileId=$(echo $qualityProfileId | cut -d' ' -f1) metadataProfileId="$(echo "$data" | jq -r ".defaultMetadataProfileId")" metadataProfileId=$(echo $metadataProfileId | cut -d' ' -f1) data="{ \"artistName\": \"$artistName\", \"foreignArtistId\": \"$foreignId\", \"qualityProfileId\": $qualityProfileId, \"metadataProfileId\": $metadataProfileId, \"monitored\":true, \"monitor\":\"all\", \"rootFolderPath\": \"$path\", \"addOptions\":{\"searchForMissingAlbums\":$lidarrSearchForMissing} }" if echo "$lidarrArtistIds" | grep "^${musicbrainz_main_artist_id}$" | read; then log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: $currentprocess of $numberOfRelatedArtistsToAddPerArtist :: $serviceArtistName :: Already in Lidarr ($musicbrainz_main_artist_id), skipping..." continue fi log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: $currentprocess of $numberOfRelatedArtistsToAddPerArtist :: $serviceArtistName :: Adding $artistName to Lidarr ($musicbrainz_main_artist_id)..." LidarrTaskStatusCheck lidarrAddArtist=$(curl -s "$lidarrUrl/api/v1/artist" -X POST -H 'Content-Type: application/json' -H "X-Api-Key: $lidarrApiKey" --data-raw "$data") else log "$artistNumber of $lidarrArtistTotal :: $lidarrArtistName :: $currentprocess of $numberOfRelatedArtistsToAddPerArtist :: $serviceArtistName :: ERROR :: Artist not found in Musicbrainz, please add \"https://listen.tidal.com/artist/${serviceArtistId}\" to the correct artist on Musicbrainz" NotifyWebhook "ArtistError" "Artist not found in Musicbrainz, please add to the correct artist on Musicbrainz" fi LidarrTaskStatusCheck done } if [ -z $lidarrSearchForMissing ]; then lidarrSearchForMissing=true fi if [ "$addDeezerTopArtists" == "true" ]; then AddDeezerTopArtists "$topLimit" fi if [ "$addDeezerTopAlbumArtists" == "true" ]; then AddDeezerTopAlbumArtists "$topLimit" fi if [ "$addDeezerTopTrackArtists" == "true" ]; then AddDeezerTopTrackArtists "$topLimit" fi if [ "$addRelatedArtists" == "true" ]; then AddDeezerRelatedArtists AddTidalRelatedArtists fi exit