PageRenderTime 68ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/catalog/local.catalog.php

https://gitlab.com/x33n/ampache
PHP | 812 lines | 516 code | 129 blank | 167 comment | 97 complexity | 7c71cd5ea137b3d42071f34a97018bc2 MD5 | raw file
  1. <?php
  2. /* vim:set softtabstop=4 shiftwidth=4 expandtab: */
  3. /**
  4. *
  5. * LICENSE: GNU General Public License, version 2 (GPLv2)
  6. * Copyright 2001 - 2015 Ampache.org
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License v2
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. *
  21. */
  22. /**
  23. * Local Catalog Class
  24. *
  25. * This class handles all actual work in regards to local catalogs.
  26. *
  27. */
  28. class Catalog_local extends Catalog
  29. {
  30. private $version = '000001';
  31. private $type = 'local';
  32. private $description = 'Local Catalog';
  33. private $count;
  34. private $added_songs_to_gather;
  35. private $added_videos_to_gather;
  36. /**
  37. * get_description
  38. * This returns the description of this catalog
  39. */
  40. public function get_description()
  41. {
  42. return $this->description;
  43. } // get_description
  44. /**
  45. * get_version
  46. * This returns the current version
  47. */
  48. public function get_version()
  49. {
  50. return $this->version;
  51. } // get_version
  52. /**
  53. * get_type
  54. * This returns the current catalog type
  55. */
  56. public function get_type()
  57. {
  58. return $this->type;
  59. } // get_type
  60. /**
  61. * get_create_help
  62. * This returns hints on catalog creation
  63. */
  64. public function get_create_help()
  65. {
  66. return "";
  67. } // get_create_help
  68. /**
  69. * is_installed
  70. * This returns true or false if local catalog is installed
  71. */
  72. public function is_installed()
  73. {
  74. $sql = "SHOW TABLES LIKE 'catalog_local'";
  75. $db_results = Dba::query($sql);
  76. return (Dba::num_rows($db_results) > 0);
  77. } // is_installed
  78. /**
  79. * install
  80. * This function installs the local catalog
  81. */
  82. public function install()
  83. {
  84. $sql = "CREATE TABLE `catalog_local` (`id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , ".
  85. "`path` VARCHAR( 255 ) COLLATE utf8_unicode_ci NOT NULL , " .
  86. "`catalog_id` INT( 11 ) NOT NULL" .
  87. ") ENGINE = MYISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci";
  88. $db_results = Dba::query($sql);
  89. return true;
  90. } // install
  91. public function catalog_fields()
  92. {
  93. $fields['path'] = array('description' => T_('Path'),'type'=>'textbox');
  94. return $fields;
  95. }
  96. public $path;
  97. /**
  98. * Constructor
  99. *
  100. * Catalog class constructor, pulls catalog information
  101. */
  102. public function __construct($catalog_id = null)
  103. {
  104. if ($catalog_id) {
  105. $this->id = intval($catalog_id);
  106. $info = $this->get_info($catalog_id);
  107. foreach ($info as $key=>$value) {
  108. $this->$key = $value;
  109. }
  110. }
  111. }
  112. /**
  113. * get_from_path
  114. *
  115. * Try to figure out which catalog path most closely resembles this one.
  116. * This is useful when creating a new catalog to make sure we're not
  117. * doubling up here.
  118. */
  119. public static function get_from_path($path)
  120. {
  121. // First pull a list of all of the paths for the different catalogs
  122. $sql = "SELECT `catalog_id`,`path` FROM `catalog_local`";
  123. $db_results = Dba::read($sql);
  124. $catalog_paths = array();
  125. $component_path = $path;
  126. while ($row = Dba::fetch_assoc($db_results)) {
  127. $catalog_paths[$row['path']] = $row['catalog_id'];
  128. }
  129. // Break it down into its component parts and start looking for a catalog
  130. do {
  131. if ($catalog_paths[$component_path]) {
  132. return $catalog_paths[$component_path];
  133. }
  134. // Keep going until the path stops changing
  135. $old_path = $component_path;
  136. $component_path = realpath($component_path . '/../');
  137. } while (strcmp($component_path,$old_path) != 0);
  138. return false;
  139. }
  140. /**
  141. * create_type
  142. *
  143. * This creates a new catalog type entry for a catalog
  144. * It checks to make sure its parameters is not already used before creating
  145. * the catalog.
  146. */
  147. public static function create_type($catalog_id, $data)
  148. {
  149. // Clean up the path just in case
  150. $path = rtrim(rtrim(trim($data['path']),'/'),'\\');
  151. if (!strlen($path)) {
  152. Error::add('general', T_('Error: Path not specified'));
  153. return false;
  154. }
  155. // Make sure that there isn't a catalog with a directory above this one
  156. if (self::get_from_path($path)) {
  157. Error::add('general', T_('Error: Defined Path is inside an existing catalog'));
  158. return false;
  159. }
  160. // Make sure the path is readable/exists
  161. if (!Core::is_readable($path)) {
  162. debug_event('catalog', 'Cannot add catalog at unopenable path ' . $path, 1);
  163. Error::add('general', sprintf(T_('Error: %s is not readable or does not exist'), scrub_out($data['path'])));
  164. return false;
  165. }
  166. // Make sure this path isn't already in use by an existing catalog
  167. $sql = 'SELECT `id` FROM `catalog_local` WHERE `path` = ?';
  168. $db_results = Dba::read($sql, array($path));
  169. if (Dba::num_rows($db_results)) {
  170. debug_event('catalog', 'Cannot add catalog with duplicate path ' . $path, 1);
  171. Error::add('general', sprintf(T_('Error: Catalog with %s already exists'), $path));
  172. return false;
  173. }
  174. $sql = 'INSERT INTO `catalog_local` (`path`, `catalog_id`) VALUES (?, ?)';
  175. Dba::write($sql, array($path, $catalog_id));
  176. return true;
  177. }
  178. /**
  179. * add_files
  180. *
  181. * Recurses through $this->path and pulls out all mp3s and returns the
  182. * full path in an array. Passes gather_type to determine if we need to
  183. * check id3 information against the db.
  184. */
  185. public function add_files($path, $options)
  186. {
  187. // Profile the memory a bit
  188. debug_event('Memory', UI::format_bytes(memory_get_usage(true)), 5);
  189. // See if we want a non-root path for the add
  190. if (isset($options['subdirectory'])) {
  191. $path = $options['subdirectory'];
  192. unset($options['subdirectory']);
  193. }
  194. // Correctly detect the slash we need to use here
  195. if (strpos($path, '/') !== false) {
  196. $slash_type = '/';
  197. } else {
  198. $slash_type = '\\';
  199. }
  200. /* Open up the directory */
  201. $handle = opendir($path);
  202. if (!is_resource($handle)) {
  203. debug_event('read', "Unable to open $path", 5);
  204. Error::add('catalog_add', sprintf(T_('Error: Unable to open %s'), $path));
  205. return false;
  206. }
  207. /* Change the dir so is_dir works correctly */
  208. if (!chdir($path)) {
  209. debug_event('read', "Unable to chdir to $path", 2);
  210. Error::add('catalog_add', sprintf(T_('Error: Unable to change to directory %s'), $path));
  211. return false;
  212. }
  213. debug_event('Memory', UI::format_bytes(memory_get_usage(true)), 5);
  214. /* Recurse through this dir and create the files array */
  215. while ( false !== ( $file = readdir($handle) ) ) {
  216. /* Skip to next if we've got . or .. */
  217. if (substr($file,0,1) == '.') { continue; }
  218. debug_event('read', "Starting work on $file inside $path", 5);
  219. debug_event('Memory', UI::format_bytes(memory_get_usage(true)), 5);
  220. /* Create the new path */
  221. $full_file = $path.$slash_type.$file;
  222. $this->add_file($full_file, $options);
  223. } // end while reading directory
  224. debug_event('closedir', "Finished reading $path , closing handle", 5);
  225. // This should only happen on the last run
  226. if ($path == $this->path) {
  227. UI::update_text('add_count_' . $this->id, $this->count);
  228. }
  229. /* Close the dir handle */
  230. @closedir($handle);
  231. } // add_files
  232. public function add_file($full_file, $options)
  233. {
  234. // Ensure that we've got our cache
  235. $this->_create_filecache();
  236. /* First thing first, check if file is already in catalog.
  237. * This check is very quick, so it should be performed before any other checks to save time
  238. */
  239. if (isset($this->_filecache[strtolower($full_file)])) {
  240. return false;
  241. }
  242. // Incase this is the second time through clear this variable
  243. // if it was set the day before
  244. unset($failed_check);
  245. if (AmpConfig::get('no_symlinks')) {
  246. if (is_link($full_file)) {
  247. debug_event('read', "Skipping symbolic link $full_file", 5);
  248. return false;
  249. }
  250. }
  251. /* If it's a dir run this function again! */
  252. if (is_dir($full_file)) {
  253. $this->add_files($full_file,$options);
  254. /* Change the dir so is_dir works correctly */
  255. if (!chdir($full_file)) {
  256. debug_event('read', "Unable to chdir to $path", 2);
  257. Error::add('catalog_add', sprintf(T_('Error: Unable to change to directory %s'), $path));
  258. }
  259. /* Skip to the next file */
  260. return true;
  261. } //it's a directory
  262. $is_audio_file = Catalog::is_audio_file($full_file);
  263. if (AmpConfig::get('catalog_video_pattern')) {
  264. $is_video_file = Catalog::is_video_file($full_file);
  265. }
  266. if ($options['parse_playlist'] && AmpConfig::get('catalog_playlist_pattern')) {
  267. $is_playlist = Catalog::is_playlist_file($full_file);
  268. }
  269. /* see if this is a valid audio file or playlist file */
  270. if ($is_audio_file || $is_video_file || $is_playlist) {
  271. /* Now that we're sure its a file get filesize */
  272. $file_size = Core::get_filesize($full_file);
  273. if (!$file_size) {
  274. debug_event('read', "Unable to get filesize for $full_file", 2);
  275. /* HINT: FullFile */
  276. Error::add('catalog_add', sprintf(T_('Error: Unable to get filesize for %s'), $full_file));
  277. } // file_size check
  278. if (!Core::is_readable($full_file)) {
  279. // not readable, warn user
  280. debug_event('read', "$full_file is not readable by ampache", 2);
  281. /* HINT: FullFile */
  282. Error::add('catalog_add', sprintf(T_('%s is not readable by ampache'), $full_file));
  283. return false;
  284. }
  285. // Check to make sure the filename is of the expected charset
  286. if (function_exists('iconv')) {
  287. $convok = false;
  288. $site_charset = AmpConfig::get('site_charset');
  289. $lc_charset = $site_charset;
  290. if (AmpConfig::get('lc_charset')) {
  291. $lc_charset = AmpConfig::get('lc_charset');
  292. }
  293. $enc_full_file = iconv($lc_charset, $site_charset, $full_file);
  294. if ($lc_charset != $site_charset) {
  295. $convok = (strcmp($full_file, iconv($site_charset, $lc_charset, $enc_full_file)) == 0);
  296. } else {
  297. $convok = (strcmp($enc_full_file, $full_file) == 0);
  298. }
  299. if (!$convok) {
  300. debug_event('read', $full_file . ' has non-' . $site_charset . ' characters and can not be indexed, converted filename:' . $enc_full_file, '1');
  301. /* HINT: FullFile */
  302. Error::add('catalog_add', sprintf(T_('%s does not match site charset'), $full_file));
  303. return false;
  304. }
  305. $full_file = $enc_full_file;
  306. // Check again with good encoding
  307. if (isset($this->_filecache[strtolower($full_file)])) {
  308. return false;
  309. }
  310. } // end if iconv
  311. if ($is_playlist) {
  312. debug_event('read', 'Found playlist file to import: ' . $full_file, '5');
  313. $this->_playlists[] = $full_file;
  314. } // if it's a playlist
  315. else {
  316. if (count($this->get_gather_types('music')) > 0) {
  317. if ($is_audio_file) {
  318. $this->insert_local_song($full_file, $options);
  319. } else {
  320. debug_event('read', $full_file . " ignored, bad media type for this music catalog.", 5);
  321. }
  322. } else if (count($this->get_gather_types('video')) > 0) {
  323. if ($is_video_file) {
  324. $this->insert_local_video($full_file, $options);
  325. } else {
  326. debug_event('read', $full_file . " ignored, bad media type for this video catalog.", 5);
  327. }
  328. }
  329. $this->count++;
  330. $file = str_replace(array('(', ')', '\''), '', $full_file);
  331. if (UI::check_ticker()) {
  332. UI::update_text('add_count_' . $this->id, $this->count);
  333. UI::update_text('add_dir_' . $this->id, scrub_out($file));
  334. } // update our current state
  335. } // if it's not an m3u
  336. } //if it matches the pattern
  337. else {
  338. debug_event('read', "$full_file ignored, non-audio file or 0 bytes", 5);
  339. } // else not an audio file
  340. }
  341. /**
  342. * add_to_catalog
  343. * this function adds new files to an
  344. * existing catalog
  345. */
  346. public function add_to_catalog($options = null)
  347. {
  348. if ($options == null) {
  349. $options = array(
  350. 'gather_art' => true,
  351. 'parse_playlist' => false
  352. );
  353. }
  354. $this->count = 0;
  355. $this->added_songs_to_gather = array();
  356. $this->added_videos_to_gather = array();
  357. if (!defined('SSE_OUTPUT')) {
  358. require AmpConfig::get('prefix') . '/templates/show_adds_catalog.inc.php';
  359. flush();
  360. }
  361. /* Set the Start time */
  362. $start_time = time();
  363. // Make sure the path doesn't end in a / or \
  364. $this->path = rtrim($this->path,'/');
  365. $this->path = rtrim($this->path,'\\');
  366. // Prevent the script from timing out and flush what we've got
  367. set_time_limit(0);
  368. /* Get the songs and then insert them into the db */
  369. $this->add_files($this->path, $options);
  370. if ($options['parse_playlist'] && count($this->_playlists)) {
  371. // Foreach Playlists we found
  372. foreach ($this->_playlists as $full_file) {
  373. $result = $this->import_playlist($full_file);
  374. if ($result['success']) {
  375. $file = basename($full_file);
  376. } // end if import worked
  377. } // end foreach playlist files
  378. }
  379. /* Do a little stats mojo here */
  380. $current_time = time();
  381. if ($options['gather_art']) {
  382. $catalog_id = $this->id;
  383. if (!defined('SSE_OUTPUT')) {
  384. require AmpConfig::get('prefix') . '/templates/show_gather_art.inc.php';
  385. flush();
  386. }
  387. $this->gather_art($this->added_songs_to_gather, $this->added_videos_to_gather);
  388. }
  389. /* Update the Catalog last_update */
  390. $this->update_last_add();
  391. $time_diff = ($current_time - $start_time) ?: 0;
  392. $rate = number_format(($time_diff > 0) ? $this->count / $time_diff : 0, 2);
  393. if ($rate <= 0) {
  394. $rate = T_('N/A');
  395. }
  396. if (!defined('SSE_OUTPUT')) {
  397. UI::show_box_top();
  398. }
  399. UI::update_text('', sprintf(T_('Catalog Update Finished. Total Time: [%s] Total Media: [%s] Media Per Second: [%s]'), date('i:s', $time_diff), $this->count, $rate));
  400. if (!defined('SSE_OUTPUT')) {
  401. UI::show_box_bottom();
  402. }
  403. } // add_to_catalog
  404. /**
  405. * verify_catalog_proc
  406. * This function compares the DB's information with the ID3 tags
  407. */
  408. public function verify_catalog_proc()
  409. {
  410. debug_event('verify', 'Starting on ' . $this->name, 5);
  411. set_time_limit(0);
  412. $stats = self::get_stats($this->id);
  413. $number = $stats['videos'] + $stats['songs'];
  414. $total_updated = 0;
  415. $this->count = 0;
  416. if (!defined('SSE_OUTPUT')) {
  417. require_once AmpConfig::get('prefix') . '/templates/show_verify_catalog.inc.php';
  418. flush();
  419. }
  420. foreach (array('video', 'song') as $media_type) {
  421. $total = $stats[$media_type . 's']; // UGLY
  422. if ($total == 0) {
  423. continue;
  424. }
  425. $chunks = floor($total / 10000);
  426. foreach (range(0, $chunks) as $chunk) {
  427. // Try to be nice about memory usage
  428. if ($chunk > 0) {
  429. $media_type::clear_cache();
  430. }
  431. $total_updated += $this->_verify_chunk($media_type, $chunk, 10000);
  432. }
  433. }
  434. debug_event('verify', "Finished, $total_updated updated in " . $this->name, 5);
  435. self::gc();
  436. $this->update_last_update();
  437. return array('total' => $number, 'updated' => $total_updated);
  438. } // verify_catalog_proc
  439. /**
  440. * _verify_chunk
  441. * This verifies a chunk of the catalog, done to save
  442. * memory
  443. */
  444. private function _verify_chunk($media_type, $chunk, $chunk_size)
  445. {
  446. debug_event('verify', "Starting chunk $chunk", 5);
  447. $count = $chunk * $chunk_size;
  448. $changed = 0;
  449. $sql = "SELECT `id`, `file` FROM `$media_type` " .
  450. "WHERE `catalog`='$this->id' LIMIT $count,$chunk_size";
  451. $db_results = Dba::read($sql);
  452. if (AmpConfig::get('memory_cache')) {
  453. while ($row = Dba::fetch_assoc($db_results, false)) {
  454. $media_ids[] = $row['id'];
  455. }
  456. $media_type::build_cache($media_ids);
  457. $db_results = Dba::read($sql);
  458. } while ($row = Dba::fetch_assoc($db_results)) {
  459. $count++;
  460. if (UI::check_ticker()) {
  461. $file = str_replace(array('(',')','\''), '', $row['file']);
  462. UI::update_text('verify_count_' . $this->id, $count);
  463. UI::update_text('verify_dir_' . $this->id, scrub_out($file));
  464. }
  465. if (!Core::is_readable(Core::conv_lc_file($row['file']))) {
  466. Error::add('general', sprintf(T_('%s does not exist or is not readable'), $row['file']));
  467. debug_event('read', $row['file'] . ' does not exist or is not readable', 5);
  468. continue;
  469. }
  470. $media = new $media_type($row['id']);
  471. $info = self::update_media_from_tags($media, $this->sort_pattern,$this->rename_pattern);
  472. if ($info['change']) {
  473. $changed++;
  474. }
  475. unset($info);
  476. }
  477. UI::update_text('verify_count_' . $this->id, $count);
  478. return $changed;
  479. } // _verify_chunk
  480. /**
  481. * clean catalog procedure
  482. *
  483. * Removes local songs that no longer exist.
  484. */
  485. public function clean_catalog_proc()
  486. {
  487. if (!Core::is_readable($this->path)) {
  488. // First sanity check; no point in proceeding with an unreadable
  489. // catalog root.
  490. debug_event('catalog', 'Catalog path:' . $this->path . ' unreadable, clean failed', 1);
  491. Error::add('general', T_('Catalog Root unreadable, stopping clean'));
  492. Error::display('general');
  493. return 0;
  494. }
  495. $dead_total = 0;
  496. $stats = self::get_stats($this->id);
  497. $this->count = 0;
  498. foreach (array('video', 'song') as $media_type) {
  499. $total = $stats[$media_type . 's']; // UGLY
  500. if ($total == 0) {
  501. continue;
  502. }
  503. $chunks = floor($total / 10000);
  504. $dead = array();
  505. foreach (range(0, $chunks) as $chunk) {
  506. $dead = array_merge($dead, $this->_clean_chunk($media_type, $chunk, 10000));
  507. }
  508. $dead_count = count($dead);
  509. // The AlmightyOatmeal sanity check
  510. // Never remove everything; it might be a dead mount
  511. if ($dead_count >= $total) {
  512. debug_event('catalog', 'All files would be removed. Doing nothing.', 1);
  513. Error::add('general', T_('All files would be removed. Doing nothing'));
  514. continue;
  515. }
  516. if ($dead_count) {
  517. $dead_total += $dead_count;
  518. $sql = "DELETE FROM `$media_type` WHERE `id` IN " .
  519. '(' . implode(',',$dead) . ')';
  520. $db_results = Dba::write($sql);
  521. }
  522. }
  523. return $dead_total;
  524. }
  525. /**
  526. * _clean_chunk
  527. * This is the clean function, its broken into
  528. * said chunks to try to save a little memory
  529. */
  530. private function _clean_chunk($media_type, $chunk, $chunk_size)
  531. {
  532. debug_event('clean', "Starting chunk $chunk", 5);
  533. $dead = array();
  534. $count = $chunk * $chunk_size;
  535. $sql = "SELECT `id`, `file` FROM `$media_type` " .
  536. "WHERE `catalog`='$this->id' LIMIT $count,$chunk_size";
  537. $db_results = Dba::read($sql);
  538. while ($results = Dba::fetch_assoc($db_results)) {
  539. debug_event('clean', 'Starting work on ' . $results['file'] . '(' . $results['id'] . ')', 5);
  540. $count++;
  541. if (UI::check_ticker()) {
  542. $file = str_replace(array('(',')', '\''), '', $results['file']);
  543. UI::update_text('clean_count_' . $this->id, $count);
  544. UI::update_text('clean_dir_' . $this->id, scrub_out($file));
  545. }
  546. $file_info = Core::get_filesize(Core::conv_lc_file($results['file']));
  547. if (!file_exists(Core::conv_lc_file($results['file'])) || $file_info < 1) {
  548. debug_event('clean', 'File not found or empty: ' . $results['file'], 5);
  549. Error::add('general', sprintf(T_('Error File Not Found or 0 Bytes: %s'), $results['file']));
  550. // Store it in an array we'll delete it later...
  551. $dead[] = $results['id'];
  552. } //if error
  553. else if (!Core::is_readable(Core::conv_lc_file($results['file']))) {
  554. debug_event('clean', $results['file'] . ' is not readable, but does exist', 1);
  555. }
  556. }
  557. return $dead;
  558. } //_clean_chunk
  559. /**
  560. * insert_local_song
  561. *
  562. * Insert a song that isn't already in the database.
  563. */
  564. private function insert_local_song($file, $options = array())
  565. {
  566. $vainfo = new vainfo($file, $this->get_gather_types('music'), '', '', '', $this->sort_pattern, $this->rename_pattern);
  567. $vainfo->get_info();
  568. $key = vainfo::get_tag_type($vainfo->tags);
  569. $results = vainfo::clean_tag_info($vainfo->tags, $key, $file);
  570. $results['catalog'] = $this->id;
  571. if (isset($options['user_upload'])) {
  572. $results['user_upload'] = $options['user_upload'];
  573. // Override artist information with artist's user
  574. if (AmpConfig::get('upload_user_artist')) {
  575. $user = new User($options['user_upload']);
  576. if ($user->id) {
  577. $artists = $user->get_artists();
  578. $artist = null;
  579. // No associated artist yet, we create a default one for the user sender
  580. if (count($artists) == 0) {
  581. $artists[] = Artist::check($user->fullname);
  582. $artist = new Artist($artists[0]);
  583. $artist->update_artist_user($user->id);
  584. } else {
  585. $artist = new Artist($artists[0]);
  586. }
  587. $results['artist'] = $artist->name;
  588. $results['mb_artistid'] = $artist->mbid;
  589. }
  590. }
  591. }
  592. if (isset($options['license'])) {
  593. $results['license'] = $options['license'];
  594. }
  595. $id = Song::insert($results);
  596. // Extended metadata loading is not deferred, retrieve it now
  597. if ($id && !AmpConfig::get('deferred_ext_metadata')) {
  598. $song = new Song($id);
  599. Recommendation::get_artist_info($song->artist);
  600. }
  601. $this->added_songs_to_gather[] = $id;
  602. $this->_filecache[strtolower($file)] = $id;
  603. return $id;
  604. }
  605. /**
  606. * insert_local_video
  607. * This inserts a video file into the video file table the tag
  608. * information we can get is super sketchy so it's kind of a crap shoot
  609. * here
  610. */
  611. public function insert_local_video($file, $options = array())
  612. {
  613. /* Create the vainfo object and get info */
  614. $gtypes = $this->get_gather_types('video');
  615. $vainfo = new vainfo($file, $gtypes,'','','',$this->sort_pattern,$this->rename_pattern);
  616. $vainfo->get_info();
  617. $tag_name = vainfo::get_tag_type($vainfo->tags, 'metadata_order_video');
  618. $results = vainfo::clean_tag_info($vainfo->tags,$tag_name,$file);
  619. $results['catalog'] = $this->id;
  620. $id = Video::insert($results, $gtypes, $options);
  621. if ($results['art']) {
  622. $art = new Art($id, 'video');
  623. $art->insert_url($results['art']);
  624. if (AmpConfig::get('generate_video_preview')) {
  625. Video::generate_preview($id);
  626. }
  627. } else {
  628. $this->added_videos_to_gather[] = $id;
  629. }
  630. $this->_filecache[strtolower($file)] = 'v_' . $id;
  631. return $id;
  632. } // insert_local_video
  633. /**
  634. * check_local_mp3
  635. * Checks the song to see if it's there already returns true if found, false if not
  636. */
  637. public function check_local_mp3($full_file, $gather_type='')
  638. {
  639. $file_date = filemtime($full_file);
  640. if ($file_date < $this->last_add) {
  641. debug_event('Check','Skipping ' . $full_file . ' File modify time before last add run','3');
  642. return true;
  643. }
  644. $sql = "SELECT `id` FROM `song` WHERE `file` = ?";
  645. $db_results = Dba::read($sql, array($full_file));
  646. //If it's found then return true
  647. if (Dba::fetch_row($db_results)) {
  648. return true;
  649. }
  650. return false;
  651. } //check_local_mp3
  652. public function get_rel_path($file_path)
  653. {
  654. $info = $this->_get_info();
  655. $catalog_path = rtrim($info->path, "/");
  656. return( str_replace( $catalog_path . "/", "", $file_path ) );
  657. }
  658. /**
  659. * format
  660. *
  661. * This makes the object human-readable.
  662. */
  663. public function format()
  664. {
  665. parent::format();
  666. $this->f_info = $this->path;
  667. $this->f_full_info = $this->path;
  668. }
  669. public function prepare_media($media)
  670. {
  671. // Do nothing, it's just file...
  672. return $media;
  673. }
  674. } // end of local catalog class