forked from yciabaud/triode-spotify
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProtocolHandlerSpotifyd.pm
More file actions
139 lines (87 loc) · 3.27 KB
/
ProtocolHandlerSpotifyd.pm
File metadata and controls
139 lines (87 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package Plugins::Spotify::ProtocolHandlerSpotifyd;
use strict;
use base qw(Slim::Formats::RemoteStream);
use IO::Socket qw(:crlf);
use Scalar::Util qw(blessed);
use Slim::Utils::Log;
use Slim::Utils::Prefs;
use Slim::Utils::Strings qw(string);
use constant PREFETCH_TIME => 30; # prefetch next track 30 secs before end of current track
my $id = 0; # unique id for track being played
my $prefetch; # timer for prefetch of next track
my $prefs = preferences('plugin.spotify');
my $log = logger('plugin.spotify');
sub bufferThreshold { 80 }
sub getMetadataFor {
my $class = shift;
Plugin::Spotify::ProtocolHandler->getMetadataFor(@_);
}
sub requestString {
my ($class, $client, $url, undef, $seekdata) = @_;
my $song = $client->streamingSong;
my $start = 0;
if (my $newtime = $seekdata->{'timeOffset'}) {
$start = int($newtime * 1000);
if ($song->startOffset != $newtime) {
$song->startOffset($newtime);
$client->master->remoteStreamStartTime(Time::HiRes::time() - $newtime);
}
} else {
# initiate prefetch of next track
$class->prefetchNext($client, $song->duration);
}
my $trackuri = $song->currentTrack->url;
$trackuri =~ s{^spotify://}{spotify:};
my $playerid = $client->id;
my $sync = $client->controller()->activePlayers();
my $format = $client->master()->streamformat();
my $sessId = $song->pluginData()->{'id'} || ++$id;
# increment id if we have already played this id on this client
# handles rew mid track and jumps in current track
my $cid = $client->id;
if (exists $song->pluginData()->{$cid} && $song->pluginData()->{$cid} == $sessId) {
$sessId = ++$id;
}
$song->pluginData()->{'id'} = $sessId;
$song->pluginData()->{$cid} = $sessId;
$playerid =~ s/:/%3A/g; # uri escape playerid
my $fmtstring = $format eq 'flc' ? 'stream.flc' : 'stream.pcm';
my $path = "$trackuri/$fmtstring?player=$playerid&start=$start&sync=$sync&id=$id";
$log->info("$path");
my $requestString = "GET $path SPOTSTREAM/1.0" . $CRLF;
if (preferences('server')->get('authorize')) {
$client->password(Slim::Player::Squeezebox::generate_random_string(20));
my $password = join '', map { sprintf("%02x", $_) } unpack("C*", $client->password);
$requestString .= "Authorization: $password" . $CRLF;
}
$requestString .= $CRLF;
return $requestString;
}
sub prefetchNext {
my ($class, $client, $duration) = @_;
return if Slim::Player::Sync::isSlave($client);
my $controller = $client->controller;
my $urlOrObj = Slim::Player::Playlist::song($client, $controller->nextsong);
my $uri = blessed($urlOrObj) ? $urlOrObj->url : $urlOrObj;
$uri =~ s{^spotify://}{spotify:};
if ($prefetch) {
Slim::Utils::Timers::killSpecific($prefetch);
}
if ($uri =~ /^spotify:track/) {
my $prefetchIn = $duration > PREFETCH_TIME ? $duration - PREFETCH_TIME : PREFETCH_TIME;
$log->info("scheduling prefetch of next track: $uri in $prefetchIn");
$prefetch = Slim::Utils::Timers::setTimer(__PACKAGE__, time() + $prefetchIn,
sub {
$log->info("prefetching: $uri");
Plugins::Spotify::Spotifyd->get("$uri/prefetch.json", sub {}, sub {});
$prefetch = undef;
}
);
}
}
sub parseDirectHeaders {
my ($class, $client, $url, @headers) = @_;
my $format = $client->master()->streamformat();
return (undef, undef, undef, undef, $format);
}
1;