PageRenderTime 49ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/model/doctrine/SongTable.class.php

http://streeme.googlecode.com/
PHP | 490 lines | 368 code | 35 blank | 87 comment | 33 complexity | 492f704d8490f799f2015f8ca7012223 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, ISC, AGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /**
  3. * SongTable
  4. *
  5. * This class has been auto-generated by the Doctrine ORM Framework
  6. */
  7. class SongTable extends Doctrine_Table
  8. {
  9. /**
  10. * Returns an instance of this class.
  11. *
  12. * @return object SongTable
  13. */
  14. public static function getInstance()
  15. {
  16. return Doctrine_Core::getTable('Song');
  17. }
  18. /**
  19. * Add a song to the library
  20. *
  21. * @param artist_id int: the related artist primary key
  22. * @param album_id int: the related album primary key
  23. * @param genre_id int: the related genre primary key
  24. * @param song_array array: the array of song info
  25. * @return int: the song insert id
  26. * @see apps/client/lib/MediaScan.class.php for information about the song_array
  27. */
  28. public function addSong( $artist_id, $album_id, $last_scan_id, $song_array )
  29. {
  30. if(
  31. isset( $song_array['filename'] )
  32. &&
  33. !empty( $song_array['filename'] )
  34. &&
  35. isset( $song_array['mtime'] )
  36. &&
  37. !empty( $song_array['mtime'] )
  38. &&
  39. $last_scan_id
  40. )
  41. {
  42. $song = new Song();
  43. $song->unique_id = sha1( uniqid( '', true ) . mt_rand( 1, 99999999 ) );
  44. $song->artist_id = (int) $artist_id;
  45. $song->album_id = (int) $album_id;
  46. $song->scan_id = (int) $last_scan_id;
  47. $song->name = $song_array[ 'song_name' ];
  48. $song->length = $song_array[ 'song_length' ];
  49. $song->accurate_length = (int) $song_array[ 'accurate_length' ];
  50. $song->filesize = (int) $song_array[ 'filesize' ];
  51. $song->bitrate = (int) $song_array[ 'bitrate' ];
  52. $song->yearpublished = (int) $song_array[ 'yearpublished' ];
  53. $song->tracknumber = (int) $song_array[ 'tracknumber' ];
  54. $song->label = $song_array[ 'label' ];
  55. $song->mtime = (int) $song_array[ 'mtime' ];
  56. $song->atime = (int) $song_array[ 'atime' ];
  57. $song->filename = $song_array[ 'filename' ];
  58. $song->save();
  59. $id = $song->getId();
  60. $song->free();
  61. return $id;
  62. }
  63. return false;
  64. }
  65. /**
  66. * Find a song record by filename and mtime
  67. *
  68. * @param filename str: the itunes style filename of the file
  69. * @param mtime int: the timestamp we're looking for
  70. * @return object single DQL fetchone
  71. */
  72. public function findByFilenameAndMtime( $filename, $mtime )
  73. {
  74. $q = Doctrine_Query::create()
  75. ->from( 'Song s' )
  76. ->where( 's.mtime = ?', $mtime )
  77. ->andWhere( 's.filename = ?', $filename );
  78. return $q->fetchOne();
  79. }
  80. /**
  81. * Fetch a single song by its unique id
  82. *
  83. * @param unique_song_id str: unique_id field
  84. * @return obj: single DQL fetchone with the song row
  85. */
  86. public function getSongByUniqueId( $unique_song_id )
  87. {
  88. //get the song from the database
  89. $q = Doctrine_Query::create()
  90. ->from( 'Song s' )
  91. ->where( 's.unique_id = ?', $unique_song_id );
  92. return $q->fetchOne();
  93. }
  94. /**
  95. * Try to mark a song as scanned by filename and mtime
  96. *
  97. * @param filename str: the itunes style filename of the file
  98. * @param mtime int: the timestamp we're looking for
  99. * @param last_scan_id int: scan id value to update
  100. * @return rows affected
  101. */
  102. public function updateScanId( $filename, $mtime, $last_scan_id )
  103. {
  104. $query = 'UPDATE ';
  105. $query .= ' song ';
  106. $query .= 'SET ';
  107. $query .= ' scan_id = :last_scan_id ';
  108. $query .= 'WHERE ';
  109. $query .= ' mtime = :mtime ';
  110. $query .= ' AND filename = :filename ';
  111. $parameters = array();
  112. $parameters['last_scan_id'] = $last_scan_id;
  113. $parameters['mtime'] = $mtime;
  114. $parameters['filename'] = $filename;
  115. $dbh = Doctrine_Manager::getInstance()->getCurrentConnection()->getDbh();
  116. $stmt = $dbh->prepare( $query );
  117. $success = $stmt->execute( $parameters );
  118. if( $success )
  119. {
  120. return $stmt->rowCount();
  121. }
  122. else
  123. {
  124. return 0;
  125. }
  126. }
  127. /**
  128. * Fetch a list of albums that have not been scanned for art yet
  129. * @param source str: the artwork source: amazon|meta|folders|service etc.
  130. * @return array: unscanned artwork list
  131. */
  132. public function getUnscannedArtList( $source )
  133. {
  134. $query = 'SELECT DISTINCT ';
  135. $query .= ' album.id as album_id, album.name as album_name, artist.name as artist_name, song.filename as song_filename ';
  136. $query .= 'FROM ';
  137. $query .= ' song ';
  138. $query .= 'LEFT JOIN ';
  139. $query .= ' album ON song.album_id = album.id ';
  140. $query .= 'LEFT JOIN ';
  141. $query .= ' artist ON song.artist_id = artist.id ';
  142. $query .= 'WHERE ';
  143. $query .= ' album.id IS NOT NULL ';
  144. switch ( $source )
  145. {
  146. case 'amazon':
  147. $query .= ' AND album.amazon_flagged != 1 ';
  148. break;
  149. case 'meta':
  150. $query .= ' AND album.meta_flagged != 1 ';
  151. break;
  152. case 'folders':
  153. $query .= ' AND album.folders_flagged != 1 ';
  154. break;
  155. case 'service':
  156. $query .= ' AND album.service_flagged != 1 ';
  157. break;
  158. }
  159. $query .= ' AND album.has_art != 1 ';
  160. $query .= ' ORDER BY album.id ASC ';
  161. $dbh = Doctrine_Manager::getInstance()->getCurrentConnection()->getDbh();
  162. return $dbh->query( $query )->fetchAll();
  163. }
  164. /**
  165. * Get file list
  166. * @param id str: song unique id | album and artist id
  167. * @param type str: song | album | artists
  168. * @return array: list of filenames for each song
  169. */
  170. public function getFileList( $id, $type )
  171. {
  172. $q = Doctrine_Query::create()
  173. ->select( 's.filename' )
  174. ->from( 'Song s' )
  175. ->where( '( 1 = 1 )' );
  176. switch( $type )
  177. {
  178. case 'artist':
  179. $q->andWhere( 's.artist_id = ?', $id );
  180. break;
  181. case 'album':
  182. $q->andWhere( 's.album_id = ?', $id );
  183. break;
  184. case 'song':
  185. $q->andWhere( 'unique_id = ?', $id );
  186. break;
  187. }
  188. return $q->fetchArray();
  189. }
  190. /**
  191. * Get total song count
  192. * @return int: total album count in database
  193. */
  194. public function getTotalSongCount()
  195. {
  196. $q = Doctrine_Query::create()
  197. ->select( 's.id' )
  198. ->from( 'Song s' );
  199. return $q->count();
  200. }
  201. /**
  202. * Get a list of songs
  203. * @param parameters array: search and pagination options
  204. * @param result_count OUT int: the resulting number of records in search before pagination
  205. * @param result_list OUT array: the resulting data set
  206. * @return bool: true if results exist, otherwise false
  207. * @see paramters list below in 'list defaults'
  208. */
  209. public function getList( $parameters=array(), &$result_count, &$result_list )
  210. {
  211. //list defaults
  212. $settings = array(
  213. 'limit' => 50, //int
  214. 'offset' => '0', //int
  215. 'order' => 'desc', //str: asc|desc
  216. 'search' => null, //str
  217. 'artist_id' => null, //int
  218. 'album_id' => null, //int
  219. 'song_id' => null, //int
  220. 'genre_id' => null, //int
  221. 'playlist_id' => null, //int
  222. 'sortcolumn' => 0, //int
  223. 'sortdirection' => 'desc', //str: asc|desc
  224. 'random' => false, //bool
  225. 'by_alpha' => null, //str: A-Z
  226. 'by_number' => null, //
  227. );
  228. $result_count = 0;
  229. $result_list = array();
  230. //import user paramters
  231. foreach ( $parameters as $name => $value )
  232. {
  233. $settings[ $name ] = $value;
  234. }
  235. //check for special space-separated search syntax eg( shuffle:true artistid:1 )
  236. $components = explode ( ' ', $settings[ 'search' ] );
  237. foreach( $components as $k=>$v )
  238. {
  239. //if playlistid: is set, change to a playlist songlist
  240. if ( stristr( $v, 'playlistid:' ) )
  241. {
  242. $match = explode( ':', $v );
  243. if ( is_array( $match ) )
  244. {
  245. $settings[ 'playlist_id' ] = $match[1];
  246. unset( $components[ $k ] );
  247. }
  248. }
  249. //if artistid: is set, add artistid to the where clause
  250. if ( stristr( $v, 'artistid:' ) )
  251. {
  252. $match = explode( ':', $v );
  253. if ( is_array( $match ) )
  254. {
  255. $settings[ 'artist_id' ] = $match[1];
  256. unset( $components[ $k ] );
  257. }
  258. }
  259. //if albumid: is set, add albumid to the where clause
  260. if ( stristr( $v, 'albumid:' ) )
  261. {
  262. $match = explode( ':', $v );
  263. if ( is_array( $match ) )
  264. {
  265. $settings[ 'album_id' ] = $match[1];
  266. unset( $components[ $k ] );
  267. }
  268. }
  269. //if genreid: is set, add genreid to the where clause
  270. if ( stristr( $v, 'genreid:' ) )
  271. {
  272. $match = explode( ':', $v );
  273. if ( is_array( $match ) )
  274. {
  275. $settings[ 'genre_id' ] = $match[1];
  276. unset( $components[ $k ] );
  277. }
  278. }
  279. //if by_alpha: is set, add an alpha LIKE to the where clause
  280. if ( stristr( $v, 'by_alpha:' ) )
  281. {
  282. $match = explode( ':', $v );
  283. if ( is_array( $match ) )
  284. {
  285. if ( $match[1] != "#" )
  286. {
  287. $settings[ 'by_alpha' ] = $match[1];
  288. unset( $components[ $k ] );
  289. }
  290. else
  291. {
  292. $settings[ 'by_number' ] = $match[1];
  293. unset( $components[ $k ] );
  294. }
  295. }
  296. }
  297. //if shuffle: is set, add genreid to the where clause
  298. if ( stristr( $v, 'shuffle:' ) )
  299. {
  300. $match = explode( ':', $v );
  301. if ( is_array( $match ) )
  302. {
  303. $settings[ 'random' ] = true;
  304. $settings[ 'sortcolumn' ] = 8;
  305. unset( $components[ $k ] );
  306. }
  307. }
  308. }
  309. //search should now be valid keywords, join them with spaces
  310. $settings[ 'search' ] = join( ' ', array_map( 'strtolower', $components ) );
  311. //this array contains the decoded sort information
  312. $expression = new Doctrine_Expression( 'random()' );
  313. $order_by = ( $settings[ 'sortdirection' ] == 'asc' ) ? ' ASC ' : ' DESC ';
  314. $column_sql = array(
  315. 0 => ' song.id ' . $order_by,
  316. 1 => ' song.name ' . $order_by,
  317. 2 => ' album.name ' . $order_by . ', song.tracknumber ASC ',
  318. 3 => ' artist.name ' . $order_by . ', album.name DESC, song.tracknumber ASC ',
  319. 4 => ' album_mtime ' . $order_by . ', album.id, song.tracknumber ASC ',
  320. 5 => ' song.yearpublished ' . $order_by . ', album.name DESC, song.tracknumber ASC ',
  321. 6 => ' song.accurate_length ' . $order_by,
  322. 7 => ' song.tracknumber ' . $order_by,
  323. 8 => ' ' . $expression . ' '
  324. );
  325. unset( $expression );
  326. $order_by_string = $column_sql[ (int) $settings[ 'sortcolumn' ] ];
  327. $parameters = array();
  328. $query = 'SELECT ';
  329. $query .= ' song.unique_id, song.name, album.name as album_name, artist.name as artist_name, song.mtime as date_modified, song.yearpublished, song.length, song.tracknumber, song.filename, ROUND( song.mtime / 20000 ) as album_mtime ';
  330. $query .= 'FROM ';
  331. if( !is_null( $settings['playlist_id'] ) )
  332. {
  333. $query .= ' playlist_files, ';
  334. }
  335. $query .= ' song ';
  336. $query .= 'LEFT JOIN ';
  337. $query .= ' artist ';
  338. $query .= 'ON song.artist_id = artist.id ';
  339. $query .= 'LEFT JOIN ';
  340. $query .= ' album ';
  341. $query .= 'ON song.album_id = album.id ';
  342. if ( !is_null( $settings[ 'genre_id' ] ) )
  343. {
  344. $query .= 'INNER JOIN ';
  345. $query .= ' song_genres ';
  346. $query .= 'ON song_genres.song_id = song.id ';
  347. }
  348. $query .= 'WHERE ( 1 = 1 ) ';
  349. if( !is_null( $settings['genre_id'] ) )
  350. {
  351. $query .= ' AND song_genres.genre_id = :genre_id ';
  352. $parameters[ 'genre_id' ] = $settings[ 'genre_id' ];
  353. }
  354. if( !is_null( $settings['playlist_id'] ) )
  355. {
  356. $query .= ' AND playlist_files.playlist_id = :playlist_id ';
  357. $query .= ' AND playlist_files.filename = song.filename ';
  358. $parameters[ 'playlist_id' ] = $settings[ 'playlist_id' ];
  359. }
  360. if ( !is_null( $settings[ 'song_id' ] ) )
  361. {
  362. $query .= ' AND song.id = :song_id ';
  363. $parameters[ 'song_id' ] = $settings[ 'song_id' ];
  364. }
  365. if ( !is_null( $settings[ 'album_id' ] ) )
  366. {
  367. $query .= ' AND song.album_id = :album_id ';
  368. $parameters[ 'album_id' ] = $settings[ 'album_id' ];
  369. }
  370. if ( !is_null( $settings[ 'artist_id' ] ) )
  371. {
  372. $query .= ' AND song.artist_id = :artist_id ';
  373. $parameters[ 'artist_id' ] = $settings[ 'artist_id' ];
  374. }
  375. if ( !is_null( $settings[ 'by_alpha' ] ) )
  376. {
  377. $query .= ' AND song.name LIKE :by_alpha ';
  378. $parameters[ 'by_alpha' ] = $settings[ 'by_alpha' ] . '%';
  379. }
  380. if ( !is_null( $settings[ 'by_number' ] ) )
  381. {
  382. $query .= ' AND ( song.name LIKE "0%" ';
  383. $query .= ' OR song.name LIKE "1%" ';
  384. $query .= ' OR song.name LIKE "2%" ';
  385. $query .= ' OR song.name LIKE "3%" ';
  386. $query .= ' OR song.name LIKE "4%" ';
  387. $query .= ' OR song.name LIKE "5%" ';
  388. $query .= ' OR song.name LIKE "6%" ';
  389. $query .= ' OR song.name LIKE "7%" ';
  390. $query .= ' OR song.name LIKE "8%" ';
  391. $query .= ' OR song.name LIKE "9%" ) ';
  392. }
  393. if ( !is_null( $settings[ 'search' ] ) && ( !empty( $settings[ 'search' ] ) || $settings[ 'search' ] === '0' ) )
  394. {
  395. $query .= ' AND ( lower( song.name ) LIKE :search OR lower( album.name ) LIKE :search OR lower( artist.name ) LIKE :search ) ';
  396. $parameters[ 'search' ] = '%' . join('%', explode(' ', $settings[ 'search' ] ) ) . '%';
  397. }
  398. //get a count of rows returned by this query before applying pagination
  399. $dbh = Doctrine_Manager::getInstance()->getCurrentConnection()->getDbh();
  400. $stmt = $dbh->prepare( $query );
  401. $success = $stmt->execute( $parameters );
  402. if( $success )
  403. {
  404. $row_count = $stmt->rowCount();
  405. if( $row_count > 1 )
  406. {
  407. //most databases have an optimized rowCount API
  408. $result_count = $row_count;
  409. }
  410. else
  411. {
  412. //sqlite compatibility: rowCount will only return 0 or 1
  413. while( $row = $stmt->fetch() ) $result_count++;
  414. }
  415. }
  416. else
  417. {
  418. return false;
  419. }
  420. //get the data set with pagination and ordering
  421. $query .= 'ORDER BY ';
  422. $query .= $order_by_string . ' ';
  423. $query .= ' LIMIT ';
  424. $query .= (int) $settings[ 'limit' ];
  425. $query .= ' OFFSET ';
  426. $query .= (int) $settings[ 'offset' ];
  427. $dbh = Doctrine_Manager::getInstance()->getCurrentConnection()->getDbh();
  428. $stmt = $dbh->prepare( $query );
  429. //echo "$query\r\n";
  430. $success = $stmt->execute( $parameters );
  431. if( $success )
  432. {
  433. $result_list = $stmt->fetchAll(Doctrine::FETCH_ASSOC);
  434. return true;
  435. }
  436. else
  437. {
  438. return false;
  439. }
  440. }
  441. /**
  442. * Remove song records not found in the specified scan
  443. *
  444. * @param last_scan_id int: this should be the id of the latest library scan
  445. * @return array: number of records removed
  446. */
  447. public function finalizeScan( $last_scan_id )
  448. {
  449. $q = Doctrine_Query::create()
  450. ->delete('Song s')
  451. ->where('s.scan_id != ?', $last_scan_id )
  452. ->execute();
  453. return $q;
  454. }
  455. }