<commit_before><?php

/**
 * ownCloud - Music app
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author <NAME> <<EMAIL>>
 * @copyright <NAME> 2020
 */

namespace OCA\Music\Migration;

use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;

class DiskNumberMigration implements IRepairStep {

	/** @var IDBConnection */
	private $db;

	/** @var IConfig */
	private $config;

	/** @var int[] */
	private $obsoleteAlbums;

	/** @var int[] */
	private $mergeFailureAlbums;

	public function __construct(IDBConnection $connection, IConfig $config) {
		$this->db = $connection;
		$this->config = $config;
		$this->obsoleteAlbums = [];
		$this->mergeFailureAlbums = [];
	}

	public function getName() {
		return 'Combine multi-disk albums and store disk numbers per track';
	}

	/**
	 * @inheritdoc
	 */
	public function run(IOutput $output) {
		$installedVersion = $this->config->getAppValue('music', 'installed_version');

		if (\version_compare($installedVersion, '0.13.0', '<=')) {
			$n = $this->copyDiskNumberToTracks();
			$output->info("$n tracks were updated with a disk number");

			$n = $this->combineMultiDiskAlbums();
			$output->info("$n tracks were assinged to new albums when combining multi-disk albums");

			$n = $this->removeObsoleteAlbums();
			$output->info("$n obsolete album entries were removed from the database");

			$n = $this->reEvaluateAlbumHashes();
			$output->info("$n albums were updated with new hashes");

			$n = $this->removeAlbumsWhichFailedMerging();
			$output->info("$n albums were rmeoved because merging them failed; these need to be rescanned by the user");

			$n = $this->removeDiskNumbersFromAlbums();
			$output->info("obsolete disk number field was nullified in $n albums");
		}
	}

	/**
	 * Copy disk numbers from the albums table to the tracks table
	 */
	private function copyDiskNumberToTracks() {
		$sql = 'UPDATE `*PREFIX*music_tracks` '. 
				'SET `disk` = (SELECT `disk` '. 
				'              FROM `*PREFIX*music_albums` '.
				'              WHERE `*PREFIX*music_tracks`.`album_id` = `*PREFIX*music_albums`.`id`) '.
				'WHERE `disk` IS NULL';
		return $this->db->executeUpdate($sql);
	}

	/**
	 * Move all tracks belonging to separate disks of the same album title to the
	 * album entity matching the first of those disks. The album entities matching
	 * the rest of the disks become obsolete.
	 */<commit_msg>Catch any unexpected exceptions in the disk number migration<commit_after><?php

/**
 * ownCloud - Music app
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author <NAME> <<EMAIL>>
 * @copyright <NAME> 2020
 */

namespace OCA\Music\Migration;

use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;

class DiskNumberMigration implements IRepairStep {

	/** @var IDBConnection */
	private $db;

	/** @var IConfig */
	private $config;

	/** @var int[] */
	private $obsoleteAlbums;

	/** @var int[] */
	private $mergeFailureAlbums;

	public function __construct(IDBConnection $connection, IConfig $config) {
		$this->db = $connection;
		$this->config = $config;
		$this->obsoleteAlbums = [];
		$this->mergeFailureAlbums = [];
	}

	public function getName() {
		return 'Combine multi-disk albums and store disk numbers per track';
	}

	/**
	 * @inheritdoc
	 */
	public function run(IOutput $output) {
		$installedVersion = $this->config->getAppValue('music', 'installed_version');

		if (\version_compare($installedVersion, '0.13.0', '<=')) {
			try {
				$this->executeMigrationSteps($output);
			} catch (\Exception $e) {
				$output->warning('Unexpected exception ' . get_class($e) . 
								'. The music DB may have been left in an inconsistent state.');
			}
		}
	}

	private function executeMigrationSteps(IOutput $output) {
		$n = $this->copyDiskNumberToTracks();
		$output->info("$n tracks were updated with a disk number");

		$n = $this->combineMultiDiskAlbums();
		$output->info("$n tracks were assinged to new albums when combining multi-disk albums");

		$n = $this->removeObsoleteAlbums();
		$output->info("$n obsolete album entries were removed from the database");

		$n = $this->reEvaluateAlbumHashes();
		$output->info("$n albums were updated with new hashes");

		$n = $this->removeAlbumsWhichFailedMerging();
		$output->info("$n albums were rmeoved because merging them failed; these need to be rescanned by the user");

		$n = $this->removeDiskNumbersFromAlbums();
		$output->info("obsolete disk number field was nullified in $n albums");
	}

	/**
	 * Copy disk numbers from the albums table to the tracks table
	 */
	private function copyDiskNumberToTracks() {
		$sql = 'UPDATE `*PREFIX*music_tracks` '. 
				'SET `disk` = (SELECT `disk` '. 
				'              FROM `*PREFIX*music_albums` '.
				'              WHERE `*PREFIX*music_tracks`.`album_id` = `*PREFIX*music_albums`.`id`) '.
				'WHERE `disk` IS NULL';
		return $this->db->executeUpdate($sql);
	}

	/**
	 * Move all tracks belonging to separate disks of the same album title to the
	 * album entity matching the first of those disks. The album entities matching
	 * the rest of the disks become obsolete.
	 */
{'fraction_non_alphanumeric': 0.13866818009837306, 'fraction_numerical': 0.00340522133938706, 'mean_word_length': 3.823905109489051, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2343181', 'n_tokens_mistral': 1816, 'n_tokens_neox': 1613, 'n_words': 493}