1 /*
2 Copyright 2009 Last.fm Ltd.
3
4 This file is part of liblastfm.
5
6 liblastfm is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 liblastfm is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with liblastfm. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "RadioStation.h"
21 #include "XmlQuery.h"
22
23 #include <QDebug>
24 #include <QRegExp>
25 #include <QStringList>
26
27
28 const float k_defaultRep(0.5);
29 const float k_defaultMainstr(0.5);
30 const bool k_defaultDisco(false);
31
32 class lastfm::RadioStationData : public QSharedData
33 {
34 public:
35 QUrl m_url;
36 QString m_title;
37 QString m_tagFilter;
38
39 float m_rep;
40 float m_mainstr;
41 bool m_disco;
42 };
43
44
RadioStation()45 lastfm::RadioStation::RadioStation()
46 : d( new RadioStationData )
47 {
48 }
49
RadioStation(const QString & s)50 lastfm::RadioStation::RadioStation( const QString& s )
51 : d( new RadioStationData )
52 {
53 // If it's a tag filtered station then extract that part
54 QString tempString = s;
55
56 if ( !tempString.startsWith("lastfm://tag/") )
57 {
58 int index = tempString.indexOf("/tag/");
59
60 if ( index != -1 )
61 {
62 d->m_tagFilter = tempString.mid( index + 5, tempString.count() - (index + 5) );
63 tempString = tempString.mid( 0, index );
64 }
65 }
66
67 d->m_url = tempString;
68 }
69
RadioStation(const RadioStation & other)70 lastfm::RadioStation::RadioStation( const RadioStation& other )
71 : d(other.d)
72 {
73 }
74
75 lastfm::RadioStation&
operator =(const RadioStation & that)76 lastfm::RadioStation::operator=( const RadioStation& that )
77 {
78 d = that.d;
79 return *this;
80 }
81
~RadioStation()82 lastfm::RadioStation::~RadioStation()
83 {
84 }
85
86 lastfm::RadioStation
library(const lastfm::User & user)87 lastfm::RadioStation::library( const lastfm::User& user )
88 {
89 QList<lastfm::User> users;
90 users << user;
91 return library( users );
92 }
93
94 lastfm::RadioStation
library(QList<lastfm::User> & users)95 lastfm::RadioStation::library( QList<lastfm::User>& users )
96 {
97 qSort(users.begin(), users.end());
98
99 QString url = (users.count() > 1) ? "lastfm://users/" : "lastfm://user/";
100
101 url.append( users[0].name() );
102
103 for ( int i = 1 ; i < users.count() ; ++i )
104 url.append( "," + users[i].name() );
105
106 url.append("/personal");
107
108 RadioStation s( url );
109 if( users.count() != 1 )
110 {
111 QString title;
112
113 for( QList<lastfm::User>::const_iterator i = users.constBegin(); i != users.constEnd(); i++ )
114 {
115 if( i == users.constEnd() - 1 )
116 title += " and " + *i;
117 else
118 title += ", " + *i;
119 }
120
121 s.setTitle( title );
122 }
123
124 return s;
125 }
126
127
128 lastfm::RadioStation
recommendations(const lastfm::User & user)129 lastfm::RadioStation::recommendations( const lastfm::User& user )
130 {
131 return RadioStation( "lastfm://user/" + user + "/recommended" );
132 }
133
134 lastfm::RadioStation
friends(const lastfm::User & user)135 lastfm::RadioStation::friends( const lastfm::User& user )
136 {
137 return RadioStation( "lastfm://user/" + user + "/friends" );
138 }
139
140 lastfm::RadioStation
neighbourhood(const lastfm::User & user)141 lastfm::RadioStation::neighbourhood( const lastfm::User& user )
142 {
143 return RadioStation( "lastfm://user/" + user + "/neighbours" );
144 }
145
146
147 lastfm::RadioStation
tag(const lastfm::Tag & tag)148 lastfm::RadioStation::tag( const lastfm::Tag& tag )
149 {
150 QList<lastfm::Tag> tags;
151 tags << tag;
152 return lastfm::RadioStation::tag( tags );
153 }
154
155
156 lastfm::RadioStation
tag(QList<lastfm::Tag> & tag)157 lastfm::RadioStation::tag( QList<lastfm::Tag>& tag )
158 {
159 qSort(tag.begin(), tag.end());
160
161 QString url = (tag.count() > 1) ? "lastfm://tag/" : "lastfm://globaltags/";
162
163 url.append( tag[0].name() );
164
165 for ( int i = 1 ; i < tag.count() ; ++i )
166 url.append( "*" + tag[i].name() );
167
168 return RadioStation( url );
169 }
170
171
172 lastfm::RadioStation
similar(const lastfm::Artist & artist)173 lastfm::RadioStation::similar( const lastfm::Artist& artist )
174 {
175 QList<lastfm::Artist> artists;
176 artists << artist;
177 return similar( artists );
178 }
179
180
181 lastfm::RadioStation
similar(QList<lastfm::Artist> & artists)182 lastfm::RadioStation::similar( QList<lastfm::Artist>& artists )
183 {
184 qSort(artists.begin(), artists.end());
185
186 QString url = (artists.count() > 1) ? "lastfm://artistnames/" : "lastfm://artist/";
187
188 url.append( artists[0].name() );
189
190 for ( int i = 1 ; i < artists.count() ; ++i )
191 url.append( "," + artists[i].name() );
192
193 if (artists.count() == 1)
194 url.append( "/similarartists" );
195
196 return RadioStation( url );
197 }
198
199
200 lastfm::RadioStation
mix(const lastfm::User & user)201 lastfm::RadioStation::mix( const lastfm::User& user )
202 {
203 return RadioStation( "lastfm://user/" + user + "/mix" );
204 }
205
206
207 QString
url() const208 lastfm::RadioStation::url() const
209 {
210 return d->m_url.toString() + (d->m_tagFilter.isEmpty() ? "" : "/tag/" + d->m_tagFilter);
211 }
212
213
214 void
setTitle(const QString & title)215 lastfm::RadioStation::setTitle( const QString& title )
216 {
217 // Stop the radio station getting renamed when the web services don't know what it's called
218 if ( !d->m_title.isEmpty() && title.compare( "a radio station", Qt::CaseInsensitive ) == 0 )
219 return;
220
221 // do not rename the current user's stations if they already have a name
222 if ( !d->m_title.isEmpty() && d->m_url.toString().startsWith( "lastfm://user/" + User().name() ) )
223 return;
224
225 d->m_title = title.trimmed();
226 }
227
228 void
setUrl(const QString & url)229 lastfm::RadioStation::setUrl( const QString& url )
230 {
231 d->m_url = url;
232 }
233
234
235 QString
title() const236 lastfm::RadioStation::title() const
237 {
238 return d->m_title; // + (d->m_tagFilter.isEmpty() ? "" : ": " + d->m_tagFilter);
239 }
240
241
242 void
setTagFilter(const QString & tag)243 lastfm::RadioStation::setTagFilter( const QString& tag )
244 {
245 d->m_tagFilter = tag;
246 }
247
248
249 QNetworkReply*
getSampleArtists(int limit) const250 lastfm::RadioStation::getSampleArtists( int limit ) const
251 {
252 QMap<QString, QString> map;
253 map["method"] = "radio.getSampleArtists";
254 map["station"] = d->m_url.toString();
255 map["limit"] = QString::number( limit );
256 return ws::get( map );
257 }
258
259
260 QNetworkReply*
getTagSuggestions(int limit) const261 lastfm::RadioStation::getTagSuggestions( int limit ) const
262 {
263 QMap<QString, QString> map;
264 map["method"] = "radio.getTagSuggestions";
265 map["station"] = d->m_url.toString();
266 map["limit"] = QString::number( limit );
267 return ws::get( map );
268 }
269
270
271 bool
isLegacyPlaylist() const272 lastfm::RadioStation::isLegacyPlaylist() const
273 {
274 return d->m_url.toString().startsWith( "lastfm://play/" ) ||
275 d->m_url.toString().startsWith( "lastfm://preview/" ) ||
276 d->m_url.toString().startsWith( "lastfm://track/" ) ||
277 d->m_url.toString().startsWith( "lastfm://playlist/" );
278 }
279
280
281 //static
282 QList<lastfm::RadioStation>
list(QNetworkReply * r)283 lastfm::RadioStation::list( QNetworkReply* r )
284 {
285 QList<lastfm::RadioStation> result;
286 XmlQuery lfm;
287
288 if ( lfm.parse( r ) )
289 {
290
291 foreach (XmlQuery xq, lfm.children("station"))
292 {
293 lastfm::RadioStation rs( QUrl::fromPercentEncoding( xq["url"].text().toUtf8() ) );
294 rs.setTitle(xq["name"].text());
295 result.append(rs);
296 }
297 }
298 else
299 {
300 qWarning() << lfm.parseError().message();
301 }
302
303 return result;
304 }
305
306
307 bool
operator ==(const RadioStation & that) const308 lastfm::RadioStation::operator==( const RadioStation& that ) const
309 {
310 return this->d->m_url == that.d->m_url && this->d->m_tagFilter == that.d->m_tagFilter;
311 }
312
313
314 void
setRep(float rep)315 lastfm::RadioStation::setRep(float rep)
316 {
317 d->m_rep = rep;
318 }
319
320
321 void
setMainstr(float mainstr)322 lastfm::RadioStation::setMainstr(float mainstr)
323 {
324 d->m_mainstr = mainstr;
325 }
326
327
328 void
setDisco(bool disco)329 lastfm::RadioStation::setDisco(bool disco)
330 {
331 d->m_disco = disco;
332 }
333
334
rep() const335 float lastfm::RadioStation::rep() const
336 {
337 return d->m_rep;
338 }
339
340
mainstr() const341 float lastfm::RadioStation::mainstr() const
342 {
343 return d->m_mainstr;
344 }
345
346
disco() const347 bool lastfm::RadioStation::disco() const
348 {
349 return d->m_disco;
350 }
351
352
operator <<(QDebug d,const lastfm::RadioStation & station)353 QDebug operator<<( QDebug d, const lastfm::RadioStation& station )
354 {
355 return d << station.url();
356 }
357