diff --git a/scripts/gen-releases-csv.py b/scripts/gen-releases-csv.py new file mode 100755 index 0000000..d2d0863 --- /dev/null +++ b/scripts/gen-releases-csv.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""Generate a CSV usable with the import:releases command from a directory. + +This script assumes your have the same format for your release directories as +me, which is "Artist/Year - Release". +""" + +import argparse +import csv +import os +import re + +release_re = re.compile(r"(?P\d{4})[\d\.]*(?: -)? (?P.+)") + +argparser = argparse.ArgumentParser() +argparser.add_argument('directory', help='directory to explore') +args = argparser.parse_args() +root = args.directory + +with open('releases.csv', 'w', newline='') as output_file: + csv_writer = csv.writer(output_file) + + for artist in os.listdir(root): + artist_dir = os.path.join(root, artist) + if not os.path.isdir(artist_dir): + continue + for release in os.listdir(os.path.join(root, artist)): + release_dir = os.path.join(artist_dir, release) + if not os.path.isdir(release_dir): + continue + match = release_re.match(release) + if not match: + continue + match_dict = match.groupdict() + csv_writer.writerow([ + artist, + match_dict["title"], + match_dict["year"], + ]) diff --git a/src/Command/ImportReleasesCommand.php b/src/Command/ImportReleasesCommand.php new file mode 100644 index 0000000..b781912 --- /dev/null +++ b/src/Command/ImportReleasesCommand.php @@ -0,0 +1,104 @@ +<?php + +namespace App\Command; + +use App\Entity\Artist; +use App\Entity\Release; +use App\Repository\ArtistRepository; +use App\Repository\ReleaseRepository; +use App\Repository\UserRepository; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +#[AsCommand( + name: 'import:releases', + description: 'Import releases from a CSV file.', +)] +class ImportReleasesCommand extends Command +{ + public function __construct( + protected EntityManagerInterface $entityManager, + protected ArtistRepository $artistRepository, + protected ReleaseRepository $releaseRepository, + protected UserRepository $userRepository, + ) + { + parent::__construct(); + } + + protected function configure(): void + { + $this + ->addArgument('username', InputArgument::REQUIRED, 'Owner username') + ->addArgument('csv', InputArgument::REQUIRED, 'CSV file') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $csvFilename = $input->getArgument('csv'); + $ownerName = $input->getArgument('username'); + + $owner = $this->userRepository->findOneBy(['username' => $ownerName]); + if (!$owner) { + $io->error("No user with the username $ownerName."); + return Command::FAILURE; + } + + $numNewArtists = 0; + $numNewReleases = 0; + $numSkippedReleases = 0; + $csvFile = fopen($csvFilename, 'r'); + while (($row = fgetcsv($csvFile)) !== false) { + $numCols = count($row); + if ($numCols < 2) { + $io->error('Skipping row with less than two columns: ' . json_encode($row)); + continue; + } + $artistName = $row[0]; + $title = $row[1]; + + $artist = $this->artistRepository->findOneBy(['name' => $artistName]); + if (!$artist) { + $artist = new Artist(); + $artist->setName($artistName); + $this->entityManager->persist($artist); + $this->entityManager->flush(); + $numNewArtists++; + } + + $releaseExists = false; + foreach ($artist->getReleases() as $artistRelease) { + if ($artistRelease->getTitle() === $title) { + $releaseExists = true; + break; + } + } + if (!$releaseExists) { + $release = new Release(); + $release->setTitle($title); + $release->setOwner($owner); + $release->addArtist($artist); + $this->entityManager->persist($release); + $this->entityManager->flush(); + $numNewReleases++; + } else { + $numSkippedReleases++; + } + } + fclose($csvFile); + + $io->success( + 'Import successful:' + . " $numNewArtists new artists," + . " $numNewReleases new releases ($numSkippedReleases skipped)." + ); + return Command::SUCCESS; + } +}