Issues (41)

src/protected/models/VideoLibrary.php (7 issues)

1
<?php
2
3
/**
4
 * Helper class for fetching library-related data
5
 *
6
 * @author Sam Stenvall <[email protected]>
7
 * @copyright Copyright &copy; Sam Stenvall 2013-
8
 * @license https://www.gnu.org/licenses/gpl.html The GNU General Public License v3.0
9
 */
10
class VideoLibrary
11
{
12
13
	const GENRE_TYPE_MOVIE = 'movie';
14
	const GENRE_TYPE_TVSHOW = 'tvshow';
15
	const SORT_ORDER_ASCENDING = 'ascending';
16
	
17
	/**
18
	 * @var string[] default properties for movies
19
	 */
20
	private static $_defaultMovieProperties = array(
21
		'year', 'genre', 'thumbnail', 'art', 'rating', 'runtime', 'playcount', 'dateadded', 'premiered'
22
	);
23
24
	/**
25
	 * @var string[] default properties for TV shows
26
	 */
27
	private static $_defaultTVShowProperties = array(
28
		'year', 'genre', 'thumbnail', 'art', 'playcount', 'premiered',
29
	);
30
31
	/**
32
	 * @var string[] default properties for episodes
33
	 */
34
	private static $_defaultEpisodeProperties = array(
35
		'plot', 'runtime', 'season', 'episode', 'streamdetails', 'thumbnail',
36
		'file', 'title', 'tvshowid', 'showtitle', 'playcount',
37
	);
38
	
39
	/**
40
	 * Returns all genres available for the specified media type (default to 
41
	 * movie genres).
42
	 * @param string $type the media type (see class constants)
43
	 * @return array the list of genres
44
	 */
45
	public static function getGenres($type = self::GENRE_TYPE_MOVIE)
46
	{
47
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetGenres', array(
48
			'type'=>$type, 'sort'=>array(
49
				'order'=>self::SORT_ORDER_ASCENDING, 'method'=>'label')));
50
51
		return self::normalizeResponse($response, 'genres', array());
52
	}
53
	
54
	/**
55
	 * Returns a list of all actors. 
56
	 * @param string $mediaType the media type to fetch actors for (movies or 
57
	 * TV shows)
58
	 * @return Actor[] the actors
59
	 */
60
	public static function getActors($mediaType)
61
	{
62
		// Fetch the list of all works
63
		$works = array();
64
		
65
		if ($mediaType === Actor::MEDIA_TYPE_MOVIE)
66
			$works = VideoLibrary::getMovies(array('properties'=>array('cast')));
67
		elseif ($mediaType === Actor::MEDIA_TYPE_TVSHOW)
68
			$works = VideoLibrary::getTVShows(array('properties'=>array('cast')));
69
70
		// Build a list of all unique actors
71
		$actors = array();
72
73
		foreach ($works as $work)
74
			$actors = array_merge($actors, $work->cast);
75
76
		// array_unique compares by string
77
		return array_unique($actors);
78
	}
79
	
80
	/**
81
	 * @return array list of all movie directors
82
	 */
83
	public static function getDirectors()
84
	{
85
		// Fetch the list of all movies
86
		$movies = VideoLibrary::getMovies(array('properties'=>array('director')));
87
		$directors = array();
88
89
		foreach ($movies as $movie)
90
			$directors = array_merge($directors, $movie->director);
91
92
		// We want this to be an array with just values, the keys don't matter
93
		return array_values(array_unique($directors));
94
	}
95
96
	/**
97
	 * Returns a list of movies
98
	 * @param array $params request parameters
99
	 * @return Movie[] the movies
100
	 */
101
	public static function getMovies($params = array())
102
	{
103
		self::addDefaultSort($params, 'sorttitle');
104
		self::defaultProperties($params, self::$_defaultMovieProperties);
105
		
106
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetMovies', $params);
107
108
		return self::normalizeResponse($response, 'movies', array(), new Movie());
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::normalizeRe..., array(), new Movie()) also could return the type Movie which is incompatible with the documented return type Movie[].
Loading history...
109
	}
110
	
111
	/**
112
	 * Returns the recently added movies
113
	 * @return Movie[] the movies
114
	 */
115
	public static function getRecentlyAddedMovies($params = array())
116
	{
117
		self::defaultProperties($params, self::$_defaultMovieProperties);
118
119
		// The grid shows six items per row, we don't want the 25th item to be 
120
		// lonely
121
		$params['limits'] = new stdClass();
122
		$params['limits']->end = 24;
123
124
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetRecentlyAddedMovies', $params);
125
126
		return self::normalizeResponse($response, 'movies', array(), new Movie());
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::normalizeRe..., array(), new Movie()) also could return the type Movie which is incompatible with the documented return type Movie[].
Loading history...
127
	}
