Passed
Push — master ( 434539...a69bb2 )
by Pauli
03:06
created

ShareController::parsePlaylist()   A

Complexity

Conditions 5
Paths 13

Size

Total Lines 33
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 27
c 2
b 0
f 0
nc 13
nop 2
dl 0
loc 33
rs 9.1768
1
<?php declare(strict_types=1);
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 2018 - 2025
11
 */
12
13
namespace OCA\Music\Controller;
14
15
use OCP\AppFramework\Controller;
16
use OCP\AppFramework\Http;
17
use OCP\AppFramework\Http\JSONResponse;
18
use OCP\Files\File;
19
use OCP\Files\Folder;
20
use OCP\IRequest;
21
use OCP\Share\IManager;
22
use OCP\Share\Exceptions\ShareNotFound;
23
24
use OCA\Music\AppFramework\Core\Logger;
25
use OCA\Music\Http\ErrorResponse;
26
use OCA\Music\Http\FileStreamResponse;
27
use OCA\Music\Utility\PlaylistFileService;
28
use OCA\Music\Utility\Scanner;
29
30
/**
31
 * End-points for shared audio file handling. Methods of this class may be
32
 * used while there is no user logged in.
33
 */
34
class ShareController extends Controller {
35
36
	private IManager $shareManager;
37
	private Scanner $scanner;
38
	private PlaylistFileService $playlistFileService;
39
	private Logger $logger;
40
41
	public function __construct(string $appname,
42
								IRequest $request,
43
								Scanner $scanner,
44
								PlaylistFileService $playlistFileService,
45
								Logger $logger,
46
								IManager $shareManager) {
47
		parent::__construct($appname, $request);
48
		$this->shareManager = $shareManager;
49
		$this->scanner = $scanner;
50
		$this->playlistFileService = $playlistFileService;
51
		$this->logger = $logger;
52
	}
53
54
	/**
55
	 * @PublicPage
56
	 * @NoCSRFRequired
57
	 */
58
	public function fileInfo(string $token, int $fileId) {
59
		$share = $this->shareManager->getShareByToken($token);
60
		$fileOwner = $share->getShareOwner();
61
		$fileOwnerHome = $this->scanner->resolveUserFolder($fileOwner);
62
63
		// If non-zero fileId is given, the $share identified by the token should
64
		// be the file's parent directory. Otherwise the share is the target file.
65
		if ($fileId == 0) {
66
			$fileId = $share->getNodeId();
67
		} else {
68
			$folderId = $share->getNodeId();
69
			$matchingFolders = $fileOwnerHome->getById($folderId);
70
			$folder = $matchingFolders[0] ?? null;
71
			if (!($folder instanceof Folder) || empty($folder->getById($fileId))) {
72
				// no such shared folder or the folder does not contain the given file
73
				$fileId = -1;
74
			}
75
		}
76
77
		$info = $this->scanner->getFileInfo($fileId, $fileOwner, $fileOwnerHome);
78
79
		if ($info) {
80
			return new JSONResponse($info);
81
		} else {
82
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
83
		}
84
	}
85
86
	/**
87
	 * @PublicPage
88
	 * @NoCSRFRequired
89
	 */
90
	public function download(string $token, int $fileId) {
91
		try {
92
			$sharedFolder = $this->getSharedFolder($token);
93
			$file = $sharedFolder->getById($fileId)[0] ?? null;
94
			if ($file instanceof File) {
95
				return new FileStreamResponse($file);
96
			} else {
97
				return new ErrorResponse(Http::STATUS_NOT_FOUND, 'no such file under the share');
98
			}
99
		} catch (ShareNotFound $ex) {
100
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'invalid share token');
101
		} catch (\OCP\Files\NotFoundException $ex) {
102
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'the share is not a valid folder');
103
		}
104
	}
105
106
	/**
107
	 * @PublicPage
108
	 * @NoCSRFRequired
109
	 */
110
	public function parsePlaylist(string $token, int $fileId) {
111
		try {
112
			$sharedFolder = $this->getSharedFolder($token);
113
			$result = $this->playlistFileService->parseFile($fileId, $sharedFolder);
114
115
			$bogusUrlId = -1;
116
117
			// compose the final result
118
			$result['files'] = \array_map(function ($fileInfo) use ($sharedFolder, &$bogusUrlId) {
119
				if (isset($fileInfo['url'])) {
120
					$fileInfo['id'] = $bogusUrlId--;
121
					$fileInfo['mimetype'] = null;
122
					$fileInfo['external'] = true;
123
					return $fileInfo;
124
				} else {
125
					$file = $fileInfo['file'];
126
					return [
127
						'id' => $file->getId(),
128
						'name' => $file->getName(),
129
						'path' => $sharedFolder->getRelativePath($file->getParent()->getPath()),
130
						'mimetype' => $file->getMimeType(),
131
						'caption' => $fileInfo['caption'],
132
						'external' => false
133
					];
134
				}
135
			}, $result['files']);
136
			return new JSONResponse($result);
137
		} catch (ShareNotFound $ex) {
138
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'invalid share token');
139
		} catch (\OCP\Files\NotFoundException $ex) {
140
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'playlist file not found');
141
		} catch (\UnexpectedValueException $ex) {
142
			return new ErrorResponse(Http::STATUS_UNSUPPORTED_MEDIA_TYPE, $ex->getMessage());
143
		}
144
	}
145
146
	private function getSharedFolder(string $token) : Folder {
147
		$share = $this->shareManager->getShareByToken($token);
148
		$fileOwner = $share->getShareOwner();
149
		$fileOwnerHome = $this->scanner->resolveUserFolder($fileOwner);
150
151
		$matchingFolders = $fileOwnerHome->getById($share->getNodeId());
152
		$folder = $matchingFolders[0] ?? null;
153
		if (!($folder instanceof Folder)) {
154
			throw new \OCP\Files\NotFoundException();
155
		}
156
157
		return $folder;
158
	}
159
}
160