Last active
September 26, 2025 10:37
-
-
Save kchiem/eb998ac3c6f5a96cbec03b8e8c3b21a6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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