128
129
	/**
130
	 * Returns details about the specified movie. The properties array 
131
	 * specifies which movie attributes to return.
132
	 * @param int $movieId the movie ID
133
	 * @param string[] $properties the properties to include in the result
134
	 * @return Movie the movie details
135
	 */
136
	public static function getMovieDetails($movieId, $properties)
137
	{
138
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetMovieDetails', array(
139
			'movieid'=>(int)$movieId,
140
			'properties'=>$properties));
141
142
		return self::normalizeResponse($response, 'moviedetails', null, new Movie());
143
	}
144
	
145
	/**
146
	 * Returns a list of TV shows. If no sort mechanism is specified in 
147
	 * @params the result will be sorted alphabetically by title.
148
	 * @param array $params request parameters
149
	 * @return TVShow[] the TV shows
150
	 */
151
	public static function getTVShows($params = array())
152
	{
153
		self::addDefaultSort($params);
154
		self::defaultProperties($params, self::$_defaultTVShowProperties);
155
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetTVShows', $params);
156
157
		return self::normalizeResponse($response, 'tvshows', array(), new TVShow());
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::normalizeRe... array(), new TVShow()) also could return the type TVShow which is incompatible with the documented return type TVShow[].
Loading history...
158
	}
159
	
160
	/**
161
	 * Returns the recently added episodes
162
	 * @param array $params (optional) request parameters
163
	 * @return Episode[] the recently added episodes
164
	 */
165
	public static function getRecentlyAddedEpisodes($params = array())
166
	{
167
		self::defaultProperties($params, self::$_defaultEpisodeProperties);
168
		
169
		$response = Yii::app()->xbmc->performRequest(
170
				'VideoLibrary.GetRecentlyAddedEpisodes', $params);
171
172
		return self::normalizeResponse($response, 'episodes', array(), new Episode());
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::normalizeRe...array(), new Episode()) also could return the type Episode which is incompatible with the documented return type Episode[].
Loading history...
173
	}
174
	
175
	/**
176
	 * Returns details about the specified TV show. The properties array 
177
	 * specifies which attributes to return.
178
	 * @param int $tvshowId the show ID
179
	 * @param string[] $properties the properties to include in the result
180
	 * @return TVShow the show details
181
	 * @throws CHttpException if the show was not found
182
	 */
183
	public static function getTVShowDetails($tvshowId, $properties)
184
	{
185
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetTVShowDetails', array(
186
			'tvshowid'=>(int)$tvshowId,
187
			'properties'=>$properties));
188
189
		return self::normalizeResponse($response, 'tvshowdetails', null, new TVShow());
190
	}
191
	
192
	/**
193
	 * Returns the season for the specified TV show, sorted alphabetically
194
	 * @param int $tvshowId the TV show ID
195
	 * @return Season[] the seasons
196
	 */
197
	public static function getSeasons($tvshowId)
198
	{
199
		$params = array('tvshowid'=>(int)$tvshowId, 
200
			'properties'=>array('season', 'art', 'episode', 'showtitle', 'tvshowid', 'playcount'));
201
		
202
		self::addDefaultSort($params);
203
		
204
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetSeasons', 
205
				$params);
206
		
207
		return self::normalizeResponse($response, 'seasons', array(), new Season());
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::normalizeRe... array(), new Season()) also could return the type Season which is incompatible with the documented return type Season[].
Loading history...
208
	}
209
	
210
	/**
211
	 * Returns information about a single season
212
	 * @param int $tvshowId the tv show ID
213
	 * @param int $season the season number
214
	 * @return Season the season details
215
	 * @throws PageNotFoundException if the season is not found
216
	 */
217
	public static function getSeasonDetails($tvshowId, $season)
218
	{
219
		$seasons = self::getSeasons($tvshowId);
220
221
		foreach ($seasons as $seasonObj)
222
			if ($seasonObj->season == $season)
223
				return $seasonObj;
224
225
		throw new PageNotFoundException();
226
	}
227
228
	/**
229
	 * Returns the episodes for the specified show and season
230
	 * @param int $tvshowId the TV show ID
231
	 * @param int $season the season number
232
	 * @param array $properties properties to include in the results. Defaults 
233
	 * to null, meaning the default properties for episodes will be included
234
	 * @return Episode[] the episodes
235
	 */
236
	public static function getEpisodes($tvshowId, $season, $properties = null)
237
	{
238
		$params = array(
239
			'tvshowid'=>(int)$tvshowId, 
240
			'season'=>(int)$season);
241
		
242
		self::addDefaultSort($params);
243
		
244
		if ($properties === null)
245
			self::defaultProperties($params, self::$_defaultEpisodeProperties);
246
		else
247
			$params['properties'] = $properties;
248
		
249
		$response = Yii::app()->xbmc->performRequest(
250
				'VideoLibrary.GetEpisodes', $params);
251
252
		return self::normalizeResponse($response, 'episodes', array(), new Episode());
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::normalizeRe...array(), new Episode()) also could return the type Episode which is incompatible with the documented return type Episode[].
Loading history...
253
	}
