Issues (263)

lib/Service/SearchMediaService.php (4 issues)

1
<?php
2
/**
3
 * Nextcloud - Gallery
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Olivier Paroz <[email protected]>
9
 *
10
 * @copyright Olivier Paroz 2017
11
 */
12
13
namespace OCA\Gallery\Service;
14
15
use OCP\Files\Folder;
0 ignored issues
show
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...
16
use OCP\Files\File;
0 ignored issues
show
The type OCP\Files\File 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...
17
18
/**
19
 * Searches the instance for media files which can be shown
20
 *
21
 * @package OCA\Gallery\Service
22
 */
23
class SearchMediaService extends FilesService {
24
25
	/** @var null|array<string,string|int> */
26
	private $images = [];
27
	/** @var null|array<string,string|int> */
28
	private $albums = [];
29
	/** @var string[] */
30
	private $supportedMediaTypes;
31
32
	/**
33
	 * This returns the list of all media files which can be shown starting from the given folder
34
	 *
35
	 * @param Folder $folderNode the current album
36
	 * @param string[] $supportedMediaTypes the list of supported media types
37
	 * @param array $features the list of supported features
38
	 *
39
	 * @return array<null|array<string,string|int>> all the images we could find
40
	 */
41
	public function getMediaFiles($folderNode, $supportedMediaTypes, $features) {
42
		$this->supportedMediaTypes = $supportedMediaTypes;
43
		$this->features = $features;
44
		$this->searchFolder($folderNode);
45
46
		return [$this->images, $this->albums];
47
	}
48
49
	/**
50
	 * Look for media files and folders in the given folder
51
	 *
52
	 * @param Folder $folder
53
	 * @param int $subDepth
54
	 *
55
	 * @return int
56
	 */
57
	private function searchFolder($folder, $subDepth = 0) {
58
		$albumImageCounter = 0;
59
		$subFolders = [];
60
		$this->addFolderToAlbumsArray($folder);
61
		$nodes = $this->getNodes($folder, $subDepth);
62
		foreach ($nodes as $node) {
63
			if (!$this->isAllowedAndAvailable($node)) {
64
				continue;
65
			}
66
			$nodeType = $this->getNodeType($node);
67
			$subFolders = array_merge($subFolders, $this->getAllowedSubFolder($node, $nodeType));
68
			$albumImageCounter = $this->addMediaFile($node, $nodeType, $albumImageCounter);
69
			if ($this->haveEnoughPictures($albumImageCounter, $subDepth)) {
70
				break;
71
			}
72
		}
73
		$albumImageCounter = $this->searchSubFolders($subFolders, $subDepth, $albumImageCounter);
74
75
		return $albumImageCounter;
76
	}
77
78
	/**
79
	 * Adds the node to the list of images if it's a file and we can generate a preview of it
80
	 *
81
	 * @param File|Folder $node
82
	 * @param string $nodeType
83
	 * @param int $albumImageCounter
84
	 *
85
	 * @return int
86
	 */
87
	private function addMediaFile($node, $nodeType, $albumImageCounter) {
88
		if ($nodeType === 'file') {
89
			$albumImageCounter = $albumImageCounter + (int)$this->isPreviewAvailable($node);
90
		}
91
92
		return $albumImageCounter;
93
	}
94
95
	/**
96
	 * Checks if we've collected enough pictures to be able to build the view
97
	 *
98
	 * An album is full when we find max 4 pictures at the same level
99
	 *
100
	 * @param int $albumImageCounter
101
	 * @param int $subDepth
102
	 *
103
	 * @return bool
104
	 */
105
	private function haveEnoughPictures($albumImageCounter, $subDepth) {
106
		if ($subDepth === 0) {
107
			return false;
108
		}
109
110
		return $albumImageCounter === 4;
111
	}
112
113
	/**
114
	 * Looks for pictures in sub-folders
115
	 *
116
	 * If we're at level 0, we need to look for pictures in sub-folders no matter what
117
	 * If we're at deeper levels, we only need to go further if we haven't managed to find one
118
	 * picture in the current folder
119
	 *
120
	 * @param array <Folder> $subFolders
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Folder> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Folder>.
Loading history...
121
	 * @param int $subDepth
122
	 * @param int $albumImageCounter
123
	 *
124
	 * @return int
125
	 */
126
	private function searchSubFolders($subFolders, $subDepth, $albumImageCounter) {
127
		if ($this->folderNeedsToBeSearched($subFolders, $subDepth, $albumImageCounter)) {
128
			$subDepth++;
129
			foreach ($subFolders as $subFolder) {
130
				//$this->logger->debug("Sub-Node path : {path}", ['path' => $subFolder->getPath()]);
131
				$albumImageCounter = $this->searchFolder($subFolder, $subDepth);
132
				if ($this->abortSearch($subDepth, $albumImageCounter)) {
133
					break;
134
				}
135
			}
136
		}
137
138
		return $albumImageCounter;
139
	}
140
141
	/**
142
	 * Checks if we need to look for media files in the specified folder
143
	 *
144
	 * @param array <Folder> $subFolders
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Folder> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Folder>.
Loading history...
145
	 * @param int $subDepth
146
	 * @param int $albumImageCounter
147
	 *
148
	 * @return bool
149
	 */
150
	private function folderNeedsToBeSearched($subFolders, $subDepth, $albumImageCounter) {
151
		return !empty($subFolders) && ($subDepth === 0 || $albumImageCounter === 0);
152
	}
153
154
	/**
155
	 * Returns true if there is no need to check any other sub-folder at the same depth level
156
	 *
157
	 * @param int $subDepth
158
	 * @param int $count
159
	 *
160
	 * @return bool
161
	 */
162
	private function abortSearch($subDepth, $count) {
163
		return $subDepth > 1 && $count > 0;
164
	}
165
166
	/**
167
	 * Returns true if the file is of a supported media type and adds it to the array of items to
168
	 * return
169
	 *
170
	 * @todo We could potentially check if the file is readable ($file->stat() maybe) in order to
171
	 *     only return valid files, but this may slow down operations
172
	 *
173
	 * @param File $file the file to test
174
	 *
175
	 * @return bool
176
	 */
177
	private function isPreviewAvailable($file) {
178
		try {
179
			$mimeType = $file->getMimeType();
180
			if (in_array($mimeType, $this->supportedMediaTypes)) {
181
				$this->addFileToImagesArray($mimeType, $file);
182
183
				return true;
184
			}
185
		} catch (\Exception $exception) {
186
			return false;
187
		}
188
189
		return false;
190
	}
191
192
	/**
193
	 * Adds a folder to the albums array
194
	 *
195
	 * @param Folder $folder the folder to add to the albums array
196
	 */
197
	private function addFolderToAlbumsArray($folder) {
198
		$albumData = $this->getFolderData($folder);
199
		$this->albums[$albumData['path']] = $albumData;
200
	}
201
202
	/**
203
	 * Adds a file to the images array
204
	 *
205
	 * @param string $mimeType the media type of the file to add to the images array
206
	 * @param File $file the file to add to the images array
207
	 */
208
	private function addFileToImagesArray($mimeType, $file) {
209
		$imageData = $this->getNodeData($file);
210
		$imageData['mimetype'] = $mimeType;
211
		$this->images[] = $imageData;
212
	}
213
214
}
215