diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 224907a72a..cf79148f64 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -912,32 +912,6 @@ namespace MediaBrowser.Controller.Entities } } - /// - /// Determine if we have changed vs the passed in copy - /// - /// The copy. - /// true if the specified copy has changed; otherwise, false. - /// - public virtual bool HasChanged(BaseItem copy) - { - if (copy == null) - { - throw new ArgumentNullException(); - } - if (IsInMixedFolder != copy.IsInMixedFolder) - { - Logger.Debug(Name + " changed due to different value for IsInMixedFolder."); - return true; - } - - var changed = copy.DateModified != DateModified; - if (changed) - { - Logger.Debug(Name + " changed - original creation: " + DateCreated + " new creation: " + copy.DateCreated + " original modified: " + DateModified + " new modified: " + copy.DateModified); - } - return changed; - } - public virtual string GetClientTypeName() { return GetType().Name; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index c08a2ddf2f..ead8998739 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -181,8 +181,6 @@ namespace MediaBrowser.Controller.Entities item.Parent = null; - LibraryManager.ReportItemRemoved(item); - return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken); } @@ -220,7 +218,6 @@ namespace MediaBrowser.Controller.Entities {LocalizedStrings.Instance.GetString("GenreDispPref")}, {LocalizedStrings.Instance.GetString("DirectorDispPref")}, {LocalizedStrings.Instance.GetString("YearDispPref")}, - //{LocalizedStrings.Instance.GetString("OfficialRatingDispPref"), null}, {LocalizedStrings.Instance.GetString("StudioDispPref")} }; diff --git a/MediaBrowser.Controller/Library/DeleteOptions.cs b/MediaBrowser.Controller/Library/DeleteOptions.cs new file mode 100644 index 0000000000..81ed908993 --- /dev/null +++ b/MediaBrowser.Controller/Library/DeleteOptions.cs @@ -0,0 +1,8 @@ + +namespace MediaBrowser.Controller.Library +{ + public class DeleteOptions + { + public bool DeleteFileLocation { get; set; } + } +} diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index a34cfa78e8..0b1ac91371 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.Controller.Library /// The parent. /// BaseItem. BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null); - + /// /// Resolves a set of files into a list of BaseItem /// @@ -335,7 +335,19 @@ namespace MediaBrowser.Controller.Library /// Deletes the item. /// /// The item. + /// The options. /// Task. - Task DeleteItem(BaseItem item); + Task DeleteItem(BaseItem item, DeleteOptions options); + } + + public static class LibraryManagerExtensions + { + public static Task DeleteItem(this ILibraryManager manager, BaseItem item) + { + return manager.DeleteItem(item, new DeleteOptions + { + DeleteFileLocation = true + }); + } } } \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 32f2d151d4..c88164897c 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -111,6 +111,7 @@ + diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index cc43142563..02bca739f4 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -95,6 +95,13 @@ namespace MediaBrowser.Controller.Persistence /// IEnumerable{ChildDefinition}. IEnumerable GetChildren(Guid parentId); + /// + /// Gets the type of the items of. + /// + /// The type. + /// IEnumerable{Guid}. + IEnumerable GetItemsOfType(Type type); + /// /// Saves the children. /// diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index eb4d3d9a65..ab3bf96cfd 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -96,5 +96,19 @@ namespace MediaBrowser.Controller.Providers /// The item. /// MetadataOptions. MetadataOptions GetMetadataOptions(IHasImages item); + + /// + /// Gets the remote search results. + /// + /// The type of the t item type. + /// The type of the t lookup type. + /// The search information. + /// The cancellation token. + /// Task{IEnumerable{SearchResult{``1}}}. + Task> GetRemoteSearchResults( + RemoteSearchQuery searchInfo, + CancellationToken cancellationToken) + where TItemType : BaseItem, new() + where TLookupType : ItemLookupInfo; } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs index 2684900793..f00a22a3a4 100644 --- a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Providers; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -9,29 +11,27 @@ namespace MediaBrowser.Controller.Providers { } - public interface IRemoteMetadataProvider : IMetadataProvider, IRemoteMetadataProvider + public interface IRemoteMetadataProvider : IMetadataProvider, IRemoteMetadataProvider, IRemoteSearchProvider where TItemType : IHasMetadata, IHasLookupInfo where TLookupInfoType : ItemLookupInfo, new() { Task> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken); } - public interface IRemoteSearchProvider + public interface IRemoteSearchProvider : IMetadataProvider where TLookupInfoType : ItemLookupInfo { - string Name { get; } + Task> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken); - Task>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken); + /// + /// Gets the image response. + /// + /// The URL. + /// The cancellation token. + /// Task{HttpResponseInfo}. + Task GetImageResponse(string url, CancellationToken cancellationToken); } - public class SearchResult - where T : ItemLookupInfo - { - public T Item { get; set; } - - public string ImageUrl { get; set; } - } - public class RemoteSearchQuery where T : ItemLookupInfo { diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index d95c27efdc..8987cae5fa 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -338,6 +338,9 @@ Providers\RemoteImageResult.cs + + Providers\RemoteSearchResult.cs + Querying\ArtistsQuery.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 93d52e9c05..76fbe20007 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -325,6 +325,9 @@ Providers\RemoteImageResult.cs + + Providers\RemoteSearchResult.cs + Querying\ArtistsQuery.cs diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 136a78381c..efe450ac15 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -112,6 +112,7 @@ + diff --git a/MediaBrowser.Model/Providers/RemoteSearchResult.cs b/MediaBrowser.Model/Providers/RemoteSearchResult.cs new file mode 100644 index 0000000000..1222666143 --- /dev/null +++ b/MediaBrowser.Model/Providers/RemoteSearchResult.cs @@ -0,0 +1,39 @@ +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Model.Providers +{ + public class RemoteSearchResult : IHasProviderIds + { + /// + /// Gets or sets the name. + /// + /// The name. + public string Name { get; set; } + /// + /// Gets or sets the provider ids. + /// + /// The provider ids. + public Dictionary ProviderIds { get; set; } + /// + /// Gets or sets the year. + /// + /// The year. + public int? ProductionYear { get; set; } + public int? IndexNumber { get; set; } + public int? IndexNumberEnd { get; set; } + public int? ParentIndexNumber { get; set; } + + public DateTime? PremiereDate { get; set; } + + public string ImageUrl { get; set; } + + public string SearchProviderName { get; set; } + + public RemoteSearchResult() + { + ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + } +} diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs index beb8fe8870..bc29bad34d 100644 --- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Movies; using System; @@ -42,6 +43,11 @@ namespace MediaBrowser.Providers.BoxSets Current = this; } + public async Task> GetSearchResults(BoxSetInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(BoxSetInfo id, CancellationToken cancellationToken) { var tmdbId = id.GetProviderId(MetadataProviders.Tmdb); @@ -282,5 +288,10 @@ namespace MediaBrowser.Providers.BoxSets public List parts { get; set; } public Images images { get; set; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index a961be960e..f584c40fa7 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -586,7 +586,7 @@ namespace MediaBrowser.Providers.Manager } } - public async Task>> GetRemoteSearchResults(RemoteSearchQuery searchInfo, + public async Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo @@ -623,7 +623,7 @@ namespace MediaBrowser.Providers.Manager } // Nothing found - return new List>(); + return new List(); } } } \ No newline at end of file diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 2dc65e6208..2f1c5cf185 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -1,5 +1,4 @@ -using System.Linq; -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; @@ -9,10 +8,12 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -45,6 +46,11 @@ namespace MediaBrowser.Providers.Movies Current = this; } + public async Task> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public Task> GetMetadata(MovieInfo info, CancellationToken cancellationToken) { return GetItemMetadata(info, cancellationToken); @@ -549,5 +555,10 @@ namespace MediaBrowser.Providers.Movies return 1; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs index 0ad19840ea..8c981e2d86 100644 --- a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs @@ -1,6 +1,9 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Providers; using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -13,6 +16,11 @@ namespace MediaBrowser.Providers.Movies return MovieDbProvider.Current.GetItemMetadata(info, cancellationToken); } + public async Task> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public string Name { get { return MovieDbProvider.Current.Name; } @@ -31,5 +39,10 @@ namespace MediaBrowser.Providers.Movies return 1; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs index 20f4af52c6..a9b3d8e115 100644 --- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; @@ -15,7 +16,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Providers.Music { - public class AudioDbAlbumProvider : IRemoteMetadataProvider, IHasOrder + public class AudioDbAlbumProvider : IRemoteMetadataProvider, IHasOrder { private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; @@ -36,6 +37,11 @@ namespace MediaBrowser.Providers.Music Current = this; } + public async Task> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(AlbumInfo info, CancellationToken cancellationToken) { var result = new MetadataResult(); @@ -81,7 +87,7 @@ namespace MediaBrowser.Providers.Music item.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, result.strMusicBrainzArtistID); item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, result.strMusicBrainzID); } - + public string Name { get { return "TheAudioDB"; } @@ -112,7 +118,7 @@ namespace MediaBrowser.Providers.Music var url = AudioDbArtistProvider.BaseUrl + "/album-mb.php?i=" + musicBrainzReleaseGroupId; var path = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId); - + Directory.CreateDirectory(Path.GetDirectoryName(path)); using (var response = await _httpClient.Get(new HttpRequestOptions @@ -206,5 +212,10 @@ namespace MediaBrowser.Providers.Music { public List album { get; set; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs index 00c5b94e09..6659116185 100644 --- a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; @@ -36,6 +37,11 @@ namespace MediaBrowser.Providers.Music Current = this; } + public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(ArtistInfo info, CancellationToken cancellationToken) { var result = new MetadataResult(); @@ -213,5 +219,10 @@ namespace MediaBrowser.Providers.Music return 1; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs index e1fd05a50c..f7086d8e6b 100644 --- a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MoreLinq; using System; @@ -32,6 +33,11 @@ namespace MediaBrowser.Providers.Music _logger = logger; } + public async Task> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(AlbumInfo id, CancellationToken cancellationToken) { var result = new MetadataResult(); @@ -204,6 +210,11 @@ namespace MediaBrowser.Providers.Music return 2; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } #region Result Objects diff --git a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs index b52185ccc2..a50e5f9d53 100644 --- a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs @@ -5,8 +5,10 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -38,6 +40,11 @@ namespace MediaBrowser.Providers.Music _logger = logger; } + public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(ArtistInfo id, CancellationToken cancellationToken) { var result = new MetadataResult(); @@ -170,5 +177,10 @@ namespace MediaBrowser.Providers.Music return 2; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs index 99fe5c38dc..55dcc99f58 100644 --- a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs +++ b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs @@ -1,8 +1,10 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Providers; using MediaBrowser.Providers.Movies; using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -15,6 +17,11 @@ namespace MediaBrowser.Providers.Music return MovieDbProvider.Current.GetItemMetadata(info, cancellationToken); } + public async Task> GetSearchResults(MusicVideoInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public string Name { get { return MovieDbProvider.Current.Name; } @@ -24,5 +31,10 @@ namespace MediaBrowser.Providers.Music { return MovieDbProvider.Current.HasChanged(item, date); } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index 1a3860dab6..43ee7bdbc0 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -3,7 +3,9 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Text; @@ -27,6 +29,11 @@ namespace MediaBrowser.Providers.Music Current = this; } + public async Task> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(AlbumInfo id, CancellationToken cancellationToken) { var releaseId = id.GetReleaseId(); @@ -232,5 +239,10 @@ namespace MediaBrowser.Providers.Music { get { return 0; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index 3c45a7a488..7c0233d3e3 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -1,7 +1,10 @@ -using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; @@ -14,6 +17,11 @@ namespace MediaBrowser.Providers.Music { public class MusicBrainzArtistProvider : IRemoteMetadataProvider { + public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(ArtistInfo id, CancellationToken cancellationToken) { var result = new MetadataResult(); @@ -115,5 +123,10 @@ namespace MediaBrowser.Providers.Music { get { return "MusicBrainz"; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs index 3f30626fff..f1cfebceaa 100644 --- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs @@ -5,11 +5,12 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Movies; using MediaBrowser.Providers.TV; using System; -using System.Globalization; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -29,6 +30,21 @@ namespace MediaBrowser.Providers.Omdb _logger = logger; } + public async Task> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + + public async Task> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + + public async Task> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public string Name { get { return "IMDb via The Open Movie Database"; } @@ -139,5 +155,10 @@ namespace MediaBrowser.Providers.Omdb return new Tuple(imdb, tvdb); } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index 5691190dc5..792c9e910d 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -6,6 +6,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Movies; using System; @@ -42,7 +43,7 @@ namespace MediaBrowser.Providers.People get { return "TheMovieDb"; } } - public async Task>> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken) + public async Task> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken) { var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb); @@ -59,18 +60,15 @@ namespace MediaBrowser.Providers.People var images = (info.images ?? new Images()).profiles ?? new List(); - var result = new SearchResult + var result = new RemoteSearchResult { - Item = new PersonLookupInfo - { - Name = info.name - }, + Name = info.name, ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path) }; - result.Item.SetProviderId(MetadataProviders.Tmdb, info.id.ToString(_usCulture)); - result.Item.SetProviderId(MetadataProviders.Imdb, info.imdb_id.ToString(_usCulture)); + result.SetProviderId(MetadataProviders.Tmdb, info.id.ToString(_usCulture)); + result.SetProviderId(MetadataProviders.Imdb, info.imdb_id.ToString(_usCulture)); return new[] { result }; } @@ -92,19 +90,16 @@ namespace MediaBrowser.Providers.People } } - private SearchResult GetSearchResult(PersonSearchResult i, string baseImageUrl) + private RemoteSearchResult GetSearchResult(PersonSearchResult i, string baseImageUrl) { - var result = new SearchResult + var result = new RemoteSearchResult { - Item = new PersonLookupInfo - { - Name = i.Name - }, + Name = i.Name, ImageUrl = string.IsNullOrEmpty(i.Profile_Path) ? null : (baseImageUrl + i.Profile_Path) }; - result.Item.SetProviderId(MetadataProviders.Tmdb, i.Id.ToString(_usCulture)); + result.SetProviderId(MetadataProviders.Tmdb, i.Id.ToString(_usCulture)); return result; } @@ -175,7 +170,7 @@ namespace MediaBrowser.Providers.People { var results = await GetSearchResults(info, cancellationToken).ConfigureAwait(false); - return results.Select(i => i.Item.GetProviderId(MetadataProviders.Tmdb)).FirstOrDefault(); + return results.Select(i => i.GetProviderId(MetadataProviders.Tmdb)).FirstOrDefault(); } internal async Task EnsurePersonInfo(string id, CancellationToken cancellationToken) @@ -351,5 +346,10 @@ namespace MediaBrowser.Providers.People } #endregion + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs index 5f9754e4aa..b640e373bd 100644 --- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs @@ -367,22 +367,32 @@ namespace MediaBrowser.Providers.TV return Path.Combine(dataPath, "fanart.xml"); } - private readonly Task _cachedTask = Task.FromResult(true); - internal Task EnsureSeriesXml(string tvdbId, CancellationToken cancellationToken) + private readonly SemaphoreSlim _ensureSemaphore = new SemaphoreSlim(1, 1); + internal async Task EnsureSeriesXml(string tvdbId, CancellationToken cancellationToken) { - var xmlPath = GetSeriesDataPath(_config.ApplicationPaths, tvdbId); + var xmlPath = GetFanartXmlPath(tvdbId); - var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath); + // Only allow one thread in here at a time since every season will be calling this method, possibly concurrently + await _ensureSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - if (fileInfo.Exists) + try { - if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7) - { - return _cachedTask; - } - } + var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath); - return DownloadSeriesXml(tvdbId, cancellationToken); + if (fileInfo.Exists) + { + if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7) + { + return; + } + } + + await DownloadSeriesXml(tvdbId, cancellationToken).ConfigureAwait(false); + } + finally + { + _ensureSemaphore.Release(); + } } /// diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index fafd829485..f4191fe8f4 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; @@ -20,13 +21,15 @@ namespace MediaBrowser.Providers.TV { private readonly IServerConfigurationManager _config; private readonly ILogger _logger; + private readonly ILibraryManager _libraryManager; private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config) + public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager) { _logger = logger; _config = config; + _libraryManager = libraryManager; } public async Task Run(IEnumerable> series, CancellationToken cancellationToken) @@ -268,7 +271,7 @@ namespace MediaBrowser.Providers.TV { _logger.Info("Removing missing/unaired episode {0} {1}x{2}", episodeToRemove.Series.Name, episodeToRemove.ParentIndexNumber, episodeToRemove.IndexNumber); - await episodeToRemove.Parent.RemoveChild(episodeToRemove, cancellationToken).ConfigureAwait(false); + await _libraryManager.DeleteItem(episodeToRemove).ConfigureAwait(false); hasChanges = true; } @@ -327,7 +330,7 @@ namespace MediaBrowser.Providers.TV { _logger.Info("Removing virtual season {0} {1}", seasonToRemove.Series.Name, seasonToRemove.IndexNumber); - await seasonToRemove.Parent.RemoveChild(seasonToRemove, cancellationToken).ConfigureAwait(false); + await _libraryManager.DeleteItem(seasonToRemove).ConfigureAwait(false); hasChanges = true; } diff --git a/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs index 5b7679e744..165f901ea0 100644 --- a/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs @@ -8,15 +8,16 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Movies; using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; -using System.Linq; namespace MediaBrowser.Providers.TV { @@ -48,6 +49,11 @@ namespace MediaBrowser.Providers.TV get { return "TheMovieDb"; } } + public async Task> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(SeriesInfo info, CancellationToken cancellationToken) { var result = new MetadataResult(); @@ -453,5 +459,10 @@ namespace MediaBrowser.Providers.TV return 2; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs index 6ba9b4cdc1..8c9b8672c7 100644 --- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Providers.TV group series by tvdbId into g select g; - await new MissingEpisodeProvider(_logger, _config).Run(seriesGroups, cancellationToken).ConfigureAwait(false); + await new MissingEpisodeProvider(_logger, _config, _libraryManager).Run(seriesGroups, cancellationToken).ConfigureAwait(false); var numComplete = 0; diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs index fd77b9b87b..08d21ab39a 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs @@ -1,9 +1,11 @@ using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; using System.Globalization; @@ -34,17 +36,54 @@ namespace MediaBrowser.Providers.TV Current = this; } + public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) + { + var list = new List(); + + string seriesTvdbId; + searchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId); + + if (!string.IsNullOrEmpty(seriesTvdbId)) + { + var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesTvdbId); + + try + { + var item = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken); + + if (item != null) + { + list.Add(new RemoteSearchResult + { + IndexNumber = item.IndexNumber, + Name = item.Name, + ParentIndexNumber = item.ParentIndexNumber, + PremiereDate = item.PremiereDate, + ProductionYear = item.ProductionYear, + ProviderIds = item.ProviderIds, + SearchProviderName = Name, + IndexNumberEnd = item.IndexNumberEnd + }); + } + } + catch (FileNotFoundException) + { + // Don't fail the provider because this will just keep on going and going. + } + } + + return list; + } + public string Name { get { return "TheTVDB"; } } - public Task> GetMetadata(EpisodeInfo id, CancellationToken cancellationToken) + public Task> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken) { - var episodeId = id; - string seriesTvdbId; - episodeId.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId); + searchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId); var result = new MetadataResult(); @@ -54,7 +93,7 @@ namespace MediaBrowser.Providers.TV try { - result.Item = FetchEpisodeData(episodeId, seriesDataPath, cancellationToken); + result.Item = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken); result.HasMetadata = result.Item != null; } catch (FileNotFoundException) @@ -192,9 +231,9 @@ namespace MediaBrowser.Providers.TV var episode = new Episode { - IndexNumber = id.IndexNumber, - ParentIndexNumber = id.ParentIndexNumber, - IndexNumberEnd = id.IndexNumberEnd + IndexNumber = id.IndexNumber, + ParentIndexNumber = id.ParentIndexNumber, + IndexNumberEnd = id.IndexNumberEnd }; try @@ -674,5 +713,10 @@ namespace MediaBrowser.Providers.TV } } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index c0ebd4a657..920da9b10f 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -9,6 +9,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; using System.Globalization; @@ -47,6 +48,11 @@ namespace MediaBrowser.Providers.TV private const string SeriesQuery = "GetSeries.php?seriesname={0}"; private const string SeriesGetZip = "http://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip"; + public async Task> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) + { + return new List(); + } + public async Task> GetMetadata(SeriesInfo itemId, CancellationToken cancellationToken) { var result = new MetadataResult(); @@ -1081,5 +1087,10 @@ namespace MediaBrowser.Providers.TV return 1; } } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index d4d7f2f215..5bf6587a90 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.FileOrganization; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; @@ -28,10 +27,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization private readonly IFileSystem _fileSystem; private readonly IFileOrganizationService _organizationService; private readonly IServerConfigurationManager _config; + private readonly IProviderManager _providerManager; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public EpisodeFileOrganizer(IFileOrganizationService organizationService, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor) + public EpisodeFileOrganizer(IFileOrganizationService organizationService, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager) { _organizationService = organizationService; _config = config; @@ -39,9 +39,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _logger = logger; _libraryManager = libraryManager; _libraryMonitor = libraryMonitor; + _providerManager = providerManager; } - public async Task OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting) + public async Task OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting, CancellationToken cancellationToken) { _logger.Info("Sorting file {0}", path); @@ -77,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization result.ExtractedEndingEpisodeNumber = endingEpisodeNumber; - OrganizeEpisode(path, seriesName, season.Value, episode.Value, endingEpisodeNumber, options, overwriteExisting, result); + await OrganizeEpisode(path, seriesName, season.Value, episode.Value, endingEpisodeNumber, options, overwriteExisting, result, cancellationToken).ConfigureAwait(false); } else { @@ -119,20 +120,20 @@ namespace MediaBrowser.Server.Implementations.FileOrganization return result; } - public async Task OrganizeWithCorrection(EpisodeFileOrganizationRequest request, TvFileOrganizationOptions options) + public async Task OrganizeWithCorrection(EpisodeFileOrganizationRequest request, TvFileOrganizationOptions options, CancellationToken cancellationToken) { var result = _organizationService.GetResult(request.ResultId); var series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId)); - OrganizeEpisode(result.OriginalPath, series, request.SeasonNumber, request.EpisodeNumber, request.EndingEpisodeNumber, _config.Configuration.TvFileOrganizationOptions, true, result); + await OrganizeEpisode(result.OriginalPath, series, request.SeasonNumber, request.EpisodeNumber, request.EndingEpisodeNumber, _config.Configuration.TvFileOrganizationOptions, true, result, cancellationToken).ConfigureAwait(false); await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); return result; } - private void OrganizeEpisode(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result) + private Task OrganizeEpisode(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result, CancellationToken cancellationToken) { var series = GetMatchingSeries(seriesName, result); @@ -142,18 +143,18 @@ namespace MediaBrowser.Server.Implementations.FileOrganization result.Status = FileSortingStatus.Failure; result.StatusMessage = msg; _logger.Warn(msg); - return; + return Task.FromResult(true); } - OrganizeEpisode(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options, overwriteExisting, result); + return OrganizeEpisode(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options, overwriteExisting, result, cancellationToken); } - private void OrganizeEpisode(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result) + private async Task OrganizeEpisode(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result, CancellationToken cancellationToken) { _logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path); // Proceed to sort the file - var newPath = GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options); + var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(newPath)) { @@ -326,25 +327,33 @@ namespace MediaBrowser.Server.Implementations.FileOrganization /// The ending episode number. /// The options. /// System.String. - private string GetNewPath(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, TvFileOrganizationOptions options) + private async Task GetNewPath(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, TvFileOrganizationOptions options, CancellationToken cancellationToken) { - // If season and episode numbers match - var currentEpisodes = series.RecursiveChildren.OfType() - .Where(i => i.IndexNumber.HasValue && - i.IndexNumber.Value == episodeNumber && - i.ParentIndexNumber.HasValue && - i.ParentIndexNumber.Value == seasonNumber) - .ToList(); + var episodeInfo = new EpisodeInfo + { + IndexNumber = episodeNumber, + IndexNumberEnd = endingEpisodeNumber, + MetadataCountryCode = series.GetPreferredMetadataCountryCode(), + MetadataLanguage = series.GetPreferredMetadataLanguage(), + ParentIndexNumber = seasonNumber, + SeriesProviderIds = series.ProviderIds + }; - if (currentEpisodes.Count == 0) + var searchResults = await _providerManager.GetRemoteSearchResults(new RemoteSearchQuery + { + SearchInfo = episodeInfo + + }, cancellationToken).ConfigureAwait(false); + + var episode = searchResults.FirstOrDefault(); + + if (episode == null) { return null; } var newPath = GetSeasonFolderPath(series, seasonNumber, options); - var episode = currentEpisodes.First(); - var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, endingEpisodeNumber, episode.Name, options); newPath = Path.Combine(newPath, episodeFileName); diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs index c03ceb6e50..7cf38b0a0e 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs @@ -3,9 +3,9 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.FileOrganization; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.FileOrganization; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; @@ -25,8 +25,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization private readonly ILibraryManager _libraryManager; private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; + private readonly IProviderManager _providerManager; - public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem) + public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager) { _taskManager = taskManager; _repo = repo; @@ -35,6 +36,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _libraryManager = libraryManager; _config = config; _fileSystem = fileSystem; + _providerManager = providerManager; } public void BeginProcessNewFiles() @@ -103,9 +105,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager, - _libraryMonitor); + _libraryMonitor, _providerManager); - await organizer.OrganizeEpisodeFile(result.OriginalPath, _config.Configuration.TvFileOrganizationOptions, true) + await organizer.OrganizeEpisodeFile(result.OriginalPath, _config.Configuration.TvFileOrganizationOptions, true, CancellationToken.None) .ConfigureAwait(false); } @@ -117,9 +119,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request) { var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager, - _libraryMonitor); + _libraryMonitor, _providerManager); - await organizer.OrganizeWithCorrection(request, _config.Configuration.TvFileOrganizationOptions).ConfigureAwait(false); + await organizer.OrganizeWithCorrection(request, _config.Configuration.TvFileOrganizationOptions, CancellationToken.None).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs index 3c5e1ed0ed..fbb743f943 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs @@ -2,8 +2,8 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.FileOrganization; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -20,8 +20,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _config; private readonly IFileOrganizationService _organizationService; + private readonly IProviderManager _providerManager; - public OrganizerScheduledTask(ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IServerConfigurationManager config, IFileOrganizationService organizationService) + public OrganizerScheduledTask(ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IServerConfigurationManager config, IFileOrganizationService organizationService, IProviderManager providerManager) { _libraryMonitor = libraryMonitor; _libraryManager = libraryManager; @@ -29,6 +30,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _fileSystem = fileSystem; _config = config; _organizationService = organizationService; + _providerManager = providerManager; } public string Name @@ -48,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization public Task Execute(CancellationToken cancellationToken, IProgress progress) { - return new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config) + return new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config, _providerManager) .Organize(_config.Configuration.TvFileOrganizationOptions, cancellationToken, progress); } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs index 85b45cf2c7..9df6e7f1c9 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs @@ -1,8 +1,8 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.FileOrganization; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.FileOrganization; @@ -24,8 +24,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization private readonly IFileSystem _fileSystem; private readonly IFileOrganizationService _organizationService; private readonly IServerConfigurationManager _config; + private readonly IProviderManager _providerManager; - public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IFileOrganizationService organizationService, IServerConfigurationManager config) + public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IFileOrganizationService organizationService, IServerConfigurationManager config, IProviderManager providerManager) { _libraryManager = libraryManager; _logger = logger; @@ -33,6 +34,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _libraryMonitor = libraryMonitor; _organizationService = organizationService; _config = config; + _providerManager = providerManager; } public async Task Organize(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress progress) @@ -57,9 +59,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization foreach (var file in eligibleFiles) { var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, - _libraryMonitor); + _libraryMonitor, _providerManager); - var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false).ConfigureAwait(false); + var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false, cancellationToken).ConfigureAwait(false); if (result.Status == FileSortingStatus.Success) { diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index b4c442ec8a..009e4716dc 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -1,4 +1,5 @@ -using Funq; +using System.Net.Sockets; +using Funq; using MediaBrowser.Common; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index 8634919fc6..fa1d4b0d51 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -3,7 +3,6 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations.ScheduledTasks; using Microsoft.Win32; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 656e0993f4..c2044476a2 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -408,8 +408,14 @@ namespace MediaBrowser.Server.Implementations.Library LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; }); } - public async Task DeleteItem(BaseItem item) + public async Task DeleteItem(BaseItem item, DeleteOptions options) { + _logger.Debug("Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", + item.GetType().Name, + item.Name, + item.Path ?? string.Empty, + item.Id); + var parent = item.Parent; var locationType = item.LocationType; @@ -436,7 +442,7 @@ namespace MediaBrowser.Server.Implementations.Library } } - if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) + if (options.DeleteFileLocation && (locationType == LocationType.FileSystem || locationType == LocationType.Offline)) { foreach (var path in item.GetDeletePaths().ToList()) { @@ -462,15 +468,14 @@ namespace MediaBrowser.Server.Implementations.Library { await parent.RemoveChild(item, CancellationToken.None).ConfigureAwait(false); } - else - { - throw new InvalidOperationException("Don't know how to delete " + item.Name); - } + await ItemRepository.DeleteItem(item.Id, CancellationToken.None).ConfigureAwait(false); foreach (var child in children) { await ItemRepository.DeleteItem(child.Id, CancellationToken.None).ConfigureAwait(false); } + + ReportItemRemoved(item); } private IEnumerable GetMetadataPaths(BaseItem item, IEnumerable children) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index f25cf541b4..989ed3c353 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -726,7 +726,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv foreach (var channelInfo in allChannelsList) { cancellationToken.ThrowIfCancellationRequested(); - + try { var item = await GetChannel(channelInfo.Item2, channelInfo.Item1, cancellationToken).ConfigureAwait(false); @@ -764,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv foreach (var item in list) { cancellationToken.ThrowIfCancellationRequested(); - + // Avoid implicitly captured closure var currentChannel = item; @@ -793,17 +793,44 @@ namespace MediaBrowser.Server.Implementations.LiveTv double percent = numComplete; percent /= allChannelsList.Count; - progress.Report(80 * percent + 10); + progress.Report(70 * percent + 10); } _programs = programs.ToDictionary(i => i.Id); + progress.Report(80); // Load these now which will prefetch metadata await GetRecordings(new RecordingQuery(), cancellationToken).ConfigureAwait(false); - + progress.Report(85); + + await DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken).ConfigureAwait(false); + progress.Report(100); } + private async Task DeleteOldPrograms(List currentIdList, IProgress progress, CancellationToken cancellationToken) + { + var list = _itemRepo.GetItemsOfType(typeof(LiveTvProgram)).ToList(); + + var numComplete = 0; + + foreach (var program in list) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (!currentIdList.Contains(program.Id)) + { + await _libraryManager.DeleteItem(program).ConfigureAwait(false); + } + + numComplete++; + double percent = numComplete; + percent /= list.Count; + + progress.Report(15 * percent + 85); + } + } + private double GetGuideDays(int channelCount) { if (_config.Configuration.LiveTvOptions.GuideDays.HasValue) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 1098dbf6d7..70362654e6 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -281,27 +281,32 @@ namespace MediaBrowser.Server.Implementations.Persistence { if (reader.Read()) { - var typeString = reader.GetString(0); - - var type = _typeMapper.GetType(typeString); - - if (type == null) - { - _logger.Debug("Unknown type {0}", typeString); - - return null; - } - - using (var stream = reader.GetMemoryStream(1)) - { - return _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem; - } + return GetItem(reader); } } return null; } } + private BaseItem GetItem(IDataReader reader) + { + var typeString = reader.GetString(0); + + var type = _typeMapper.GetType(typeString); + + if (type == null) + { + _logger.Debug("Unknown type {0}", typeString); + + return null; + } + + using (var stream = reader.GetMemoryStream(1)) + { + return _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem; + } + } + /// /// Gets the critic reviews. /// @@ -468,6 +473,34 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + public IEnumerable GetItemsOfType(Type type) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select type,data from TypedBaseItems where type = @type"; + + cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var item = GetItem(reader); + + if (item != null) + { + yield return item; + } + } + } + } + } + public async Task DeleteItem(Guid id, CancellationToken cancellationToken) { if (id == Guid.Empty) diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 10dec2da6f..527e00f620 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -363,7 +363,7 @@ namespace MediaBrowser.ServerApplication var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer); RegisterSingleInstance(newsService); - var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager); + var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager); RegisterSingleInstance(fileOrganizationService); progress.Report(15); diff --git a/MediaBrowser.ServerApplication/Native/Autorun.cs b/MediaBrowser.ServerApplication/Native/Autorun.cs index d1c02db84f..0262f711e7 100644 --- a/MediaBrowser.ServerApplication/Native/Autorun.cs +++ b/MediaBrowser.ServerApplication/Native/Autorun.cs @@ -16,15 +16,17 @@ namespace MediaBrowser.ServerApplication.Native { var shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Media Browser 3", "Media Browser Server.lnk"); + var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup); + if (autorun) { //Copy our shortut into the startup folder for this user - File.Copy(shortcutPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), Path.GetFileName(shortcutPath) ?? "MBstartup.lnk"), true); + File.Copy(shortcutPath, Path.Combine(startupPath, Path.GetFileName(shortcutPath) ?? "MBstartup.lnk"), true); } else { //Remove our shortcut from the startup folder for this user - File.Delete(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), Path.GetFileName(shortcutPath) ?? "MBstartup.lnk")); + File.Delete(Path.Combine(startupPath, Path.GetFileName(shortcutPath) ?? "MBstartup.lnk")); } } } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index a958415ff5..b41293e3e2 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.329 + 3.0.330 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater 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 a552297d4d..ef257122bd 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.329 + 3.0.330 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 15da720c27..3bb5887c16 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.329 + 3.0.330 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 - +