From 937e434ab6f32ef4444066a9f84bfbea23538432 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sat, 9 Mar 2013 20:18:29 -0500 Subject: moved the javascript apiclient to it's own repo and nuget package --- MediaBrowser.Api/Javascript/ApiClient.js | 1387 -------------------- .../Javascript/JavascriptApiClientService.cs | 59 - MediaBrowser.Api/MediaBrowser.Api.csproj | 2 - MediaBrowser.Api/UserLibrary/ItemsService.cs | 2 +- MediaBrowser.Controller/Drawing/ImageManager.cs | 2 +- MediaBrowser.Controller/Library/DtoBuilder.cs | 2 +- MediaBrowser.Model/Entities/ImageType.cs | 2 +- MediaBrowser.Model/PropertyChanged.xml | 54 + MediaBrowser.WebDashboard/Api/DashboardService.cs | 23 +- MediaBrowser.WebDashboard/ApiClient.js | 1387 ++++++++++++++++++++ .../MediaBrowser.WebDashboard.csproj | 1 + MediaBrowser.WebDashboard/packages.config | 1 + 12 files changed, 1462 insertions(+), 1460 deletions(-) delete mode 100644 MediaBrowser.Api/Javascript/ApiClient.js delete mode 100644 MediaBrowser.Api/Javascript/JavascriptApiClientService.cs create mode 100644 MediaBrowser.Model/PropertyChanged.xml create mode 100644 MediaBrowser.WebDashboard/ApiClient.js 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 -{ - /// - /// Class GetJavascriptApiClient - /// - [Route("/JsApiClient.js", "GET")] - [ServiceStack.ServiceHost.Api(("Gets an api wrapper written in Javascript"))] - public class GetJavascriptApiClient - { - /// - /// Version identifier for caching - /// - /// The v. - public string V { get; set; } - } - - /// - /// Class JavascriptApiClientService - /// - public class JavascriptApiClientService : BaseRestService - { - /// - /// Gets the specified request. - /// - /// The request. - /// System.Object. - 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); - } - - /// - /// Gets the stream. - /// - /// Stream. - private Task GetStream() - { - return Task.FromResult(GetType().Assembly.GetManifestResourceStream("MediaBrowser.Api.Javascript.ApiClient.js")); - } - } -} diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 8444dc46cc..e0a9444a70 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -85,7 +85,6 @@ - @@ -141,7 +140,6 @@ - diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 92f267a21d..9aa4203a9b 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -465,7 +465,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; diff --git a/MediaBrowser.Controller/Drawing/ImageManager.cs b/MediaBrowser.Controller/Drawing/ImageManager.cs index d95f72df70..3c6f845e57 100644 --- a/MediaBrowser.Controller/Drawing/ImageManager.cs +++ b/MediaBrowser.Controller/Drawing/ImageManager.cs @@ -356,7 +356,7 @@ namespace MediaBrowser.Controller.Drawing return item.ScreenshotImagePaths[imageIndex]; } - if (imageType == ImageType.ChapterImage) + if (imageType == ImageType.Chapter) { var video = (Video)item; diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index b8e775e976..92a15b117c 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -678,7 +678,7 @@ namespace MediaBrowser.Controller.Library if (!string.IsNullOrEmpty(chapterInfo.ImagePath)) { - dto.ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.ChapterImage, chapterInfo.ImagePath); + dto.ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Chapter, chapterInfo.ImagePath); } return dto; diff --git a/MediaBrowser.Model/Entities/ImageType.cs b/MediaBrowser.Model/Entities/ImageType.cs index aaae8dda37..8ad1090b83 100644 --- a/MediaBrowser.Model/Entities/ImageType.cs +++ b/MediaBrowser.Model/Entities/ImageType.cs @@ -49,6 +49,6 @@ namespace MediaBrowser.Model.Entities /// /// The chapter image /// - ChapterImage + Chapter } } diff --git a/MediaBrowser.Model/PropertyChanged.xml b/MediaBrowser.Model/PropertyChanged.xml new file mode 100644 index 0000000000..e69755cf46 --- /dev/null +++ b/MediaBrowser.Model/PropertyChanged.xml @@ -0,0 +1,54 @@ + + + + PropertyChanged + + + + + Injects this property to be notified when a dependant property is set. + + + + + Initializes a new instance of . + + A property that will be notified for. + + + + Initializes a new instance of . + + A property that will be notified for. + The properties that will be notified for. + + + + Injects this property to be notified when a dependant property is set. + + + + + Initializes a new instance of . + + A property that the assigned property depends on. + + + + Initializes a new instance of . + + A property that the assigned property depends on. + The properties that the assigned property depends on. + + + + Exclude a or property from notification. + + + + + Exclude a or property from IsChanged flagging. + + + + diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 86e4c10ea7..4c861c61bd 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using System.Reflection; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; @@ -391,7 +392,6 @@ namespace MediaBrowser.WebDashboard.Api { "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js", "http://code.jquery.com/mobile/1.3.0/jquery.mobile-1.3.0.min.js", - "../jsapiclient.js" + versionString, "scripts/all.js" + versionString }; @@ -447,20 +447,27 @@ namespace MediaBrowser.WebDashboard.Api var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine); + await AppendResource(assembly, memoryStream, "MediaBrowser.WebDashboard.ApiClient.js", newLineBytes).ConfigureAwait(false); + foreach (var file in scriptFiles) { - using (var stream = assembly.GetManifestResourceStream(resourcePrefix + file)) - { - await stream.CopyToAsync(memoryStream).ConfigureAwait(false); - - await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false); - } + await AppendResource(assembly, memoryStream, resourcePrefix + file, newLineBytes).ConfigureAwait(false); } memoryStream.Position = 0; return memoryStream; } + private async Task AppendResource(Assembly assembly, Stream outputStream, string path, byte[] newLineBytes) + { + using (var stream = assembly.GetManifestResourceStream(path)) + { + await stream.CopyToAsync(outputStream).ConfigureAwait(false); + + await outputStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false); + } + } + } } diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js new file mode 100644 index 0000000000..31022de382 --- /dev/null +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -0,0 +1,1387 @@ +/** + * 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.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 188c187226..07992b1e38 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -403,6 +403,7 @@ + diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 629487c799..fb7a49ef6f 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,5 +1,6 @@  + -- cgit v1.2.3 From 31d079f1baea895b5cb0f1a737140ab94dc9a4fe Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sat, 9 Mar 2013 23:22:36 -0500 Subject: unified the two sorting api's --- MediaBrowser.Api/UserLibrary/ItemsService.cs | 265 +-------------------- MediaBrowser.Controller/Entities/Folder.cs | 73 +----- MediaBrowser.Controller/Library/DtoBuilder.cs | 5 - MediaBrowser.Controller/Library/ILibraryManager.cs | 15 +- .../MediaBrowser.Controller.csproj | 4 +- .../Sorting/BaseItemComparer.cs | 248 ------------------- .../Sorting/IBaseItemComparer.cs | 17 ++ .../Sorting/IUserBaseItemComparer.cs | 16 ++ MediaBrowser.Controller/Sorting/SortOrder.cs | 33 --- MediaBrowser.Model/DTO/BaseItemDto.cs | 7 - MediaBrowser.Model/DTO/ItemFields.cs | 5 - MediaBrowser.Model/DTO/ItemQuery.cs | 8 +- MediaBrowser.Model/DTO/ItemSortBy.cs | 32 ++- .../Library/LibraryManager.cs | 69 +++++- .../MediaBrowser.Server.Implementations.csproj | 11 + .../Sorting/AlbumArtistComparer.cs | 46 ++++ .../Sorting/AlbumComparer.cs | 46 ++++ .../Sorting/ArtistComparer.cs | 46 ++++ .../Sorting/CommunityRatingComparer.cs | 29 +++ .../Sorting/DateCreatedComparer.cs | 33 +++ .../Sorting/DatePlayedComparer.cs | 56 +++++ .../Sorting/PremiereDateComparer.cs | 52 ++++ .../Sorting/ProductionYearComparer.cs | 52 ++++ .../Sorting/RandomComparer.cs | 33 +++ .../Sorting/RuntimeComparer.cs | 32 +++ .../Sorting/SortNameComparer.cs | 33 +++ MediaBrowser.ServerApplication/ApplicationHost.cs | 3 +- .../LibraryExplorer.xaml.cs | 62 ++++- .../MediaBrowser.ServerApplication.csproj | 5 +- ...MediaBrowser.ServerApplication_TemporaryKey.pfx | Bin 1676 -> 0 bytes 30 files changed, 676 insertions(+), 660 deletions(-) delete mode 100644 MediaBrowser.Controller/Sorting/BaseItemComparer.cs create mode 100644 MediaBrowser.Controller/Sorting/IBaseItemComparer.cs create mode 100644 MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs delete mode 100644 MediaBrowser.Controller/Sorting/SortOrder.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs delete mode 100644 MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 9aa4203a9b..a02c3c0122 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -1,5 +1,4 @@ using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -81,12 +80,6 @@ namespace MediaBrowser.Api.UserLibrary /// The index by. public string IndexBy { get; set; } - /// - /// The dynamic, localized sort function name - /// - /// The dynamic sort by. - public string DynamicSortBy { get; set; } - /// /// What to sort the results by /// @@ -254,7 +247,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); } /// @@ -266,58 +259,9 @@ namespace MediaBrowser.Api.UserLibrary /// IEnumerable{BaseItem}. private IEnumerable ApplySortOrder(GetItems request, IEnumerable items, User user) { - var isFirst = true; - var descending = (GetSortOrder(request) ?? SortOrder.Ascending) == SortOrder.Descending; + var orderBy = GetOrderBy(request).ToArray(); - IOrderedEnumerable orderedItems = null; - - 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; - } - - /// - /// Gets the comparer. - /// - /// The sort by. - /// The user. - /// IComparer{BaseItem}. - /// - private IComparer 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, GetSortOrder(request) ?? SortOrder.Ascending); } /// @@ -575,16 +519,16 @@ namespace MediaBrowser.Api.UserLibrary /// /// The request. /// IEnumerable{ItemSortBy}. - private IEnumerable GetOrderBy(GetItems request) + private IEnumerable 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(','); } /// @@ -621,201 +565,4 @@ namespace MediaBrowser.Api.UserLibrary return x.DateCreated.CompareTo(y.DateCreated); } } - - /// - /// Class RandomComparer - /// - public class RandomComparer : IComparer - { - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) - { - return Guid.NewGuid().CompareTo(Guid.NewGuid()); - } - } - - /// - /// Class SortNameComparer - /// - public class SortNameComparer : IComparer - { - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) - { - return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase); - } - } - - /// - /// Class AlbumArtistComparer - /// - public class AlbumArtistComparer : IComparer - { - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) - { - return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); - } - - /// - /// Gets the value. - /// - /// The x. - /// System.String. - private string GetValue(BaseItem x) - { - var audio = x as Audio; - - return audio == null ? string.Empty : audio.AlbumArtist; - } - } - - /// - /// Class AlbumComparer - /// - public class AlbumComparer : IComparer - { - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) - { - return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); - } - - /// - /// Gets the value. - /// - /// The x. - /// System.String. - private string GetValue(BaseItem x) - { - var audio = x as Audio; - - return audio == null ? string.Empty : audio.Album; - } - } - - /// - /// Class ArtistComparer - /// - public class ArtistComparer : IComparer - { - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) - { - return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); - } - - /// - /// Gets the value. - /// - /// The x. - /// System.String. - private string GetValue(BaseItem x) - { - var audio = x as Audio; - - return audio == null ? string.Empty : audio.Artist; - } - } - - /// - /// Class PremiereDateComparer - /// - public class PremiereDateComparer : IComparer - { - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) - { - return GetDate(x).CompareTo(GetDate(y)); - } - - /// - /// Gets the date. - /// - /// The x. - /// DateTime. - 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; - } - } - - /// - /// Class DatePlayedComparer - /// - public class DatePlayedComparer : IComparer - { - /// - /// Gets or sets the user. - /// - /// The user. - public User User { get; set; } - - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) - { - return GetDate(x).CompareTo(GetDate(y)); - } - - /// - /// Gets the date. - /// - /// The x. - /// DateTime. - 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.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index c6f4790298..ef34742df4 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -13,7 +13,6 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using SortOrder = MediaBrowser.Controller.Sorting.SortOrder; namespace MediaBrowser.Controller.Entities { @@ -177,63 +176,6 @@ namespace MediaBrowser.Controller.Entities } } - #region Sorting - - /// - /// The _sort by options - /// - private Dictionary> _sortByOptions; - /// - /// Dictionary of sort options - consists of a display value (localized) and an IComparer of BaseItem - /// - /// The sort by options. - [IgnoreDataMember] - public Dictionary> SortByOptions - { - get { return _sortByOptions ?? (_sortByOptions = GetSortByOptions()); } - } - - /// - /// Returns the valid set of sort by options for this folder type. - /// Override or extend to modify. - /// - /// Dictionary{System.StringIComparer{BaseItem}}. - protected virtual Dictionary> GetSortByOptions() - { - return new Dictionary> { - {LocalizedStrings.Instance.GetString("NameDispPref"), new BaseItemComparer(SortOrder.Name, Logger)}, - {LocalizedStrings.Instance.GetString("DateDispPref"), new BaseItemComparer(SortOrder.Date, Logger)}, - {LocalizedStrings.Instance.GetString("RatingDispPref"), new BaseItemComparer(SortOrder.Rating, Logger)}, - {LocalizedStrings.Instance.GetString("RuntimeDispPref"), new BaseItemComparer(SortOrder.Runtime, Logger)}, - {LocalizedStrings.Instance.GetString("YearDispPref"), new BaseItemComparer(SortOrder.Year, Logger)} - }; - - } - - /// - /// Get a sorting comparer by name - /// - /// The name. - /// IComparer{BaseItem}. - private IComparer GetSortingFunction(string name) - { - IComparer sorting; - SortByOptions.TryGetValue(name ?? "", out sorting); - return sorting ?? new BaseItemComparer(SortOrder.Name, Logger); - } - - /// - /// Get the list of sort by choices for this folder (localized). - /// - /// The sort by option strings. - [IgnoreDataMember] - public IEnumerable SortByOptionStrings - { - get { return SortByOptions.Keys; } - } - - #endregion - #region Indexing /// @@ -877,11 +819,9 @@ namespace MediaBrowser.Controller.Entities /// /// The user. /// The index by. - /// The sort by. - /// The sort order. /// IEnumerable{BaseItem}. /// - public virtual IEnumerable GetChildren(User user, string indexBy = null, string sortBy = null, Model.Entities.SortOrder? sortOrder = null) + public virtual IEnumerable GetChildren(User user, string indexBy = null) { if (user == null) { @@ -889,7 +829,7 @@ namespace MediaBrowser.Controller.Entities } //the true root should return our users root folder children - if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, indexBy, sortBy, sortOrder); + if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, indexBy); IEnumerable result = null; @@ -904,14 +844,7 @@ namespace MediaBrowser.Controller.Entities result = ActualChildren.Where(c => c.IsVisible(user)); } - if (string.IsNullOrEmpty(sortBy)) - { - return result; - } - - return sortOrder.HasValue && sortOrder.Value == Model.Entities.SortOrder.Descending - ? result.OrderByDescending(i => i, GetSortingFunction(sortBy)) - : result.OrderBy(i => i, GetSortingFunction(sortBy)); + return result; } /// diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index 92a15b117c..bdaa51b6c1 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -373,11 +373,6 @@ namespace MediaBrowser.Controller.Library { dto.IndexOptions = folder.IndexByOptionStrings.ToArray(); } - - if (fields.Contains(ItemFields.SortOptions)) - { - dto.SortOptions = folder.SortByOptionStrings.ToArray(); - } } // Add audio info diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 3f19302093..40131b6d20 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; @@ -158,7 +159,19 @@ namespace MediaBrowser.Controller.Library /// The plugin folders. /// The resolvers. /// The intro providers. + /// The item comparers. void AddParts(IEnumerable rules, IEnumerable pluginFolders, - IEnumerable resolvers, IEnumerable introProviders); + IEnumerable resolvers, IEnumerable introProviders, IEnumerable itemComparers); + + /// + /// Sorts the specified items. + /// + /// The items. + /// The user. + /// The sort by. + /// The sort order. + /// IEnumerable{BaseItem}. + IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, + SortOrder sortOrder); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 5ae6cccac5..9b75290237 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -185,8 +185,8 @@ - - + + diff --git a/MediaBrowser.Controller/Sorting/BaseItemComparer.cs b/MediaBrowser.Controller/Sorting/BaseItemComparer.cs deleted file mode 100644 index 94c16775d0..0000000000 --- a/MediaBrowser.Controller/Sorting/BaseItemComparer.cs +++ /dev/null @@ -1,248 +0,0 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; - -namespace MediaBrowser.Controller.Sorting { - /// - /// Class BaseItemComparer - /// - public class BaseItemComparer : IComparer { - /// - /// The _order - /// - private readonly SortOrder _order; - /// - /// The _property name - /// - private readonly string _propertyName; - /// - /// The _compare culture - /// - private readonly StringComparison _compareCulture = StringComparison.CurrentCultureIgnoreCase; - - /// - /// Gets or sets the logger. - /// - /// The logger. - private ILogger Logger { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The order. - /// The logger. - public BaseItemComparer(SortOrder order, ILogger logger) { - _order = order; - Logger = logger; - } - - /// - /// Initializes a new instance of the class. - /// - /// The order. - /// The compare. - /// The logger. - public BaseItemComparer(SortOrder order, StringComparison compare, ILogger logger) - { - _order = order; - _compareCulture = compare; - Logger = logger; - } - - /// - /// Initializes a new instance of the class. - /// - /// The property. - /// The logger. - public BaseItemComparer(string property, ILogger logger) - { - _order = SortOrder.Custom; - _propertyName = property; - Logger = logger; - } - - /// - /// Initializes a new instance of the class. - /// - /// The property. - /// The compare. - /// The logger. - public BaseItemComparer(string property, StringComparison compare, ILogger logger) - { - _order = SortOrder.Custom; - _propertyName = property; - _compareCulture = compare; - Logger = logger; - } - - #region IComparer Members - - /// - /// Compares the specified x. - /// - /// The x. - /// The y. - /// System.Int32. - public int Compare(BaseItem x, BaseItem y) { - int compare = 0; - - switch (_order) { - - case SortOrder.Date: - compare = -x.DateCreated.CompareTo(y.DateCreated); - break; - - case SortOrder.Year: - - var xProductionYear = x.ProductionYear ?? 0; - var yProductionYear = y.ProductionYear ?? 0; - - - compare = yProductionYear.CompareTo(xProductionYear); - break; - - case SortOrder.Rating: - - var xRating = x.CommunityRating ?? 0; - var yRating = y.CommunityRating ?? 0; - - compare = yRating.CompareTo(xRating); - break; - - case SortOrder.Runtime: - var xRuntime = x.RunTimeTicks ?? 0; - var yRuntime = y.RunTimeTicks ?? 0; - - compare = xRuntime.CompareTo(yRuntime); - break; - - case SortOrder.Custom: - - Logger.Debug("Sorting on custom field " + _propertyName); - var yProp = y.GetType().GetProperty(_propertyName); - var xProp = x.GetType().GetProperty(_propertyName); - if (yProp == null || xProp == null) break; - var yVal = yProp.GetValue(y, null); - var xVal = xProp.GetValue(x,null); - if (yVal == null && xVal == null) break; - if (yVal == null) return 1; - if (xVal == null) return -1; - compare = String.Compare(xVal.ToString(), yVal.ToString(),_compareCulture); - break; - - default: - compare = 0; - break; - } - - if (compare == 0) { - - var name1 = x.SortName ?? x.Name ?? ""; - var name2 = y.SortName ?? y.Name ?? ""; - - //if (Config.Instance.EnableAlphanumericSorting) - compare = AlphaNumericCompare(name1, name2,_compareCulture); - //else - // compare = String.Compare(name1,name2,_compareCulture); - } - - return compare; - } - - - #endregion - - /// - /// Alphas the numeric compare. - /// - /// The s1. - /// The s2. - /// The compare culture. - /// System.Int32. - private int AlphaNumericCompare(string s1, string s2, StringComparison compareCulture) { - // http://dotnetperls.com/Content/Alphanumeric-Sorting.aspx - - int len1 = s1.Length; - int len2 = s2.Length; - int marker1 = 0; - int marker2 = 0; - - // Walk through two the strings with two markers. - while (marker1 < len1 && marker2 < len2) { - char ch1 = s1[marker1]; - char ch2 = s2[marker2]; - - // Some buffers we can build up characters in for each chunk. - var space1 = new char[len1]; - var loc1 = 0; - var space2 = new char[len2]; - var loc2 = 0; - - // Walk through all following characters that are digits or - // characters in BOTH strings starting at the appropriate marker. - // Collect char arrays. - do { - space1[loc1++] = ch1; - marker1++; - - if (marker1 < len1) { - ch1 = s1[marker1]; - } else { - break; - } - } while (char.IsDigit(ch1) == char.IsDigit(space1[0])); - - do { - space2[loc2++] = ch2; - marker2++; - - if (marker2 < len2) { - ch2 = s2[marker2]; - } else { - break; - } - } while (char.IsDigit(ch2) == char.IsDigit(space2[0])); - - // If we have collected numbers, compare them numerically. - // Otherwise, if we have strings, compare them alphabetically. - var str1 = new string(space1); - var str2 = new string(space2); - - var result = 0; - - //biggest int - 2147483647 - if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]) /*&& str1.Length < 10 && str2.Length < 10*/) //this assumed the entire string was a number... - { - int thisNumericChunk; - var isValid = false; - - if (int.TryParse(str1.Substring(0, str1.Length > 9 ? 10 : str1.Length), out thisNumericChunk)) - { - int thatNumericChunk; - - if (int.TryParse(str2.Substring(0, str2.Length > 9 ? 10 : str2.Length), out thatNumericChunk)) - { - isValid = true; - result = thisNumericChunk.CompareTo(thatNumericChunk); - } - } - - if (!isValid) - { - Logger.Error("Error comparing numeric strings: " + str1 + "/" + str2); - result = String.Compare(str1, str2, compareCulture); - } - - } else { - result = String.Compare(str1,str2,compareCulture); - } - - if (result != 0) { - return result; - } - } - return len1 - len2; - } - } -} diff --git a/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs new file mode 100644 index 0000000000..6d0b95bcb5 --- /dev/null +++ b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs @@ -0,0 +1,17 @@ +using MediaBrowser.Controller.Entities; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Sorting +{ + /// + /// Interface IBaseItemComparer + /// + public interface IBaseItemComparer : IComparer + { + /// + /// Gets the name. + /// + /// The name. + string Name { get; } + } +} diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs new file mode 100644 index 0000000000..b9da1f6a62 --- /dev/null +++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs @@ -0,0 +1,16 @@ +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Sorting +{ + /// + /// Represents a BaseItem comparer that requires a User to perform it's comparison + /// + public interface IUserBaseItemComparer : IBaseItemComparer + { + /// + /// Gets or sets the user. + /// + /// The user. + User User { get; set; } + } +} diff --git a/MediaBrowser.Controller/Sorting/SortOrder.cs b/MediaBrowser.Controller/Sorting/SortOrder.cs deleted file mode 100644 index 3152ac67e4..0000000000 --- a/MediaBrowser.Controller/Sorting/SortOrder.cs +++ /dev/null @@ -1,33 +0,0 @@ - -namespace MediaBrowser.Controller.Sorting { - /// - /// Enum SortOrder - /// - public enum SortOrder { - - /// - /// Sort by name - /// - Name, - /// - /// Sort by date added to the library - /// - Date, - /// - /// Sort by community rating - /// - Rating, - /// - /// Sort by runtime - /// - Runtime, - /// - /// Sort by year - /// - Year, - /// - /// Custom sort order added by plugins - /// - Custom - } -} diff --git a/MediaBrowser.Model/DTO/BaseItemDto.cs b/MediaBrowser.Model/DTO/BaseItemDto.cs index 971b0bde74..b1d3f83c23 100644 --- a/MediaBrowser.Model/DTO/BaseItemDto.cs +++ b/MediaBrowser.Model/DTO/BaseItemDto.cs @@ -315,13 +315,6 @@ namespace MediaBrowser.Model.Dto [ProtoMember(52)] public List AirDays { get; set; } - /// - /// Gets or sets the sort options. - /// - /// The sort options. - [ProtoMember(53)] - public string[] SortOptions { get; set; } - /// /// Gets or sets the index options. /// diff --git a/MediaBrowser.Model/DTO/ItemFields.cs b/MediaBrowser.Model/DTO/ItemFields.cs index a24c8a8f01..981afe8947 100644 --- a/MediaBrowser.Model/DTO/ItemFields.cs +++ b/MediaBrowser.Model/DTO/ItemFields.cs @@ -86,11 +86,6 @@ namespace MediaBrowser.Model.Dto /// SortName, - /// - /// The fields that the server supports sorting on - /// - SortOptions, - /// /// The studios of the item /// diff --git a/MediaBrowser.Model/DTO/ItemQuery.cs b/MediaBrowser.Model/DTO/ItemQuery.cs index 6d64a093bc..085a872b1a 100644 --- a/MediaBrowser.Model/DTO/ItemQuery.cs +++ b/MediaBrowser.Model/DTO/ItemQuery.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Model.Dto /// What to sort the results by /// /// The sort by. - public ItemSortBy[] SortBy { get; set; } + public string[] SortBy { get; set; } /// /// The sort order to return results with @@ -116,12 +116,6 @@ namespace MediaBrowser.Model.Dto /// The index by. public string IndexBy { get; set; } - /// - /// The dynamic, localized sort function name - /// - /// The dynamic sort by. - public string DynamicSortBy { get; set; } - /// /// Gets or sets the image types. /// diff --git a/MediaBrowser.Model/DTO/ItemSortBy.cs b/MediaBrowser.Model/DTO/ItemSortBy.cs index 30cd1c3a45..141690a55a 100644 --- a/MediaBrowser.Model/DTO/ItemSortBy.cs +++ b/MediaBrowser.Model/DTO/ItemSortBy.cs @@ -2,41 +2,53 @@ namespace MediaBrowser.Model.Dto { /// - /// Enum ItemSortBy + /// These represent sort orders that are known by the core /// - public enum ItemSortBy + public static class ItemSortBy { /// /// The album /// - Album, + public const string Album = "Album"; /// /// The album artist /// - AlbumArtist, + public const string AlbumArtist = "AlbumArtist"; /// /// The artist /// - Artist, + public const string Artist = "Artist"; /// /// The date created /// - DateCreated, + public const string DateCreated = "DateCreated"; /// /// The date played /// - DatePlayed, + public const string DatePlayed = "DatePlayed"; /// /// The premiere date /// - PremiereDate, + public const string PremiereDate = "PremiereDate"; /// /// The sort name /// - SortName, + public const string SortName = "SortName"; /// /// The random /// - Random + public const string Random = "Random"; + /// + /// The runtime + /// + public const string Runtime = "Runtime"; + /// + /// The community rating + /// + public const string CommunityRating = "CommunityRating"; + /// + /// The production year + /// + public const string ProductionYear = "ProductionYear"; } } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 78ada14316..6cd46a3100 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -9,6 +9,7 @@ using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.ScheduledTasks; +using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations.Library.Resolvers; @@ -22,6 +23,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using SortOrder = MediaBrowser.Model.Entities.SortOrder; namespace MediaBrowser.Server.Implementations.Library { @@ -54,6 +56,12 @@ namespace MediaBrowser.Server.Implementations.Library /// The entity resolvers enumerable. private IEnumerable EntityResolvers { get; set; } + /// + /// Gets or sets the comparers. + /// + /// The comparers. + private IEnumerable Comparers { get; set; } + #region LibraryChanged Event /// /// Fires whenever any validation routine adds or removes items. The added and removed items are properties of the args. @@ -124,12 +132,14 @@ namespace MediaBrowser.Server.Implementations.Library /// The plugin folders. /// The resolvers. /// The intro providers. - public void AddParts(IEnumerable rules, IEnumerable pluginFolders, IEnumerable resolvers, IEnumerable introProviders) + /// The item comparers. + public void AddParts(IEnumerable rules, IEnumerable pluginFolders, IEnumerable resolvers, IEnumerable introProviders, IEnumerable itemComparers) { EntityResolutionIgnoreRules = rules; PluginFolderCreators = pluginFolders; EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray(); IntroProviders = introProviders; + Comparers = itemComparers; } /// @@ -702,5 +712,62 @@ namespace MediaBrowser.Server.Implementations.Library { return IntroProviders.SelectMany(i => i.GetIntros(item, user)); } + + /// + /// Sorts the specified sort by. + /// + /// The items. + /// The user. + /// The sort by. + /// The sort order. + /// IEnumerable{BaseItem}. + public IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, SortOrder sortOrder) + { + var isFirst = true; + + IOrderedEnumerable orderedItems = null; + + foreach (var orderBy in sortBy.Select(o => GetComparer(o, user)).Where(c => c != null)) + { + if (isFirst) + { + orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy); + } + else + { + orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy); + } + + isFirst = false; + } + + return orderedItems ?? items; + } + + /// + /// Gets the comparer. + /// + /// The name. + /// The user. + /// IBaseItemComparer. + private IBaseItemComparer GetComparer(string name, User user) + { + var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase)); + + if (comparer != null) + { + // If it requires a user, create a new one, and assign the user + if (comparer is IUserBaseItemComparer) + { + var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType()); + + userComparer.User = user; + + return userComparer; + } + } + + return comparer; + } } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 0b9f7c7e13..c8a7a2fc18 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -139,6 +139,17 @@ + + + + + + + + + + + diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs new file mode 100644 index 0000000000..e045cdfc87 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs @@ -0,0 +1,46 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class AlbumArtistComparer + /// + public class AlbumArtistComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); + } + + /// + /// Gets the value. + /// + /// The x. + /// System.String. + private string GetValue(BaseItem x) + { + var audio = x as Audio; + + return audio == null ? string.Empty : audio.AlbumArtist; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.AlbumArtist; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs new file mode 100644 index 0000000000..24e1f40da8 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs @@ -0,0 +1,46 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class AlbumComparer + /// + public class AlbumComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); + } + + /// + /// Gets the value. + /// + /// The x. + /// System.String. + private string GetValue(BaseItem x) + { + var audio = x as Audio; + + return audio == null ? string.Empty : audio.Album; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.Album; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs new file mode 100644 index 0000000000..278a397858 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs @@ -0,0 +1,46 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class ArtistComparer + /// + public class ArtistComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); + } + + /// + /// Gets the value. + /// + /// The x. + /// System.String. + private string GetValue(BaseItem x) + { + var audio = x as Audio; + + return audio == null ? string.Empty : audio.Artist; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.Artist; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs new file mode 100644 index 0000000000..2e1b73ccff --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs @@ -0,0 +1,29 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + public class CommunityRatingComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return (x.CommunityRating ?? 0).CompareTo(y.CommunityRating ?? 0); + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.CommunityRating; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs new file mode 100644 index 0000000000..d340913c94 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs @@ -0,0 +1,33 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class DateCreatedComparer + /// + public class DateCreatedComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return DateTime.Compare(x.DateCreated, y.DateCreated); + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.DateCreated; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs new file mode 100644 index 0000000000..49e4645594 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -0,0 +1,56 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class DatePlayedComparer + /// + public class DatePlayedComparer : IUserBaseItemComparer + { + /// + /// Gets or sets the user. + /// + /// The user. + public User User { get; set; } + + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return GetDate(x).CompareTo(GetDate(y)); + } + + /// + /// Gets the date. + /// + /// The x. + /// DateTime. + private DateTime GetDate(BaseItem x) + { + var userdata = x.GetUserData(User, false); + + if (userdata != null && userdata.LastPlayedDate.HasValue) + { + return userdata.LastPlayedDate.Value; + } + + return DateTime.MaxValue; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.DatePlayed; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs new file mode 100644 index 0000000000..2a8d524052 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs @@ -0,0 +1,52 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class PremiereDateComparer + /// + public class PremiereDateComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return GetDate(x).CompareTo(GetDate(y)); + } + + /// + /// Gets the date. + /// + /// The x. + /// DateTime. + 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; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.PremiereDate; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs new file mode 100644 index 0000000000..47a03048cc --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs @@ -0,0 +1,52 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class ProductionYearComparer + /// + public class ProductionYearComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return GetValue(x).CompareTo(GetValue(y)); + } + + /// + /// Gets the date. + /// + /// The x. + /// DateTime. + private int GetValue(BaseItem x) + { + if (x.ProductionYear.HasValue) + { + return x.ProductionYear.Value; + } + + if (x.PremiereDate.HasValue) + { + return x.PremiereDate.Value.Year; + } + + return 0; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.ProductionYear; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs new file mode 100644 index 0000000000..e7e98a8a01 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs @@ -0,0 +1,33 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class RandomComparer + /// + public class RandomComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return Guid.NewGuid().CompareTo(Guid.NewGuid()); + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.Random; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs new file mode 100644 index 0000000000..71893ef316 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs @@ -0,0 +1,32 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class RuntimeComparer + /// + public class RuntimeComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return (x.RunTimeTicks ?? 0).CompareTo(y.RunTimeTicks ?? 0); + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.Runtime; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs new file mode 100644 index 0000000000..067f8c453e --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs @@ -0,0 +1,33 @@ +using MediaBrowser.Controller.Entities; +using System; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Dto; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + /// + /// Class SortNameComparer + /// + public class SortNameComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase); + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.SortName; } + } + } +} diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index c822aae847..e156c465be 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -18,6 +18,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Updates; using MediaBrowser.Controller.Weather; using MediaBrowser.IsoMounter; @@ -242,7 +243,7 @@ namespace MediaBrowser.ServerApplication ServerManager.AddWebSocketListeners(GetExports(false)); ServerManager.Start(); - LibraryManager.AddParts(GetExports(), GetExports(), GetExports(), GetExports()); + LibraryManager.AddParts(GetExports(), GetExports(), GetExports(), GetExports(), GetExports()); ProviderManager.AddMetadataProviders(GetExports().OrderBy(e => e.Priority).ToArray()); } diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs index d567a9fd8e..26e0978a34 100644 --- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs +++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; @@ -78,7 +79,8 @@ namespace MediaBrowser.ServerApplication Cursor = Cursors.Wait; await Task.Run(() => { - IEnumerable children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children.OrderBy(i => i.SortName) : _libraryManager.RootFolder.GetChildren(CurrentUser, sortBy: LocalizedStrings.Instance.GetString("NameDispPref")); + IEnumerable children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children : _libraryManager.RootFolder.GetChildren(CurrentUser); + children = OrderByName(children, CurrentUser); foreach (Folder folder in children) { @@ -86,9 +88,12 @@ namespace MediaBrowser.ServerApplication var currentFolder = folder; Task.Factory.StartNew(() => { - var prefs = ddlProfile.SelectedItem != null ? currentFolder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")} : new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")}; + var prefs = ddlProfile.SelectedItem != null ? currentFolder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false) ?? new DisplayPreferences {SortBy = ItemSortBy.SortName} : new DisplayPreferences {SortBy = ItemSortBy.SortName}; var node = new TreeViewItem { Tag = currentFolder }; - AddChildren(node, currentFolder.GetChildren(CurrentUser, prefs.IndexBy, prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")), CurrentUser); + + var subChildren = currentFolder.GetChildren(CurrentUser, prefs.IndexBy); + subChildren = OrderByName(subChildren, CurrentUser); + AddChildren(node, subChildren, CurrentUser); node.Header = currentFolder.Name + " (" + node.Items.Count + ")"; tvwLibrary.Items.Add(node); @@ -100,6 +105,28 @@ namespace MediaBrowser.ServerApplication } + /// + /// Orders the name of the by. + /// + /// The items. + /// The user. + /// IEnumerable{BaseItem}. + private IEnumerable OrderByName(IEnumerable items, User user) + { + return OrderBy(items, user, ItemSortBy.SortName); + } + + /// + /// Orders the name of the by. + /// + /// The items. + /// The user. + /// IEnumerable{BaseItem}. + private IEnumerable OrderBy(IEnumerable items, User user, string order) + { + return _libraryManager.Sort(items, user, new[] { order }, SortOrder.Ascending); + } + /// /// Adds the children. /// @@ -115,7 +142,7 @@ namespace MediaBrowser.ServerApplication if (subFolder != null) { var prefs = subFolder.GetDisplayPrefs(user, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")}; - AddChildren(node, subFolder.GetChildren(user, sortBy: prefs.SortBy), user); + AddChildren(node, OrderBy(subFolder.GetChildren(user), user, prefs.SortBy), user); node.Header = item.Name + " (" + node.Items.Count + ")"; } else @@ -152,14 +179,29 @@ namespace MediaBrowser.ServerApplication { lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Visible; ddlIndexBy.ItemsSource = folder.IndexByOptionStrings; - ddlSortBy.ItemsSource = folder.SortByOptionStrings; + + ddlSortBy.ItemsSource = new [] + { + ItemSortBy.SortName, + ItemSortBy.Album, + ItemSortBy.AlbumArtist, + ItemSortBy.Artist, + ItemSortBy.CommunityRating, + ItemSortBy.DateCreated, + ItemSortBy.DatePlayed, + ItemSortBy.PremiereDate, + ItemSortBy.ProductionYear, + ItemSortBy.Random, + ItemSortBy.Runtime + }; + var prefs = folder.GetDisplayPrefs(ddlProfile.SelectedItem as User, false); ddlIndexBy.SelectedItem = prefs != null ? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref") : LocalizedStrings.Instance.GetString("NoneDispPref"); ddlSortBy.SelectedItem = prefs != null - ? prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref") - : LocalizedStrings.Instance.GetString("NameDispPref"); + ? prefs.SortBy ?? ItemSortBy.SortName + : ItemSortBy.SortName; } else { @@ -311,7 +353,7 @@ namespace MediaBrowser.ServerApplication var folder = treeItem != null ? treeItem.Tag as Folder : null; - var prefs = folder != null ? folder.GetDisplayPrefs(CurrentUser, true) : new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")}; + var prefs = folder != null ? folder.GetDisplayPrefs(CurrentUser, true) : new DisplayPreferences {SortBy = ItemSortBy.SortName}; if (folder != null && prefs.IndexBy != ddlIndexBy.SelectedItem as string) { //grab UI context so we can update within the below task @@ -326,7 +368,7 @@ namespace MediaBrowser.ServerApplication //re-build the current item's children as an index prefs.IndexBy = ddlIndexBy.SelectedItem as string; treeItem.Items.Clear(); - AddChildren(treeItem,folder.GetChildren(CurrentUser, prefs.IndexBy, prefs.SortBy), CurrentUser); + AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy), CurrentUser); treeItem.Header = folder.Name + "(" + treeItem.Items.Count + ")"; Cursor = Cursors.Arrow; @@ -367,7 +409,7 @@ namespace MediaBrowser.ServerApplication //re-sort prefs.SortBy = ddlSortBy.SelectedItem as string; treeItem.Items.Clear(); - AddChildren(treeItem,folder.GetChildren(CurrentUser,prefs.IndexBy, prefs.SortBy ?? LocalizedStrings.Instance.GetString("NameDispPref")), CurrentUser); + AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy ?? ItemSortBy.SortName), CurrentUser); treeItem.Header = folder.Name + "(" + treeItem.Items.Count + ")"; Cursor = Cursors.Arrow; diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index ec3137d837..88ef979509 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -76,7 +76,7 @@ - true + false false @@ -112,6 +112,9 @@ MinimumRecommendedRules.ruleset true + + LocalIntranet + ..\packages\Hardcodet.Wpf.TaskbarNotification.1.0.4.0\lib\net40\Hardcodet.Wpf.TaskbarNotification.dll diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx deleted file mode 100644 index 64676b0546..0000000000 Binary files a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx and /dev/null differ -- cgit v1.2.3 From b1be6f1d73272fb629ff453f6890766faeccf9de Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 10 Mar 2013 00:36:39 -0500 Subject: minor namespace changes in the model --- MediaBrowser.Api/Library/LibraryService.cs | 1 + .../UserLibrary/BaseItemsByNameService.cs | 1 + MediaBrowser.Api/UserLibrary/ItemsService.cs | 5 +- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 1 + MediaBrowser.Controller/Library/DtoBuilder.cs | 1 + MediaBrowser.Model/DTO/ItemFields.cs | 114 ------------------- MediaBrowser.Model/DTO/ItemFilter.cs | 38 ------- MediaBrowser.Model/DTO/ItemQuery.cs | 125 -------------------- MediaBrowser.Model/DTO/ItemSortBy.cs | 54 --------- MediaBrowser.Model/DTO/ItemsResult.cs | 25 ---- MediaBrowser.Model/DTO/MediaType.cs | 22 ---- MediaBrowser.Model/Dto/ItemsByNameQuery.cs | 52 --------- MediaBrowser.Model/MediaBrowser.Model.csproj | 13 +-- MediaBrowser.Model/Querying/ItemFields.cs | 114 +++++++++++++++++++ MediaBrowser.Model/Querying/ItemFilter.cs | 38 +++++++ MediaBrowser.Model/Querying/ItemQuery.cs | 126 +++++++++++++++++++++ MediaBrowser.Model/Querying/ItemSortBy.cs | 54 +++++++++ MediaBrowser.Model/Querying/ItemsByNameQuery.cs | 53 +++++++++ MediaBrowser.Model/Querying/ItemsResult.cs | 26 +++++ .../Sorting/AlbumArtistComparer.cs | 1 + .../Sorting/AlbumComparer.cs | 1 + .../Sorting/ArtistComparer.cs | 1 + .../Sorting/CommunityRatingComparer.cs | 1 + .../Sorting/DateCreatedComparer.cs | 1 + .../Sorting/DatePlayedComparer.cs | 1 + .../Sorting/PremiereDateComparer.cs | 1 + .../Sorting/ProductionYearComparer.cs | 1 + .../Sorting/RandomComparer.cs | 1 + .../Sorting/RuntimeComparer.cs | 1 + .../Sorting/SortNameComparer.cs | 1 + .../LibraryExplorer.xaml.cs | 1 + Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 34 files changed, 441 insertions(+), 444 deletions(-) delete mode 100644 MediaBrowser.Model/DTO/ItemFields.cs delete mode 100644 MediaBrowser.Model/DTO/ItemFilter.cs delete mode 100644 MediaBrowser.Model/DTO/ItemQuery.cs delete mode 100644 MediaBrowser.Model/DTO/ItemSortBy.cs delete mode 100644 MediaBrowser.Model/DTO/ItemsResult.cs delete mode 100644 MediaBrowser.Model/DTO/MediaType.cs delete mode 100644 MediaBrowser.Model/Dto/ItemsByNameQuery.cs create mode 100644 MediaBrowser.Model/Querying/ItemFields.cs create mode 100644 MediaBrowser.Model/Querying/ItemFilter.cs create mode 100644 MediaBrowser.Model/Querying/ItemQuery.cs create mode 100644 MediaBrowser.Model/Querying/ItemSortBy.cs create mode 100644 MediaBrowser.Model/Querying/ItemsByNameQuery.cs create mode 100644 MediaBrowser.Model/Querying/ItemsResult.cs 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/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 975f8bdfe4..0a47e5df6b 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -2,6 +2,7 @@ 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; diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index a02c3c0122..b344f9491a 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -2,6 +2,7 @@ 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; @@ -84,7 +85,7 @@ namespace MediaBrowser.Api.UserLibrary /// What to sort the results by /// /// The sort by. - [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; } /// @@ -98,7 +99,7 @@ namespace MediaBrowser.Api.UserLibrary /// Filters to apply to the results /// /// The filters. - [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; } /// 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; diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index bdaa51b6c1..ef5cbada0a 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Library { diff --git a/MediaBrowser.Model/DTO/ItemFields.cs b/MediaBrowser.Model/DTO/ItemFields.cs deleted file mode 100644 index 981afe8947..0000000000 --- a/MediaBrowser.Model/DTO/ItemFields.cs +++ /dev/null @@ -1,114 +0,0 @@ - -namespace MediaBrowser.Model.Dto -{ - /// - /// Used to control the data that gets attached to DtoBaseItems - /// - public enum ItemFields - { - /// - /// Audio properties - /// - AudioInfo, - - /// - /// The chapters - /// - Chapters, - - /// - /// The date created of the item - /// - DateCreated, - - /// - /// The display media type - /// - DisplayMediaType, - - /// - /// Item display preferences - /// - DisplayPreferences, - - /// - /// Genres - /// - Genres, - - /// - /// Child count, recursive child count, etc - /// - ItemCounts, - - /// - /// The fields that the server supports indexing on - /// - IndexOptions, - - /// - /// The item overview - /// - Overview, - - /// - /// The id of the item's parent - /// - ParentId, - - /// - /// The physical path of the item - /// - Path, - - /// - /// The list of people for the item - /// - People, - - /// - /// Imdb, tmdb, etc - /// - ProviderIds, - - /// - /// The aspect ratio of the primary image - /// - PrimaryImageAspectRatio, - - /// - /// AirDays, status, SeriesName, etc - /// - SeriesInfo, - - /// - /// The sort name of the item - /// - SortName, - - /// - /// The studios of the item - /// - Studios, - - /// - /// The taglines of the item - /// - Taglines, - - /// - /// The trailer url of the item - /// - TrailerUrls, - - /// - /// The user data of the item - /// - UserData, - - /// - /// The media streams - /// - MediaStreams - } -} diff --git a/MediaBrowser.Model/DTO/ItemFilter.cs b/MediaBrowser.Model/DTO/ItemFilter.cs deleted file mode 100644 index 038acc5874..0000000000 --- a/MediaBrowser.Model/DTO/ItemFilter.cs +++ /dev/null @@ -1,38 +0,0 @@ - -namespace MediaBrowser.Model.Dto -{ - /// - /// Enum ItemFilter - /// - public enum ItemFilter - { - /// - /// The item is a folder - /// - IsFolder = 1, - /// - /// The item is not folder - /// - IsNotFolder = 2, - /// - /// The item is unplayed - /// - IsUnplayed = 3, - /// - /// The item is played - /// - IsPlayed = 4, - /// - /// The item is a favorite - /// - IsFavorite = 5, - /// - /// The item is recently added - /// - IsRecentlyAdded = 6, - /// - /// The item is resumable - /// - IsResumable = 7 - } -} diff --git a/MediaBrowser.Model/DTO/ItemQuery.cs b/MediaBrowser.Model/DTO/ItemQuery.cs deleted file mode 100644 index 085a872b1a..0000000000 --- a/MediaBrowser.Model/DTO/ItemQuery.cs +++ /dev/null @@ -1,125 +0,0 @@ -using MediaBrowser.Model.Entities; -using System; - -namespace MediaBrowser.Model.Dto -{ - /// - /// Contains all the possible parameters that can be used to query for items - /// - public class ItemQuery - { - /// - /// The user to localize search results for - /// - /// The user id. - public Guid UserId { get; set; } - - /// - /// Specify this to localize the search to a specific item or folder. Omit to use the root. - /// - /// The parent id. - public string ParentId { get; set; } - - /// - /// Skips over a given number of items within the results. Use for paging. - /// - /// The start index. - public int? StartIndex { get; set; } - - /// - /// The maximum number of items to return - /// - /// The limit. - public int? Limit { get; set; } - - /// - /// What to sort the results by - /// - /// The sort by. - public string[] SortBy { get; set; } - - /// - /// The sort order to return results with - /// - /// The sort order. - public SortOrder? SortOrder { get; set; } - - /// - /// Filters to apply to the results - /// - /// The filters. - public ItemFilter[] Filters { get; set; } - - /// - /// Fields to return within the items, in addition to basic information - /// - /// The fields. - public ItemFields[] Fields { get; set; } - - /// - /// Whether or not to perform the query recursively - /// - /// true if recursive; otherwise, false. - public bool Recursive { get; set; } - - /// - /// Limit results to items containing specific genres - /// - /// The genres. - public string[] Genres { get; set; } - - /// - /// Limit results to items containing specific studios - /// - /// The studios. - public string[] Studios { get; set; } - - /// - /// Gets or sets the exclude item types. - /// - /// The exclude item types. - public string[] ExcludeItemTypes { get; set; } - - /// - /// Gets or sets the include item types. - /// - /// The include item types. - public string[] IncludeItemTypes { get; set; } - - /// - /// Limit results to items containing specific years - /// - /// The years. - public int[] Years { get; set; } - - /// - /// Limit results to items containing a specific person - /// - /// The person. - public string Person { get; set; } - - /// - /// If the Person filter is used, this can also be used to restrict to a specific person type - /// - /// The type of the person. - public string PersonType { get; set; } - - /// - /// Search characters used to find items - /// - /// The index by. - public string SearchTerm { get; set; } - - /// - /// The dynamic, localized index function name - /// - /// The index by. - public string IndexBy { get; set; } - - /// - /// Gets or sets the image types. - /// - /// The image types. - public ImageType[] ImageTypes { get; set; } - } -} diff --git a/MediaBrowser.Model/DTO/ItemSortBy.cs b/MediaBrowser.Model/DTO/ItemSortBy.cs deleted file mode 100644 index 141690a55a..0000000000 --- a/MediaBrowser.Model/DTO/ItemSortBy.cs +++ /dev/null @@ -1,54 +0,0 @@ - -namespace MediaBrowser.Model.Dto -{ - /// - /// These represent sort orders that are known by the core - /// - public static class ItemSortBy - { - /// - /// The album - /// - public const string Album = "Album"; - /// - /// The album artist - /// - public const string AlbumArtist = "AlbumArtist"; - /// - /// The artist - /// - public const string Artist = "Artist"; - /// - /// The date created - /// - public const string DateCreated = "DateCreated"; - /// - /// The date played - /// - public const string DatePlayed = "DatePlayed"; - /// - /// The premiere date - /// - public const string PremiereDate = "PremiereDate"; - /// - /// The sort name - /// - public const string SortName = "SortName"; - /// - /// The random - /// - public const string Random = "Random"; - /// - /// The runtime - /// - public const string Runtime = "Runtime"; - /// - /// The community rating - /// - public const string CommunityRating = "CommunityRating"; - /// - /// The production year - /// - public const string ProductionYear = "ProductionYear"; - } -} diff --git a/MediaBrowser.Model/DTO/ItemsResult.cs b/MediaBrowser.Model/DTO/ItemsResult.cs deleted file mode 100644 index 623e04fdd2..0000000000 --- a/MediaBrowser.Model/DTO/ItemsResult.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ProtoBuf; - -namespace MediaBrowser.Model.Dto -{ - /// - /// Represents the result of a query for items - /// - [ProtoContract] - public class ItemsResult - { - /// - /// The set of items returned based on sorting, paging, etc - /// - /// The items. - [ProtoMember(1)] - public BaseItemDto[] Items { get; set; } - - /// - /// The total number of records available - /// - /// The total record count. - [ProtoMember(2)] - public int TotalRecordCount { get; set; } - } -} diff --git a/MediaBrowser.Model/DTO/MediaType.cs b/MediaBrowser.Model/DTO/MediaType.cs deleted file mode 100644 index eae97e6163..0000000000 --- a/MediaBrowser.Model/DTO/MediaType.cs +++ /dev/null @@ -1,22 +0,0 @@ - -namespace MediaBrowser.Model.Dto -{ - /// - /// Enum MediaType - /// - public enum MediaType - { - /// - /// The audio - /// - Audio, - /// - /// The game - /// - Game, - /// - /// The video - /// - Video - } -} diff --git a/MediaBrowser.Model/Dto/ItemsByNameQuery.cs b/MediaBrowser.Model/Dto/ItemsByNameQuery.cs deleted file mode 100644 index a10b290123..0000000000 --- a/MediaBrowser.Model/Dto/ItemsByNameQuery.cs +++ /dev/null @@ -1,52 +0,0 @@ -using MediaBrowser.Model.Entities; -using System; - -namespace MediaBrowser.Model.Dto -{ - /// - /// Class ItemsByNameQuery - /// - public class ItemsByNameQuery - { - /// - /// Gets or sets the user id. - /// - /// The user id. - public Guid UserId { get; set; } - /// - /// Gets or sets the start index. - /// - /// The start index. - public int? StartIndex { get; set; } - /// - /// Gets or sets the size of the page. - /// - /// The size of the page. - public int? Limit { get; set; } - /// - /// Gets or sets a value indicating whether this is recursive. - /// - /// true if recursive; otherwise, false. - public bool Recursive { get; set; } - /// - /// Gets or sets the sort order. - /// - /// The sort order. - public SortOrder? SortOrder { get; set; } - /// - /// If specified the search will be localized within a specific item or folder - /// - /// The item id. - public string ItemId { get; set; } - /// - /// Fields to return within the items, in addition to basic information - /// - /// The fields. - public ItemFields[] Fields { get; set; } - /// - /// Gets or sets the person types. - /// - /// The person types. - public string[] PersonTypes { get; set; } - } -} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 6c2a62f911..36f585e5cd 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -45,8 +45,7 @@ - - + @@ -63,8 +62,8 @@ - - + + @@ -90,11 +89,11 @@ - - + + - + diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs new file mode 100644 index 0000000000..8cf9796c0e --- /dev/null +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -0,0 +1,114 @@ + +namespace MediaBrowser.Model.Querying +{ + /// + /// Used to control the data that gets attached to DtoBaseItems + /// + public enum ItemFields + { + /// + /// Audio properties + /// + AudioInfo, + + /// + /// The chapters + /// + Chapters, + + /// + /// The date created of the item + /// + DateCreated, + + /// + /// The display media type + /// + DisplayMediaType, + + /// + /// Item display preferences + /// + DisplayPreferences, + + /// + /// Genres + /// + Genres, + + /// + /// Child count, recursive child count, etc + /// + ItemCounts, + + /// + /// The fields that the server supports indexing on + /// + IndexOptions, + + /// + /// The item overview + /// + Overview, + + /// + /// The id of the item's parent + /// + ParentId, + + /// + /// The physical path of the item + /// + Path, + + /// + /// The list of people for the item + /// + People, + + /// + /// Imdb, tmdb, etc + /// + ProviderIds, + + /// + /// The aspect ratio of the primary image + /// + PrimaryImageAspectRatio, + + /// + /// AirDays, status, SeriesName, etc + /// + SeriesInfo, + + /// + /// The sort name of the item + /// + SortName, + + /// + /// The studios of the item + /// + Studios, + + /// + /// The taglines of the item + /// + Taglines, + + /// + /// The trailer url of the item + /// + TrailerUrls, + + /// + /// The user data of the item + /// + UserData, + + /// + /// The media streams + /// + MediaStreams + } +} diff --git a/MediaBrowser.Model/Querying/ItemFilter.cs b/MediaBrowser.Model/Querying/ItemFilter.cs new file mode 100644 index 0000000000..9c7f139a80 --- /dev/null +++ b/MediaBrowser.Model/Querying/ItemFilter.cs @@ -0,0 +1,38 @@ + +namespace MediaBrowser.Model.Querying +{ + /// + /// Enum ItemFilter + /// + public enum ItemFilter + { + /// + /// The item is a folder + /// + IsFolder = 1, + /// + /// The item is not folder + /// + IsNotFolder = 2, + /// + /// The item is unplayed + /// + IsUnplayed = 3, + /// + /// The item is played + /// + IsPlayed = 4, + /// + /// The item is a favorite + /// + IsFavorite = 5, + /// + /// The item is recently added + /// + IsRecentlyAdded = 6, + /// + /// The item is resumable + /// + IsResumable = 7 + } +} diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs new file mode 100644 index 0000000000..3b320a0110 --- /dev/null +++ b/MediaBrowser.Model/Querying/ItemQuery.cs @@ -0,0 +1,126 @@ +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using System; + +namespace MediaBrowser.Model.Querying +{ + /// + /// Contains all the possible parameters that can be used to query for items + /// + public class ItemQuery + { + /// + /// The user to localize search results for + /// + /// The user id. + public Guid UserId { get; set; } + + /// + /// Specify this to localize the search to a specific item or folder. Omit to use the root. + /// + /// The parent id. + public string ParentId { get; set; } + + /// + /// Skips over a given number of items within the results. Use for paging. + /// + /// The start index. + public int? StartIndex { get; set; } + + /// + /// The maximum number of items to return + /// + /// The limit. + public int? Limit { get; set; } + + /// + /// What to sort the results by + /// + /// The sort by. + public string[] SortBy { get; set; } + + /// + /// The sort order to return results with + /// + /// The sort order. + public SortOrder? SortOrder { get; set; } + + /// + /// Filters to apply to the results + /// + /// The filters. + public ItemFilter[] Filters { get; set; } + + /// + /// Fields to return within the items, in addition to basic information + /// + /// The fields. + public ItemFields[] Fields { get; set; } + + /// + /// Whether or not to perform the query recursively + /// + /// true if recursive; otherwise, false. + public bool Recursive { get; set; } + + /// + /// Limit results to items containing specific genres + /// + /// The genres. + public string[] Genres { get; set; } + + /// + /// Limit results to items containing specific studios + /// + /// The studios. + public string[] Studios { get; set; } + + /// + /// Gets or sets the exclude item types. + /// + /// The exclude item types. + public string[] ExcludeItemTypes { get; set; } + + /// + /// Gets or sets the include item types. + /// + /// The include item types. + public string[] IncludeItemTypes { get; set; } + + /// + /// Limit results to items containing specific years + /// + /// The years. + public int[] Years { get; set; } + + /// + /// Limit results to items containing a specific person + /// + /// The person. + public string Person { get; set; } + + /// + /// If the Person filter is used, this can also be used to restrict to a specific person type + /// + /// The type of the person. + public string PersonType { get; set; } + + /// + /// Search characters used to find items + /// + /// The index by. + public string SearchTerm { get; set; } + + /// + /// The dynamic, localized index function name + /// + /// The index by. + public string IndexBy { get; set; } + + /// + /// Gets or sets the image types. + /// + /// The image types. + public ImageType[] ImageTypes { get; set; } + } +} diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs new file mode 100644 index 0000000000..9599e2aac2 --- /dev/null +++ b/MediaBrowser.Model/Querying/ItemSortBy.cs @@ -0,0 +1,54 @@ + +namespace MediaBrowser.Model.Querying +{ + /// + /// These represent sort orders that are known by the core + /// + public static class ItemSortBy + { + /// + /// The album + /// + public const string Album = "Album"; + /// + /// The album artist + /// + public const string AlbumArtist = "AlbumArtist"; + /// + /// The artist + /// + public const string Artist = "Artist"; + /// + /// The date created + /// + public const string DateCreated = "DateCreated"; + /// + /// The date played + /// + public const string DatePlayed = "DatePlayed"; + /// + /// The premiere date + /// + public const string PremiereDate = "PremiereDate"; + /// + /// The sort name + /// + public const string SortName = "SortName"; + /// + /// The random + /// + public const string Random = "Random"; + /// + /// The runtime + /// + public const string Runtime = "Runtime"; + /// + /// The community rating + /// + public const string CommunityRating = "CommunityRating"; + /// + /// The production year + /// + public const string ProductionYear = "ProductionYear"; + } +} diff --git a/MediaBrowser.Model/Querying/ItemsByNameQuery.cs b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs new file mode 100644 index 0000000000..5be23f3dd6 --- /dev/null +++ b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs @@ -0,0 +1,53 @@ +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using System; + +namespace MediaBrowser.Model.Querying +{ + /// + /// Class ItemsByNameQuery + /// + public class ItemsByNameQuery + { + /// + /// Gets or sets the user id. + /// + /// The user id. + public Guid UserId { get; set; } + /// + /// Gets or sets the start index. + /// + /// The start index. + public int? StartIndex { get; set; } + /// + /// Gets or sets the size of the page. + /// + /// The size of the page. + public int? Limit { get; set; } + /// + /// Gets or sets a value indicating whether this is recursive. + /// + /// true if recursive; otherwise, false. + public bool Recursive { get; set; } + /// + /// Gets or sets the sort order. + /// + /// The sort order. + public SortOrder? SortOrder { get; set; } + /// + /// If specified the search will be localized within a specific item or folder + /// + /// The item id. + public string ItemId { get; set; } + /// + /// Fields to return within the items, in addition to basic information + /// + /// The fields. + public ItemFields[] Fields { get; set; } + /// + /// Gets or sets the person types. + /// + /// The person types. + public string[] PersonTypes { get; set; } + } +} diff --git a/MediaBrowser.Model/Querying/ItemsResult.cs b/MediaBrowser.Model/Querying/ItemsResult.cs new file mode 100644 index 0000000000..f8393b7fc3 --- /dev/null +++ b/MediaBrowser.Model/Querying/ItemsResult.cs @@ -0,0 +1,26 @@ +using MediaBrowser.Model.Dto; +using ProtoBuf; + +namespace MediaBrowser.Model.Querying +{ + /// + /// Represents the result of a query for items + /// + [ProtoContract] + public class ItemsResult + { + /// + /// The set of items returned based on sorting, paging, etc + /// + /// The items. + [ProtoMember(1)] + public BaseItemDto[] Items { get; set; } + + /// + /// The total number of records available + /// + /// The total record count. + [ProtoMember(2)] + public int TotalRecordCount { get; set; } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs index e045cdfc87..5356ecf9e8 100644 --- a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs index 24e1f40da8..f8d319e361 100644 --- a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs index 278a397858..e41185dff0 100644 --- a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs index 2e1b73ccff..5aa1ad100d 100644 --- a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs index d340913c94..5097ae4596 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs index 49e4645594..34b0335b89 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs index 2a8d524052..a3dd56b656 100644 --- a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs index 47a03048cc..6626929522 100644 --- a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs index e7e98a8a01..73c636bab6 100644 --- a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs index 71893ef316..576187b849 100644 --- a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs index 067f8c453e..5053b14dbd 100644 --- a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs @@ -2,6 +2,7 @@ using System; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs index 26e0978a34..1968bbc7d1 100644 --- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs +++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index f1ac09af5b..75ac535d80 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.40 + 3.0.42 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 8b22d08860..048cb1d45b 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.40 + 3.0.42 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index a97d2fc035..d5ca086be7 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.40 + 3.0.42 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + -- cgit v1.2.3 From 3acfd73d86a06fc024e4293e37aa4e0fe226409c Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 10 Mar 2013 01:45:16 -0500 Subject: fixed scheduled tasks firing too early --- .../BaseApplicationHost.cs | 65 ++++++++++++++++++++-- .../Udp/UdpServer.cs | 5 +- MediaBrowser.ServerApplication/ApplicationHost.cs | 50 +++++++++-------- 3 files changed, 93 insertions(+), 27 deletions(-) diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index a9c73d0e91..1950c1428e 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -13,7 +13,6 @@ using MediaBrowser.Common.Security; using MediaBrowser.Common.Updates; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.System; using MediaBrowser.Model.Updates; using SimpleInjector; using System; @@ -26,6 +25,10 @@ using System.Threading.Tasks; namespace MediaBrowser.Common.Implementations { + /// + /// Class BaseApplicationHost + /// + /// The type of the T application paths type. public abstract class BaseApplicationHost : IApplicationHost where TApplicationPathsType : class, IApplicationPaths, new() { @@ -87,6 +90,7 @@ namespace MediaBrowser.Common.Implementations /// /// Gets assemblies that failed to load /// + /// The failed assemblies. public List FailedAssemblies { get; protected set; } /// @@ -148,11 +152,31 @@ namespace MediaBrowser.Common.Implementations /// /// The kernel. protected ITaskManager TaskManager { get; private set; } + /// + /// Gets the security manager. + /// + /// The security manager. protected ISecurityManager SecurityManager { get; private set; } + /// + /// Gets the package manager. + /// + /// The package manager. protected IPackageManager PackageManager { get; private set; } + /// + /// Gets the HTTP client. + /// + /// The HTTP client. protected IHttpClient HttpClient { get; private set; } + /// + /// Gets the network manager. + /// + /// The network manager. protected INetworkManager NetworkManager { get; private set; } + /// + /// Gets the configuration manager. + /// + /// The configuration manager. protected IConfigurationManager ConfigurationManager { get; private set; } /// @@ -187,7 +211,21 @@ namespace MediaBrowser.Common.Implementations FindParts(); - Task.Run(() => ConfigureAutoRunAtStartup()); + await RunStartupTasks().ConfigureAwait(false); + } + + /// + /// Runs the startup tasks. + /// + /// Task. + protected virtual Task RunStartupTasks() + { + return Task.Run(() => + { + Resolve().AddTasks(GetExports(false)); + + Task.Run(() => ConfigureAutoRunAtStartup()); + }); } /// @@ -202,6 +240,10 @@ namespace MediaBrowser.Common.Implementations /// The name of the log file prefix. protected abstract string LogFilePrefixName { get; } + /// + /// Gets the configuration manager. + /// + /// IConfigurationManager. protected abstract IConfigurationManager GetConfigurationManager(); /// @@ -210,8 +252,6 @@ namespace MediaBrowser.Common.Implementations protected virtual void FindParts() { Plugins = GetExports(); - - Resolve().AddTasks(GetExports(false)); } /// @@ -236,6 +276,7 @@ namespace MediaBrowser.Common.Implementations /// /// Registers resources that classes will depend on /// + /// Task. protected virtual Task RegisterResources() { return Task.Run(() => @@ -509,10 +550,23 @@ namespace MediaBrowser.Common.Implementations } } + /// + /// Restarts this instance. + /// public abstract void Restart(); + /// + /// Gets or sets a value indicating whether this instance can self update. + /// + /// true if this instance can self update; otherwise, false. public abstract bool CanSelfUpdate { get; } + /// + /// Checks for update. + /// + /// The cancellation token. + /// The progress. + /// Task{CheckForUpdateResult}. public abstract Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress); /// @@ -529,6 +583,9 @@ namespace MediaBrowser.Common.Implementations EventHelper.QueueEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs { Argument = package.version }, Logger); } + /// + /// Shuts down. + /// public abstract void Shutdown(); } } diff --git a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs index c6869c12d7..8315b20008 100644 --- a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs +++ b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs @@ -127,7 +127,10 @@ namespace MediaBrowser.Server.Implementations.Udp /// public void Stop() { - _udpClient.Close(); + if (_udpClient != null) + { + _udpClient.Close(); + } } /// diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index e156c465be..d5a5057925 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -127,23 +127,21 @@ namespace MediaBrowser.ServerApplication /// /// The HTTP server. private IHttpServer HttpServer { get; set; } - + /// - /// Inits this instance. + /// Runs the startup tasks. /// /// Task. - public override async Task Init() + protected override async Task RunStartupTasks() { - await base.Init().ConfigureAwait(false); + // Do these before allowing the base method to run, which will invoke startup scheduled tasks + await ServerKernel.LoadRepositories(ServerConfigurationManager).ConfigureAwait(false); - Task.Run(async () => - { - await ServerKernel.LoadRepositories(ServerConfigurationManager).ConfigureAwait(false); + await base.RunStartupTasks().ConfigureAwait(false); - DirectoryWatchers.Start(); + DirectoryWatchers.Start(); - Parallel.ForEach(GetExports(), entryPoint => entryPoint.Run()); - }); + Parallel.ForEach(GetExports(), entryPoint => entryPoint.Run()); } /// @@ -206,13 +204,15 @@ namespace MediaBrowser.ServerApplication ServerKernel.FFMpegManager = new FFMpegManager(ServerKernel, ZipClient, JsonSerializer, ProtobufSerializer, LogManager, ApplicationPaths); ServerKernel.ImageManager = new ImageManager(ServerKernel, ProtobufSerializer, LogManager.GetLogger("ImageManager"), ApplicationPaths); - ServerKernel.UserDataRepositories = GetExports(); - ServerKernel.UserRepositories = GetExports(); - ServerKernel.DisplayPreferencesRepositories = GetExports(); - ServerKernel.ItemRepositories = GetExports(); - ServerKernel.WeatherProviders = GetExports(); - ServerKernel.ImageEnhancers = GetExports().OrderBy(e => e.Priority).ToArray(); - ServerKernel.StringFiles = GetExports(); + Parallel.Invoke( + () => ServerKernel.UserDataRepositories = GetExports(), + () => ServerKernel.UserRepositories = GetExports(), + () => ServerKernel.DisplayPreferencesRepositories = GetExports(), + () => ServerKernel.ItemRepositories = GetExports(), + () => ServerKernel.WeatherProviders = GetExports(), + () => ServerKernel.ImageEnhancers = GetExports().OrderBy(e => e.Priority).ToArray(), + () => ServerKernel.StringFiles = GetExports() + ); } /// @@ -238,14 +238,20 @@ namespace MediaBrowser.ServerApplication { base.FindParts(); - HttpServer.Init(GetExports(false)); + Parallel.Invoke( + + () => + { + HttpServer.Init(GetExports(false)); - ServerManager.AddWebSocketListeners(GetExports(false)); - ServerManager.Start(); + ServerManager.AddWebSocketListeners(GetExports(false)); + ServerManager.Start(); + }, - LibraryManager.AddParts(GetExports(), GetExports(), GetExports(), GetExports(), GetExports()); + () => LibraryManager.AddParts(GetExports(), GetExports(), GetExports(), GetExports(), GetExports()), - ProviderManager.AddMetadataProviders(GetExports().OrderBy(e => e.Priority).ToArray()); + () => ProviderManager.AddMetadataProviders(GetExports().OrderBy(e => e.Priority).ToArray()) + ); } /// -- cgit v1.2.3 From c7d2b3a407940110c3601c9a0d096a5dbc249bb8 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 10 Mar 2013 15:44:36 -0400 Subject: updated ffmpeg. cleaned up some unused api properties --- MediaBrowser.Controller/Library/DtoBuilder.cs | 3 - .../MediaBrowser.Controller.csproj | 2 +- .../MediaInfo/ffmpeg20130209.zip.REMOVED.git-id | 1 - .../MediaInfo/ffmpeg20130310.zip.REMOVED.git-id | 1 + MediaBrowser.Model/DTO/BaseItemDto.cs | 68 +++++++++++----------- .../Sorting/AlbumArtistComparer.cs | 3 +- .../Sorting/AlbumComparer.cs | 3 +- .../Sorting/ArtistComparer.cs | 3 +- .../Sorting/CommunityRatingComparer.cs | 1 - .../Sorting/DateCreatedComparer.cs | 3 +- .../Sorting/DatePlayedComparer.cs | 3 +- .../Sorting/PremiereDateComparer.cs | 3 +- .../Sorting/ProductionYearComparer.cs | 1 - .../Sorting/RandomComparer.cs | 3 +- .../Sorting/RuntimeComparer.cs | 1 - .../Sorting/SortNameComparer.cs | 3 +- 16 files changed, 44 insertions(+), 58 deletions(-) delete mode 100644 MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id create mode 100644 MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index ef5cbada0a..820fd8c007 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -367,9 +367,6 @@ namespace MediaBrowser.Controller.Library { var folder = (Folder)item; - dto.IsRoot = folder.IsRoot; - dto.IsVirtualFolder = folder.IsVirtualFolder; - if (fields.Contains(ItemFields.IndexOptions)) { dto.IndexOptions = folder.IndexByOptionStrings.ToArray(); diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 9b75290237..89353b2ef0 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -202,7 +202,7 @@ - + diff --git a/MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id b/MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id deleted file mode 100644 index 307afc51cb..0000000000 --- a/MediaBrowser.Controller/MediaInfo/ffmpeg20130209.zip.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -985770c0d2633a13719be2e5cf19554262415f62 \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id b/MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id new file mode 100644 index 0000000000..830011a04f --- /dev/null +++ b/MediaBrowser.Controller/MediaInfo/ffmpeg20130310.zip.REMOVED.git-id @@ -0,0 +1 @@ +a005e50576665b191cbd02b42d6260bffb764690 \ No newline at end of file diff --git a/MediaBrowser.Model/DTO/BaseItemDto.cs b/MediaBrowser.Model/DTO/BaseItemDto.cs index b1d3f83c23..e3034f58e9 100644 --- a/MediaBrowser.Model/DTO/BaseItemDto.cs +++ b/MediaBrowser.Model/DTO/BaseItemDto.cs @@ -154,20 +154,6 @@ namespace MediaBrowser.Model.Dto [ProtoMember(25)] public bool IsFolder { get; set; } - /// - /// If the item is a Folder this will determine if it's the Root or not - /// - /// null if [is root] contains no value, true if [is root]; otherwise, false. - [ProtoMember(26)] - public bool? IsRoot { get; set; } - - /// - /// If the item is a Folder this will determine if it's a VF or not - /// - /// null if [is virtual folder] contains no value, true if [is virtual folder]; otherwise, false. - [ProtoMember(27)] - public bool? IsVirtualFolder { get; set; } - /// /// Gets or sets the parent id. /// @@ -391,26 +377,6 @@ namespace MediaBrowser.Model.Dto return Type.Equals(type, StringComparison.OrdinalIgnoreCase); } - /// - /// Gets a value indicating whether this instance can resume. - /// - /// true if this instance can resume; otherwise, false. - [IgnoreDataMember] - public bool CanResume - { - get { return UserData != null && UserData.PlaybackPositionTicks > 0; } - } - - /// - /// Gets the resume position ticks. - /// - /// The resume position ticks. - [IgnoreDataMember] - public long ResumePositionTicks - { - get { return UserData == null ? 0 : UserData.PlaybackPositionTicks; } - } - /// /// Gets or sets the image tags. /// @@ -467,6 +433,26 @@ namespace MediaBrowser.Model.Dto [ProtoMember(69)] public string MediaType { get; set; } + /// + /// Gets a value indicating whether this instance can resume. + /// + /// true if this instance can resume; otherwise, false. + [IgnoreDataMember] + public bool CanResume + { + get { return UserData != null && UserData.PlaybackPositionTicks > 0; } + } + + /// + /// Gets the resume position ticks. + /// + /// The resume position ticks. + [IgnoreDataMember] + public long ResumePositionTicks + { + get { return UserData == null ? 0 : UserData.PlaybackPositionTicks; } + } + /// /// Gets the backdrop count. /// @@ -597,12 +583,26 @@ namespace MediaBrowser.Model.Dto get { return string.Equals(MediaType, Entities.MediaType.Game, StringComparison.OrdinalIgnoreCase); } } + /// + /// Gets a value indicating whether this instance is person. + /// + /// true if this instance is person; otherwise, false. [IgnoreDataMember] public bool IsPerson { get { return string.Equals(Type, "Person", StringComparison.OrdinalIgnoreCase); } } + /// + /// Gets a value indicating whether this instance is root. + /// + /// true if this instance is root; otherwise, false. + [IgnoreDataMember] + public bool IsRoot + { + get { return string.Equals(Type, "AggregateFolder", StringComparison.OrdinalIgnoreCase); } + } + /// /// Occurs when [property changed]. /// diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs index 5356ecf9e8..2493c0fc62 100644 --- a/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/AlbumArtistComparer.cs @@ -1,9 +1,8 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; -using System; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs index f8d319e361..f455d5c2bd 100644 --- a/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/AlbumComparer.cs @@ -1,9 +1,8 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; -using System; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs index e41185dff0..c34f096a2a 100644 --- a/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/ArtistComparer.cs @@ -1,9 +1,8 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; -using System; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs index 5aa1ad100d..bdd18a648b 100644 --- a/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/CommunityRatingComparer.cs @@ -1,6 +1,5 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting diff --git a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs index 5097ae4596..9862f0a8a6 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DateCreatedComparer.cs @@ -1,8 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; -using System; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs index 34b0335b89..db7e455c79 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -1,8 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; -using System; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs index a3dd56b656..fcbc58987d 100644 --- a/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/PremiereDateComparer.cs @@ -1,8 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; -using System; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs index 6626929522..16d5313347 100644 --- a/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/ProductionYearComparer.cs @@ -1,6 +1,5 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting diff --git a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs index 73c636bab6..b1677331ac 100644 --- a/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/RandomComparer.cs @@ -1,8 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; -using System; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { diff --git a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs index 576187b849..793cb265e8 100644 --- a/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/RuntimeComparer.cs @@ -1,6 +1,5 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.Sorting diff --git a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs index 5053b14dbd..873753a2b2 100644 --- a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs @@ -1,8 +1,7 @@ using MediaBrowser.Controller.Entities; -using System; using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; +using System; namespace MediaBrowser.Server.Implementations.Sorting { -- cgit v1.2.3 From e5592bd220f09a85314cd56fb9c5a287061b9752 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 10 Mar 2013 23:12:21 -0400 Subject: bring back support for byte ranged requests --- MediaBrowser.Api/Playback/Hls/AudioHlsService.cs | 4 +- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 2 +- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 3 +- MediaBrowser.Installer/App.xaml.cs | 8 +- .../MediaBrowser.Installer.csproj | 4 - .../HttpServer/BaseRestService.cs | 12 +- .../HttpServer/RangeRequestWriter.cs | 172 +++++++++++++++++++++ .../MediaBrowser.Server.Implementations.csproj | 1 + 8 files changed, 190 insertions(+), 16 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs 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..59ac741297 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 { @@ -35,6 +35,7 @@ namespace MediaBrowser.Api.Playback.Hls var file = SegmentFilePrefix + request.SegmentId + Path.GetExtension(Request.PathInfo); file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file); + Logger.Info(file); return ToStaticFileResult(file); } diff --git a/MediaBrowser.Installer/App.xaml.cs b/MediaBrowser.Installer/App.xaml.cs index a7c1681e88..3e1230d441 100644 --- a/MediaBrowser.Installer/App.xaml.cs +++ b/MediaBrowser.Installer/App.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace MediaBrowser.Installer { diff --git a/MediaBrowser.Installer/MediaBrowser.Installer.csproj b/MediaBrowser.Installer/MediaBrowser.Installer.csproj index 473e8d37ab..470a18463b 100644 --- a/MediaBrowser.Installer/MediaBrowser.Installer.csproj +++ b/MediaBrowser.Installer/MediaBrowser.Installer.csproj @@ -87,15 +87,11 @@ - - - - 4.0 diff --git a/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs b/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs index cdb6adbe73..89d1ea72d5 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using System.Net; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; @@ -257,6 +258,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer var stream = await factoryFn().ConfigureAwait(false); + var httpListenerResponse = (HttpListenerResponse) Response.OriginalResponse; + httpListenerResponse.SendChunked = false; + + if (IsRangeRequest) + { + return new RangeRequestWriter(Request.Headers, httpListenerResponse, stream); + } + + httpListenerResponse.ContentLength64 = stream.Length; return new StreamWriter(stream); } diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs new file mode 100644 index 0000000000..77e14362d1 --- /dev/null +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -0,0 +1,172 @@ +using ServiceStack.Service; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.HttpServer +{ + public class RangeRequestWriter : IStreamWriter + { + /// + /// Gets or sets the source stream. + /// + /// The source stream. + public Stream SourceStream { get; set; } + public HttpListenerResponse Response { get; set; } + public NameValueCollection RequestHeaders { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The request headers. + /// The response. + /// The source. + public RangeRequestWriter(NameValueCollection requestHeaders, HttpListenerResponse response, Stream source) + { + RequestHeaders = requestHeaders; + Response = response; + SourceStream = source; + } + + /// + /// The _requested ranges + /// + private List> _requestedRanges; + /// + /// Gets the requested ranges. + /// + /// The requested ranges. + protected IEnumerable> RequestedRanges + { + get + { + if (_requestedRanges == null) + { + _requestedRanges = new List>(); + + // Example: bytes=0-,32-63 + var ranges = RequestHeaders["Range"].Split('=')[1].Split(','); + + foreach (var range in ranges) + { + var vals = range.Split('-'); + + long start = 0; + long? end = null; + + if (!string.IsNullOrEmpty(vals[0])) + { + start = long.Parse(vals[0]); + } + if (!string.IsNullOrEmpty(vals[1])) + { + end = long.Parse(vals[1]); + } + + _requestedRanges.Add(new KeyValuePair(start, end)); + } + } + + return _requestedRanges; + } + } + + /// + /// Writes to. + /// + /// The response stream. + public void WriteTo(Stream responseStream) + { + Response.Headers["Accept-Ranges"] = "bytes"; + Response.StatusCode = 206; + + var task = WriteToAsync(responseStream); + + Task.WaitAll(task); + } + + /// + /// Writes to async. + /// + /// The response stream. + /// Task. + private Task WriteToAsync(Stream responseStream) + { + var requestedRange = RequestedRanges.First(); + + var totalLength = SourceStream.Length; + + // If the requested range is "0-", we can optimize by just doing a stream copy + if (!requestedRange.Value.HasValue) + { + return ServeCompleteRangeRequest(requestedRange, responseStream, totalLength); + } + + // This will have to buffer a portion of the content into memory + return ServePartialRangeRequest(requestedRange.Key, requestedRange.Value.Value, responseStream, totalLength); + } + + /// + /// Handles a range request of "bytes=0-" + /// This will serve the complete content and add the content-range header + /// + /// The requested range. + /// The response stream. + /// Total length of the content. + /// Task. + private Task ServeCompleteRangeRequest(KeyValuePair requestedRange, Stream responseStream, long totalContentLength) + { + var rangeStart = requestedRange.Key; + var rangeEnd = totalContentLength - 1; + var rangeLength = 1 + rangeEnd - rangeStart; + + // Content-Length is the length of what we're serving, not the original content + Response.ContentLength64 = rangeLength; + Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); + + if (rangeStart > 0) + { + SourceStream.Position = rangeStart; + } + + return SourceStream.CopyToAsync(responseStream); + } + + /// + /// Serves a partial range request + /// + /// The range start. + /// The range end. + /// The response stream. + /// Total length of the content. + /// Task. + private async Task ServePartialRangeRequest(long rangeStart, long rangeEnd, Stream responseStream, long totalContentLength) + { + var rangeLength = 1 + rangeEnd - rangeStart; + + // Content-Length is the length of what we're serving, not the original content + Response.ContentLength64 = rangeLength; + Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); + + SourceStream.Position = rangeStart; + + // Fast track to just copy the stream to the end + if (rangeEnd == totalContentLength - 1) + { + await SourceStream.CopyToAsync(responseStream).ConfigureAwait(false); + } + else + { + // Read the bytes we need + var buffer = new byte[Convert.ToInt32(rangeLength)]; + await SourceStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + await responseStream.WriteAsync(buffer, 0, Convert.ToInt32(rangeLength)).ConfigureAwait(false); + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index c8a7a2fc18..2bb75a18da 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -109,6 +109,7 @@ + -- cgit v1.2.3 From a96ec4f169f82d40595fbb0d8f40ccc90c1074e9 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 10 Mar 2013 23:17:36 -0400 Subject: better source stream disposal --- .../HttpServer/RangeRequestWriter.cs | 39 ++++++++++++---------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs index 77e14362d1..e5c4c9796b 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -94,31 +94,35 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// /// The response stream. /// Task. - private Task WriteToAsync(Stream responseStream) + private async Task WriteToAsync(Stream responseStream) { - var requestedRange = RequestedRanges.First(); + using (var source = SourceStream) + { + var requestedRange = RequestedRanges.First(); - var totalLength = SourceStream.Length; + var totalLength = SourceStream.Length; - // If the requested range is "0-", we can optimize by just doing a stream copy - if (!requestedRange.Value.HasValue) - { - return ServeCompleteRangeRequest(requestedRange, responseStream, totalLength); - } + // If the requested range is "0-", we can optimize by just doing a stream copy + if (!requestedRange.Value.HasValue) + { + await ServeCompleteRangeRequest(source, requestedRange, responseStream, totalLength).ConfigureAwait(false); + } - // This will have to buffer a portion of the content into memory - return ServePartialRangeRequest(requestedRange.Key, requestedRange.Value.Value, responseStream, totalLength); + // This will have to buffer a portion of the content into memory + await ServePartialRangeRequest(source, requestedRange.Key, requestedRange.Value.Value, responseStream, totalLength).ConfigureAwait(false); + } } /// /// Handles a range request of "bytes=0-" /// This will serve the complete content and add the content-range header /// + /// The source stream. /// The requested range. /// The response stream. /// Total length of the content. /// Task. - private Task ServeCompleteRangeRequest(KeyValuePair requestedRange, Stream responseStream, long totalContentLength) + private Task ServeCompleteRangeRequest(Stream sourceStream, KeyValuePair requestedRange, Stream responseStream, long totalContentLength) { var rangeStart = requestedRange.Key; var rangeEnd = totalContentLength - 1; @@ -130,21 +134,22 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (rangeStart > 0) { - SourceStream.Position = rangeStart; + sourceStream.Position = rangeStart; } - return SourceStream.CopyToAsync(responseStream); + return sourceStream.CopyToAsync(responseStream); } /// /// Serves a partial range request /// + /// The source stream. /// The range start. /// The range end. /// The response stream. /// Total length of the content. /// Task. - private async Task ServePartialRangeRequest(long rangeStart, long rangeEnd, Stream responseStream, long totalContentLength) + private async Task ServePartialRangeRequest(Stream sourceStream, long rangeStart, long rangeEnd, Stream responseStream, long totalContentLength) { var rangeLength = 1 + rangeEnd - rangeStart; @@ -152,18 +157,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer Response.ContentLength64 = rangeLength; Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); - SourceStream.Position = rangeStart; + sourceStream.Position = rangeStart; // Fast track to just copy the stream to the end if (rangeEnd == totalContentLength - 1) { - await SourceStream.CopyToAsync(responseStream).ConfigureAwait(false); + await sourceStream.CopyToAsync(responseStream).ConfigureAwait(false); } else { // Read the bytes we need var buffer = new byte[Convert.ToInt32(rangeLength)]; - await SourceStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + await sourceStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); await responseStream.WriteAsync(buffer, 0, Convert.ToInt32(rangeLength)).ConfigureAwait(false); } -- cgit v1.2.3 From de755c4b9363134d7df144387e6394578a0db12b Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 10 Mar 2013 23:44:22 -0400 Subject: fixed audio in hls --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 6 ++---- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index f22a9e09b4..66b1a3353f 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -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/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index 59ac741297..578eb93ac0 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -35,7 +35,6 @@ namespace MediaBrowser.Api.Playback.Hls var file = SegmentFilePrefix + request.SegmentId + Path.GetExtension(Request.PathInfo); file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file); - Logger.Info(file); return ToStaticFileResult(file); } -- cgit v1.2.3 From 7c677e0ee6e9e8b7816a7dae9cbf1c55502c3599 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Mon, 11 Mar 2013 00:04:08 -0400 Subject: better streaming logging --- .../Progressive/BaseProgressiveStreamingService.cs | 6 +----- .../Progressive/ProgressiveStreamWriter.cs | 21 +++++++++++++++++--- .../HttpServer/BaseRestService.cs | 2 +- .../HttpServer/StreamWriter.cs | 23 ++++++++++++++++++---- 4 files changed, 39 insertions(+), 13 deletions(-) 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); } /// 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; } + + /// + /// Initializes a new instance of the class. + /// + /// The path. + /// The state. + /// The logger. + public ProgressiveStreamWriter(string path, StreamState state, ILogger logger) + { + Path = path; + State = state; + Logger = logger; + } /// /// 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.Server.Implementations/HttpServer/BaseRestService.cs b/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs index 89d1ea72d5..0445cd8632 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/BaseRestService.cs @@ -267,7 +267,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer } httpListenerResponse.ContentLength64 = stream.Length; - return new StreamWriter(stream); + return new StreamWriter(stream, Logger); } string content; diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs index ab178b6ea5..6f5d6e25fe 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs @@ -1,4 +1,6 @@ -using ServiceStack.Service; +using MediaBrowser.Model.Logging; +using ServiceStack.Service; +using System; using System.IO; using System.Threading.Tasks; @@ -9,6 +11,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// public class StreamWriter : IStreamWriter { + private ILogger Logger { get; set; } + /// /// Gets or sets the source stream. /// @@ -19,9 +23,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// Initializes a new instance of the class. /// /// The source. - public StreamWriter(Stream source) + /// The logger. + public StreamWriter(Stream source, ILogger logger) { SourceStream = source; + Logger = logger; } /// @@ -42,9 +48,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// Task. private async Task WriteToAsync(Stream responseStream) { - using (var src = SourceStream) + try { - await src.CopyToAsync(responseStream).ConfigureAwait(false); + using (var src = SourceStream) + { + await src.CopyToAsync(responseStream).ConfigureAwait(false); + } + } + catch (Exception ex) + { + Logger.ErrorException("Error streaming media", ex); + + throw; } } } -- cgit v1.2.3 From 177d9cc1721aa347eeb7cc015a97361d04106437 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Mon, 11 Mar 2013 01:06:55 -0400 Subject: consolidated some api code --- MediaBrowser.Api/MediaBrowser.Api.csproj | 1 + MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- .../UserLibrary/BaseItemsByNameService.cs | 56 ++---------------- MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 58 ++++++++++++++++++ MediaBrowser.Api/UserLibrary/ItemsService.cs | 69 +--------------------- MediaBrowser.Model/Querying/ItemsByNameQuery.cs | 9 ++- 6 files changed, 72 insertions(+), 123 deletions(-) create mode 100644 MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index e0a9444a70..fc02410cc2 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -106,6 +106,7 @@ + diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 66b1a3353f..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 { diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 0a47e5df6b..5fb2097cd2 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -1,7 +1,6 @@ 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; @@ -24,12 +23,16 @@ namespace MediaBrowser.Api.UserLibrary /// The _user manager /// protected readonly IUserManager UserManager; + /// + /// The library manager + /// protected readonly ILibraryManager LibraryManager; /// /// Initializes a new instance of the class. /// /// The user manager. + /// The library manager. protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager) { UserManager = userManager; @@ -45,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 items; @@ -158,54 +161,7 @@ namespace MediaBrowser.Api.UserLibrary /// /// Class GetItemsByName /// - public class GetItemsByName : IReturn + public class GetItemsByName : BaseItemsRequest, IReturn { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public Guid UserId { get; set; } - - /// - /// Gets or sets the start index. - /// - /// The start index. - [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; } - - /// - /// Gets or sets the size of the page. - /// - /// The size of the page. - [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; } - - /// - /// Gets or sets a value indicating whether this is recursive. - /// - /// true if recursive; otherwise, false. - [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; } - - /// - /// Gets or sets the sort order. - /// - /// The sort order. - [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public SortOrder? SortOrder { get; set; } - - /// - /// If specified the search will be localized within a specific item or folder - /// - /// The item id. - [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; } - - /// - /// Fields to return within the items, in addition to basic information - /// - /// The fields. - 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 + { + /// + /// Gets or sets the user id. + /// + /// The user id. + [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public Guid UserId { get; set; } + + /// + /// Skips over a given number of items within the results. Use for paging. + /// + /// The start index. + [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; } + + /// + /// The maximum number of items to return + /// + /// The limit. + [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; } + + /// + /// Whether or not to perform the query recursively + /// + /// true if recursive; otherwise, false. + [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; } + + /// + /// Gets or sets the sort order. + /// + /// The sort order. + [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public SortOrder? SortOrder { get; set; } + + /// + /// Specify this to localize the search to a specific item or folder. Omit to use the root. + /// + /// The parent id. + [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; } + + /// + /// Fields to return within the items, in addition to basic information + /// + /// The fields. + [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 b344f9491a..ff062c1830 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -1,6 +1,5 @@ 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; @@ -17,43 +16,8 @@ namespace MediaBrowser.Api.UserLibrary /// [Route("/Users/{UserId}/Items", "GET")] [ServiceStack.ServiceHost.Api(Description = "Gets items based on a query.")] - public class GetItems : IReturn + public class GetItems : BaseItemsRequest, IReturn { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public Guid UserId { get; set; } - - /// - /// Specify this to localize the search to a specific item or folder. Omit to use the root. - /// - /// The parent id. - [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; } - - /// - /// Skips over a given number of items within the results. Use for paging. - /// - /// The start index. - [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; } - - /// - /// The maximum number of items to return - /// - /// The limit. - [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; } - - /// - /// Whether or not to perform the query recursively - /// - /// true if recursive; otherwise, false. - [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; } - /// /// Limit results to items containing a specific person /// @@ -88,13 +52,6 @@ namespace MediaBrowser.Api.UserLibrary [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; } - /// - /// The sort order to return results with - /// - /// The sort order. - [ApiMember(Name = "SortOrder", Description = "Optional. Ascending / Descending sort order", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public string SortOrder { get; set; } - /// /// Filters to apply to the results /// @@ -102,13 +59,6 @@ namespace MediaBrowser.Api.UserLibrary [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; } - /// - /// Fields to return within the items, in addition to basic information - /// - /// The fields. - [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; } - /// /// Limit results to items containing specific genres /// @@ -262,7 +212,7 @@ namespace MediaBrowser.Api.UserLibrary { var orderBy = GetOrderBy(request).ToArray(); - return orderBy.Length == 0 ? items : _libraryManager.Sort(items, user, orderBy, GetSortOrder(request) ?? SortOrder.Ascending); + return orderBy.Length == 0 ? items : _libraryManager.Sort(items, user, orderBy, request.SortOrder ?? SortOrder.Ascending); } /// @@ -466,21 +416,6 @@ namespace MediaBrowser.Api.UserLibrary return items; } - /// - /// Gets the sort order. - /// - /// The request. - /// System.Nullable{SortOrder}. - private SortOrder? GetSortOrder(GetItems request) - { - if (string.IsNullOrEmpty(request.SortOrder)) - { - return null; - } - - return (SortOrder)Enum.Parse(typeof(SortOrder), request.SortOrder, true); - } - /// /// Gets the filters. /// diff --git a/MediaBrowser.Model/Querying/ItemsByNameQuery.cs b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs index 5be23f3dd6..35964aea3d 100644 --- a/MediaBrowser.Model/Querying/ItemsByNameQuery.cs +++ b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Entities; using System; namespace MediaBrowser.Model.Querying @@ -35,10 +34,10 @@ namespace MediaBrowser.Model.Querying /// The sort order. public SortOrder? SortOrder { get; set; } /// - /// If specified the search will be localized within a specific item or folder + /// Gets or sets the parent id. /// - /// The item id. - public string ItemId { get; set; } + /// The parent id. + public string ParentId { get; set; } /// /// Fields to return within the items, in addition to basic information /// -- cgit v1.2.3 From f010d032edfabc3bc64d20aab9f5f6fdb3cfc330 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Mon, 11 Mar 2013 08:26:27 -0400 Subject: remove unused api properties --- MediaBrowser.Controller/Library/DtoBuilder.cs | 2 -- MediaBrowser.Model/DTO/BaseItemDto.cs | 7 ------- Nuget/MediaBrowser.Common.Internal.nuspec | 4 ++-- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 ++-- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index 820fd8c007..fcd3e68aa3 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -161,8 +161,6 @@ namespace MediaBrowser.Controller.Library /// The fields. private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List fields) { - dto.IsNew = item.IsRecentlyAdded(user); - if (fields.Contains(ItemFields.UserData)) { var userData = item.GetUserData(user, false); diff --git a/MediaBrowser.Model/DTO/BaseItemDto.cs b/MediaBrowser.Model/DTO/BaseItemDto.cs index e3034f58e9..5b63f588cb 100644 --- a/MediaBrowser.Model/DTO/BaseItemDto.cs +++ b/MediaBrowser.Model/DTO/BaseItemDto.cs @@ -217,13 +217,6 @@ namespace MediaBrowser.Model.Dto [ProtoMember(36)] public UserItemDataDto UserData { get; set; } - /// - /// Gets or sets a value indicating whether this instance is new. - /// - /// true if this instance is new; otherwise, false. - [ProtoMember(37)] - public bool IsNew { get; set; } - /// /// Gets or sets the recently added item count. /// diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 75ac535d80..4ba290fac7 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.42 + 3.0.43 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 048cb1d45b..36e8ce994c 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.42 + 3.0.43 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index d5ca086be7..5193e4480d 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.42 + 3.0.43 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + -- cgit v1.2.3 From 39020714f75b1bd1fe41355d4e9dadc9620ed8a1 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Mon, 11 Mar 2013 10:54:08 -0400 Subject: live saving on the metadata pages --- .../Playback/Progressive/VideoService.cs | 1 + .../Html/advancedMetadata.html | 7 +- MediaBrowser.WebDashboard/Html/metadata.html | 17 ++- MediaBrowser.WebDashboard/Html/metadataImages.html | 137 ++++++++++----------- .../scripts/AdvancedMetadataConfigurationPage.js | 10 +- .../Html/scripts/MetadataConfigurationPage.js | 8 +- .../Html/scripts/MetadataImagesPage.js | 8 +- 7 files changed, 99 insertions(+), 89 deletions(-) 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.WebDashboard/Html/advancedMetadata.html b/MediaBrowser.WebDashboard/Html/advancedMetadata.html index 60e02ba3c0..6ea3d7e74b 100644 --- a/MediaBrowser.WebDashboard/Html/advancedMetadata.html +++ b/MediaBrowser.WebDashboard/Html/advancedMetadata.html @@ -21,13 +21,10 @@
-
  • - -
  • diff --git a/MediaBrowser.WebDashboard/Html/metadata.html b/MediaBrowser.WebDashboard/Html/metadata.html index 4618dd4bd8..28fd7dedd0 100644 --- a/MediaBrowser.WebDashboard/Html/metadata.html +++ b/MediaBrowser.WebDashboard/Html/metadata.html @@ -18,32 +18,29 @@
    • - +
    • - +
    • - +
    • - +
    • - +
    • -
    • - -
    diff --git a/MediaBrowser.WebDashboard/Html/metadataImages.html b/MediaBrowser.WebDashboard/Html/metadataImages.html index b06a3205b7..0197af43da 100644 --- a/MediaBrowser.WebDashboard/Html/metadataImages.html +++ b/MediaBrowser.WebDashboard/Html/metadataImages.html @@ -18,7 +18,7 @@
    • - +
      When enabled, images will be refreshed periodically @@ -26,100 +26,100 @@
    • - +
    • - -
      -

      Movies

      -
      - - - - +
      +

      Movies

      +
      + + - - + + - - + + + + + + + + - - - -
      +
      -
      -

      TV Series

      -
      - - +
      +

      TV Series

      +
      + + - - + + - - + + - - -
      + +
      +
      -
      -

      TV Seasons

      -
      - - - - - +
      +

      TV Seasons

      +
      + + - - -
      + + + +
      -
      -

      Music Artists

      -
      - - +
      - - +
      +

      Music Artists

      +
      + + - - + + - - -
      + + + +
      - -
      -

      Music Albums

      -
      - - - - -
      +
      + +
      +

      Music Albums

      +
      + + + +
      +
      +
    • - @@ -130,7 +130,7 @@
    • - @@ -139,20 +139,17 @@
    • -
    • -
    • - -
    diff --git a/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js b/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js index 73ed3f4311..8b89add10a 100644 --- a/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js +++ b/MediaBrowser.WebDashboard/Html/scripts/AdvancedMetadataConfigurationPage.js @@ -33,7 +33,7 @@ var checkedAttribute = configuration.InternetProviderExcludeTypes.indexOf(type) != -1 ? ' checked="checked"' : ''; - html += ''; + html += ''; html += ''; } @@ -42,6 +42,12 @@ $('#divItemTypes', page).html(html).trigger("create"); }, + submit: function () { + + $('.btnSubmit', $.mobile.activePage)[0].click(); + + }, + onSubmit: function () { Dashboard.showLoadingMsg(); @@ -54,7 +60,7 @@ return currentCheckbox.getAttribute('data-itemtype'); }); - ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult); + ApiClient.updateServerConfiguration(config); }); // Disable default form submission diff --git a/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js b/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js index e68940b832..f7a9ba07b2 100644 --- a/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js +++ b/MediaBrowser.WebDashboard/Html/scripts/MetadataConfigurationPage.js @@ -79,6 +79,12 @@ $('#selectLanguage', '#metadataConfigurationPage').html(html).selectmenu("refresh"); }, + submit: function () { + + $('.btnSubmit', $.mobile.activePage)[0].click(); + + }, + onSubmit: function () { Dashboard.showLoadingMsg(); @@ -92,7 +98,7 @@ config.PreferredMetadataLanguage = $('#selectLanguage', form).val(); config.MetadataCountryCode = $('#selectCountry', form).val(); - ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult); + ApiClient.updateServerConfiguration(config); }); // Disable default form submission diff --git a/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js b/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js index 0dff46c398..e09172d36e 100644 --- a/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js +++ b/MediaBrowser.WebDashboard/Html/scripts/MetadataImagesPage.js @@ -42,6 +42,12 @@ Dashboard.hideLoadingMsg(); }, + submit: function () { + + $('.btnSubmit', $.mobile.activePage)[0].click(); + + }, + onSubmit: function () { Dashboard.showLoadingMsg(); @@ -75,7 +81,7 @@ config.DownloadMusicAlbumImages.Primary = $('#chkDownloadAlbumPrimary', form).checked(); config.DownloadMusicAlbumImages.Backdrops = $('#chkDownloadAlbumBackdrops', form).checked(); - ApiClient.updateServerConfiguration(config).done(Dashboard.processServerConfigurationUpdateResult); + ApiClient.updateServerConfiguration(config); }); // Disable default form submission -- cgit v1.2.3