Index: Slim/Buttons/TrackInfo.pm =================================================================== --- Slim/Buttons/TrackInfo.pm (revision 17118) +++ Slim/Buttons/TrackInfo.pm (working copy) @@ -30,6 +30,9 @@ our %functions = (); +my %infoProvider; +my @infoOrdering; + # button functions for track info screens sub init { @@ -50,6 +53,11 @@ playOrAdd($client,$addOrInsert); }, ); + + # Our information providers are pluggable, call the + # registerInfoProvider function to extend the details + # provided in the track info menu. + registerDefaultInfoProviders(); } sub cliQuery { @@ -229,184 +237,28 @@ return; } - # If Audioscrobbler is enabled and the current track can be scrobbled, - # add 'Last.fm: Love this track' as the first item - if ( Slim::Utils::PluginManager->isEnabled( 'Slim::Plugin::AudioScrobbler::Plugin' ) ) { - if ( Slim::Plugin::AudioScrobbler::Plugin->canScrobble( $client, $track ) ) { - push @{$client->trackInfoLines}, $client->string('PLUGIN_AUDIOSCROBBLER_LOVE_TRACK'); - push @{$client->trackInfoContent}, sub { - my $client = shift; - - $client->execute( [ 'audioscrobbler', 'loveTrack', $track->url ] ); - - $client->showBriefly( { - line => [ - $client->string('PLUGIN_AUDIOSCROBBLER_LOVE_TRACK'), - $client->string('PLUGIN_AUDIOSCROBBLER_TRACK_LOVED'), - ], - } ); - }; - } + # If we don't have an ordering, generate one. + # This will be triggered every time a change is made to the + # registered information providers, but only then. After + # that, we will have our ordering and only need to step + # through it. + if (scalar(@infoOrdering) == 0) + { + # We don't know what order the entries should be in, + # so work that out. + generateInfoOrderingItem($client, 'top', undef); + generateInfoOrderingItem($client, 'middle', undef); + generateInfoOrderingItem($client, 'bottom', undef); } - - if (my $title = $track->title) { - push (@{$client->trackInfoLines}, $client->string('TITLE') . ": $title"); - push (@{$client->trackInfoContent}, undef); - } - - # Loop through the contributor types and append - for my $role (sort $track->contributorRoles) { - - for my $contributor ($track->contributorsOfType($role)) { - - push (@{$client->trackInfoLines}, sprintf('%s: %s', $client->string(uc($role)), $contributor->name)); - push (@{$client->trackInfoContent}, { - 'type' => uc($role), - 'obj' => $contributor, - }); - } - } - - # Used below for ReplayGain - my $album = $track->album; - - if ($album) { - push (@{$client->trackInfoLines}, join(': ', $client->string('ALBUM'), $album->name)); - push (@{$client->trackInfoContent}, { - 'type' => 'ALBUM', - 'obj' => $album, - }); - } - - if (my $tracknum = $track->tracknum) { - push (@{$client->trackInfoLines}, $client->string('TRACK') . ": $tracknum"); - push (@{$client->trackInfoContent}, undef); - } - - if (my $year = $track->year) { - push (@{$client->trackInfoLines}, $client->string('YEAR') . ": $year"); - push (@{$client->trackInfoContent}, { - 'type' => 'YEAR', - 'obj' => $year, - }); - } - - for my $genre ($track->genres) { - - push (@{$client->trackInfoLines}, join(': ', $client->string('GENRE'), $genre->name)); - push (@{$client->trackInfoContent}, { - 'type' => 'GENRE', - 'obj' => $genre, - }); - } - - if (my $ct = Slim::Schema->contentType($track)) { - push (@{$client->trackInfoLines}, $client->string('TYPE') . ": " . $client->string(uc($ct))); - push (@{$client->trackInfoContent}, undef); - } - - if (my $comment = $track->comment) { - push (@{$client->trackInfoLines}, $client->string('COMMENT') . ": $comment"); - push (@{$client->trackInfoContent}, undef); - } - - if (my $duration = $track->duration) { - push (@{$client->trackInfoLines}, $client->string('LENGTH') . ": $duration"); - push (@{$client->trackInfoContent}, undef); - } - - if (my $replaygain = $track->replay_gain) { - push (@{$client->trackInfoLines}, $client->string('REPLAYGAIN') . ": " . sprintf("%2.2f",$replaygain) . " dB"); - push (@{$client->trackInfoContent}, undef); - } - if (my $rating = $track->rating) { - push (@{$client->trackInfoLines}, $client->string('RATING') . ": " . sprintf("%d",$rating) . " /100"); - push (@{$client->trackInfoContent}, undef); - } - - if (blessed($album) && $album->can('replay_gain')) { - - if (my $albumreplaygain = $album->replay_gain) { - push (@{$client->trackInfoLines}, $client->string('ALBUMREPLAYGAIN') . ": " . sprintf("%2.2f",$albumreplaygain) . " dB"); - push (@{$client->trackInfoContent}, undef); + # Now run the order, which generates all the items we need. + for my $ref (@infoOrdering) + { + if (defined $ref->{'func'}) + { + $ref->{'func'}($client, $ref->{'private'}, $url, $track); } } - - if ( my $bitrate = ( Slim::Music::Info::getCurrentBitrate($track->url) || $track->prettyBitRate ) ) { - - # A bitrate of -1 is set by Scanner::scanBitrate or Formats::*::scanBitrate when the - # bitrate of a remote stream can't be determined - if ( $bitrate ne '-1' ) { - my $undermax = Slim::Player::TranscodingHelper::underMax($client, $track->url); - my $rate = $bitrate; - my $convert = ''; - - if (!$undermax) { - - $rate = Slim::Utils::Prefs::maxRate($client) . $client->string('KBPS') . " ABR"; - } - - if ($client->modeParam('current') && (defined $undermax && !$undermax)) { - - $convert = sprintf('(%s %s)', $client->string('CONVERTED_TO'), $rate); - } - - push (@{$client->trackInfoLines}, sprintf("%s: %s %s", - $client->string('BITRATE'), $bitrate, $convert, - )); - - push (@{$client->trackInfoContent}, undef); - } - } - - if ($track->samplerate) { - push (@{$client->trackInfoLines}, $client->string('SAMPLERATE') . ": " . $track->prettySampleRate); - push (@{$client->trackInfoContent}, undef); - } - - if ($track->samplesize) { - push (@{$client->trackInfoLines}, $client->string('SAMPLESIZE') . ": " . $track->samplesize . " " . $client->string('BITS')); - push (@{$client->trackInfoContent}, undef); - } - - if (my $len = $track->filesize) { - push (@{$client->trackInfoLines}, $client->string('FILELENGTH') . ": " . Slim::Utils::Misc::delimitThousands($len)); - push (@{$client->trackInfoContent}, undef); - } - - if ( !Slim::Music::Info::isRemoteURL($track->url) ) { - if (my $age = $track->modificationTime) { - push (@{$client->trackInfoLines}, $client->string('MODTIME').": $age"); - push (@{$client->trackInfoContent}, undef); - } - } - - if (my $url = $track->url) { - push (@{$client->trackInfoLines}, "URL: ". Slim::Utils::Misc::unescape($url)); - push (@{$client->trackInfoContent}, undef); - } - - if (my $tag = $track->tagversion) { - push (@{$client->trackInfoLines}, $client->string('TAGVERSION') . ": $tag"); - push (@{$client->trackInfoContent}, undef); - } - - if ($track->drm) { - push (@{$client->trackInfoLines}, $client->string('DRM')); - push (@{$client->trackInfoContent}, undef); - } - - if (Slim::Music::Info::isURL($track->url) && Slim::Utils::Favorites->enabled) { - - $client->modeParam( 'favorite', Slim::Utils::Favorites->new($client)->findUrl($track->url) ); - - push (@{$client->trackInfoLines}, 'FAVORITE'); # replaced in lines() - push (@{$client->trackInfoContent}, { - 'type' => 'FAVORITE', - 'obj' => '', - }); - } } sub listExitHandler { @@ -518,34 +370,6 @@ 'selectionCriteria' => $selectionCriteria, }); - } elsif ($curType eq 'FAVORITE') { - - my $favorites = Slim::Utils::Favorites->new($client); - my $favIndex = $client->modeParam('favorite'); - - if (!defined $favIndex) { - - $favIndex = $favorites->add(track($client), $track->title || $track->url); - - $client->showBriefly( { - 'line' => [ $client->string('FAVORITES_ADDING'), $track->title || $track->url ] - }); - - $client->modeParam('favorite', $favIndex); - - } else { - - # Bug 6177, Menu to confirm favorite removal - Slim::Buttons::Common::pushModeLeft( $client, 'favorites.delete', { - title => $track->title || $track->url, - index => $favIndex, - depth => 2, - } ); - - } - - $push = 0; - } else { $push = 0; @@ -563,21 +387,11 @@ # 2nd line's content is provided entirely by trackInfoLines, which returns an array of information lines my $line2 = $client->trackInfoLines->[$index]; - - # special case favorites line, which must be determined dynamically - if ($line2 eq 'FAVORITE') { - my $favIndex = $client->modeParam('favorite'); - if (!defined $favIndex) { - $line2 = $client->string('FAVORITES_RIGHT_TO_ADD'); - } else { - if ($favIndex =~ /^\d+$/) { - # existing favorite at top level - display favorite number starting at 1 (favs are zero based) - $line2 = $client->string('FAVORITES_FAVORITE') . ' ' . ($favIndex + 1); - } else { - # existing favorite not at top level - don't display number - $line2 = $client->string('FAVORITES_FAVORITE'); - } - } + + if (ref $line2 eq 'CODE') + { + # Dynamic line; so call the function to obtain the details + $line2 = &$line2($client); } return $line2; @@ -598,6 +412,633 @@ return ($overlay1, $overlay2); } +## +# Register an information provider with the current providers +# +# @param[in] $name The name of the provider +# @param[in] %details A hashref of the information required by the +# provider +# after => any provider which this info is after +# before => any provider which this info is before +# isa => any provider which this is a member of +# func => the function to call to provide info +# private => a private value to pass to the function +sub registerInfoProvider +{ + my ($name, %details) = @_; + + $details{'name'} = $name; # For diagnostic purposes + if (!defined $details{'after'} && + !defined $details{'before'} && + !defined $details{'isa'}) + { + # If they didn't say anything about where it goes, + # place it in the middle. + $details{'isa'} = 'middle'; + } + $infoProvider{$name} = \%details; + + # Clear the array to force it to be rebuilt + @infoOrdering = (); +} + + +## +# Deregister an information provider +# +# @param[in] $name The name of the provider +sub deregisterInfoProvider +{ + my ($name); + delete $infoProvider{$name}; + + # Clear the array to force it to be rebuilt + @infoOrdering = (); +} + + +## +# Add information to the current list of items. +# +# @param[in] $client The client this request is coming from +# @param[in] $line The text line to add, or may be a coderef in order +# that the line be determined on each execution +# @param[in] $content The operation to perform when this item is selected. +# May be a hashref of information to search for: +# 'type' => a type of search: +# ALBUM = album+track search +# = contributor role search +# GENRE = genre+contrib+album+track search +# YEAR = year+album+track search +# 'obj' => the value searched +# Or may be a code ref to execute the code in the form +# func($client); +# Or may be undef to never push right. +sub addInfo +{ + my $client = shift; + my $line = shift; + my $content = shift; + + push (@{$client->trackInfoLines}, $line); + push (@{$client->trackInfoContent}, $content); +} + +## +# Adds an item to the ordering list, following any +# 'after', 'before' and 'isa' requirements that the +# registered providers have requested. +# +# @param[in] $client The client we're ordering for +# @param[in] $name The name of the item to add +# @param[in] $previous The item before this one, for 'before' processing +sub generateInfoOrderingItem +{ + my $client = shift; + my $name = shift; + my $previous = shift; + my $item; + + # Check for the 'before' items which are 'after' the last item + if (defined $previous) + { + for $item (sort { $a cmp $b } + grep { + defined $infoProvider{$_}->{'after'} && + $infoProvider{$_}->{'after'} eq $previous && + defined $infoProvider{$_}->{'before'} && + $infoProvider{$_}->{'before'} eq $name + } keys %infoProvider) + { + &generateInfoOrderingItem($client, $item, $previous); + } + } + + # Now the before items which are just before this item + for $item (sort { $a cmp $b } + grep { + !defined $infoProvider{$_}->{'after'} && + defined $infoProvider{$_}->{'before'} && + $infoProvider{$_}->{'before'} eq $name + } keys %infoProvider) + { + &generateInfoOrderingItem($client, $item, $previous); + } + + # Add the item itself + push @infoOrdering, $infoProvider{$name}; + + # Now any items that are members of the group + for $item (sort { $a cmp $b } + grep { + defined $infoProvider{$_}->{'isa'} && + $infoProvider{$_}->{'isa'} eq $name + } keys %infoProvider) + { + &generateInfoOrderingItem($client, $item, undef); + } + + # Any 'after' items + for $item (sort { $a cmp $b } + grep { + defined $infoProvider{$_}->{'after'} && + $infoProvider{$_}->{'after'} eq $name && + !defined $infoProvider{$_}->{'before'} + } keys %infoProvider) + { + &generateInfoOrderingItem($client, $item, $name); + } +} + + +## +# Add the 'title' information to the information. +# +# Should call addInfo to add information to the menu. +# +# @param[in] $client The client this request is coming from +# @param[in] $private A private value passed on registration +# @param[in] $url The URL to which this information refers +# @param[in] $track The track reference +sub infoTitle +{ + my ($client, $private, $url, $track) = @_; + + if (my $title = $track->title) + { + addInfo($client, + $client->string('TITLE') . ": $title", + undef); + } +} + +## +# See infoTitle +sub infoAlbum +{ + my ($client, $private, $url, $track) = @_; + my $album = $track->album; + + if ($album) { + addInfo($client, + join(': ', $client->string('ALBUM'), $album->name), + { + 'type' => 'ALBUM', + 'obj' => $album, + }); + } +} + +## +# See infoTitle +sub infoContributors +{ + my ($client, $private, $url, $track) = @_; + + # Loop through the contributor types and append + for my $role (sort $track->contributorRoles) { + + for my $contributor ($track->contributorsOfType($role)) { + + addInfo($client, + sprintf('%s: %s', $client->string(uc($role)), $contributor->name), + { + 'type' => uc($role), + 'obj' => $contributor, + }); + } + } +} + +## +# See infoTitle +sub infoTrackNum +{ + my ($client, $private, $url, $track) = @_; + + if (my $tracknum = $track->tracknum) { + addInfo($client, + $client->string('TRACK') . ": $tracknum", + undef); + } +} + +## +# See infoTitle +sub infoYear +{ + my ($client, $private, $url, $track) = @_; + + if (my $year = $track->year) { + addInfo($client, + $client->string('YEAR') . ": $year", + { + 'type' => 'YEAR', + 'obj' => $year, + }); + } +} + +## +# See infoTitle +sub infoGenres +{ + my ($client, $private, $url, $track) = @_; + + for my $genre ($track->genres) { + addInfo($client, + join(': ', $client->string('GENRE'), $genre->name), + { + 'type' => 'GENRE', + 'obj' => $genre, + }); + } +} + +## +# See infoTitle +sub infoContentType +{ + my ($client, $private, $url, $track) = @_; + + if (my $ct = Slim::Schema->contentType($track)) { + addInfo($client, + $client->string('TYPE') . ": " . $client->string(uc($ct)), + undef); + } +} + +## +# See infoTitle +sub infoComment +{ + my ($client, $private, $url, $track) = @_; + + if (my $comment = $track->comment) { + addInfo($client, + $client->string('COMMENT') . ": $comment", + undef); + } +} + +## +# See infoTitle +sub infoDuration +{ + my ($client, $private, $url, $track) = @_; + + if (my $duration = $track->duration) { + addInfo($client, + $client->string('LENGTH') . ": $duration", + undef); + } +} + +## +# See infoTitle +sub infoReplayGain +{ + my ($client, $private, $url, $track) = @_; + + # It makes sense to keep the replaygain and album replaygain + # together. Under earlier vrsions they were separated by the + # rating, which looked strange. + my $album = $track->album; + + if (my $replaygain = $track->replay_gain) { + addInfo($client, + $client->string('REPLAYGAIN') . ": " . sprintf("%2.2f",$replaygain) . " dB", + undef); + } + + if (blessed($album) && $album->can('replay_gain')) { + if (my $albumreplaygain = $album->replay_gain) { + addInfo($client, + $client->string('ALBUMREPLAYGAIN') . ": " . sprintf("%2.2f",$albumreplaygain) . " dB", + undef); + } + } +} + +## +# See infoTitle +sub infoRating +{ + my ($client, $private, $url, $track) = @_; + + if (my $rating = $track->rating) { + addInfo($client, + $client->string('RATING') . ": " . sprintf("%d",$rating) . " /100", + undef); + } +} + +## +# See infoTitle +sub infoBitRate +{ + my ($client, $private, $url, $track) = @_; + + if ( my $bitrate = ( Slim::Music::Info::getCurrentBitrate($track->url) || $track->prettyBitRate ) ) { + + # A bitrate of -1 is set by Scanner::scanBitrate or Formats::*::scanBitrate when the + # bitrate of a remote stream can't be determined + if ( $bitrate ne '-1' ) { + my $undermax = Slim::Player::TranscodingHelper::underMax($client, $track->url); + my $rate = $bitrate; + my $convert = ''; + + if (!$undermax) { + + $rate = Slim::Utils::Prefs::maxRate($client) . $client->string('KBPS') . " ABR"; + } + + if ($client->modeParam('current') && (defined $undermax && !$undermax)) { + + $convert = sprintf('(%s %s)', $client->string('CONVERTED_TO'), $rate); + } + + addInfo($client, + sprintf("%s: %s %s", $client->string('BITRATE'), $bitrate, $convert), + undef); + } + } +} + +## +# See infoTitle +sub infoSampleRate +{ + my ($client, $private, $url, $track) = @_; + + if ($track->samplerate) { + addInfo($client, + $client->string('SAMPLERATE') . ": " . $track->prettySampleRate, + undef); + } +} + +## +# See infoTitle +sub infoSampleSize +{ + my ($client, $private, $url, $track) = @_; + + if ($track->samplesize) { + addInfo($client, + $client->string('SAMPLESIZE') . ": " . $track->samplesize . " " . $client->string('BITS'), + undef); + } +} + +## +# See infoTitle +sub infoFileSize +{ + my ($client, $private, $url, $track) = @_; + + if (my $len = $track->filesize) { + addInfo($client, + $client->string('FILELENGTH') . ": " . Slim::Utils::Misc::delimitThousands($len), + undef); + } +} + +## +# See infoTitle +sub infoFileModTime +{ + my ($client, $private, $url, $track) = @_; + + if ( !Slim::Music::Info::isRemoteURL($track->url) ) { + if (my $age = $track->modificationTime) { + addInfo($client, + $client->string('MODTIME').": $age", + undef); + } + } +} + +## +# See infoTitle +sub infoUrl +{ + my ($client, $private, $url, $track) = @_; + + if (my $turl = $track->url) { + addInfo($client, + "URL: ". Slim::Utils::Misc::unescape($turl), + undef); + } +} + + +## +# See infoTitle +sub infoTagVersion +{ + my ($client, $private, $url, $track) = @_; + + if (my $tag = $track->tagversion) { + addInfo($client, + $client->string('TAGVERSION') . ": $tag", + undef); + } +} + + +## +# See infoTitle +sub infoDRM +{ + my ($client, $private, $url, $track) = @_; + + if ($track->drm) { + addInfo($client, + $client->string('DRM'), + undef); + } +} + + +## +# See infoTitle +# (it's possible this function should live in the +# Favorites plugin, not here). +sub infoFavorite +{ + my ($client, $private, $url, $track) = @_; + + if (Slim::Music::Info::isURL($track->url) && Slim::Utils::Favorites->enabled) { + + $client->modeParam( 'favorite', Slim::Utils::Favorites->new($client)->findUrl($track->url) ); + + addInfo($client, + + # We dynamically determine the line's text for favorites + sub { + my $client = shift; + my $line; + my $favIndex = $client->modeParam('favorite'); + if (!defined $favIndex) { + $line = $client->string('FAVORITES_RIGHT_TO_ADD'); + } else { + if ($favIndex =~ /^\d+$/) { + # existing favorite at top level - display favorite number starting at 1 (favs are zero based) + $line = $client->string('FAVORITES_FAVORITE') . ' ' . ($favIndex + 1); + } else { + # existing favorite not at top level - don't display number + $line = $client->string('FAVORITES_FAVORITE'); + } + } + + return $line; + }, + + sub { + my $client = shift; + my $favorites = Slim::Utils::Favorites->new($client); + my $favIndex = $client->modeParam('favorite'); + + if (!defined $favIndex) { + + $favIndex = $favorites->add(track($client), $track->title || $track->url); + + $client->showBriefly( { + 'line' => [ $client->string('FAVORITES_ADDING'), $track->title || $track->url ] + }); + + $client->modeParam('favorite', $favIndex); + + } else { + + # Bug 6177, Menu to confirm favorite removal + Slim::Buttons::Common::pushModeLeft( $client, 'favorites.delete', { + title => $track->title || $track->url, + index => $favIndex, + depth => 2, + } ); + + } + } ); + } +} + + +## +# Register all the information providers that we provide. +# +sub registerDefaultInfoProviders +{ + # The 'top', 'middle' and 'bottom' groups, so that we can add items in absolute + # positions + registerInfoProvider('top', ('isa' => '') ); + registerInfoProvider('middle', ('isa' => '') ); + registerInfoProvider('bottom', ('isa' => '') ); + + registerInfoProvider('title', ( + 'after' => 'top', + 'func' => \&infoTitle + )); + + registerInfoProvider('contributors', ( + 'after' => 'title', + 'func' => \&infoContributors + )); + + registerInfoProvider('album', ( + 'after' => 'contributors', + 'func' => \&infoAlbum + )); + + registerInfoProvider('tracknum', ( + 'after' => 'album', + 'func' => \&infoTrackNum + )); + + registerInfoProvider('year', ( + 'after' => 'tracknum', + 'func' => \&infoYear + )); + + registerInfoProvider('genres', ( + 'after' => 'year', + 'func' => \&infoGenres + )); + + registerInfoProvider('type', ( + 'after' => 'genres', + 'func' => \&infoContentType + )); + + registerInfoProvider('comment', ( + 'after' => 'type', + 'func' => \&infoComment + )); + + registerInfoProvider('duration', ( + 'after' => 'comment', + 'func' => \&infoDuration + )); + + registerInfoProvider('replaygain', ( + 'after' => 'duration', + 'func' => \&infoReplayGain + )); + + registerInfoProvider('rating', ( + 'after' => 'replaygain', + 'func' => \&infoRating + )); + + registerInfoProvider('formatinfo', ( + 'after' => 'rating' + )); + + registerInfoProvider('fileinfo', ( + 'after' => 'formatinfo' + )); + + registerInfoProvider('favorite', ( + 'after' => 'fileinfo', + 'func' => \&infoFavorite + )); + + # File information + registerInfoProvider('filesize', ( + 'isa' => 'fileinfo', + 'func' => \&infoFileSize + )); + + registerInfoProvider('modtime', ( + 'isa' => 'fileinfo', + 'func' => \&infoFileModTime + )); + + registerInfoProvider('url', ( + 'isa' => 'fileinfo', + 'func' => \&infoUrl + )); + + # Format information + registerInfoProvider('bitrate', ( + 'isa' => 'formatinfo', + 'func' => \&infoBitRate + )); + registerInfoProvider('samplerate', ( + 'isa' => 'formatinfo', + 'func' => \&infoSampleRate + )); + registerInfoProvider('samplesize', ( + 'isa' => 'formatinfo', + 'func' => \&infoSampleSize + )); + registerInfoProvider('drm', ( + 'isa' => 'formatinfo', + 'func' => \&infoDRM + )); +} + =head1 SEE ALSO L Index: Slim/Plugin/AudioScrobbler/Plugin.pm =================================================================== --- Slim/Plugin/AudioScrobbler/Plugin.pm (revision 17118) +++ Slim/Plugin/AudioScrobbler/Plugin.pm (working copy) @@ -79,6 +79,13 @@ Slim::Control::Request::addDispatch(['audioscrobbler', 'banTrack', '_url'], [0, 1, 1, \&banTrack]); + + # Register the 'love this track' option in the TrackInfo menu + Slim::Buttons::TrackInfo::registerInfoProvider('audioscrobbler', + ( + 'isa' => 'top', + 'func' => \&infoLoveTrack + )); } sub shutdownPlugin { @@ -1095,4 +1102,41 @@ return; } + + +## +# Mark the current track as being 'loved'. +# +# Should call addInfo to add information to the menu. +# +# @param[in] $client The client this request is coming from +# @param[in] $private A private value passed on registration +# @param[in] $url The URL to which this information refers +# @param[in] $track The track reference +sub infoLoveTrack +{ + my ($client, $private, $url, $track) = @_; + # If Audioscrobbler is enabled and the current track can be scrobbled, + # add 'Last.fm: Love this track' as the first item + if ( Slim::Utils::PluginManager->isEnabled( 'Slim::Plugin::AudioScrobbler::Plugin' ) ) { + if ( Slim::Plugin::AudioScrobbler::Plugin->canScrobble( $client, $track ) ) { + Slim::Buttons::TrackInfo::addInfo($client, + $client->string('PLUGIN_AUDIOSCROBBLER_LOVE_TRACK'), + sub { + my $client = shift; + + $client->execute( [ 'audioscrobbler', 'loveTrack', $track->url ] ); + + $client->showBriefly( { + line => [ + $client->string('PLUGIN_AUDIOSCROBBLER_LOVE_TRACK'), + $client->string('PLUGIN_AUDIOSCROBBLER_TRACK_LOVED'), + ], + } ); + } + ); + } + } +} + 1;