diff options
23 files changed, 257 insertions, 410 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 33b80eabb..035939f70 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -22,4 +22,24 @@ - [Sagaia] (https://github.com/Sagaia) - [JHawk111](https://github.com/JHawk111) - [David3663](https://github.com/david3663) - - [DigiTM](https://github.com/DigiTM) + - [Smyken](https://github.com/Smyken) + - [doron1] (https://github.com/doron1) + - [brainfryd] (https://github.com/brainfryd) + - [DGMayor] (http://github.com/DGMayor) + - [Jon-theHTPC] (https://github.com/Jon-theHTPC) + - [aspdend] (https://github.com/aspdend) + - [RedshirtMB](https://github.com/RedshirtMB) + - [thealienamongus](https://github.com/thealienamongus) + - [brocass](https://github.com/brocass) + - [pjrollo2000](https://github.com/pjrollo2000) + - [abobader](https://github.com/abobader) + - [milli260876](https://github.com/milli260876) + - [vileboy] (https://github.com/vileboy) + - [starkadius] (https://github.com/starkadius) + - [wraslor](https://github.com/wraslor) + - [mrwebsmith](https://github.com/mrwebsmith) + - [rickster53](https://github.com/rickster53) + - [Tharnax] (https://github.com/Tharnax) + - [0sm0] (https://github.com/0sm0) + - [swhitmore](https://github.com/swhitmore) + - [DigiTM](https://github.com/DigiTM)
\ No newline at end of file diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 54b2c0ea7..09e175e30 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -273,13 +273,6 @@ namespace MediaBrowser.Api song.Artist = request.Artists[0]; } - var musicAlbum = item as MusicAlbum; - - if (musicAlbum != null) - { - musicAlbum.MusicBrainzReleaseGroupId = request.GetProviderId("MusicBrainzReleaseGroupId"); - } - var musicVideo = item as MusicVideo; if (musicVideo != null) diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 7e6444e16..563625a54 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.Api [ApiMember(Name = "TargetSystems", Description = "Optional. Filter by target system type. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET", AllowMultiple = true)] public string TargetSystems { get; set; } - [ApiMember(Name = "IsPremium", Description = "Optiona. Filter by premium status", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + [ApiMember(Name = "IsPremium", Description = "Optional. Filter by premium status", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? IsPremium { get; set; } } diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs index 85d2a2003..b2b858b6d 100644 --- a/MediaBrowser.Controller/Dto/DtoBuilder.cs +++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs @@ -90,6 +90,11 @@ namespace MediaBrowser.Controller.Dto } } + if (fields.Contains(ItemFields.DisplayPreferencesId)) + { + dto.DisplayPreferencesId = item.DisplayPreferencesId.ToString("N"); + } + if (user != null) { AttachUserSpecificInfo(dto, item, user, fields); @@ -272,11 +277,6 @@ namespace MediaBrowser.Controller.Dto /// <param name="fields">The fields.</param> private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields) { - if (item.IsFolder && fields.Contains(ItemFields.DisplayPreferencesId)) - { - dto.DisplayPreferencesId = ((Folder) item).DisplayPreferencesId.ToString("N"); - } - if (item.IsFolder) { var hasItemCounts = fields.Contains(ItemFields.ItemCounts); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 1526cf46a..1668b91d4 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -91,11 +91,5 @@ namespace MediaBrowser.Controller.Entities.Audio { return RecursiveChildren.OfType<Audio>().Any(i => i.HasArtist(artist)); } - - /// <summary> - /// Gets or sets the music brainz release group id. - /// </summary> - /// <value>The music brainz release group id.</value> - public string MusicBrainzReleaseGroupId { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cc2e82b1f..a75dc47e1 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; @@ -84,6 +85,21 @@ namespace MediaBrowser.Controller.Entities public Guid Id { get; set; } /// <summary> + /// Return the id that should be used to key display prefs for this item. + /// Default is based on the type for everything except actual generic folders. + /// </summary> + /// <value>The display prefs id.</value> + [IgnoreDataMember] + public virtual Guid DisplayPreferencesId + { + get + { + var thisType = GetType(); + return thisType == typeof(Folder) ? Id : thisType.FullName.GetMD5(); + } + } + + /// <summary> /// Gets or sets the path. /// </summary> /// <value>The path.</value> @@ -393,7 +409,12 @@ namespace MediaBrowser.Controller.Entities { get { - return ForcedSortName ?? _sortName ?? (_sortName = CreateSortName()); + if (!string.IsNullOrEmpty(ForcedSortName)) + { + return ForcedSortName; + } + + return _sortName ?? (_sortName = CreateSortName()); } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ca43ca616..91f4504c2 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -16,6 +16,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MoreLinq; namespace MediaBrowser.Controller.Entities { @@ -66,21 +67,6 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// Return the id that should be used to key display prefs for this item. - /// Default is based on the type for everything except actual generic folders. - /// </summary> - /// <value>The display prefs id.</value> - [IgnoreDataMember] - public virtual Guid DisplayPreferencesId - { - get - { - var thisType = GetType(); - return thisType == typeof(Folder) ? Id : thisType.FullName.GetMD5(); - } - } - public virtual List<LinkedChild> LinkedChildren { get; set; } protected virtual bool SupportsShortcutChildren @@ -974,7 +960,31 @@ namespace MediaBrowser.Controller.Entities /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param> /// <returns>IEnumerable{BaseItem}.</returns> /// <exception cref="System.ArgumentNullException"></exception> - public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = false) + public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + { + if (user == null) + { + throw new ArgumentNullException(); + } + + var children = GetRecursiveChildrenInternal(user, includeLinkedChildren); + + if (includeLinkedChildren) + { + children = children.DistinctBy(i => i.Id); + } + + return children; + } + + /// <summary> + /// Gets allowed recursive children of an item + /// </summary> + /// <param name="user">The user.</param> + /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param> + /// <returns>IEnumerable{BaseItem}.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + private IEnumerable<BaseItem> GetRecursiveChildrenInternal(User user, bool includeLinkedChildren) { if (user == null) { @@ -989,7 +999,7 @@ namespace MediaBrowser.Controller.Entities if (subFolder != null) { - foreach (var subitem in subFolder.GetRecursiveChildren(user, includeLinkedChildren)) + foreach (var subitem in subFolder.GetRecursiveChildrenInternal(user, includeLinkedChildren)) { yield return subitem; } diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index c1ca5336b..dc2b49c75 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using MoreLinq; namespace MediaBrowser.Controller.IO { @@ -38,7 +39,10 @@ namespace MediaBrowser.Controller.IO if (!resolveShortcuts && flattenFolderDepth == 0) { - return entries.ToDictionary(i => i.FullName, StringComparer.OrdinalIgnoreCase); + // Seeing dupes on some users file system for some reason + return entries + .DistinctBy(i => i.FullName, StringComparer.OrdinalIgnoreCase) + .ToDictionary(i => i.FullName, StringComparer.OrdinalIgnoreCase); } var dict = new Dictionary<string, FileSystemInfo>(StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 2761c51e0..ba4f84ac2 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -173,8 +173,16 @@ namespace MediaBrowser.Controller.Providers break; } case "SortTitle": - item.ForcedSortName = reader.ReadElementContentAsString(); - break; + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.ForcedSortName = val; + } + + break; + } case "Overview": case "Description": @@ -503,7 +511,7 @@ namespace MediaBrowser.Controller.Providers { DateTime airDate; - if (DateTime.TryParse(firstAired, out airDate) && airDate.Year > 1850) + if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out airDate) && airDate.Year > 1850) { item.PremiereDate = airDate.ToUniversalTime(); item.ProductionYear = airDate.Year; @@ -522,7 +530,7 @@ namespace MediaBrowser.Controller.Providers { DateTime airDate; - if (DateTime.TryParse(firstAired, out airDate) && airDate.Year > 1850) + if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out airDate) && airDate.Year > 1850) { item.EndDate = airDate.ToUniversalTime(); } @@ -548,13 +556,23 @@ namespace MediaBrowser.Controller.Providers break; case "MusicbrainzId": - var mbz = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(mbz)) { - item.SetProviderId(MetadataProviders.Musicbrainz, mbz); + var mbz = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(mbz)) + { + item.SetProviderId(MetadataProviders.Musicbrainz, mbz); + } + break; + } + case "MusicBrainzReleaseGroupId": + { + var mbz = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(mbz)) + { + item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, mbz); + } + break; } - break; - case "RottenTomatoesId": var rtId = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(rtId)) diff --git a/MediaBrowser.Model/Entities/MetadataProviders.cs b/MediaBrowser.Model/Entities/MetadataProviders.cs index b089b668c..db784a35f 100644 --- a/MediaBrowser.Model/Entities/MetadataProviders.cs +++ b/MediaBrowser.Model/Entities/MetadataProviders.cs @@ -34,6 +34,7 @@ namespace MediaBrowser.Model.Entities /// <summary> /// Tmdb Collection Id /// </summary> - TmdbCollection + TmdbCollection, + MusicBrainzReleaseGroup } } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index e80ba2b7d..69a23b84f 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -180,8 +180,7 @@ namespace MediaBrowser.Providers.Movies } private const string TmdbConfigUrl = "http://api.themoviedb.org/3/configuration?api_key={0}"; - private const string Search3 = @"http://api.themoviedb.org/3/search/movie?api_key={1}&query={0}&language={2}"; - private const string AltTitleSearch = @"http://api.themoviedb.org/3/movie/{0}/alternative_titles?api_key={1}&country={2}"; + private const string Search3 = @"http://api.themoviedb.org/3/search/{3}?api_key={1}&query={0}&language={2}"; private const string GetMovieInfo3 = @"http://api.themoviedb.org/3/movie/{0}?api_key={1}&language={2}&append_to_response=casts,releases,images,keywords,trailers"; private const string GetBoxSetInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&language={2}&append_to_response=images"; @@ -193,8 +192,6 @@ namespace MediaBrowser.Providers.Movies new Regex(@"(?<name>.*)") // last resort matches the whole string as the name }; - public const string AltMetaFileName = "movie.xml"; - protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) { if (HasAltMeta(item)) @@ -237,7 +234,10 @@ namespace MediaBrowser.Providers.Movies { return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName("collection.xml"); } - return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName(AltMetaFileName); + + var xmlFileName = MovieProviderFromXml.GetXmlFilename(item); + + return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName(xmlFileName); } /// <summary> @@ -248,8 +248,19 @@ namespace MediaBrowser.Providers.Movies /// <returns>Task.</returns> private async Task FetchMovieData(BaseItem item, CancellationToken cancellationToken) { - string id = item.GetProviderId(MetadataProviders.Tmdb) ?? await FindId(item, item.ProductionYear, cancellationToken).ConfigureAwait(false); - if (id != null) + var id = item.GetProviderId(MetadataProviders.Tmdb); + + if (string.IsNullOrEmpty(id)) + { + id = item.GetProviderId(MetadataProviders.Imdb); + } + + if (string.IsNullOrEmpty(id)) + { + id = await FindId(item, cancellationToken).ConfigureAwait(false); + } + + if (!string.IsNullOrEmpty(id)) { Logger.Debug("MovieDbProvider - getting movie info with id: " + id); @@ -291,21 +302,17 @@ namespace MediaBrowser.Providers.Movies /// Finds the id. /// </summary> /// <param name="item">The item.</param> - /// <param name="productionYear">The production year.</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>Task{System.String}.</returns> - public async Task<string> FindId(BaseItem item, int? productionYear, CancellationToken cancellationToken) + public async Task<string> FindId(BaseItem item, CancellationToken cancellationToken) { - int? year; + int? yearInName; string name = item.Name; - ParseName(name, out name, out year); + ParseName(name, out name, out yearInName); - if (year == null && productionYear != null) - { - year = productionYear; - } + var year = item.ProductionYear ?? yearInName; - Logger.Info("MovieDbProvider: Finding id for movie: " + name); + Logger.Info("MovieDbProvider: Finding id for item: " + name); string language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower(); //if we are a boxset - look at our first child @@ -313,19 +320,23 @@ namespace MediaBrowser.Providers.Movies if (boxset != null) { // See if any movies have a collection id already - return boxset.Children.Concat(boxset.GetLinkedChildren()).OfType<Video>() + var collId = boxset.Children.Concat(boxset.GetLinkedChildren()).OfType<Video>() .Select(i => i.GetProviderId(MetadataProviders.TmdbCollection)) .FirstOrDefault(i => i != null); + + if (collId != null) return collId; + } //nope - search for it - var id = await AttemptFindId(name, year, language, cancellationToken).ConfigureAwait(false); + var searchType = item is BoxSet ? "collection" : "movie"; + var id = await AttemptFindId(name, searchType, year, language, cancellationToken).ConfigureAwait(false); if (id == null) { //try in english if wasn't before if (language != "en") { - id = await AttemptFindId(name, year, "en", cancellationToken).ConfigureAwait(false); + id = await AttemptFindId(name, searchType, year, "en", cancellationToken).ConfigureAwait(false); } else { @@ -340,12 +351,12 @@ namespace MediaBrowser.Providers.Movies // Search again if the new name is different if (!string.Equals(name, originalName)) { - id = await AttemptFindId(name, year, language, cancellationToken).ConfigureAwait(false); + id = await AttemptFindId(name, searchType, year, language, cancellationToken).ConfigureAwait(false); if (id == null && language != "en") { //one more time, in english - id = await AttemptFindId(name, year, "en", cancellationToken).ConfigureAwait(false); + id = await AttemptFindId(name, searchType, year, "en", cancellationToken).ConfigureAwait(false); } } @@ -359,7 +370,7 @@ namespace MediaBrowser.Providers.Movies if (!string.Equals(pathName, name, StringComparison.OrdinalIgnoreCase) && !string.Equals(pathName, originalName, StringComparison.OrdinalIgnoreCase)) { - id = await AttemptFindId(pathName, year, "en", cancellationToken).ConfigureAwait(false); + id = await AttemptFindId(pathName, searchType, year, "en", cancellationToken).ConfigureAwait(false); } } } @@ -372,13 +383,14 @@ namespace MediaBrowser.Providers.Movies /// Attempts the find id. /// </summary> /// <param name="name">The name.</param> + /// <param name="type">movie or collection</param> /// <param name="year">The year.</param> /// <param name="language">The language.</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>Task{System.String}.</returns> - private async Task<string> AttemptFindId(string name, int? year, string language, CancellationToken cancellationToken) + private async Task<string> AttemptFindId(string name, string type, int? year, string language, CancellationToken cancellationToken) { - string url3 = string.Format(Search3, UrlEncode(name), ApiKey, language); + string url3 = string.Format(Search3, UrlEncode(name), ApiKey, language, type); TmdbMovieSearchResults searchResult = null; using (Stream json = await GetMovieDbResponse(new HttpRequestOptions @@ -392,95 +404,12 @@ namespace MediaBrowser.Providers.Movies searchResult = JsonSerializer.DeserializeFromStream<TmdbMovieSearchResults>(json); } - if (searchResult == null || searchResult.results.Count == 0) - { - //try replacing numbers - foreach (var pair in ReplaceStartNumbers) - { - if (name.StartsWith(pair.Key)) - { - name = name.Remove(0, pair.Key.Length); - name = pair.Value + name; - } - } - foreach (var pair in ReplaceEndNumbers) - { - if (name.EndsWith(pair.Key)) - { - name = name.Remove(name.IndexOf(pair.Key), pair.Key.Length); - name = name + pair.Value; - } - } - Logger.Info("MovieDBProvider - No results. Trying replacement numbers: " + name); - url3 = string.Format(Search3, UrlEncode(name), ApiKey, language); - - using (var json = await GetMovieDbResponse(new HttpRequestOptions - { - Url = url3, - CancellationToken = cancellationToken, - AcceptHeader = AcceptHeader - - }).ConfigureAwait(false)) - { - searchResult = JsonSerializer.DeserializeFromStream<TmdbMovieSearchResults>(json); - } - } if (searchResult != null) { - string compName = GetComparableName(name, Logger); foreach (var possible in searchResult.results) { - string matchedName = null; + string matchedName = possible.title ?? possible.name; string id = possible.id.ToString(CultureInfo.InvariantCulture); - string n = possible.title; - if (GetComparableName(n, Logger) == compName) - { - matchedName = n; - } - else - { - n = possible.original_title; - if (GetComparableName(n, Logger) == compName) - { - matchedName = n; - } - } - - Logger.Debug("MovieDbProvider - " + compName + " didn't match " + n); - //if main title matches we don't have to look for alternatives - if (matchedName == null) - { - //that title didn't match - look for alternatives - url3 = string.Format(AltTitleSearch, id, ApiKey, ConfigurationManager.Configuration.MetadataCountryCode); - - using (var json = await GetMovieDbResponse(new HttpRequestOptions - { - Url = url3, - CancellationToken = cancellationToken, - AcceptHeader = AcceptHeader - - }).ConfigureAwait(false)) - { - var response = JsonSerializer.DeserializeFromStream<TmdbAltTitleResults>(json); - - if (response != null && response.titles != null) - { - foreach (var title in response.titles) - { - var t = GetComparableName(title.title, Logger); - if (t == compName) - { - Logger.Debug("MovieDbProvider - " + compName + - " matched " + t); - matchedName = t; - break; - } - Logger.Debug("MovieDbProvider - " + compName + - " did not match " + t); - } - } - } - } if (matchedName != null) { @@ -520,45 +449,6 @@ namespace MediaBrowser.Providers.Movies } /// <summary> - /// Gets the boxset id from movie. - /// </summary> - /// <param name="name">The name.</param> - /// <param name="year">The year.</param> - /// <param name="language">The language.</param> - /// <param name="cancellationToken">The cancellation token</param> - /// <returns>Task{System.String}.</returns> - protected async Task<string> GetBoxsetIdFromMovie(string name, int? year, string language, CancellationToken cancellationToken) - { - string id = null; - string childId = await AttemptFindId(name, year, language, cancellationToken).ConfigureAwait(false); - if (childId != null) - { - string url = string.Format(GetMovieInfo3, childId, ApiKey, language); - - using (Stream json = await GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = AcceptHeader - - }).ConfigureAwait(false)) - { - var movieResult = JsonSerializer.DeserializeFromStream<CompleteMovieData>(json); - - if (movieResult != null && movieResult.belongs_to_collection != null) - { - id = movieResult.belongs_to_collection.id.ToString(CultureInfo.InvariantCulture); - } - else - { - Logger.Error("Unable to obtain boxset id."); - } - } - } - return id; - } - - /// <summary> /// Fetches the movie data. /// </summary> /// <param name="item">The item.</param> @@ -850,126 +740,6 @@ namespace MediaBrowser.Providers.Movies } } - /// <summary> - /// The remove - /// </summary> - const string Remove = "\"'!`?"; - // "Face/Off" support. - /// <summary> - /// The spacers - /// </summary> - const string Spacers = "/,.:;\\(){}[]+-_=–*"; // (there are not actually two - in the they are different char codes) - /// <summary> - /// The replace start numbers - /// </summary> - static readonly Dictionary<string, string> ReplaceStartNumbers = new Dictionary<string, string> { - {"1 ","one "}, - {"2 ","two "}, - {"3 ","three "}, - {"4 ","four "}, - {"5 ","five "}, - {"6 ","six "}, - {"7 ","seven "}, - {"8 ","eight "}, - {"9 ","nine "}, - {"10 ","ten "}, - {"11 ","eleven "}, - {"12 ","twelve "}, - {"13 ","thirteen "}, - {"100 ","one hundred "}, - {"101 ","one hundred one "} - }; - - /// <summary> - /// The replace end numbers - /// </summary> - static readonly Dictionary<string, string> ReplaceEndNumbers = new Dictionary<string, string> { - {" 1"," i"}, - {" 2"," ii"}, - {" 3"," iii"}, - {" 4"," iv"}, - {" 5"," v"}, - {" 6"," vi"}, - {" 7"," vii"}, - {" 8"," viii"}, - {" 9"," ix"}, - {" 10"," x"} - }; - - /// <summary> - /// Gets the name of the comparable. - /// </summary> - /// <param name="name">The name.</param> - /// <param name="logger">The logger.</param> - /// <returns>System.String.</returns> - internal static string GetComparableName(string name, ILogger logger) - { - name = name.ToLower(); - name = name.Replace("á", "a"); - name = name.Replace("é", "e"); - name = name.Replace("í", "i"); - name = name.Replace("ó", "o"); - name = name.Replace("ú", "u"); - name = name.Replace("ü", "u"); - name = name.Replace("ñ", "n"); - foreach (var pair in ReplaceStartNumbers) - { - if (name.StartsWith(pair.Key)) - { - name = name.Remove(0, pair.Key.Length); - name = pair.Value + name; - logger.Info("MovieDbProvider - Replaced Start Numbers: " + name); - } - } - foreach (var pair in ReplaceEndNumbers) - { - if (name.EndsWith(pair.Key)) - { - name = name.Remove(name.IndexOf(pair.Key), pair.Key.Length); - name = name + pair.Value; - logger.Info("MovieDbProvider - Replaced End Numbers: " + name); - } - } - name = name.Normalize(NormalizationForm.FormKD); - var sb = new StringBuilder(); - foreach (var c in name) - { - if (c >= 0x2B0 && c <= 0x0333) - { - // skip char modifier and diacritics - } - else if (Remove.IndexOf(c) > -1) - { - // skip chars we are removing - } - else if (Spacers.IndexOf(c) > -1) - { - sb.Append(" "); - } - else if (c == '&') - { - sb.Append(" and "); - } - else - { - sb.Append(c); - } - } - name = sb.ToString(); - name = name.Replace(", the", ""); - name = name.Replace(" the ", " "); - name = name.Replace("the ", ""); - - string prev_name; - do - { - prev_name = name; - name = name.Replace(" ", " "); - } while (name.Length != prev_name.Length); - - return name.Trim(); - } - #region Result Objects @@ -1058,6 +828,10 @@ namespace MediaBrowser.Providers.Movies /// <value>The vote_average.</value> public double vote_average { get; set; } /// <summary> + /// For collection search results + /// </summary> + public string name { get; set; } + /// <summary> /// Gets or sets the vote_count. /// </summary> /// <value>The vote_count.</value> diff --git a/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs b/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs index 76fee746c..762920955 100644 --- a/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs +++ b/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs @@ -52,6 +52,13 @@ namespace MediaBrowser.Providers.Movies get { return MetadataProviderPriority.First; } } + internal static string GetXmlFilename(BaseItem item) + { + var filename = "movie.xml"; + + return Path.Combine(item.MetaLocation, filename); + } + /// <summary> /// Override this to return the date that should be compared to the last refresh date /// to determine if this provider should be re-fetched. @@ -60,7 +67,7 @@ namespace MediaBrowser.Providers.Movies /// <returns>DateTime.</returns> protected override DateTime CompareDate(BaseItem item) { - var entry = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "movie.xml")); + var entry = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, GetXmlFilename(item))); return entry != null ? entry.LastWriteTimeUtc : DateTime.MinValue; } @@ -86,7 +93,7 @@ namespace MediaBrowser.Providers.Movies { cancellationToken.ThrowIfCancellationRequested(); - var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "movie.xml")); + var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, GetXmlFilename(item))); if (metadataFile != null) { diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs index b02128a37..fa7daaf25 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -182,10 +182,13 @@ namespace MediaBrowser.Providers.Music var releaseEntryId = item.GetProviderId(MetadataProviders.Musicbrainz); + var musicBrainzReleaseGroupId = album.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); // Fanart uses the release group id so we'll have to get that now using the release entry id - if (string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId)) + if (string.IsNullOrEmpty(musicBrainzReleaseGroupId)) { - album.MusicBrainzReleaseGroupId = await GetReleaseGroupId(releaseEntryId, cancellationToken).ConfigureAwait(false); + musicBrainzReleaseGroupId = await GetReleaseGroupId(releaseEntryId, cancellationToken).ConfigureAwait(false); + + album.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, musicBrainzReleaseGroupId); } var doc = new XmlDocument(); @@ -199,9 +202,9 @@ namespace MediaBrowser.Providers.Music // Try try with the release entry Id, if that doesn't produce anything try the release group id var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + releaseEntryId + "\"]/cdart/@url"); - if (node == null && !string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId)) + if (node == null && !string.IsNullOrEmpty(musicBrainzReleaseGroupId)) { - node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/cdart/@url"); + node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + musicBrainzReleaseGroupId + "\"]/cdart/@url"); } var path = node != null ? node.Value : null; @@ -218,9 +221,9 @@ namespace MediaBrowser.Providers.Music // Try try with the release entry Id, if that doesn't produce anything try the release group id var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + releaseEntryId + "\"]/albumcover/@url"); - if (node == null && !string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId)) + if (node == null && !string.IsNullOrEmpty(musicBrainzReleaseGroupId)) { - node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/albumcover/@url"); + node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + musicBrainzReleaseGroupId + "\"]/albumcover/@url"); } var path = node != null ? node.Value : null; diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs index 9a4899cba..154b4ab60 100644 --- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs @@ -119,11 +119,14 @@ namespace MediaBrowser.Providers.Savers public string GetSavePath(BaseItem item) { - var video = (Video)item; + if (item.IsInMixedFolder) + { + return Path.ChangeExtension(item.Path, ".xml"); + } + + var filename = MovieProviderFromXml.GetXmlFilename(item); - return video.IsInMixedFolder ? - Path.ChangeExtension(item.Path, ".xml") : - Path.Combine(item.MetaLocation, "movie.xml"); + return Path.Combine(item.MetaLocation, filename); } } } diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index 5c9e90312..edeea611a 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -65,6 +65,7 @@ namespace MediaBrowser.Providers.Savers "IMDbId", "TMDbId", "TVcomId", + "TvDbId", "RottenTomatoesId", "MusicbrainzId", "TMDbCollectionId", @@ -81,7 +82,8 @@ namespace MediaBrowser.Providers.Savers "BirthDate", "DeathDate", "LockedFields", - "Chapters" + "Chapters", + "MusicBrainzReleaseGroupId" }); var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase); @@ -332,6 +334,13 @@ namespace MediaBrowser.Providers.Savers builder.Append("<MusicbrainzId>" + SecurityElement.Escape(mbz) + "</MusicbrainzId>"); } + mbz = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); + + if (!string.IsNullOrEmpty(mbz)) + { + builder.Append("<MusicBrainzReleaseGroupId>" + SecurityElement.Escape(mbz) + "</MusicBrainzReleaseGroupId>"); + } + var gamesdb = item.GetProviderId(MetadataProviders.Gamesdb); if (!string.IsNullOrEmpty(gamesdb)) diff --git a/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs b/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs index 9ccbd3eb7..9099d10d6 100644 --- a/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs @@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.TV return ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataDownload; } } - + /// <summary> /// Gets the priority. /// </summary> @@ -147,7 +147,7 @@ namespace MediaBrowser.Providers.TV return seriesXmlFileInfo.LastWriteTimeUtc; } } - + return base.CompareDate(item); } @@ -240,7 +240,7 @@ namespace MediaBrowser.Providers.TV { return status; } - IEnumerable<XmlDocument> extraEpisodesNode = new XmlDocument[]{}; + IEnumerable<XmlDocument> extraEpisodesNode = new XmlDocument[] { }; if (episode.IndexNumberEnd.HasValue) { @@ -262,7 +262,7 @@ namespace MediaBrowser.Providers.TV var xElements = all.Where(x => int.Parse(x.Element("EpisodeNumber").Value) > episode.IndexNumber && int.Parse(x.Element("EpisodeNumber").Value) <= episode.IndexNumberEnd.Value); extraEpisodesNode = xElements.OrderBy(x => x.Element("EpisodeNumber").Value).Select(x => x.ToXmlDocument()); } - + } var doc = new XmlDocument(); doc.LoadXml(episodeNode.OuterXml); @@ -320,14 +320,15 @@ namespace MediaBrowser.Providers.TV var persons = Regex.Matches(actors, @"([^|()]|\([^)]*\)*)+") .Cast<Match>() .Select(m => m.Value).Where(i => !string.IsNullOrWhiteSpace(i) && !string.IsNullOrEmpty(i)); - foreach (var person in persons.Select(str => { - var nameGroup = str.Split(new[] {'('}, 2, StringSplitOptions.RemoveEmptyEntries); - var name = nameGroup[0].Trim(); - var roles = nameGroup.Count() > 1 ? nameGroup[1].Trim() : null; - if (roles != null) - roles = roles.EndsWith(")") ? roles.Substring(0, roles.Length - 1) : roles; - return new PersonInfo {Type = PersonType.GuestStar, Name = name, Role = roles}; - })) + foreach (var person in persons.Select(str => + { + var nameGroup = str.Split(new[] { '(' }, 2, StringSplitOptions.RemoveEmptyEntries); + var name = nameGroup[0].Trim(); + var roles = nameGroup.Count() > 1 ? nameGroup[1].Trim() : null; + if (roles != null) + roles = roles.EndsWith(")") ? roles.Substring(0, roles.Length - 1) : roles; + return new PersonInfo { Type = PersonType.GuestStar, Name = name, Role = roles }; + })) { episode.AddPerson(person); } @@ -340,14 +341,15 @@ namespace MediaBrowser.Providers.TV var persons = Regex.Matches(extraActors, @"([^|()]|\([^)]*\)*)+") .Cast<Match>() .Select(m => m.Value).Where(i => !string.IsNullOrWhiteSpace(i) && !string.IsNullOrEmpty(i)); - foreach (var person in persons.Select(str => { - var nameGroup = str.Split(new[] {'('}, 2, StringSplitOptions.RemoveEmptyEntries); - var name = nameGroup[0].Trim(); - var roles = nameGroup.Count() > 1 ? nameGroup[1].Trim() : null; - if (roles != null) - roles = roles.EndsWith(")") ? roles.Substring(0, roles.Length - 1) : roles; - return new PersonInfo {Type = PersonType.GuestStar, Name = name, Role = roles}; - }).Where(person => !episode.People.Any(x => x.Type == person.Type && x.Name == person.Name)) + foreach (var person in persons.Select(str => + { + var nameGroup = str.Split(new[] { '(' }, 2, StringSplitOptions.RemoveEmptyEntries); + var name = nameGroup[0].Trim(); + var roles = nameGroup.Count() > 1 ? nameGroup[1].Trim() : null; + if (roles != null) + roles = roles.EndsWith(")") ? roles.Substring(0, roles.Length - 1) : roles; + return new PersonInfo { Type = PersonType.GuestStar, Name = name, Role = roles }; + }).Where(person => !episode.People.Any(x => x.Type == person.Type && x.Name == person.Name)) ) { episode.AddPerson(person); @@ -358,9 +360,9 @@ namespace MediaBrowser.Providers.TV if (directors != null) { // Sometimes tvdb actors have leading spaces - foreach (var person in directors.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries) + foreach (var person in directors.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries) .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(str => new PersonInfo {Type = PersonType.Director, Name = str.Trim()})) + .Select(str => new PersonInfo { Type = PersonType.Director, Name = str.Trim() })) { episode.AddPerson(person); } @@ -371,9 +373,9 @@ namespace MediaBrowser.Providers.TV if (writers != null) { // Sometimes tvdb actors have leading spaces - foreach (var person in writers.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries) + foreach (var person in writers.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries) .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(str => new PersonInfo {Type = PersonType.Writer, Name = str.Trim()})) + .Select(str => new PersonInfo { Type = PersonType.Writer, Name = str.Trim() })) { episode.AddPerson(person); } diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs index e98a0a2c5..cb6097504 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs @@ -27,7 +27,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications private readonly INotificationsRepository _notificationsRepo; private readonly IUserManager _userManager; - private readonly TimeSpan _frequency = TimeSpan.FromHours(3); + private readonly TimeSpan _frequency = TimeSpan.FromHours(6); private readonly TimeSpan _maxAge = TimeSpan.FromDays(31); public RemoteNotifications(IApplicationPaths appPaths, ILogger logger, IHttpClient httpClient, IJsonSerializer json, INotificationsRepository notificationsRepo, IUserManager userManager) diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index d408e082a..4991db8e2 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -230,8 +230,6 @@ <EmbeddedResource Include="MediaEncoder\readme.txt" /> </ItemGroup> <ItemGroup> - <EmbeddedResource Include="MediaEncoder\fonts\ARIALUNI.TTF" /> - <EmbeddedResource Include="MediaEncoder\fonts\fonts.conf" /> <EmbeddedResource Include="MediaEncoder\ffmpeg20130813.zip" /> <None Include="packages.config" /> </ItemGroup> diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs index f5b5ea6c0..2ce49aabb 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.MediaInfo; +using MediaBrowser.Common.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -47,6 +48,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder /// <value>The json serializer.</value> private readonly IJsonSerializer _jsonSerializer; + private readonly IHttpClient _httpClient; + /// <summary> /// The video image resource pool /// </summary> @@ -81,12 +84,13 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder /// <param name="appPaths">The app paths.</param> /// <param name="jsonSerializer">The json serializer.</param> public MediaEncoder(ILogger logger, IZipClient zipClient, IApplicationPaths appPaths, - IJsonSerializer jsonSerializer) + IJsonSerializer jsonSerializer, IHttpClient httpClient) { _logger = logger; _zipClient = zipClient; _appPaths = appPaths; _jsonSerializer = jsonSerializer; + _httpClient = httpClient; // Not crazy about this but it's the only way to suppress ffmpeg crash dialog boxes SetErrorMode(ErrorModes.SEM_FAILCRITICALERRORS | ErrorModes.SEM_NOALIGNMENTFAULTEXCEPT | @@ -194,22 +198,30 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder /// <param name="assembly">The assembly.</param> /// <param name="zipFileResourcePath">The zip file resource path.</param> /// <param name="targetPath">The target path.</param> - private void ExtractTools(Assembly assembly, string zipFileResourcePath, string targetPath) + private async void ExtractTools(Assembly assembly, string zipFileResourcePath, string targetPath) { using (var resourceStream = assembly.GetManifestResourceStream(zipFileResourcePath)) { _zipClient.ExtractAll(resourceStream, targetPath, false); } - ExtractFonts(assembly, targetPath); + try + { + await DownloadFonts(targetPath).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting ffmpeg font files", ex); + } } + private const string FontUrl = "https://www.dropbox.com/s/9nb76tybcsw5xrk/ARIALUNI.zip?dl=1"; + /// <summary> /// Extracts the fonts. /// </summary> - /// <param name="assembly">The assembly.</param> /// <param name="targetPath">The target path.</param> - private async void ExtractFonts(Assembly assembly, string targetPath) + private async Task DownloadFonts(string targetPath) { var fontsDirectory = Path.Combine(targetPath, "fonts"); @@ -224,54 +236,44 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder if (!File.Exists(fontFile)) { - using (var stream = assembly.GetManifestResourceStream(GetType().Namespace + ".fonts." + fontFilename)) + var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions { - using ( - var fileStream = new FileStream(fontFile, FileMode.Create, FileAccess.Write, FileShare.Read, - StreamDefaults.DefaultFileStreamBufferSize, - FileOptions.Asynchronous)) - { - await stream.CopyToAsync(fileStream).ConfigureAwait(false); - } + Url = FontUrl, + Progress = new Progress<double>() + }); + + _zipClient.ExtractAll(tempFile, fontsDirectory, true); + + try + { + File.Delete(tempFile); + } + catch (IOException ex) + { + // Log this, but don't let it fail the operation + _logger.ErrorException("Error deleting temp file {0}", ex, tempFile); } } - await ExtractFontConfigFile(assembly, fontsDirectory).ConfigureAwait(false); + await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false); } - /// <summary> - /// Extracts the font config file. - /// </summary> - /// <param name="assembly">The assembly.</param> - /// <param name="fontsDirectory">The fonts directory.</param> - /// <returns>Task.</returns> - private async Task ExtractFontConfigFile(Assembly assembly, string fontsDirectory) + private async Task WriteFontConfigFile(string fontsDirectory) { const string fontConfigFilename = "fonts.conf"; var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename); if (!File.Exists(fontConfigFile)) { - using ( - var stream = assembly.GetManifestResourceStream(GetType().Namespace + ".fonts." + fontConfigFilename) - ) - { - using (var streamReader = new StreamReader(stream)) - { - var contents = await streamReader.ReadToEndAsync().ConfigureAwait(false); + var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory); - contents = contents.Replace("<dir></dir>", "<dir>" + fontsDirectory + "</dir>"); + var bytes = Encoding.UTF8.GetBytes(contents); - var bytes = Encoding.UTF8.GetBytes(contents); - - using ( - var fileStream = new FileStream(fontConfigFile, FileMode.Create, FileAccess.Write, - FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, - FileOptions.Asynchronous)) - { - await fileStream.WriteAsync(bytes, 0, bytes.Length); - } - } + using (var fileStream = new FileStream(fontConfigFile, FileMode.Create, FileAccess.Write, + FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, + FileOptions.Asynchronous)) + { + await fileStream.WriteAsync(bytes, 0, bytes.Length); } } } diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/fonts/fonts.conf b/MediaBrowser.Server.Implementations/MediaEncoder/fonts/fonts.conf deleted file mode 100644 index 648bdb7b2..000000000 --- a/MediaBrowser.Server.Implementations/MediaEncoder/fonts/fonts.conf +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<fontconfig> - -<dir></dir> - <alias> - <family>Arial</family> - <prefer>Arial Unicode MS</prefer> - </alias> -</fontconfig>
\ No newline at end of file diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 099b9a3df..eb8a73049 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -272,7 +272,7 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager)); - MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), ZipClient, ApplicationPaths, JsonSerializer); + MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), ZipClient, ApplicationPaths, JsonSerializer, HttpClient); RegisterSingleInstance(MediaEncoder); var clientConnectionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository); diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 0c5360b49..744debbcd 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -237,7 +237,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal @@ -1,7 +1,7 @@ Media Browser ============ -Media Browser Server is a media cataloging and transcoding server built on top of other popular open source technologies such as **Service Stack**, **jQuery** and **jQuery mobile**. +Media Browser Server is a home media server built on top of other popular open source technologies such as **Service Stack**, **jQuery**, **jQuery mobile** and **Lucene .NET**. It features a REST-based api with built-in documention to facilitate plugin development. |
