diff options
| author | Luke <luke.pulverenti@gmail.com> | 2017-10-04 14:52:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-10-04 14:52:50 -0400 |
| commit | 185fa7f5e76a9971e34c35783698d37902ed14cb (patch) | |
| tree | a840cff09050c5c76645596bfd99bb5dfd5ad4a0 /MediaBrowser.Controller | |
| parent | c67f03ee97019aff0af41e8c6f4f8525ef90b5e5 (diff) | |
| parent | 1caae368d5f75d96dada65cd2175831982363c21 (diff) | |
Merge pull request #2941 from MediaBrowser/dev
Dev
Diffstat (limited to 'MediaBrowser.Controller')
| -rw-r--r-- | MediaBrowser.Controller/Channels/IChannelManager.cs | 5 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Dlna/IEventManager.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 45 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 13 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/IHasMetadata.cs | 11 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/User.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserViewBuilder.cs | 100 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Video.cs | 33 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/ILibraryManager.cs | 12 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/IUserViewManager.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 20 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs | 5 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs | 5 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaBrowser.Controller.csproj | 1 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs | 326 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Providers/IProviderManager.cs | 8 |
16 files changed, 437 insertions, 156 deletions
diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index 46e55a21ce..37fc892b36 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -117,14 +117,13 @@ namespace MediaBrowser.Controller.Channels /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>BaseItemDto.</returns> - Task<Folder> GetInternalChannelFolder(CancellationToken cancellationToken); + Folder GetInternalChannelFolder(CancellationToken cancellationToken); /// <summary> /// Gets the channel folder. /// </summary> /// <param name="userId">The user identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>BaseItemDto.</returns> - Task<BaseItemDto> GetChannelFolder(string userId, CancellationToken cancellationToken); + BaseItemDto GetChannelFolder(string userId, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Dlna/IEventManager.cs b/MediaBrowser.Controller/Dlna/IEventManager.cs index 8c91bd889d..3af357a174 100644 --- a/MediaBrowser.Controller/Dlna/IEventManager.cs +++ b/MediaBrowser.Controller/Dlna/IEventManager.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Dlna /// <summary> /// Renews the event subscription. /// </summary> - EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string requestedTimeoutString); + EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl); /// <summary> /// Creates the event subscription. diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 502ba6c60e..46c037a44d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1281,8 +1281,8 @@ namespace MediaBrowser.Controller.Entities { var subOptions = new MetadataRefreshOptions(options); - if (!i.ExtraType.HasValue || - i.ExtraType.Value != Model.Entities.ExtraType.ThemeSong || + if (!i.ExtraType.HasValue || + i.ExtraType.Value != Model.Entities.ExtraType.ThemeSong || i.OwnerId != ownerId || i.ParentId != Guid.Empty) { @@ -1356,14 +1356,20 @@ namespace MediaBrowser.Controller.Entities internal virtual bool IsValidFromResolver(BaseItem newItem) { - var current = this; + return true; + } - if (current.IsInMixedFolder != newItem.IsInMixedFolder) + internal virtual ItemUpdateType UpdateFromResolvedItem(BaseItem newItem) + { + var updateType = ItemUpdateType.None; + + if (IsInMixedFolder != newItem.IsInMixedFolder) { - return false; + IsInMixedFolder = newItem.IsInMixedFolder; + updateType |= ItemUpdateType.MetadataImport; } - return true; + return updateType; } public void AfterMetadataRefresh() @@ -1966,14 +1972,14 @@ namespace MediaBrowser.Controller.Entities /// <param name="type">The type.</param> /// <param name="index">The index.</param> /// <returns>Task.</returns> - public Task DeleteImage(ImageType type, int index) + public void DeleteImage(ImageType type, int index) { var info = GetImageInfo(type, index); if (info == null) { // Nothing to do - return Task.FromResult(true); + return; } // Remove it from the item @@ -1984,7 +1990,7 @@ namespace MediaBrowser.Controller.Entities FileSystem.DeleteFile(info.Path); } - return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); } public void RemoveImage(ItemImageInfo image) @@ -1997,9 +2003,9 @@ namespace MediaBrowser.Controller.Entities ImageInfos = ImageInfos.Except(deletedImages).ToArray(); } - public virtual Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) + public virtual void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) { - return LibraryManager.UpdateItem(this, updateReason, cancellationToken); + LibraryManager.UpdateItem(this, updateReason, cancellationToken); } /// <summary> @@ -2209,7 +2215,7 @@ namespace MediaBrowser.Controller.Entities return type == ImageType.Backdrop || type == ImageType.Screenshot || type == ImageType.Chapter; } - public Task SwapImages(ImageType type, int index1, int index2) + public void SwapImages(ImageType type, int index1, int index2) { if (!AllowsMultipleImages(type)) { @@ -2222,13 +2228,13 @@ namespace MediaBrowser.Controller.Entities if (info1 == null || info2 == null) { // Nothing to do - return Task.FromResult(true); + return; } if (!info1.IsLocalFile || !info2.IsLocalFile) { // TODO: Not supported yet - return Task.FromResult(true); + return; } var path1 = info1.Path; @@ -2240,7 +2246,7 @@ namespace MediaBrowser.Controller.Entities info1.DateModified = FileSystem.GetLastWriteTimeUtc(info1.Path); info2.DateModified = FileSystem.GetLastWriteTimeUtc(info2.Path); - return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); } public virtual bool IsPlayed(User user) @@ -2526,15 +2532,6 @@ namespace MediaBrowser.Controller.Entities return LibraryManager.DeleteItem(this, options); } - public virtual Task OnFileDeleted() - { - // Remove from database - return Delete(new DeleteOptions - { - DeleteFileLocation = false - }); - } - public virtual List<ExternalUrl> GetRelatedUrls() { return new List<ExternalUrl>(); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 6d88f70152..ce7145a791 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -328,11 +328,6 @@ namespace MediaBrowser.Controller.Entities return dictionary; } - private bool IsValidFromResolver(BaseItem current, BaseItem newItem) - { - return current.IsValidFromResolver(newItem); - } - protected override void TriggerOnRefreshStart() { } @@ -421,10 +416,15 @@ namespace MediaBrowser.Controller.Entities { BaseItem currentChild; - if (currentChildren.TryGetValue(child.Id, out currentChild) && IsValidFromResolver(currentChild, child)) + if (currentChildren.TryGetValue(child.Id, out currentChild) && currentChild.IsValidFromResolver(child)) { validChildren.Add(currentChild); + if (currentChild.UpdateFromResolvedItem(child) > ItemUpdateType.None) + { + currentChild.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); + } + continue; } @@ -542,7 +542,6 @@ namespace MediaBrowser.Controller.Entities if (validChildrenNeedGeneration) { validChildren = Children.ToList(); - validChildrenNeedGeneration = false; } await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken); diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 4146686b21..b7d31b4d6a 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -151,11 +151,7 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Swaps the images. /// </summary> - /// <param name="type">The type.</param> - /// <param name="index1">The index1.</param> - /// <param name="index2">The index2.</param> - /// <returns>Task.</returns> - Task SwapImages(ImageType type, int index1, int index2); + void SwapImages(ImageType type, int index1, int index2); /// <summary> /// Gets or sets the primary image path. @@ -249,10 +245,7 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Updates to repository. /// </summary> - /// <param name="updateReason">The update reason.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken); + void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken); /// <summary> /// Sets the image. diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 36bbf6886a..821327b7f3 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -235,10 +235,9 @@ namespace MediaBrowser.Controller.Entities }, CancellationToken.None); } - public override Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) + public override void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) { UserManager.UpdateUser(this); - return Task.FromResult(true); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 43adc4af68..acc452fbc3 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -78,26 +78,26 @@ namespace MediaBrowser.Controller.Entities case SpecialFolder.LiveTvChannels: { - var result = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery + var result = _liveTvManager.GetInternalChannels(new LiveTvChannelQuery { UserId = query.User.Id.ToString("N"), Limit = query.Limit, StartIndex = query.StartIndex - }, new DtoOptions(), CancellationToken.None).ConfigureAwait(false); + }, new DtoOptions(), CancellationToken.None); return GetResult(result); } case SpecialFolder.LiveTvNowPlaying: { - var result = await _liveTvManager.GetRecommendedProgramsInternal(new RecommendedProgramQuery + var result = _liveTvManager.GetRecommendedProgramsInternal(new RecommendedProgramQuery { UserId = query.User.Id.ToString("N"), Limit = query.Limit, IsAiring = true - }, new Dto.DtoOptions(), CancellationToken.None).ConfigureAwait(false); + }, new Dto.DtoOptions(), CancellationToken.None); return GetResult(result); } @@ -142,22 +142,22 @@ namespace MediaBrowser.Controller.Entities return GetResult(user.RootFolder.GetChildren(user, true), queryParent, query); case CollectionType.Playlists: - return GetPlaylistsView(queryParent, user, query); + return GetPlaylistsView(queryParent, user, query); case CollectionType.BoxSets: return GetBoxsetView(queryParent, user, query); case CollectionType.TvShows: - return await GetTvView(queryParent, user, query).ConfigureAwait(false); + return GetTvView(queryParent, user, query); case CollectionType.Movies: - return await GetMovieFolders(queryParent, user, query).ConfigureAwait(false); + return GetMovieFolders(queryParent, user, query); case SpecialFolder.TvShowSeries: return GetTvSeries(queryParent, user, query); case SpecialFolder.TvGenres: - return await GetTvGenres(queryParent, user, query).ConfigureAwait(false); + return GetTvGenres(queryParent, user, query); case SpecialFolder.TvGenre: return GetTvGenreItems(queryParent, displayParent, user, query); @@ -178,10 +178,10 @@ namespace MediaBrowser.Controller.Entities return GetMovieLatest(queryParent, user, query); case SpecialFolder.MovieGenres: - return await GetMovieGenres(queryParent, user, query).ConfigureAwait(false); + return GetMovieGenres(queryParent, user, query); case SpecialFolder.MovieGenre: - return GetMovieGenreItems(queryParent, displayParent, user, query); + return GetMovieGenreItems(queryParent, displayParent, user, query); case SpecialFolder.MovieResume: return GetMovieResume(queryParent, user, query); @@ -199,7 +199,7 @@ namespace MediaBrowser.Controller.Entities return GetFavoriteSeries(queryParent, user, query); case CollectionType.Music: - return await GetMusicFolders(queryParent, user, query).ConfigureAwait(false); + return GetMusicFolders(queryParent, user, query); case SpecialFolder.MusicGenres: return GetMusicGenres(queryParent, user, query); @@ -223,7 +223,7 @@ namespace MediaBrowser.Controller.Entities return GetMusicSongs(queryParent, user, query); case SpecialFolder.MusicFavorites: - return await GetMusicFavorites(queryParent, user, query).ConfigureAwait(false); + return GetMusicFavorites(queryParent, user, query); case SpecialFolder.MusicFavoriteAlbums: return GetFavoriteAlbums(queryParent, user, query); @@ -245,7 +245,7 @@ namespace MediaBrowser.Controller.Entities } } - private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, InternalItemsQuery query) + private QueryResult<BaseItem> GetMusicFolders(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { @@ -262,25 +262,25 @@ namespace MediaBrowser.Controller.Entities var list = new List<BaseItem>(); - list.Add(await GetUserView(SpecialFolder.MusicLatest, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicPlaylists, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicAlbums, "2", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, "3", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicArtists, "4", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicSongs, "5", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicGenres, "6", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicFavorites, "7", parent).ConfigureAwait(false)); + list.Add(GetUserView(SpecialFolder.MusicLatest, "0", parent)); + list.Add(GetUserView(SpecialFolder.MusicPlaylists, "1", parent)); + list.Add(GetUserView(SpecialFolder.MusicAlbums, "2", parent)); + list.Add(GetUserView(SpecialFolder.MusicAlbumArtists, "3", parent)); + list.Add(GetUserView(SpecialFolder.MusicArtists, "4", parent)); + list.Add(GetUserView(SpecialFolder.MusicSongs, "5", parent)); + list.Add(GetUserView(SpecialFolder.MusicGenres, "6", parent)); + list.Add(GetUserView(SpecialFolder.MusicFavorites, "7", parent)); return GetResult(list, parent, query); } - private async Task<QueryResult<BaseItem>> GetMusicFavorites(Folder parent, User user, InternalItemsQuery query) + private QueryResult<BaseItem> GetMusicFavorites(Folder parent, User user, InternalItemsQuery query) { var list = new List<BaseItem>(); - list.Add(await GetUserView(SpecialFolder.MusicFavoriteAlbums, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicFavoriteArtists, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MusicFavoriteSongs, "2", parent).ConfigureAwait(false)); + list.Add(GetUserView(SpecialFolder.MusicFavoriteAlbums, "0", parent)); + list.Add(GetUserView(SpecialFolder.MusicFavoriteArtists, "1", parent)); + list.Add(GetUserView(SpecialFolder.MusicFavoriteSongs, "2", parent)); return GetResult(list, parent, query); } @@ -426,7 +426,7 @@ namespace MediaBrowser.Controller.Entities return 50; } - private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, InternalItemsQuery query) + private QueryResult<BaseItem> GetMovieFolders(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { @@ -443,12 +443,12 @@ namespace MediaBrowser.Controller.Entities var list = new List<BaseItem>(); - list.Add(await GetUserView(SpecialFolder.MovieResume, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MovieLatest, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MovieMovies, "2", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MovieCollections, "3", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MovieFavorites, "4", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.MovieGenres, "5", parent).ConfigureAwait(false)); + list.Add(GetUserView(SpecialFolder.MovieResume, "0", parent)); + list.Add(GetUserView(SpecialFolder.MovieLatest, "1", parent)); + list.Add(GetUserView(SpecialFolder.MovieMovies, "2", parent)); + list.Add(GetUserView(SpecialFolder.MovieCollections, "3", parent)); + list.Add(GetUserView(SpecialFolder.MovieFavorites, "4", parent)); + list.Add(GetUserView(SpecialFolder.MovieGenres, "5", parent)); return GetResult(list, parent, query); } @@ -538,9 +538,9 @@ namespace MediaBrowser.Controller.Entities }; } - private async Task<QueryResult<BaseItem>> GetMovieGenres(Folder parent, User user, InternalItemsQuery query) + private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, InternalItemsQuery query) { - var tasks = parent.QueryRecursive(new InternalItemsQuery(user) + var genres = parent.QueryRecursive(new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(Movie).Name }, Recursive = true, @@ -566,8 +566,6 @@ namespace MediaBrowser.Controller.Entities .Where(i => i != null) .Select(i => GetUserView(i.Name, SpecialFolder.MovieGenre, i.SortName, parent)); - var genres = await Task.WhenAll(tasks).ConfigureAwait(false); - return GetResult(genres, parent, query); } @@ -598,7 +596,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query) + private QueryResult<BaseItem> GetTvView(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { @@ -615,13 +613,13 @@ namespace MediaBrowser.Controller.Entities var list = new List<BaseItem>(); - list.Add(await GetUserView(SpecialFolder.TvResume, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.TvNextUp, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.TvLatest, "2", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.TvShowSeries, "3", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.TvFavoriteSeries, "4", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.TvFavoriteEpisodes, "5", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.TvGenres, "6", parent).ConfigureAwait(false)); + list.Add(GetUserView(SpecialFolder.TvResume, "0", parent)); + list.Add(GetUserView(SpecialFolder.TvNextUp, "1", parent)); + list.Add(GetUserView(SpecialFolder.TvLatest, "2", parent)); + list.Add(GetUserView(SpecialFolder.TvShowSeries, "3", parent)); + list.Add(GetUserView(SpecialFolder.TvFavoriteSeries, "4", parent)); + list.Add(GetUserView(SpecialFolder.TvFavoriteEpisodes, "5", parent)); + list.Add(GetUserView(SpecialFolder.TvGenres, "6", parent)); return GetResult(list, parent, query); } @@ -679,9 +677,9 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private async Task<QueryResult<BaseItem>> GetTvGenres(Folder parent, User user, InternalItemsQuery query) + private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, InternalItemsQuery query) { - var tasks = parent.QueryRecursive(new InternalItemsQuery(user) + var genres = parent.QueryRecursive(new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(Series).Name }, Recursive = true, @@ -707,8 +705,6 @@ namespace MediaBrowser.Controller.Entities .Where(i => i != null) .Select(i => GetUserView(i.Name, SpecialFolder.TvGenre, i.SortName, parent)); - var genres = await Task.WhenAll(tasks).ConfigureAwait(false); - return GetResult(genres, parent, query); } @@ -1740,18 +1736,18 @@ namespace MediaBrowser.Controller.Entities var list = new List<BaseItem>(); //list.Add(await GetUserSubView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.LiveTvChannels, string.Empty, user.RootFolder).ConfigureAwait(false)); - list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, string.Empty, user.RootFolder).ConfigureAwait(false)); + list.Add(GetUserView(SpecialFolder.LiveTvChannels, string.Empty, user.RootFolder)); + list.Add(GetUserView(SpecialFolder.LiveTvRecordingGroups, string.Empty, user.RootFolder)); return GetResult(list, queryParent, query); } - private Task<UserView> GetUserView(string name, string type, string sortName, BaseItem parent) + private UserView GetUserView(string name, string type, string sortName, BaseItem parent) { return _userViewManager.GetUserSubView(name, parent.Id.ToString("N"), type, sortName, CancellationToken.None); } - private Task<UserView> GetUserView(string type, string sortName, BaseItem parent) + private UserView GetUserView(string type, string sortName, BaseItem parent) { return _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, sortName, CancellationToken.None); } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 8693d867cc..8203e53042 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -406,30 +406,31 @@ namespace MediaBrowser.Controller.Entities } } - internal override bool IsValidFromResolver(BaseItem newItem) + internal override ItemUpdateType UpdateFromResolvedItem(BaseItem newItem) { - var current = this; + var updateType = base.UpdateFromResolvedItem(newItem); - var newAsVideo = newItem as Video; - - if (newAsVideo != null) + var newVideo = newItem as Video; + if (newVideo != null) { - if (!current.AdditionalParts.SequenceEqual(newAsVideo.AdditionalParts, StringComparer.OrdinalIgnoreCase)) + if (!AdditionalParts.SequenceEqual(newVideo.AdditionalParts, StringComparer.Ordinal)) { - return false; + AdditionalParts = newVideo.AdditionalParts; + updateType |= ItemUpdateType.MetadataImport; } - if (!current.LocalAlternateVersions.SequenceEqual(newAsVideo.LocalAlternateVersions, StringComparer.OrdinalIgnoreCase)) + if (!LocalAlternateVersions.SequenceEqual(newVideo.LocalAlternateVersions, StringComparer.Ordinal)) { - return false; + LocalAlternateVersions = newVideo.LocalAlternateVersions; + updateType |= ItemUpdateType.MetadataImport; } - - if (newAsVideo.VideoType != VideoType) + if (VideoType != newVideo.VideoType) { - return false; + VideoType = newVideo.VideoType; + updateType |= ItemUpdateType.MetadataImport; } } - return base.IsValidFromResolver(newItem); + return updateType; } public static string[] QueryPlayableStreamFiles(string rootPath, VideoType videoType) @@ -521,9 +522,9 @@ namespace MediaBrowser.Controller.Entities } } - public override async Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) + public override void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) { - await base.UpdateToRepository(updateReason, cancellationToken).ConfigureAwait(false); + base.UpdateToRepository(updateReason, cancellationToken); var localAlternates = GetLocalAlternateVersionIds() .Select(i => LibraryManager.GetItemById(i)) @@ -540,7 +541,7 @@ namespace MediaBrowser.Controller.Entities item.Genres = Genres; item.ProviderIds = ProviderIds; - await item.UpdateToRepository(ItemUpdateType.MetadataDownload, cancellationToken).ConfigureAwait(false); + item.UpdateToRepository(ItemUpdateType.MetadataDownload, cancellationToken); } } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 3001e33661..7fceeb780b 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -207,11 +207,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Updates the item. /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateReason">The update reason.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task UpdateItem(BaseItem item, ItemUpdateType updateReason, CancellationToken cancellationToken); + void UpdateItem(BaseItem item, ItemUpdateType updateReason, CancellationToken cancellationToken); /// <summary> /// Retrieves the item. @@ -330,8 +326,7 @@ namespace MediaBrowser.Controller.Library /// <param name="viewType">Type of the view.</param> /// <param name="sortName">Name of the sort.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task<UserView>.</returns> - Task<UserView> GetNamedView(string name, + UserView GetNamedView(string name, string viewType, string sortName, CancellationToken cancellationToken); @@ -345,8 +340,7 @@ namespace MediaBrowser.Controller.Library /// <param name="sortName">Name of the sort.</param> /// <param name="uniqueId">The unique identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task<UserView>.</returns> - Task<UserView> GetNamedView(string name, + UserView GetNamedView(string name, string parentId, string viewType, string sortName, diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs index 76182c641b..ac37dc869c 100644 --- a/MediaBrowser.Controller/Library/IUserViewManager.cs +++ b/MediaBrowser.Controller/Library/IUserViewManager.cs @@ -13,9 +13,9 @@ namespace MediaBrowser.Controller.Library { Task<Folder[]> GetUserViews(UserViewQuery query, CancellationToken cancellationToken); - Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken); + UserView GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken); - Task<UserView> GetUserSubView(string category, string type, string sortName, CancellationToken cancellationToken); + UserView GetUserSubView(string category, string type, string sortName, CancellationToken cancellationToken); List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request, DtoOptions options); } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index be85e115c4..56f2353f16 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -236,14 +236,12 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="query">The query.</param> /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{QueryResult{ProgramInfoDto}}.</returns> - Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken); + QueryResult<BaseItemDto> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the recommended programs internal. /// </summary> - /// <returns>Task<QueryResult<LiveTvProgram>>.</returns> - Task<QueryResult<BaseItem>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken); + QueryResult<BaseItem> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the live tv information. @@ -264,8 +262,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the live tv folder. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>BaseItemDto.</returns> - Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken); + Folder GetInternalLiveTvFolder(CancellationToken cancellationToken); /// <summary> /// Gets the live tv folder. @@ -273,7 +270,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="userId">The user identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>BaseItemDto.</returns> - Task<BaseItemDto> GetLiveTvFolder(string userId, CancellationToken cancellationToken); + BaseItemDto GetLiveTvFolder(string userId, CancellationToken cancellationToken); /// <summary> /// Gets the enabled users. @@ -284,7 +281,7 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Gets the internal channels. /// </summary> - Task<QueryResult<BaseItem>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken); + QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken); /// <summary> /// Gets the internal recordings. @@ -362,13 +359,6 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="user">The user.</param> void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user); - /// <summary> - /// Called when [recording file deleted]. - /// </summary> - /// <param name="recording">The recording.</param> - /// <returns>Task.</returns> - Task OnRecordingFileDeleted(BaseItem recording); - Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken); Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken); diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs index 8fa96076b7..2dfc59d228 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs @@ -161,10 +161,5 @@ namespace MediaBrowser.Controller.LiveTv { return LiveTvManager.DeleteRecording(this); } - - public override Task OnFileDeleted() - { - return LiveTvManager.OnRecordingFileDeleted(this); - } } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index c5fe7b1b31..1dfed4f75d 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -160,10 +160,5 @@ namespace MediaBrowser.Controller.LiveTv { return LiveTvManager.DeleteRecording(this); } - - public override Task OnFileDeleted() - { - return LiveTvManager.OnRecordingFileDeleted(this); - } } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b33993859b..960ff0aa7d 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -176,6 +176,7 @@ <Compile Include="MediaEncoding\MediaStreamSelector.cs" /> <Compile Include="Net\AuthenticatedAttribute.cs" /> <Compile Include="Net\AuthorizationInfo.cs" /> + <Compile Include="Net\BasePeriodicWebSocketListener.cs" /> <Compile Include="Net\IAuthorizationContext.cs" /> <Compile Include="Net\IAuthService.cs" /> <Compile Include="Net\IHasResultFactory.cs" /> diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs new file mode 100644 index 0000000000..6be94e7e6e --- /dev/null +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Threading; + +namespace MediaBrowser.Controller.Net +{ + /// <summary> + /// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received + /// </summary> + /// <typeparam name="TReturnDataType">The type of the T return data type.</typeparam> + /// <typeparam name="TStateType">The type of the T state type.</typeparam> + public abstract class BasePeriodicWebSocketListener<TReturnDataType, TStateType> : IWebSocketListener, IDisposable + where TStateType : WebSocketListenerState, new() + where TReturnDataType : class + { + /// <summary> + /// The _active connections + /// </summary> + protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>> ActiveConnections = + new List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>>(); + + /// <summary> + /// Gets the name. + /// </summary> + /// <value>The name.</value> + protected abstract string Name { get; } + + /// <summary> + /// Gets the data to send. + /// </summary> + /// <param name="state">The state.</param> + /// <returns>Task{`1}.</returns> + protected abstract Task<TReturnDataType> GetDataToSend(TStateType state); + + /// <summary> + /// The logger + /// </summary> + protected ILogger Logger; + + protected ITimerFactory TimerFactory { get; private set; } + + protected BasePeriodicWebSocketListener(ILogger logger, ITimerFactory timerFactory) + { + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + + Logger = logger; + TimerFactory = timerFactory; + } + + /// <summary> + /// The null task result + /// </summary> + protected Task NullTaskResult = Task.FromResult(true); + + /// <summary> + /// Processes the message. + /// </summary> + /// <param name="message">The message.</param> + /// <returns>Task.</returns> + public Task ProcessMessage(WebSocketMessageInfo message) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + if (string.Equals(message.MessageType, Name + "Start", StringComparison.OrdinalIgnoreCase)) + { + Start(message); + } + + if (string.Equals(message.MessageType, Name + "Stop", StringComparison.OrdinalIgnoreCase)) + { + Stop(message); + } + + return NullTaskResult; + } + + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + protected virtual bool SendOnTimer + { + get + { + return false; + } + } + + protected virtual void ParseMessageParams(string[] values) + { + + } + + /// <summary> + /// Starts sending messages over a web socket + /// </summary> + /// <param name="message">The message.</param> + private void Start(WebSocketMessageInfo message) + { + var vals = message.Data.Split(','); + + var dueTimeMs = long.Parse(vals[0], UsCulture); + var periodMs = long.Parse(vals[1], UsCulture); + + if (vals.Length > 2) + { + ParseMessageParams(vals.Skip(2).ToArray()); + } + + var cancellationTokenSource = new CancellationTokenSource(); + + Logger.Debug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); + + var timer = SendOnTimer ? + TimerFactory.Create(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : + null; + + var state = new TStateType + { + IntervalMs = periodMs, + InitialDelayMs = dueTimeMs + }; + + lock (ActiveConnections) + { + ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>(message.Connection, cancellationTokenSource, timer, state)); + } + + if (timer != null) + { + timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs)); + } + } + + /// <summary> + /// Timers the callback. + /// </summary> + /// <param name="state">The state.</param> + private void TimerCallback(object state) + { + var connection = (IWebSocketConnection)state; + + Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple; + + lock (ActiveConnections) + { + tuple = ActiveConnections.FirstOrDefault(c => c.Item1 == connection); + } + + if (tuple == null) + { + return; + } + + if (connection.State != WebSocketState.Open || tuple.Item2.IsCancellationRequested) + { + DisposeConnection(tuple); + return; + } + + SendData(tuple); + } + + protected void SendData(bool force) + { + List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>> tuples; + + lock (ActiveConnections) + { + tuples = ActiveConnections + .Where(c => + { + if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested) + { + var state = c.Item4; + + if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs) + { + return true; + } + } + + return false; + }) + .ToList(); + } + + foreach (var tuple in tuples) + { + SendData(tuple); + } + } + + private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple) + { + var connection = tuple.Item1; + + try + { + var state = tuple.Item4; + + var data = await GetDataToSend(state).ConfigureAwait(false); + + if (data != null) + { + await connection.SendAsync(new WebSocketMessage<TReturnDataType> + { + MessageType = Name, + Data = data + + }, tuple.Item2.Token).ConfigureAwait(false); + + state.DateLastSendUtc = DateTime.UtcNow; + } + } + catch (OperationCanceledException) + { + if (tuple.Item2.IsCancellationRequested) + { + DisposeConnection(tuple); + } + } + catch (Exception ex) + { + Logger.ErrorException("Error sending web socket message {0}", ex, Name); + DisposeConnection(tuple); + } + } + + /// <summary> + /// Stops sending messages over a web socket + /// </summary> + /// <param name="message">The message.</param> + private void Stop(WebSocketMessageInfo message) + { + lock (ActiveConnections) + { + var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection); + + if (connection != null) + { + DisposeConnection(connection); + } + } + } + + /// <summary> + /// Disposes the connection. + /// </summary> + /// <param name="connection">The connection.</param> + private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> connection) + { + Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); + + var timer = connection.Item3; + + if (timer != null) + { + try + { + timer.Dispose(); + } + catch (ObjectDisposedException) + { + + } + } + + try + { + connection.Item2.Cancel(); + connection.Item2.Dispose(); + } + catch (ObjectDisposedException) + { + + } + + ActiveConnections.Remove(connection); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + lock (ActiveConnections) + { + foreach (var connection in ActiveConnections.ToList()) + { + DisposeConnection(connection); + } + } + } + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + public class WebSocketListenerState + { + public DateTime DateLastSendUtc { get; set; } + public long InitialDelayMs { get; set; } + public long IntervalMs { get; set; } + } +} diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 77e6a7e405..c2cbda11d9 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -119,16 +119,12 @@ namespace MediaBrowser.Controller.Providers /// <param name="item">The item.</param> /// <param name="updateType">Type of the update.</param> /// <returns>Task.</returns> - Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType); + void SaveMetadata(IHasMetadata item, ItemUpdateType updateType); /// <summary> /// Saves the metadata. /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateType">Type of the update.</param> - /// <param name="savers">The savers.</param> - /// <returns>Task.</returns> - Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType, IEnumerable<string> savers); + void SaveMetadata(IHasMetadata item, ItemUpdateType updateType, IEnumerable<string> savers); /// <summary> /// Gets the metadata options. |
