From d36b8a907549c605b1bc93071ad034f3a7b2f062 Mon Sep 17 00:00:00 2001 From: Karolis Date: Sun, 5 May 2024 22:40:06 +0300 Subject: [PATCH 1/8] Bump debian compat level to 10 Will not package with level 5, minimum 7 is required, but everything <10 is deprecated. --- debian/compat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/compat b/debian/compat index 7ed6ff82..f599e28b 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -5 +10 From 93f4218fc2e9fd4e1f8d425af2e68d355a8f97b1 Mon Sep 17 00:00:00 2001 From: Carl di Ortus Date: Sun, 5 May 2024 23:17:48 +0300 Subject: [PATCH 2/8] copy-paste from last.fm to listenbrainz --- plugins/listenbrainz.pm | 293 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 plugins/listenbrainz.pm diff --git a/plugins/listenbrainz.pm b/plugins/listenbrainz.pm new file mode 100644 index 00000000..3e634dec --- /dev/null +++ b/plugins/listenbrainz.pm @@ -0,0 +1,293 @@ +# Copyright (C) 2005-2009 Quentin Sculo +# +# This file is part of Gmusicbrowser. +# Gmusicbrowser is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, as +# published by the Free Software Foundation + +=for gmbplugin AUDIOSCROBBLER +name last.fm +title last.fm plugin +desc Submit played songs to last.fm +=cut + + +package GMB::Plugin::AUDIOSCROBBLER; +use strict; +use warnings; +use constant +{ CLIENTID => 'gmb', VERSION => '0.1', + OPT => 'PLUGIN_AUDIOSCROBBLER_',#used to identify the plugin's options + SAVEFILE => 'audioscrobbler.queue', #file used to save unsent data +}; +use Digest::MD5 'md5_hex'; +require $::HTTP_module; + +our $ignore_current_song; + +my $self=bless {},__PACKAGE__; +my @ToSubmit; my $NowPlaying; my $NowPlayingID; my $unsent_saved=0; +my $interval=5; my ($timeout,$waiting); +my ($HandshakeOK,$submiturl,$nowplayingurl,$sessionid); +my ($Serrors,$Stop); +my $Log= Gtk3::ListStore->new('Glib::String'); +Load(); + +sub Start +{ ::Watch($self,PlayingSong=> \&SongChanged); + ::Watch($self,Played => \&Played); + ::Watch($self,Save => \&Save); + $self->{on}=1; + Sleep(); + SongChanged() if $::TogPlay; + $Serrors=$Stop=undef; +} +sub Stop +{ $waiting->abort if $waiting; + Glib::Source->remove($timeout) if $timeout; + $timeout=$waiting=undef; + ::UnWatch($self,$_) for qw/PlayingSong Played Save/; + $self->{on}=undef; + $interval=5; + #@ToSubmit=(); +} + +sub prefbox +{ my $vbox= Gtk3::VBox->new(::FALSE, 2); + my $sg1= Gtk3::SizeGroup->new('horizontal'); + my $sg2= Gtk3::SizeGroup->new('horizontal'); + my $entry1=::NewPrefEntry(OPT.'USER',_"username :", cb => \&userpass_changed, sizeg1 => $sg1,sizeg2=>$sg2); + my $entry2=::NewPrefEntry(OPT.'PASS',_"password :", cb => \&userpass_changed, sizeg1 => $sg1,sizeg2=>$sg2, hide => 1); + my $label2= Gtk3::Button->new(_"(see http://www.last.fm)"); + $label2->set_relief('none'); + $label2->signal_connect(clicked => sub + { my $url='http://www.last.fm'; + my $user=$::Options{OPT.'USER'}; + $url.="/user/$user/" if defined $user && $user ne ''; + ::openurl($url); + }); + my $ignore= Gtk3::CheckButton->new(_"Don't submit current song"); + $ignore->signal_connect(toggled=>sub { return if $_[0]->{busy}; $ignore_current_song= $_[0]->get_active ? $::SongID : undef; ::HasChanged('Lastfm_ignore_current'); }); + ::Watch($ignore,Lastfm_ignore_current => sub { $_[0]->{busy}=1; $_[0]->set_active(defined $ignore_current_song); delete $_[0]->{busy}; } ); + my $queue= Gtk3::Label->new; + my $sendnow= Gtk3::Button->new(_"Send now"); + $sendnow->signal_connect(clicked=> \&SendNow); + my $qbox= ::Hpack($queue,$sendnow); + $vbox->pack_start($_,::FALSE,::FALSE,0) for $label2,$entry1,$entry2,$ignore,$qbox; + $vbox->add( ::LogView($Log) ); + $qbox->{label}=$queue; + $qbox->{button}=$sendnow; + $qbox->show_all; + update_queue_label($qbox); + $qbox->set_no_show_all(1); + ::Watch($qbox,Lastfm_state_change=>\&update_queue_label); + return $vbox; +} +sub update_queue_label +{ my $qbox=shift; + my $label= $qbox->{label}; + if (@ToSubmit && (@ToSubmit>1 || (!$waiting && (!$timeout || $interval>10)))) + { $label->set_text(::__n("%d song waiting to be sent","%d songs waiting to be sent", scalar @ToSubmit )); + $label->get_parent->show; + $qbox->{button}->set_sensitive(!$waiting); + } + else { $label->get_parent->hide } +} +sub userpass_changed +{ $HandshakeOK=$Serrors=undef; + $Stop=undef if $Stop && $Stop eq 'BadAuth'; +} + +sub SongChanged +{ if (defined $ignore_current_song) + { return if defined $::SongID && $::SongID == $ignore_current_song; + $ignore_current_song=undef; ::HasChanged('Lastfm_ignore_current'); + } + $NowPlaying=undef; + my ($title,$artist,$album,$track,$length)= Songs::Get($::SongID,qw/title artist album track length/); + return if $title eq '' || $artist eq ''; + $NowPlaying= [ $artist, $title, $album, $length, $track, '' ]; + $NowPlayingID=$::SongID; + Sleep(); +} + +sub Played +{ my (undef,$ID,undef,$start_time,$seconds,$coverage)=@_; + return if $ignore_current_song; + return unless $seconds>10; + my $length= Songs::Get($ID,'length'); + if ($length>=30 && ($seconds >= 240 || $coverage >= .5) ) + { my ($title,$artist,$album,$track)= Songs::Get($ID,qw/title artist album track/); + return if $title eq '' || $artist eq ''; + ::IdleDo("9_".__PACKAGE__,10000,\&Save) if @ToSubmit>$unsent_saved; + push @ToSubmit,[ $artist,$title,$album,'',$length,$start_time,$track,'P' ]; + Sleep(); + ::QHasChanged('Lastfm_state_change'); + } +} + +sub Handshake +{ $HandshakeOK=0; + my $user=$::Options{OPT.'USER'}; + return 0 unless defined $user && $user ne ''; + my $pass=$::Options{OPT.'PASS'}; + my $time=time; + my $auth=md5_hex(md5_hex($pass).$time); + Send(\&response_cb,'http://post.audioscrobbler.com/?hs=true&p=1.2&c='.CLIENTID.'&v='.VERSION."&u=$user&t=$time&a=$auth"); +} + +sub response_cb +{ my ($response,@lines)=@_; + my $error; + if (!defined $response) {$error=_"connection failed";} + elsif ($response eq 'OK') { } + elsif ($response=~m/^FAILED (.*)$/) {$error=$1} + elsif ($response eq 'BADAUTH') {$error=_("User authentification error"); $Stop='BadAuth';} + elsif ($response eq 'BANNED') {$error=_("Client banned, contact gmusicbrowser's developer"); $Stop='Banned';} + elsif ($response eq 'BADTIME') {$error=_("System clock is not close enough to the current time"); $Stop='BadTime';} + else {$error=_"unknown error";} + + if (defined $error) + { unless ($Stop) + { $interval*=2; + $interval=30*60 if $interval>30*60; + $interval=60 if $interval<60; + $error.= ::__x( ' (' . _("retry in {seconds} s") . ')', seconds => $interval); + } + Log(_("Handshake failed : ").$error); + } + else + { ($sessionid,$nowplayingurl,$submiturl)=@lines; + $interval=5; + $HandshakeOK=1; + $Serrors=0; + Log(_"Handshake OK"); + } +} + +sub Submit +{ my $post="s=$sessionid"; + my $i=0; + my $url; + if (@ToSubmit) + { while (my $aref=$ToSubmit[$i]) + { my @data= map { defined $_ ? ::url_escapeall($_) : "" } @$aref; + $post.=sprintf "&a[$i]=%s&t[$i]=%s&b[$i]=%s&m[$i]=%s&l[$i]=%s&i[$i]=%s&n[$i]=%s&o[$i]=%s&r[$i]=", @data; + $i++; + last if $i==50; #don't submit more than 50 songs at a time + } + $url=$submiturl; + return unless $i; + } + elsif ($NowPlaying) + { if (!defined $::PlayingID || $::PlayingID!=$NowPlayingID) { $NowPlaying=undef; return } + my @data= map { defined $_ ? ::url_escapeall($_) : "" } @$NowPlaying; + $post.= sprintf "&a=%s&t=%s&b=%s&l=%s&n=%s&m=%s", @data; + $url=$nowplayingurl; + } + else {return} + my $response_cb=sub + { my ($response,@lines)=@_; + my $error; + if (!defined $response) {$error=_"connection failed"; $Serrors++} + elsif ($response eq 'OK') + { $Serrors=0; + if ($i) + { Log( _("Submit OK") . ' ('. + ($i>1 ? ::__n("%d song","%d songs",$i) + : ::__x( _"{song} by {artist}", song=> $ToSubmit[0][1], artist => $ToSubmit[0][0]) ) . ')' ); + splice @ToSubmit,0,$i; + ::IdleDo("9_".__PACKAGE__,10000,\&Save) if $unsent_saved; + } + elsif ($NowPlaying) + { Log( _("Submit Now-Playing OK") . ' ('. + ::__x( _"{song} by {artist}", song=> $NowPlaying->[1], artist => $NowPlaying->[0]) . ')' ); + $NowPlaying=undef; + } + } + elsif ($response eq 'BADSESSION') + { $error=_"Bad session"; + $HandshakeOK=0; + } + elsif ($response=~m/^FAILED (.*)$/) + { $error=$1; + $Serrors++; + } + else {$error=_"unknown error"; $Serrors++} + + $HandshakeOK=0 if $Serrors && $Serrors>2; + + if (defined $error) + { Log(_("Submit failed : ").$error); + } + }; + + warn "submitting: $post\n" if $::debug; + Send($response_cb,$url,$post); +} + +sub SendNow +{ $interval=5; + $Serrors=$Stop=undef; + Glib::Source->remove($timeout) if $timeout; + Awake(); +} +sub Sleep +{ #warn "Sleep\n"; + return unless $self->{on}; + ::QHasChanged('Lastfm_state_change'); + return if $Stop || $waiting || $timeout; + $timeout=Glib::Timeout->add(1000*$interval,\&Awake) if @ToSubmit || $NowPlaying; + #warn "Sleeping $interval seconds\n" if $timeout; +} +sub Awake +{ #warn "Awoke\n"; + $timeout=undef; + return 0 if !$self->{on} || $waiting; + if ($HandshakeOK) { Submit(); } + else { Handshake(); } + Sleep(); + return 0; +} +sub Send +{ my ($response_cb,$url,$post)=@_; + my $cb=sub + { my @response=(defined $_[0])? split "\012",$_[0] : (); + $waiting=undef; + &$response_cb(@response); + Sleep(); + }; + $waiting=Simple_http::get_with_cb(cb => $cb,url => $url,post => $post); + ::QHasChanged('Lastfm_state_change'); +} + +sub Log +{ my $text=$_[0]; + $Log->set( $Log->prepend,0, localtime().' '.$text ); + warn "$text\n" if $::debug; + if (my $iter=$Log->iter_nth_child(undef,50)) { $Log->remove($iter); } +} + +sub Load #read unsent data +{ return unless -r $::HomeDir.SAVEFILE; + return unless open my$fh,'<:utf8',$::HomeDir.SAVEFILE; + while (my $line=<$fh>) + { chomp $line; + my @data=split "\x1D",$line; + push @ToSubmit,\@data if @data==8; + } + close $fh; + Log(::__("Loaded %d unsent song from previous session","Loaded %d unsent songs from previous session", scalar @ToSubmit)); +} +sub Save #save unsent data to a file +{ $unsent_saved=@ToSubmit; + unless (@ToSubmit) + { unlink $::HomeDir.SAVEFILE; return } + my $fh; + unless (open $fh,'>:utf8',$::HomeDir.SAVEFILE) + { warn "Error creating '$::HomeDir".SAVEFILE."' : $!\nUnsent last.fm data will be lost.\n"; return; } + print $fh join("\x1D",@$_)."\n" for @ToSubmit; + close $fh; +} + +1; From c04d1ae8e9fc7c751122716ef1da89000239fdcd Mon Sep 17 00:00:00 2001 From: Carl di Ortus Date: Sun, 5 May 2024 23:54:28 +0300 Subject: [PATCH 3/8] rename all instances, restore original querystring --- plugins/listenbrainz.pm | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/plugins/listenbrainz.pm b/plugins/listenbrainz.pm index 3e634dec..9fd9ec00 100644 --- a/plugins/listenbrainz.pm +++ b/plugins/listenbrainz.pm @@ -1,24 +1,24 @@ -# Copyright (C) 2005-2009 Quentin Sculo +# Copyright (C) 2024 Carl di Ortus # # This file is part of Gmusicbrowser. # Gmusicbrowser is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation -=for gmbplugin AUDIOSCROBBLER -name last.fm -title last.fm plugin -desc Submit played songs to last.fm +=for gmbplugin LISTENBRAINZ +name listenbrainz +title listenbrainz.org plugin +desc Submit played songs to listenbrainz =cut -package GMB::Plugin::AUDIOSCROBBLER; +package GMB::Plugin::LISTENBRAINZ; use strict; use warnings; use constant { CLIENTID => 'gmb', VERSION => '0.1', - OPT => 'PLUGIN_AUDIOSCROBBLER_',#used to identify the plugin's options - SAVEFILE => 'audioscrobbler.queue', #file used to save unsent data + OPT => 'PLUGIN_LISTENBRAINZ_',#used to identify the plugin's options + SAVEFILE => 'listenbrainz.queue', #file used to save unsent data }; use Digest::MD5 'md5_hex'; require $::HTTP_module; @@ -58,17 +58,17 @@ sub prefbox my $sg2= Gtk3::SizeGroup->new('horizontal'); my $entry1=::NewPrefEntry(OPT.'USER',_"username :", cb => \&userpass_changed, sizeg1 => $sg1,sizeg2=>$sg2); my $entry2=::NewPrefEntry(OPT.'PASS',_"password :", cb => \&userpass_changed, sizeg1 => $sg1,sizeg2=>$sg2, hide => 1); - my $label2= Gtk3::Button->new(_"(see http://www.last.fm)"); + my $label2= Gtk3::Button->new(_"(see https://listenbrainz.org)"); $label2->set_relief('none'); $label2->signal_connect(clicked => sub - { my $url='http://www.last.fm'; + { my $url='https://listenbrainz.org'; my $user=$::Options{OPT.'USER'}; $url.="/user/$user/" if defined $user && $user ne ''; ::openurl($url); }); my $ignore= Gtk3::CheckButton->new(_"Don't submit current song"); - $ignore->signal_connect(toggled=>sub { return if $_[0]->{busy}; $ignore_current_song= $_[0]->get_active ? $::SongID : undef; ::HasChanged('Lastfm_ignore_current'); }); - ::Watch($ignore,Lastfm_ignore_current => sub { $_[0]->{busy}=1; $_[0]->set_active(defined $ignore_current_song); delete $_[0]->{busy}; } ); + $ignore->signal_connect(toggled=>sub { return if $_[0]->{busy}; $ignore_current_song= $_[0]->get_active ? $::SongID : undef; ::HasChanged('Listenbrainz_ignore_current'); }); + ::Watch($ignore,Listenbrainz_ignore_current => sub { $_[0]->{busy}=1; $_[0]->set_active(defined $ignore_current_song); delete $_[0]->{busy}; } ); my $queue= Gtk3::Label->new; my $sendnow= Gtk3::Button->new(_"Send now"); $sendnow->signal_connect(clicked=> \&SendNow); @@ -80,7 +80,7 @@ sub prefbox $qbox->show_all; update_queue_label($qbox); $qbox->set_no_show_all(1); - ::Watch($qbox,Lastfm_state_change=>\&update_queue_label); + ::Watch($qbox,Listenbrainz_state_change=>\&update_queue_label); return $vbox; } sub update_queue_label @@ -101,7 +101,7 @@ sub userpass_changed sub SongChanged { if (defined $ignore_current_song) { return if defined $::SongID && $::SongID == $ignore_current_song; - $ignore_current_song=undef; ::HasChanged('Lastfm_ignore_current'); + $ignore_current_song=undef; ::HasChanged('Listenbrainz_ignore_current'); } $NowPlaying=undef; my ($title,$artist,$album,$track,$length)= Songs::Get($::SongID,qw/title artist album track length/); @@ -122,7 +122,7 @@ sub Played ::IdleDo("9_".__PACKAGE__,10000,\&Save) if @ToSubmit>$unsent_saved; push @ToSubmit,[ $artist,$title,$album,'',$length,$start_time,$track,'P' ]; Sleep(); - ::QHasChanged('Lastfm_state_change'); + ::QHasChanged('Listenbrainz_state_change'); } } @@ -133,7 +133,7 @@ sub Handshake my $pass=$::Options{OPT.'PASS'}; my $time=time; my $auth=md5_hex(md5_hex($pass).$time); - Send(\&response_cb,'http://post.audioscrobbler.com/?hs=true&p=1.2&c='.CLIENTID.'&v='.VERSION."&u=$user&t=$time&a=$auth"); + Send(\&response_cb,'http://proxy.listenbrainz.org/?hs=true&p=1.2&c='.CLIENTID.'&v='.VERSION."&u=$user&t=$time&a=$auth"); } sub response_cb @@ -235,7 +235,7 @@ sub SendNow sub Sleep { #warn "Sleep\n"; return unless $self->{on}; - ::QHasChanged('Lastfm_state_change'); + ::QHasChanged('Listenbrainz_state_change'); return if $Stop || $waiting || $timeout; $timeout=Glib::Timeout->add(1000*$interval,\&Awake) if @ToSubmit || $NowPlaying; #warn "Sleeping $interval seconds\n" if $timeout; @@ -258,7 +258,7 @@ sub Send Sleep(); }; $waiting=Simple_http::get_with_cb(cb => $cb,url => $url,post => $post); - ::QHasChanged('Lastfm_state_change'); + ::QHasChanged('Listenbrainz_state_change'); } sub Log @@ -285,7 +285,7 @@ sub Save #save unsent data to a file { unlink $::HomeDir.SAVEFILE; return } my $fh; unless (open $fh,'>:utf8',$::HomeDir.SAVEFILE) - { warn "Error creating '$::HomeDir".SAVEFILE."' : $!\nUnsent last.fm data will be lost.\n"; return; } + { warn "Error creating '$::HomeDir".SAVEFILE."' : $!\nUnsent listenbrainz.org data will be lost.\n"; return; } print $fh join("\x1D",@$_)."\n" for @ToSubmit; close $fh; } From bb1e8c5cecaf2f199c1496f732e558026dc7bb31 Mon Sep 17 00:00:00 2001 From: Carl di Ortus Date: Sun, 2 Jun 2024 13:28:24 +0300 Subject: [PATCH 4/8] redo listenbrainz plugin with native API --- plugins/listenbrainz.pm | 206 ++++++++++++++-------------------------- simple_http_wget.pm | 30 ++++-- 2 files changed, 91 insertions(+), 145 deletions(-) diff --git a/plugins/listenbrainz.pm b/plugins/listenbrainz.pm index 9fd9ec00..1669b159 100644 --- a/plugins/listenbrainz.pm +++ b/plugins/listenbrainz.pm @@ -18,7 +18,6 @@ use warnings; use constant { CLIENTID => 'gmb', VERSION => '0.1', OPT => 'PLUGIN_LISTENBRAINZ_',#used to identify the plugin's options - SAVEFILE => 'listenbrainz.queue', #file used to save unsent data }; use Digest::MD5 'md5_hex'; require $::HTTP_module; @@ -26,38 +25,33 @@ require $::HTTP_module; our $ignore_current_song; my $self=bless {},__PACKAGE__; -my @ToSubmit; my $NowPlaying; my $NowPlayingID; my $unsent_saved=0; -my $interval=5; my ($timeout,$waiting); -my ($HandshakeOK,$submiturl,$nowplayingurl,$sessionid); -my ($Serrors,$Stop); +my @ToSubmit; my @NowPlaying; my $NowPlayingID; +my $interval=10; my ($timeout,$waiting); +my ($Stop); my $Log= Gtk3::ListStore->new('Glib::String'); -Load(); sub Start { ::Watch($self,PlayingSong=> \&SongChanged); ::Watch($self,Played => \&Played); - ::Watch($self,Save => \&Save); $self->{on}=1; Sleep(); SongChanged() if $::TogPlay; - $Serrors=$Stop=undef; + $Stop=undef; } sub Stop { $waiting->abort if $waiting; Glib::Source->remove($timeout) if $timeout; $timeout=$waiting=undef; - ::UnWatch($self,$_) for qw/PlayingSong Played Save/; + ::UnWatch($self,$_) for qw/PlayingSong Played/; $self->{on}=undef; - $interval=5; - #@ToSubmit=(); + $interval=10; } sub prefbox { my $vbox= Gtk3::VBox->new(::FALSE, 2); my $sg1= Gtk3::SizeGroup->new('horizontal'); my $sg2= Gtk3::SizeGroup->new('horizontal'); - my $entry1=::NewPrefEntry(OPT.'USER',_"username :", cb => \&userpass_changed, sizeg1 => $sg1,sizeg2=>$sg2); - my $entry2=::NewPrefEntry(OPT.'PASS',_"password :", cb => \&userpass_changed, sizeg1 => $sg1,sizeg2=>$sg2, hide => 1); + my $entry2=::NewPrefEntry(OPT.'TOKEN',_"Token :", cb => \&Stop, sizeg1 => $sg1,sizeg2=>$sg2, hide => 1); my $label2= Gtk3::Button->new(_"(see https://listenbrainz.org)"); $label2->set_relief('none'); $label2->signal_connect(clicked => sub @@ -73,7 +67,7 @@ sub prefbox my $sendnow= Gtk3::Button->new(_"Send now"); $sendnow->signal_connect(clicked=> \&SendNow); my $qbox= ::Hpack($queue,$sendnow); - $vbox->pack_start($_,::FALSE,::FALSE,0) for $label2,$entry1,$entry2,$ignore,$qbox; + $vbox->pack_start($_,::FALSE,::FALSE,0) for $label2,$entry2,$ignore,$qbox; $vbox->add( ::LogView($Log) ); $qbox->{label}=$queue; $qbox->{button}=$sendnow; @@ -86,28 +80,27 @@ sub prefbox sub update_queue_label { my $qbox=shift; my $label= $qbox->{label}; - if (@ToSubmit && (@ToSubmit>1 || (!$waiting && (!$timeout || $interval>10)))) - { $label->set_text(::__n("%d song waiting to be sent","%d songs waiting to be sent", scalar @ToSubmit )); + if (@ToSubmit && (!$waiting && (!$timeout || $interval>10))) + { $label->set_text(::__n("song waiting to be sent")); $label->get_parent->show; $qbox->{button}->set_sensitive(!$waiting); } else { $label->get_parent->hide } } -sub userpass_changed -{ $HandshakeOK=$Serrors=undef; - $Stop=undef if $Stop && $Stop eq 'BadAuth'; -} sub SongChanged { if (defined $ignore_current_song) { return if defined $::SongID && $::SongID == $ignore_current_song; $ignore_current_song=undef; ::HasChanged('Listenbrainz_ignore_current'); } - $NowPlaying=undef; - my ($title,$artist,$album,$track,$length)= Songs::Get($::SongID,qw/title artist album track length/); + @NowPlaying=undef; + my ($title,$artist,$album)= Songs::Get($::SongID,qw/title artist album/); return if $title eq '' || $artist eq ''; - $NowPlaying= [ $artist, $title, $album, $length, $track, '' ]; + warn "set NowPlaying"; + @NowPlaying= ( $artist, $title, $album ); $NowPlayingID=$::SongID; + $interval=10; + $timeout=undef; Sleep(); } @@ -117,147 +110,110 @@ sub Played return unless $seconds>10; my $length= Songs::Get($ID,'length'); if ($length>=30 && ($seconds >= 240 || $coverage >= .5) ) - { my ($title,$artist,$album,$track)= Songs::Get($ID,qw/title artist album track/); + { my ($title,$artist,$album)= Songs::Get($ID,qw/title artist album/); return if $title eq '' || $artist eq ''; - ::IdleDo("9_".__PACKAGE__,10000,\&Save) if @ToSubmit>$unsent_saved; - push @ToSubmit,[ $artist,$title,$album,'',$length,$start_time,$track,'P' ]; + warn "set ToSumbit"; + @ToSubmit= ( $artist, $title, $album ); + $interval=10; + $timeout=undef; Sleep(); ::QHasChanged('Listenbrainz_state_change'); } } -sub Handshake -{ $HandshakeOK=0; - my $user=$::Options{OPT.'USER'}; - return 0 unless defined $user && $user ne ''; - my $pass=$::Options{OPT.'PASS'}; - my $time=time; - my $auth=md5_hex(md5_hex($pass).$time); - Send(\&response_cb,'http://proxy.listenbrainz.org/?hs=true&p=1.2&c='.CLIENTID.'&v='.VERSION."&u=$user&t=$time&a=$auth"); -} - -sub response_cb -{ my ($response,@lines)=@_; - my $error; - if (!defined $response) {$error=_"connection failed";} - elsif ($response eq 'OK') { } - elsif ($response=~m/^FAILED (.*)$/) {$error=$1} - elsif ($response eq 'BADAUTH') {$error=_("User authentification error"); $Stop='BadAuth';} - elsif ($response eq 'BANNED') {$error=_("Client banned, contact gmusicbrowser's developer"); $Stop='Banned';} - elsif ($response eq 'BADTIME') {$error=_("System clock is not close enough to the current time"); $Stop='BadTime';} - else {$error=_"unknown error";} - - if (defined $error) - { unless ($Stop) - { $interval*=2; - $interval=30*60 if $interval>30*60; - $interval=60 if $interval<60; - $error.= ::__x( ' (' . _("retry in {seconds} s") . ')', seconds => $interval); - } - Log(_("Handshake failed : ").$error); - } - else - { ($sessionid,$nowplayingurl,$submiturl)=@lines; - $interval=5; - $HandshakeOK=1; - $Serrors=0; - Log(_"Handshake OK"); - } -} - sub Submit -{ my $post="s=$sessionid"; +{ my $i=0; - my $url; + my $url= 'https://api.listenbrainz.org/1/submit-listens'; + my $listen_type; + my $listened_at; + my @payload; if (@ToSubmit) - { while (my $aref=$ToSubmit[$i]) - { my @data= map { defined $_ ? ::url_escapeall($_) : "" } @$aref; - $post.=sprintf "&a[$i]=%s&t[$i]=%s&b[$i]=%s&m[$i]=%s&l[$i]=%s&i[$i]=%s&n[$i]=%s&o[$i]=%s&r[$i]=", @data; - $i++; - last if $i==50; #don't submit more than 50 songs at a time - } - $url=$submiturl; - return unless $i; + { @payload= @ToSubmit; + $listen_type= "single"; + $listened_at= time(); } - elsif ($NowPlaying) - { if (!defined $::PlayingID || $::PlayingID!=$NowPlayingID) { $NowPlaying=undef; return } - my @data= map { defined $_ ? ::url_escapeall($_) : "" } @$NowPlaying; - $post.= sprintf "&a=%s&t=%s&b=%s&l=%s&n=%s&m=%s", @data; - $url=$nowplayingurl; + elsif (@NowPlaying) + { if (!defined $::PlayingID || $::PlayingID!=$NowPlayingID) { @NowPlaying=undef; return } + @payload= @NowPlaying; + $listen_type= "playing_now"; + $listened_at= undef; } else {return} + my $post= '{"listen_type": "'.$listen_type.'", "payload": [{'; + $post.= '"listened_at": '.$listened_at.',' if $listened_at; + $post.= '"track_metadata": {"artist_name": "'.$payload[0].'", "track_name": "'.$payload[1].'"'; + $post.=', "release_name": "'.$payload[2].'"' if $payload[2]; + $post.='}}]}'; my $response_cb=sub { my ($response,@lines)=@_; my $error; - if (!defined $response) {$error=_"connection failed"; $Serrors++} - elsif ($response eq 'OK') - { $Serrors=0; - if ($i) - { Log( _("Submit OK") . ' ('. - ($i>1 ? ::__n("%d song","%d songs",$i) - : ::__x( _"{song} by {artist}", song=> $ToSubmit[0][1], artist => $ToSubmit[0][0]) ) . ')' ); - splice @ToSubmit,0,$i; - ::IdleDo("9_".__PACKAGE__,10000,\&Save) if $unsent_saved; - } - elsif ($NowPlaying) - { Log( _("Submit Now-Playing OK") . ' ('. - ::__x( _"{song} by {artist}", song=> $NowPlaying->[1], artist => $NowPlaying->[0]) . ')' ); - $NowPlaying=undef; - } + if (!defined $response) {$error=_"connection failed";} + elsif ($response eq '{"status":"ok"}') + { if (@ToSubmit) { + Log( _("Submit OK ") . + ::__x( _"{song} by {artist}", song=> $payload[1], artist => $payload[0]) ); + undef @ToSubmit; + $interval=10; + return + }; + if (@NowPlaying) { + Log( _("NowPlaying OK ") . + ::__x( _"{song} by {artist}", song=> $payload[1], artist => $payload[0]) ); + $interval=60; + return + }; } elsif ($response eq 'BADSESSION') { $error=_"Bad session"; - $HandshakeOK=0; } elsif ($response=~m/^FAILED (.*)$/) { $error=$1; - $Serrors++; } - else {$error=_"unknown error"; $Serrors++} - - $HandshakeOK=0 if $Serrors && $Serrors>2; + else {$error=_"unknown error";} if (defined $error) { Log(_("Submit failed : ").$error); + Log(_("Response : ").$response) if $response; + $interval*=2; } }; - warn "submitting: $post\n" if $::debug; - Send($response_cb,$url,$post); + my $authtoken=$::Options{OPT.'TOKEN'}; + Send($response_cb,$url,$post,$authtoken); } sub SendNow -{ $interval=5; - $Serrors=$Stop=undef; +{ $interval=10; + $Stop=undef; Glib::Source->remove($timeout) if $timeout; Awake(); } + sub Sleep -{ #warn "Sleep\n"; - return unless $self->{on}; +{ return unless $self->{on}; ::QHasChanged('Listenbrainz_state_change'); return if $Stop || $waiting || $timeout; - $timeout=Glib::Timeout->add(1000*$interval,\&Awake) if @ToSubmit || $NowPlaying; - #warn "Sleeping $interval seconds\n" if $timeout; + $timeout=Glib::Timeout->add(1000*$interval,\&Awake) if @ToSubmit || @NowPlaying; } + sub Awake -{ #warn "Awoke\n"; - $timeout=undef; +{ $timeout=undef; return 0 if !$self->{on} || $waiting; - if ($HandshakeOK) { Submit(); } - else { Handshake(); } + Submit(); Sleep(); return 0; } + sub Send -{ my ($response_cb,$url,$post)=@_; +{ my ($response_cb,$url,$post,$authtoken)=@_; my $cb=sub { my @response=(defined $_[0])? split "\012",$_[0] : (); $waiting=undef; &$response_cb(@response); Sleep(); }; - $waiting=Simple_http::get_with_cb(cb => $cb,url => $url,post => $post); + $waiting=Simple_http::get_with_cb(cb => $cb,url => $url,post => $post,authtoken => $authtoken); ::QHasChanged('Listenbrainz_state_change'); } @@ -268,26 +224,4 @@ sub Log if (my $iter=$Log->iter_nth_child(undef,50)) { $Log->remove($iter); } } -sub Load #read unsent data -{ return unless -r $::HomeDir.SAVEFILE; - return unless open my$fh,'<:utf8',$::HomeDir.SAVEFILE; - while (my $line=<$fh>) - { chomp $line; - my @data=split "\x1D",$line; - push @ToSubmit,\@data if @data==8; - } - close $fh; - Log(::__("Loaded %d unsent song from previous session","Loaded %d unsent songs from previous session", scalar @ToSubmit)); -} -sub Save #save unsent data to a file -{ $unsent_saved=@ToSubmit; - unless (@ToSubmit) - { unlink $::HomeDir.SAVEFILE; return } - my $fh; - unless (open $fh,'>:utf8',$::HomeDir.SAVEFILE) - { warn "Error creating '$::HomeDir".SAVEFILE."' : $!\nUnsent listenbrainz.org data will be lost.\n"; return; } - print $fh join("\x1D",@$_)."\n" for @ToSubmit; - close $fh; -} - 1; diff --git a/simple_http_wget.pm b/simple_http_wget.pm index 3e19ebea..6ce9dfb1 100644 --- a/simple_http_wget.pm +++ b/simple_http_wget.pm @@ -22,7 +22,7 @@ sub get_with_cb { my $self=bless {}; my %params=@_; $self->{params}=\%params; - my ($callback,$url,$post)=@params{qw/cb url post/}; + my ($callback,$url,$post,$authtoken)=@params{qw/cb url post authtoken/}; delete $params{cache} unless $UseCache; if (my $cached= $params{cache} && GMB::Cache::get($url)) { warn "cached result\n" if $::debug; @@ -36,13 +36,24 @@ sub get_with_cb : $orig_proxy; $ENV{http_proxy}=$proxy; - my $useragent= $params{user_agent} || 'Mozilla/5.0'; - my $accept= $params{'accept'} || ''; - my $gzip= $gzip_ok ? '--header=Accept-Encoding: gzip' : ''; - my @cmd_and_args= (qw/wget --timeout=40 -S -O -/, $gzip, "--header=Accept: $accept", "--user-agent=$useragent"); - push @cmd_and_args, "--referer=$params{referer}" if $params{referer}; - push @cmd_and_args, '--post-data='.$post if $post; #FIXME not sure if I should escape something - push @cmd_and_args, '--',$url; + my $cmd_and_args= 'wget --timeout=40 -S -O -'; + $cmd_and_args.= " -U ".($params{user_agent} || "'Mozilla/5.0'"); + $cmd_and_args.= " --header='Accept-Encoding: gzip'" if $gzip_ok; + $cmd_and_args.= " --header='Authorization: Token ".$authtoken."'" if $authtoken; + $cmd_and_args.= " --header='Content-Type: application/json'" if $authtoken; + $cmd_and_args.= " --referer=$params{referer}" if $params{referer}; + $cmd_and_args.= " --post-data='".$post."'" if $post; #FIXME not sure if I should escape something + $cmd_and_args.= " -- '$url'"; + warn "$cmd_and_args\n"; + + # my $useragent= $params{user_agent} || 'Mozilla/5.0'; + # my @cmd_and_args= (qw/wget --timeout=40 -S -O -/, "--user-agent='$useragent'"); + # push @cmd_and_args, "--header='Authorization: Token ".$authtoken."'" if $authtoken; + # push @cmd_and_args, "--header='Content-Type: application/json'" if $authtoken; + # push @cmd_and_args, "--referer=$params{referer}" if $params{referer}; + # push @cmd_and_args, "--post-data='".$post."'" if $post; #FIXME not sure if I should escape something + # push @cmd_and_args, '--',$url; + # warn "@cmd_and_args\n"; pipe my($content_fh),my$wfh; pipe my($error_fh),my$ewfh; my $pid=fork; @@ -52,7 +63,8 @@ sub get_with_cb open my($olderr), ">&", \*STDERR; open \*STDOUT,'>&='.fileno $wfh; open \*STDERR,'>&='.fileno $ewfh; - exec @cmd_and_args or print $olderr "launch failed (@cmd_and_args) : $!\n"; + #exec @cmd_and_args or print $olderr "launch failed (@cmd_and_args) : $!\n"; + exec $cmd_and_args or print $olderr "launch failed ($cmd_and_args) : $!\n"; POSIX::_exit(1); } close $wfh; close $ewfh; From ac5a78917f4f3ff9616475296aca513a1c63479d Mon Sep 17 00:00:00 2001 From: Carl di Ortus Date: Sat, 10 Aug 2024 17:23:15 +0300 Subject: [PATCH 5/8] fix duplicate listenbrainz submits --- plugins/listenbrainz.pm | 28 ++++++++++++++++++---------- simple_http.pm | 9 +++++++-- simple_http_wget.pm | 11 +---------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/plugins/listenbrainz.pm b/plugins/listenbrainz.pm index 1669b159..3909ae3b 100644 --- a/plugins/listenbrainz.pm +++ b/plugins/listenbrainz.pm @@ -39,7 +39,9 @@ sub Start $Stop=undef; } sub Stop -{ $waiting->abort if $waiting; +{ + @NowPlaying=undef; + $waiting->abort if $waiting; Glib::Source->remove($timeout) if $timeout; $timeout=$waiting=undef; ::UnWatch($self,$_) for qw/PlayingSong Played/; @@ -89,18 +91,17 @@ sub update_queue_label } sub SongChanged -{ if (defined $ignore_current_song) +{ + @NowPlaying=undef; + if (defined $ignore_current_song) { return if defined $::SongID && $::SongID == $ignore_current_song; $ignore_current_song=undef; ::HasChanged('Listenbrainz_ignore_current'); } - @NowPlaying=undef; my ($title,$artist,$album)= Songs::Get($::SongID,qw/title artist album/); return if $title eq '' || $artist eq ''; - warn "set NowPlaying"; @NowPlaying= ( $artist, $title, $album ); $NowPlayingID=$::SongID; $interval=10; - $timeout=undef; Sleep(); } @@ -112,10 +113,8 @@ sub Played if ($length>=30 && ($seconds >= 240 || $coverage >= .5) ) { my ($title,$artist,$album)= Songs::Get($ID,qw/title artist album/); return if $title eq '' || $artist eq ''; - warn "set ToSumbit"; @ToSubmit= ( $artist, $title, $album ); $interval=10; - $timeout=undef; Sleep(); ::QHasChanged('Listenbrainz_state_change'); } @@ -139,14 +138,16 @@ sub Submit $listen_type= "playing_now"; $listened_at= undef; } - else {return} + else { return; } my $post= '{"listen_type": "'.$listen_type.'", "payload": [{'; $post.= '"listened_at": '.$listened_at.',' if $listened_at; $post.= '"track_metadata": {"artist_name": "'.$payload[0].'", "track_name": "'.$payload[1].'"'; $post.=', "release_name": "'.$payload[2].'"' if $payload[2]; $post.='}}]}'; my $response_cb=sub - { my ($response,@lines)=@_; + { + my ($response,@lines)=@_; + #warn "response: $response"; my $error; if (!defined $response) {$error=_"connection failed";} elsif ($response eq '{"status":"ok"}') @@ -154,6 +155,7 @@ sub Submit Log( _("Submit OK ") . ::__x( _"{song} by {artist}", song=> $payload[1], artist => $payload[0]) ); undef @ToSubmit; + undef $waiting; $interval=10; return }; @@ -161,6 +163,7 @@ sub Submit Log( _("NowPlaying OK ") . ::__x( _"{song} by {artist}", song=> $payload[1], artist => $payload[0]) ); $interval=60; + undef $waiting; return }; } @@ -180,6 +183,9 @@ sub Submit }; my $authtoken=$::Options{OPT.'TOKEN'}; + #warn "PAYLOAD - @payload"; + #warn "NOWPLAYING - @NowPlaying"; + #warn "TOSUBMIT - @ToSubmit"; Send($response_cb,$url,$post,$authtoken); } @@ -198,7 +204,8 @@ sub Sleep } sub Awake -{ $timeout=undef; +{ Glib::Source->remove($timeout) if $timeout; + $timeout=undef; return 0 if !$self->{on} || $waiting; Submit(); Sleep(); @@ -213,6 +220,7 @@ sub Send &$response_cb(@response); Sleep(); }; + $waiting=Simple_http::get_with_cb(cb => $cb,url => $url,post => $post,authtoken => $authtoken); ::QHasChanged('Listenbrainz_state_change'); } diff --git a/simple_http.pm b/simple_http.pm index a4e67cfb..a03e8b6a 100644 --- a/simple_http.pm +++ b/simple_http.pm @@ -28,7 +28,7 @@ sub get_with_cb my %params=@_; $self->{params}=\%params; delete $params{cache} unless $UseCache; - my ($callback,$url,$post)=@params{qw/cb url post/}; + my ($callback,$url,$post,$authtoken)=@params{qw/cb url post authtoken/}; if (my $cached= $params{cache} && GMB::Cache::get($url)) { warn "cached result\n" if $::debug; Glib::Timeout->add(10,sub { $callback->( ${$cached->{data}}, type=>$cached->{type}, filename=>$cached->{filename}, ); 0}); @@ -109,11 +109,16 @@ sub connecting_cb print $socket "Host: $host:$port".EOL; print $socket "User-Agent: $useragent".EOL; print $socket "Referer: $params->{referer}".EOL if $params->{referer}; + print $socket "Authorization: Token $params->{authtoken}".EOL if $params->{authtoken}; print $socket "Accept: $accept".EOL; print $socket "Accept-Encoding: gzip".EOL if $gzip_ok; #print $socket "Connection: Keep-Alive".EOL; if (defined $post) - { print $socket 'Content-Type: application/x-www-form-urlencoded; charset=utf-8'.EOL; + { if ($params->{authtoken}) { + print $socket 'Content-Type: application/json'.EOL; + } else { + print $socket 'Content-Type: application/x-www-form-urlencoded; charset=utf-8'.EOL; + } print $socket "Content-Length: ".length($post).EOL.EOL; print $socket $post.EOL; } diff --git a/simple_http_wget.pm b/simple_http_wget.pm index 6ce9dfb1..42567245 100644 --- a/simple_http_wget.pm +++ b/simple_http_wget.pm @@ -44,16 +44,8 @@ sub get_with_cb $cmd_and_args.= " --referer=$params{referer}" if $params{referer}; $cmd_and_args.= " --post-data='".$post."'" if $post; #FIXME not sure if I should escape something $cmd_and_args.= " -- '$url'"; - warn "$cmd_and_args\n"; + #warn "$cmd_and_args\n"; - # my $useragent= $params{user_agent} || 'Mozilla/5.0'; - # my @cmd_and_args= (qw/wget --timeout=40 -S -O -/, "--user-agent='$useragent'"); - # push @cmd_and_args, "--header='Authorization: Token ".$authtoken."'" if $authtoken; - # push @cmd_and_args, "--header='Content-Type: application/json'" if $authtoken; - # push @cmd_and_args, "--referer=$params{referer}" if $params{referer}; - # push @cmd_and_args, "--post-data='".$post."'" if $post; #FIXME not sure if I should escape something - # push @cmd_and_args, '--',$url; - # warn "@cmd_and_args\n"; pipe my($content_fh),my$wfh; pipe my($error_fh),my$ewfh; my $pid=fork; @@ -63,7 +55,6 @@ sub get_with_cb open my($olderr), ">&", \*STDERR; open \*STDOUT,'>&='.fileno $wfh; open \*STDERR,'>&='.fileno $ewfh; - #exec @cmd_and_args or print $olderr "launch failed (@cmd_and_args) : $!\n"; exec $cmd_and_args or print $olderr "launch failed ($cmd_and_args) : $!\n"; POSIX::_exit(1); } From ef7924ed4f3f4b99601d91da42b8c8e60da8921a Mon Sep 17 00:00:00 2001 From: Carl di Ortus Date: Wed, 14 Aug 2024 21:54:49 +0300 Subject: [PATCH 6/8] save post body to file, wget use filename --- plugins/listenbrainz.pm | 45 ++++++++++++++++++++++++++++++----------- simple_http_wget.pm | 4 ++-- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/plugins/listenbrainz.pm b/plugins/listenbrainz.pm index 3909ae3b..15244067 100644 --- a/plugins/listenbrainz.pm +++ b/plugins/listenbrainz.pm @@ -15,11 +15,12 @@ desc Submit played songs to listenbrainz package GMB::Plugin::LISTENBRAINZ; use strict; use warnings; +use JSON; use constant { CLIENTID => 'gmb', VERSION => '0.1', OPT => 'PLUGIN_LISTENBRAINZ_',#used to identify the plugin's options + SAVEFILE => 'listenbrainz.queue', #file used to save unsent data }; -use Digest::MD5 'md5_hex'; require $::HTTP_module; our $ignore_current_song; @@ -139,19 +140,29 @@ sub Submit $listened_at= undef; } else { return; } - my $post= '{"listen_type": "'.$listen_type.'", "payload": [{'; - $post.= '"listened_at": '.$listened_at.',' if $listened_at; - $post.= '"track_metadata": {"artist_name": "'.$payload[0].'", "track_name": "'.$payload[1].'"'; - $post.=', "release_name": "'.$payload[2].'"' if $payload[2]; - $post.='}}]}'; + my $post= { + listen_type => $listen_type, + payload => [ + { + #listened_at => $listened_at, + track_metadata => { + artist_name => $payload[0], + track_name => $payload[1] + #release_name => $payload[2] + } + } + ] + }; + $post->{payload}[0]->{listened_at} = $listened_at if $listened_at; + $post->{payload}[0]->{track_metadata}->{release_name} = $payload[2] if $payload[2]; my $response_cb=sub { my ($response,@lines)=@_; - #warn "response: $response"; my $error; if (!defined $response) {$error=_"connection failed";} elsif ($response eq '{"status":"ok"}') - { if (@ToSubmit) { + { unlink $::HomeDir.SAVEFILE; + if (@ToSubmit) { Log( _("Submit OK ") . ::__x( _"{song} by {artist}", song=> $payload[1], artist => $payload[0]) ); undef @ToSubmit; @@ -183,10 +194,8 @@ sub Submit }; my $authtoken=$::Options{OPT.'TOKEN'}; - #warn "PAYLOAD - @payload"; - #warn "NOWPLAYING - @NowPlaying"; - #warn "TOSUBMIT - @ToSubmit"; - Send($response_cb,$url,$post,$authtoken); + Save($post); + Send($response_cb,$url,$::HomeDir.SAVEFILE,$authtoken); } sub SendNow @@ -232,4 +241,16 @@ sub Log if (my $iter=$Log->iter_nth_child(undef,50)) { $Log->remove($iter); } } +sub Save +{ my $savebody=$_[0]; + unless ($savebody) + { unlink $::HomeDir.SAVEFILE; return } + my $fh; + unless (open $fh,'>:utf8',$::HomeDir.SAVEFILE) + { warn "Error creating '$::HomeDir".SAVEFILE."' : $!\nUnsent listenbrainz.org data will be lost.\n"; return; } + my $json=(to_json $savebody); + print $fh $json; + close $fh; +} + 1; diff --git a/simple_http_wget.pm b/simple_http_wget.pm index 42567245..d71eb154 100644 --- a/simple_http_wget.pm +++ b/simple_http_wget.pm @@ -42,10 +42,10 @@ sub get_with_cb $cmd_and_args.= " --header='Authorization: Token ".$authtoken."'" if $authtoken; $cmd_and_args.= " --header='Content-Type: application/json'" if $authtoken; $cmd_and_args.= " --referer=$params{referer}" if $params{referer}; - $cmd_and_args.= " --post-data='".$post."'" if $post; #FIXME not sure if I should escape something + $cmd_and_args.= " --post-file='".$post."'" if $post; $cmd_and_args.= " -- '$url'"; #warn "$cmd_and_args\n"; - + pipe my($content_fh),my$wfh; pipe my($error_fh),my$ewfh; my $pid=fork; From 5255ba09b8175677afe81a40ac696dba81536864 Mon Sep 17 00:00:00 2001 From: Carl di Ortus Date: Thu, 3 Apr 2025 21:27:51 +0300 Subject: [PATCH 7/8] immediately submit on song change --- gmusicbrowser_songs.pm | 18 ++++++++++++++++++ plugins/listenbrainz.pm | 6 ++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/gmusicbrowser_songs.pm b/gmusicbrowser_songs.pm index 3d84a476..b7a90779 100644 --- a/gmusicbrowser_songs.pm +++ b/gmusicbrowser_songs.pm @@ -1151,6 +1151,24 @@ our %timespan_menu= editsubmenu=>0, category=>'extra', }, +# https://github.com/carl-di-ortus/gmusicbrowser/issues/3 +# https://picard-docs.musicbrainz.org/downloads/MusicBrainz_Picard_Tag_Map.html +# musicbrainz_trackid => +# { name => _"MBID", +# id3v2 => 'TXXX;MusicBrainz Release Track Id;%v', vorbis => 'musicbrainz_releasetrackid', ape => 'MUSICBRAINZ_RELEASETRACKID', ilst => "----:com.apple.iTunes:MusicBrainz Release Track Id", 'id3v2.3' => 'TXXX;MusicBrainz Release Track Id;%v', +# flags => 'fgaescpi', +# type => 'string', +# category=>'extra', +# postread=> sub { my $v=shift; warn "V $v"; }, +# }, +# acoustid => +# { name => _"AcoustID", +# id3v2 => 'TXXX;Acoustid Id;%v', vorbis => 'ACOUSTID_ID', ape => 'ACOUSTID_ID', ilst => "----:com.apple.iTunes:Acoustid Id", +# flags => 'fgaescpi', +# type => 'string', +# category=>'extra', +# postread=> sub { my $v=shift }, +# }, style => { name => _"Styles", width => 180, flags => 'fgaescpil', type => 'flags', diff --git a/plugins/listenbrainz.pm b/plugins/listenbrainz.pm index 15244067..138b12cb 100644 --- a/plugins/listenbrainz.pm +++ b/plugins/listenbrainz.pm @@ -16,9 +16,10 @@ package GMB::Plugin::LISTENBRAINZ; use strict; use warnings; use JSON; +use List::Util qw(max); use constant { CLIENTID => 'gmb', VERSION => '0.1', - OPT => 'PLUGIN_LISTENBRAINZ_',#used to identify the plugin's options + OPT => 'PLUGIN_LISTENBRAINZ_', #used to identify the plugin's options SAVEFILE => 'listenbrainz.queue', #file used to save unsent data }; require $::HTTP_module; @@ -103,7 +104,7 @@ sub SongChanged @NowPlaying= ( $artist, $title, $album ); $NowPlayingID=$::SongID; $interval=10; - Sleep(); + SendNow(); } sub Played @@ -190,6 +191,7 @@ sub Submit { Log(_("Submit failed : ").$error); Log(_("Response : ").$response) if $response; $interval*=2; + $interval=max($interval, 300); } }; From 82543a6f7894f0b2992cf542ee71033d2c2afe11 Mon Sep 17 00:00:00 2001 From: Carl di Ortus Date: Fri, 4 Apr 2025 16:51:36 +0300 Subject: [PATCH 8/8] Remove duplicate timer removal, fixes non-critical Glib-critical warning --- plugins/listenbrainz.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/listenbrainz.pm b/plugins/listenbrainz.pm index 138b12cb..01c6dcf0 100644 --- a/plugins/listenbrainz.pm +++ b/plugins/listenbrainz.pm @@ -203,7 +203,6 @@ sub Submit sub SendNow { $interval=10; $Stop=undef; - Glib::Source->remove($timeout) if $timeout; Awake(); }