254
	
255
	/**
256
	 * Returns details about the specified TV show episode
257
	 * @param int $episodeId the episode ID
258
	 * @param string[] $properties the properties to include in the result
259
	 * @return Episode the episode details
260
	 */
261
	public static function getEpisodeDetails($episodeId, $properties)
262
	{
263
		$response = Yii::app()->xbmc->performRequest('VideoLibrary.GetEpisodeDetails', array(
264
			'episodeid'=>(int)$episodeId,
265
			'properties'=>$properties));
266
267
		return self::normalizeResponse($response, 'episodedetails', null, new Episode());
268
	}
269
	
270
	/**
271
	 * Returns an array with the download links for a video. It takes a file
272
	 * string from e.g. VideoLibrary.GetVideoDetails as parameter.
273
	 * @param string $file a file string returned from the API
274
	 * @param boolean $omitCredentials whether URL credentials should be 
275
	 * omitted
276
	 * @return array the download links
277
	 * @throws CHttpException if the files have been deleted from disk while
278
	 * the item is still in the library
279
	 */
280
	public static function getVideoLinks($file, $omitCredentials = false)
281
	{
282
		$files = array();
283
284
		foreach (self::parseStackedFile($file) as $rawFile)
285
		{
286
			// Create the URL to the file. If the file has been deleted from
287
			// disc but the movie still exists in the library the API call 
288
			// throws an exception. We just skip this file if that's the case.
289
			try
290
			{
291
				$response = Yii::app()->xbmc->performRequest(
292
						'Files.PrepareDownload', array('path'=>$rawFile));
293
				
294
				$files[] = Yii::app()->xbmc->getVFSHelper()->getUrl(
295
						$response->result->details->path, $omitCredentials);
296
			}
297
			catch(CHttpException $e)
298
			{
299
				$files[] = false;
300
			}
301
		}
302
303
		return $files;
304
	}
305
	
306
	/**
307
	 * Parses potential stack:// files into an array of "normal" VFS URLs
308
	 * @param string $file a VFS URL (potentially stack://)
309
	 * @return array list of files
310
	 */
311
	private static function parseStackedFile($file)
312
	{
313
		if (strpos($file, 'stack://') === false)
314
			return array($file);
315
		
316
		$files = preg_split('/ , /i', $file);
317
318
		// Remove stack:// from the first item
319
		$files[0] = substr($files[0], 8);
320
		
321
		return $files;
322
	}
323
	
324
	/**
325
	 * Adds the specified sort method to the request parameters. The sort 
326
	 * method defaults to "label":
327
	 * @param array $params the parameters
328
	 * @param string $sortMethod the sort method to use
329
	 */
330
	private static function addDefaultSort(&$params, $sortMethod = 'label')
331
	{
332
		if (!isset($params['sort']))
333
		{
334
			$params['sort'] = array(
335
				'order'=>self::SORT_ORDER_ASCENDING,
336
				'ignorearticle'=>Setting::getBoolean('ignoreArticle'),
337
				'method'=>$sortMethod);
338
		}
339
	}
340
	
341
	/**
342
	 * Ensures that the specified properties are specified in 
343
	 * params['properties']. If properties have already been defined they 
344
	 * remain untouched
345
	 * @param array $params the parameters
346
	 * @param string[] $properties the properties
347
	 */
348
	private static function defaultProperties(&$params, $properties)
349
	{
350
		if (!isset($params['properties']))
351
			$params['properties'] = $properties;
352
	}
353
354
	/**
355
	 * Returns the $resultSet from the $response object, or $defaultValue if 
356
	 * the result set is not available
357
	 * @param stdClass $response an API response object
358
	 * @param string $resultSet the name of the result set
359
	 * @param mixed $defaultValue the value to return if the result set is not 
360
	 * available
361
	 * @param mixed an instance of the class the results should be mapped to, or 
0 ignored issues
show
The type an 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...
362
	 * null to use stdClass
363
	 * @return mixed the normalized response
364
	 */
365
	private static function normalizeResponse($response, $resultSet, $defaultValue, $targetObject = null)
366
	{
367
		if (isset($response->result->{$resultSet}))
368
		{
369
			$result = $response->result->{$resultSet};
370
371
			if ($targetObject !== null)
372
			{
373
				$mapper = new JsonMapper();
374
				
375
				if (is_array($result))
376
					return $mapper->mapArray($result, new ArrayObject(), $targetObject::class)->getArrayCopy();
377
				elseif (is_object($result))
378
					return $mapper->map($result, $targetObject);
379
			}
380
381
			return $response->result->{$resultSet};
382
		}
383
		else
384
			return $defaultValue;
385
	}
386
387
}
388