Skip to content

Commit

Permalink
Add occ command playlist-import
Browse files Browse the repository at this point in the history
The command may be used to import one or several playlists from file(s)
for one or multiple users. If the user already has a playlist with the same
name as the file, then either option `overwrite` or `append` has to be used.

refs #832
  • Loading branch information
paulijar committed Oct 30, 2021
1 parent a72eaf7 commit 1d71064
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 3 deletions.
7 changes: 7 additions & 0 deletions appinfo/register_command.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,10 @@
$c->query('PlaylistBusinessLayer'),
$c->query('PlaylistFileService')
));
$application->add(new OCA\Music\Command\PlaylistImport(
$c->query('UserManager'),
$c->query('GroupManager'),
$c->query('RootFolder'),
$c->query('PlaylistBusinessLayer'),
$c->query('PlaylistFileService')
));
7 changes: 7 additions & 0 deletions lib/BusinessLayer/PlaylistBusinessLayer.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ public function removeTracks($trackIndices, $playlistId, $userId) {
return $playlist;
}

public function removeAllTracks($playlistId, $userId) {
$playlist = $this->find($playlistId, $userId);
$playlist->setTrackIdsFromArray([]);
$this->mapper->update($playlist);
return $playlist;
}

public function moveTrack($fromIndex, $toIndex, $playlistId, $userId) {
$playlist = $this->find($playlistId, $userId);
$trackIds = $playlist->getTrackIdsAsArray();
Expand Down
132 changes: 132 additions & 0 deletions lib/Command/PlaylistImport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php declare(strict_types=1);

/**
* ownCloud - Music app
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Pauli Järvinen <pauli.jarvinen@gmail.com>
* @copyright Pauli Järvinen 2021
*/

namespace OCA\Music\Command;

use OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
use OCA\Music\BusinessLayer\PlaylistBusinessLayer;
use OCA\Music\Db\Playlist;
use OCA\Music\Utility\PlaylistFileService;

use OCP\Files\Folder;
use OCP\Files\IRootFolder;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class PlaylistImport extends BaseCommand {
/** @var IRootFolder */
private $rootFolder;
/** @var PlaylistBusinessLayer */
private $businessLayer;
/** @var PlaylistFileService */
private $playlistFileService;

public function __construct(
\OCP\IUserManager $userManager,
\OCP\IGroupManager $groupManager,
IRootFolder $rootFolder,
PlaylistBusinessLayer $playlistBusinessLayer,
PlaylistFileService $playlistFileService) {
$this->rootFolder = $rootFolder;
$this->businessLayer = $playlistBusinessLayer;
$this->playlistFileService = $playlistFileService;
parent::__construct($userManager, $groupManager);
}

protected function doConfigure() : void {
$this
->setName('music:playlist-import')
->setDescription('import user playlist(s) from file(s)')
->addOption(
'file',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'path of the playlist file, relative to the user home folder'
)
->addOption(
'overwrite',
null,
InputOption::VALUE_NONE,
'overwrite the target playlist if it already exists'
)
->addOption(
'append',
null,
InputOption::VALUE_NONE,
'append imported tracks to an existing playlist if found'
)
;
}

protected function doExecute(InputInterface $input, OutputInterface $output, array $users) : void {
$files = $input->getOption('file');
$overwrite = (bool)$input->getOption('overwrite');
$append = (bool)$input->getOption('append');

if (empty($files)) {
throw new \InvalidArgumentException('At least one <error>file</error> argument must be given');
}

if ($overwrite && $append) {
throw new \InvalidArgumentException('The options <error>overwrite</error> and <error>append</error> are mutually exclusive');
}

if ($input->getOption('all')) {
$this->userManager->callForAllUsers(function($user) use ($output, $files, $overwrite, $append) {
$this->executeForUser($user->getUID(), $files, $overwrite, $append, $output);
});
} else {
foreach ($users as $userId) {
$this->executeForUser($userId, $files, $overwrite, $append, $output);
}
}
}

private function executeForUser(string $userId, array $files, bool $overwrite, bool $append, OutputInterface $output) : void {
$output->writeln("Importing playlist(s) for <info>$userId</info>...");

$userFolder = $this->rootFolder->getUserFolder($userId);

foreach ($files as $filePath) {
$name = \pathinfo($filePath, PATHINFO_FILENAME);
$existingLists = $this->businessLayer->findAllByName($name, $userId);
if (\count($existingLists) === 0) {
$playlist = $this->businessLayer->create($name, $userId);
} elseif (!$overwrite && !$append) {
$output->writeln(" The playlist <error>$name</error> already exists, give argument <info>overwrite</info> or <info>append</info>");
$playlist = null;
} else {
$playlist = $existingLists[0];
}

if ($playlist !== null) {
$this->importPlaylist($filePath, $playlist, $userId, $userFolder, $overwrite, $output);
}
}
}

private function importPlaylist(string $filePath, Playlist $playlist, string $userId, Folder $userFolder, bool $overwrite, OutputInterface $output) : void {
try {
$id = $playlist->getId();
$result = $this->playlistFileService->importFromFile($playlist->getId(), $userId, $userFolder, $filePath, $overwrite ? 'overwrite' : 'append');
$output->writeln(" <info>{$result['imported_count']}</info> tracks were imported to playlist <info>$id</info> from <info>$filePath</info>");
} catch (BusinessLayerException $ex) {
$output->writeln(" User <info>$userId</info> has no playlist with id <error>$id</error>");
} catch (\OCP\Files\NotFoundException $ex) {
$output->writeln(" Invalid file path <error>$filePath</error>");
} catch (\UnexpectedValueException $ex) {
$output->writeln(" The file <error>$filePath</error> is not a supported playlist file");
}
}
}
12 changes: 9 additions & 3 deletions lib/Utility/PlaylistFileService.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function __construct(
* @throws \OCP\Files\NotPermittedException if the user is not allowed to write to the given folder
*/
public function exportToFile(
int $id, string $userId, Folder $userFolder, string $folderPath, string $collisionMode) : string {
int $id, string $userId, Folder $userFolder, string $folderPath, string $collisionMode='abort') : string {
$playlist = $this->playlistBusinessLayer->find($id, $userId);
$tracks = $this->playlistBusinessLayer->getPlaylistTracks($id, $userId);
$targetFolder = Util::getFolderFromRelativePath($userFolder, $folderPath);
Expand Down Expand Up @@ -113,7 +113,7 @@ public function exportToFile(
* @throws \OCP\Files\NotPermittedException if the user is not allowed to write to the given folder
*/
public function exportRadioStationsToFile(
string $userId, Folder $userFolder, string $folderPath, string $filename, string $collisionMode) : string {
string $userId, Folder $userFolder, string $folderPath, string $filename, string $collisionMode='abort') : string {
$targetFolder = Util::getFolderFromRelativePath($userFolder, $folderPath);

$filename = self::checkFileNameConflict($targetFolder, $filename, $collisionMode);
Expand All @@ -137,6 +137,9 @@ public function exportRadioStationsToFile(
* @param string $userId owner of the playlist
* @param Folder $userFolder user home dir
* @param string $filePath path of the file to import
* @parma string $mode one of the following:
* - 'append' (dafault) Append the imported tracks after the existing tracks on the list
* - 'overwrite' Replace any previous tracks on the list with the imported tracks
* @return array with three keys:
* - 'playlist': The Playlist entity after the modification
* - 'imported_count': An integer showing the number of tracks imported
Expand All @@ -145,7 +148,7 @@ public function exportRadioStationsToFile(
* @throws \OCP\Files\NotFoundException if the $filePath is not a valid file
* @throws \UnexpectedValueException if the $filePath points to a file of unsupported type
*/
public function importFromFile(int $id, string $userId, Folder $userFolder, string $filePath) : array {
public function importFromFile(int $id, string $userId, Folder $userFolder, string $filePath, string $mode='append') : array {
$parsed = self::doParseFile(self::getFile($userFolder, $filePath), $userFolder, self::PARSE_LOCAL_FILES_ONLY);
$trackFilesAndCaptions = $parsed['files'];
$invalidPaths = $parsed['invalid_paths'];
Expand All @@ -160,6 +163,9 @@ public function importFromFile(int $id, string $userId, Folder $userFolder, stri
}
}

if ($mode === 'overwrite') {
$this->playlistBusinessLayer->removeAllTracks($id, $userId);
}
$playlist = $this->playlistBusinessLayer->addTracks($trackIds, $id, $userId);

if (\count($invalidPaths) > 0) {
Expand Down

0 comments on commit 1d71064

Please sign in to comment.