Passed
Push — feature/playlist_improvements ( e80580...0cb3ef )
by Pauli
12:06
created

PlaylistFileService::exportToFile()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 32
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 23
c 1
b 0
f 0
nc 10
nop 3
dl 0
loc 32
rs 8.9297
1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Pauli Järvinen <[email protected]>
10
 * @copyright Pauli Järvinen 2020
11
 */
12
13
namespace OCA\Music\Utility;
14
15
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
16
use \OCA\Music\AppFramework\Core\Logger;
17
use \OCA\Music\BusinessLayer\PlaylistBusinessLayer;
18
use \OCA\Music\BusinessLayer\TrackBusinessLayer;
19
20
use \OCP\Files\Folder;
0 ignored issues
show
Bug introduced by
The type OCP\Files\Folder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use \OCP\IConfig;
0 ignored issues
show
Bug introduced by
The type OCP\IConfig was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
23
/**
24
 * Class responsible of exporting playlists to file and importing playlist
25
 * contents from file.
26
 */
27
class PlaylistFileService {
28
	private $playlistBusinessLayer;
29
	private $trackBusinessLayer;
30
	private $userFolder;
31
	private $userId;
32
	private $logger;
33
34
	public function __construct(
35
			PlaylistBusinessLayer $playlistBusinessLayer,
36
			TrackBusinessLayer $trackBusinessLayer,
37
			Folder $userFolder,
38
			$userId,
39
			Logger $logger) {
40
		$this->playlistBusinessLayer = $playlistBusinessLayer;
41
		$this->trackBusinessLayer = $trackBusinessLayer;
42
		$this->userFolder = $userFolder;
43
		$this->userId = $userId;
44
		$this->logger = $logger;
45
	}
46
47
	/**
48
	 * export the playlist to a file
49
	 * @param int $id playlist ID
50
	 * @param string $folderPath parent folder path
51
	 * @param string $collisionMode action to take on file name collision,
52
	 *								supported values:
53
	 *								- 'overwrite' The existing file will be overwritten
54
	 *								- 'keepboth' The new file is named with a suffix to make it unique
55
	 *								- 'abort' (default) The operation will fail
56
	 * @return string path of the written file
57
	 * @throws BusinessLayerException if playlist with ID not found
58
	 * @throws \OCP\Files\NotFoundException if the $folderPath is not a valid folder
59
	 * @throws \RuntimeException on name conflict if $collisionMode == 'abort'
60
	 * @throws \OCP\Files\NotPermittedException if the user is not allowed to write to the given folder
61
	 */
62
	public function exportToFile($id, $folderPath, $collisionMode) {
63
		$playlist = $this->playlistBusinessLayer->find($id, $this->userId);
64
		$tracks = $this->playlistBusinessLayer->getPlaylistTracks($id, $this->userId);
65
		$targetFolder = Util::getFolderFromRelativePath($this->userFolder, $folderPath);
66
67
		$filename = \str_replace('/', '-', $playlist->getName()) . '.m3u8';
68
69
		if ($targetFolder->nodeExists($filename)) {
70
			switch ($collisionMode) {
71
				case 'overwrite':
72
					$targetFolder->get($filename)->delete();
73
					break;
74
				case 'keepboth':
75
					$filename = $targetFolder->getNonExistingName($filename);
76
					break;
77
				default:
78
					throw new \RuntimeException('file already exists');
79
			}
80
		}
81
82
		$content = "#EXTM3U\n#EXTENC: UTF-8\n";
83
		foreach ($tracks as $track) {
84
			$nodes = $this->userFolder->getById($track->getFileId());
85
			if (\count($nodes) > 0) {
86
				$content .= "#EXTINF:{$track->getLength()},{$track->getTitle()}\n";
87
				$content .= Util::relativePath($targetFolder->getPath(), $nodes[0]->getPath()) . "\n";
88
			}
89
		}
90
		$file = $targetFolder->newFile($filename);
91
		$file->putContent($content);
92
93
		return $this->userFolder->getRelativePath($file->getPath());
94
	}
95
	
96
	/**
97
	 * export the playlist to a file
98
	 * @param int $id playlist ID
99
	 * @param string $filePath path of the file to import
100
	 * @return array with three keys:
101
	 * 			- 'playlist': The Playlist entity after the modification
102
	 * 			- 'imported_count': An integer showing the number of tracks imported
103
	 * 			- 'failed_count': An integer showing the number of tracks in the file which could not be imported
104
	 * @throws BusinessLayerException if playlist with ID not found
105
	 * @throws \OCP\Files\NotFoundException if the $filePath is not a valid file
106
	 */
107
	public function importFromFile($id, $filePath) {
108
		$file = $this->userFolder->get($filePath);
109
110
		$trackIds = [];
111
		$failedCount = 0;
112
113
		$cwd = \dirname($filePath);
114
		$fp = $file->fopen('r');
115
		while ($line = \fgets($fp)) {
116
			$line = \trim($line);
117
			if (Util::startsWith($line, '#')) {
118
				// comment line
119
			} else {
120
				$path = Util::resolveRelativePath($cwd, $line);
121
				try {
122
					$trackFile = $this->userFolder->get($path);
123
					if ($track = $this->trackBusinessLayer->findByFileId($trackFile->getId(), $this->userId)) {
124
						$trackIds[] = $track->getId();
125
					} else {
126
						$failedCount++;
127
					}
128
				}
129
				catch (\OCP\Files\NotFoundException $ex) {
0 ignored issues
show
Bug introduced by
The type OCP\Files\NotFoundException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
130
					$failedCount++;
131
				}
132
			}
133
		}
134
		\fclose($fp);
135
136
		$playlist = $this->playlistBusinessLayer->addTracks($trackIds, $id, $this->userId);
137
138
		return [
139
			'playlist' => $playlist,
140
			'imported_count' => \count($trackIds),
141
			'failed_count' => $failedCount
142
		];
143
	}	
144
}
145