Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 64 additions & 3 deletions API/Async.pm
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,58 @@ sub albumTracks {
my $tracks = shift;
$tracks = $tracks->{data} if $tracks;
# only missing data in album/tracks is the album itself...
$tracks = Plugins::Deezer::API->cacheTrackMetadata( $tracks, { album => $album } ) if $tracks;

$cb->($tracks || []);
# Deezer sets readable:false for tracks not licensed in the user's region or
# subscription. Queuing them causes error 2002 for every track. Filter them
# out here, consistent with playlistTracks. This is independent from the
# FALLBACK mechanism in getTrackUrl/flowTracks: FALLBACK handles tracks that
# are listed as readable but fail at playback time with an alternative version;
# readable:false means the track is genuinely unavailable and no FALLBACK is
# provided. User-uploaded tracks (negative IDs) bypass licensing entirely.
my $total = $tracks ? scalar @$tracks : 0;

# Step 1: filter readable:false and already-known-norights tracks.
# The norights cache is only consulted when check_track_rights is
# enabled; disabling the option restores all tracks to visibility.
my $checkRights = $prefs->get('check_track_rights');
$tracks = [grep {
($_->{readable} || (defined $_->{id} && $_->{id} < 0)) &&
(!$checkRights || !$cache->get("deezer_track_norights_$_->{id}"))
} @$tracks] if $tracks;

my $finish = sub {
my $filtered = shift;
$filtered = Plugins::Deezer::API->cacheTrackMetadata($filtered, { album => $album });
my $kept = $filtered ? scalar @$filtered : 0;
$log->info("albumTracks id=$id: $total total, $kept kept after filter");
$cb->($filtered || []);
};

# Step 2: if check_track_rights is enabled and this album has not been
# rights-checked yet, call song.getListData to find remaining unplayable
# tracks and cache them (TTL from rights_cache_ttl pref).
if ($checkRights && $tracks && @$tracks
&& !$cache->get("deezer_album_rights_$id")) {
my @ids = map { $_->{id} } @$tracks;
$self->gwCall(sub {
my ($result) = @_;
my $ttl = ($prefs->get('rights_cache_ttl') || 24) * 3600;
my %unplayable;
foreach my $t (@{ $result->{results}->{data} || [] }) {
if (!($t->{RIGHTS} && %{$t->{RIGHTS}}) && !$t->{FALLBACK}) {
$unplayable{$t->{SNG_ID}} = 1;
$cache->set("deezer_track_norights_$t->{SNG_ID}", 1, $ttl);
}
}
$cache->set("deezer_album_rights_$id", 1, $ttl);
$finish->([grep { !$unplayable{$_->{id}} } @$tracks]);
}, {
method => 'song.getListData',
}, {
sng_ids => \@ids,
});
} else {
$finish->($tracks || []);
}
}, {
limit => MAX_LIMIT,
} );
Expand Down Expand Up @@ -721,6 +770,18 @@ sub getTrackUrl {
my @trackIds = map { $_->{SNG_ID} } @{ $result->{results}->{data} };
#$log->error(Data::Dump::dump(\@trackTokens), Data::Dump::dump(\@trackIds));

# Tracks with no rights AND no fallback cannot be streamed by any means.
# Cache their IDs so albumTracks can exclude them from future listings.
# Use the user-configured TTL (rights_cache_ttl, in hours).
my $norights_ttl = ($prefs->get('rights_cache_ttl') || 24) * 3600;
foreach my $track (@{ $result->{results}->{data} || [] }) {
if (!($track->{RIGHTS} && %{$track->{RIGHTS}}) && !$track->{FALLBACK}) {
$cache->set("deezer_track_norights_$track->{SNG_ID}", 1, $norights_ttl);
main::INFOLOG && $log->is_info && $log->info("Track $track->{SNG_ID} has no rights and no fallback, marked unplayable");
}
}


return $cb->() unless @trackTokens;

$self->_getProviders( $cb, $context->{license}, $params->{quality}, \@trackTokens, \@trackIds );
Expand Down
12 changes: 12 additions & 0 deletions HTML/EN/plugins/Deezer/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@
<input name="pref_unfold_collection" type="checkbox" [% IF prefs.pref_unfold_collection %] checked [% END %]>
[% END %]

[% WRAPPER setting title="PLUGIN_DEEZER_CHECK_RIGHTS" desc="PLUGIN_DEEZER_CHECK_RIGHTS_DESC" %]
<input name="pref_check_track_rights" type="checkbox" [% IF prefs.pref_check_track_rights %] checked [% END %]>
[% END %]

[% WRAPPER setting title="PLUGIN_DEEZER_RIGHTS_CACHE_TTL" desc="PLUGIN_DEEZER_RIGHTS_CACHE_TTL_DESC" %]
<select class="stdedit" name="pref_rights_cache_ttl">
[% FOREACH entry IN [['1h','1'],['6h','6'],['12h','12'],['24h','24'],['48h','48'],['7 Tage','168']] %]
<option [% IF entry.1 == prefs.pref_rights_cache_ttl %]selected[% END %] value="[% entry.1 %]">[% entry.0 %]</option>
[% END %]
</select>
[% END %]

[% WRAPPER setting title="PLUGIN_DEEZER_QUALITY" desc="PLUGIN_DEEZER_QUALITY_DESC" %]
<!-- <input list="rates" name="pref_quality" id="quality"> -->
<!-- <datalist id="rates"> -->
Expand Down
6 changes: 5 additions & 1 deletion Plugin.pm
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ sub initPlugin {
liveformat => 'mp3',
quality => 'HIGH',
serial => '29436f4b2c5b2b552e4c221b2d7c7a4e7a336c002d7278512e486f1f2c677d432b1c224e29522c0b280e7f42750f7b43794a271c7d652b06744c5454795f6c4e781f51197d742e077b5b344e7b0e694d7e4c271e2c1c7c032c4f794e786060062b4260432f306b40',
unfold_collection => 1,
unfold_collection => 1,
check_track_rights => 0,
rights_cache_ttl => 24,
});

