Skip to content

Instantly share code, notes, and snippets.

@kchiem
Last active September 26, 2025 10:37
Show Gist options
  • Select an option

  • Save kchiem/eb998ac3c6f5a96cbec03b8e8c3b21a6 to your computer and use it in GitHub Desktop.

Select an option

Save kchiem/eb998ac3c6f5a96cbec03b8e8c3b21a6 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
# -*- Perl -*-
use strict;
use warnings;
use open qw(:std :encoding(UTF-8));
use Data::Dumper qw(Dumper);
use Getopt::Std;
use IO::Handle;
use JSON::Tiny qw(decode_json);
use LWP::UserAgent;
use Time::Duration;
use URI::Escape;
# EDIT THIS TO YOUR DOCKER URL
use constant LIDARR_BASE => 'http://docker:8686';
# ANSI escape sequences
sub ERASE_EOL { return "\033[K"; }
sub CURSOR_BACK { return "\033[${_[0]}D"; }
sub STATUS { return $_[0] . ERASE_EOL . CURSOR_BACK(length($_[0])) }
getopts('bfhv');
my $dump_body = defined $::opt_b ? $::opt_b : 0;
my $dump_headers = defined $::opt_h ? $::opt_h : 0;
my $fresh_result = defined $::opt_f ? $::opt_f : 0; # vs STALE
my $validate_data = defined $::opt_v ? $::opt_v : 0;
my $url = shift || die "$0 [url]";
my $is_mb = 0;
my $type;
my $id;
STDERR->autoflush(1);
if ($url =~ m%/(release-group|artist|album)/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b%) {
($type, $id) = ($1, $2);
if ($type eq 'release-group') {
$is_mb = 1;
$type = 'album';
}
}
else {
die "unrecognized url: $url";
}
my $json = ping_api($type, $id);
if ($validate_data) {
if (validate($type, $json)) {
# ping associated artist
if ($type eq 'album') {
my $artist_json = ping_api('artist', $json->{artists}[0]{id});
validate('artist', $artist_json);
}
}
}
if ($is_mb or $type eq 'artist') {
print "- add-to-lidarr: " .
LIDARR_BASE . "/add/search?term=" . uri_escape("lidarr:$id") . "\n";
}
else {
print "- refresh: " . LIDARR_BASE . "/artist/" . $json->{artistid} . "\n";
}
## subroutines
sub ping_api {
my ($type, $id) = @_;
my $ua = new LWP::UserAgent;
my $start = time();
my $loops = 0;
my $api = "https://api.lidarr.audio/api/v0.4/$type/$id";
my $json;
print STDERR "Pinging $api\n";
while (1) {
$loops++;
print STDERR STATUS("- attempt $loops");
my $res = $ua->get($api);
my $status = $res->code;
if ($res->is_success) {
eval {
$json = decode_json($res->content);
};
if ($@) {
chomp $@;
warn "Retrying: $@\n";
} elsif ($fresh_result and $res->header('cf-cache-status') eq 'STALE') {
$status .= ' STALE';
} else {
print STDERR ERASE_EOL;
if ($dump_body) {
print $res->content;
} elsif ($dump_headers) {
print $res->headers->as_string;
} else {
last;
}
exit 0;
}
}
print STDERR STATUS("- attempt $loops: $status");
sleep 5;
}
my $elapsed = time() - $start;
print "- ready ($loops attempts, " . duration($elapsed) . ")\n"
if $loops > 1;
if ($type eq 'artist') {
print "- artist: " . $json->{artistname} . "\n";
} else {
print "- album: " . $json->{title} . "\n";
}
return $json;
}
sub validate {
my ($type, $json) = @_;
my @warnings;
if ($type eq 'artist') {
# make sure there are albums
unless (exists $json->{Albums} and scalar @{$json->{Albums}}) {
push(@warnings, 'no albums');
}
}
else {
# detect Unknown Artist problem
unless (exists $json->{artists} and scalar @{$json->{artists}} and
exists $json->{artists}[0]{artistname} and
$json->{artists}[0]{artistname} !~ m%^Unknown Artist \(%) {
push(@warnings, 'no artist');
}
unless (exists $json->{Releases} and scalar @{$json->{Releases}}) {
push(@warnings, 'no releases');
}
else {
unless (exists $json->{Releases}[0]{Tracks} and
scalar @{$json->{Releases}[0]{Tracks}}) {
push(@warnings, 'no tracks');
}
}
}
if (@warnings) {
warn 'WARNING: ' . join(', ', @warnings) . "\n";
return 0;
}
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment