PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/public_html/tj/gsapi.php

https://github.com/ibash/ThumbDJ
PHP | 1144 lines | 613 code | 131 blank | 400 comment | 135 complexity | a8a225619fd968dde6d0cade968ebe46 MD5 | raw file
  1. <?php
  2. /**
  3. * Grooveshark API Class
  4. * @author James Hartig
  5. * @copyright 2010
  6. * Released under GNU General Public License v3 (See LICENSE for license)
  7. */
  8. /*
  9. Recommended to be called like $gsapi = new gsapi(key,secret)
  10. YOU MUST SET THE KEY,SECRET EITHER BELOW OR LIKE ABOVE!
  11. Note: even if you are only using the static functions, calling $gsapi = new gsapi(key,secret) will set the key and secret for those as well
  12. */
  13. class gsapi{
  14. private static $api_host = "api.grooveshark.com/ws/2.1/"; //generally don't change this
  15. private static $pic_host = "http://beta.grooveshark.com/static/amazonart/m"; //generally don't change this
  16. private static $listen_host = "http://listen.grooveshark.com/"; //change this to preview.grooveshark.com if you are with VIP //this could potentially automatically be done...
  17. private static $ws_key = ""; //this is your api key
  18. private static $ws_secret = ""; //this is your api secret
  19. private $session;
  20. public $userid;
  21. /*
  22. * Construct gsapi
  23. Requirements: none
  24. Static Function
  25. */
  26. function gsapi($key=null,$secret=null){
  27. if (!empty($key))
  28. self::$ws_key = $key;
  29. if (!empty($secret))
  30. self::$ws_secret = $secret;
  31. if (empty(self::$ws_key) || empty(self::$ws_secret))
  32. trigger_error("gsapi class requires a valid key and secret.",E_USER_ERROR);
  33. }
  34. /*
  35. * Ping Grooveshark to make sure Pickles is sleeping
  36. Requirements: none
  37. Static Function
  38. */
  39. public static function pingService(){
  40. return self::apiCall('pingService',array());
  41. }
  42. /*
  43. * Retrieve a userid from Username
  44. * Also, serves the purpose of checking if a username exists. If this function returns false
  45. or 0 (can be checked with == 0) then the username is either invalid (false) or not found (0)
  46. Requirements: none
  47. Static Function
  48. */
  49. public static function getUserIDFromUsername($username){
  50. if (preg_match("/^([A-Za-z0-9]){1,16}$/",$username) === false){
  51. //we run the preg_match before calling the api because why waste the http call if the user already sent a bad username
  52. // you may notice we removed the error reporting
  53. return false;
  54. }
  55. $return = self::apiCall('getUserIDFromUsername',array('username'=>$username));
  56. if (isset($return['decoded']['result']['UserID']))
  57. return (int)$return['decoded']['result']['UserID'];
  58. else
  59. return false;
  60. }
  61. /*
  62. * Retrieve the profile URL for a Username
  63. * You can choose to provide the userID if you want to not call getUserIDFromUsername again
  64. Requirements: none
  65. Static Function
  66. */
  67. public static function getUserProfileUrlFromUsername($username,$userid=null){
  68. if ($userid == null && ($userid = self::getUserIDFromUsername($username)) == 0)
  69. return false;
  70. return sprintf("http://listen.grooveshark.com/#/user/%s/%u",strtolower($username),$userid);
  71. }
  72. /*
  73. * Retrieve the forum profile URL for a Username
  74. Requirements: none
  75. Static Function
  76. */
  77. public static function getUserForumProfileUrlFromUsername($username){
  78. return sprintf("http://forums.grooveshark.com/profile/%s/",strtolower($username));
  79. }
  80. /*
  81. * Start a new session
  82. Requirements: none
  83. Even though this function requires nothing, it is not static
  84. */
  85. public function startSession(){
  86. $return = self::apiCall('startSession',array());
  87. if (isset($return['decoded']['result']['success']) && $return['decoded']['result']['success'] === true){
  88. $this->session = $return['decoded']['result']['sessionID'];
  89. return $this->session;
  90. }else
  91. return false;
  92. }
  93. /*
  94. * Start a new session provided an existing session key
  95. Requirements: none
  96. Even though this function requires nothing, it is not static
  97. */
  98. public function setSession($sessionid){
  99. $this->session = $sessionid;
  100. return $sessionid;
  101. }
  102. /*
  103. * Returns the current SessionID
  104. * It is highly recommended to store this instead of username/token
  105. Requirements: session
  106. */
  107. public function getSession(){
  108. if (empty($this->session)){
  109. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  110. return false;
  111. }
  112. $return = self::apiCall('logout',array('sessionID'=>$this->session));
  113. if (isset($return['decoded']['result']['success']))
  114. return $return['decoded']['result']['success'];
  115. else
  116. return false;
  117. }
  118. /*
  119. * Ends the current session
  120. * Do this if you do not plan on using the user again
  121. Requirements: session
  122. */
  123. public function logout(){
  124. if (empty($this->session)){
  125. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  126. return false;
  127. }
  128. $return = self::apiCall('logout',array('sessionID'=>$this->session));
  129. if (isset($return['decoded']['result']['success']))
  130. return $return['decoded']['result']['success'];
  131. else
  132. return false;
  133. }
  134. /*
  135. * Authenticate the user and "login"
  136. * You MUST pass the token not the password, see getUserToken if you need to get the token
  137. Requirements: session
  138. */
  139. public function authenticateUser($username, $token){
  140. if (empty($this->session)){
  141. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  142. return false;
  143. }
  144. if (preg_match("/^([A-Za-z0-9]){3,20}$/",$username) === false){
  145. trigger_error(__FUNCTION__." requires a valid username. The username provided was invalid.",E_USER_ERROR);
  146. return false;
  147. }
  148. $return = self::apiCall('authenticateUser',array('username'=>$username,'token'=>$token,'sessionID'=>$this->session));
  149. if (isset($return['decoded']['result']['UserID']) && $return['decoded']['result']['UserID'] > 0)
  150. return $return['decoded']['result'];
  151. else
  152. return false;
  153. }
  154. /*
  155. * Get playlist info from the playlistID
  156. * All this function returns is the playlist name.
  157. Requirements: none
  158. Static function
  159. @param integer playlistID
  160. */
  161. public static function getPlaylistInfo($playlistID){
  162. if (!is_numeric($playlistID)){
  163. trigger_error(__FUNCTION__." requires a valid playlistID. The playlistID provided was invalid.",E_USER_ERROR);
  164. return false;
  165. }
  166. $return = self::apiCall('getPlaylistInfo',array('playlistID'=>$playlistID));
  167. if (isset($return['decoded']['result']))
  168. return $return['decoded']['result'];
  169. else
  170. return false;
  171. }
  172. /*
  173. * Get playlist URL from the playlistID
  174. Requirements: none
  175. Static function
  176. @param integer playlistID
  177. */
  178. public static function getPlaylistURL($playlistID){
  179. if (!is_numeric($playlistID)){
  180. trigger_error(__FUNCTION__." requires a valid playlistID. The playlistID provided was invalid.",E_USER_ERROR);
  181. return false;
  182. }
  183. $return = self::apiCall('getPlaylistURLFromPlaylistID',array('playlistID'=>$playlistID));
  184. if (isset($return['decoded']['result']))
  185. return $return['decoded']['result'];
  186. else
  187. return false;
  188. }
  189. /*
  190. * Retrieves information from the given album
  191. Requirements: none
  192. Static function
  193. @param integer artistID
  194. */
  195. public static function getArtistInfo($artistid){
  196. if (!is_numeric($artistid) || self::getDoesArtistExist($artistid) === false){
  197. trigger_error(__FUNCTION__." requires a valid artistID. The artistID provided was invalid.",E_USER_ERROR);
  198. return false;
  199. }
  200. $return = self::apiCall('getArtistInfo',array('artistID'=>$artistid));
  201. if (isset($return['decoded']['result']))
  202. return $return['decoded']['result'];
  203. else
  204. return false;
  205. }
  206. /*
  207. * Get playlist songs from the playlistID
  208. Return: array { [n]=> array(6) { ["SongID"]=> int ["SongName"]=> string ["ArtistID"]=> int ["ArtistName"]=> string ["AlbumName"]=> string ["Sort"]=> int) }
  209. TODO: Make sure Sort returns sorted
  210. Requirements: none
  211. Static function
  212. @param integer playlistID
  213. @param integer limit, optional
  214. */
  215. public static function getPlaylistSongs($playlistID,$limit=null){
  216. if (!is_numeric($playlistID)){
  217. trigger_error(__FUNCTION__." requires a valid playlistID. The playlistID provided was invalid.",E_USER_ERROR);
  218. return false;
  219. }
  220. $return = self::apiCall('getPlaylistSongs',array('playlistID'=>$playlistID,'limit'=>$limit));
  221. if (isset($return['decoded']['result']))
  222. return $return['decoded']['result'];
  223. else
  224. return false;
  225. }
  226. /*
  227. * Get songs on an album from the albumID
  228. Return: array { [n]=> array(6) { ["SongID"]=> int ["SongName"]=> string ["ArtistID"]=> int ["ArtistName"]=> string ["AlbumName"]=> string ["Sort"]=> int) }
  229. TODO: Make sure Sort returns sorted
  230. TODO: better checking of duplicates
  231. Requirements: none
  232. Static function
  233. @param integer albumID
  234. @param integer limit, optional
  235. @param bool unique, whether we should attempt to filter out duplicate songs by their titles
  236. */
  237. public static function getAlbumSongs($albumid,$limit=null,$unique=false){
  238. if (!is_numeric($albumid)){
  239. trigger_error(__FUNCTION__." requires a valid albumID. The albumID provided was invalid.",E_USER_ERROR);
  240. return false;
  241. }
  242. $return = self::apiCall('getAlbumSongs',array('albumID'=>$albumid,'limit'=>$limit));
  243. if (isset($return['decoded']['result'][0]) && count($return['decoded']['result'][0])>0 ){
  244. $songs = array();
  245. foreach($return['decoded']['result'][0] AS $k => &$song){
  246. if ($unique){
  247. if (!isset($songs[$song['SongName']]) || ($song['IsVerified']==1 && $songs[$song['SongName']][1]==0)){
  248. if (isset($songs[$song['SongName']]))
  249. unset($return['decoded']['result'][0][$songs[$song['SongName']][0]]); //remove old result
  250. if (!empty($song['CoverArtFilename']))
  251. $song['CoverArtLink'] = self::$pic_host.$song['CoverArtFilename']; //add filename with the actual url to the array
  252. $songs[$song['SongName']] = array($k,$song['IsVerified']);
  253. }else{
  254. unset($return['decoded']['result'][0][$k]);
  255. }
  256. }else{
  257. if (!empty($song['CoverArtFilename']))
  258. $song['CoverArtLink'] = self::$pic_host.$song['CoverArtFilename']; //add filename with the actual url to the array
  259. }
  260. }
  261. return $return['decoded']['result'][0];
  262. }else
  263. return false;
  264. }
  265. /*
  266. * Return the user token before doing authorize
  267. Requirements: none
  268. Static function
  269. */
  270. public static function getUserToken($username,$password){
  271. return md5($username.md5($password));
  272. }
  273. /*
  274. * Returns userInfo from SessionID.
  275. * Information returned: IsPremium, UserID, Username
  276. Requirements: session
  277. */
  278. public function getUserInfoFromSessionID(){
  279. if (empty($this->session)){
  280. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  281. return false;
  282. }
  283. $return = self::apiCall('getUserInfoFromSessionIDEx',array('sessionID'=>$this->session));
  284. //var_dump($return);
  285. if (isset($return['decoded']['result']['UserID']))
  286. return $return['decoded']['result'];
  287. else
  288. return false;
  289. }
  290. /*
  291. * Deprecated version of getUserPlaylistsEx
  292. Requirements: session
  293. @param integer limit, optional
  294. */
  295. public function getUserPlaylists($limit=null){
  296. if (empty($this->session)){
  297. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  298. return false;
  299. }
  300. $return = self::apiCall('getUserPlaylists',array('sessionID'=>$this->session,'limit'=>$limit));
  301. //var_dump($return);
  302. if (isset($return['decoded']['result']))
  303. return $return['decoded']['result'];
  304. else
  305. return false;
  306. }
  307. /*
  308. * Returns the playlists of the userID given.
  309. Requirements: none
  310. Static function
  311. @param integer userID
  312. @param integer limit, optional
  313. */
  314. public static function getUserPlaylistsByUserID($userid, $limit=null){
  315. if (!is_numeric($userid)){
  316. trigger_error(__FUNCTION__." requires a valid userID. The userID provided was invalid.",E_USER_ERROR);
  317. return false;
  318. }
  319. $return = self::apiCall('getUserPlaylistsByUserID',array('userID'=>$userid,'limit'=>$limit));
  320. //var_dump($return);
  321. if (isset($return['decoded']['result']['playlists']))
  322. return $return['decoded']['result']['playlists'];
  323. else
  324. return false;
  325. }
  326. /*
  327. * Adds a song to the logged-in user's favorites
  328. * appears to only return a success parameter
  329. Requirements: session
  330. @param integer songID
  331. */
  332. public function addUserFavoriteSong($song){
  333. if (empty($this->session)){
  334. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  335. return false;
  336. }
  337. if (!is_numeric($song) || self::getDoesSongExist($song) === false){
  338. trigger_error(__FUNCTION__." requires a songID. No valid songID was found.",E_USER_ERROR);
  339. return false;
  340. }
  341. $return = self::apiCall('addUserFavoriteSong',array('sessionID'=>$this->session,'songID'=>$song));
  342. if (isset($return['decoded']['result']['success']))
  343. return $return['decoded']['result'];
  344. else
  345. return false;
  346. }
  347. /*
  348. * Returns a songID from the Tinysong Base62
  349. Requirements: none
  350. Static Session
  351. @param string base62 from tinysong
  352. */
  353. public static function getSongIDFromTinysongBase62($base){
  354. if (preg_match("/^[A-Za-z0-9]$/",$base)){
  355. trigger_error(__FUNCTION__." requires a valid base62 song.",E_USER_ERROR);
  356. return false;
  357. }
  358. $return = self::apiCall('getSongIDFromTinysongBase62',array('base62'=>$base));
  359. if (isset($return['decoded']['result']['songID']))
  360. return $return['decoded']['result']['songID'];
  361. else
  362. return false;
  363. }
  364. /*
  365. * Returns a songURL from the Tinysong Base62
  366. Requirements: none
  367. Static Session
  368. @param string base62 from tinysong
  369. */
  370. public static function getSongURLFromTinysongBase62($base){
  371. if (preg_match("/^[A-Za-z0-9]$/",$base)){
  372. trigger_error(__FUNCTION__." requires a valid base62 song.",E_USER_ERROR);
  373. return false;
  374. }
  375. $return = self::apiCall('getSongURLFromTinysongBase62',array('base62'=>$base));
  376. if (isset($return['decoded']['result']['url']))
  377. return $return['decoded']['result']['url'];
  378. else
  379. return false;
  380. }
  381. /*
  382. * Returns any meta data about a song
  383. Requirements: none
  384. Static Session
  385. @param integer songID
  386. */
  387. public static function getSongInfo($song){
  388. if (!is_numeric($song) || self::getDoesSongExist($song) === false){
  389. trigger_error(__FUNCTION__." requires a songID. No valid songID was found.",E_USER_ERROR);
  390. return false;
  391. }
  392. $return = self::apiCall('getSongInfoEx',array('songID'=>$song));
  393. if (isset($return['decoded']['result']))
  394. return $return['decoded']['result'];
  395. else
  396. return false;
  397. }
  398. /*
  399. * Returns any meta data about an album
  400. Requirements: none
  401. Static Session
  402. @param integer albumID
  403. */
  404. public static function getAlbumInfo($album){
  405. if (!is_numeric($album) || self::getDoesAlbumExist($album) === false){
  406. trigger_error(__FUNCTION__." requires a albumID. No valid albumID was found.",E_USER_ERROR);
  407. return false;
  408. }
  409. $return = self::apiCall('getAlbumInfo',array('albumID'=>$song));
  410. if (isset($return['decoded']['result']))
  411. return $return['decoded']['result'];
  412. else
  413. return false;
  414. }
  415. /*
  416. * Returns a URL to the songID provided
  417. Requirements: none
  418. Static Session
  419. @param integer songID
  420. */
  421. public static function getSongURLFromSongID($song){
  422. if (!is_numeric($song) || self::getDoesSongExist($song) === false){
  423. trigger_error(__FUNCTION__." requires a songID. No valid songID was found.",E_USER_ERROR);
  424. return false;
  425. }
  426. $return = self::apiCall('getSongURLFromSongID',array('songID'=>$song));
  427. if (isset($return['decoded']['result']['url']))
  428. return $return['decoded']['result']['url'];
  429. else
  430. return false;
  431. }
  432. /*
  433. * Creates a playlist under the logged in user
  434. Requirements: session
  435. @param string playlistName (Unique)
  436. @param array songs, integer array of songIDs
  437. */
  438. public function createPlaylist($name,$songs){
  439. if (empty($this->session)){
  440. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  441. return false;
  442. }
  443. if (empty($name)){
  444. trigger_error(__FUNCTION__." requires a name. No valid playlist name was found.",E_USER_ERROR);
  445. return false;
  446. }
  447. if (!array($songs) || count($songs)<1){
  448. trigger_error(__FUNCTION__." requires songIDs. No songIDs were sent. Be sure to send an array of songIDs.",E_USER_ERROR);
  449. return false;
  450. }
  451. $return = self::apiCall('createPlaylist',array('sessionID'=>$this->session,'name'=>$name,'songIDs'=>self::formatSongIDs($songs)));
  452. //var_dump($return);
  453. if (isset($return['decoded']['result']))
  454. return $return['decoded']['result'];
  455. else
  456. return false;
  457. }
  458. /*
  459. * Adds a song to the tail-end of a playlist
  460. TODO: add support for adding multiple songs (will most likely require a new class to maintain compatibility)
  461. TODO: if the song exists already, we will remove it and append it to the end
  462. Requirements: session
  463. @param integer playlistID
  464. @param integer songID
  465. */
  466. public function addSongToPlaylist($playlist,$song){
  467. if (empty($this->session)){
  468. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  469. return false;
  470. }
  471. if (!is_numeric($playlist)){
  472. trigger_error(__FUNCTION__." requires a playlistID. No valid playlistID was found.",E_USER_ERROR);
  473. return false;
  474. }
  475. if (!is_numeric($song) || self::getDoesSongExist($song) === false){
  476. trigger_error(__FUNCTION__." requires a songID. No valid songID was found.",E_USER_ERROR);
  477. return false;
  478. }
  479. //first we need to retrieve playlist songs then we need to set playlist songs
  480. $songs = self::getPlaylistSongs($playlist);
  481. if (!is_array($songs))
  482. return false; //we couldn't process the songs, look for getPlaylistSongs to return error
  483. $songs[] = $song;
  484. return $this->setPlaylistSongs($playlist,$songs);
  485. }
  486. /*
  487. * Changes the Playlist songs
  488. Requirements: session
  489. @param integer playlistID
  490. @param array songs, integer array of songIDs
  491. */
  492. public function setPlaylistSongs($playlist,$songs){
  493. if (empty($this->session)){
  494. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  495. return false;
  496. }
  497. if (!is_numeric($playlist)){
  498. trigger_error(__FUNCTION__." requires a name. No valid playlist name was found.",E_USER_ERROR);
  499. return false;
  500. }
  501. if (!array($songs) || count($songs)<1){
  502. trigger_error(__FUNCTION__." requires songIDs. No songIDs were sent. Be sure to send an array of songIDs.",E_USER_ERROR);
  503. return false;
  504. }
  505. $return = self::apiCall('setPlaylistSongs',array('sessionID'=>$this->session,'playlistID'=>$playlist,'songIDs'=>self::formatSongIDs($songs)));
  506. //var_dump($return);
  507. if (isset($return['decoded']['result']))
  508. return $return['decoded']['result'];
  509. else
  510. return false;
  511. }
  512. /*
  513. * Returns whether a song exists or not.
  514. * This is commonly used internally by this class
  515. Requirements: none
  516. static function
  517. @param integer songID
  518. */
  519. public static function getDoesSongExist($song){
  520. if (!is_numeric($song))
  521. return false;
  522. //since this method is commonly used to test a songID, we don't return an error if it is incorrect, just false
  523. $return = self::apiCall('getDoesSongExist',array('songID'=>$song));
  524. if (isset($return['decoded']['result'][0]))
  525. return (boolean)$return['decoded']['result'][0];
  526. else
  527. return false;
  528. }
  529. /*
  530. * Returns whether an artist exists or not.
  531. Requirements: none
  532. static function
  533. @param integer artistID
  534. */
  535. public static function getDoesArtistExist($artist){
  536. if (!is_numeric($artist))
  537. return false;
  538. //since this method is commonly used to test a artistID, we don't return an error if it is incorrect, just false
  539. $return = self::apiCall('getDoesArtistExist',array('artistID'=>$artist));
  540. if (isset($return['decoded']['result'][0]))
  541. return (boolean)$return['decoded']['result'][0];
  542. else
  543. return false;
  544. }
  545. /*
  546. * Returns whether an album exists or not.
  547. Requirements: none
  548. static function
  549. @param integer albumID
  550. */
  551. public static function getDoesAlbumExist($album){
  552. if (!is_numeric($album))
  553. return false;
  554. //since this method is commonly used to test a albumID, we don't return an error if it is incorrect, just false
  555. $return = self::apiCall('getDoesAlbumExist',array('albumID'=>$album));
  556. if (isset($return['decoded']['result'][0]))
  557. return (boolean)$return['decoded']['result'][0];
  558. else
  559. return false;
  560. }
  561. /*
  562. * Returns a list of an artist's albums
  563. Requirements: none
  564. static function
  565. Returns an array with pager subarray and songs subarray
  566. */
  567. public static function getArtistAlbums($artist,$verified=false){
  568. if (!is_numeric($artist)){
  569. rigger_error(__FUNCTION__." requires artistID. No artistID was sent.",E_USER_ERROR);
  570. return false;
  571. }
  572. if ($verified)
  573. $return = self::apiCall('getArtistVerifiedAlbums',array('artistID'=>$artist));
  574. else
  575. $return = self::apiCall('getArtistAlbums',array('artistID'=>$artist));
  576. if (isset($return['decoded']['result'][0]['albums']))
  577. return $return['decoded']['result'][0];
  578. else
  579. return false;
  580. }
  581. /*
  582. Alias class for getArtistAlbums with verified true
  583. */
  584. public static function getArtistVerifiedAlbums($artist){
  585. return self::getArtistAlbums($artist,true);
  586. }
  587. /*
  588. * Returns the top 100 songs for an artist
  589. Requirements: none
  590. Static function
  591. */
  592. public static function getArtistPopularSongs($artist){
  593. if (!is_numeric($artist)){
  594. rigger_error(__FUNCTION__." requires artistID. No artistID was sent.",E_USER_ERROR);
  595. return false;
  596. }
  597. $return = self::apiCall('getArtistPopularSongs',array('artistID'=>$artist));
  598. if (isset($return['decoded']['result'][0]['songs']))
  599. return $return['decoded']['result'][0]['songs'];
  600. else
  601. return false;
  602. }
  603. /*
  604. * A list of Popular Songs from Today
  605. Requirements: none
  606. Static function
  607. */
  608. public static function getPopularSongsToday($limit=null){
  609. $return = self::apiCall('getPopularSongsToday',array('limit'=>$limit));
  610. if (isset($return['decoded']['result']['songs']))
  611. return $return['decoded']['result']['songs'];
  612. else
  613. return false;
  614. }
  615. /*
  616. * Returns a list of favorites from the user.
  617. TODO: Sort by newest at the top.
  618. Requirements: session
  619. */
  620. public function getUserFavoriteSongs($limit=null){
  621. if (empty($this->session)){
  622. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  623. return false;
  624. }
  625. $return = self::apiCall('getUserFavoriteSongs',array('sessionID'=>$this->session,'limit'=>$limit));
  626. //var_dump($return);
  627. if (isset($return['decoded']['result']['songs']))
  628. return $return['decoded']['result']['songs'];
  629. else
  630. return false;
  631. }
  632. /*
  633. * Returns more detailed information about the current user
  634. * This requires higher level access and is generally unavaliable.
  635. Requirements: session, extended access
  636. */
  637. public function getExtendedUserInfoFromSessionID(){
  638. if (empty($this->session)){
  639. trigger_error(__FUNCTION__." requires a valid session. No session was found.",E_USER_ERROR);
  640. return false;
  641. }
  642. $return = self::apiCall('getExtendedUserInfoFromSessionID',array('sessionID'=>$this->session));
  643. /* this method has not yet been tested for the result set */
  644. if (isset($return['decoded']['result']))
  645. return $return['decoded']['result'];
  646. else
  647. return false;
  648. }
  649. /*
  650. * Returns the Country from the IP Address it was requested from
  651. Requirements: session, extended access
  652. */
  653. public static function getCountry(){
  654. $return = self::apiCall('getCountry',array());
  655. /* this method has not yet been tested for the result set */
  656. if (isset($return['decoded']['result']))
  657. return $return['decoded']['result'];
  658. else
  659. return false;
  660. }
  661. /*
  662. * Returns the file URL from songID
  663. * Requires the country object
  664. Requirements: session, extended access, getCountry access
  665. */
  666. public static function getFileURLFromSongID($song){
  667. if (!is_numeric($song) || self::getDoesSongExist($song) === false){
  668. trigger_error(__FUNCTION__." requires a songID. No valid songID was found.",E_USER_ERROR);
  669. return false;
  670. }
  671. $country = self::getCountry(); //we need to test this for the output
  672. $return = self::apiCall('getFileURLFromSongID',array('songID'=>$song,'country'=>$country));
  673. /* this method has not yet been tested for the result set */
  674. if (isset($return['decoded']['result']['url']))
  675. return $return['decoded']['result']['url'];
  676. else
  677. return false;
  678. }
  679. /*
  680. * Get search results for a song
  681. * This method is access controlled.
  682. Requirements: extended access
  683. Static Method
  684. Returns an array with pager subarray and songs subarray
  685. */
  686. public static function getSongSearchResults($query,$limit=null,$page=null){
  687. if (empty($query)){
  688. trigger_error(__FUNCTION__." requires a query. No query was found.",E_USER_ERROR);
  689. return false;
  690. }
  691. $return = self::apiCall('getSongSearchResults',array('query'=>$query,'limit'=>$limit,'page'=>$page));
  692. if (isset($return['decoded']['result'][0]['songs']))
  693. return $return['decoded']['result'][0];
  694. else
  695. return false;
  696. }
  697. /*
  698. * Get search results for an artist name
  699. * This method is access controlled.
  700. Requirements: extended access
  701. Static Method
  702. Returns an array with pager subarray and songs subarray
  703. */
  704. public static function getArtistSearchResults($query,$limit=null,$page=null){
  705. if (empty($query)){
  706. trigger_error(__FUNCTION__." requires a query. No query was found.",E_USER_ERROR);
  707. return false;
  708. }
  709. $return = self::apiCall('getArtistSearchResults',array('query'=>$query,'limit'=>$limit,'page'=>$page));
  710. if (isset($return['decoded']['result']['artists'])){
  711. foreach($return['decoded']['result']['artists'] AS &$artst)
  712. $artst['GroovesharkLink'] = self::$listen_host."#/artist/".preg_replace("/[^\w]+/","+",$artst['ArtistName'])."/".$artst['ArtistID'];
  713. return $return['decoded']['result'];
  714. }else
  715. return false;
  716. }
  717. /*
  718. * Get search results for an album name
  719. * This method is access controlled.
  720. Requirements: extended access
  721. Static Method
  722. Returns an array with pager subarray and songs subarray
  723. */
  724. public static function getAlbumSearchResults($query,$limit=null,$page=null){
  725. if (empty($query)){
  726. trigger_error(__FUNCTION__." requires a query. No query was found.",E_USER_ERROR);
  727. return false;
  728. }
  729. $return = self::apiCall('getAlbumSearchResults',array('query'=>$query,'limit'=>$limit,'page'=>$page));
  730. if (isset($return['decoded']['result']['albums'])){
  731. foreach($return['decoded']['result']['albums'] AS &$albm){
  732. if (!empty($albm['CoverArtFilename']))
  733. $albm['CoverArtLink'] = self::$pic_host.$albm['CoverArtFilename']; //add filename with the actual url to the array
  734. $albm['GroovesharkLink'] = self::$listen_host."#/album/".preg_replace("/[^\w]+/","+",$albm['AlbumName'])."/".$albm['AlbumID'];
  735. }
  736. return $return['decoded']['result'];
  737. }else
  738. return false;
  739. }
  740. /*
  741. * Get search results for an album name
  742. * This method is access controlled.
  743. * This method is version 2 and contains an additional parameter for the songs.
  744. Requirements: extended access
  745. Static Method
  746. Returns an array with pager subarray and songs subarray
  747. */
  748. public static function getAlbumSearchResults2($query,$limit=null,$page=null){
  749. if (empty($query)){
  750. trigger_error(__FUNCTION__." requires a query. No query was found.",E_USER_ERROR);
  751. return false;
  752. }
  753. $return = self::apiCall('getAlbumSearchResults',array('query'=>$query,'limit'=>$limit,'page'=>$page));
  754. if (isset($return['decoded']['result']['albums'])){
  755. foreach($return['decoded']['result']['albums'] AS &$albm){
  756. if (!empty($albm['CoverArtFilename']))
  757. $albm['CoverArtLink'] = self::$pic_host.$albm['CoverArtFilename']; //add filename with the actual url to the array
  758. $albm['GroovesharkLink'] = self::$listen_host."#/album/".preg_replace("/[^\w]+/","+",$albm['AlbumName'])."/".$albm['AlbumID'];
  759. $albm['Songs'] = self::getAlbumSongs($albm['AlbumID']);
  760. $albm['SongCount'] = count($albm['Songs']);
  761. }
  762. return $return['decoded']['result'];
  763. }else
  764. return false;
  765. }
  766. /*
  767. Basically login is just an alias class for authenticateUser
  768. */
  769. public function login($username, $password){
  770. return $this->authenticateUser($username,$password);
  771. }
  772. /*
  773. Another alias class for logout
  774. */
  775. public function endSession(){
  776. return $this->logout();
  777. }
  778. /*
  779. * Private call to grooveshark API, this is where the magic happens!
  780. */
  781. private static function apiCall($method,$args=array(),$https=false){
  782. $args['sig'] = self::createMessageSig($method, $args, self::$ws_secret);
  783. $args['wsKey'] = self::$ws_key;
  784. $args['method'] = $method;
  785. $args['format'] = 'json';
  786. $query_str = "";
  787. //yes we could use http_build_query but it is PHP5 only, plus where's the fun in that?
  788. foreach ($args as $k => $v){
  789. if ($v !== null){
  790. if (is_array($v)){
  791. foreach($v AS $k2 => $v2)
  792. $query_str .= "&".urlencode($k).'['.$k2.']'.'='.urlencode($v2);
  793. }else
  794. $query_str .= "&".urlencode($k)."=".urlencode($v);
  795. }
  796. }
  797. unset($args, $k, $v);
  798. $query_str = "?".substr($query_str,1); //remove beginning & and replace with a ?
  799. $url = sprintf('%s://%s',($https === true ? "https" : "http"),self::$api_host.$query_str);
  800. $c = curl_init();
  801. curl_setopt($c, CURLOPT_URL, $url);
  802. curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
  803. curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 4);
  804. curl_setopt($c, CURLOPT_TIMEOUT, 10);
  805. curl_setopt($c, CURLOPT_USERAGENT, 'fastest963-GSAPI-PHP');
  806. $result = curl_exec($c);
  807. $httpCode = curl_getinfo($c, CURLINFO_HTTP_CODE);
  808. curl_close($c);
  809. $decoded = json_decode($result, true);
  810. return array('http'=>$httpCode,'raw'=>$result,'decoded'=>$decoded);
  811. }
  812. /*
  813. * Creates the message signature before sending to Grooveshark
  814. */
  815. private static function createMessageSig($method, $params, $secret){
  816. ksort($params);
  817. $data = '';
  818. foreach ($params as $key => $value){
  819. if ($value !== null){
  820. if (is_array($value)){
  821. $data .= $key;
  822. foreach ($value as $k => $v)
  823. $data .= $k.$v;
  824. }else
  825. $data .= $key.$value;
  826. }
  827. }
  828. return hash_hmac('md5', $method.$data, $secret);
  829. }
  830. /*
  831. * Formats the songIDs for use with setPlaylistSongs and other functions.
  832. * Has been altered to strip everything but the SongID
  833. */
  834. private static function formatSongIDs($songs){
  835. $final = array();
  836. foreach($songs AS $sng){
  837. if (is_array($sng)){
  838. if (isset($sng['SongID']))
  839. $final[] = $sng['SongID'];
  840. else {
  841. foreach($sng AS $k => $v){ //check for if case is not SongID
  842. if (strtolower($k) == 'songid'){
  843. $final[] = $v;
  844. break;
  845. }
  846. }
  847. }
  848. }else
  849. $final[] = $sng;
  850. }
  851. return $final; //be SURE TO put this under the arg songIDs
  852. }
  853. /*
  854. * Uses the tinysong API to return the details of a song.
  855. * Parameters: the query (the title plus usually the artist)
  856. TODO: deprecate this function with preference to tinysongApiSongDetailsAdv
  857. */
  858. public static function tinysongApiSongDetails($query){
  859. if (empty($query))
  860. return false;
  861. $http = self::httpCall('http://tinysong.com/b/'.urlencode($query));
  862. if ($http['raw'] == "NSF;")
  863. return false;
  864. $details = explode("; ",$http['raw']);
  865. return array("TinyLink"=>$details[0],"SongID"=>$details[1],"SongName"=>$details[2],"ArtistID"=>$details[3],"ArtistName"=>$details[4],"AlbumID"=>$details[5],"AlbumName"=>$details[6],"LongLink"=>$details[7],"GroovesharkLink"=>$details[7],"Link"=>$details[0]);
  866. }
  867. /*
  868. * Uses the tinysong API to return the details of a song.
  869. * Title is required, artist is optional as well as album
  870. TODO: add support for mb_strtolower
  871. */
  872. public static function tinysongApiSongDetailsAdv($title,$artist="",$album=""){
  873. if (empty($title))
  874. return false;
  875. //build request
  876. $query_str = "title%3A".urlencode($title);
  877. if (!empty($artist))
  878. $query_str .= " artist%3A".urlencode($artist);
  879. if (!empty($album))
  880. $query_str .= " album%3A".urlencode($album);
  881. $http = self::httpCall('http://tinysong.com/s/'.$query_str.'?limit=32');
  882. if ($http['raw'] == "NSF;")
  883. return false;
  884. $title = strtolower($title);
  885. $artist = strtolower($artist);
  886. $album = strtolower($album);
  887. $songs = explode("\n",$http['raw']);
  888. foreach($songs AS $song){
  889. $details = explode("; ",$http['raw']);
  890. $passed = false;
  891. if (strtolower($details[2]) == $title){
  892. if (empty($album) && empty($artist)){
  893. $passed = true;
  894. }elseif(!empty($artist) && $artist == strtolower($details[4])){
  895. if (empty($album) || $album == strtolower($details[6]))
  896. $passed = true;
  897. }elseif(!empty($album) && $album == strtolower($details[6])){
  898. $passed = true;
  899. }
  900. }
  901. if ($passed)
  902. return array("TinyLink"=>$details[0],"SongID"=>$details[1],"SongName"=>$details[2],"ArtistID"=>$details[3],"ArtistName"=>$details[4],"AlbumID"=>$details[5],"AlbumName"=>$details[6],"LongLink"=>$details[7],"GroovesharkLink"=>$details[7],"Link"=>$details[0]);
  903. }
  904. return array(); //we found nothing
  905. //TODO: fix this and make it return the closest match
  906. }
  907. /*
  908. * Instead of modifying the apiCall function we are using this little function to process TinySong queries
  909. */
  910. protected static function httpCall($url,$ua='fastest963-GSAPI-PHP'){
  911. if (empty($url))
  912. return false;
  913. $c = curl_init();
  914. curl_setopt($c, CURLOPT_URL, $url);
  915. curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
  916. curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 4);
  917. curl_setopt($c, CURLOPT_TIMEOUT, 10);
  918. curl_setopt($c, CURLOPT_USERAGENT, $ua);
  919. $result = curl_exec($c);
  920. $code = curl_getinfo($c, CURLINFO_HTTP_CODE);
  921. $size = curl_getinfo($c, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
  922. $type = curl_getinfo($c, CURLINFO_CONTENT_TYPE);
  923. curl_close($c);
  924. return array('http'=>$code,'raw'=>$result,'size'=>$size,'type'=>$type);
  925. }
  926. }
  927. /*class gsSearchResults{
  928. private $numPages;
  929. private $hasPrevPage;
  930. private $hasNextPage;
  931. }*/
  932. ?>