# reset the API ref when a player changes user
Expand Down Expand Up @@ -513,6 +515,8 @@ sub getAlbum {

getAPIHandler($client)->albumTracks(sub {
my $items = _renderTracks(shift);
$items = [{ name => cstring($client, 'PLUGIN_DEEZER_NO_PLAYABLE_TRACKS'), type => 'textarea' }]
unless @$items;
$cb->( { items => $items } );
}, $params->{id} );
}
Expand Down
2 changes: 1 addition & 1 deletion Settings.pm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ sub name { Slim::Web::HTTP::CSRF->protectName('PLUGIN_DEEZER_NAME') }

sub page { Slim::Web::HTTP::CSRF->protectURI('plugins/Deezer/settings.html') }

sub prefs { return ($prefs, qw(quality liveformat liverate unfold_collection)) }
sub prefs { return ($prefs, qw(quality liveformat liverate unfold_collection check_track_rights rights_cache_ttl)) }

sub handler {
my ($class, $client, $params, $callback, @args) = @_;
Expand Down
20 changes: 20 additions & 0 deletions strings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -562,3 +562,23 @@ PLUGIN_DEEZER_UNFOLD_DESC
FR Configure le déroulement du menu de votre collection
HU Állítsa be a gyűjtemény menüjének összehajtási módját
UA Встановіть режим згортання меню вашої колекції

PLUGIN_DEEZER_CHECK_RIGHTS
DE Verfügbarkeit beim Öffnen eines Albums prüfen
EN Check track availability on album open

PLUGIN_DEEZER_CHECK_RIGHTS_DESC
DE Ruft beim Öffnen eines Albums die Streaming-Rechte von Deezer ab. Nicht abspielbare Tracks werden sofort ausgeblendet statt beim Abspielen zu scheitern. Beim ersten Öffnen entsteht eine kurze Verzögerung (~300ms).
EN Fetches streaming rights from Deezer for all tracks when an album is opened. Unplayable tracks are hidden immediately instead of failing at playback. Adds a short delay (~300ms) the first time each album is opened.

PLUGIN_DEEZER_RIGHTS_CACHE_TTL
DE Cache-Dauer für Verfügbarkeit
EN Availability cache duration

PLUGIN_DEEZER_RIGHTS_CACHE_TTL_DESC
DE Wie lange die Track-Verfügbarkeit gecacht wird. Nach Ablauf wird erneut geprüft.
EN How long track availability is cached. After expiry the check is repeated.

PLUGIN_DEEZER_NO_PLAYABLE_TRACKS
DE Keine abspielbaren Tracks verfügbar. Möglicherweise sind diese Titel in deiner Region oder mit deinem Abonnement nicht lizenziert.
EN No playable tracks available. These tracks may not be licensed for your region or subscription.