Album.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <?php
  2. /* GNU FM -- a free network service for sharing your music listening habits
  3. Copyright (C) 2009 Free Software Foundation, Inc
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Affero General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. require_once($install_path . '/database.php');
  16. require_once($install_path . '/data/Artist.php');
  17. require_once($install_path . '/data/Track.php');
  18. require_once($install_path . '/data/Tag.php');
  19. require_once($install_path . '/utils/resolve-external.php');
  20. require_once($install_path . '/utils/linkeddata.php');
  21. /**
  22. * Represents album data
  23. *
  24. * General album attributes are accessible as public variables.
  25. * Lists of tracks are only generated when requested.
  26. */
  27. class Album {
  28. public $name, $artist_name, $mbid, $releasedate, $image;
  29. public $id;
  30. /**
  31. * Album constructor
  32. *
  33. * @param string name The name of the album to load
  34. * @param string artist The name of the artist who recorded this album
  35. */
  36. function __construct($name, $artist) {
  37. global $adodb;
  38. $adodb->SetFetchMode(ADODB_FETCH_ASSOC);
  39. $this->query = 'SELECT name, artist_name, mbid, image, releasedate FROM Album WHERE '
  40. . 'lower(name) = lower(' . $adodb->qstr($name) . ') AND '
  41. . 'lower(artist_name) = lower(' . $adodb->qstr($artist) . ')';
  42. $r = $adodb->CacheGetRow(1200, $this->query);
  43. if (!$r) {
  44. throw new Exception('No such album: ' . $name);
  45. } else {
  46. $row = sanitize($r);
  47. $this->name = $row['name'];
  48. $this->mbid = $row['mbid'];
  49. $this->artist_name = $row['artist_name'];
  50. $this->releasedate = $row['releasedate'];
  51. $this->image = resolve_external_url($row['image']);
  52. $this->id = identifierAlbum(null, $this->artist_name, null, $this->name, null, null, null, $this->mbid);
  53. $this->track_query = 'SELECT name, artist_name FROM Track WHERE artist_name = '
  54. . $adodb->qstr($this->artist_name) . ' AND album_name = '
  55. . $adodb->qstr($this->name);
  56. if ($this->image == '') {
  57. $this->image = false;
  58. }
  59. }
  60. }
  61. /**
  62. * Create a new Album
  63. *
  64. * @param string $name The name of the album
  65. * @param string $artist_name The name of the artist who recorded this album
  66. * @param string $image The URL to this album's cover image (optional)
  67. * @return Album Album object corresponding to the newly created album
  68. */
  69. public static function create($name, $artist_name, $image = '') {
  70. global $adodb;
  71. $adodb->Execute('INSERT INTO Album (name, artist_name, image) VALUES ('
  72. . $adodb->qstr($name) . ', '
  73. . $adodb->qstr($artist_name) . ', '
  74. . $adodb->qstr($image) . ')');
  75. try {
  76. $artist = new Artist($artist_name);
  77. $artist->clearAlbumCache();
  78. } catch (Exception $e) {
  79. // No such artist.
  80. }
  81. return new Album($name, $artist_name);
  82. }
  83. /**
  84. * Clears the track cache
  85. */
  86. function clearTrackCache() {
  87. global $adodb;
  88. $adodb->CacheFlush($this->track_query);
  89. }
  90. /**
  91. * Clear the cache of the album information
  92. */
  93. function clearCache() {
  94. global $adodb;
  95. $adodb->CacheFlush($this->query);
  96. }
  97. /**
  98. * Retrieves total play count for all tracks on this album
  99. *
  100. * @return int Number of plays
  101. */
  102. function getPlayCount() {
  103. global $adodb;
  104. $adodb->SetFetchMode(ADODB_FETCH_ASSOC);
  105. try {
  106. $count = $adodb->CacheGetOne(600,
  107. 'SELECT COUNT(*) AS scrobbles FROM Scrobbles JOIN Track ON Scrobbles.track = Track.name WHERE Scrobbles.artist = '
  108. . $adodb->qstr($this->artist_name) . ' AND Track.album_name ='
  109. . $adodb->qstr($this->name));
  110. } catch (Exception $e) {
  111. reportError($res->getMessage());
  112. $c = 0;
  113. }
  114. if (!$count) {
  115. $c = 0;
  116. } else {
  117. $c = $count;
  118. }
  119. return $c;
  120. }
  121. /**
  122. * Retrieves all the tracks in an album
  123. *
  124. * @return array Track objects
  125. */
  126. function getTracks() {
  127. global $adodb;
  128. $adodb->SetFetchMode(ADODB_FETCH_ASSOC);
  129. $res = $adodb->CacheGetAll(600, $this->track_query);
  130. foreach ($res as &$row) {
  131. $tracks[] = new Track($row['name'], $row['artist_name']);
  132. }
  133. return $tracks;
  134. }
  135. /**
  136. * Gives the URL for this album
  137. *
  138. * @return string The URL of this album
  139. */
  140. function getURL() {
  141. return Server::getAlbumURL($this->artist_name, $this->name);
  142. }
  143. /**
  144. * Gives the URL for managers to add a new track to this album
  145. *
  146. * @return string The URL for adding tracks to this album
  147. */
  148. function getAddTrackURL() {
  149. return Server::getAddTrackURL($this->artist_name, $this->name);
  150. }
  151. /**
  152. * Get the top tags for this album, ordered by tag count
  153. *
  154. * @param int $limit The number of tags to return (default is 10)
  155. * @param int $offset The position of the first tag to return (default is 0)
  156. * @param int $cache Caching period of query in seconds (default is 600)
  157. * @return array Tag details ((tag, freq) .. )
  158. */
  159. function getTopTags($limit=10, $offset=0, $cache=600) {
  160. return Tag::_getTagData($cache, $limit, $offset, null, $this->artist_name, $this->name);
  161. }
  162. /**
  163. * Get a specific user's tags for this album.
  164. *
  165. * @param int $userid Get tags for this user
  166. * @param int $limit The number of tags to return (default is 10)
  167. * @param int $offset The position of the first tag to return (default is 0)
  168. * @param int $cache Caching period of query in seconds (default is 600)
  169. * @return array Tag details ((tag, freq) .. )
  170. */
  171. function getTags($userid, $limit=10, $offset=0, $cache=600) {
  172. if(isset($userid)) {
  173. return Tag::_getTagData($cache, $limit, $offset, $userid, $this->artist_name, $this->name);
  174. }
  175. }
  176. /**
  177. * Set the cover art for this artist.
  178. *
  179. * @param string $image The URL of the image to use.
  180. */
  181. function setImage($image) {
  182. global $adodb;
  183. $adodb->Execute('UPDATE Album SET image=' . $adodb->qstr($image)
  184. . ' WHERE artist_name = ' . $adodb->qstr($this->artist_name)
  185. . ' AND name = ' . $adodb->qstr($this->name));
  186. $this->clearCache();
  187. }
  188. function getEditURL() {
  189. return Server::getAlbumEditURL($this->artist_name, $this->name);
  190. }
  191. /**
  192. * Return Album Art URL from Wikipedia
  193. *
  194. * @deprecated mb_convert_case fails and wikipedia returns 403. 20120307 kabniel
  195. *
  196. * @param string $album_name Album name
  197. * @param string $artist_name Artist name
  198. * @param bool $save Save info to Album table.
  199. * @param string $api_url Wikipedia API URL
  200. * @return array An object with the url and usage_url properties
  201. */
  202. function WikipediaAlbumArt ($album_name, $artist_name, $save = false, $api_url = 'http://en.wikipedia.org/w/api.php') {
  203. global $adodb;
  204. /*
  205. * Search query string
  206. */
  207. $album_name = mb_convert_case($album_name, 'UTF-8');
  208. $artist_name = mb_convert_case($artist_name, 'UTF-8');
  209. $get_params = array(
  210. 'action' => 'query',
  211. 'format' => 'php',
  212. 'redirects' => true,
  213. 'list' => 'search',
  214. 'srsearch' => "$album_name $artist_name album",
  215. 'srlimit' => 10
  216. );
  217. try {
  218. if (is_null($album_name)) {
  219. throw new Exception('No album name provided.');
  220. }
  221. $search_url = $api_url . '?' . http_build_query($get_params);
  222. $open = fopen($search_url, 'r');
  223. if ($open == false) {
  224. throw new Exception('Can\'t open Search URL');
  225. }
  226. $search_results = unserialize(stream_get_contents($open));
  227. fclose($open);
  228. if (!isset($search_results['query']['search']) || count($search_results['query']['search']) == 0) {
  229. return false;
  230. }
  231. $results = array();
  232. foreach ($search_results['query']['search'] as $id => $page) {
  233. switch ($page['title']) {
  234. case $album_name:
  235. $weight = 0.5;
  236. break;
  237. case "$album_name (album)":
  238. $weight = 0.75;
  239. break;
  240. case "$album_name ($artist_name album)":
  241. $weight = 1;
  242. break;
  243. default:
  244. $weight = 0;
  245. }
  246. if ($weight > 0) {
  247. $results[$page['title']] = $weight;
  248. }
  249. }
  250. if (count($results) > 0) {
  251. # order by weight
  252. # highest gets on bottom
  253. asort($results);
  254. end($results);
  255. $possible_cover = key($results);
  256. # Cover search query string
  257. $cover_params = array(
  258. 'action' => 'query',
  259. 'format' => 'php',
  260. 'redirects' => true,
  261. 'generator' => 'images',
  262. 'titles' => $possible_cover,
  263. 'prop' => 'imageinfo',
  264. 'iiprop' => 'url'
  265. );
  266. $cover_search_url = $api_url . '?' . http_build_query($cover_params);
  267. $open_cover_url = fopen($cover_search_url, 'r');
  268. if ($open_cover_url == false) {
  269. throw new Exception ('Can\'t open Cover Search URL');
  270. }
  271. $cover_search_results = unserialize(stream_get_contents($open_cover_url));
  272. fclose($open_cover_url);
  273. if (!isset($cover_search_results['query']['pages']) || count($cover_search_results['query']['pages']) == 0) {
  274. return false;
  275. }
  276. foreach ($cover_search_results['query']['pages'] as $image_id => $image) {
  277. # Wikipedia covers are mostly JPEG images.
  278. # Gets the first image (hard guess!)
  279. if (preg_match('/\.jpg$/i', $image['title']) == 1) {
  280. $cover = $image['imageinfo'][0];
  281. break;
  282. }
  283. }
  284. /*
  285. * Save the info if $save = true
  286. */
  287. if ($save) {
  288. $adodb->SetFetchMode(ADODB_FETCH_ASSOC);
  289. $album = $adodb->qstr($album_name);
  290. $artist = $adodb->qstr($artist_name);
  291. $license = $adodb->qstr($cover['descriptionurl']);
  292. $image = $adodb->qstr($cover['url']);
  293. $sql = ('UPDATE Album SET image = '
  294. . ($image) . ', '
  295. . ' artwork_license = '
  296. . ($license) . ' WHERE artist_name = '. ($artist)
  297. . ' AND name = ' . ($album));
  298. $res = $adodb->Execute($sql);
  299. }
  300. return $cover['url'];
  301. } else {
  302. return false;
  303. }
  304. } catch (Exception $e) {
  305. reportError($e->getMessage());
  306. }
  307. return $album_art_url;
  308. }
  309. }
  310. /**
  311. * Retrieves and saves the URL to cover art for an album
  312. *
  313. * @deprecated amazonaws.com returns error 400. 20120307 kabniel
  314. *
  315. * @param string $artist Artist name
  316. * @param string $album Album name
  317. */
  318. function go_get_album_art($artist, $album){
  319. global $adodb;
  320. $adodb->SetFetchMode(ADODB_FETCH_ASSOC);
  321. $Access_Key_ID = '1EST86JB355JBS3DFE82'; // this is mattl's personal key :)
  322. $SearchIndex = 'Music';
  323. $Keywords = rawurlencode($artist . ' ' . $album);
  324. $Operation = 'ItemSearch';
  325. $Version = '2007-07-16';
  326. $ResponseGroup = 'ItemAttributes,Images';
  327. $request =
  328. 'http://ecs.amazonaws.com/onca/xml'
  329. . '?Service=AWSECommerceService'
  330. . '&AssociateTag=' . $Associate_tag
  331. . '&AWSAccessKeyId=' . $Access_Key_ID
  332. . '&Operation=' . $Operation
  333. . '&Version=' . $Version
  334. . '&SearchIndex=' . $SearchIndex
  335. . '&Keywords=' . $Keywords
  336. . '&ResponseGroup=' . $ResponseGroup;
  337. $aws_xml = simplexml_load_file($request) or die('xml response not loading');
  338. $image = $aws_xml->Items->Item->MediumImage->URL;
  339. $URI = $aws_xml->Items->Item->DetailPageURL;
  340. if ($image) {
  341. if ($license == '') {
  342. $license = 'amazon';
  343. }
  344. $license = $adodb->qstr($license);
  345. $image = $adodb->qstr($image);
  346. $album = $adodb->qstr($album);
  347. $artist = $adodb->qstr($artist);
  348. $sql = ('UPDATE Album SET image = '
  349. . ($image) . ', '
  350. . ' artwork_license = '
  351. . ($license) . ' WHERE artist_name = '. ($artist)
  352. . ' AND name = ' . ($album));
  353. try {
  354. $res = $adodb->Execute($sql);
  355. } catch (Exception $e) {
  356. die('FAILED ' . $e->getMessage() . ' query was :' . $sql);
  357. }
  358. }
  359. }