/src/libtomahawk/infosystem/infoplugins/generic/hypemPlugin.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 395 lines · 286 code · 81 blank · 28 comment · 38 complexity · 4e340216bf3e13bc3c06a79f2503a95c MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Hugo Lindstr??m <hugolm84@gmail.com>
  4. *
  5. * Tomahawk 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 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * Tomahawk 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.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "hypemPlugin.h"
  19. #include <QDir>
  20. #include <QSettings>
  21. #include <QCryptographicHash>
  22. #include <QNetworkConfiguration>
  23. #include <QNetworkReply>
  24. #include "album.h"
  25. #include "typedefs.h"
  26. #include "tomahawksettings.h"
  27. #include "utils/tomahawkutils.h"
  28. #include "utils/logger.h"
  29. #define HYPEM_URL "http://hypem.com/playlist/"
  30. #define HYPEM_END_URL "json/1/data.js"
  31. #include <qjson/parser.h>
  32. #include <qjson/serializer.h>
  33. using namespace Tomahawk::InfoSystem;
  34. hypemPlugin::hypemPlugin()
  35. : InfoPlugin()
  36. , m_chartsFetchJobs( 0 )
  37. {
  38. m_supportedGetTypes << InfoChart << InfoChartCapabilities;
  39. m_types << "Artists" << "Tracks" << "Recent by Tag";
  40. m_trackTypes << "Last 3 Days"
  41. << "Last Week"
  42. << "No Remixes"
  43. << "On Twitter";
  44. m_byTagTypes << "Dance"
  45. << "Experimental"
  46. << "Electronic"
  47. << "Funk"
  48. << "Hip-hop"
  49. << "Indie"
  50. << "Instrumental"
  51. << "Post-punk"
  52. << "Rock"
  53. << "Singer-songwriter"
  54. << "Alternative"
  55. << "Pop"
  56. << "Female"
  57. << "Vocalist"
  58. << "Folk"
  59. << "Electro"
  60. << "Lo-fi"
  61. << "Psychedelic"
  62. << "Rap"
  63. << "British"
  64. << "Ambient"
  65. << "Dubstep"
  66. << "House"
  67. << "Chillwave"
  68. << "Dreampop"
  69. << "Shoegaze"
  70. << "Chillout"
  71. << "Soul"
  72. << "French"
  73. << "Acoustic"
  74. << "Canadian"
  75. << "60s"
  76. << "80s"
  77. << "Techno"
  78. << "Punk"
  79. << "New wave";
  80. chartTypes();
  81. }
  82. hypemPlugin::~hypemPlugin()
  83. {
  84. qDebug() << Q_FUNC_INFO;
  85. }
  86. void
  87. hypemPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData )
  88. {
  89. emit info( requestData, QVariant() );
  90. return;
  91. }
  92. void
  93. hypemPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
  94. {
  95. qDebug() << Q_FUNC_INFO << requestData.caller;
  96. qDebug() << Q_FUNC_INFO << requestData.customData;
  97. InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
  98. switch ( requestData.type )
  99. {
  100. case InfoChart:
  101. if ( !hash.contains( "chart_source" ) || hash["chart_source"].toLower() != "hype machine" )
  102. {
  103. dataError( requestData );
  104. break;
  105. }
  106. qDebug() << Q_FUNC_INFO << "InfoCHart req for" << hash["chart_source"];
  107. fetchChart( requestData );
  108. break;
  109. case InfoChartCapabilities:
  110. fetchChartCapabilities( requestData );
  111. break;
  112. default:
  113. dataError( requestData );
  114. }
  115. }
  116. void
  117. hypemPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
  118. {
  119. if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
  120. {
  121. dataError( requestData );
  122. return;
  123. }
  124. InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
  125. Tomahawk::InfoSystem::InfoStringHash criteria;
  126. /// Each request needs to contain both a id and source
  127. if ( !hash.contains( "chart_id" ) && !hash.contains( "chart_source" ) )
  128. {
  129. dataError( requestData );
  130. return;
  131. }
  132. /// Set the criterias for current chart
  133. criteria["chart_id"] = hash["chart_id"];
  134. criteria["chart_source"] = hash["chart_source"];
  135. /// @todo
  136. /// set cache time based on wether requested type is 3day, lastweek or recent.
  137. emit getCachedInfo( criteria, 86400000, requestData );
  138. }
  139. void
  140. hypemPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData )
  141. {
  142. if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
  143. {
  144. dataError( requestData );
  145. return;
  146. }
  147. Tomahawk::InfoSystem::InfoStringHash criteria;
  148. emit getCachedInfo( criteria, 0, requestData );
  149. }
  150. void
  151. hypemPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
  152. {
  153. switch ( requestData.type )
  154. {
  155. case InfoChart:
  156. {
  157. /// Fetch the chart, we need source and id
  158. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart not in cache! Fetching...";
  159. QUrl url = QUrl( QString( HYPEM_URL "%1/%2" ).arg( criteria["chart_id"].toLower() ).arg(HYPEM_END_URL) );
  160. qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
  161. QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
  162. reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
  163. connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) );
  164. return;
  165. }
  166. case InfoChartCapabilities:
  167. {
  168. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching...";
  169. if ( m_chartsFetchJobs > 0 )
  170. {
  171. qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
  172. m_cachedRequests.append( requestData );
  173. return;
  174. }
  175. emit info( requestData, m_allChartsMap );
  176. return;
  177. }
  178. default:
  179. {
  180. tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss";
  181. emit info( requestData, QVariant() );
  182. return;
  183. }
  184. }
  185. }
  186. void
  187. hypemPlugin::chartTypes()
  188. {
  189. /// Get possible chart type for specifichypemPlugin: InfoChart types returned chart source
  190. tDebug() << Q_FUNC_INFO << "Got hypem types";
  191. QVariantMap charts;
  192. foreach(QVariant types, m_types )
  193. {
  194. QList< InfoStringHash > chart_types;
  195. QList< InfoStringHash > pop_charts;
  196. InfoStringHash c;
  197. if(types.toString() != "Artists")
  198. {
  199. if(types.toString() == "Tracks")
  200. {
  201. foreach(QVariant trackType, m_trackTypes)
  202. {
  203. QString typeId;
  204. if(trackType.toString() == "Last 3 Days")
  205. typeId = "popular/3day";
  206. if(trackType.toString() == "Last Week")
  207. typeId = "popular/lastweek";
  208. if(trackType.toString() == "No Remixes")
  209. typeId = "popular/noremix";
  210. if(trackType.toString() == "On Twitter")
  211. typeId = "popular/twitter";
  212. c[ "id" ] = typeId;
  213. c[ "label" ] = trackType.toString();
  214. c[ "type" ] = "tracks";
  215. pop_charts.append( c );
  216. }
  217. chart_types.append( pop_charts );
  218. }
  219. else if(types.toString() == "Recent by Tag")
  220. {
  221. foreach(QVariant tagTypes, m_byTagTypes)
  222. {
  223. c[ "id" ] = "tags/" + tagTypes.toString().toLower();
  224. c[ "label" ] = tagTypes.toString();
  225. c[ "type" ] = tagTypes.toString();
  226. chart_types.append( c );
  227. }
  228. }
  229. }else
  230. {
  231. InfoStringHash c;
  232. c[ "id" ] = "popular/artists";
  233. c[ "label" ] = "Most Recent";
  234. c[ "type" ] = "artists";
  235. chart_types.append( c );
  236. }
  237. charts.insert( types.toString(), QVariant::fromValue<QList< InfoStringHash > >( chart_types ) );
  238. }
  239. m_allChartsMap.insert( "Hype Machine", QVariant::fromValue<QVariantMap>( charts ) );
  240. qDebug() << "hypemPlugin:Chartstype: " << m_allChartsMap;
  241. }
  242. void
  243. hypemPlugin::chartReturned()
  244. {
  245. /// Chart request returned something! Woho
  246. QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
  247. QString url = reply->url().toString();
  248. QVariantMap returnedData;
  249. if ( reply->error() == QNetworkReply::NoError )
  250. {
  251. QJson::Parser p;
  252. bool ok;
  253. QVariantMap res = p.parse( reply, &ok ).toMap();
  254. if ( !ok )
  255. {
  256. tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine();
  257. return;
  258. }
  259. /// SO we have a result, parse it!
  260. QList< InfoStringHash > top_tracks;
  261. QStringList top_artists;
  262. if( url.contains( "artists" ) )
  263. setChartType( Artist );
  264. else
  265. setChartType( Track );
  266. foreach(QVariant result, res )
  267. {
  268. QString title, artist;
  269. QVariantMap chartMap = result.toMap();
  270. if ( !chartMap.isEmpty() )
  271. {
  272. title = chartMap.value( "title" ).toString();
  273. artist = chartMap.value( "artist" ).toString();
  274. if( chartType() == Track )
  275. {
  276. InfoStringHash pair;
  277. pair["artist"] = artist;
  278. pair["track"] = title;
  279. top_tracks << pair;
  280. qDebug() << "HypemChart type is track";
  281. }
  282. if( chartType() == Artist )
  283. {
  284. top_artists << artist;
  285. qDebug() << "HypemChart type is artist";
  286. }
  287. }
  288. }
  289. if( chartType() == Track )
  290. {
  291. tDebug() << "HypemPlugin:" << "\tgot " << top_tracks.size() << " tracks";
  292. returnedData["tracks"] = QVariant::fromValue( top_tracks );
  293. returnedData["type"] = "tracks";
  294. }
  295. if( chartType() == Artist )
  296. {
  297. tDebug() << "HypemPlugin:" << "\tgot " << top_artists.size() << " artists";
  298. returnedData["artists"] = top_artists;
  299. returnedData["type"] = "artists";
  300. }
  301. Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
  302. emit info( requestData, returnedData );
  303. // update cache
  304. Tomahawk::InfoSystem::InfoStringHash criteria;
  305. Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
  306. criteria[ "chart_id" ] = origData[ "chart_id" ];
  307. criteria[ "chart_source" ] = origData[ "chart_source" ];
  308. /// @todo
  309. /// set cache time based on wether requested type is 3day, lastweek or recent.
  310. emit updateCache( criteria, 86400000, requestData.type, returnedData );
  311. }
  312. else
  313. qDebug() << "Network error in fetching chart:" << reply->url().toString();
  314. }