2 * Copyright 2003-2018 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "QobuzInputPlugin.hxx"
22 #include "QobuzClient.hxx"
23 #include "QobuzTrackRequest.hxx"
24 #include "QobuzTagScanner.hxx"
25 #include "CurlInputPlugin.hxx"
26 #include "PluginUnavailable.hxx"
27 #include "input/ProxyInputStream.hxx"
28 #include "input/FailingInputStream.hxx"
29 #include "input/InputPlugin.hxx"
30 #include "config/Block.hxx"
31 #include "thread/Mutex.hxx"
32 #include "util/StringCompare.hxx"
39 static QobuzClient
*qobuz_client
;
41 class QobuzInputStream final
42 : public ProxyInputStream
, QobuzSessionHandler
, QobuzTrackHandler
{
44 const std::string track_id
;
46 std::unique_ptr
<QobuzTrackRequest
> track_request
;
48 std::exception_ptr error
;
51 QobuzInputStream(const char *_uri
, const char *_track_id
,
52 Mutex
&_mutex
, Cond
&_cond
) noexcept
53 :ProxyInputStream(_uri
, _mutex
, _cond
),
56 qobuz_client
->AddLoginHandler(*this);
60 qobuz_client
->RemoveLoginHandler(*this);
63 /* virtual methods from InputStream */
65 void Check() override
{
67 std::rethrow_exception(error
);
71 void Failed(std::exception_ptr e
) {
72 SetInput(std::make_unique
<FailingInputStream
>(GetURI(), e
,
76 /* virtual methods from QobuzSessionHandler */
77 void OnQobuzSession() noexcept override
;
79 /* virtual methods from QobuzTrackHandler */
80 void OnQobuzTrackSuccess(std::string url
) noexcept override
;
81 void OnQobuzTrackError(std::exception_ptr error
) noexcept override
;
85 QobuzInputStream::OnQobuzSession() noexcept
87 const std::lock_guard
<Mutex
> protect(mutex
);
90 const auto session
= qobuz_client
->GetSession();
92 QobuzTrackHandler
&handler
= *this;
93 track_request
= std::make_unique
<QobuzTrackRequest
>(*qobuz_client
,
97 track_request
->Start();
99 Failed(std::current_exception());
104 QobuzInputStream::OnQobuzTrackSuccess(std::string url
) noexcept
106 const std::lock_guard
<Mutex
> protect(mutex
);
107 track_request
.reset();
110 SetInput(OpenCurlInputStream(url
.c_str(), {},
113 Failed(std::current_exception());
118 QobuzInputStream::OnQobuzTrackError(std::exception_ptr e
) noexcept
120 const std::lock_guard
<Mutex
> protect(mutex
);
121 track_request
.reset();
127 InitQobuzInput(EventLoop
&event_loop
, const ConfigBlock
&block
)
129 const char *base_url
= block
.GetBlockValue("base_url",
130 "http://www.qobuz.com/api.json/0.2/");
132 const char *app_id
= block
.GetBlockValue("app_id");
133 if (app_id
== nullptr)
134 throw PluginUnavailable("No Qobuz app_id configured");
136 const char *app_secret
= block
.GetBlockValue("app_secret");
137 if (app_secret
== nullptr)
138 throw PluginUnavailable("No Qobuz app_secret configured");
140 const char *device_manufacturer_id
= block
.GetBlockValue("device_manufacturer_id",
141 "df691fdc-fa36-11e7-9718-635337d7df8f");
143 const char *username
= block
.GetBlockValue("username");
144 const char *email
= block
.GetBlockValue("email");
145 if (username
== nullptr && email
== nullptr)
146 throw PluginUnavailable("No Qobuz username configured");
148 const char *password
= block
.GetBlockValue("password");
149 if (password
== nullptr)
150 throw PluginUnavailable("No Qobuz password configured");
152 const char *format_id
= block
.GetBlockValue("format_id", "5");
154 qobuz_client
= new QobuzClient(event_loop
, base_url
,
156 device_manufacturer_id
,
157 username
, email
, password
,
169 ExtractQobuzTrackId(const char *uri
)
171 // TODO: what's the standard "qobuz://" URI syntax?
172 const char *track_id
= StringAfterPrefix(uri
, "qobuz://track/");
173 if (track_id
== nullptr)
182 static InputStreamPtr
183 OpenQobuzInput(const char *uri
, Mutex
&mutex
, Cond
&cond
)
185 assert(qobuz_client
!= nullptr);
187 const char *track_id
= ExtractQobuzTrackId(uri
);
188 if (track_id
== nullptr)
191 // TODO: validate track_id
193 return std::make_unique
<QobuzInputStream
>(uri
, track_id
, mutex
, cond
);
196 static std::unique_ptr
<RemoteTagScanner
>
197 ScanQobuzTags(const char *uri
, RemoteTagHandler
&handler
)
199 assert(qobuz_client
!= nullptr);
201 const char *track_id
= ExtractQobuzTrackId(uri
);
202 if (track_id
== nullptr)
205 return std::make_unique
<QobuzTagScanner
>(*qobuz_client
, track_id
,
209 const InputPlugin qobuz_input_plugin
= {