aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api
diff options
context:
space:
mode:
authorEric Reed <ebr@mediabrowser3.com>2013-03-11 11:03:41 -0400
committerEric Reed <ebr@mediabrowser3.com>2013-03-11 11:03:41 -0400
commit6470c62c5048dd22caff3a2f4cb296e7e0e5937a (patch)
treea566b28ca659291da99bdded88b4b366cc2572e1 /MediaBrowser.Api
parent889bd32e9e798fe816f4ae1d0051e755c30eac5e (diff)
parent39020714f75b1bd1fe41355d4e9dadc9620ed8a1 (diff)
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
Diffstat (limited to 'MediaBrowser.Api')
-rw-r--r--MediaBrowser.Api/Javascript/ApiClient.js1387
-rw-r--r--MediaBrowser.Api/Javascript/JavascriptApiClientService.cs59
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs1
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj3
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs8
-rw-r--r--MediaBrowser.Api/Playback/Hls/AudioHlsService.cs4
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs6
-rw-r--r--MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs21
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs1
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs57
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs58
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs339
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs1
15 files changed, 106 insertions, 1843 deletions
diff --git a/MediaBrowser.Api/Javascript/ApiClient.js b/MediaBrowser.Api/Javascript/ApiClient.js
deleted file mode 100644
index 31022de382..0000000000
--- a/MediaBrowser.Api/Javascript/ApiClient.js
+++ /dev/null
@@ -1,1387 +0,0 @@
-/**
- * Represents a javascript version of ApiClient.
- * This should be kept up to date with all possible api methods and parameters
- */
-var ApiClient = {
-
- serverProtocol: "http",
-
- /**
- * Gets or sets the host name of the server
- */
- serverHostName: "localhost",
-
- serverPortNumber: 8096,
-
- /**
- * Detects the hostname and port of MB server based on the current url
- */
- inferServerFromUrl: function () {
-
- var loc = window.location;
-
- ApiClient.serverProtocol = loc.protocol;
- ApiClient.serverHostName = loc.hostname;
- ApiClient.serverPortNumber = loc.port;
- },
-
- /**
- * Creates an api url based on a handler name and query string parameters
- * @param {String} name
- * @param {Object} params
- */
- getUrl: function (name, params) {
-
- if (!name) {
- throw new Error("Url name cannot be empty");
- }
-
- params = params || {};
-
- var url = ApiClient.serverProtocol + "//" + ApiClient.serverHostName + ":" + ApiClient.serverPortNumber + "/mediabrowser/" + name;
-
- if (params) {
- url += "?" + $.param(params);
-
- }
- return url;
- },
-
- /**
- * Returns the name of the current browser
- */
- getDeviceName: function () {
-
- /*if ($.browser.chrome) {
- return "Chrome";
- }
- if ($.browser.safari) {
- return "Safari";
- }
- if ($.browser.webkit) {
- return "WebKit";
- }
- if ($.browser.msie) {
- return "Internet Explorer";
- }
- if ($.browser.firefox) {
- return "Firefox";
- }
- if ($.browser.mozilla) {
- return "Firefox";
- }
- if ($.browser.opera) {
- return "Opera";
- }*/
-
- return "Web Browser";
- },
-
- /**
- * Creates a custom api url based on a handler name and query string parameters
- * @param {String} name
- * @param {Object} params
- */
- getCustomUrl: function (name, params) {
-
- if (!name) {
- throw new Error("Url name cannot be empty");
- }
-
- params = params || {};
- params.client = "Dashboard";
- params.device = ApiClient.getDeviceName();
- params.format = "json";
-
- var url = ApiClient.serverProtocol + "//" + ApiClient.serverHostName + ":" + ApiClient.serverPortNumber + "/mediabrowser/" + name;
-
- if (params) {
- url += "?" + $.param(params);
-
- }
- return url;
- },
-
- /**
- * Gets an item from the server
- * Omit itemId to get the root folder.
- */
- getItem: function (userId, itemId) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- var url = ApiClient.getUrl("Users/" + userId + "/Items/" + itemId);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets the root folder from the server
- */
- getRootFolder: function (userId) {
-
- return ApiClient.getItem(userId);
- },
-
- /**
- * Gets the current server status
- */
- getSystemInfo: function () {
-
- var url = ApiClient.getUrl("System/Info");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets all cultures known to the server
- */
- getCultures: function () {
-
- var url = ApiClient.getUrl("Localization/cultures");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets all countries known to the server
- */
- getCountries: function () {
-
- var url = ApiClient.getUrl("Localization/countries");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets plugin security info
- */
- getPluginSecurityInfo: function () {
-
- var url = ApiClient.getUrl("Plugins/SecurityInfo");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets the directory contents of a path on the server
- */
- getDirectoryContents: function (path, options) {
-
- if (!path) {
- throw new Error("null path");
- }
-
- options = options || {};
-
- options.path = path;
-
- var url = ApiClient.getUrl("Environment/DirectoryContents", options);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a list of physical drives from the server
- */
- getDrives: function () {
-
- var url = ApiClient.getUrl("Environment/Drives");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a list of network devices from the server
- */
- getNetworkDevices: function () {
-
- var url = ApiClient.getUrl("Environment/NetworkDevices");
-
- return $.getJSON(url);
- },
-
- /**
- * Cancels a package installation
- */
- cancelPackageInstallation: function (installationId) {
-
- if (!installationId) {
- throw new Error("null installationId");
- }
-
- var url = ApiClient.getUrl("Packages/Installing/" + id);
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Installs or updates a new plugin
- */
- installPlugin: function (name, updateClass, version) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- if (!updateClass) {
- throw new Error("null updateClass");
- }
-
- var options = {
- updateClass: updateClass
- };
-
- if (version) {
- options.version = version;
- }
-
- var url = ApiClient.getUrl("Packages/Installed/" + name, options);
-
- return $.post(url);
- },
-
- /**
- * Instructs the server to perform a pending kernel reload or app restart.
- * If a restart is not currently required, nothing will happen.
- */
- performPendingRestart: function () {
-
- var url = ApiClient.getUrl("System/Restart");
-
- return $.post(url);
- },
-
- /**
- * Gets information about an installable package
- */
- getPackageInfo: function (name) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- var url = ApiClient.getUrl("Packages/" + name);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets the latest available application update (if any)
- */
- getAvailableApplicationUpdate: function () {
-
- var url = ApiClient.getUrl("Packages/Updates", { PackageType: "System" });
-
- return $.getJSON(url);
- },
-
- /**
- * Gets the latest available plugin updates (if any)
- */
- getAvailablePluginUpdates: function () {
-
- var url = ApiClient.getUrl("Packages/Updates", { PackageType: "UserInstalled" });
-
- return $.getJSON(url);
- },
-
- /**
- * Gets the virtual folder for a view. Specify a userId to get a user view, or omit for the default view.
- */
- getVirtualFolders: function (userId) {
-
- var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
-
- url = ApiClient.getUrl(url);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets all the paths of the locations in the physical root.
- */
- getPhysicalPaths: function () {
-
- var url = ApiClient.getUrl("Library/PhysicalPaths");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets the current server configuration
- */
- getServerConfiguration: function () {
-
- var url = ApiClient.getUrl("System/Configuration");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets the server's scheduled tasks
- */
- getScheduledTasks: function () {
-
- var url = ApiClient.getUrl("ScheduledTasks");
-
- return $.getJSON(url);
- },
-
- /**
- * Starts a scheduled task
- */
- startScheduledTask: function (id) {
-
- if (!id) {
- throw new Error("null id");
- }
-
- var url = ApiClient.getUrl("ScheduledTasks/Running/" + id);
-
- return $.post(url);
- },
-
- /**
- * Gets a scheduled task
- */
- getScheduledTask: function (id) {
-
- if (!id) {
- throw new Error("null id");
- }
-
- var url = ApiClient.getUrl("ScheduledTasks/" + id);
-
- return $.getJSON(url);
- },
-
- /**
- * Stops a scheduled task
- */
- stopScheduledTask: function (id) {
-
- if (!id) {
- throw new Error("null id");
- }
-
- var url = ApiClient.getUrl("ScheduledTasks/Running/" + id);
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Gets the configuration of a plugin
- * @param {String} Id
- */
- getPluginConfiguration: function (id) {
-
- if (!id) {
- throw new Error("null Id");
- }
-
- var url = ApiClient.getUrl("Plugins/" + id + "/Configuration");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a list of plugins that are available to be installed
- */
- getAvailablePlugins: function () {
-
- var url = ApiClient.getUrl("Packages", { PackageType: "UserInstalled" });
-
- return $.getJSON(url);
- },
-
- /**
- * Uninstalls a plugin
- * @param {String} Id
- */
- uninstallPlugin: function (id) {
-
- if (!id) {
- throw new Error("null Id");
- }
-
- var url = ApiClient.getUrl("Plugins/" + id);
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Removes a virtual folder from either the default view or a user view
- * @param {String} name
- */
- removeVirtualFolder: function (name, userId) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
-
- url += "/" + name;
- url = ApiClient.getUrl(url);
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Adds a virtual folder to either the default view or a user view
- * @param {String} name
- */
- addVirtualFolder: function (name, userId) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
-
- url += "/" + name;
- url = ApiClient.getUrl(url);
-
- return $.post(url);
- },
-
- /**
- * Renames a virtual folder, within either the default view or a user view
- * @param {String} name
- */
- renameVirtualFolder: function (name, newName, userId) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
-
- url += "/" + name + "/Name";
-
- url = ApiClient.getUrl(url, { newName: newName });
-
- return $.post(url);
- },
-
- /**
- * Adds an additional mediaPath to an existing virtual folder, within either the default view or a user view
- * @param {String} name
- */
- addMediaPath: function (virtualFolderName, mediaPath, userId) {
-
- if (!virtualFolderName) {
- throw new Error("null virtualFolderName");
- }
-
- if (!mediaPath) {
- throw new Error("null mediaPath");
- }
-
- var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
-
- url += "/" + virtualFolderName + "/Paths";
-
- url = ApiClient.getUrl(url, { path: mediaPath });
-
- return $.post(url);
- },
-
- /**
- * Removes a media path from a virtual folder, within either the default view or a user view
- * @param {String} name
- */
- removeMediaPath: function (virtualFolderName, mediaPath, userId) {
-
- if (!virtualFolderName) {
- throw new Error("null virtualFolderName");
- }
-
- if (!mediaPath) {
- throw new Error("null mediaPath");
- }
-
- var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
-
- url += "/" + virtualFolderName + "/Paths";
-
- url = ApiClient.getUrl(url, { path: mediaPath });
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Deletes a user
- * @param {String} id
- */
- deleteUser: function (id) {
-
- if (!id) {
- throw new Error("null id");
- }
-
- var url = ApiClient.getUrl("Users/" + id);
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Deletes a user image
- * @param {String} userId
- * @param {String} imageType The type of image to delete, based on the server-side ImageType enum.
- */
- deleteUserImage: function (userId, imageType) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- if (!imageType) {
- throw new Error("null imageType");
- }
-
- var url = ApiClient.getUrl("Users/" + userId + "/Images/" + imageType);
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Uploads a user image
- * @param {String} userId
- * @param {String} imageType The type of image to delete, based on the server-side ImageType enum.
- * @param {Object} file The file from the input element
- */
- uploadUserImage: function (userId, imageType, file) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- if (!imageType) {
- throw new Error("null imageType");
- }
-
- if (!file || !file.type.match('image.*')) {
- throw new Error("File must be an image.");
- }
-
- var deferred = $.Deferred();
-
- var reader = new FileReader();
-
- reader.onerror = function () {
- deferred.reject();
- };
-
- reader.onabort = function () {
- deferred.reject();
- };
-
- // Closure to capture the file information.
- reader.onload = function (e) {
-
- var data = window.btoa(e.target.result);
-
- var url = ApiClient.getUrl("Users/" + userId + "/Images/" + imageType);
-
- $.ajax({
- type: "POST",
- url: url,
- data: data,
- contentType: "image/" + file.name.substring(file.name.lastIndexOf('.') + 1)
-
- }).done(function (result) {
-
- deferred.resolveWith(null, [result]);
-
- }).fail(function () {
- deferred.reject();
- });
- };
-
- // Read in the image file as a data URL.
- reader.readAsBinaryString(file);
-
- return deferred.promise();
- },
-
- /**
- * Gets the list of installed plugins on the server
- */
- getInstalledPlugins: function () {
-
- var url = ApiClient.getUrl("Plugins");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a user by id
- * @param {String} id
- */
- getUser: function (id) {
-
- if (!id) {
- throw new Error("Must supply a userId");
- }
-
- var url = ApiClient.getUrl("Users/" + id);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a studio
- */
- getStudio: function (name) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- var url = ApiClient.getUrl("Studios/" + name);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a genre
- */
- getGenre: function (name) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- var url = ApiClient.getUrl("Genres/" + name);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a year
- */
- getYear: function (year) {
-
- if (!year) {
- throw new Error("null year");
- }
-
- var url = ApiClient.getUrl("Years/" + year);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a Person
- */
- getPerson: function (name) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- var url = ApiClient.getUrl("Persons/" + name);
-
- return $.getJSON(url);
- },
-
- /**
- * Gets weather info
- * @param {String} location - us zip code / city, state, country / city, country
- * Omit location to get weather info using stored server configuration value
- */
- getWeatherInfo: function (location) {
-
- var url = ApiClient.getUrl("weather", {
- location: location
- });
-
- return $.getJSON(url);
- },
-
- /**
- * Gets all users from the server
- */
- getAllUsers: function () {
-
- var url = ApiClient.getUrl("users");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets all available parental ratings from the server
- */
- getParentalRatings: function () {
-
- var url = ApiClient.getUrl("Localization/ParentalRatings");
-
- return $.getJSON(url);
- },
-
- /**
- * Gets a list of all available conrete BaseItem types from the server
- */
- getItemTypes: function (options) {
-
- var url = ApiClient.getUrl("Library/ItemTypes", options);
-
- return $.getJSON(url);
- },
-
- /**
- * Constructs a url for a user image
- * @param {String} userId
- * @param {Object} options
- * Options supports the following properties:
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getUserImageUrl: function (userId, options) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- options = options || {
- };
-
- var url = "Users/" + userId + "/Images/" + options.type;
-
- if (options.index != null) {
- url += "/" + options.index;
- }
-
- // Don't put these on the query string
- delete options.type;
- delete options.index;
-
- return ApiClient.getUrl(url, options);
- },
-
- /**
- * Constructs a url for a person image
- * @param {String} name
- * @param {Object} options
- * Options supports the following properties:
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getPersonImageUrl: function (name, options) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- options = options || {
- };
-
- var url = "Persons/" + name + "/Images/" + options.type;
-
- if (options.index != null) {
- url += "/" + options.index;
- }
-
- // Don't put these on the query string
- delete options.type;
- delete options.index;
-
- return ApiClient.getUrl(url, options);
- },
-
- /**
- * Constructs a url for a year image
- * @param {String} year
- * @param {Object} options
- * Options supports the following properties:
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getYearImageUrl: function (year, options) {
-
- if (!year) {
- throw new Error("null year");
- }
-
- options = options || {
- };
-
- var url = "Years/" + year + "/Images/" + options.type;
-
- if (options.index != null) {
- url += "/" + options.index;
- }
-
- // Don't put these on the query string
- delete options.type;
- delete options.index;
-
- return ApiClient.getUrl(url, options);
- },
-
- /**
- * Constructs a url for a genre image
- * @param {String} name
- * @param {Object} options
- * Options supports the following properties:
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getGenreImageUrl: function (name, options) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- options = options || {
- };
-
- var url = "Genres/" + name + "/Images/" + options.type;
-
- if (options.index != null) {
- url += "/" + options.index;
- }
-
- // Don't put these on the query string
- delete options.type;
- delete options.index;
-
- return ApiClient.getUrl(url, options);
- },
-
- /**
- * Constructs a url for a genre image
- * @param {String} name
- * @param {Object} options
- * Options supports the following properties:
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getStudioImageUrl: function (name, options) {
-
- if (!name) {
- throw new Error("null name");
- }
-
- options = options || {
- };
-
- var url = "Studios/" + name + "/Images/" + options.type;
-
- if (options.index != null) {
- url += "/" + options.index;
- }
-
- // Don't put these on the query string
- delete options.type;
- delete options.index;
-
- return ApiClient.getUrl(url, options);
- },
-
- /**
- * Constructs a url for an item image
- * @param {String} itemId
- * @param {Object} options
- * Options supports the following properties:
- * type - Primary, logo, backdrop, etc. See the server-side enum ImageType
- * index - When downloading a backdrop, use this to specify which one (omitting is equivalent to zero)
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getImageUrl: function (itemId, options) {
-
- if (!itemId) {
- throw new Error("itemId cannot be empty");
- }
-
- options = options || {
- };
-
- var url = "Items/" + itemId + "/Images/" + options.type;
-
- if (options.index != null) {
- url += "/" + options.index;
- }
-
- // Don't put these on the query string
- delete options.type;
- delete options.index;
-
- return ApiClient.getUrl(url, options);
- },
-
- /**
- * Constructs a url for an item logo image
- * If the item doesn't have a logo, it will inherit a logo from a parent
- * @param {Object} item A BaseItem
- * @param {Object} options
- * Options supports the following properties:
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getLogoImageUrl: function (item, options) {
-
- if (!item) {
- throw new Error("null item");
- }
-
- options = options || {
- };
-
- options.imageType = "logo";
-
- var logoItemId = item.HasLogo ? item.Id : item.ParentLogoItemId;
-
- return logoItemId ? ApiClient.getImageUrl(logoItemId, options) : null;
- },
-
- /**
- * Constructs an array of backdrop image url's for an item
- * If the item doesn't have any backdrops, it will inherit them from a parent
- * @param {Object} item A BaseItem
- * @param {Object} options
- * Options supports the following properties:
- * width - download the image at a fixed width
- * height - download the image at a fixed height
- * maxWidth - download the image at a maxWidth
- * maxHeight - download the image at a maxHeight
- * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
- * For best results do not specify both width and height together, as aspect ratio might be altered.
- */
- getBackdropImageUrl: function (item, options) {
-
- if (!item) {
- throw new Error("null item");
- }
-
- options = options || {
- };
-
- options.imageType = "backdrop";
-
- var backdropItemId;
- var backdropCount;
-
- if (!item.BackdropCount) {
- backdropItemId = item.ParentBackdropItemId;
- backdropCount = item.ParentBackdropCount || 0;
- } else {
- backdropItemId = item.Id;
- backdropCount = item.BackdropCount;
- }
-
- if (!backdropItemId) {
- return [];
- }
-
- var files = [];
-
- for (var i = 0; i < backdropCount; i++) {
-
- options.imageIndex = i;
-
- files[i] = ApiClient.getImageUrl(backdropItemId, options);
- }
-
- return files;
- },
-
- /**
- * Authenticates a user
- * @param {String} userId
- * @param {String} password
- */
- authenticateUser: function (userId, password) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- var url = ApiClient.getUrl("Users/" + userId + "/authenticate");
-
- var postData = {
- };
-
- if (password) {
- postData.password = password;
- }
-
- return $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(postData),
- dataType: "json",
- contentType: "application/json"
- });
- },
-
- /**
- * Updates a user's password
- * @param {String} userId
- * @param {String} currentPassword
- * @param {String} newPassword
- */
- updateUserPassword: function (userId, currentPassword, newPassword) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- var url = ApiClient.getUrl("Users/" + userId + "/Password");
-
- var postData = {
- };
-
- if (currentPassword) {
- postData.currentPassword = currentPassword;
- }
- if (newPassword) {
- postData.newPassword = newPassword;
- }
- return $.post(url, postData);
- },
-
- /**
- * Resets a user's password
- * @param {String} userId
- */
- resetUserPassword: function (userId) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- var url = ApiClient.getUrl("Users/" + userId + "/Password");
-
- var postData = {
- };
-
- postData.resetPassword = 1;
- return $.post(url, postData);
- },
-
- /**
- * Updates the server's configuration
- * @param {Object} configuration
- */
- updateServerConfiguration: function (configuration) {
-
- if (!configuration) {
- throw new Error("null configuration");
- }
-
- var url = ApiClient.getUrl("System/Configuration");
-
- return $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(configuration),
- dataType: "json",
- contentType: "application/json"
- });
- },
-
- /**
- * Updates plugin security info
- */
- updatePluginSecurityInfo: function (info) {
-
- var url = ApiClient.getUrl("Plugins/SecurityInfo");
-
- return $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(info),
- dataType: "json",
- contentType: "application/json"
- });
- },
-
- /**
- * Creates a user
- * @param {Object} user
- */
- createUser: function (user) {
-
- if (!user) {
- throw new Error("null user");
- }
-
- var url = ApiClient.getUrl("Users");
-
- return $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(user),
- dataType: "json",
- contentType: "application/json"
- });
- },
-
- /**
- * Updates a user
- * @param {Object} user
- */
- updateUser: function (user) {
-
- if (!user) {
- throw new Error("null user");
- }
-
- var url = ApiClient.getUrl("Users/" + user.Id);
-
- return $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(user),
- dataType: "json",
- contentType: "application/json"
- });
- },
-
- /**
- * Updates the Triggers for a ScheduledTask
- * @param {String} id
- * @param {Object} triggers
- */
- updateScheduledTaskTriggers: function (id, triggers) {
-
- if (!id) {
- throw new Error("null id");
- }
-
- if (!triggers) {
- throw new Error("null triggers");
- }
-
- var url = ApiClient.getUrl("ScheduledTasks/" + id + "/Triggers");
-
- return $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(triggers),
- dataType: "json",
- contentType: "application/json"
- });
- },
-
- /**
- * Updates a plugin's configuration
- * @param {String} Id
- * @param {Object} configuration
- */
- updatePluginConfiguration: function (id, configuration) {
-
- if (!id) {
- throw new Error("null Id");
- }
-
- if (!configuration) {
- throw new Error("null configuration");
- }
-
- var url = ApiClient.getUrl("Plugins/" + id + "/Configuration");
-
- return $.ajax({
- type: "POST",
- url: url,
- data: JSON.stringify(configuration),
- dataType: "json",
- contentType: "application/json"
- });
- },
-
- /**
- * Gets items based on a query, typicall for children of a folder
- * @param {String} userId
- * @param {Object} options
- * Options accepts the following properties:
- * itemId - Localize the search to a specific folder (root if omitted)
- * startIndex - Use for paging
- * limit - Use to limit results to a certain number of items
- * filter - Specify one or more ItemFilters, comma delimeted (see server-side enum)
- * sortBy - Specify an ItemSortBy (comma-delimeted list see server-side enum)
- * sortOrder - ascending/descending
- * fields - additional fields to include aside from basic info. This is a comma delimited list. See server-side enum ItemFields.
- * index - the name of the dynamic, localized index function
- * dynamicSortBy - the name of the dynamic localized sort function
- * recursive - Whether or not the query should be recursive
- * searchTerm - search term to use as a filter
- */
- getItems: function (userId, options) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- return $.getJSON(ApiClient.getUrl("Users/" + userId + "/Items", options));
- },
-
- /**
- * Marks an item as played or unplayed
- * This should not be used to update playstate following playback.
- * There are separate playstate check-in methods for that. This should be used for a
- * separate option to reset playstate.
- * @param {String} userId
- * @param {String} itemId
- * @param {Boolean} wasPlayed
- */
- updatePlayedStatus: function (userId, itemId, wasPlayed) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- if (!itemId) {
- throw new Error("null itemId");
- }
-
- var url = "Users/" + userId + "/PlayedItems/" + itemId;
-
- var method = wasPlayed ? "POST" : "DELETE";
-
- return $.ajax({
- type: method,
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Updates a user's favorite status for an item and returns the updated UserItemData object.
- * @param {String} userId
- * @param {String} itemId
- * @param {Boolean} isFavorite
- */
- updateFavoriteStatus: function (userId, itemId, isFavorite) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- if (!itemId) {
- throw new Error("null itemId");
- }
-
- var url = "Users/" + userId + "/FavoriteItems/" + itemId;
-
- var method = isFavorite ? "POST" : "DELETE";
-
- return $.ajax({
- type: method,
- url: url,
- dataType: "json"
- });
- },
-
- /**
- * Updates a user's personal rating for an item
- * @param {String} userId
- * @param {String} itemId
- * @param {Boolean} likes
- */
- updateUserItemRating: function (userId, itemId, likes) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- if (!itemId) {
- throw new Error("null itemId");
- }
-
- var url = ApiClient.getUrl("Users/" + userId + "/Items/" + itemId + "/Rating", {
- likes: likes
- });
-
- return $.post(url);
- },
-
- /**
- * Clears a user's personal rating for an item
- * @param {String} userId
- * @param {String} itemId
- */
- clearUserItemRating: function (userId, itemId) {
-
- if (!userId) {
- throw new Error("null userId");
- }
-
- if (!itemId) {
- throw new Error("null itemId");
- }
-
- var url = ApiClient.getUrl("Users/" + userId + "/Items/" + itemId + "/Rating");
-
- return $.ajax({
- type: "DELETE",
- url: url,
- dataType: "json"
- });
- }
-};
-
-// Do this initially. The consumer can always override later
-ApiClient.inferServerFromUrl();
diff --git a/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs b/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs
deleted file mode 100644
index 5ea6f3ebe9..0000000000
--- a/MediaBrowser.Api/Javascript/JavascriptApiClientService.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Server.Implementations.HttpServer;
-using ServiceStack.ServiceHost;
-using System;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Api.Javascript
-{
- /// <summary>
- /// Class GetJavascriptApiClient
- /// </summary>
- [Route("/JsApiClient.js", "GET")]
- [ServiceStack.ServiceHost.Api(("Gets an api wrapper written in Javascript"))]
- public class GetJavascriptApiClient
- {
- /// <summary>
- /// Version identifier for caching
- /// </summary>
- /// <value>The v.</value>
- public string V { get; set; }
- }
-
- /// <summary>
- /// Class JavascriptApiClientService
- /// </summary>
- public class JavascriptApiClientService : BaseRestService
- {
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetJavascriptApiClient request)
- {
- TimeSpan? cacheDuration = null;
-
- // If there's a version number in the query string we can cache this unconditionally
- if (!string.IsNullOrEmpty(request.V))
- {
- cacheDuration = TimeSpan.FromDays(365);
- }
-
- var assembly = GetType().Assembly.GetName();
-
- return ToStaticResult(assembly.Version.ToString().GetMD5(), null, cacheDuration, MimeTypes.GetMimeType("script.js"), GetStream);
- }
-
- /// <summary>
- /// Gets the stream.
- /// </summary>
- /// <returns>Stream.</returns>
- private Task<Stream> GetStream()
- {
- return Task.FromResult(GetType().Assembly.GetManifestResourceStream("MediaBrowser.Api.Javascript.ApiClient.js"));
- }
- }
-}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index ae15500dfd..f0633c4b62 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using System;
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 8444dc46cc..fc02410cc2 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -85,7 +85,6 @@
<Compile Include="Images\ImageRequest.cs" />
<Compile Include="Images\ImageService.cs" />
<Compile Include="Images\ImageWriter.cs" />
- <Compile Include="Javascript\JavascriptApiClientService.cs" />
<Compile Include="Library\LibraryHelpers.cs" />
<Compile Include="Library\LibraryService.cs" />
<Compile Include="Library\LibraryStructureService.cs" />
@@ -107,6 +106,7 @@
<Compile Include="ApiEntryPoint.cs" />
<Compile Include="SystemService.cs" />
<Compile Include="UserLibrary\BaseItemsByNameService.cs" />
+ <Compile Include="UserLibrary\BaseItemsRequest.cs" />
<Compile Include="UserLibrary\GenresService.cs" />
<Compile Include="UserLibrary\ItemsService.cs" />
<Compile Include="UserLibrary\PersonsService.cs" />
@@ -141,7 +141,6 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
- <EmbeddedResource Include="Javascript\ApiClient.js" />
<Content Include="options.xml" />
</ItemGroup>
<ItemGroup />
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index f22a9e09b4..570c6eea05 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Server.Implementations.HttpServer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -14,7 +15,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Server.Implementations.HttpServer;
namespace MediaBrowser.Api.Playback
{
@@ -650,10 +650,8 @@ namespace MediaBrowser.Api.Playback
state.VideoStream = GetMediaStream(media.MediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video, true);
state.SubtitleStream = GetMediaStream(media.MediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
}
- else
- {
- state.AudioStream = GetMediaStream(media.MediaStreams, null, MediaStreamType.Audio, true);
- }
+
+ state.AudioStream = GetMediaStream(media.MediaStreams, null, MediaStreamType.Audio, true);
return state;
}
diff --git a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
index ecdab94b3c..98033c057d 100644
--- a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
@@ -18,8 +18,8 @@ namespace MediaBrowser.Api.Playback.Hls
}
- [Route("/Audio/{Id}/segments/{SegmentId}.mp3", "GET")]
- [Route("/Audio/{Id}/segments/{SegmentId}.aac", "GET")]
+ [Route("/Audio/{Id}/segments/{SegmentId}/stream.mp3", "GET")]
+ [Route("/Audio/{Id}/segments/{SegmentId}/stream.aac", "GET")]
[ServiceStack.ServiceHost.Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
public class GetHlsAudioSegment
{
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 1fb8a504fb..c27219bbf4 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -127,7 +127,7 @@ namespace MediaBrowser.Api.Playback.Hls
// The segement paths within the playlist are phsyical, so strip that out to make it relative
fileText = fileText.Replace(Path.GetDirectoryName(playlist) + Path.DirectorySeparatorChar, string.Empty);
- fileText = fileText.Replace(SegmentFilePrefix, "segments/");
+ fileText = fileText.Replace(SegmentFilePrefix, "segments/").Replace(".ts", "/stream.ts").Replace(".aac", "/stream.aac").Replace(".mp3", "/stream.mp3");
// Even though we specify target duration of 9, ffmpeg seems unable to keep all segments under that amount
fileText = fileText.Replace("#EXT-X-TARGETDURATION:9", "#EXT-X-TARGETDURATION:10");
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index dfbed538f4..578eb93ac0 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Api.Playback.Hls
}
- [Route("/Videos/{Id}/segments/{SegmentId}.ts", "GET")]
+ [Route("/Videos/{Id}/segments/{SegmentId}/stream.ts", "GET")]
[ServiceStack.ServiceHost.Api(Description = "Gets an Http live streaming segment file. Internal use only.")]
public class GetHlsVideoSegment
{
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 251cd4bd6d..a4acc28450 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -135,11 +135,7 @@ namespace MediaBrowser.Api.Playback.Progressive
ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
}
- return new ProgressiveStreamWriter
- {
- Path = outputPath,
- State = state
- };
+ return new ProgressiveStreamWriter(outputPath, state, Logger);
}
/// <summary>
diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
index e9e1340028..efab3bbc69 100644
--- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
+++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
@@ -9,9 +9,22 @@ namespace MediaBrowser.Api.Playback.Progressive
{
public class ProgressiveStreamWriter : IStreamWriter
{
- public string Path { get; set; }
- public StreamState State { get; set; }
- public ILogger Logger { get; set; }
+ private string Path { get; set; }
+ private StreamState State { get; set; }
+ private ILogger Logger { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ProgressiveStreamWriter" /> class.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="state">The state.</param>
+ /// <param name="logger">The logger.</param>
+ public ProgressiveStreamWriter(string path, StreamState state, ILogger logger)
+ {
+ Path = path;
+ State = state;
+ Logger = logger;
+ }
/// <summary>
/// Writes to.
@@ -38,6 +51,8 @@ namespace MediaBrowser.Api.Playback.Progressive
catch (Exception ex)
{
Logger.ErrorException("Error streaming media", ex);
+
+ throw;
}
finally
{
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index d8ffa61fdc..10455c0288 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -20,6 +20,7 @@ namespace MediaBrowser.Api.Playback.Progressive
[Route("/Videos/{Id}/stream.mkv", "GET")]
[Route("/Videos/{Id}/stream.mpeg", "GET")]
[Route("/Videos/{Id}/stream.avi", "GET")]
+ [Route("/Videos/{Id}/stream.m2ts", "GET")]
[Route("/Videos/{Id}/stream", "GET")]
[ServiceStack.ServiceHost.Api(Description = "Gets a video stream")]
public class GetVideoStream : VideoStreamRequest
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 975f8bdfe4..5fb2097cd2 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -1,7 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using System;
@@ -23,12 +23,16 @@ namespace MediaBrowser.Api.UserLibrary
/// The _user manager
/// </summary>
protected readonly IUserManager UserManager;
+ /// <summary>
+ /// The library manager
+ /// </summary>
protected readonly ILibraryManager LibraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
/// </summary>
/// <param name="userManager">The user manager.</param>
+ /// <param name="libraryManager">The library manager.</param>
protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager)
{
UserManager = userManager;
@@ -44,7 +48,7 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId);
- var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, UserManager, LibraryManager, user.Id);
+ var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager, user.Id);
IEnumerable<BaseItem> items;
@@ -157,54 +161,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetItemsByName
/// </summary>
- public class GetItemsByName : IReturn<ItemsResult>
+ public class GetItemsByName : BaseItemsRequest, IReturn<ItemsResult>
{
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
-
- /// <summary>
- /// Gets or sets the start index.
- /// </summary>
- /// <value>The start index.</value>
- [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? StartIndex { get; set; }
-
- /// <summary>
- /// Gets or sets the size of the page.
- /// </summary>
- /// <value>The size of the page.</value>
- [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? Limit { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this <see cref="GetItemsByName" /> is recursive.
- /// </summary>
- /// <value><c>true</c> if recursive; otherwise, <c>false</c>.</value>
- [ApiMember(Name = "Recursive", Description = "When searching within folders, this determines whether or not the search will be recursive. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
- public bool Recursive { get; set; }
-
- /// <summary>
- /// Gets or sets the sort order.
- /// </summary>
- /// <value>The sort order.</value>
- [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public SortOrder? SortOrder { get; set; }
-
- /// <summary>
- /// If specified the search will be localized within a specific item or folder
- /// </summary>
- /// <value>The item id.</value>
- [ApiMember(Name = "Id", Description = "If specified the search will be localized within a specific item or folder", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string Id { get; set; }
-
- /// <summary>
- /// Fields to return within the items, in addition to basic information
- /// </summary>
- /// <value>The fields.</value>
- public string Fields { get; set; }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
new file mode 100644
index 0000000000..ed1beab6fe
--- /dev/null
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -0,0 +1,58 @@
+using MediaBrowser.Model.Entities;
+using ServiceStack.ServiceHost;
+using System;
+
+namespace MediaBrowser.Api.UserLibrary
+{
+ public abstract class BaseItemsRequest
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public Guid UserId { get; set; }
+
+ /// <summary>
+ /// Skips over a given number of items within the results. Use for paging.
+ /// </summary>
+ /// <value>The start index.</value>
+ [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? StartIndex { get; set; }
+
+ /// <summary>
+ /// The maximum number of items to return
+ /// </summary>
+ /// <value>The limit.</value>
+ [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? Limit { get; set; }
+
+ /// <summary>
+ /// Whether or not to perform the query recursively
+ /// </summary>
+ /// <value><c>true</c> if recursive; otherwise, <c>false</c>.</value>
+ [ApiMember(Name = "Recursive", Description = "When searching within folders, this determines whether or not the search will be recursive. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+ public bool Recursive { get; set; }
+
+ /// <summary>
+ /// Gets or sets the sort order.
+ /// </summary>
+ /// <value>The sort order.</value>
+ [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public SortOrder? SortOrder { get; set; }
+
+ /// <summary>
+ /// Specify this to localize the search to a specific item or folder. Omit to use the root.
+ /// </summary>
+ /// <value>The parent id.</value>
+ [ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ParentId { get; set; }
+
+ /// <summary>
+ /// Fields to return within the items, in addition to basic information
+ /// </summary>
+ /// <value>The fields.</value>
+ [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: AudioInfo, Chapters, DateCreated, DisplayMediaType, DisplayPreferences, Genres, ItemCounts, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, SeriesInfo, SortName, Studios, Taglines, TrailerUrls, UserData", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string Fields { get; set; }
+ }
+}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 92f267a21d..ff062c1830 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -1,8 +1,7 @@
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using System;
@@ -17,44 +16,9 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
[Route("/Users/{UserId}/Items", "GET")]
[ServiceStack.ServiceHost.Api(Description = "Gets items based on a query.")]
- public class GetItems : IReturn<ItemsResult>
+ public class GetItems : BaseItemsRequest, IReturn<ItemsResult>
{
/// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
-
- /// <summary>
- /// Specify this to localize the search to a specific item or folder. Omit to use the root.
- /// </summary>
- /// <value>The parent id.</value>
- [ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string ParentId { get; set; }
-
- /// <summary>
- /// Skips over a given number of items within the results. Use for paging.
- /// </summary>
- /// <value>The start index.</value>
- [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? StartIndex { get; set; }
-
- /// <summary>
- /// The maximum number of items to return
- /// </summary>
- /// <value>The limit.</value>
- [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? Limit { get; set; }
-
- /// <summary>
- /// Whether or not to perform the query recursively
- /// </summary>
- /// <value><c>true</c> if recursive; otherwise, <c>false</c>.</value>
- [ApiMember(Name = "Recursive", Description = "When searching within folders, this determines whether or not the search will be recursive. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
- public bool Recursive { get; set; }
-
- /// <summary>
/// Limit results to items containing a specific person
/// </summary>
/// <value>The person.</value>
@@ -82,40 +46,20 @@ namespace MediaBrowser.Api.UserLibrary
public string IndexBy { get; set; }
/// <summary>
- /// The dynamic, localized sort function name
- /// </summary>
- /// <value>The dynamic sort by.</value>
- public string DynamicSortBy { get; set; }
-
- /// <summary>
/// What to sort the results by
/// </summary>
/// <value>The sort by.</value>
- [ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album,AlbumArtist,Artist,DateCreated,DatePlayed,PremiereDate,SortName,Random", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ [ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, CommunityRating, DateCreated, DatePlayed, PremiereDate, ProductionYear, SortName, Random, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string SortBy { get; set; }
/// <summary>
- /// The sort order to return results with
- /// </summary>
- /// <value>The sort order.</value>
- [ApiMember(Name = "SortOrder", Description = "Optional. Ascending / Descending sort order", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string SortOrder { get; set; }
-
- /// <summary>
/// Filters to apply to the results
/// </summary>
/// <value>The filters.</value>
- [ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder,IsNotFolder,IsUnplayed,IsPlayed,IsFavorite,IsResumable", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ [ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsRecentlyAdded, IsResumable", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Filters { get; set; }
/// <summary>
- /// Fields to return within the items, in addition to basic information
- /// </summary>
- /// <value>The fields.</value>
- [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: AudioInfo, Chapters, DateCreated, DisplayMediaType, DisplayPreferences, Genres, ItemCounts, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, SeriesInfo, SortName, Studios, Taglines, TrailerUrls, UserData", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string Fields { get; set; }
-
- /// <summary>
/// Limit results to items containing specific genres
/// </summary>
/// <value>The genres.</value>
@@ -254,7 +198,7 @@ namespace MediaBrowser.Api.UserLibrary
return ((Folder)item).GetRecursiveChildren(user);
}
- return ((Folder)item).GetChildren(user, request.IndexBy, request.DynamicSortBy, GetSortOrder(request));
+ return ((Folder)item).GetChildren(user, request.IndexBy);
}
/// <summary>
@@ -266,58 +210,9 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user)
{
- var isFirst = true;
- var descending = (GetSortOrder(request) ?? SortOrder.Ascending) == SortOrder.Descending;
-
- IOrderedEnumerable<BaseItem> orderedItems = null;
+ var orderBy = GetOrderBy(request).ToArray();
- foreach (var orderBy in GetOrderBy(request).Select(o => GetComparer(o, user)))
- {
- if (isFirst)
- {
- orderedItems = descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy);
- }
- else
- {
- orderedItems = descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy);
- }
-
- isFirst = false;
- }
-
- return orderedItems ?? items;
- }
-
- /// <summary>
- /// Gets the comparer.
- /// </summary>
- /// <param name="sortBy">The sort by.</param>
- /// <param name="user">The user.</param>
- /// <returns>IComparer{BaseItem}.</returns>
- /// <exception cref="System.ArgumentException"></exception>
- private IComparer<BaseItem> GetComparer(ItemSortBy sortBy, User user)
- {
- switch (sortBy)
- {
- case ItemSortBy.Album:
- return new AlbumComparer();
- case ItemSortBy.AlbumArtist:
- return new AlbumArtistComparer();
- case ItemSortBy.Artist:
- return new ArtistComparer();
- case ItemSortBy.Random:
- return new RandomComparer();
- case ItemSortBy.DateCreated:
- return new DateCreatedComparer();
- case ItemSortBy.SortName:
- return new SortNameComparer();
- case ItemSortBy.PremiereDate:
- return new PremiereDateComparer();
- case ItemSortBy.DatePlayed:
- return new DatePlayedComparer { User = user };
- default:
- throw new ArgumentException();
- }
+ return orderBy.Length == 0 ? items : _libraryManager.Sort(items, user, orderBy, request.SortOrder ?? SortOrder.Ascending);
}
/// <summary>
@@ -465,7 +360,7 @@ namespace MediaBrowser.Api.UserLibrary
return item.ScreenshotImagePaths != null && item.ScreenshotImagePaths.Count > 0;
}
- if (imageType == ImageType.ChapterImage)
+ if (imageType == ImageType.Chapter)
{
var video = item as Video;
@@ -522,21 +417,6 @@ namespace MediaBrowser.Api.UserLibrary
}
/// <summary>
- /// Gets the sort order.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Nullable{SortOrder}.</returns>
- private SortOrder? GetSortOrder(GetItems request)
- {
- if (string.IsNullOrEmpty(request.SortOrder))
- {
- return null;
- }
-
- return (SortOrder)Enum.Parse(typeof(SortOrder), request.SortOrder, true);
- }
-
- /// <summary>
/// Gets the filters.
/// </summary>
/// <param name="request">The request.</param>
@@ -575,16 +455,16 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>IEnumerable{ItemSortBy}.</returns>
- private IEnumerable<ItemSortBy> GetOrderBy(GetItems request)
+ private IEnumerable<string> GetOrderBy(GetItems request)
{
var val = request.SortBy;
if (string.IsNullOrEmpty(val))
{
- return new ItemSortBy[] { };
+ return new string[] { };
}
- return val.Split(',').Select(v => (ItemSortBy)Enum.Parse(typeof(ItemSortBy), v, true));
+ return val.Split(',');
}
/// <summary>
@@ -621,201 +501,4 @@ namespace MediaBrowser.Api.UserLibrary
return x.DateCreated.CompareTo(y.DateCreated);
}
}
-
- /// <summary>
- /// Class RandomComparer
- /// </summary>
- public class RandomComparer : IComparer<BaseItem>
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return Guid.NewGuid().CompareTo(Guid.NewGuid());
- }
- }
-
- /// <summary>
- /// Class SortNameComparer
- /// </summary>
- public class SortNameComparer : IComparer<BaseItem>
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase);
- }
- }
-
- /// <summary>
- /// Class AlbumArtistComparer
- /// </summary>
- public class AlbumArtistComparer : IComparer<BaseItem>
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
- }
-
- /// <summary>
- /// Gets the value.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>System.String.</returns>
- private string GetValue(BaseItem x)
- {
- var audio = x as Audio;
-
- return audio == null ? string.Empty : audio.AlbumArtist;
- }
- }
-
- /// <summary>
- /// Class AlbumComparer
- /// </summary>
- public class AlbumComparer : IComparer<BaseItem>
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
- }
-
- /// <summary>
- /// Gets the value.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>System.String.</returns>
- private string GetValue(BaseItem x)
- {
- var audio = x as Audio;
-
- return audio == null ? string.Empty : audio.Album;
- }
- }
-
- /// <summary>
- /// Class ArtistComparer
- /// </summary>
- public class ArtistComparer : IComparer<BaseItem>
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
- }
-
- /// <summary>
- /// Gets the value.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>System.String.</returns>
- private string GetValue(BaseItem x)
- {
- var audio = x as Audio;
-
- return audio == null ? string.Empty : audio.Artist;
- }
- }
-
- /// <summary>
- /// Class PremiereDateComparer
- /// </summary>
- public class PremiereDateComparer : IComparer<BaseItem>
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return GetDate(x).CompareTo(GetDate(y));
- }
-
- /// <summary>
- /// Gets the date.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>DateTime.</returns>
- private DateTime GetDate(BaseItem x)
- {
- if (x.PremiereDate.HasValue)
- {
- return x.PremiereDate.Value;
- }
-
- if (x.ProductionYear.HasValue)
- {
- return new DateTime(x.ProductionYear.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc);
- }
- return DateTime.MaxValue;
- }
- }
-
- /// <summary>
- /// Class DatePlayedComparer
- /// </summary>
- public class DatePlayedComparer : IComparer<BaseItem>
- {
- /// <summary>
- /// Gets or sets the user.
- /// </summary>
- /// <value>The user.</value>
- public User User { get; set; }
-
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return GetDate(x).CompareTo(GetDate(y));
- }
-
- /// <summary>
- /// Gets the date.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>DateTime.</returns>
- private DateTime GetDate(BaseItem x)
- {
- var userdata = x.GetUserData(User, false);
-
- if (userdata != null && userdata.LastPlayedDate.HasValue)
- {
- return userdata.LastPlayedDate.Value;
- }
-
- return DateTime.MinValue;
- }
- }
}
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 1182dbb054..88b7dc57c3 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Connectivity;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Server.Implementations.HttpServer;
using ServiceStack.ServiceHost;
using ServiceStack.Text.Controller;