aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/FilterService.cs2
-rw-r--r--MediaBrowser.Api/GamesService.cs41
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs17
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs152
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs248
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs32
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs2
-rw-r--r--MediaBrowser.Api/Reports/ReportsService.cs1
-rw-r--r--MediaBrowser.Api/SimilarItemsHelper.cs16
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs4
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs30
-rw-r--r--MediaBrowser.Api/TvShowsService.cs41
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs3
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs1
-rw-r--r--MediaBrowser.Api/UserService.cs9
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs4
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs10
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj4
-rw-r--r--MediaBrowser.Common.Implementations/packages.config2
-rw-r--r--MediaBrowser.Common/Net/HttpRequestOptions.cs3
-rw-r--r--MediaBrowser.Controller/Channels/ChannelItemInfo.cs2
-rw-r--r--MediaBrowser.Controller/Chapters/IChapterManager.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs23
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs7
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs28
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs295
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs2
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs14
-rw-r--r--MediaBrowser.Controller/Entities/KeywordExtensions.cs (renamed from MediaBrowser.Controller/Entities/IHasKeywords.cs)12
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs9
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs22
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs2
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs34
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs81
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs221
-rw-r--r--MediaBrowser.Controller/Entities/TagExtensions.cs (renamed from MediaBrowser.Controller/Entities/IHasTags.cs)15
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs22
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs5
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs7
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs103
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs1
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs7
-rw-r--r--MediaBrowser.Controller/LiveTv/IListingsProvider.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs11
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvService.cs19
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs21
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerEventInfo.cs14
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj11
-rw-r--r--MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs8
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs4
-rw-r--r--MediaBrowser.Controller/Persistence/IUserDataRepository.cs2
-rw-r--r--MediaBrowser.Controller/Providers/BaseItemXmlParser.cs16
-rw-r--r--MediaBrowser.Controller/Providers/IItemIdentityConverter.cs4
-rw-r--r--MediaBrowser.Controller/Providers/IItemIdentityProvider.cs4
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs22
-rw-r--r--MediaBrowser.Controller/Providers/IProviderRepository.cs25
-rw-r--r--MediaBrowser.Controller/Providers/ItemIdentifier.cs36
-rw-r--r--MediaBrowser.Controller/Providers/ItemIdentities.cs16
-rw-r--r--MediaBrowser.Controller/Providers/ItemInfo.cs8
-rw-r--r--MediaBrowser.Controller/Providers/MetadataStatus.cs49
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs3
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs18
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs2
-rw-r--r--MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs4
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml2
-rw-r--r--MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs36
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs5
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs16
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs6
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj6
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj6
-rw-r--r--MediaBrowser.Model/ApiClient/ServerCredentials.cs4
-rw-r--r--MediaBrowser.Model/ApiClient/ServerInfo.cs1
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs1
-rw-r--r--MediaBrowser.Model/Configuration/FanartOptions.cs5
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs26
-rw-r--r--MediaBrowser.Model/Configuration/TheMovieDbOptions.cs12
-rw-r--r--MediaBrowser.Model/Configuration/TvdbOptions.cs12
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs8
-rw-r--r--MediaBrowser.Model/Dlna/ResolutionNormalizer.cs20
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs3
-rw-r--r--MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs1
-rw-r--r--MediaBrowser.Model/Entities/ImageType.cs24
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs5
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvOptions.cs24
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj2
-rw-r--r--MediaBrowser.Model/Querying/ItemSortBy.cs1
-rw-r--r--MediaBrowser.Providers/Books/BookMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Channels/ChannelMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Chapters/ChapterManager.cs2
-rw-r--r--MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs7
-rw-r--r--MediaBrowser.Providers/Folders/DefaultImageProvider.cs165
-rw-r--r--MediaBrowser.Providers/Folders/FolderMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Folders/UserViewMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Games/GameMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Games/GameSystemMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Genres/GenreMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/LiveTv/AudioRecordingService.cs6
-rw-r--r--MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/LiveTv/VideoRecordingService.cs6
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs166
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs23
-rw-r--r--MediaBrowser.Providers/Manager/ProviderUtils.cs20
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj6
-rw-r--r--MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs196
-rw-r--r--MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs29
-rw-r--r--MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs6
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbImageProvider.cs7
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbProvider.cs42
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs5
-rw-r--r--MediaBrowser.Providers/Movies/MovieExternalIds.cs7
-rw-r--r--MediaBrowser.Providers/Movies/MovieMetadataService.cs17
-rw-r--r--MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs249
-rw-r--r--MediaBrowser.Providers/Music/AlbumMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Music/ArtistMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Music/AudioMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Music/FanArtAlbumProvider.cs31
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs25
-rw-r--r--MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs203
-rw-r--r--MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs5
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs177
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs9
-rw-r--r--MediaBrowser.Providers/Music/MusicVideoMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbImageProvider.cs48
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbItemProvider.cs14
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbProvider.cs118
-rw-r--r--MediaBrowser.Providers/People/PersonMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Photos/PhotoMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Studios/StudioMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/TV/EpisodeMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs33
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs192
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs25
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs14
-rw-r--r--MediaBrowser.Providers/TV/SeasonMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/TV/SeriesMetadataService.cs7
-rw-r--r--MediaBrowser.Providers/TV/SeriesPostScanTask.cs39
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs16
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs14
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs7
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs55
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs28
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs103
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonIdentityProvider.cs65
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs40
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs22
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs30
-rw-r--r--MediaBrowser.Providers/TV/TvExternalIds.cs2
-rw-r--r--MediaBrowser.Providers/Users/UserMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Videos/VideoMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Years/YearMetadataService.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs255
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Connect/Responses.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceManager.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs131
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs24
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs36
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs83
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs7
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs9
-rw-r--r--MediaBrowser.Server.Implementations/IO/FileRefresher.cs289
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs276
-rw-r--r--MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs188
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs52
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserDataManager.cs109
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs39
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs106
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs23
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs165
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs44
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs200
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs89
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj22
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs450
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs31
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs64
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs263
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs58
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs434
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs778
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs248
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs77
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs204
-rw-r--r--MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs332
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs16
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Social/SharingRepository.cs174
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncRepository.cs868
-rw-r--r--MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs118
-rw-r--r--MediaBrowser.Server.Implementations/packages.config8
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj5
-rw-r--r--MediaBrowser.Server.Mono/Native/DbConnector.cs24
-rw-r--r--MediaBrowser.Server.Mono/Native/SqliteExtensions.cs62
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs128
-rw-r--r--MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj4
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs44
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs44
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs20
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs40
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs61
-rw-r--r--MediaBrowser.ServerApplication/App.config1
-rw-r--r--MediaBrowser.ServerApplication/BackgroundServiceInstaller.cs2
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs12
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj5
-rw-r--r--MediaBrowser.ServerApplication/Native/DbConnector.cs24
-rw-r--r--MediaBrowser.ServerApplication/Native/SqliteExtensions.cs62
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkManager.cs14
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs7
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs2
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj48
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs14
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs26
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs7
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec6
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
-rw-r--r--SharedVersion.cs4
241 files changed, 5250 insertions, 6284 deletions
diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs
index c4419531c..b3b75359a 100644
--- a/MediaBrowser.Api/FilterService.cs
+++ b/MediaBrowser.Api/FilterService.cs
@@ -80,7 +80,7 @@ namespace MediaBrowser.Api
.OrderBy(i => i)
.ToArray();
- result.Tags = items.OfType<IHasTags>()
+ result.Tags = items
.SelectMany(i => i.Tags)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(i => i)
diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs
index 387771b6d..cb77e62ad 100644
--- a/MediaBrowser.Api/GamesService.cs
+++ b/MediaBrowser.Api/GamesService.cs
@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api
{
@@ -187,18 +188,40 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetSimilarGames request)
{
+ var result = GetSimilarItemsResult(request);
+
+ return ToOptimizedSerializedResultUsingCache(result);
+ }
+
+ private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ {
+ var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
+
+ var item = string.IsNullOrEmpty(request.Id) ?
+ (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
+ _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
+
+ var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ Limit = request.Limit,
+ IncludeItemTypes = new[]
+ {
+ typeof(Game).Name
+ },
+ SimilarTo = item
+
+ }).ToList();
+
var dtoOptions = GetDtoOptions(request);
- var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
- _itemRepo,
- _libraryManager,
- _userDataRepository,
- _dtoService,
- Logger,
- request, new[] { typeof(Game) },
- SimilarItemsHelper.GetSimiliarityScore);
+ var result = new QueryResult<BaseItemDto>
+ {
+ Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(),
- return ToOptimizedSerializedResultUsingCache(result);
+ TotalRecordCount = itemsResult.Count
+ };
+
+ return result;
}
}
}
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 5bb4ed5f0..79aaccfe8 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -280,11 +280,7 @@ namespace MediaBrowser.Api
episode.AbsoluteEpisodeNumber = request.AbsoluteEpisodeNumber;
}
- var hasTags = item as IHasTags;
- if (hasTags != null)
- {
- hasTags.Tags = request.Tags;
- }
+ item.Tags = request.Tags;
var hasTaglines = item as IHasTaglines;
if (hasTaglines != null)
@@ -298,11 +294,7 @@ namespace MediaBrowser.Api
hasShortOverview.ShortOverview = request.ShortOverview;
}
- var hasKeywords = item as IHasKeywords;
- if (hasKeywords != null)
- {
- hasKeywords.Keywords = request.Keywords;
- }
+ item.Keywords = request.Keywords;
if (request.Studios != null)
{
@@ -427,11 +419,6 @@ namespace MediaBrowser.Api
series.Status = request.SeriesStatus;
series.AirDays = request.AirDays;
series.AirTime = request.AirTime;
-
- if (request.DisplaySpecialsWithSeasons.HasValue)
- {
- series.DisplaySpecialsWithSeasons = request.DisplaySpecialsWithSeasons.Value;
- }
}
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index d3a4558c8..41c0c39ea 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -439,6 +439,12 @@ namespace MediaBrowser.Api.LiveTv
public string Id { get; set; }
}
+ [Route("/LiveTv/ListingProviders/Default", "GET")]
+ [Authenticated(AllowBeforeStartupWizard = true)]
+ public class GetDefaultListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
+ {
+ }
+
[Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
[Authenticated(AllowBeforeStartupWizard = true)]
public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
@@ -478,6 +484,40 @@ namespace MediaBrowser.Api.LiveTv
{
}
+ [Route("/LiveTv/ChannelMappingOptions")]
+ [Authenticated(AllowBeforeStartupWizard = true)]
+ public class GetChannelMappingOptions
+ {
+ [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ProviderId { get; set; }
+ }
+
+ [Route("/LiveTv/ChannelMappings")]
+ [Authenticated(AllowBeforeStartupWizard = true)]
+ public class SetChannelMapping
+ {
+ [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ProviderId { get; set; }
+ public string TunerChannelNumber { get; set; }
+ public string ProviderChannelNumber { get; set; }
+ }
+
+ public class ChannelMappingOptions
+ {
+ public List<TunerChannelMapping> TunerChannels { get; set; }
+ public List<NameIdPair> ProviderChannels { get; set; }
+ public List<NameValuePair> Mappings { get; set; }
+ public string ProviderName { get; set; }
+ }
+
+ public class TunerChannelMapping
+ {
+ public string Name { get; set; }
+ public string Number { get; set; }
+ public string ProviderChannelNumber { get; set; }
+ public string ProviderChannelName { get; set; }
+ }
+
[Route("/LiveTv/Registration", "GET")]
[Authenticated]
public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord>
@@ -525,6 +565,11 @@ namespace MediaBrowser.Api.LiveTv
_dtoService = dtoService;
}
+ public object Get(GetDefaultListingProvider request)
+ {
+ return ToOptimizedResult(new ListingsProviderInfo());
+ }
+
public async Task<object> Get(GetSatChannnelScanResult request)
{
var result = await _liveTvManager.GetSatChannelScanResult(request, CancellationToken.None).ConfigureAwait(false);
@@ -539,6 +584,102 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedResult(result);
}
+ public async Task<object> Post(SetChannelMapping request)
+ {
+ var config = GetConfiguration();
+
+ var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase));
+ listingsProviderInfo.ChannelMappings = listingsProviderInfo.ChannelMappings.Where(i => !string.Equals(i.Name, request.TunerChannelNumber, StringComparison.OrdinalIgnoreCase)).ToArray();
+
+ if (!string.Equals(request.TunerChannelNumber, request.ProviderChannelNumber, StringComparison.OrdinalIgnoreCase))
+ {
+ var list = listingsProviderInfo.ChannelMappings.ToList();
+ list.Add(new NameValuePair
+ {
+ Name = request.TunerChannelNumber,
+ Value = request.ProviderChannelNumber
+ });
+ listingsProviderInfo.ChannelMappings = list.ToArray();
+ }
+
+ UpdateConfiguration(config);
+
+ var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var mappings = listingsProviderInfo.ChannelMappings.ToList();
+
+ var tunerChannelMappings =
+ tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList();
+
+ return tunerChannelMappings.First(i => string.Equals(i.Number, request.TunerChannelNumber, StringComparison.OrdinalIgnoreCase));
+ }
+
+ public async Task<object> Get(GetChannelMappingOptions request)
+ {
+ var config = GetConfiguration();
+
+ var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase));
+
+ var listingsProviderName = _liveTvManager.ListingProviders.First(i => string.Equals(i.Type, listingsProviderInfo.Type, StringComparison.OrdinalIgnoreCase)).Name;
+
+ var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var mappings = listingsProviderInfo.ChannelMappings.ToList();
+
+ var result = new ChannelMappingOptions
+ {
+ TunerChannels = tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList(),
+
+ ProviderChannels = providerChannels.Select(i => new NameIdPair
+ {
+ Name = i.Name,
+ Id = i.Number
+
+ }).ToList(),
+
+ Mappings = mappings,
+
+ ProviderName = listingsProviderName
+ };
+
+ return ToOptimizedResult(result);
+ }
+
+ private TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, List<NameValuePair> mappings, List<ChannelInfo> providerChannels)
+ {
+ var result = new TunerChannelMapping
+ {
+ Name = channel.Number + " " + channel.Name,
+ Number = channel.Number
+ };
+
+ var mapping = mappings.FirstOrDefault(i => string.Equals(i.Name, channel.Number, StringComparison.OrdinalIgnoreCase));
+ var providerChannelNumber = channel.Number;
+
+ if (mapping != null)
+ {
+ providerChannelNumber = mapping.Value;
+ }
+
+ var providerChannel = providerChannels.FirstOrDefault(i => string.Equals(i.Number, providerChannelNumber, StringComparison.OrdinalIgnoreCase));
+
+ if (providerChannel != null)
+ {
+ result.ProviderChannelNumber = providerChannel.Number;
+ result.ProviderChannelName = providerChannel.Name;
+ }
+
+ return result;
+ }
+
public object Get(GetSatIniMappings request)
{
return ToOptimizedResult(_liveTvManager.GetSatIniMappings());
@@ -550,9 +691,7 @@ namespace MediaBrowser.Api.LiveTv
var response = await _httpClient.Get(new HttpRequestOptions
{
- Url = "https://json.schedulesdirect.org/20141201/available/countries",
- CacheLength = TimeSpan.FromDays(1),
- CacheMode = CacheMode.Unconditional
+ Url = "https://json.schedulesdirect.org/20141201/available/countries"
}).ConfigureAwait(false);
@@ -609,6 +748,11 @@ namespace MediaBrowser.Api.LiveTv
return _config.GetConfiguration<LiveTvOptions>("livetv");
}
+ private void UpdateConfiguration(LiveTvOptions options)
+ {
+ _config.SaveConfiguration("livetv", options);
+ }
+
public async Task<object> Get(GetLineups request)
{
var info = await _liveTvManager.GetLineups(request.Type, request.Id, request.Country, request.Location).ConfigureAwait(false);
@@ -648,7 +792,7 @@ namespace MediaBrowser.Api.LiveTv
Items = returnArray,
TotalRecordCount = channelResult.TotalRecordCount
};
-
+
return ToOptimizedSerializedResultUsingCache(result);
}
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index d8946e416..ff18d440c 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -14,6 +14,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Controller.LiveTv;
namespace MediaBrowser.Api.Movies
{
@@ -110,18 +111,16 @@ namespace MediaBrowser.Api.Movies
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public async Task<object> Get(GetSimilarMovies request)
+ public object Get(GetSimilarMovies request)
{
- var result = await GetSimilarItemsResult(
- request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
+ var result = GetSimilarItemsResult(request);
return ToOptimizedSerializedResultUsingCache(result);
}
- public async Task<object> Get(GetSimilarTrailers request)
+ public object Get(GetSimilarTrailers request)
{
- var result = await GetSimilarItemsResult(
- request, SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
+ var result = GetSimilarItemsResult(request);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -130,148 +129,85 @@ namespace MediaBrowser.Api.Movies
{
var user = _userManager.GetUserById(request.UserId);
- var query = new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Movie).Name }
- };
-
- if (user.Configuration.IncludeTrailersInSuggestions)
- {
- var includeList = query.IncludeItemTypes.ToList();
- includeList.Add(typeof(Trailer).Name);
- query.IncludeItemTypes = includeList.ToArray();
- }
-
- var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
- var movies = _libraryManager.GetItemList(query, parentIds)
- .OrderBy(i => (int)i.SourceType);
-
- var listEligibleForCategories = new List<BaseItem>();
- var listEligibleForSuggestion = new List<BaseItem>();
-
- var list = movies.ToList();
-
- listEligibleForCategories.AddRange(list);
- listEligibleForSuggestion.AddRange(list);
-
- listEligibleForCategories = listEligibleForCategories
- // Exclude trailers from the suggestion categories
- .Where(i => i is Movie)
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
- .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- listEligibleForSuggestion = listEligibleForSuggestion
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
- .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
- .ToList();
-
var dtoOptions = GetDtoOptions(request);
dtoOptions.Fields = request.GetItemFields().ToList();
- var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, dtoOptions);
+ var result = GetRecommendationCategories(user, request.ParentId, request.CategoryLimit, request.ItemLimit, dtoOptions);
return ToOptimizedResult(result);
}
- private async Task<ItemsResult> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
+ private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
var item = string.IsNullOrEmpty(request.Id) ?
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
-
- var query = new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Movie).Name }
- };
-
- if (user == null || user.Configuration.IncludeTrailersInSuggestions)
- {
- var includeList = query.IncludeItemTypes.ToList();
- includeList.Add(typeof(Trailer).Name);
- query.IncludeItemTypes = includeList.ToArray();
- }
-
- var list = _libraryManager.GetItemList(query)
- .OrderBy(i => (int)i.SourceType)
- .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
- .ToList();
- if (item is Video)
+ var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- var imdbId = item.GetProviderId(MetadataProviders.Imdb);
-
- // Use imdb id to try to filter duplicates of the same item
- if (!string.IsNullOrWhiteSpace(imdbId))
+ Limit = request.Limit,
+ IncludeItemTypes = new[]
{
- list = list
- .Where(i => !string.Equals(imdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase))
- .ToList();
- }
- }
-
- var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList();
-
- IEnumerable<BaseItem> returnItems = items;
-
- if (request.Limit.HasValue)
- {
- returnItems = returnItems.Take(request.Limit.Value);
- }
+ typeof(Movie).Name,
+ typeof(Trailer).Name,
+ typeof(LiveTvProgram).Name
+ },
+ IsMovie = true,
+ SimilarTo = item
+ }).ToList();
var dtoOptions = GetDtoOptions(request);
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
- Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
+ Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(),
- TotalRecordCount = items.Count
+ TotalRecordCount = itemsResult.Count
};
return result;
}
- private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, List<BaseItem> allMoviesForCategories, List<BaseItem> allMovies, int categoryLimit, int itemLimit, DtoOptions dtoOptions)
+ private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, string parentId, int categoryLimit, int itemLimit, DtoOptions dtoOptions)
{
var categories = new List<RecommendationDto>();
- var recentlyPlayedMovies = allMoviesForCategories
- .Select(i =>
+ var parentIds = string.IsNullOrWhiteSpace(parentId) ? new string[] { } : new[] { parentId };
+ var query = new InternalItemsQuery(user)
+ {
+ IncludeItemTypes = new[]
{
- var userdata = _userDataRepository.GetUserData(user, i);
- return new Tuple<BaseItem, bool, DateTime>(i, userdata.Played, userdata.LastPlayedDate ?? DateTime.MinValue);
- })
- .Where(i => i.Item2)
- .OrderByDescending(i => i.Item3)
- .Select(i => i.Item1)
- .ToList();
+ typeof(Movie).Name,
+ //typeof(Trailer).Name,
+ //typeof(LiveTvProgram).Name
+ },
+ // IsMovie = true
+ SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.Random },
+ SortOrder = SortOrder.Descending,
+ Limit = 7
+ };
- var excludeFromLiked = recentlyPlayedMovies.Take(10);
- var likedMovies = allMovies
- .Select(i =>
- {
- var score = 0;
- var userData = _userDataRepository.GetUserData(user, i);
+ var recentlyPlayedMovies = _libraryManager.GetItemList(query, parentIds).ToList();
- if (userData.IsFavorite)
- {
- score = 2;
- }
- else
- {
- score = userData.Likes.HasValue ? userData.Likes.Value ? 1 : -1 : 0;
- }
+ var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ IncludeItemTypes = new[]
+ {
+ typeof(Movie).Name,
+ typeof(Trailer).Name,
+ typeof(LiveTvProgram).Name
+ },
+ IsMovie = true,
+ SortBy = new[] { ItemSortBy.Random },
+ SortOrder = SortOrder.Descending,
+ Limit = 10,
+ IsFavoriteOrLiked = true,
+ ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray()
- return new Tuple<BaseItem, int>(i, score);
- })
- .OrderByDescending(i => i.Item2)
- .ThenBy(i => Guid.NewGuid())
- .Where(i => i.Item2 > 0)
- .Select(i => i.Item1)
- .Where(i => !excludeFromLiked.Contains(i));
+ }, parentIds).ToList();
var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
// Get recently played directors
@@ -284,11 +220,11 @@ namespace MediaBrowser.Api.Movies
.OrderBy(i => Guid.NewGuid())
.ToList();
- var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
- var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator();
+ var similarToRecentlyPlayed = GetSimilarTo(user, recentlyPlayedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
+ var similarToLiked = GetSimilarTo(user, likedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToLikedItem).GetEnumerator();
- var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
- var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
+ var hasDirectorFromRecentlyPlayed = GetWithDirector(user, recentDirectors, itemLimit, dtoOptions, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
+ var hasActorFromRecentlyPlayed = GetWithActor(user, recentActors, itemLimit, dtoOptions, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
var categoryTypes = new List<IEnumerator<RecommendationDto>>
{
@@ -331,23 +267,34 @@ namespace MediaBrowser.Api.Movies
return categories.OrderBy(i => i.RecommendationType).ThenBy(i => Guid.NewGuid());
}
- private IEnumerable<RecommendationDto> GetWithDirector(User user, List<BaseItem> allMovies, IEnumerable<string> directors, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetWithDirector(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
- var userId = user.Id;
-
- foreach (var director in directors)
+ foreach (var name in names)
{
- var items = allMovies
- .Where(i => _libraryManager.GetPeople(i).Any(p => string.Equals(p.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Name, director, StringComparison.OrdinalIgnoreCase)))
- .Take(itemLimit)
- .ToList();
+ var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ Person = name,
+ // Account for duplicates by imdb id, since the database doesn't support this yet
+ Limit = itemLimit + 2,
+ PersonTypes = new[] { PersonType.Director },
+ IncludeItemTypes = new[]
+ {
+ typeof(Movie).Name,
+ typeof(Trailer).Name,
+ typeof(LiveTvProgram).Name
+ },
+ IsMovie = true
+
+ }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ .Take(itemLimit)
+ .ToList();
if (items.Count > 0)
{
yield return new RecommendationDto
{
- BaselineItemName = director,
- CategoryId = director.GetMD5().ToString("N"),
+ BaselineItemName = name,
+ CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
};
@@ -355,20 +302,26 @@ namespace MediaBrowser.Api.Movies
}
}
- private IEnumerable<RecommendationDto> GetWithActor(User user, List<BaseItem> allMovies, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetWithActor(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
foreach (var name in names)
{
- var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery(user)
+ var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- Person = name
-
- });
-
- var items = allMovies
- .Where(i => itemsWithActor.Contains(i.Id))
- .Take(itemLimit)
- .ToList();
+ Person = name,
+ // Account for duplicates by imdb id, since the database doesn't support this yet
+ Limit = itemLimit + 2,
+ IncludeItemTypes = new[]
+ {
+ typeof(Movie).Name,
+ typeof(Trailer).Name,
+ typeof(LiveTvProgram).Name
+ },
+ IsMovie = true
+
+ }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ .Take(itemLimit)
+ .ToList();
if (items.Count > 0)
{
@@ -383,14 +336,23 @@ namespace MediaBrowser.Api.Movies
}
}
- private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> allMovies, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
+ private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
foreach (var item in baselineItems)
{
- var similar = SimilarItemsHelper
- .GetSimilaritems(item, _libraryManager, allMovies, SimilarItemsHelper.GetSimiliarityScore)
- .Take(itemLimit)
- .ToList();
+ var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ Limit = itemLimit,
+ IncludeItemTypes = new[]
+ {
+ typeof(Movie).Name,
+ typeof(Trailer).Name,
+ typeof(LiveTvProgram).Name
+ },
+ IsMovie = true,
+ SimilarTo = item
+
+ }).ToList();
if (similar.Count > 0)
{
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 421ccdb5d..7913f547a 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -846,7 +846,7 @@ namespace MediaBrowser.Api.Playback
if (MediaEncoder.SupportsDecoder("h264_qsv"))
{
// Seeing stalls and failures with decoding. Not worth it compared to encoding.
- //return "-c:v h264_qsv ";
+ return "-c:v h264_qsv ";
}
break;
case "mpeg2video":
@@ -980,11 +980,6 @@ namespace MediaBrowser.Api.Playback
var transcodingId = Guid.NewGuid().ToString("N");
var commandLineArgs = GetCommandLineArguments(outputPath, state, true);
- if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging)
- {
- commandLineArgs = "-loglevel debug " + commandLineArgs;
- }
-
var process = new Process
{
StartInfo = new ProcessStartInfo
@@ -1212,7 +1207,7 @@ namespace MediaBrowser.Api.Playback
}
}
- private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream)
+ private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream, string outputVideoCodec)
{
var bitrate = request.VideoBitRate;
@@ -1237,6 +1232,18 @@ namespace MediaBrowser.Api.Playback
}
}
+ if (bitrate.HasValue)
+ {
+ var inputVideoCodec = videoStream == null ? null : videoStream.Codec;
+ bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
+
+ // If a max bitrate was requested, don't let the scaled bitrate exceed it
+ if (request.VideoBitRate.HasValue)
+ {
+ bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
+ }
+ }
+
return bitrate;
}
@@ -1519,6 +1526,13 @@ namespace MediaBrowser.Api.Playback
}
else if (i == 25)
{
+ if (videoRequest != null)
+ {
+ videoRequest.ForceLiveStream = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ }
+ }
+ else if (i == 26)
+ {
if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
{
SubtitleDeliveryMethod method;
@@ -1528,7 +1542,7 @@ namespace MediaBrowser.Api.Playback
}
}
}
- else if (i == 26)
+ else if (i == 27)
{
request.TranscodingMaxAudioChannels = int.Parse(val, UsCulture);
}
@@ -1690,7 +1704,7 @@ namespace MediaBrowser.Api.Playback
if (videoRequest != null)
{
state.OutputVideoCodec = state.VideoRequest.VideoCodec;
- state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream);
+ state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
if (state.OutputVideoBitrate.HasValue)
{
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 061afed6d..fbcccbaca 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -96,7 +96,7 @@ namespace MediaBrowser.Api.Playback
public long? InputFileSize { get; set; }
public string OutputAudioSync = "1";
- public string OutputVideoSync = "vfr";
+ public string OutputVideoSync = "-1";
public List<string> SupportedAudioCodecs { get; set; }
diff --git a/MediaBrowser.Api/Reports/ReportsService.cs b/MediaBrowser.Api/Reports/ReportsService.cs
index cb1615826..36a2a4b61 100644
--- a/MediaBrowser.Api/Reports/ReportsService.cs
+++ b/MediaBrowser.Api/Reports/ReportsService.cs
@@ -213,7 +213,6 @@ namespace MediaBrowser.Api.Reports
NameStartsWith = request.NameStartsWith,
NameStartsWithOrGreater = request.NameStartsWithOrGreater,
HasImdbId = request.HasImdbId,
- IsYearMismatched = request.IsYearMismatched,
IsPlaceHolder = request.IsPlaceHolder,
IsLocked = request.IsLocked,
IsInBoxSet = request.IsInBoxSet,
diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs
index 277bba1dd..537ffc913 100644
--- a/MediaBrowser.Api/SimilarItemsHelper.cs
+++ b/MediaBrowser.Api/SimilarItemsHelper.cs
@@ -116,24 +116,12 @@ namespace MediaBrowser.Api
private static IEnumerable<string> GetTags(BaseItem item)
{
- var hasTags = item as IHasTags;
- if (hasTags != null)
- {
- return hasTags.Tags;
- }
-
- return new List<string>();
+ return item.Tags;
}
private static IEnumerable<string> GetKeywords(BaseItem item)
{
- var hasTags = item as IHasKeywords;
- if (hasTags != null)
- {
- return hasTags.Keywords;
- }
-
- return new List<string>();
+ return item.Keywords;
}
/// <summary>
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index ca934830d..f4aee080a 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -111,10 +111,10 @@ namespace MediaBrowser.Api
{
config.EnableLocalizedGuids = true;
config.EnableCustomPathSubFolders = true;
- config.EnableDateLastRefresh = true;
config.EnableStandaloneMusicKeys = true;
config.EnableCaseSensitiveItemIds = true;
- config.SchemaVersion = 79;
+ config.EnableFolderView = true;
+ config.SchemaVersion = 92;
}
public void Post(UpdateStartupConfiguration request)
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index c2183ad7b..160fda065 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -98,6 +98,10 @@ namespace MediaBrowser.Api.Subtitles
[ApiMember(Name = "EndPositionTicks", Description = "EndPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public long? EndPositionTicks { get; set; }
+
+ [ApiMember(Name = "CopyTimestamps", Description = "CopyTimestamps", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ public bool CopyTimestamps { get; set; }
+ public bool AddVttTimeMap { get; set; }
}
[Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
@@ -175,7 +179,7 @@ namespace MediaBrowser.Api.Subtitles
var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks);
- var url = string.Format("stream.vtt?StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
+ var url = string.Format("stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
positionTicks.ToString(CultureInfo.InvariantCulture),
endPositionTicks.ToString(CultureInfo.InvariantCulture),
accessToken);
@@ -190,7 +194,7 @@ namespace MediaBrowser.Api.Subtitles
return ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
- public object Get(GetSubtitle request)
+ public async Task<object> Get(GetSubtitle request)
{
if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase))
{
@@ -209,20 +213,32 @@ namespace MediaBrowser.Api.Subtitles
return ToStaticFileResult(subtitleStream.Path);
}
- var stream = GetSubtitles(request).Result;
+ using (var stream = await GetSubtitles(request).ConfigureAwait(false))
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ var text = reader.ReadToEnd();
+
+ if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap)
+ {
+ text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
+ }
- return ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format));
+ return ResultFactory.GetResult(text, MimeTypes.GetMimeType("file." + request.Format));
+ }
+ }
}
- private async Task<Stream> GetSubtitles(GetSubtitle request)
+ private Task<Stream> GetSubtitles(GetSubtitle request)
{
- return await _subtitleEncoder.GetSubtitles(request.Id,
+ return _subtitleEncoder.GetSubtitles(request.Id,
request.MediaSourceId,
request.Index,
request.Format,
request.StartPositionTicks,
request.EndPositionTicks,
- CancellationToken.None).ConfigureAwait(false);
+ request.CopyTimestamps,
+ CancellationToken.None);
}
public object Get(SearchRemoteSubtitles request)
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index aa0485d57..5ccfede1e 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -12,6 +12,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api
{
@@ -273,18 +274,40 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetSimilarShows request)
{
+ var result = GetSimilarItemsResult(request);
+
+ return ToOptimizedSerializedResultUsingCache(result);
+ }
+
+ private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ {
+ var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
+
+ var item = string.IsNullOrEmpty(request.Id) ?
+ (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
+ _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
+
+ var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ Limit = request.Limit,
+ IncludeItemTypes = new[]
+ {
+ typeof(Series).Name
+ },
+ SimilarTo = item
+
+ }).ToList();
+
var dtoOptions = GetDtoOptions(request);
- var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
- _itemRepo,
- _libraryManager,
- _userDataManager,
- _dtoService,
- Logger,
- request, new[] { typeof(Series) },
- SimilarItemsHelper.GetSimiliarityScore);
+ var result = new QueryResult<BaseItemDto>
+ {
+ Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(),
- return ToOptimizedSerializedResultUsingCache(result);
+ TotalRecordCount = itemsResult.Count
+ };
+
+ return result;
}
public object Get(GetUpcomingEpisodes request)
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 565bed053..18dec3253 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -333,12 +333,7 @@ namespace MediaBrowser.Api.UserLibrary
var tags = request.GetTags();
if (tags.Length > 0)
{
- var hasTags = i as IHasTags;
- if (hasTags == null)
- {
- return false;
- }
- if (!tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
+ if (!tags.Any(v => i.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index aee1a8d54..d27a560ba 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -100,9 +100,6 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "HasTvdbId", Description = "Optional filter by items that have a tvdb id or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? HasTvdbId { get; set; }
- [ApiMember(Name = "IsYearMismatched", Description = "Optional filter by items that are potentially misidentified.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool? IsYearMismatched { get; set; }
-
[ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsInBoxSet { get; set; }
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index dac1a6b1a..644b28437 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -187,7 +187,6 @@ namespace MediaBrowser.Api.UserLibrary
NameStartsWith = request.NameStartsWith,
NameStartsWithOrGreater = request.NameStartsWithOrGreater,
HasImdbId = request.HasImdbId,
- IsYearMismatched = request.IsYearMismatched,
IsPlaceHolder = request.IsPlaceHolder,
IsLocked = request.IsLocked,
IsInBoxSet = request.IsInBoxSet,
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 9b611c397..07ff36c41 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -385,7 +385,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("User not found");
}
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), null).ConfigureAwait(false);
await _userManager.DeleteUser(user).ConfigureAwait(false);
}
@@ -465,6 +465,10 @@ namespace MediaBrowser.Api
}
await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
+
+ var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
+
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
}
@@ -602,7 +606,8 @@ namespace MediaBrowser.Api
throw new ArgumentException("There must be at least one enabled user in the system.");
}
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
+ var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false);
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index f44c975d4..a76ab9f07 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -552,7 +552,7 @@ namespace MediaBrowser.Common.Implementations
}
catch (Exception ex)
{
- Logger.Error("Error creating {0}", ex, type.Name);
+ Logger.ErrorException("Error creating {0}", ex, type.Name);
throw;
}
@@ -571,7 +571,7 @@ namespace MediaBrowser.Common.Implementations
}
catch (Exception ex)
{
- Logger.Error("Error creating {0}", ex, type.Name);
+ Logger.ErrorException("Error creating {0}", ex, type.Name);
// Don't blow up in release mode
return null;
}
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
index f9dbd766f..ce1e9fd7f 100644
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
@@ -143,7 +143,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
};
}
- private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
+ private WebRequest GetRequest(HttpRequestOptions options, string method)
{
var request = CreateWebRequest(options.Url);
var httpWebRequest = request as HttpWebRequest;
@@ -154,7 +154,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
AddRequestHeaders(httpWebRequest, options);
- httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
+ httpWebRequest.AutomaticDecompression = options.EnableHttpCompression ?
+ (options.DecompressionMethod ?? DecompressionMethods.Deflate) :
+ DecompressionMethods.None;
}
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
@@ -366,7 +368,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
};
}
- var httpWebRequest = GetRequest(options, httpMethod, options.EnableHttpCompression);
+ var httpWebRequest = GetRequest(options, httpMethod);
if (options.RequestContentBytes != null ||
!string.IsNullOrEmpty(options.RequestContent) ||
@@ -556,7 +558,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
options.CancellationToken.ThrowIfCancellationRequested();
- var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression);
+ var httpWebRequest = GetRequest(options, "GET");
if (options.ResourcePool != null)
{
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index 70489d714..a889879d5 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -65,8 +65,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
</Reference>
- <Reference Include="SimpleInjector, Version=3.1.4.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
- <HintPath>..\packages\SimpleInjector.3.1.4\lib\net45\SimpleInjector.dll</HintPath>
+ <Reference Include="SimpleInjector, Version=3.1.5.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <HintPath>..\packages\SimpleInjector.3.1.5\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config
index d1d135b20..d1ede89a1 100644
--- a/MediaBrowser.Common.Implementations/packages.config
+++ b/MediaBrowser.Common.Implementations/packages.config
@@ -4,5 +4,5 @@
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="NLog" version="4.3.4" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
- <package id="SimpleInjector" version="3.1.4" targetFramework="net45" />
+ <package id="SimpleInjector" version="3.1.5" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs
index 75368a5fc..1a7f414a7 100644
--- a/MediaBrowser.Common/Net/HttpRequestOptions.cs
+++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Threading;
namespace MediaBrowser.Common.Net
@@ -16,6 +17,8 @@ namespace MediaBrowser.Common.Net
/// <value>The URL.</value>
public string Url { get; set; }
+ public DecompressionMethods? DecompressionMethod { get; set; }
+
/// <summary>
/// Gets or sets the accept header.
/// </summary>
diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
index 587023ab4..6135240e9 100644
--- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
+++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
@@ -53,6 +53,8 @@ namespace MediaBrowser.Controller.Channels
public bool IsInfiniteStream { get; set; }
+ public string HomePageUrl { get; set; }
+
public ChannelItemInfo()
{
MediaSources = new List<ChannelMediaInfo>();
diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs
index 676ef9c56..27e06fb8d 100644
--- a/MediaBrowser.Controller/Chapters/IChapterManager.cs
+++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs
@@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Chapters
/// <param name="chapters">The chapters.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveChapters(string itemId, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken);
+ Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken);
/// <summary>
/// Searches the specified video.
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index c34a884ff..06710b030 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -20,7 +20,6 @@ namespace MediaBrowser.Controller.Entities.Audio
IHasArtist,
IHasMusicGenres,
IHasLookupInfo<SongInfo>,
- IHasTags,
IHasMediaSources,
IThemeMedia,
IArchivable
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 615276e83..1f3b0c92a 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -179,17 +179,13 @@ namespace MediaBrowser.Controller.Entities.Audio
{
var items = GetRecursiveChildren().ToList();
- var songs = items.OfType<Audio>().ToList();
-
- var others = items.Except(songs).ToList();
-
- var totalItems = songs.Count + others.Count;
+ var totalItems = items.Count;
var numComplete = 0;
var childUpdateType = ItemUpdateType.None;
// Refresh songs
- foreach (var item in songs)
+ foreach (var item in items)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -199,7 +195,7 @@ namespace MediaBrowser.Controller.Entities.Audio
numComplete++;
double percent = numComplete;
percent /= totalItems;
- progress.Report(percent * 100);
+ progress.Report(percent * 95);
}
var parentRefreshOptions = refreshOptions;
@@ -212,19 +208,6 @@ namespace MediaBrowser.Controller.Entities.Audio
// Refresh current item
await RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
- // Refresh all non-songs
- foreach (var item in others)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var updateType = await item.RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
-
- numComplete++;
- double percent = numComplete;
- percent /= totalItems;
- progress.Report(percent * 100);
- }
-
progress.Report(100);
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 02dad93cb..c1743c749 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -62,13 +62,6 @@ namespace MediaBrowser.Controller.Entities.Audio
query.ArtistNames = new[] { Name };
}
- // Need this for now since the artist filter isn't yet supported by the db
- if (ConfigurationManager.Configuration.SchemaVersion < 79)
- {
- var filter = GetItemFilter();
- return LibraryManager.GetItemList(query).Where(filter);
- }
-
return LibraryManager.GetItemList(query);
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 61060766f..33fd03e15 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -26,6 +26,7 @@ using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.LiveTv;
+using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities
{
@@ -36,6 +37,7 @@ namespace MediaBrowser.Controller.Entities
{
protected BaseItem()
{
+ Keywords = new List<string>();
Tags = new List<string>();
Genres = new List<string>();
Studios = new List<string>();
@@ -69,10 +71,14 @@ namespace MediaBrowser.Controller.Entities
public List<ItemImageInfo> ImageInfos { get; set; }
+ [IgnoreDataMember]
+ public bool IsVirtualItem { get; set; }
+
/// <summary>
/// Gets or sets the album.
/// </summary>
/// <value>The album.</value>
+ [IgnoreDataMember]
public string Album { get; set; }
/// <summary>
@@ -810,6 +816,8 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public List<string> Tags { get; set; }
+ public List<string> Keywords { get; set; }
+
/// <summary>
/// Gets or sets the home page URL.
/// </summary>
@@ -1031,9 +1039,7 @@ namespace MediaBrowser.Controller.Entities
}
: options;
- var result = await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
-
- return result;
+ return await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
}
[IgnoreDataMember]
@@ -1394,15 +1400,10 @@ namespace MediaBrowser.Controller.Entities
private bool IsVisibleViaTags(User user)
{
- var hasTags = this as IHasTags;
-
- if (hasTags != null)
+ var policy = user.Policy;
+ if (policy.BlockedTags.Any(i => Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
{
- var policy = user.Policy;
- if (policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
- {
- return false;
- }
+ return false;
}
return true;
@@ -2214,5 +2215,10 @@ namespace MediaBrowser.Controller.Entities
DeleteFileLocation = false
});
}
+
+ public virtual List<ExternalUrl> GetRelatedUrls()
+ {
+ return new List<ExternalUrl>();
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index 1c86a53f0..96fad670e 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
{
- public class Book : BaseItem, IHasTags, IHasLookupInfo<BookInfo>, IHasSeries
+ public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
{
[IgnoreDataMember]
public override string MediaType
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index e7b1df55a..e3841099e 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class Folder
/// </summary>
- public class Folder : BaseItem, IHasThemeMedia, IHasTags
+ public class Folder : BaseItem, IHasThemeMedia
{
public static IUserManager UserManager { get; set; }
public static IUserViewManager UserViewManager { get; set; }
@@ -164,49 +164,15 @@ namespace MediaBrowser.Controller.Entities
item.DateModified = DateTime.UtcNow;
}
- AddChildInternal(item.Id);
-
await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
}
- protected void AddChildrenInternal(List<Guid> children)
- {
- lock (_childrenSyncLock)
- {
- var newChildren = ChildIds.ToList();
- newChildren.AddRange(children);
- _children = newChildren.ToList();
- }
- }
- protected void AddChildInternal(Guid child)
- {
- lock (_childrenSyncLock)
- {
- var childIds = ChildIds.ToList();
- if (!childIds.Contains(child))
- {
- childIds.Add(child);
- _children = childIds.ToList();
- }
- }
- }
-
- protected void RemoveChildrenInternal(List<Guid> children)
- {
- lock (_childrenSyncLock)
- {
- _children = ChildIds.Except(children).ToList();
- }
- }
-
/// <summary>
/// Removes the child.
/// </summary>
/// <param name="item">The item.</param>
public void RemoveChild(BaseItem item)
{
- RemoveChildrenInternal(new[] { item.Id }.ToList());
-
item.SetParent(null);
}
@@ -242,33 +208,6 @@ namespace MediaBrowser.Controller.Entities
#endregion
/// <summary>
- /// The children
- /// </summary>
- private IReadOnlyList<Guid> _children;
- /// <summary>
- /// The _children sync lock
- /// </summary>
- private readonly object _childrenSyncLock = new object();
- /// <summary>
- /// Gets or sets the actual children.
- /// </summary>
- /// <value>The actual children.</value>
- protected virtual IEnumerable<Guid> ChildIds
- {
- get
- {
- lock (_childrenSyncLock)
- {
- if (_children == null)
- {
- _children = LoadChildren().ToList();
- }
- return _children.ToList();
- }
- }
- }
-
- /// <summary>
/// Gets the actual children.
/// </summary>
/// <value>The actual children.</value>
@@ -277,7 +216,7 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- return ChildIds.Select(LibraryManager.GetItemById).Where(i => i != null);
+ return LoadChildren().Select(LibraryManager.GetItemById).Where(i => i != null);
}
}
@@ -461,17 +400,15 @@ namespace MediaBrowser.Controller.Entities
foreach (var item in itemsRemoved)
{
- if (item.LocationType == LocationType.Virtual ||
- item.LocationType == LocationType.Remote)
+ var itemLocationType = item.LocationType;
+ if (itemLocationType == LocationType.Virtual ||
+ itemLocationType == LocationType.Remote)
{
- // Don't remove these because there's no way to accurately validate them.
- validChildren.Add(item);
}
else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path))
{
await UpdateIsOffline(item, true).ConfigureAwait(false);
- validChildren.Add(item);
}
else
{
@@ -481,8 +418,6 @@ namespace MediaBrowser.Controller.Entities
if (actualRemovals.Count > 0)
{
- RemoveChildrenInternal(actualRemovals.Select(i => i.Id).ToList());
-
foreach (var item in actualRemovals)
{
Logger.Debug("Removed item: " + item.Path);
@@ -495,8 +430,6 @@ namespace MediaBrowser.Controller.Entities
}
await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);
-
- AddChildrenInternal(newItems.Select(i => i.Id).ToList());
}
}
@@ -733,6 +666,27 @@ namespace MediaBrowser.Controller.Entities
});
}
+ public virtual int GetChildCount(User user)
+ {
+ if (LinkedChildren.Count > 0)
+ {
+ if (!(this is ICollectionFolder))
+ {
+ return GetChildren(user, true).Count();
+ }
+ }
+
+ var result = GetItems(new InternalItemsQuery(user)
+ {
+ Recursive = false,
+ Limit = 0,
+ ParentId = Id
+
+ }).Result;
+
+ return result.TotalRecordCount;
+ }
+
public QueryResult<BaseItem> QueryRecursive(InternalItemsQuery query)
{
var user = query.User;
@@ -768,58 +722,13 @@ namespace MediaBrowser.Controller.Entities
{
if (!(this is ICollectionFolder))
{
- Logger.Debug("Query requires post-filtering due to LinkedChildren");
+ Logger.Debug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name);
return true;
}
}
- var supportsUserDataQueries = ConfigurationManager.Configuration.SchemaVersion >= 76;
-
if (query.SortBy != null && query.SortBy.Length > 0)
{
- if (!supportsUserDataQueries)
- {
- if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed");
- return true;
- }
- }
-
- if (ConfigurationManager.Configuration.SchemaVersion < 79)
- {
- if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist");
- return true;
- }
- }
-
if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder");
@@ -840,11 +749,6 @@ namespace MediaBrowser.Controller.Entities
Logger.Debug("Query requires post-filtering due to ItemSortBy.Metascore");
return true;
}
- if (query.SortBy.Contains(ItemSortBy.OfficialRating, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.OfficialRating");
- return true;
- }
if (query.SortBy.Contains(ItemSortBy.Players, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Players");
@@ -860,11 +764,6 @@ namespace MediaBrowser.Controller.Entities
Logger.Debug("Query requires post-filtering due to ItemSortBy.SeriesSortName");
return true;
}
- if (query.SortBy.Contains(ItemSortBy.Studio, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.Studio");
- return true;
- }
if (query.SortBy.Contains(ItemSortBy.VideoBitRate, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.VideoBitRate");
@@ -884,39 +783,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (!supportsUserDataQueries)
- {
- if (query.IsLiked.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsLiked");
- return true;
- }
-
- if (query.IsFavoriteOrLiked.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked");
- return true;
- }
-
- if (query.IsFavorite.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsFavorite");
- return true;
- }
-
- if (query.IsResumable.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsResumable");
- return true;
- }
-
- if (query.IsPlayed.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsPlayed");
- return true;
- }
- }
-
if (query.IsInBoxSet.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsInBoxSet");
@@ -930,30 +796,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (query.HasImdbId.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to HasImdbId");
- return true;
- }
-
- if (query.HasTmdbId.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to HasTmdbId");
- return true;
- }
-
- if (query.HasTvdbId.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to HasTvdbId");
- return true;
- }
-
- if (query.IsYearMismatched.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsYearMismatched");
- return true;
- }
-
if (query.HasOfficialRating.HasValue)
{
Logger.Debug("Query requires post-filtering due to HasOfficialRating");
@@ -1003,12 +845,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (query.ImageTypes.Length > 0)
- {
- Logger.Debug("Query requires post-filtering due to ImageTypes");
- return true;
- }
-
// Apply studio filter
if (query.StudioIds.Length > 0)
{
@@ -1042,12 +878,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (query.OfficialRatings.Length > 0)
- {
- Logger.Debug("Query requires post-filtering due to OfficialRatings");
- return true;
- }
-
if (query.IsMissing.HasValue)
{
Logger.Debug("Query requires post-filtering due to IsMissing");
@@ -1066,7 +896,7 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User))
+ if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User, ConfigurationManager))
{
Logger.Debug("Query requires post-filtering due to CollapseBoxSetItems");
return true;
@@ -1102,15 +932,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (ConfigurationManager.Configuration.SchemaVersion < 79)
- {
- if (query.ArtistNames.Length > 0)
- {
- Logger.Debug("Query requires post-filtering due to ArtistNames");
- return true;
- }
- }
-
return false;
}
@@ -1183,7 +1004,7 @@ namespace MediaBrowser.Controller.Entities
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query)
{
- return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager);
+ return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager);
}
public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
@@ -1613,60 +1434,36 @@ namespace MediaBrowser.Controller.Entities
return;
}
- var recursiveItemCount = 0;
- var unplayed = 0;
-
- double totalPercentPlayed = 0;
-
- var itemsResult = GetItems(new InternalItemsQuery(user)
+ var unplayedQueryResult = GetItems(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false,
- ExcludeLocationTypes = new[] { LocationType.Virtual },
- EnableTotalRecordCount = false
+ IsVirtualItem = false,
+ EnableTotalRecordCount = true,
+ Limit = 0,
+ IsPlayed = false
}).Result;
- var children = itemsResult.Items;
-
- // Loop through each recursive child
- foreach (var child in children)
+ var allItemsQueryResult = GetItems(new InternalItemsQuery(user)
{
- recursiveItemCount++;
-
- var isUnplayed = true;
-
- var itemUserData = UserDataManager.GetUserData(user, child);
-
- // Incrememt totalPercentPlayed
- if (itemUserData != null)
- {
- if (itemUserData.Played)
- {
- totalPercentPlayed += 100;
-
- isUnplayed = false;
- }
- else if (itemUserData.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0)
- {
- double itemPercent = itemUserData.PlaybackPositionTicks;
- itemPercent /= child.RunTimeTicks.Value;
- totalPercentPlayed += itemPercent;
- }
- }
+ Recursive = true,
+ IsFolder = false,
+ IsVirtualItem = false,
+ EnableTotalRecordCount = true,
+ Limit = 0
- if (isUnplayed)
- {
- unplayed++;
- }
- }
+ }).Result;
- dto.UnplayedItemCount = unplayed;
+ double recursiveItemCount = allItemsQueryResult.TotalRecordCount;
+ double unplayedCount = unplayedQueryResult.TotalRecordCount;
if (recursiveItemCount > 0)
{
- dto.PlayedPercentage = totalPercentPlayed / recursiveItemCount;
+ var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100;
+ dto.PlayedPercentage = 100 - unplayedPercentage;
dto.Played = dto.PlayedPercentage.Value >= 100;
+ dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
index 9ed240046..317c71529 100644
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ b/MediaBrowser.Controller/Entities/Game.cs
@@ -7,7 +7,7 @@ using System.Linq;
namespace MediaBrowser.Controller.Entities
{
- public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasTags, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
+ public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
{
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 823f4066c..e193a9dad 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -19,6 +19,8 @@ namespace MediaBrowser.Controller.Entities
public User User { get; set; }
+ public BaseItem SimilarTo { get; set; }
+
public bool? IsFolder { get; set; }
public bool? IsFavorite { get; set; }
public bool? IsFavoriteOrLiked { get; set; }
@@ -33,6 +35,7 @@ namespace MediaBrowser.Controller.Entities
public string[] ExcludeTags { get; set; }
public string[] ExcludeInheritedTags { get; set; }
public string[] Genres { get; set; }
+ public string[] Keywords { get; set; }
public bool? IsMissing { get; set; }
public bool? IsUnaired { get; set; }
@@ -52,6 +55,7 @@ namespace MediaBrowser.Controller.Entities
public string Person { get; set; }
public string[] PersonIds { get; set; }
public string[] ItemIds { get; set; }
+ public string[] ExcludeItemIds { get; set; }
public string AdjacentTo { get; set; }
public string[] PersonTypes { get; set; }
@@ -60,7 +64,6 @@ namespace MediaBrowser.Controller.Entities
public bool? IsInBoxSet { get; set; }
public bool? IsLocked { get; set; }
public bool? IsPlaceHolder { get; set; }
- public bool? IsYearMismatched { get; set; }
public bool? HasImdbId { get; set; }
public bool? HasOverview { get; set; }
@@ -107,6 +110,7 @@ namespace MediaBrowser.Controller.Entities
internal List<Guid> ItemIdsFromPersonFilters { get; set; }
public int? ParentIndexNumber { get; set; }
+ public int? ParentIndexNumberNotEquals { get; set; }
public int? IndexNumber { get; set; }
public int? MinParentalRating { get; set; }
public int? MaxParentalRating { get; set; }
@@ -114,6 +118,7 @@ namespace MediaBrowser.Controller.Entities
public bool? IsCurrentSchema { get; set; }
public bool? HasDeadParentId { get; set; }
public bool? IsOffline { get; set; }
+ public bool? IsVirtualItem { get; set; }
public Guid? ParentId { get; set; }
public string[] AncestorIds { get; set; }
@@ -137,6 +142,8 @@ namespace MediaBrowser.Controller.Entities
public bool GroupByPresentationUniqueKey { get; set; }
public bool EnableTotalRecordCount { get; set; }
public bool ForceDirect { get; set; }
+ public Dictionary<string, string> ExcludeProviderIds { get; set; }
+ public string GroupByAncestorOfType { get; set; }
public InternalItemsQuery()
{
@@ -145,12 +152,14 @@ namespace MediaBrowser.Controller.Entities
AlbumNames = new string[] { };
ArtistNames = new string[] { };
-
+ ExcludeProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
BlockUnratedItems = new UnratedItem[] { };
Tags = new string[] { };
OfficialRatings = new string[] { };
SortBy = new string[] { };
MediaTypes = new string[] { };
+ Keywords = new string[] { };
IncludeItemTypes = new string[] { };
ExcludeItemTypes = new string[] { };
Genres = new string[] { };
@@ -164,6 +173,7 @@ namespace MediaBrowser.Controller.Entities
PersonIds = new string[] { };
ChannelIds = new string[] { };
ItemIds = new string[] { };
+ ExcludeItemIds = new string[] { };
AncestorIds = new string[] { };
TopParentIds = new string[] { };
ExcludeTags = new string[] { };
diff --git a/MediaBrowser.Controller/Entities/IHasKeywords.cs b/MediaBrowser.Controller/Entities/KeywordExtensions.cs
index ab9eb4aee..5c9afdf3d 100644
--- a/MediaBrowser.Controller/Entities/IHasKeywords.cs
+++ b/MediaBrowser.Controller/Entities/KeywordExtensions.cs
@@ -1,21 +1,11 @@
using System;
-using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Entities
{
- public interface IHasKeywords
- {
- /// <summary>
- /// Gets or sets the keywords.
- /// </summary>
- /// <value>The keywords.</value>
- List<string> Keywords { get; set; }
- }
-
public static class KeywordExtensions
{
- public static void AddKeyword(this IHasKeywords item, string name)
+ public static void AddKeyword(this BaseItem item, string name)
{
if (string.IsNullOrWhiteSpace(name))
{
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 09a9d97bc..4effc162e 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <summary>
/// Class BoxSet
/// </summary>
- public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IHasShares
+ public class BoxSet : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IHasShares
{
public List<Share> Shares { get; set; }
@@ -26,7 +26,6 @@ namespace MediaBrowser.Controller.Entities.Movies
RemoteTrailerIds = new List<Guid>();
DisplayOrder = ItemSortBy.PremiereDate;
- Keywords = new List<string>();
Shares = new List<Share>();
}
@@ -48,12 +47,6 @@ namespace MediaBrowser.Controller.Entities.Movies
public List<MediaUrl> RemoteTrailers { get; set; }
/// <summary>
- /// Gets or sets the tags.
- /// </summary>
- /// <value>The tags.</value>
- public List<string> Keywords { get; set; }
-
- /// <summary>
/// Gets or sets the display order.
/// </summary>
/// <value>The display order.</value>
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 5882b5f4d..c7a833c58 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -8,13 +8,14 @@ using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities.Movies
{
/// <summary>
/// Class Movie
/// </summary>
- public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
+ public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasProductionLocations, IHasBudget, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
{
public List<Guid> SpecialFeatureIds { get; set; }
@@ -31,7 +32,6 @@ namespace MediaBrowser.Controller.Entities.Movies
ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>();
Taglines = new List<string>();
- Keywords = new List<string>();
ProductionLocations = new List<string>();
}
@@ -41,7 +41,6 @@ namespace MediaBrowser.Controller.Entities.Movies
public List<Guid> LocalTrailerIds { get; set; }
public List<Guid> RemoteTrailerIds { get; set; }
- public List<string> Keywords { get; set; }
public List<MediaUrl> RemoteTrailers { get; set; }
@@ -163,5 +162,22 @@ namespace MediaBrowser.Controller.Entities.Movies
return hasChanges;
}
+
+ public override List<ExternalUrl> GetRelatedUrls()
+ {
+ var list = base.GetRelatedUrls();
+
+ var imdbId = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(imdbId))
+ {
+ list.Add(new ExternalUrl
+ {
+ Name = "Trakt",
+ Url = string.Format("https://trakt.tv/movies/{0}", imdbId)
+ });
+ }
+
+ return list;
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 3358ccc6f..de756563d 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -5,7 +5,7 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities
{
- public class Photo : BaseItem, IHasTags, IHasTaglines
+ public class Photo : BaseItem, IHasTaglines
{
public List<string> Taglines { get; set; }
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index 48ca7bbcc..e46978af3 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class Studio
/// </summary>
- public class Studio : BaseItem, IItemByName, IHasTags
+ public class Studio : BaseItem, IItemByName
{
public override List<string> GetUserDataKeys()
{
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index a4b0b3082..2dc459239 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -11,13 +11,25 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary>
/// Class Episode
/// </summary>
- public class Episode : Video, IHasLookupInfo<EpisodeInfo>, IHasSeries
- {
- /// <summary>
- /// Gets the season in which it aired.
- /// </summary>
- /// <value>The aired season.</value>
- public int? AirsBeforeSeasonNumber { get; set; }
+ public class Episode : Video, IHasTrailers, IHasLookupInfo<EpisodeInfo>, IHasSeries
+ {
+
+ public Episode()
+ {
+ RemoteTrailers = new List<MediaUrl>();
+ LocalTrailerIds = new List<Guid>();
+ RemoteTrailerIds = new List<Guid>();
+ }
+
+ public List<Guid> LocalTrailerIds { get; set; }
+ public List<Guid> RemoteTrailerIds { get; set; }
+ public List<MediaUrl> RemoteTrailers { get; set; }
+
+ /// <summary>
+ /// Gets the season in which it aired.
+ /// </summary>
+ /// <value>The aired season.</value>
+ public int? AirsBeforeSeasonNumber { get; set; }
public int? AirsAfterSeasonNumber { get; set; }
public int? AirsBeforeEpisodeNumber { get; set; }
@@ -96,7 +108,13 @@ namespace MediaBrowser.Controller.Entities.TV
var series = Series;
if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue)
{
- list.InsertRange(0, series.GetUserDataKeys().Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000")));
+ var seriesUserDataKeys = series.GetUserDataKeys();
+ var take = seriesUserDataKeys.Count;
+ if (seriesUserDataKeys.Count > 1)
+ {
+ take--;
+ }
+ list.InsertRange(0, seriesUserDataKeys.Take(take).Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000")));
}
return list;
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index 7fa1b55de..9a9014844 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -75,6 +75,11 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
+ public override int GetChildCount(User user)
+ {
+ return GetChildren(user, true).Count();
+ }
+
/// <summary>
/// This Episode's Series Instance
/// </summary>
@@ -128,39 +133,16 @@ namespace MediaBrowser.Controller.Entities.TV
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
}
- public override bool RequiresRefresh()
- {
- var result = base.RequiresRefresh();
-
- if (!result)
- {
- if (!IsVirtualItem.HasValue)
- {
- return true;
- }
- }
-
- return result;
- }
-
- [IgnoreDataMember]
- public bool? IsVirtualItem { get; set; }
-
[IgnoreDataMember]
public bool IsMissingSeason
{
- get { return (IsVirtualItem ?? DetectIsVirtualItem()) && !IsUnaired; }
+ get { return (IsVirtualItem) && !IsUnaired; }
}
[IgnoreDataMember]
public bool IsVirtualUnaired
{
- get { return (IsVirtualItem ?? DetectIsVirtualItem()) && IsUnaired; }
- }
-
- private bool DetectIsVirtualItem()
- {
- return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.LocationType == LocationType.Virtual);
+ get { return (IsVirtualItem) && IsUnaired; }
}
[IgnoreDataMember]
@@ -196,52 +178,17 @@ namespace MediaBrowser.Controller.Entities.TV
{
var config = user.Configuration;
- return GetEpisodes(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes);
+ return GetEpisodes(Series, user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes);
}
- public IEnumerable<Episode> GetEpisodes(User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
+ public IEnumerable<Episode> GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
{
- var series = Series;
-
- if (IndexNumber.HasValue && series != null)
- {
- return series.GetEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes);
- }
-
- var episodes = GetRecursiveChildren(user)
- .OfType<Episode>();
-
- if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
- {
- var seasonNumber = IndexNumber;
- var list = episodes.ToList();
-
- if (seasonNumber.HasValue)
- {
- list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
- .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value));
- }
- else
- {
- list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>()
- .Where(i => !i.ParentIndexNumber.HasValue));
- }
-
- episodes = list.DistinctBy(i => i.Id);
- }
-
- if (!includeMissingEpisodes)
- {
- episodes = episodes.Where(i => !i.IsMissingEpisode);
- }
- if (!includeVirtualUnairedEpisodes)
- {
- episodes = episodes.Where(i => !i.IsVirtualUnaired);
- }
+ return GetEpisodes(series, user, includeMissingEpisodes, includeVirtualUnairedEpisodes, null);
+ }
- return LibraryManager
- .Sort(episodes, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending)
- .Cast<Episode>();
+ public IEnumerable<Episode> GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> allSeriesEpisodes)
+ {
+ return series.GetEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes, allSeriesEpisodes);
}
public IEnumerable<Episode> GetEpisodes()
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 6c499f618..1cc496b35 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Providers;
using MoreLinq;
namespace MediaBrowser.Controller.Entities.TV
@@ -30,7 +31,6 @@ namespace MediaBrowser.Controller.Entities.TV
RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>();
- DisplaySpecialsWithSeasons = true;
}
[IgnoreDataMember]
@@ -57,8 +57,6 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- public bool DisplaySpecialsWithSeasons { get; set; }
-
public List<Guid> LocalTrailerIds { get; set; }
public List<Guid> RemoteTrailerIds { get; set; }
@@ -94,10 +92,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
- return GetRecursiveChildren(i => i is Episode)
- .Select(i => i.DateCreated)
- .OrderByDescending(i => i)
- .FirstOrDefault();
+ return DateLastMediaAdded ?? DateTime.MinValue;
}
}
@@ -106,14 +101,30 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
- if (EnablePooling())
+ var userdatakeys = GetUserDataKeys();
+
+ if (userdatakeys.Count > 1)
{
- return GetUserDataKeys().First();
+ return userdatakeys[0];
}
return base.PresentationUniqueKey;
}
}
+ public override int GetChildCount(User user)
+ {
+ var result = LibraryManager.GetItemsResult(new InternalItemsQuery(user)
+ {
+ AncestorWithPresentationUniqueKey = PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Season).Name },
+ SortBy = new[] { ItemSortBy.SortName },
+ IsVirtualItem = false,
+ Limit = 0
+ });
+
+ return result.TotalRecordCount;
+ }
+
/// <summary>
/// Gets the user data key.
/// </summary>
@@ -182,27 +193,32 @@ namespace MediaBrowser.Controller.Entities.TV
protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query)
{
- var user = query.User;
-
- Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
-
- IEnumerable<BaseItem> items;
-
if (query.User == null)
{
- items = query.Recursive
- ? GetRecursiveChildren(filter)
- : Children.Where(filter);
+ return base.GetItemsInternal(query);
}
- else
+
+ var user = query.User;
+
+ if (query.Recursive)
{
- items = query.Recursive
- ? GetSeasons(user).Cast<BaseItem>().Concat(GetEpisodes(user)).Where(filter)
- : GetSeasons(user).Where(filter);
+ query.AncestorWithPresentationUniqueKey = PresentationUniqueKey;
+ if (query.SortBy.Length == 0)
+ {
+ query.SortBy = new[] { ItemSortBy.SortName };
+ }
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
+ }
+ query.IsVirtualItem = false;
+ return Task.FromResult(LibraryManager.GetItemsResult(query));
}
- var result = PostFilterAndSort(items, query);
+ Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
+ var items = GetSeasons(user).Where(filter);
+ var result = PostFilterAndSort(items, query);
return Task.FromResult(result);
}
@@ -210,33 +226,13 @@ namespace MediaBrowser.Controller.Entities.TV
{
IEnumerable<Season> seasons;
- if (EnablePooling())
+ seasons = LibraryManager.GetItemList(new InternalItemsQuery(user)
{
- var seriesIds = LibraryManager.GetItemIds(new InternalItemsQuery(user)
- {
- PresentationUniqueKey = PresentationUniqueKey,
- IncludeItemTypes = new[] { typeof(Series).Name }
- });
+ AncestorWithPresentationUniqueKey = PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Season).Name },
+ SortBy = new[] { ItemSortBy.SortName }
- if (seriesIds.Count > 1)
- {
- seasons = LibraryManager.GetItemList(new InternalItemsQuery(user)
- {
- AncestorIds = seriesIds.Select(i => i.ToString("N")).ToArray(),
- IncludeItemTypes = new[] { typeof(Season).Name },
- SortBy = new[] { ItemSortBy.SortName }
-
- }).Cast<Season>();
- }
- else
- {
- seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType<Season>();
- }
- }
- else
- {
- seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType<Season>();
- }
+ }).Cast<Season>();
if (!includeMissingSeasons)
{
@@ -259,8 +255,18 @@ namespace MediaBrowser.Controller.Entities.TV
public IEnumerable<Episode> GetEpisodes(User user, bool includeMissing, bool includeVirtualUnaired)
{
- var allEpisodes = GetSeasons(user, true, true)
- .SelectMany(i => i.GetEpisodes(user, includeMissing, includeVirtualUnaired))
+ var allItems = LibraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ AncestorWithPresentationUniqueKey = PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name },
+ SortBy = new[] { ItemSortBy.SortName }
+
+ }).ToList();
+
+ var allSeriesEpisodes = allItems.OfType<Episode>().ToList();
+
+ var allEpisodes = allItems.OfType<Season>()
+ .SelectMany(i => i.GetEpisodes(this, user, includeMissing, includeVirtualUnaired, allSeriesEpisodes))
.Reverse()
.ToList();
@@ -283,9 +289,6 @@ namespace MediaBrowser.Controller.Entities.TV
var totalItems = seasons.Count + otherItems.Count;
var numComplete = 0;
- refreshOptions = new MetadataRefreshOptions(refreshOptions);
- refreshOptions.IsPostRecursiveRefresh = true;
-
// Refresh current item
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
@@ -315,7 +318,7 @@ namespace MediaBrowser.Controller.Entities.TV
&& refreshOptions.MetadataRefreshMode != MetadataRefreshMode.FullRefresh
&& !refreshOptions.ReplaceAllMetadata
&& episode.IsMissingEpisode
- && episode.LocationType == Model.Entities.LocationType.Virtual
+ && episode.LocationType == LocationType.Virtual
&& episode.PremiereDate.HasValue
&& (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30)
{
@@ -333,6 +336,8 @@ namespace MediaBrowser.Controller.Entities.TV
progress.Report(percent * 100);
}
+ refreshOptions = new MetadataRefreshOptions(refreshOptions);
+ refreshOptions.IsPostRecursiveRefresh = true;
await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
progress.Report(100);
@@ -345,50 +350,32 @@ namespace MediaBrowser.Controller.Entities.TV
return GetEpisodes(user, season, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes);
}
- private bool EnablePooling()
+ private IEnumerable<Episode> GetAllEpisodes(User user)
{
- return false;
+ return LibraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ AncestorWithPresentationUniqueKey = PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ SortBy = new[] { ItemSortBy.SortName }
+
+ }).Cast<Episode>();
}
public IEnumerable<Episode> GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
{
- IEnumerable<Episode> episodes;
-
- if (EnablePooling())
- {
- var seriesIds = LibraryManager.GetItemIds(new InternalItemsQuery(user)
- {
- PresentationUniqueKey = PresentationUniqueKey,
- IncludeItemTypes = new[] { typeof(Series).Name }
- });
+ IEnumerable<Episode> episodes = GetAllEpisodes(user);
- if (seriesIds.Count > 1)
- {
- episodes = LibraryManager.GetItemList(new InternalItemsQuery(user)
- {
- AncestorIds = seriesIds.Select(i => i.ToString("N")).ToArray(),
- IncludeItemTypes = new[] { typeof(Episode).Name },
- SortBy = new[] { ItemSortBy.SortName }
+ return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
+ }
- }).Cast<Episode>();
- }
- else
- {
- episodes = GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Episode).Name }
- }).Cast<Episode>();
- }
- }
- else
+ public IEnumerable<Episode> GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> allSeriesEpisodes)
+ {
+ if (allSeriesEpisodes == null)
{
- episodes = GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Episode).Name }
- }).Cast<Episode>();
+ return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes);
}
- episodes = FilterEpisodesBySeason(episodes, parentSeason, DisplaySpecialsWithSeasons);
+ var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons);
if (!includeMissingEpisodes)
{
@@ -436,38 +423,31 @@ namespace MediaBrowser.Controller.Entities.TV
public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, Season parentSeason, bool includeSpecials)
{
var seasonNumber = parentSeason.IndexNumber;
- if (!includeSpecials || (seasonNumber.HasValue && seasonNumber.Value == 0))
- {
- var seasonPresentationKey = parentSeason.PresentationUniqueKey;
+ var seasonPresentationKey = parentSeason.PresentationUniqueKey;
- return episodes.Where(i =>
- {
- if ((i.ParentIndexNumber ?? -1) == seasonNumber)
- {
- return true;
- }
+ var supportSpecialsInSeason = includeSpecials && seasonNumber.HasValue && seasonNumber.Value != 0;
- var season = i.Season;
- return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
- });
- }
- else
+ return episodes.Where(episode =>
{
- var seasonPresentationKey = parentSeason.PresentationUniqueKey;
-
- return episodes.Where(episode =>
+ var currentSeasonNumber = supportSpecialsInSeason ? episode.AiredSeasonNumber : episode.ParentIndexNumber;
+ if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
{
- var currentSeasonNumber = episode.AiredSeasonNumber;
+ return true;
+ }
- if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
- {
- return true;
- }
+ if (!currentSeasonNumber.HasValue && !seasonNumber.HasValue && parentSeason.LocationType == LocationType.Virtual)
+ {
+ return true;
+ }
+ if (!episode.ParentIndexNumber.HasValue)
+ {
var season = episode.Season;
return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
- });
- }
+ }
+
+ return false;
+ });
}
protected override bool GetBlockUnratedValue(UserPolicy config)
@@ -508,5 +488,22 @@ namespace MediaBrowser.Controller.Entities.TV
return hasChanges;
}
+
+ public override List<ExternalUrl> GetRelatedUrls()
+ {
+ var list = base.GetRelatedUrls();
+
+ var imdbId = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(imdbId))
+ {
+ list.Add(new ExternalUrl
+ {
+ Name = "Trakt",
+ Url = string.Format("https://trakt.tv/shows/{0}", imdbId)
+ });
+ }
+
+ return list;
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasTags.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs
index 45a56009d..0e1df72cd 100644
--- a/MediaBrowser.Controller/Entities/IHasTags.cs
+++ b/MediaBrowser.Controller/Entities/TagExtensions.cs
@@ -1,24 +1,11 @@
using System;
-using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Entities
{
- /// <summary>
- /// Interface IHasTags
- /// </summary>
- public interface IHasTags
- {
- /// <summary>
- /// Gets or sets the tags.
- /// </summary>
- /// <value>The tags.</value>
- List<string> Tags { get; set; }
- }
-
public static class TagExtensions
{
- public static void AddTag(this IHasTags item, string name)
+ public static void AddTag(this BaseItem item, string name)
{
if (string.IsNullOrWhiteSpace(name))
{
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index 3be2fc624..eab5ab679 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -5,13 +5,14 @@ using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Class Trailer
/// </summary>
- public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
+ public class Trailer : Video, IHasCriticRating, IHasProductionLocations, IHasBudget, IHasTaglines, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
{
public List<string> ProductionLocations { get; set; }
@@ -30,8 +31,6 @@ namespace MediaBrowser.Controller.Entities
public List<MediaUrl> RemoteTrailers { get; set; }
- public List<string> Keywords { get; set; }
-
[IgnoreDataMember]
public bool IsLocalTrailer
{
@@ -110,5 +109,22 @@ namespace MediaBrowser.Controller.Entities
return hasChanges;
}
+
+ public override List<ExternalUrl> GetRelatedUrls()
+ {
+ var list = base.GetRelatedUrls();
+
+ var imdbId = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(imdbId))
+ {
+ list.Add(new ExternalUrl
+ {
+ Name = "Trakt",
+ Url = string.Format("https://trakt.tv/movies/{0}", imdbId)
+ });
+ }
+
+ return list;
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index 37c4c91b1..8e6f11c2c 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -38,6 +38,11 @@ namespace MediaBrowser.Controller.Entities
return PostFilterAndSort(result.Where(filter), query);
}
+ public override int GetChildCount(User user)
+ {
+ return GetChildren(user, true).Count();
+ }
+
[IgnoreDataMember]
protected override bool SupportsShortcutChildren
{
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index e40d9ca38..35375e7e6 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -45,6 +45,11 @@ namespace MediaBrowser.Controller.Entities
return list;
}
+ public override int GetChildCount(User user)
+ {
+ return GetChildren(user, true).Count();
+ }
+
protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query)
{
var parent = this as Folder;
@@ -58,7 +63,7 @@ namespace MediaBrowser.Controller.Entities
parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
}
- return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager, PlaylistManager)
+ return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager, PlaylistManager)
.GetUserItems(parent, this, ViewType, query);
}
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index d4a8b0730..0cb806274 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -18,6 +18,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Controller.Entities
{
@@ -30,10 +32,10 @@ namespace MediaBrowser.Controller.Entities
private readonly ILogger _logger;
private readonly IUserDataManager _userDataManager;
private readonly ITVSeriesManager _tvSeriesManager;
- private readonly ICollectionManager _collectionManager;
+ private readonly IServerConfigurationManager _config;
private readonly IPlaylistManager _playlistManager;
- public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager, IPlaylistManager playlistManager)
+ public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, IServerConfigurationManager config, IPlaylistManager playlistManager)
{
_userViewManager = userViewManager;
_liveTvManager = liveTvManager;
@@ -42,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
_logger = logger;
_userDataManager = userDataManager;
_tvSeriesManager = tvSeriesManager;
- _collectionManager = collectionManager;
+ _config = config;
_playlistManager = playlistManager;
}
@@ -159,7 +161,7 @@ namespace MediaBrowser.Controller.Entities
return await GetTvGenres(queryParent, user, query).ConfigureAwait(false);
case SpecialFolder.TvGenre:
- return await GetTvGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false);
+ return GetTvGenreItems(queryParent, displayParent, user, query);
case SpecialFolder.TvResume:
return GetTvResume(queryParent, user, query);
@@ -332,13 +334,14 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query)
{
- var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ var items = parent.QueryRecursive(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
- IncludeItemTypes = new[] { typeof(Audio.Audio).Name }
+ IncludeItemTypes = new[] { typeof(Audio.Audio).Name },
+ EnableTotalRecordCount = false
- }).Cast<IHasAlbumArtist>();
+ }).Items.Cast<IHasAlbumArtist>();
var artists = _libraryManager.GetAlbumArtists(items);
@@ -347,13 +350,14 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, InternalItemsQuery query)
{
- var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ var items = parent.QueryRecursive(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
- IncludeItemTypes = new[] { typeof(Audio.Audio).Name, typeof(MusicVideo).Name }
+ IncludeItemTypes = new[] { typeof(Audio.Audio).Name, typeof(MusicVideo).Name },
+ EnableTotalRecordCount = false
- }).Cast<IHasArtist>();
+ }).Items.Cast<IHasArtist>();
var artists = _libraryManager.GetArtists(items);
@@ -362,13 +366,14 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query)
{
- var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ var items = parent.QueryRecursive(new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parent.Id,
- IncludeItemTypes = new[] { typeof(Audio.Audio).Name }
+ IncludeItemTypes = new[] { typeof(Audio.Audio).Name },
+ EnableTotalRecordCount = false
- }).Cast<IHasAlbumArtist>();
+ }).Items.Cast<IHasAlbumArtist>();
var artists = _libraryManager.GetAlbumArtists(items).Where(i => _userDataManager.GetUserData(user, i).IsFavorite);
@@ -660,6 +665,7 @@ namespace MediaBrowser.Controller.Entities
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Episode).Name };
+ query.ExcludeLocationTypes = new[] { LocationType.Virtual };
return _libraryManager.GetItemsResult(query);
}
@@ -737,7 +743,7 @@ namespace MediaBrowser.Controller.Entities
return GetResult(genres, parent, query);
}
- private async Task<QueryResult<BaseItem>> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
+ private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
{
query.Recursive = true;
query.ParentId = queryParent.Id;
@@ -766,7 +772,7 @@ namespace MediaBrowser.Controller.Entities
{
items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
- return PostFilterAndSort(items, queryParent, null, query, _libraryManager);
+ return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config);
}
public static bool FilterItem(BaseItem item, InternalItemsQuery query)
@@ -779,14 +785,15 @@ namespace MediaBrowser.Controller.Entities
int? totalRecordLimit,
InternalItemsQuery query)
{
- return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager);
+ return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config);
}
public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items,
BaseItem queryParent,
int? totalRecordLimit,
InternalItemsQuery query,
- ILibraryManager libraryManager)
+ ILibraryManager libraryManager,
+ IServerConfigurationManager configurationManager)
{
var user = query.User;
@@ -795,7 +802,7 @@ namespace MediaBrowser.Controller.Entities
query.IsVirtualUnaired,
query.IsUnaired);
- items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user);
+ items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager);
// This must be the last filter
if (!string.IsNullOrEmpty(query.AdjacentTo))
@@ -809,14 +816,15 @@ namespace MediaBrowser.Controller.Entities
public static IEnumerable<BaseItem> CollapseBoxSetItemsIfNeeded(IEnumerable<BaseItem> items,
InternalItemsQuery query,
BaseItem queryParent,
- User user)
+ User user,
+ IServerConfigurationManager configurationManager)
{
if (items == null)
{
throw new ArgumentNullException("items");
}
- if (CollapseBoxSetItems(query, queryParent, user))
+ if (CollapseBoxSetItems(query, queryParent, user, configurationManager))
{
items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user);
}
@@ -849,7 +857,8 @@ namespace MediaBrowser.Controller.Entities
public static bool CollapseBoxSetItems(InternalItemsQuery query,
BaseItem queryParent,
- User user)
+ User user,
+ IServerConfigurationManager configurationManager)
{
// Could end up stuck in a loop like this
if (queryParent is BoxSet)
@@ -861,7 +870,7 @@ namespace MediaBrowser.Controller.Entities
if (!param.HasValue)
{
- if (user != null && !user.Configuration.GroupMoviesIntoBoxSets)
+ if (user != null && !configurationManager.Configuration.EnableGroupingIntoCollections)
{
return false;
}
@@ -992,11 +1001,6 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- if (request.IsYearMismatched.HasValue)
- {
- return false;
- }
-
if (!string.IsNullOrWhiteSpace(request.Person))
{
return false;
@@ -1415,16 +1419,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- if (query.IsYearMismatched.HasValue)
- {
- var filterValue = query.IsYearMismatched.Value;
-
- if (IsYearMismatched(item, libraryManager) != filterValue)
- {
- return false;
- }
- }
-
if (query.HasOfficialRating.HasValue)
{
var filterValue = query.HasOfficialRating.Value;
@@ -1658,12 +1652,7 @@ namespace MediaBrowser.Controller.Entities
var tags = query.Tags;
if (tags.Length > 0)
{
- var hasTags = item as IHasTags;
- if (hasTags == null)
- {
- return false;
- }
- if (!tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
+ if (!tags.Any(v => item.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
@@ -1976,34 +1965,6 @@ namespace MediaBrowser.Controller.Entities
return _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, sortName, CancellationToken.None);
}
- public static bool IsYearMismatched(BaseItem item, ILibraryManager libraryManager)
- {
- if (item.ProductionYear.HasValue)
- {
- var path = item.Path;
-
- if (!string.IsNullOrEmpty(path))
- {
- var info = libraryManager.ParseName(Path.GetFileName(path));
- var yearInName = info.Year;
-
- // Go up a level if we didn't get a year
- if (!yearInName.HasValue)
- {
- info = libraryManager.ParseName(Path.GetFileName(Path.GetDirectoryName(path)));
- yearInName = info.Year;
- }
-
- if (yearInName.HasValue)
- {
- return yearInName.Value != item.ProductionYear.Value;
- }
- }
- }
-
- return false;
- }
-
public static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
{
var list = items.ToList();
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 6a9d7cb51..2502033c8 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -21,7 +21,6 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Video : BaseItem,
IHasAspectRatio,
- IHasTags,
ISupportsPlaceHolders,
IHasMediaSources,
IHasShortOverview,
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 936b97c6e..1d0e06482 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -151,13 +151,6 @@ namespace MediaBrowser.Controller.Library
BaseItem GetItemById(Guid id);
/// <summary>
- /// Gets the memory item by identifier.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>BaseItem.</returns>
- BaseItem GetMemoryItemById(Guid id);
-
- /// <summary>
/// Gets the intros.
/// </summary>
/// <param name="item">The item.</param>
diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
index f5048bdda..5ecd70cc5 100644
--- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
+++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
@@ -15,5 +15,6 @@ namespace MediaBrowser.Controller.LiveTv
Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
+ Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index a4bd32fff..ffba3097c 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Querying;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Events;
namespace MediaBrowser.Controller.LiveTv
{
@@ -385,5 +386,15 @@ namespace MediaBrowser.Controller.LiveTv
List<NameValuePair> GetSatIniMappings();
Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken);
+
+ Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
+ Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
+
+ List<IListingsProvider> ListingProviders { get;}
+
+ event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
index 4ef4847a3..d7d8336d0 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
@@ -226,4 +226,23 @@ namespace MediaBrowser.Controller.LiveTv
/// <returns>Task.</returns>
Task ResetTuner(string id, CancellationToken cancellationToken);
}
+
+ public interface ISupportsNewTimerIds
+ {
+ /// <summary>
+ /// Creates the timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task<string> CreateTimer(TimerInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Creates the series timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken);
+ }
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index cc30709db..74c993248 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.LiveTv
{
@@ -235,5 +236,25 @@ namespace MediaBrowser.Controller.LiveTv
return false;
}
}
+
+ public override List<ExternalUrl> GetRelatedUrls()
+ {
+ var list = base.GetRelatedUrls();
+
+ var imdbId = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(imdbId))
+ {
+ if (IsMovie)
+ {
+ list.Add(new ExternalUrl
+ {
+ Name = "Trakt",
+ Url = string.Format("https://trakt.tv/movies/{0}", imdbId)
+ });
+ }
+ }
+
+ return list;
+ }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
new file mode 100644
index 000000000..0e1a05475
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class TimerEventInfo
+ {
+ public string Id { get; set; }
+ public string ProgramId { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index bc28ec015..9b4c35c41 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -142,7 +142,7 @@
<Compile Include="Entities\IHasDisplayOrder.cs" />
<Compile Include="Entities\IHasId.cs" />
<Compile Include="Entities\IHasImages.cs" />
- <Compile Include="Entities\IHasKeywords.cs" />
+ <Compile Include="Entities\KeywordExtensions.cs" />
<Compile Include="Entities\IHasMediaSources.cs" />
<Compile Include="Entities\IHasMetascore.cs" />
<Compile Include="Entities\IHasOriginalTitle.cs" />
@@ -154,7 +154,6 @@
<Compile Include="Entities\IHasSpecialFeatures.cs" />
<Compile Include="Entities\IHasStartDate.cs" />
<Compile Include="Entities\IHasTaglines.cs" />
- <Compile Include="Entities\IHasTags.cs" />
<Compile Include="Entities\IHasThemeMedia.cs" />
<Compile Include="Entities\IHasTrailers.cs" />
<Compile Include="Entities\IHasUserData.cs" />
@@ -177,6 +176,7 @@
<Compile Include="Entities\PhotoAlbum.cs" />
<Compile Include="Entities\Share.cs" />
<Compile Include="Entities\SourceType.cs" />
+ <Compile Include="Entities\TagExtensions.cs" />
<Compile Include="Entities\UserView.cs" />
<Compile Include="Entities\UserViewBuilder.cs" />
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
@@ -218,6 +218,7 @@
<Compile Include="LiveTv\ProgramInfo.cs" />
<Compile Include="LiveTv\RecordingInfo.cs" />
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
+ <Compile Include="LiveTv\TimerEventInfo.cs" />
<Compile Include="LiveTv\TimerInfo.cs" />
<Compile Include="Localization\ILocalizationManager.cs" />
<Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />
@@ -290,14 +291,11 @@
<Compile Include="Providers\IImageFileSaver.cs" />
<Compile Include="Providers\IImageProvider.cs" />
<Compile Include="Providers\IImageSaver.cs" />
- <Compile Include="Providers\IItemIdentityConverter.cs" />
- <Compile Include="Providers\IItemIdentityProvider.cs" />
<Compile Include="Providers\ILocalImageFileProvider.cs" />
<Compile Include="Providers\ILocalMetadataProvider.cs" />
<Compile Include="Providers\ImageRefreshMode.cs" />
<Compile Include="Providers\ImageRefreshOptions.cs" />
<Compile Include="Providers\IPreRefreshProvider.cs" />
- <Compile Include="Providers\IProviderRepository.cs" />
<Compile Include="Providers\IRemoteImageProvider.cs" />
<Compile Include="Providers\ILocalImageProvider.cs" />
<Compile Include="Providers\IMetadataProvider.cs" />
@@ -330,11 +328,8 @@
<Compile Include="Sorting\SortHelper.cs" />
<Compile Include="Subtitles\ISubtitleManager.cs" />
<Compile Include="Subtitles\ISubtitleProvider.cs" />
- <Compile Include="Providers\ItemIdentifier.cs" />
- <Compile Include="Providers\ItemIdentities.cs" />
<Compile Include="Providers\ItemLookupInfo.cs" />
<Compile Include="Providers\MetadataRefreshOptions.cs" />
- <Compile Include="Providers\MetadataStatus.cs" />
<Compile Include="Providers\ISeriesOrderManager.cs" />
<Compile Include="Session\ISessionManager.cs" />
<Compile Include="Entities\AggregateFolder.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
index e538b84d8..44489cbf5 100644
--- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
@@ -10,13 +10,6 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Gets the subtitles.
/// </summary>
- /// <param name="itemId">The item identifier.</param>
- /// <param name="mediaSourceId">The media source identifier.</param>
- /// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
- /// <param name="outputFormat">The output format.</param>
- /// <param name="startTimeTicks">The start time ticks.</param>
- /// <param name="endTimeTicks">The end time ticks.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Stream}.</returns>
Task<Stream> GetSubtitles(string itemId,
string mediaSourceId,
@@ -24,6 +17,7 @@ namespace MediaBrowser.Controller.MediaEncoding
string outputFormat,
long startTimeTicks,
long? endTimeTicks,
+ bool preserveOriginalTimestamps,
CancellationToken cancellationToken);
/// <summary>
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index 7bcc36958..80a6e4042 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="chapters">The chapters.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken);
+ Task SaveChapters(Guid id, List<ChapterInfo> chapters, CancellationToken cancellationToken);
/// <summary>
/// Gets the media streams.
@@ -97,7 +97,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="streams">The streams.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
+ Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken);
/// <summary>
/// Gets the item ids.
diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
index 2e165f416..ca4dc9751 100644
--- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
@@ -29,6 +29,8 @@ namespace MediaBrowser.Controller.Persistence
/// <returns>Task{UserItemData}.</returns>
UserItemData GetUserData(Guid userId, string key);
+ UserItemData GetUserData(Guid userId, List<string> keys);
+
/// <summary>
/// Return all user data associated with the given user
/// </summary>
diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
index 1014fc2ee..a783910e3 100644
--- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
+++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
@@ -803,11 +803,7 @@ namespace MediaBrowser.Controller.Providers
{
using (var subtree = reader.ReadSubtree())
{
- var hasTags = item as IHasTags;
- if (hasTags != null)
- {
- FetchFromTagsNode(subtree, hasTags);
- }
+ FetchFromTagsNode(subtree, item);
}
break;
}
@@ -816,11 +812,7 @@ namespace MediaBrowser.Controller.Providers
{
using (var subtree = reader.ReadSubtree())
{
- var hasTags = item as IHasKeywords;
- if (hasTags != null)
- {
- FetchFromKeywordsNode(subtree, hasTags);
- }
+ FetchFromKeywordsNode(subtree, item);
}
break;
}
@@ -1070,7 +1062,7 @@ namespace MediaBrowser.Controller.Providers
}
}
- private void FetchFromTagsNode(XmlReader reader, IHasTags item)
+ private void FetchFromTagsNode(XmlReader reader, BaseItem item)
{
reader.MoveToContent();
@@ -1099,7 +1091,7 @@ namespace MediaBrowser.Controller.Providers
}
}
- private void FetchFromKeywordsNode(XmlReader reader, IHasKeywords item)
+ private void FetchFromKeywordsNode(XmlReader reader, BaseItem item)
{
reader.MoveToContent();
diff --git a/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs b/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
deleted file mode 100644
index bfdd1dbf3..000000000
--- a/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public interface IItemIdentityConverter { }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs b/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
deleted file mode 100644
index 6b403bb55..000000000
--- a/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public interface IItemIdentityProvider { }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 57e4ff320..3eefa9647 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -97,13 +97,11 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="imageProviders">The image providers.</param>
/// <param name="metadataServices">The metadata services.</param>
- /// <param name="identityProviders">The identity providers.</param>
- /// <param name="identityConverters">The identity converters.</param>
/// <param name="metadataProviders">The metadata providers.</param>
/// <param name="savers">The savers.</param>
/// <param name="imageSavers">The image savers.</param>
/// <param name="externalIds">The external ids.</param>
- void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, IEnumerable<IItemIdentityProvider> identityProviders, IEnumerable<IItemIdentityConverter> identityConverters, IEnumerable<IMetadataProvider> metadataProviders,
+ void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, IEnumerable<IMetadataProvider> metadataProviders,
IEnumerable<IMetadataSaver> savers,
IEnumerable<IImageSaver> imageSavers,
IEnumerable<IExternalId> externalIds);
@@ -135,7 +133,7 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{ExternalUrl}.</returns>
- IEnumerable<ExternalUrl> GetExternalUrls(IHasProviderIds item);
+ IEnumerable<ExternalUrl> GetExternalUrls(BaseItem item);
/// <summary>
/// Gets the external identifier infos.
@@ -190,21 +188,5 @@ namespace MediaBrowser.Controller.Providers
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{HttpResponseInfo}.</returns>
Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken);
-
- /// <summary>
- /// Gets the item identity providers.
- /// </summary>
- /// <typeparam name="TLookupInfo">The type of the t lookup information.</typeparam>
- /// <returns>IEnumerable&lt;IItemIdentityProvider&lt;TLookupInfo, TIdentity&gt;&gt;.</returns>
- IEnumerable<IItemIdentityProvider<TLookupInfo>> GetItemIdentityProviders<TLookupInfo>()
- where TLookupInfo : ItemLookupInfo;
-
- /// <summary>
- /// Gets the item identity converters.
- /// </summary>
- /// <typeparam name="TLookupInfo">The type of the t lookup information.</typeparam>
- /// <returns>IEnumerable&lt;IItemIdentityConverter&lt;TIdentity&gt;&gt;.</returns>
- IEnumerable<IItemIdentityConverter<TLookupInfo>> GetItemIdentityConverters<TLookupInfo>()
- where TLookupInfo : ItemLookupInfo;
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IProviderRepository.cs b/MediaBrowser.Controller/Providers/IProviderRepository.cs
deleted file mode 100644
index 891275d77..000000000
--- a/MediaBrowser.Controller/Providers/IProviderRepository.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using MediaBrowser.Controller.Persistence;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
-{
- public interface IProviderRepository : IRepository
- {
- /// <summary>
- /// Gets the metadata status.
- /// </summary>
- /// <param name="itemId">The item identifier.</param>
- /// <returns>MetadataStatus.</returns>
- MetadataStatus GetMetadataStatus(Guid itemId);
-
- /// <summary>
- /// Saves the metadata status.
- /// </summary>
- /// <param name="status">The status.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SaveMetadataStatus(MetadataStatus status, CancellationToken cancellationToken);
- }
-}
diff --git a/MediaBrowser.Controller/Providers/ItemIdentifier.cs b/MediaBrowser.Controller/Providers/ItemIdentifier.cs
deleted file mode 100644
index bbc6dd76c..000000000
--- a/MediaBrowser.Controller/Providers/ItemIdentifier.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
-{
- public static class ItemIdentifier<TLookupInfo>
- where TLookupInfo : ItemLookupInfo
- {
- public static async Task FindIdentities(TLookupInfo item, IProviderManager providerManager, CancellationToken cancellationToken)
- {
- var providers = providerManager.GetItemIdentityProviders<TLookupInfo>();
- var converters = providerManager.GetItemIdentityConverters<TLookupInfo>().ToList();
-
- foreach (var provider in providers)
- {
- await provider.Identify(item);
- }
-
- bool changesMade = true;
-
- while (changesMade)
- {
- changesMade = false;
-
- foreach (var converter in converters)
- {
- if (await converter.Convert(item))
- {
- changesMade = true;
- }
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ItemIdentities.cs b/MediaBrowser.Controller/Providers/ItemIdentities.cs
deleted file mode 100644
index 48316d0f4..000000000
--- a/MediaBrowser.Controller/Providers/ItemIdentities.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
-{
- public interface IItemIdentityProvider<in TLookupInfo> : IItemIdentityProvider
- where TLookupInfo : ItemLookupInfo
- {
- Task Identify(TLookupInfo info);
- }
-
- public interface IItemIdentityConverter<in TLookupInfo> : IItemIdentityConverter
- where TLookupInfo : ItemLookupInfo
- {
- Task<bool> Convert(TLookupInfo info);
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs
index d16a73028..63cc48058 100644
--- a/MediaBrowser.Controller/Providers/ItemInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemInfo.cs
@@ -1,3 +1,4 @@
+using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
@@ -5,10 +6,6 @@ namespace MediaBrowser.Controller.Providers
{
public class ItemInfo
{
- public ItemInfo()
- {
- }
-
public ItemInfo(IHasMetadata item)
{
Path = item.Path;
@@ -21,8 +18,11 @@ namespace MediaBrowser.Controller.Providers
VideoType = video.VideoType;
IsPlaceHolder = video.IsPlaceHolder;
}
+
+ ItemType = item.GetType();
}
+ public Type ItemType { get; set; }
public string Path { get; set; }
public string ContainingFolderPath { get; set; }
public VideoType VideoType { get; set; }
diff --git a/MediaBrowser.Controller/Providers/MetadataStatus.cs b/MediaBrowser.Controller/Providers/MetadataStatus.cs
deleted file mode 100644
index b19377a68..000000000
--- a/MediaBrowser.Controller/Providers/MetadataStatus.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.Providers
-{
- public class MetadataStatus
- {
- /// <summary>
- /// Gets or sets the item identifier.
- /// </summary>
- /// <value>The item identifier.</value>
- public Guid ItemId { get; set; }
-
- /// <summary>
- /// Gets or sets the date last metadata refresh.
- /// </summary>
- /// <value>The date last metadata refresh.</value>
- public DateTime? DateLastMetadataRefresh { get; set; }
-
- /// <summary>
- /// Gets or sets the date last images refresh.
- /// </summary>
- /// <value>The date last images refresh.</value>
- public DateTime? DateLastImagesRefresh { get; set; }
-
- public DateTime? ItemDateModified { get; set; }
-
- public bool IsDirty { get; private set; }
-
- public void SetDateLastMetadataRefresh(DateTime? date)
- {
- if (date != DateLastMetadataRefresh)
- {
- IsDirty = true;
- }
-
- DateLastMetadataRefresh = date;
- }
-
- public void SetDateLastImagesRefresh(DateTime? date)
- {
- if (date != DateLastImagesRefresh)
- {
- IsDirty = true;
- }
-
- DateLastImagesRefresh = date;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index fa74c5749..6659d1553 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -315,9 +315,8 @@ namespace MediaBrowser.Controller.Session
/// <summary>
/// Revokes the user tokens.
/// </summary>
- /// <param name="userId">The user identifier.</param>
/// <returns>Task.</returns>
- Task RevokeUserTokens(string userId);
+ Task RevokeUserTokens(string userId, string currentAccessToken);
/// <summary>
/// Revokes the token.
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index af833a85c..77daebee2 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -1015,17 +1015,17 @@ namespace MediaBrowser.Dlna.Didl
int? width = null;
int? height = null;
- //try
- //{
- // var size = _imageProcessor.GetImageSize(imageInfo);
+ try
+ {
+ var size = _imageProcessor.GetImageSize(imageInfo);
- // width = Convert.ToInt32(size.Width);
- // height = Convert.ToInt32(size.Height);
- //}
- //catch
- //{
+ width = Convert.ToInt32(size.Width);
+ height = Convert.ToInt32(size.Height);
+ }
+ catch
+ {
- //}
+ }
var inputFormat = (Path.GetExtension(imageInfo.Path) ?? string.Empty)
.TrimStart('.')
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index bbb9bf6de..cd9a7b1f0 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -101,6 +101,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
var uri = new Uri(location);
+ _logger.Debug("Attempting to create PlayToController from location {0}", location);
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger).ConfigureAwait(false);
if (device.RendererCommands == null)
@@ -112,6 +113,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
+ _logger.Debug("Logging session activity from location {0}", location);
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
.ConfigureAwait(false);
diff --git a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
index 1b06e1d6a..c117d030f 100644
--- a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
@@ -21,8 +21,8 @@ namespace MediaBrowser.Dlna.Profiles
new HttpHeaderInfo
{
Name = "User-Agent",
- Value = @"SEC_",
- Match = HeaderMatchType.Substring
+ Value = @".*(SEC_HHP_\[TV\] [A-Z]{2}\d{2}J[A-Z]?\d{3,4})*.",
+ Match = HeaderMatchType.Regex
}
}
};
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
index b09c25afa..967538bdf 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
@@ -4,7 +4,7 @@
<Identification>
<ModelUrl>samsung.com</ModelUrl>
<Headers>
- <HttpHeaderInfo name="User-Agent" value="SEC_" match="Substring" />
+ <HttpHeaderInfo name="User-Agent" value=".*(SEC_HHP_\[TV\] [A-Z]{2}\d{2}J[A-Z]?\d{3,4})*." match="Regex" />
</Headers>
</Identification>
<Manufacturer>Emby</Manufacturer>
diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
index be81d21d2..2b3f53aeb 100644
--- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
+++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
@@ -593,36 +593,28 @@ namespace MediaBrowser.LocalMetadata.Savers
builder.Append("</Studios>");
}
- var hasTags = item as IHasTags;
- if (hasTags != null)
+ if (item.Tags.Count > 0)
{
- if (hasTags.Tags.Count > 0)
- {
- builder.Append("<Tags>");
-
- foreach (var tag in hasTags.Tags)
- {
- builder.Append("<Tag>" + SecurityElement.Escape(tag) + "</Tag>");
- }
+ builder.Append("<Tags>");
- builder.Append("</Tags>");
+ foreach (var tag in item.Tags)
+ {
+ builder.Append("<Tag>" + SecurityElement.Escape(tag) + "</Tag>");
}
+
+ builder.Append("</Tags>");
}
- var hasKeywords = item as IHasKeywords;
- if (hasKeywords != null)
+ if (item.Keywords.Count > 0)
{
- if (hasKeywords.Keywords.Count > 0)
- {
- builder.Append("<PlotKeywords>");
-
- foreach (var tag in hasKeywords.Keywords)
- {
- builder.Append("<PlotKeyword>" + SecurityElement.Escape(tag) + "</PlotKeyword>");
- }
+ builder.Append("<PlotKeywords>");
- builder.Append("</PlotKeywords>");
+ foreach (var tag in item.Keywords)
+ {
+ builder.Append("<PlotKeyword>" + SecurityElement.Escape(tag) + "</PlotKeyword>");
}
+
+ builder.Append("</PlotKeywords>");
}
var people = libraryManager.GetPeople(item);
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index d551d5c8c..dd227952e 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -73,11 +73,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
var commandLineArgs = GetCommandLineArguments(encodingJob);
- if (GetEncodingOptions().EnableDebugLogging)
- {
- commandLineArgs = "-loglevel debug " + commandLineArgs;
- }
-
var process = new Process
{
StartInfo = new ProcessStartInfo
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 1544a78b6..7fe7facdf 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -99,7 +99,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (videoRequest != null)
{
state.OutputVideoCodec = state.Options.VideoCodec;
- state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream);
+ state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream, state.OutputVideoCodec);
if (state.OutputVideoBitrate.HasValue)
{
@@ -396,7 +396,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return request.AudioChannels;
}
- private int? GetVideoBitrateParamValue(EncodingJobOptions request, MediaStream videoStream)
+ private int? GetVideoBitrateParamValue(EncodingJobOptions request, MediaStream videoStream, string outputVideoCodec)
{
var bitrate = request.VideoBitRate;
@@ -421,6 +421,18 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ if (bitrate.HasValue)
+ {
+ var inputVideoCodec = videoStream == null ? null : videoStream.Codec;
+ bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
+
+ // If a max bitrate was requested, don't let the scaled bitrate exceed it
+ if (request.VideoBitRate.HasValue)
+ {
+ bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
+ }
+ }
+
return bitrate;
}
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 44c69d4c1..44a0f264d 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -408,7 +408,9 @@ namespace MediaBrowser.MediaEncoding.Probing
Level = streamInfo.level,
Index = streamInfo.index,
PixelFormat = streamInfo.pix_fmt,
- NalLengthSize = streamInfo.nal_length_size
+ NalLengthSize = streamInfo.nal_length_size,
+ TimeBase = streamInfo.time_base,
+ CodecTimeBase = streamInfo.codec_time_base
};
if (string.Equals(streamInfo.is_avc, "true", StringComparison.OrdinalIgnoreCase) ||
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 8c33cc7c0..25adbcdb0 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -58,6 +58,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
string outputFormat,
long startTimeTicks,
long? endTimeTicks,
+ bool preserveOriginalTimestamps,
CancellationToken cancellationToken)
{
var ms = new MemoryStream();
@@ -68,7 +69,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var trackInfo = reader.Parse(stream, cancellationToken);
- FilterEvents(trackInfo, startTimeTicks, endTimeTicks, false);
+ FilterEvents(trackInfo, startTimeTicks, endTimeTicks, preserveOriginalTimestamps);
var writer = GetWriter(outputFormat);
@@ -116,6 +117,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
string outputFormat,
long startTimeTicks,
long? endTimeTicks,
+ bool preserveOriginalTimestamps,
CancellationToken cancellationToken)
{
var subtitle = await GetSubtitleStream(itemId, mediaSourceId, subtitleStreamIndex, cancellationToken)
@@ -130,7 +132,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
using (var stream = subtitle.Item1)
{
- return await ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, cancellationToken).ConfigureAwait(false);
+ return await ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index ba4d1b59e..f759ffeae 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -230,12 +230,6 @@
<Compile Include="..\MediaBrowser.Model\Configuration\SubtitlePlaybackMode.cs">
<Link>Configuration\SubtitlePlaybackMode.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Configuration\TheMovieDbOptions.cs">
- <Link>Configuration\TheMovieDbOptions.cs</Link>
- </Compile>
- <Compile Include="..\MediaBrowser.Model\Configuration\TvdbOptions.cs">
- <Link>Configuration\TvdbOptions.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Configuration\UnratedItem.cs">
<Link>Configuration\UnratedItem.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index f5d538cc4..05bbeb50e 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -204,12 +204,6 @@
<Compile Include="..\MediaBrowser.Model\Configuration\SubtitlePlaybackMode.cs">
<Link>Configuration\SubtitlePlaybackMode.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Configuration\TheMovieDbOptions.cs">
- <Link>Configuration\TheMovieDbOptions.cs</Link>
- </Compile>
- <Compile Include="..\MediaBrowser.Model\Configuration\TvdbOptions.cs">
- <Link>Configuration\TvdbOptions.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Configuration\UnratedItem.cs">
<Link>Configuration\UnratedItem.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/ApiClient/ServerCredentials.cs b/MediaBrowser.Model/ApiClient/ServerCredentials.cs
index 0f0ab65d4..19f68445e 100644
--- a/MediaBrowser.Model/ApiClient/ServerCredentials.cs
+++ b/MediaBrowser.Model/ApiClient/ServerCredentials.cs
@@ -57,6 +57,10 @@ namespace MediaBrowser.Model.ApiClient
{
existing.RemoteAddress = server.RemoteAddress;
}
+ if (!string.IsNullOrEmpty(server.ConnectServerId))
+ {
+ existing.ConnectServerId = server.ConnectServerId;
+ }
if (!string.IsNullOrEmpty(server.LocalAddress))
{
existing.LocalAddress = server.LocalAddress;
diff --git a/MediaBrowser.Model/ApiClient/ServerInfo.cs b/MediaBrowser.Model/ApiClient/ServerInfo.cs
index e1fa581d7..48995e80a 100644
--- a/MediaBrowser.Model/ApiClient/ServerInfo.cs
+++ b/MediaBrowser.Model/ApiClient/ServerInfo.cs
@@ -12,6 +12,7 @@ namespace MediaBrowser.Model.ApiClient
public String Name { get; set; }
public String Id { get; set; }
+ public String ConnectServerId { get; set; }
public String LocalAddress { get; set; }
public String RemoteAddress { get; set; }
public String ManualAddress { get; set; }
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index 516d00ee6..d33cf5577 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -6,7 +6,6 @@ namespace MediaBrowser.Model.Configuration
public int EncodingThreadCount { get; set; }
public string TranscodingTempPath { get; set; }
public double DownMixAudioBoost { get; set; }
- public bool EnableDebugLogging { get; set; }
public bool EnableThrottling { get; set; }
public int ThrottleDelaySeconds { get; set; }
public string HardwareAccelerationType { get; set; }
diff --git a/MediaBrowser.Model/Configuration/FanartOptions.cs b/MediaBrowser.Model/Configuration/FanartOptions.cs
index e992abe5d..6924b25d7 100644
--- a/MediaBrowser.Model/Configuration/FanartOptions.cs
+++ b/MediaBrowser.Model/Configuration/FanartOptions.cs
@@ -4,11 +4,6 @@ namespace MediaBrowser.Model.Configuration
public class FanartOptions
{
/// <summary>
- /// Gets or sets a value indicating whether [enable automatic updates].
- /// </summary>
- /// <value><c>true</c> if [enable automatic updates]; otherwise, <c>false</c>.</value>
- public bool EnableAutomaticUpdates { get; set; }
- /// <summary>
/// Gets or sets the user API key.
/// </summary>
/// <value>The user API key.</value>
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 1cb19afdf..e4c17ff2b 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary>
/// <value><c>true</c> if [enable case sensitive item ids]; otherwise, <c>false</c>.</value>
public bool EnableCaseSensitiveItemIds { get; set; }
-
+
/// <summary>
/// Gets or sets the metadata path.
/// </summary>
@@ -87,12 +87,6 @@ namespace MediaBrowser.Model.Configuration
public bool SaveLocalMeta { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether [enable localized guids].
- /// </summary>
- /// <value><c>true</c> if [enable localized guids]; otherwise, <c>false</c>.</value>
- public bool EnableLocalizedGuids { get; set; }
-
- /// <summary>
/// Gets or sets the preferred metadata language.
/// </summary>
/// <value>The preferred metadata language.</value>
@@ -161,7 +155,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary>
/// <value>The dashboard source path.</value>
public string DashboardSourcePath { get; set; }
-
+
/// <summary>
/// Gets or sets the image saving convention.
/// </summary>
@@ -190,14 +184,10 @@ namespace MediaBrowser.Model.Configuration
public bool EnableVideoArchiveFiles { get; set; }
public int RemoteClientBitrateLimit { get; set; }
- public bool DenyIFrameEmbedding { get; set; }
-
public AutoOnOff EnableLibraryMonitor { get; set; }
public int SharingExpirationDays { get; set; }
- public bool EnableDateLastRefresh { get; set; }
-
public string[] Migrations { get; set; }
public int MigrationVersion { get; set; }
@@ -207,16 +197,24 @@ namespace MediaBrowser.Model.Configuration
public bool EnableAnonymousUsageReporting { get; set; }
public bool EnableStandaloneMusicKeys { get; set; }
+ public bool EnableLocalizedGuids { get; set; }
+ public bool EnableFolderView { get; set; }
+ public bool EnableGroupingIntoCollections { get; set; }
+ public bool DisplaySpecialsWithinSeasons { get; set; }
+ public bool DisplayCollectionsView { get; set; }
+ public string[] LocalNetworkAddresses { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
public ServerConfiguration()
{
+ LocalNetworkAddresses = new string[] { };
Migrations = new string[] { };
- EnableLocalizedGuids = true;
EnableCustomPathSubFolders = true;
+ EnableLocalizedGuids = true;
+ DisplaySpecialsWithinSeasons = true;
ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096;
@@ -229,10 +227,8 @@ namespace MediaBrowser.Model.Configuration
EnableAnonymousUsageReporting = true;
EnableAutomaticRestart = true;
- DenyIFrameEmbedding = true;
EnableUPnP = true;
-
SharingExpirationDays = 30;
MinResumePct = 5;
MaxResumePct = 90;
diff --git a/MediaBrowser.Model/Configuration/TheMovieDbOptions.cs b/MediaBrowser.Model/Configuration/TheMovieDbOptions.cs
deleted file mode 100644
index 9a73e3476..000000000
--- a/MediaBrowser.Model/Configuration/TheMovieDbOptions.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-
-namespace MediaBrowser.Model.Configuration
-{
- public class TheMovieDbOptions
- {
- /// <summary>
- /// Gets or sets a value indicating whether [enable automatic updates].
- /// </summary>
- /// <value><c>true</c> if [enable automatic updates]; otherwise, <c>false</c>.</value>
- public bool EnableAutomaticUpdates { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Configuration/TvdbOptions.cs b/MediaBrowser.Model/Configuration/TvdbOptions.cs
deleted file mode 100644
index 034af609c..000000000
--- a/MediaBrowser.Model/Configuration/TvdbOptions.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-
-namespace MediaBrowser.Model.Configuration
-{
- public class TvdbOptions
- {
- /// <summary>
- /// Gets or sets a value indicating whether [enable automatic updates].
- /// </summary>
- /// <value><c>true</c> if [enable automatic updates]; otherwise, <c>false</c>.</value>
- public bool EnableAutomaticUpdates { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index 5f42dd2de..69dc23b21 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -34,14 +34,11 @@ namespace MediaBrowser.Model.Configuration
public SubtitlePlaybackMode SubtitleMode { get; set; }
public bool DisplayCollectionsView { get; set; }
- public bool DisplayFoldersView { get; set; }
public bool EnableLocalPassword { get; set; }
public string[] OrderedViews { get; set; }
- public bool IncludeTrailersInSuggestions { get; set; }
-
public string[] LatestItemsExcludes { get; set; }
public string[] PlainFolderViews { get; set; }
@@ -51,7 +48,8 @@ namespace MediaBrowser.Model.Configuration
public bool RememberAudioSelections { get; set; }
public bool RememberSubtitleSelections { get; set; }
public bool EnableNextEpisodeAutoPlay { get; set; }
-
+ public bool DisplayFoldersView { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.
/// </summary>
@@ -69,8 +67,6 @@ namespace MediaBrowser.Model.Configuration
PlainFolderViews = new string[] { };
- IncludeTrailersInSuggestions = true;
-
GroupedFolders = new string[] { };
}
}
diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
index 8a412ac2c..ed18fed65 100644
--- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
+++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
@@ -56,5 +56,25 @@ namespace MediaBrowser.Model.Dlna
MaxHeight = maxHeight
};
}
+
+ private static double GetVideoBitrateScaleFactor(string codec)
+ {
+ if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
+ {
+ return .5;
+ }
+ return 1;
+ }
+
+ public static int ScaleBitrate(int bitrate, string inputVideoCodec, string outputVideoCodec)
+ {
+ var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec);
+ var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec);
+ var scaleFactor = outputScaleFactor/inputScaleFactor;
+ var newBitrate = scaleFactor*bitrate;
+
+ return Convert.ToInt32(newBitrate);
+ }
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 313c30e2c..d35eb37a8 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -335,7 +335,8 @@ namespace MediaBrowser.Model.Dlna
Name = stream.Language ?? "Unknown",
Format = subtitleProfile.Format,
Index = stream.Index,
- DeliveryMethod = subtitleProfile.Method
+ DeliveryMethod = subtitleProfile.Method,
+ DisplayTitle = stream.DisplayTitle
};
if (info.DeliveryMethod == SubtitleDeliveryMethod.External)
diff --git a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs
index 61b2895fc..7a89308dc 100644
--- a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs
@@ -7,6 +7,7 @@ namespace MediaBrowser.Model.Dlna
public string Name { get; set; }
public bool IsForced { get; set; }
public string Format { get; set; }
+ public string DisplayTitle { get; set; }
public int Index { get; set; }
public SubtitleDeliveryMethod DeliveryMethod { get; set; }
public bool IsExternalUrl { get; set; }
diff --git a/MediaBrowser.Model/Entities/ImageType.cs b/MediaBrowser.Model/Entities/ImageType.cs
index 18097abb4..6e0ba717f 100644
--- a/MediaBrowser.Model/Entities/ImageType.cs
+++ b/MediaBrowser.Model/Entities/ImageType.cs
@@ -9,50 +9,50 @@ namespace MediaBrowser.Model.Entities
/// <summary>
/// The primary
/// </summary>
- Primary,
+ Primary = 0,
/// <summary>
/// The art
/// </summary>
- Art,
+ Art = 1,
/// <summary>
/// The backdrop
/// </summary>
- Backdrop,
+ Backdrop = 2,
/// <summary>
/// The banner
/// </summary>
- Banner,
+ Banner = 3,
/// <summary>
/// The logo
/// </summary>
- Logo,
+ Logo = 4,
/// <summary>
/// The thumb
/// </summary>
- Thumb,
+ Thumb = 5,
/// <summary>
/// The disc
/// </summary>
- Disc,
+ Disc = 6,
/// <summary>
/// The box
/// </summary>
- Box,
+ Box = 7,
/// <summary>
/// The screenshot
/// </summary>
- Screenshot,
+ Screenshot = 8,
/// <summary>
/// The menu
/// </summary>
- Menu,
+ Menu = 9,
/// <summary>
/// The chapter image
/// </summary>
- Chapter,
+ Chapter = 10,
/// <summary>
/// The box rear
/// </summary>
- BoxRear
+ BoxRear = 11
}
}
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 64c7d9aa6..868f6b64f 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -36,6 +36,9 @@ namespace MediaBrowser.Model.Entities
/// <value>The comment.</value>
public string Comment { get; set; }
+ public string TimeBase { get; set; }
+ public string CodecTimeBase { get; set; }
+
public string Title { get; set; }
public string DisplayTitle
@@ -89,7 +92,7 @@ namespace MediaBrowser.Model.Entities
if (!string.IsNullOrEmpty(Language))
{
- attributes.Add(Language);
+ attributes.Add(StringHelper.FirstToUpper(Language));
}
if (!string.IsNullOrEmpty(Codec))
{
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index e00443d19..242a2d24e 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -1,4 +1,6 @@
using System.Collections.Generic;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.LiveTv
{
@@ -73,11 +75,33 @@ namespace MediaBrowser.Model.LiveTv
public string[] EnabledTuners { get; set; }
public bool EnableAllTuners { get; set; }
+ public string[] NewsCategories { get; set; }
+ public string[] SportsCategories { get; set; }
+ public string[] KidsCategories { get; set; }
+ public string[] MovieCategories { get; set; }
+ public NameValuePair[] ChannelMappings { get; set; }
public ListingsProviderInfo()
{
+ NewsCategories = new string[] { "news", "journalism", "documentary", "current affairs" };
+ SportsCategories = new string[] { "sports", "basketball", "baseball", "football" };
+ KidsCategories = new string[] { "kids", "family", "children", "childrens", "disney" };
+ MovieCategories = new string[] { "movie" };
EnabledTuners = new string[] { };
EnableAllTuners = true;
+ ChannelMappings = new NameValuePair[] {};
+ }
+
+ public string GetMappedChannel(string channelNumber)
+ {
+ foreach (NameValuePair mapping in ChannelMappings)
+ {
+ if (StringHelper.EqualsIgnoreCase(mapping.Name, channelNumber))
+ {
+ return mapping.Value;
+ }
+ }
+ return channelNumber;
}
}
}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 7c469b9fb..522b7d38d 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -97,8 +97,6 @@
<Compile Include="Configuration\FanartOptions.cs" />
<Compile Include="Configuration\MetadataConfiguration.cs" />
<Compile Include="Configuration\PeopleMetadataOptions.cs" />
- <Compile Include="Configuration\TheMovieDbOptions.cs" />
- <Compile Include="Configuration\TvdbOptions.cs" />
<Compile Include="Configuration\XbmcMetadataOptions.cs" />
<Compile Include="Configuration\SubtitlePlaybackMode.cs" />
<Compile Include="Connect\ConnectAuthenticationExchangeResult.cs" />
diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs
index 9c2926b54..6f4ebd0c5 100644
--- a/MediaBrowser.Model/Querying/ItemSortBy.cs
+++ b/MediaBrowser.Model/Querying/ItemSortBy.cs
@@ -85,5 +85,6 @@ namespace MediaBrowser.Model.Querying
public const string GameSystem = "GameSystem";
public const string IsFavoriteOrLiked = "IsFavoriteOrLiked";
public const string DateLastContentAdded = "DateLastContentAdded";
+ public const string SeriesDatePlayed = "SeriesDatePlayed";
}
}
diff --git a/MediaBrowser.Providers/Books/BookMetadataService.cs b/MediaBrowser.Providers/Books/BookMetadataService.cs
index eb3335c9a..6f4a744c2 100644
--- a/MediaBrowser.Providers/Books/BookMetadataService.cs
+++ b/MediaBrowser.Providers/Books/BookMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Books
{
public class BookMetadataService : MetadataService<Book, BookInfo>
{
- public BookMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<Book> source, MetadataResult<Book> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -25,5 +21,9 @@ namespace MediaBrowser.Providers.Books
target.Item.SeriesName = source.Item.SeriesName;
}
}
+
+ public BookMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
index 9a2488781..2dacb16ca 100644
--- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
+++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
@@ -15,10 +15,6 @@ namespace MediaBrowser.Providers.BoxSets
{
public class BoxSetMetadataService : MetadataService<BoxSet, BoxSetInfo>
{
- public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override async Task<ItemUpdateType> BeforeSave(BoxSet item, bool isFullRefresh, ItemUpdateType currentUpdateType)
{
var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false);
@@ -54,5 +50,9 @@ namespace MediaBrowser.Providers.BoxSets
targetItem.Shares = sourceItem.Shares;
}
}
+
+ public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
index 3a1d2374c..22e196d72 100644
--- a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
+++ b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Channels
{
public class ChannelMetadataService : MetadataService<Channel, ItemLookupInfo>
{
- public ChannelMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<Channel> source, MetadataResult<Channel> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<Channel> source, MetadataResult<Channel> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public ChannelMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Chapters/ChapterManager.cs b/MediaBrowser.Providers/Chapters/ChapterManager.cs
index 6e2cd77eb..88811c850 100644
--- a/MediaBrowser.Providers/Chapters/ChapterManager.cs
+++ b/MediaBrowser.Providers/Chapters/ChapterManager.cs
@@ -259,7 +259,7 @@ namespace MediaBrowser.Providers.Chapters
return _itemRepo.GetChapters(new Guid(itemId));
}
- public Task SaveChapters(string itemId, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken)
+ public Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken)
{
return _itemRepo.SaveChapters(new Guid(itemId), chapters, cancellationToken);
}
diff --git a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
index e1de443de..35c61b5c5 100644
--- a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
@@ -16,14 +16,13 @@ namespace MediaBrowser.Providers.Folders
{
public class CollectionFolderMetadataService : MetadataService<CollectionFolder, ItemLookupInfo>
{
- public CollectionFolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager)
- : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<CollectionFolder> source, MetadataResult<CollectionFolder> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<CollectionFolder> source, MetadataResult<CollectionFolder> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public CollectionFolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
deleted file mode 100644
index 08b4f6461..000000000
--- a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Providers;
-using MediaBrowser.Providers.Genres;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Providers.Folders
-{
- public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor
- {
- private readonly IHttpClient _httpClient;
-
- public DefaultImageProvider(IHttpClient httpClient)
- {
- _httpClient = httpClient;
- }
-
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
- {
- return new List<ImageType>
- {
- ImageType.Primary
- };
- }
-
- public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
- {
- var view = item as UserView;
-
- if (view != null)
- {
- return GetImages(view.ViewType, cancellationToken);
- }
-
- var folder = (ICollectionFolder)item;
- return GetImages(folder.CollectionType, cancellationToken);
- }
-
- private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, CancellationToken cancellationToken)
- {
- var url = GetImageUrl(viewType);
-
- var list = new List<RemoteImageInfo>();
-
- if (!string.IsNullOrWhiteSpace(url))
- {
- list.AddRange(new List<RemoteImageInfo>{
- new RemoteImageInfo
- {
- ProviderName = Name,
- Url = url,
- Type = ImageType.Primary
- }
- });
- }
-
- return Task.FromResult<IEnumerable<RemoteImageInfo>>(list);
- }
-
- private string GetImageUrl(string viewType)
- {
- const string urlPrefix = "https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/images/folders/";
-
- if (string.Equals(viewType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
- {
- return urlPrefix + "books.jpg";
- }
- if (string.Equals(viewType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
- {
- return urlPrefix + "games.jpg";
- }
- if (string.Equals(viewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
- {
- //return urlPrefix + "music.jpg";
- }
- if (string.Equals(viewType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- //return urlPrefix + "photos.png";
- }
- if (string.Equals(viewType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- //return urlPrefix + "tv.jpg";
- }
- if (string.Equals(viewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase))
- {
- return urlPrefix + "channels.jpg";
- }
- if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
- {
- return urlPrefix + "livetv.png";
- }
- if (string.Equals(viewType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- //return urlPrefix + "movies.jpg";
- }
- if (string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
- {
- return urlPrefix + "playlists.jpg";
- }
- if (string.Equals(viewType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
- {
- //return urlPrefix + "homevideos.jpg";
- }
- if (string.Equals(viewType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
- {
- return urlPrefix + "musicvideos.jpg";
- }
- if (string.Equals(viewType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
- {
- //return urlPrefix + "collections.jpg";
- }
- if (string.IsNullOrWhiteSpace(viewType))
- {
- //return urlPrefix + "generic.jpg";
- }
-
- return null;
- }
-
- public string Name
- {
- get { return "Default Image Provider"; }
- }
-
- public bool Supports(IHasImages item)
- {
- var view = item as UserView;
-
- if (view != null)
- {
- return !string.IsNullOrWhiteSpace(GetImageUrl(view.ViewType));
- }
-
- var folder = item as ICollectionFolder;
-
- if (folder != null)
- {
- return !string.IsNullOrWhiteSpace(GetImageUrl(folder.CollectionType));
- }
-
- return false;
- }
-
- public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
- {
- return _httpClient.GetResponse(new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = url,
- ResourcePool = GenreImageProvider.ImageDownloadResourcePool
- });
- }
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- return GetSupportedImages(item).Any(i => !item.HasImage(i));
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Providers/Folders/FolderMetadataService.cs b/MediaBrowser.Providers/Folders/FolderMetadataService.cs
index e938297b7..8c4737fc4 100644
--- a/MediaBrowser.Providers/Folders/FolderMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/FolderMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Folders
{
public class FolderMetadataService : MetadataService<Folder, ItemLookupInfo>
{
- public FolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
public override int Order
{
get
@@ -29,5 +25,9 @@ namespace MediaBrowser.Providers.Folders
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
+
+ public FolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
index 7c298a3ed..b8f58307a 100644
--- a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Folders
{
public class UserViewMetadataService : MetadataService<UserView, ItemLookupInfo>
{
- public UserViewMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<UserView> source, MetadataResult<UserView> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<UserView> source, MetadataResult<UserView> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public UserViewMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
index f80691d72..fb2244e32 100644
--- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
+++ b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.GameGenres
{
public class GameGenreMetadataService : MetadataService<GameGenre, ItemLookupInfo>
{
- public GameGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<GameGenre> source, MetadataResult<GameGenre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<GameGenre> source, MetadataResult<GameGenre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public GameGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Games/GameMetadataService.cs b/MediaBrowser.Providers/Games/GameMetadataService.cs
index 23284b84e..a44f1d95f 100644
--- a/MediaBrowser.Providers/Games/GameMetadataService.cs
+++ b/MediaBrowser.Providers/Games/GameMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Games
{
public class GameMetadataService : MetadataService<Game, GameInfo>
{
- public GameMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<Game> source, MetadataResult<Game> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -33,5 +29,9 @@ namespace MediaBrowser.Providers.Games
targetItem.PlayersSupported = sourceItem.PlayersSupported;
}
}
+
+ public GameMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
index a70b5c7fe..6cf2a45a4 100644
--- a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
+++ b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Games
{
public class GameSystemMetadataService : MetadataService<GameSystem, GameSystemInfo>
{
- public GameSystemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<GameSystem> source, MetadataResult<GameSystem> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -28,5 +24,9 @@ namespace MediaBrowser.Providers.Games
targetItem.GameSystemName = sourceItem.GameSystemName;
}
}
+
+ public GameSystemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs
index 7aba931a2..d4ea3e9cf 100644
--- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs
+++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Genres
{
public class GenreMetadataService : MetadataService<Genre, ItemLookupInfo>
{
- public GenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<Genre> source, MetadataResult<Genre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<Genre> source, MetadataResult<Genre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public GenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
index 4ccbb9116..1d99a678b 100644
--- a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
+++ b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.LiveTv
{
public class AudioRecordingService : MetadataService<LiveTvAudioRecording, ItemLookupInfo>
{
- public AudioRecordingService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<LiveTvAudioRecording> source, MetadataResult<LiveTvAudioRecording> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<LiveTvAudioRecording> source, MetadataResult<LiveTvAudioRecording> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public AudioRecordingService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
index 0b9b18bbc..8abb99689 100644
--- a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
+++ b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.LiveTv
{
public class ChannelMetadataService : MetadataService<LiveTvChannel, ItemLookupInfo>
{
- public ChannelMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<LiveTvChannel> source, MetadataResult<LiveTvChannel> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<LiveTvChannel> source, MetadataResult<LiveTvChannel> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public ChannelMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
index 0bf4a1b37..b73d82c19 100644
--- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
+++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.LiveTv
{
public class ProgramMetadataService : MetadataService<LiveTvProgram, LiveTvProgramLookupInfo>
{
- public ProgramMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<LiveTvProgram> source, MetadataResult<LiveTvProgram> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<LiveTvProgram> source, MetadataResult<LiveTvProgram> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public ProgramMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
index 47ac546a2..15530f8f9 100644
--- a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
+++ b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.LiveTv
{
public class VideoRecordingService : MetadataService<LiveTvVideoRecording, ItemLookupInfo>
{
- public VideoRecordingService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<LiveTvVideoRecording> source, MetadataResult<LiveTvVideoRecording> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<LiveTvVideoRecording> source, MetadataResult<LiveTvVideoRecording> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public VideoRecordingService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 7184302f1..678d495cb 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -12,11 +11,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Providers.Manager
@@ -28,95 +22,26 @@ namespace MediaBrowser.Providers.Manager
protected readonly IServerConfigurationManager ServerConfigurationManager;
protected readonly ILogger Logger;
protected readonly IProviderManager ProviderManager;
- protected readonly IProviderRepository ProviderRepo;
protected readonly IFileSystem FileSystem;
protected readonly IUserDataManager UserDataManager;
protected readonly ILibraryManager LibraryManager;
- protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager)
+ protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager)
{
ServerConfigurationManager = serverConfigurationManager;
Logger = logger;
ProviderManager = providerManager;
- ProviderRepo = providerRepo;
FileSystem = fileSystem;
UserDataManager = userDataManager;
LibraryManager = libraryManager;
}
- /// <summary>
- /// Saves the provider result.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="result">The result.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <returns>Task.</returns>
- protected Task SaveProviderResult(TItemType item, MetadataStatus result, IDirectoryService directoryService)
- {
- result.ItemId = item.Id;
-
- //var locationType = item.LocationType;
-
- //if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
- //{
- // if (!string.IsNullOrWhiteSpace(item.Path))
- // {
- // var file = directoryService.GetFile(item.Path);
-
- // if ((file.Attributes & FileAttributes.Directory) != FileAttributes.Directory && file.Exists)
- // {
- // result.ItemDateModified = FileSystem.GetLastWriteTimeUtc(file);
- // }
- // }
- //}
-
- result.ItemDateModified = item.DateModified;
-
- if (EnableDateLastRefreshed(item))
- {
- return Task.FromResult(true);
- }
-
- return ProviderRepo.SaveMetadataStatus(result, CancellationToken.None);
- }
-
- /// <summary>
- /// Gets the last result.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>ProviderResult.</returns>
- protected MetadataStatus GetLastResult(IHasMetadata item)
- {
- if (GetLastRefreshDate(item) == default(DateTime))
- {
- return new MetadataStatus { ItemId = item.Id };
- }
-
- if (EnableDateLastRefreshed(item) && item.DateModifiedDuringLastRefresh.HasValue)
- {
- return new MetadataStatus
- {
- ItemId = item.Id,
- DateLastImagesRefresh = item.DateLastRefreshed,
- DateLastMetadataRefresh = item.DateLastRefreshed,
- ItemDateModified = item.DateModifiedDuringLastRefresh.Value
- };
- }
-
- var result = ProviderRepo.GetMetadataStatus(item.Id) ?? new MetadataStatus { ItemId = item.Id };
-
- item.DateModifiedDuringLastRefresh = result.ItemDateModified;
-
- return result;
- }
-
public async Task<ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
{
var itemOfType = (TItemType)item;
var config = ProviderManager.GetMetadataOptions(item);
var updateType = ItemUpdateType.None;
- var refreshResult = GetLastResult(item);
var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem);
var localImagesFailed = false;
@@ -153,12 +78,10 @@ namespace MediaBrowser.Providers.Manager
// TODO: If this returns true, should we instead just change metadata refresh mode to Full?
requiresRefresh = item.RequiresRefresh();
- var providers = GetProviders(item, refreshResult, refreshOptions, requiresRefresh)
+ var providers = GetProviders(item, refreshOptions, requiresRefresh)
.ToList();
- var dateLastRefresh = EnableDateLastRefreshed(item)
- ? item.DateLastRefreshed
- : refreshResult.DateLastMetadataRefresh ?? default(DateTime);
+ var dateLastRefresh = item.DateLastRefreshed;
if (providers.Count > 0 || dateLastRefresh == default(DateTime))
{
@@ -185,13 +108,11 @@ namespace MediaBrowser.Providers.Manager
updateType = updateType | result.UpdateType;
if (result.Failures == 0)
{
- refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow);
hasRefreshedMetadata = true;
}
else
{
hasRefreshedMetadata = false;
- refreshResult.SetDateLastMetadataRefresh(null);
}
}
}
@@ -199,7 +120,7 @@ namespace MediaBrowser.Providers.Manager
// Next run remote image providers, but only if local image providers didn't throw an exception
if (!localImagesFailed && refreshOptions.ImageRefreshMode != ImageRefreshMode.ValidationOnly)
{
- var providers = GetNonLocalImageProviders(item, allImageProviders, refreshResult, refreshOptions).ToList();
+ var providers = GetNonLocalImageProviders(item, allImageProviders, refreshOptions).ToList();
if (providers.Count > 0)
{
@@ -208,13 +129,11 @@ namespace MediaBrowser.Providers.Manager
updateType = updateType | result.UpdateType;
if (result.Failures == 0)
{
- refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow);
hasRefreshedImages = true;
}
else
{
hasRefreshedImages = false;
- refreshResult.SetDateLastImagesRefresh(null);
}
}
}
@@ -248,11 +167,6 @@ namespace MediaBrowser.Providers.Manager
await SaveItem(metadataResult, updateType, cancellationToken).ConfigureAwait(false);
}
- if (updateType > ItemUpdateType.None || refreshResult.IsDirty)
- {
- await SaveProviderResult(itemOfType, refreshResult, refreshOptions.DirectoryService).ConfigureAwait(false);
- }
-
await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false);
return updateType;
@@ -265,61 +179,9 @@ namespace MediaBrowser.Providers.Manager
lookupInfo.Year = result.ProductionYear;
}
- private async Task FindIdentities(TIdType id, CancellationToken cancellationToken)
- {
- try
- {
- await ItemIdentifier<TIdType>.FindIdentities(id, ProviderManager, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error in FindIdentities", ex);
- }
- }
-
private DateTime GetLastRefreshDate(IHasMetadata item)
{
- if (EnableDateLastRefreshed(item))
- {
- return item.DateLastRefreshed;
- }
-
- return item.DateLastSaved;
- }
-
- private bool EnableDateLastRefreshed(IHasMetadata item)
- {
- if (ServerConfigurationManager.Configuration.EnableDateLastRefresh)
- {
- return true;
- }
-
- if (item.DateLastRefreshed != default(DateTime))
- {
- return true;
- }
-
- if (!(item is Audio) && !(item is Video))
- {
- return true;
- }
-
- if (item is IItemByName)
- {
- return true;
- }
-
- if (item.SourceType != SourceType.Library)
- {
- return true;
- }
-
- if (item is MusicVideo)
- {
- return true;
- }
-
- return false;
+ return item.DateLastRefreshed;
}
protected async Task SaveItem(MetadataResult<TItemType> result, ItemUpdateType reason, CancellationToken cancellationToken)
@@ -466,14 +328,12 @@ namespace MediaBrowser.Providers.Manager
/// Gets the providers.
/// </summary>
/// <returns>IEnumerable{`0}.</returns>
- protected IEnumerable<IMetadataProvider> GetProviders(IHasMetadata item, MetadataStatus status, MetadataRefreshOptions options, bool requiresRefresh)
+ protected IEnumerable<IMetadataProvider> GetProviders(IHasMetadata item, MetadataRefreshOptions options, bool requiresRefresh)
{
// Get providers to refresh
var providers = ((ProviderManager)ProviderManager).GetMetadataProviders<TItemType>(item).ToList();
- var dateLastRefresh = EnableDateLastRefreshed(item)
- ? item.DateLastRefreshed
- : status.DateLastMetadataRefresh ?? default(DateTime);
+ var dateLastRefresh = item.DateLastRefreshed;
// Run all if either of these flags are true
var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || requiresRefresh;
@@ -535,14 +395,12 @@ namespace MediaBrowser.Providers.Manager
return providers;
}
- protected virtual IEnumerable<IImageProvider> GetNonLocalImageProviders(IHasMetadata item, IEnumerable<IImageProvider> allImageProviders, MetadataStatus status, ImageRefreshOptions options)
+ protected virtual IEnumerable<IImageProvider> GetNonLocalImageProviders(IHasMetadata item, IEnumerable<IImageProvider> allImageProviders, ImageRefreshOptions options)
{
// Get providers to refresh
var providers = allImageProviders.Where(i => !(i is ILocalImageProvider)).ToList();
- var dateLastImageRefresh = EnableDateLastRefreshed(item)
- ? item.DateLastRefreshed
- : status.DateLastImagesRefresh ?? default(DateTime);
+ var dateLastImageRefresh = item.DateLastRefreshed;
// Run all if either of these flags are true
var runAllProviders = options.ImageRefreshMode == ImageRefreshMode.FullRefresh || dateLastImageRefresh == default(DateTime);
@@ -552,12 +410,6 @@ namespace MediaBrowser.Providers.Manager
providers = providers
.Where(i =>
{
- var hasChangeMonitor = i as IHasChangeMonitor;
- if (hasChangeMonitor != null)
- {
- return HasChanged(item, hasChangeMonitor, dateLastImageRefresh, options.DirectoryService);
- }
-
var hasFileChangeMonitor = i as IHasItemChangeMonitor;
if (hasFileChangeMonitor != null)
{
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index c95d58a42..0f0745d1b 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -55,8 +55,6 @@ namespace MediaBrowser.Providers.Manager
private readonly IFileSystem _fileSystem;
private IMetadataService[] _metadataServices = { };
- private IItemIdentityProvider[] _identityProviders = { };
- private IItemIdentityConverter[] _identityConverters = { };
private IMetadataProvider[] _metadataProviders = { };
private IEnumerable<IMetadataSaver> _savers;
private IImageSaver[] _imageSavers;
@@ -92,22 +90,17 @@ namespace MediaBrowser.Providers.Manager
/// </summary>
/// <param name="imageProviders">The image providers.</param>
/// <param name="metadataServices">The metadata services.</param>
- /// <param name="identityProviders">The identity providers.</param>
- /// <param name="identityConverters">The identity converters.</param>
/// <param name="metadataProviders">The metadata providers.</param>
/// <param name="metadataSavers">The metadata savers.</param>
/// <param name="imageSavers">The image savers.</param>
/// <param name="externalIds">The external ids.</param>
public void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices,
- IEnumerable<IItemIdentityProvider> identityProviders, IEnumerable<IItemIdentityConverter> identityConverters,
IEnumerable<IMetadataProvider> metadataProviders, IEnumerable<IMetadataSaver> metadataSavers,
IEnumerable<IImageSaver> imageSavers, IEnumerable<IExternalId> externalIds)
{
ImageProviders = imageProviders.ToArray();
_metadataServices = metadataServices.OrderBy(i => i.Order).ToArray();
- _identityProviders = identityProviders.ToArray();
- _identityConverters = identityConverters.ToArray();
_metadataProviders = metadataProviders.ToArray();
_imageSavers = imageSavers.ToArray();
_externalIds = externalIds.OrderBy(i => i.Name).ToArray();
@@ -301,18 +294,6 @@ namespace MediaBrowser.Providers.Manager
.ThenBy(GetDefaultOrder);
}
- public IEnumerable<IItemIdentityProvider<TLookupInfo>> GetItemIdentityProviders<TLookupInfo>()
- where TLookupInfo : ItemLookupInfo
- {
- return _identityProviders.OfType<IItemIdentityProvider<TLookupInfo>>();
- }
-
- public IEnumerable<IItemIdentityConverter<TLookupInfo>> GetItemIdentityConverters<TLookupInfo>()
- where TLookupInfo : ItemLookupInfo
- {
- return _identityConverters.OfType<IItemIdentityConverter<TLookupInfo>>();
- }
-
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item, bool includeDisabled)
{
var options = GetMetadataOptions(item);
@@ -849,7 +830,7 @@ namespace MediaBrowser.Providers.Manager
});
}
- public IEnumerable<ExternalUrl> GetExternalUrls(IHasProviderIds item)
+ public IEnumerable<ExternalUrl> GetExternalUrls(BaseItem item)
{
return GetExternalIds(item)
.Select(i =>
@@ -872,7 +853,7 @@ namespace MediaBrowser.Providers.Manager
Url = string.Format(i.UrlFormatString, value)
};
- }).Where(i => i != null);
+ }).Where(i => i != null).Concat(item.GetRelatedUrls());
}
public IEnumerable<ExternalIdInfo> GetExternalIdInfos(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index 59a2da460..5f23cf69c 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -151,29 +151,17 @@ namespace MediaBrowser.Providers.Manager
if (!lockedFields.Contains(MetadataFields.Tags))
{
- var sourceHasTags = source as IHasTags;
- var targetHasTags = target as IHasTags;
-
- if (sourceHasTags != null && targetHasTags != null)
+ if (replaceData || target.Tags.Count == 0)
{
- if (replaceData || targetHasTags.Tags.Count == 0)
- {
- targetHasTags.Tags = sourceHasTags.Tags;
- }
+ target.Tags = source.Tags;
}
}
if (!lockedFields.Contains(MetadataFields.Keywords))
{
- var sourceHasKeywords = source as IHasKeywords;
- var targetHasKeywords = target as IHasKeywords;
-
- if (sourceHasKeywords != null && targetHasKeywords != null)
+ if (replaceData || target.Keywords.Count == 0)
{
- if (replaceData || targetHasKeywords.Keywords.Count == 0)
- {
- targetHasKeywords.Keywords = sourceHasKeywords.Keywords;
- }
+ target.Keywords = source.Keywords;
}
}
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index f07478f98..240b2e2cc 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -89,7 +89,6 @@
<Compile Include="Channels\ChannelMetadataService.cs" />
<Compile Include="Chapters\ChapterManager.cs" />
<Compile Include="Folders\CollectionFolderMetadataService.cs" />
- <Compile Include="Folders\DefaultImageProvider.cs" />
<Compile Include="Folders\FolderMetadataService.cs" />
<Compile Include="Folders\UserViewMetadataService.cs" />
<Compile Include="GameGenres\GameGenreMetadataService.cs" />
@@ -145,10 +144,7 @@
<Compile Include="Omdb\OmdbProvider.cs" />
<Compile Include="Omdb\OmdbItemProvider.cs" />
<Compile Include="People\MovieDbPersonImageProvider.cs" />
- <Compile Include="Movies\MovieUpdatesPrescanTask.cs" />
- <Compile Include="Movies\FanArtMovieUpdatesPostScanTask.cs" />
<Compile Include="Movies\MovieDbProvider.cs" />
- <Compile Include="Music\FanArtUpdatesPostScanTask.cs" />
<Compile Include="Music\FanArtAlbumProvider.cs" />
<Compile Include="Music\FanArtArtistProvider.cs" />
<Compile Include="Music\MusicBrainzAlbumProvider.cs" />
@@ -168,7 +164,6 @@
<Compile Include="Subtitles\SubtitleManager.cs" />
<Compile Include="TV\DummySeasonProvider.cs" />
<Compile Include="TV\EpisodeMetadataService.cs" />
- <Compile Include="TV\FanArt\FanArtTvUpdatesPostScanTask.cs" />
<Compile Include="TV\FanArt\FanArtSeasonProvider.cs" />
<Compile Include="TV\FanArt\FanartSeriesProvider.cs" />
<Compile Include="TV\MissingEpisodeProvider.cs" />
@@ -182,7 +177,6 @@
<Compile Include="TV\SeriesMetadataService.cs" />
<Compile Include="TV\TheTVDB\TvdbEpisodeImageProvider.cs" />
<Compile Include="People\TvdbPersonImageProvider.cs" />
- <Compile Include="TV\TheTVDB\TvdbSeasonIdentityProvider.cs" />
<Compile Include="TV\TheTVDB\TvdbSeasonImageProvider.cs" />
<Compile Include="TV\TheTVDB\TvdbSeriesImageProvider.cs" />
<Compile Include="TV\SeasonMetadataService.cs" />
diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
deleted file mode 100644
index 5262f8e3b..000000000
--- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Providers.Music;
-using MediaBrowser.Providers.TV;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using CommonIO;
-
-namespace MediaBrowser.Providers.Movies
-{
- class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask
- {
- private const string UpdatesUrl = "https://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IFileSystem _fileSystem;
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public FanartMovieUpdatesPostScanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
- {
- _jsonSerializer = jsonSerializer;
- _config = config;
- _logger = logger;
- _httpClient = httpClient;
- _fileSystem = fileSystem;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var options = FanartSeriesProvider.Current.GetFanartOptions();
-
- if (!options.EnableAutomaticUpdates)
- {
- progress.Report(100);
- return;
- }
-
- var path = FanartMovieImageProvider.GetMoviesDataPath(_config.CommonApplicationPaths);
-
- _fileSystem.CreateDirectory(path);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
-
- // Don't check for updates every single time
- if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)
- {
- return;
- }
-
- // Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- // If this is our first time, don't do any updates and just record the timestamp
- if (!string.IsNullOrEmpty(lastUpdateTime))
- {
- var moviesToUpdate = await GetMovieIdsToUpdate(existingDirectories, lastUpdateTime, options, cancellationToken).ConfigureAwait(false);
-
- progress.Report(5);
-
- await UpdateMovies(moviesToUpdate, progress, cancellationToken).ConfigureAwait(false);
- }
-
- var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
-
- _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
-
- progress.Report(100);
- }
-
- private async Task<IEnumerable<string>> GetMovieIdsToUpdate(IEnumerable<string> existingIds, string lastUpdateTime, FanartOptions options, CancellationToken cancellationToken)
- {
- var url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime);
-
- var clientKey = options.UserApiKey;
- if (!string.IsNullOrWhiteSpace(clientKey))
- {
- url += "&client_key=" + clientKey;
- }
-
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = FanartArtistProvider.Current.FanArtResourcePool
-
- }).ConfigureAwait(false))
- {
- using (var reader = new StreamReader(stream))
- {
- var json = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- // If empty fanart will return a string of "null", rather than an empty list
- if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase))
- {
- return new List<string>();
- }
-
- var updates = _jsonSerializer.DeserializeFromString<List<RootObject>>(json);
-
- var existingDictionary = existingIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- return updates.SelectMany(i =>
- {
- var list = new List<string>();
-
- if (!string.IsNullOrWhiteSpace(i.imdb_id))
- {
- list.Add(i.imdb_id);
- }
- if (!string.IsNullOrWhiteSpace(i.tmdb_id))
- {
- list.Add(i.tmdb_id);
- }
-
- return list;
-
- }).Where(existingDictionary.ContainsKey);
- }
- }
- }
-
- private async Task UpdateMovies(IEnumerable<string> idList, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = idList.ToList();
- var numComplete = 0;
-
- foreach (var id in list)
- {
- _logger.Info("Updating movie " + id);
-
- await FanartMovieImageProvider.Current.DownloadMovieJson(id, cancellationToken).ConfigureAwait(false);
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 95;
-
- progress.Report(percent + 5);
- }
- }
-
- /// <summary>
- /// Dates the time to unix timestamp.
- /// </summary>
- /// <param name="dateTime">The date time.</param>
- /// <returns>System.Double.</returns>
- private static double DateTimeToUnixTimestamp(DateTime dateTime)
- {
- return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds;
- }
-
- public class RootObject
- {
- public string tmdb_id { get; set; }
- public string imdb_id { get; set; }
- public string name { get; set; }
- public string new_images { get; set; }
- public string total_images { get; set; }
- }
- }
-}
diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
index 775e6dfb9..18f177932 100644
--- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
@@ -24,7 +24,7 @@ using MediaBrowser.Providers.TV;
namespace MediaBrowser.Providers.Movies
{
- public class FanartMovieImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
+ public class FanartMovieImageProvider : IRemoteImageProvider, IHasOrder
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -241,33 +241,6 @@ namespace MediaBrowser.Providers.Movies
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- var options = FanartSeriesProvider.Current.GetFanartOptions();
- if (!options.EnableAutomaticUpdates)
- {
- return false;
- }
-
- var id = item.GetProviderId(MetadataProviders.Tmdb);
- if (string.IsNullOrEmpty(id))
- {
- id = item.GetProviderId(MetadataProviders.Imdb);
- }
-
- if (!string.IsNullOrEmpty(id))
- {
- // Process images
- var path = GetFanartJsonPath(id);
-
- var fileInfo = _fileSystem.GetFileInfo(path);
-
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
-
/// <summary>
/// Gets the movie data path.
/// </summary>
diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
index d13716cba..3b3065893 100644
--- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
+++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
@@ -314,11 +314,7 @@ namespace MediaBrowser.Providers.Movies
if (movieData.keywords != null && movieData.keywords.keywords != null)
{
- var hasTags = movie as IHasKeywords;
- if (hasTags != null)
- {
- hasTags.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList();
- }
+ movie.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList();
}
if (movieData.trailers != null && movieData.trailers.youtube != null &&
diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
index 5958c3a0a..f9e9bc947 100644
--- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
@@ -17,7 +17,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.Movies
{
- class MovieDbImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
+ class MovieDbImageProvider : IRemoteImageProvider, IHasOrder
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
@@ -221,10 +221,5 @@ namespace MediaBrowser.Providers.Movies
ResourcePool = MovieDbProvider.Current.MovieDbResourcePool
});
}
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- return MovieDbProvider.Current.HasChanged(item);
- }
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index c588a9a69..6a2e72743 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -409,33 +409,6 @@ namespace MediaBrowser.Providers.Movies
return await _httpClient.Get(options).ConfigureAwait(false);
}
- public TheMovieDbOptions GetTheMovieDbOptions()
- {
- return _configurationManager.GetConfiguration<TheMovieDbOptions>("themoviedb");
- }
-
- public bool HasChanged(IHasMetadata item)
- {
- if (!GetTheMovieDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
-
- var tmdbId = item.GetProviderId(MetadataProviders.Tmdb);
-
- if (!String.IsNullOrEmpty(tmdbId))
- {
- // Process images
- var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
-
- var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
-
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
-
public void Dispose()
{
Dispose(true);
@@ -659,19 +632,4 @@ namespace MediaBrowser.Providers.Movies
});
}
}
-
- public class TmdbConfigStore : IConfigurationFactory
- {
- public IEnumerable<ConfigurationStore> GetConfigurations()
- {
- return new List<ConfigurationStore>
- {
- new ConfigurationStore
- {
- Key = "themoviedb",
- ConfigurationType = typeof(TheMovieDbOptions)
- }
- };
- }
- }
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs
index 5fb3ea369..1d8691ab8 100644
--- a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs
@@ -33,11 +33,6 @@ namespace MediaBrowser.Providers.Movies
get { return MovieDbProvider.Current.Name; }
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- return MovieDbProvider.Current.HasChanged(item);
- }
-
public int Order
{
get
diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs
index 3bceb976e..a6b7bde6f 100644
--- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs
+++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs
@@ -148,6 +148,13 @@ namespace MediaBrowser.Providers.Movies
public bool Supports(IHasProviderIds item)
{
+ // Supports images for tv movies
+ var tvProgram = item as LiveTvProgram;
+ if (tvProgram != null && tvProgram.IsMovie)
+ {
+ return true;
+ }
+
return item is Movie || item is MusicVideo || item is Series || item is Episode || item is Trailer;
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
index e70ec0057..83be9ca6f 100644
--- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs
+++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
@@ -13,10 +13,6 @@ namespace MediaBrowser.Providers.Movies
{
public class MovieMetadataService : MetadataService<Movie, MovieInfo>
{
- public MovieMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override bool IsFullLocalMetadata(Movie item)
{
if (string.IsNullOrWhiteSpace(item.Overview))
@@ -42,15 +38,14 @@ namespace MediaBrowser.Providers.Movies
targetItem.CollectionName = sourceItem.CollectionName;
}
}
- }
- public class TrailerMetadataService : MetadataService<Trailer, TrailerInfo>
- {
- public TrailerMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager)
- : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ public MovieMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
}
+ }
+ public class TrailerMetadataService : MetadataService<Trailer, TrailerInfo>
+ {
protected override bool IsFullLocalMetadata(Trailer item)
{
if (string.IsNullOrWhiteSpace(item.Overview))
@@ -73,6 +68,10 @@ namespace MediaBrowser.Providers.Movies
target.Item.TrailerTypes = source.Item.TrailerTypes;
}
}
+
+ public TrailerMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
deleted file mode 100644
index 70c155ad5..000000000
--- a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
+++ /dev/null
@@ -1,249 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using CommonIO;
-
-namespace MediaBrowser.Providers.Movies
-{
- public class MovieUpdatesPreScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The updates URL
- /// </summary>
- private const string UpdatesUrl = "https://api.themoviedb.org/3/movie/changes?start_date={0}&api_key={1}&page={2}";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
- private readonly IJsonSerializer _json;
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="MovieUpdatesPreScanTask"/> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="config">The config.</param>
- /// <param name="json">The json.</param>
- public MovieUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- _logger = logger;
- _httpClient = httpClient;
- _config = config;
- _json = json;
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- }
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- if (!MovieDbProvider.Current.GetTheMovieDbOptions().EnableAutomaticUpdates)
- {
- progress.Report(100);
- return;
- }
-
- var path = MovieDbProvider.GetMoviesDataPath(_config.CommonApplicationPaths);
-
- _fileSystem.CreateDirectory(path);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
-
- // Don't check for updates every single time
- if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 7)
- {
- return;
- }
-
- // Find out the last time we queried tvdb for updates
- var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- if (!string.IsNullOrEmpty(lastUpdateTime))
- {
- long lastUpdateTicks;
-
- if (long.TryParse(lastUpdateTime, NumberStyles.Any, UsCulture, out lastUpdateTicks))
- {
- var lastUpdateDate = new DateTime(lastUpdateTicks, DateTimeKind.Utc);
-
- // They only allow up to 14 days of updates
- if ((DateTime.UtcNow - lastUpdateDate).TotalDays > 13)
- {
- lastUpdateDate = DateTime.UtcNow.AddDays(-13);
- }
-
- var updatedIds = await GetIdsToUpdate(lastUpdateDate, 1, cancellationToken).ConfigureAwait(false);
-
- var existingDictionary = existingDirectories.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- var idsToUpdate = updatedIds.Where(i => !string.IsNullOrWhiteSpace(i) && existingDictionary.ContainsKey(i));
-
- await UpdateMovies(idsToUpdate, progress, cancellationToken).ConfigureAwait(false);
- }
- }
-
- _fileSystem.WriteAllText(timestampFile, DateTime.UtcNow.Ticks.ToString(UsCulture), Encoding.UTF8);
- progress.Report(100);
- }
-
-
- /// <summary>
- /// Gets the ids to update.
- /// </summary>
- /// <param name="lastUpdateTime">The last update time.</param>
- /// <param name="page">The page.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{IEnumerable{System.String}}.</returns>
- private async Task<IEnumerable<string>> GetIdsToUpdate(DateTime lastUpdateTime, int page, CancellationToken cancellationToken)
- {
- bool hasMorePages;
- var list = new List<string>();
-
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = string.Format(UpdatesUrl, lastUpdateTime.ToString("yyyy-MM-dd"), MovieDbProvider.ApiKey, page),
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = MovieDbProvider.Current.MovieDbResourcePool,
- AcceptHeader = MovieDbProvider.AcceptHeader
-
- }).ConfigureAwait(false))
- {
- var obj = _json.DeserializeFromStream<RootObject>(stream);
-
- var data = obj.results.Select(i => i.id.ToString(UsCulture));
-
- list.AddRange(data);
-
- hasMorePages = page < obj.total_pages;
- }
-
- if (hasMorePages)
- {
- var more = await GetIdsToUpdate(lastUpdateTime, page + 1, cancellationToken).ConfigureAwait(false);
-
- list.AddRange(more);
- }
-
- return list;
- }
-
- /// <summary>
- /// Updates the movies.
- /// </summary>
- /// <param name="ids">The ids.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateMovies(IEnumerable<string> ids, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = ids.ToList();
- var numComplete = 0;
-
- // Gather all movies into a lookup by tmdb id
- var allMovies = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
- {
- IncludeItemTypes = new[] {typeof (Movie).Name},
- Recursive = true
-
- }).Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb)))
- .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb));
-
- foreach (var id in list)
- {
- // Find the preferred language(s) for the movie in the library
- var languages = allMovies[id]
- .Select(i => i.GetPreferredMetadataLanguage())
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- foreach (var language in languages)
- {
- try
- {
- await UpdateMovie(id, language, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error updating tmdb movie id {0}, language {1}", ex, id, language);
- }
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 100;
-
- progress.Report(percent);
- }
- }
-
- /// <summary>
- /// Updates the movie.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <param name="preferredMetadataLanguage">The preferred metadata language.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private Task UpdateMovie(string id, string preferredMetadataLanguage, CancellationToken cancellationToken)
- {
- _logger.Info("Updating movie from tmdb " + id + ", language " + preferredMetadataLanguage);
-
- return MovieDbProvider.Current.DownloadMovieInfo(id, preferredMetadataLanguage, cancellationToken);
- }
-
- class Result
- {
- public int id { get; set; }
- public bool? adult { get; set; }
- }
-
- class RootObject
- {
- public List<Result> results { get; set; }
- public int page { get; set; }
- public int total_pages { get; set; }
- public int total_results { get; set; }
-
- public RootObject()
- {
- results = new List<Result>();
- }
- }
- }
-}
diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
index 8f951723e..4f87b2036 100644
--- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
@@ -15,10 +15,6 @@ namespace MediaBrowser.Providers.Music
{
public class AlbumMetadataService : MetadataService<MusicAlbum, AlbumInfo>
{
- public AlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override async Task<ItemUpdateType> BeforeSave(MusicAlbum item, bool isFullRefresh, ItemUpdateType currentUpdateType)
{
var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false);
@@ -166,5 +162,9 @@ namespace MediaBrowser.Providers.Music
targetItem.Artists = sourceItem.Artists;
}
}
+
+ public AlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
index 21e9b006b..b2f975b13 100644
--- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs
+++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
@@ -15,10 +15,6 @@ namespace MediaBrowser.Providers.Music
{
public class ArtistMetadataService : MetadataService<MusicArtist, ArtistInfo>
{
- public ArtistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override async Task<ItemUpdateType> BeforeSave(MusicArtist item, bool isFullRefresh, ItemUpdateType currentUpdateType)
{
var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false);
@@ -58,5 +54,9 @@ namespace MediaBrowser.Providers.Music
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
+
+ public ArtistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs
index 161a16193..532128186 100644
--- a/MediaBrowser.Providers/Music/AudioMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Music
{
public class AudioMetadataService : MetadataService<Audio, SongInfo>
{
- public AudioMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<Audio> source, MetadataResult<Audio> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -33,5 +29,9 @@ namespace MediaBrowser.Providers.Music
targetItem.Album = sourceItem.Album;
}
}
+
+ public AudioMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
index 5b3bd87db..b47e8df5a 100644
--- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
@@ -19,7 +19,7 @@ using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.Music
{
- public class FanartAlbumProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
+ public class FanartAlbumProvider : IRemoteImageProvider, IHasOrder
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -212,34 +212,5 @@ namespace MediaBrowser.Providers.Music
ResourcePool = FanartArtistProvider.Current.FanArtResourcePool
});
}
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- var options = FanartSeriesProvider.Current.GetFanartOptions();
- if (!options.EnableAutomaticUpdates)
- {
- return false;
- }
-
- var album = (MusicAlbum)item;
- var artist = album.MusicArtist;
-
- if (artist != null)
- {
- var artistMusicBrainzId = artist.GetProviderId(MetadataProviders.MusicBrainzArtist);
-
- if (!String.IsNullOrEmpty(artistMusicBrainzId))
- {
- // Process images
- var artistJsonPath = FanartArtistProvider.GetArtistJsonPath(_config.CommonApplicationPaths, artistMusicBrainzId);
-
- var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
-
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
- }
-
- return false;
- }
}
}
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index 37b51da5a..9b18ac5e9 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -22,7 +22,7 @@ using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.Music
{
- public class FanartArtistProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
+ public class FanartArtistProvider : IRemoteImageProvider, IHasOrder
{
internal readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3);
internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4";
@@ -207,29 +207,6 @@ namespace MediaBrowser.Providers.Music
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- var options = FanartSeriesProvider.Current.GetFanartOptions();
- if (!options.EnableAutomaticUpdates)
- {
- return false;
- }
-
- var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
-
- if (!String.IsNullOrEmpty(id))
- {
- // Process images
- var artistJsonPath = GetArtistJsonPath(_config.CommonApplicationPaths, id);
-
- var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
-
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
-
private readonly Task _cachedTask = Task.FromResult(true);
internal Task EnsureArtistJson(string musicBrainzId, CancellationToken cancellationToken)
{
diff --git a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs b/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
deleted file mode 100644
index 3b829af9e..000000000
--- a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
+++ /dev/null
@@ -1,203 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using CommonIO;
-using MediaBrowser.Providers.TV;
-
-namespace MediaBrowser.Providers.Music
-{
- class FanartUpdatesPostScanTask : ILibraryPostScanTask
- {
- private const string UpdatesUrl = "https://api.fanart.tv/webservice/newmusic/{0}/{1}/";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IFileSystem _fileSystem;
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public FanartUpdatesPostScanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
- {
- _jsonSerializer = jsonSerializer;
- _config = config;
- _logger = logger;
- _httpClient = httpClient;
- _fileSystem = fileSystem;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var options = FanartSeriesProvider.Current.GetFanartOptions();
-
- if (!options.EnableAutomaticUpdates)
- {
- progress.Report(100);
- return;
- }
-
- var path = FanartArtistProvider.GetArtistDataPath(_config.CommonApplicationPaths);
-
- _fileSystem.CreateDirectory(path);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
-
- // Don't check for updates every single time
- if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)
- {
- return;
- }
-
- // Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- // If this is our first time, don't do any updates and just record the timestamp
- if (!string.IsNullOrEmpty(lastUpdateTime))
- {
- var artistsToUpdate = await GetArtistIdsToUpdate(existingDirectories, lastUpdateTime, options, cancellationToken).ConfigureAwait(false);
-
- progress.Report(5);
-
- await UpdateArtists(artistsToUpdate, progress, cancellationToken).ConfigureAwait(false);
- }
-
- var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
-
- _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the artist ids to update.
- /// </summary>
- /// <param name="existingArtistIds">The existing series ids.</param>
- /// <param name="lastUpdateTime">The last update time.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{IEnumerable{System.String}}.</returns>
- private async Task<IEnumerable<string>> GetArtistIdsToUpdate(IEnumerable<string> existingArtistIds, string lastUpdateTime, FanartOptions options, CancellationToken cancellationToken)
- {
- var url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime);
-
- if (!string.IsNullOrWhiteSpace(options.UserApiKey))
- {
- url += "&client_key=" + options.UserApiKey;
- }
-
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = FanartArtistProvider.Current.FanArtResourcePool
-
- }).ConfigureAwait(false))
- {
- // If empty fanart will return a string of "null", rather than an empty list
- using (var reader = new StreamReader(stream))
- {
- var json = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase))
- {
- return new List<string>();
- }
-
- var existingDictionary = existingArtistIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- var updates = _jsonSerializer.DeserializeFromString<List<FanArtUpdate>>(json);
-
- return updates.Select(i => i.id).Where(existingDictionary.ContainsKey);
- }
- }
- }
-
- /// <summary>
- /// Updates the artists.
- /// </summary>
- /// <param name="idList">The id list.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateArtists(IEnumerable<string> idList, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = idList.ToList();
- var numComplete = 0;
-
- foreach (var id in list)
- {
- await UpdateArtist(id, cancellationToken).ConfigureAwait(false);
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 95;
-
- progress.Report(percent + 5);
- }
- }
-
- /// <summary>
- /// Updates the artist.
- /// </summary>
- /// <param name="musicBrainzId">The musicBrainzId.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private Task UpdateArtist(string musicBrainzId, CancellationToken cancellationToken)
- {
- _logger.Info("Updating artist " + musicBrainzId);
-
- return FanartArtistProvider.Current.DownloadArtistJson(musicBrainzId, cancellationToken);
- }
-
- /// <summary>
- /// Dates the time to unix timestamp.
- /// </summary>
- /// <param name="dateTime">The date time.</param>
- /// <returns>System.Double.</returns>
- private static double DateTimeToUnixTimestamp(DateTime dateTime)
- {
- return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds;
- }
-
- public class FanArtUpdate
- {
- public string id { get; set; }
- public string name { get; set; }
- public string new_images { get; set; }
- public string total_images { get; set; }
- }
- }
-}
diff --git a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs
index d031b3d6b..88689dd5a 100644
--- a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs
+++ b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs
@@ -27,11 +27,6 @@ namespace MediaBrowser.Providers.Music
get { return MovieDbProvider.Current.Name; }
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- return MovieDbProvider.Current.HasChanged(item);
- }
-
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
throw new NotImplementedException();
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index e41982ef6..792f92b49 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -25,6 +25,8 @@ namespace MediaBrowser.Providers.Music
private readonly IApplicationHost _appHost;
private readonly ILogger _logger;
+ public static string MusicBrainzBaseUrl = "https://www.musicbrainz.org";
+
public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger)
{
_httpClient = httpClient;
@@ -42,7 +44,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrEmpty(releaseId))
{
- url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=reid:{0}", releaseId);
+ url = string.Format("/ws/2/release/?query=reid:{0}", releaseId);
}
else
{
@@ -50,7 +52,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrWhiteSpace(artistMusicBrainzId))
{
- url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
+ url = string.Format("/ws/2/release/?query=\"{0}\" AND arid:{1}",
WebUtility.UrlEncode(searchInfo.Name),
artistMusicBrainzId);
}
@@ -58,7 +60,7 @@ namespace MediaBrowser.Providers.Music
{
isNameSearch = true;
- url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
+ url = string.Format("/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
WebUtility.UrlEncode(searchInfo.Name),
WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
}
@@ -77,7 +79,7 @@ namespace MediaBrowser.Providers.Music
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
{
var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
+ ns.AddNamespace("mb", MusicBrainzBaseUrl + "/ns/mmd-2.0#");
var list = new List<RemoteSearchResult>();
@@ -197,57 +199,86 @@ namespace MediaBrowser.Providers.Music
private async Task<ReleaseResult> GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken)
{
- var url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
+ var url = string.Format("/ws/2/release/?query=\"{0}\" AND arid:{1}",
WebUtility.UrlEncode(albumName),
artistId);
var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
- return GetReleaseResult(doc);
+ return ReleaseResult.Parse(doc);
}
private async Task<ReleaseResult> GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken)
{
- var url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
+ var url = string.Format("/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
WebUtility.UrlEncode(albumName),
WebUtility.UrlEncode(artistName));
var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
- return GetReleaseResult(doc);
+ return ReleaseResult.Parse(doc);
}
- private ReleaseResult GetReleaseResult(XmlDocument doc)
+ private class ReleaseResult
{
- var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
+ public string ReleaseId;
+ public string ReleaseGroupId;
- var result = new ReleaseResult
+ public static ReleaseResult Parse(XmlDocument doc)
{
+ var docElem = doc.DocumentElement;
- };
+ if (docElem == null)
+ {
+ return new ReleaseResult();
+ }
- var releaseIdNode = doc.SelectSingleNode("//mb:release-list/mb:release/@id", ns);
+ var releaseList = docElem.FirstChild;
+ if (releaseList == null)
+ {
+ return new ReleaseResult();
+ }
- if (releaseIdNode != null)
- {
- result.ReleaseId = releaseIdNode.Value;
- }
+ var nodes = releaseList.ChildNodes;
+ string releaseId = null;
+ string releaseGroupId = null;
- var releaseGroupIdNode = doc.SelectSingleNode("//mb:release-list/mb:release/mb:release-group/@id", ns);
+ if (nodes != null)
+ {
+ foreach (var node in nodes.Cast<XmlNode>())
+ {
+ if (string.Equals(node.Name, "release", StringComparison.OrdinalIgnoreCase))
+ {
+ releaseId = node.Attributes["id"].Value;
+ releaseGroupId = GetReleaseGroupIdFromReleaseNode(node);
+ break;
+ }
+ }
+ }
- if (releaseGroupIdNode != null)
- {
- result.ReleaseGroupId = releaseGroupIdNode.Value;
+ return new ReleaseResult
+ {
+ ReleaseId = releaseId,
+ ReleaseGroupId = releaseGroupId
+ };
}
- return result;
- }
+ private static string GetReleaseGroupIdFromReleaseNode(XmlNode node)
+ {
+ var subNodes = node.ChildNodes;
+ if (subNodes != null)
+ {
+ foreach (var subNode in subNodes.Cast<XmlNode>())
+ {
+ if (string.Equals(subNode.Name, "release-group", StringComparison.OrdinalIgnoreCase))
+ {
+ return subNode.Attributes["id"].Value;
+ }
+ }
+ }
- private class ReleaseResult
- {
- public string ReleaseId;
- public string ReleaseGroupId;
+ return null;
+ }
}
/// <summary>
@@ -258,15 +289,36 @@ namespace MediaBrowser.Providers.Music
/// <returns>Task{System.String}.</returns>
private async Task<string> GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken)
{
- var url = string.Format("https://www.musicbrainz.org/ws/2/release-group/?query=reid:{0}", releaseEntryId);
+ var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId);
var doc = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false);
- var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
- var node = doc.SelectSingleNode("//mb:release-group-list/mb:release-group/@id", ns);
+ var docElem = doc.DocumentElement;
- return node != null ? node.Value : null;
+ if (docElem == null)
+ {
+ return null;
+ }
+
+ var releaseList = docElem.FirstChild;
+ if (releaseList == null)
+ {
+ return null;
+ }
+
+ var nodes = releaseList.ChildNodes;
+
+ if (nodes != null)
+ {
+ foreach (var node in nodes.Cast<XmlNode>())
+ {
+ if (string.Equals(node.Name, "release-group", StringComparison.OrdinalIgnoreCase))
+ {
+ return node.Attributes["id"].Value;
+ }
+ }
+ }
+ return null;
}
/// <summary>
@@ -274,6 +326,49 @@ namespace MediaBrowser.Providers.Music
/// </summary>
private readonly SemaphoreSlim _musicBrainzResourcePool = new SemaphoreSlim(1, 1);
+ private long _lastMbzUrlQueryTicks = 0;
+ private List<MbzUrl> _mbzUrls = null;
+ private MbzUrl _chosenUrl;
+
+ private async Task<MbzUrl> GetMbzUrl()
+ {
+ if (_mbzUrls == null || (DateTime.UtcNow.Ticks - _lastMbzUrlQueryTicks) > TimeSpan.FromHours(12).Ticks)
+ {
+ await RefreshMzbUrls().ConfigureAwait(false);
+
+ var urls = _mbzUrls.ToList();
+ _chosenUrl = urls[new Random().Next(0, urls.Count - 1)];
+ }
+
+ return _chosenUrl;
+ }
+
+ private async Task RefreshMzbUrls()
+ {
+ try
+ {
+ _mbzUrls = new List<MbzUrl>
+ {
+ new MbzUrl
+ {
+ url = MusicBrainzBaseUrl,
+ throttleMs = 1000
+ }
+ };
+ }
+ catch
+ {
+ _mbzUrls = new List<MbzUrl>
+ {
+ new MbzUrl
+ {
+ url = MusicBrainzBaseUrl,
+ throttleMs = 1000
+ }
+ };
+ }
+ }
+
/// <summary>
/// Gets the music brainz response.
/// </summary>
@@ -283,9 +378,15 @@ namespace MediaBrowser.Providers.Music
/// <returns>Task{XmlDocument}.</returns>
internal async Task<XmlDocument> GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken)
{
- // MusicBrainz is extremely adamant about limiting to one request per second
+ var urlInfo = await GetMbzUrl().ConfigureAwait(false);
- await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
+ if (urlInfo.throttleMs > 0)
+ {
+ // MusicBrainz is extremely adamant about limiting to one request per second
+ await Task.Delay(urlInfo.throttleMs, cancellationToken).ConfigureAwait(false);
+ }
+
+ url = urlInfo.url.TrimEnd('/') + url;
var doc = new XmlDocument();
@@ -317,5 +418,11 @@ namespace MediaBrowser.Providers.Music
{
throw new NotImplementedException();
}
+
+ internal class MbzUrl
+ {
+ public string url { get; set; }
+ public int throttleMs { get; set; }
+ }
}
}
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index 2eb65f4e5..f36062ebe 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
@@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrWhiteSpace(musicBrainzId))
{
- var url = string.Format("https://www.musicbrainz.org/ws/2/artist/?query=arid:{0}", musicBrainzId);
+ var url = string.Format("/ws/2/artist/?query=arid:{0}", musicBrainzId);
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken)
.ConfigureAwait(false);
@@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.Music
// They seem to throw bad request failures on any term with a slash
var nameToSearch = searchInfo.Name.Replace('/', ' ');
- var url = String.Format("https://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
+ var url = String.Format("/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
@@ -49,7 +49,7 @@ namespace MediaBrowser.Providers.Music
if (HasDiacritics(searchInfo.Name))
{
// Try again using the search with accent characters url
- url = String.Format("https://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
+ url = String.Format("/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
@@ -62,9 +62,6 @@ namespace MediaBrowser.Providers.Music
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
{
- //var ns = new XmlNamespaceManager(doc.NameTable);
- //ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
-
var list = new List<RemoteSearchResult>();
var docElem = doc.DocumentElement;
diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
index b309ce906..a50c07721 100644
--- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
+++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
@@ -13,10 +13,6 @@ namespace MediaBrowser.Providers.Music
{
class MusicVideoMetadataService : MetadataService<MusicVideo, MusicVideoInfo>
{
- public MusicVideoMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<MusicVideo> source, MetadataResult<MusicVideo> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -34,5 +30,9 @@ namespace MediaBrowser.Providers.Music
targetItem.Artists = sourceItem.Artists.ToList();
}
}
+
+ public MusicVideoMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
index adffdfca6..d7b96271b 100644
--- a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
+++ b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.MusicGenres
{
public class MusicGenreMetadataService : MetadataService<MusicGenre, ItemLookupInfo>
{
- public MusicGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<MusicGenre> source, MetadataResult<MusicGenre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<MusicGenre> source, MetadataResult<MusicGenre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public MusicGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
index a1e038374..563118940 100644
--- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Common.Net;
+using CommonIO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
@@ -6,7 +8,10 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Model.Serialization;
using System.Collections.Generic;
+using System.IO;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -15,10 +20,16 @@ namespace MediaBrowser.Providers.Omdb
public class OmdbImageProvider : IRemoteImageProvider, IHasOrder
{
private readonly IHttpClient _httpClient;
+ private readonly IJsonSerializer _jsonSerializer;
+ private readonly IFileSystem _fileSystem;
+ private readonly IServerConfigurationManager _configurationManager;
- public OmdbImageProvider(IHttpClient httpClient)
+ public OmdbImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager configurationManager)
{
+ _jsonSerializer = jsonSerializer;
_httpClient = httpClient;
+ _fileSystem = fileSystem;
+ _configurationManager = configurationManager;
}
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
@@ -29,22 +40,29 @@ namespace MediaBrowser.Providers.Omdb
};
}
- public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
{
var imdbId = item.GetProviderId(MetadataProviders.Imdb);
var list = new List<RemoteImageInfo>();
+ var provider = new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _configurationManager);
+
if (!string.IsNullOrWhiteSpace(imdbId))
{
- list.Add(new RemoteImageInfo
+ OmdbProvider.RootObject rootObject = await provider.GetRootObject(imdbId, cancellationToken).ConfigureAwait(false);
+
+ if (!string.IsNullOrEmpty(rootObject.Poster))
{
- ProviderName = Name,
- Url = string.Format("https://img.omdbapi.com/?i={0}&apikey=82e83907", imdbId)
- });
+ list.Add(new RemoteImageInfo
+ {
+ ProviderName = Name,
+ Url = string.Format("https://img.omdbapi.com/?i={0}&apikey=82e83907", imdbId)
+ });
+ }
}
- return Task.FromResult<IEnumerable<RemoteImageInfo>>(list);
+ return list;
}
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
@@ -65,18 +83,6 @@ namespace MediaBrowser.Providers.Omdb
public bool Supports(IHasImages item)
{
- // We'll hammer Omdb if we enable this
- if (item is Person)
- {
- return false;
- }
-
- // Save the http requests since we know it's not currently supported
- if (item is Season || item is Episode)
- {
- return false;
- }
-
// Supports images for tv movies
var tvProgram = item as LiveTvProgram;
if (tvProgram != null && tvProgram.IsMovie)
@@ -84,7 +90,7 @@ namespace MediaBrowser.Providers.Omdb
return true;
}
- return item is Movie || item is Trailer;
+ return item is Movie || item is Trailer || item is Episode;
}
public int Order
diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
index a0d60c166..7a803eb6f 100644
--- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Common.Net;
+using CommonIO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
@@ -26,13 +28,17 @@ namespace MediaBrowser.Providers.Omdb
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
+ private readonly IServerConfigurationManager _configurationManager;
- public OmdbItemProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger, ILibraryManager libraryManager)
+ public OmdbItemProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager configurationManager)
{
_jsonSerializer = jsonSerializer;
_httpClient = httpClient;
_logger = logger;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
+ _configurationManager = configurationManager;
}
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
@@ -220,7 +226,7 @@ namespace MediaBrowser.Providers.Omdb
result.Item.SetProviderId(MetadataProviders.Imdb, imdbId);
result.HasMetadata = true;
- await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
+ await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _configurationManager).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
}
return result;
@@ -259,7 +265,7 @@ namespace MediaBrowser.Providers.Omdb
result.Item.SetProviderId(MetadataProviders.Imdb, imdbId);
result.HasMetadata = true;
- await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
+ await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _configurationManager).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
}
return result;
diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
index 44e250350..4056073f2 100644
--- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
@@ -1,11 +1,16 @@
-using MediaBrowser.Common.Net;
+using CommonIO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Serialization;
using System;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Net;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -15,17 +20,17 @@ namespace MediaBrowser.Providers.Omdb
{
internal static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1);
private readonly IJsonSerializer _jsonSerializer;
+ private readonly IFileSystem _fileSystem;
+ private readonly IServerConfigurationManager _configurationManager;
private readonly IHttpClient _httpClient;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public static OmdbProvider Current;
-
- public OmdbProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient)
+ public OmdbProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager configurationManager)
{
_jsonSerializer = jsonSerializer;
_httpClient = httpClient;
-
- Current = this;
+ _fileSystem = fileSystem;
+ _configurationManager = configurationManager;
}
public async Task Fetch(BaseItem item, string imdbId, string language, string country, CancellationToken cancellationToken)
@@ -35,19 +40,7 @@ namespace MediaBrowser.Providers.Omdb
throw new ArgumentNullException("imdbId");
}
- var imdbParam = imdbId.StartsWith("tt", StringComparison.OrdinalIgnoreCase) ? imdbId : "tt" + imdbId;
-
- var url = string.Format("https://www.omdbapi.com/?i={0}&tomatoes=true", imdbParam);
-
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = ResourcePool,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- var result = _jsonSerializer.DeserializeFromStream<RootObject>(stream);
+ var result = await GetRootObject(imdbId, cancellationToken);
// Only take the name and rating if the user's language is set to english, since Omdb has no localization
if (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
@@ -84,7 +77,6 @@ namespace MediaBrowser.Providers.Omdb
}
if (!string.IsNullOrEmpty(result.tomatoConsensus)
- && !string.Equals(result.tomatoConsensus, "n/a", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
{
hasCriticRating.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
@@ -109,20 +101,90 @@ namespace MediaBrowser.Providers.Omdb
item.CommunityRating = imdbRating;
}
- if (!string.IsNullOrEmpty(result.Website)
- && !string.Equals(result.Website, "n/a", StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(result.Website))
{
item.HomePageUrl = result.Website;
}
- if (!string.IsNullOrWhiteSpace(result.imdbID)
- && !string.Equals(result.imdbID, "n/a", StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrWhiteSpace(result.imdbID))
{
item.SetProviderId(MetadataProviders.Imdb, result.imdbID);
}
ParseAdditionalMetadata(item, result);
+ }
+
+ internal async Task<RootObject> GetRootObject(string imdbId, CancellationToken cancellationToken)
+ {
+ var path = await EnsureItemInfo(imdbId, cancellationToken);
+
+ string resultString;
+
+ using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 131072))
+ {
+ using (var reader = new StreamReader(stream, new UTF8Encoding(false)))
+ {
+ resultString = reader.ReadToEnd();
+ resultString = resultString.Replace("\"N/A\"", "\"\"");
+ }
}
+
+ var result = _jsonSerializer.DeserializeFromString<RootObject>(resultString);
+ return result;
+ }
+
+ private async Task<string> EnsureItemInfo(string imdbId, CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrWhiteSpace(imdbId))
+ {
+ throw new ArgumentNullException("imdbId");
+ }
+
+ var imdbParam = imdbId.StartsWith("tt", StringComparison.OrdinalIgnoreCase) ? imdbId : "tt" + imdbId;
+
+ var path = GetDataFilePath(imdbParam);
+
+ var fileInfo = _fileSystem.GetFileSystemInfo(path);
+
+ if (fileInfo.Exists)
+ {
+ // If it's recent or automatic updates are enabled, don't re-download
+ if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 3)
+ {
+ return path;
+ }
+ }
+
+ var url = string.Format("https://www.omdbapi.com/?i={0}&tomatoes=true", imdbParam);
+
+ using (var stream = await _httpClient.Get(new HttpRequestOptions
+ {
+ Url = url,
+ ResourcePool = ResourcePool,
+ CancellationToken = cancellationToken
+
+ }).ConfigureAwait(false))
+ {
+ var rootObject = _jsonSerializer.DeserializeFromStream<RootObject>(stream);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+ _jsonSerializer.SerializeToFile(rootObject, path);
+ }
+
+ return path;
+ }
+
+ internal string GetDataFilePath(string imdbId)
+ {
+ if (string.IsNullOrEmpty(imdbId))
+ {
+ throw new ArgumentNullException("imdbId");
+ }
+
+ var dataPath = Path.Combine(_configurationManager.ApplicationPaths.CachePath, "omdb");
+
+ var filename = string.Format("{0}.json", imdbId);
+
+ return Path.Combine(dataPath, filename);
}
private void ParseAdditionalMetadata(BaseItem item, RootObject result)
@@ -130,8 +192,7 @@ namespace MediaBrowser.Providers.Omdb
// Grab series genres because imdb data is better than tvdb. Leave movies alone
// But only do it if english is the preferred language because this data will not be localized
if (ShouldFetchGenres(item) &&
- !string.IsNullOrWhiteSpace(result.Genre) &&
- !string.Equals(result.Genre, "n/a", StringComparison.OrdinalIgnoreCase))
+ !string.IsNullOrWhiteSpace(result.Genre))
{
item.Genres.Clear();
@@ -156,8 +217,7 @@ namespace MediaBrowser.Providers.Omdb
}
var hasAwards = item as IHasAwards;
- if (hasAwards != null && !string.IsNullOrEmpty(result.Awards) &&
- !string.Equals(result.Awards, "n/a", StringComparison.OrdinalIgnoreCase))
+ if (hasAwards != null && !string.IsNullOrEmpty(result.Awards))
{
hasAwards.AwardSummary = WebUtility.HtmlDecode(result.Awards);
}
@@ -178,7 +238,7 @@ namespace MediaBrowser.Providers.Omdb
return string.Equals(lang, "en", StringComparison.OrdinalIgnoreCase);
}
- private class RootObject
+ internal class RootObject
{
public string Title { get; set; }
public string Year { get; set; }
diff --git a/MediaBrowser.Providers/People/PersonMetadataService.cs b/MediaBrowser.Providers/People/PersonMetadataService.cs
index 13a370bc5..0be5773db 100644
--- a/MediaBrowser.Providers/People/PersonMetadataService.cs
+++ b/MediaBrowser.Providers/People/PersonMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.People
{
public class PersonMetadataService : MetadataService<Person, PersonLookupInfo>
{
- public PersonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<Person> source, MetadataResult<Person> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -28,5 +24,9 @@ namespace MediaBrowser.Providers.People
targetItem.PlaceOfBirth = sourceItem.PlaceOfBirth;
}
}
+
+ public PersonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
index 262480885..9bfff6b84 100644
--- a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Photos
{
class PhotoAlbumMetadataService : MetadataService<PhotoAlbum, ItemLookupInfo>
{
- public PhotoAlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<PhotoAlbum> source, MetadataResult<PhotoAlbum> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<PhotoAlbum> source, MetadataResult<PhotoAlbum> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public PhotoAlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
index 0836c5ede..fb6ff6f09 100644
--- a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
+++ b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Photos
{
class PhotoMetadataService : MetadataService<Photo, ItemLookupInfo>
{
- public PhotoMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<Photo> source, MetadataResult<Photo> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<Photo> source, MetadataResult<Photo> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public PhotoMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
index 89ca8da25..d1d5ba7de 100644
--- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
+++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Playlists
{
class PlaylistMetadataService : MetadataService<Playlist, ItemLookupInfo>
{
- public PlaylistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<Playlist> source, MetadataResult<Playlist> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -34,5 +30,9 @@ namespace MediaBrowser.Providers.Playlists
targetItem.Shares = sourceItem.Shares;
}
}
+
+ public PlaylistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Studios/StudioMetadataService.cs b/MediaBrowser.Providers/Studios/StudioMetadataService.cs
index eef1e8e07..9ee594a66 100644
--- a/MediaBrowser.Providers/Studios/StudioMetadataService.cs
+++ b/MediaBrowser.Providers/Studios/StudioMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Studios
{
public class StudioMetadataService : MetadataService<Studio, ItemLookupInfo>
{
- public StudioMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<Studio> source, MetadataResult<Studio> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<Studio> source, MetadataResult<Studio> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public StudioMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
index c848fcd0e..a15de4866 100644
--- a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
+++ b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.TV
{
public class EpisodeMetadataService : MetadataService<Episode, EpisodeInfo>
{
- public EpisodeMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override void MergeData(MetadataResult<Episode> source, MetadataResult<Episode> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -58,5 +54,9 @@ namespace MediaBrowser.Providers.TV
targetItem.IndexNumberEnd = sourceItem.IndexNumberEnd;
}
}
+
+ public EpisodeMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
index 673663d7f..b1930d8f0 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
@@ -21,7 +21,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class FanArtSeasonProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
+ public class FanArtSeasonProvider : IRemoteImageProvider, IHasOrder
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -224,36 +224,5 @@ namespace MediaBrowser.Providers.TV
ResourcePool = FanartArtistProvider.Current.FanArtResourcePool
});
}
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- var options = FanartSeriesProvider.Current.GetFanartOptions();
- if (!options.EnableAutomaticUpdates)
- {
- return false;
- }
-
- var season = (Season)item;
- var series = season.Series;
-
- if (series == null)
- {
- return false;
- }
-
- var tvdbId = series.GetProviderId(MetadataProviders.Tvdb);
-
- if (!String.IsNullOrEmpty(tvdbId))
- {
- // Process images
- var imagesFilePath = FanartSeriesProvider.Current.GetFanartJsonPath(tvdbId);
-
- var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
-
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
}
}
diff --git a/MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs b/MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs
deleted file mode 100644
index 37e76531b..000000000
--- a/MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Providers.Music;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using CommonIO;
-
-namespace MediaBrowser.Providers.TV
-{
- class FanArtTvUpdatesPostScanTask : ILibraryPostScanTask
- {
- private const string UpdatesUrl = "https://webservice.fanart.tv/v3/tv/latest?api_key={0}&date={1}";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IFileSystem _fileSystem;
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public FanArtTvUpdatesPostScanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
- {
- _jsonSerializer = jsonSerializer;
- _config = config;
- _logger = logger;
- _httpClient = httpClient;
- _fileSystem = fileSystem;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var options = FanartSeriesProvider.Current.GetFanartOptions();
-
- if (!options.EnableAutomaticUpdates)
- {
- progress.Report(100);
- return;
- }
-
- var path = FanartSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
-
- _fileSystem.CreateDirectory(path);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
-
- // Don't check for updates every single time
- if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)
- {
- return;
- }
-
- // Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- // If this is our first time, don't do any updates and just record the timestamp
- if (!string.IsNullOrEmpty(lastUpdateTime))
- {
- var seriesToUpdate = await GetSeriesIdsToUpdate(existingDirectories, lastUpdateTime, options, cancellationToken).ConfigureAwait(false);
-
- progress.Report(5);
-
- await UpdateSeries(seriesToUpdate, progress, cancellationToken).ConfigureAwait(false);
- }
-
- var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
-
- _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the series ids to update.
- /// </summary>
- /// <param name="existingSeriesIds">The existing series ids.</param>
- /// <param name="lastUpdateTime">The last update time.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{IEnumerable{System.String}}.</returns>
- private async Task<IEnumerable<string>> GetSeriesIdsToUpdate(IEnumerable<string> existingSeriesIds, string lastUpdateTime, FanartOptions options, CancellationToken cancellationToken)
- {
- var url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime);
-
- if (!string.IsNullOrWhiteSpace(options.UserApiKey))
- {
- url += "&client_key=" + options.UserApiKey;
- }
-
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = FanartArtistProvider.Current.FanArtResourcePool
-
- }).ConfigureAwait(false))
- {
- // If empty fanart will return a string of "null", rather than an empty list
- using (var reader = new StreamReader(stream))
- {
- var json = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(json))
- {
- return new List<string>();
- }
-
- var existingDictionary = existingSeriesIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- var updates = _jsonSerializer.DeserializeFromString<List<FanartUpdatesPostScanTask.FanArtUpdate>>(json);
-
- return updates.Select(i => i.id).Where(existingDictionary.ContainsKey);
- }
- }
- }
-
- /// <summary>
- /// Updates the series.
- /// </summary>
- /// <param name="idList">The id list.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateSeries(IEnumerable<string> idList, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = idList.ToList();
- var numComplete = 0;
-
- foreach (var id in list)
- {
- _logger.Info("Updating series " + id);
-
- await FanartSeriesProvider.Current.DownloadSeriesJson(id, cancellationToken).ConfigureAwait(false);
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 95;
-
- progress.Report(percent + 5);
- }
- }
-
- /// <summary>
- /// Dates the time to unix timestamp.
- /// </summary>
- /// <param name="dateTime">The date time.</param>
- /// <returns>System.Double.</returns>
- private static double DateTimeToUnixTimestamp(DateTime dateTime)
- {
- return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds;
- }
-
- public class FanArtUpdate
- {
- public string id { get; set; }
- public string name { get; set; }
- public string new_images { get; set; }
- public string total_images { get; set; }
- }
- }
-}
diff --git a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
index 3c831dbbc..5662082db 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
@@ -23,7 +23,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class FanartSeriesProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
+ public class FanartSeriesProvider : IRemoteImageProvider, IHasOrder
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -341,29 +341,6 @@ namespace MediaBrowser.Providers.TV
}
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- var options = GetFanartOptions();
- if (!options.EnableAutomaticUpdates)
- {
- return false;
- }
-
- var tvdbId = item.GetProviderId(MetadataProviders.Tvdb);
-
- if (!String.IsNullOrEmpty(tvdbId))
- {
- // Process images
- var imagesFilePath = GetFanartJsonPath(tvdbId);
-
- var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
-
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
-
public class Image
{
public string id { get; set; }
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index 2a3150c78..4e2d9a8d2 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -428,7 +428,8 @@ namespace MediaBrowser.Providers.TV
Name = name,
IndexNumber = episodeNumber,
ParentIndexNumber = seasonNumber,
- Id = _libraryManager.GetNewItemId((series.Id + seasonNumber.ToString(_usCulture) + name), typeof(Episode))
+ Id = _libraryManager.GetNewItemId((series.Id + seasonNumber.ToString(_usCulture) + name), typeof(Episode)),
+ IsVirtualItem = true
};
episode.SetParent(season);
diff --git a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
index 5da1fcf27..ebbefbeb1 100644
--- a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Common.Net;
+using CommonIO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -21,12 +23,16 @@ namespace MediaBrowser.Providers.TV
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
private readonly OmdbItemProvider _itemProvider;
+ private readonly IFileSystem _fileSystem;
+ private readonly IServerConfigurationManager _configurationManager;
- public OmdbEpisodeProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger, ILibraryManager libraryManager)
+ public OmdbEpisodeProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager configurationManager)
{
_jsonSerializer = jsonSerializer;
_httpClient = httpClient;
- _itemProvider = new OmdbItemProvider(jsonSerializer, httpClient, logger, libraryManager);
+ _fileSystem = fileSystem;
+ _configurationManager = configurationManager;
+ _itemProvider = new OmdbItemProvider(jsonSerializer, httpClient, logger, libraryManager, fileSystem, configurationManager);
}
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
@@ -58,7 +64,7 @@ namespace MediaBrowser.Providers.TV
result.Item.SetProviderId(MetadataProviders.Imdb, imdbId);
result.HasMetadata = true;
- await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
+ await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _configurationManager).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
}
return result;
diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
index ae19a6a44..e4894915d 100644
--- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
@@ -15,10 +15,6 @@ namespace MediaBrowser.Providers.TV
{
public class SeasonMetadataService : MetadataService<Season, SeasonInfo>
{
- public SeasonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
protected override async Task<ItemUpdateType> BeforeSave(Season item, bool isFullRefresh, ItemUpdateType currentUpdateType)
{
var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false);
@@ -79,5 +75,9 @@ namespace MediaBrowser.Providers.TV
return ItemUpdateType.None;
}
+
+ public SeasonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index dfa8e30f3..f440baf5b 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.TV
{
private readonly ILocalizationManager _localization;
- public SeriesMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager, ILocalizationManager localization) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ public SeriesMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager, ILocalizationManager localization) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
_localization = localization;
}
@@ -76,11 +76,6 @@ namespace MediaBrowser.Providers.TV
{
targetItem.AirDays = sourceItem.AirDays;
}
-
- if (mergeMetadataSettings)
- {
- targetItem.DisplaySpecialsWithSeasons = sourceItem.DisplaySpecialsWithSeasons;
- }
}
}
}
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
index 3c0a5fc73..d044c828f 100644
--- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
@@ -195,28 +195,35 @@ namespace MediaBrowser.Providers.TV
private async void LibraryUpdateTimerCallback(object state)
{
- if (MissingEpisodeProvider.IsRunning)
+ try
{
- return;
- }
+ if (MissingEpisodeProvider.IsRunning)
+ {
+ return;
+ }
- if (_libraryManager.IsScanRunning)
- {
- return ;
- }
+ if (_libraryManager.IsScanRunning)
+ {
+ return;
+ }
- var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
- {
- IncludeItemTypes = new[] { typeof(Series).Name },
- Recursive = true,
- GroupByPresentationUniqueKey = false
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false
- }).Cast<Series>().ToList();
+ }).Cast<Series>().ToList();
- var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
+ var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
- await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem)
- .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false);
+ await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem)
+ .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in SeriesPostScanTask", ex);
+ }
}
private bool FilterItem(BaseItem item)
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
index 9bab3d380..bc9842b73 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
@@ -114,6 +114,22 @@ namespace MediaBrowser.Providers.TV
item.CommunityRating = (float)response.vote_average;
item.VoteCount = response.vote_count;
+ if (response.videos != null && response.videos.results != null)
+ {
+ foreach (var video in response.videos.results)
+ {
+ if (video.type.Equals("trailer", System.StringComparison.OrdinalIgnoreCase)
+ || video.type.Equals("clip", System.StringComparison.OrdinalIgnoreCase))
+ {
+ if (video.site.Equals("youtube", System.StringComparison.OrdinalIgnoreCase))
+ {
+ var videoUrl = string.Format("http://www.youtube.com/watch?v={0}", video.key);
+ item.AddTrailerUrl(videoUrl, true);
+ }
+ }
+ }
+ }
+
result.ResetPeople();
var credits = response.credits;
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
index 36800202f..a6df245b0 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
@@ -210,7 +210,19 @@ namespace MediaBrowser.Providers.TV
public class Videos
{
- public List<object> results { get; set; }
+ public List<Video> results { get; set; }
+ }
+
+ public class Video
+ {
+ public string id { get; set; }
+ public string iso_639_1 { get; set; }
+ public string iso_3166_1 { get; set; }
+ public string key { get; set; }
+ public string name { get; set; }
+ public string site { get; set; }
+ public string size { get; set; }
+ public string type { get; set; }
}
public class RootObject
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
index 2e51393e3..194af5b99 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.TV
result.HasMetadata = true;
result.Item = new Season();
- result.Item.Name = info.Name;
+ result.Item.Name = seasonInfo.name;
result.Item.IndexNumber = seasonNumber;
result.Item.Overview = seasonInfo.overview;
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
index 65ac12adf..06481f8f2 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
@@ -16,7 +16,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.TV
{
- public class MovieDbSeriesImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
+ public class MovieDbSeriesImageProvider : IRemoteImageProvider, IHasOrder
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
@@ -195,10 +195,5 @@ namespace MediaBrowser.Providers.TV
ResourcePool = MovieDbProvider.Current.MovieDbResourcePool
});
}
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- return MovieDbSeriesProvider.Current.HasChanged(item);
- }
}
}
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
index 7d0f49955..3245a2c85 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
@@ -168,7 +168,7 @@ namespace MediaBrowser.Providers.TV
{
cancellationToken.ThrowIfCancellationRequested();
- result.Item = await FetchMovieData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
+ result.Item = await FetchSeriesData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
result.HasMetadata = result.Item != null;
}
@@ -176,7 +176,7 @@ namespace MediaBrowser.Providers.TV
return result;
}
- private async Task<Series> FetchMovieData(string tmdbId, string language, string preferredCountryCode, CancellationToken cancellationToken)
+ private async Task<Series> FetchSeriesData(string tmdbId, string language, string preferredCountryCode, CancellationToken cancellationToken)
{
string dataFilePath = null;
RootObject seriesInfo = null;
@@ -285,6 +285,21 @@ namespace MediaBrowser.Providers.TV
series.OfficialRating = minimumRelease.rating;
}
+ if (seriesInfo.videos != null && seriesInfo.videos.results != null)
+ {
+ foreach (var video in seriesInfo.videos.results)
+ {
+ if (video.type.Equals("trailer", System.StringComparison.OrdinalIgnoreCase)
+ || video.type.Equals("clip", System.StringComparison.OrdinalIgnoreCase))
+ {
+ if (video.site.Equals("youtube", System.StringComparison.OrdinalIgnoreCase))
+ {
+ var videoUrl = string.Format("http://www.youtube.com/watch?v={0}", video.key);
+ series.AddTrailerUrl(videoUrl, true);
+ }
+ }
+ }
+ }
}
internal static string GetSeriesDataPath(IApplicationPaths appPaths, string tmdbId)
@@ -414,28 +429,6 @@ namespace MediaBrowser.Providers.TV
return Path.Combine(path, filename);
}
- public bool HasChanged(IHasMetadata item)
- {
- if (!MovieDbProvider.Current.GetTheMovieDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
-
- var tmdbId = item.GetProviderId(MetadataProviders.Tmdb);
-
- if (!String.IsNullOrEmpty(tmdbId))
- {
- // Process images
- var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
-
- var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
-
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
-
private async Task<RemoteSearchResult> FindByExternalId(string id, string externalSource, CancellationToken cancellationToken)
{
var url = string.Format("https://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}",
@@ -577,7 +570,19 @@ namespace MediaBrowser.Providers.TV
public class Videos
{
- public List<object> results { get; set; }
+ public List<Video> results { get; set; }
+ }
+
+ public class Video
+ {
+ public string id { get; set; }
+ public string iso_639_1 { get; set; }
+ public string iso_3166_1 { get; set; }
+ public string key { get; set; }
+ public string name { get; set; }
+ public string site { get; set; }
+ public string size { get; set; }
+ public string type { get; set; }
}
public class ContentRating
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
index 7a0b2c90c..881513286 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
@@ -17,7 +17,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class TvdbEpisodeImageProvider : IRemoteImageProvider, IHasItemChangeMonitor
+ public class TvdbEpisodeImageProvider : IRemoteImageProvider
{
private readonly IServerConfigurationManager _config;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
@@ -173,31 +173,5 @@ namespace MediaBrowser.Providers.TV
ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool
});
}
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- // For non-unaired items, only enable if configured
- if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
-
- if (!item.HasImage(ImageType.Primary))
- {
- var episode = (Episode)item;
-
- var series = episode.Series;
-
- if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
- {
- // Process images
- var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
-
- return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > item.DateLastRefreshed;
- }
- }
-
- return false;
- }
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
index 509b22ee6..a41a95c12 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.TV
/// <summary>
/// Class RemoteEpisodeProvider
/// </summary>
- class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo>, IHasItemChangeMonitor
+ class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>
{
private static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
@@ -144,27 +144,6 @@ namespace MediaBrowser.Providers.TV
return result;
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
-
- var episode = (Episode)item;
- var series = episode.Series;
-
- if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
- {
- // Process images
- var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
-
- return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > item.DateLastRefreshed;
- }
-
- return false;
- }
-
/// <summary>
/// Gets the episode XML files.
/// </summary>
@@ -892,86 +871,6 @@ namespace MediaBrowser.Providers.TV
});
}
- public Task Identify(EpisodeInfo info)
- {
- if (info.ProviderIds.ContainsKey(FullIdKey))
- {
- return Task.FromResult<object>(null);
- }
-
- string seriesTvdbId;
- info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId);
-
- if (string.IsNullOrEmpty(seriesTvdbId) || info.IndexNumber == null)
- {
- return Task.FromResult<object>(null);
- }
-
- var id = new Identity(seriesTvdbId, info.ParentIndexNumber, info.IndexNumber.Value, info.IndexNumberEnd);
- info.SetProviderId(FullIdKey, id.ToString());
-
- return Task.FromResult(id);
- }
-
public int Order { get { return 0; } }
-
- public struct Identity
- {
- public string SeriesId { get; private set; }
- public int? SeasonIndex { get; private set; }
- public int EpisodeNumber { get; private set; }
- public int? EpisodeNumberEnd { get; private set; }
-
- public Identity(string id)
- : this()
- {
- this = ParseIdentity(id).Value;
- }
-
- public Identity(string seriesId, int? seasonIndex, int episodeNumber, int? episodeNumberEnd)
- : this()
- {
- SeriesId = seriesId;
- SeasonIndex = seasonIndex;
- EpisodeNumber = episodeNumber;
- EpisodeNumberEnd = episodeNumberEnd;
- }
-
- public override string ToString()
- {
- return string.Format("{0}:{1}:{2}",
- SeriesId,
- SeasonIndex != null ? SeasonIndex.Value.ToString() : "A",
- EpisodeNumber + (EpisodeNumberEnd != null ? "-" + EpisodeNumberEnd.Value.ToString() : ""));
- }
-
- public static Identity? ParseIdentity(string id)
- {
- if (string.IsNullOrEmpty(id))
- return null;
-
- try {
- var parts = id.Split(':');
- var series = parts[0];
- var season = parts[1] != "A" ? (int?)int.Parse(parts[1]) : null;
-
- int index;
- int? indexEnd;
-
- if (parts[2].Contains("-")) {
- var split = parts[2].IndexOf("-", StringComparison.OrdinalIgnoreCase);
- index = int.Parse(parts[2].Substring(0, split));
- indexEnd = int.Parse(parts[2].Substring(split + 1));
- } else {
- index = int.Parse(parts[2]);
- indexEnd = null;
- }
-
- return new Identity(series, season, index, indexEnd);
- } catch {
- return null;
- }
- }
- }
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonIdentityProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonIdentityProvider.cs
deleted file mode 100644
index 4198430c9..000000000
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonIdentityProvider.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Providers.TV
-{
- public class TvdbSeasonIdentityProvider : IItemIdentityProvider<SeasonInfo>
- {
- public static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
-
- public Task Identify(SeasonInfo info)
- {
- string tvdbSeriesId;
- if (!info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out tvdbSeriesId) || string.IsNullOrEmpty(tvdbSeriesId) || info.IndexNumber == null)
- {
- return Task.FromResult<object>(null);
- }
-
- if (string.IsNullOrEmpty(info.GetProviderId(FullIdKey)))
- {
- var id = string.Format("{0}:{1}", tvdbSeriesId, info.IndexNumber.Value);
- info.SetProviderId(FullIdKey, id);
- }
-
- return Task.FromResult<object>(null);
- }
-
- public static TvdbSeasonIdentity? ParseIdentity(string id)
- {
- if (id == null)
- {
- return null;
- }
-
- try
- {
- var parts = id.Split(':');
- return new TvdbSeasonIdentity(parts[0], int.Parse(parts[1]));
- }
- catch
- {
- return null;
- }
- }
- }
-
- public struct TvdbSeasonIdentity
- {
- public string SeriesId { get; private set; }
- public int Index { get; private set; }
-
- public TvdbSeasonIdentity(string id)
- : this()
- {
- this = TvdbSeasonIdentityProvider.ParseIdentity(id).Value;
- }
-
- public TvdbSeasonIdentity(string seriesId, int index)
- : this()
- {
- SeriesId = seriesId;
- Index = index;
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
index 52d12e501..4b619665c 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
@@ -20,7 +20,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
+ public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder
{
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
@@ -70,21 +70,6 @@ namespace MediaBrowser.Providers.TV
var seriesProviderIds = series.ProviderIds;
var seasonNumber = season.IndexNumber.Value;
- var identity = TvdbSeasonIdentityProvider.ParseIdentity(season.GetProviderId(TvdbSeasonIdentityProvider.FullIdKey));
- if (identity == null)
- {
- identity = new TvdbSeasonIdentity(series.GetProviderId(MetadataProviders.Tvdb), seasonNumber);
- }
-
- if (identity != null)
- {
- var id = identity.Value;
- seasonNumber = AdjustForSeriesOffset(series, id.Index);
-
- seriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- seriesProviderIds[MetadataProviders.Tvdb.ToString()] = id.SeriesId;
- }
-
var seriesDataPath = await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesProviderIds, series.GetPreferredMetadataLanguage(), cancellationToken).ConfigureAwait(false);
if (!string.IsNullOrWhiteSpace(seriesDataPath))
@@ -362,28 +347,5 @@ namespace MediaBrowser.Providers.TV
ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool
});
}
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
-
- var season = (Season)item;
- var series = season.Series;
-
- if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
- {
- // Process images
- var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, series.ProviderIds), "banners.xml");
-
- var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
-
- return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
index d1cdc717e..c8efbfb14 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
@@ -20,7 +20,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class TvdbSeriesImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
+ public class TvdbSeriesImageProvider : IRemoteImageProvider, IHasOrder
{
private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient;
@@ -331,25 +331,5 @@ namespace MediaBrowser.Providers.TV
ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool
});
}
-
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
- {
- if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
-
- if (TvdbSeriesProvider.IsValidSeries(item.ProviderIds))
- {
- // Process images
- var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, item.ProviderIds), "banners.xml");
-
- var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
-
- return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
- }
-
- return false;
- }
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index ee1505b46..49ca5cdf2 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -25,7 +25,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IItemIdentityProvider<SeriesInfo>, IHasOrder
+ public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{
private const string TvdbSeriesOffset = "TvdbSeriesOffset";
private const string TvdbSeriesOffsetFormat = "{0}-{1}";
@@ -311,11 +311,6 @@ namespace MediaBrowser.Providers.TV
return null;
}
- public TvdbOptions GetTvDbOptions()
- {
- return _config.GetConfiguration<TvdbOptions>("tvdb");
- }
-
internal static bool IsValidSeries(Dictionary<string, string> seriesProviderIds)
{
string id;
@@ -392,27 +387,25 @@ namespace MediaBrowser.Providers.TV
var seriesXmlFilename = preferredMetadataLanguage + ".xml";
- var automaticUpdatesEnabled = GetTvDbOptions().EnableAutomaticUpdates;
-
const int cacheDays = 1;
var seriesFile = files.FirstOrDefault(i => string.Equals(seriesXmlFilename, i.Name, StringComparison.OrdinalIgnoreCase));
// No need to check age if automatic updates are enabled
- if (seriesFile == null || !seriesFile.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalDays > cacheDays))
+ if (seriesFile == null || !seriesFile.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalDays > cacheDays)
{
return false;
}
var actorsXml = files.FirstOrDefault(i => string.Equals("actors.xml", i.Name, StringComparison.OrdinalIgnoreCase));
// No need to check age if automatic updates are enabled
- if (actorsXml == null || !actorsXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalDays > cacheDays))
+ if (actorsXml == null || !actorsXml.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalDays > cacheDays)
{
return false;
}
var bannersXml = files.FirstOrDefault(i => string.Equals("banners.xml", i.Name, StringComparison.OrdinalIgnoreCase));
// No need to check age if automatic updates are enabled
- if (bannersXml == null || !bannersXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalDays > cacheDays))
+ if (bannersXml == null || !bannersXml.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalDays > cacheDays)
{
return false;
}
@@ -1450,19 +1443,4 @@ namespace MediaBrowser.Providers.TV
});
}
}
-
- public class TvdbConfigStore : IConfigurationFactory
- {
- public IEnumerable<ConfigurationStore> GetConfigurations()
- {
- return new List<ConfigurationStore>
- {
- new ConfigurationStore
- {
- Key = "tvdb",
- ConfigurationType = typeof(TvdbOptions)
- }
- };
- }
- }
}
diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs
index f5a26ba0a..2ba3b6ff6 100644
--- a/MediaBrowser.Providers/TV/TvExternalIds.cs
+++ b/MediaBrowser.Providers/TV/TvExternalIds.cs
@@ -88,7 +88,7 @@ namespace MediaBrowser.Providers.TV
public string UrlFormatString
{
- get { return null; }
+ get { return "https://thetvdb.com/index.php?tab=episode&id={0}"; }
}
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Users/UserMetadataService.cs b/MediaBrowser.Providers/Users/UserMetadataService.cs
index 90a874191..0637e9a02 100644
--- a/MediaBrowser.Providers/Users/UserMetadataService.cs
+++ b/MediaBrowser.Providers/Users/UserMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Users
{
public class UserMetadataService : MetadataService<User, ItemLookupInfo>
{
- public UserMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<User> source, MetadataResult<User> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<User> source, MetadataResult<User> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public UserMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Providers/Videos/VideoMetadataService.cs b/MediaBrowser.Providers/Videos/VideoMetadataService.cs
index fb2a7638e..a4fc462ef 100644
--- a/MediaBrowser.Providers/Videos/VideoMetadataService.cs
+++ b/MediaBrowser.Providers/Videos/VideoMetadataService.cs
@@ -12,10 +12,6 @@ namespace MediaBrowser.Providers.Videos
{
public class VideoMetadataService : MetadataService<Video, ItemLookupInfo>
{
- public VideoMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
- {
- }
-
public override int Order
{
get
@@ -29,5 +25,9 @@ namespace MediaBrowser.Providers.Videos
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
+
+ public VideoMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
}
}
diff --git a/MediaBrowser.Providers/Years/YearMetadataService.cs b/MediaBrowser.Providers/Years/YearMetadataService.cs
index 3c348b2de..fd65c379d 100644
--- a/MediaBrowser.Providers/Years/YearMetadataService.cs
+++ b/MediaBrowser.Providers/Years/YearMetadataService.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Providers.Years
{
public class YearMetadataService : MetadataService<Year, ItemLookupInfo>
{
- public YearMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
+ protected override void MergeData(MetadataResult<Year> source, MetadataResult<Year> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
{
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- protected override void MergeData(MetadataResult<Year> source, MetadataResult<Year> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ public YearMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
index b0e05a5bc..c992def39 100644
--- a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
+++ b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
@@ -15,54 +15,26 @@ namespace MediaBrowser.Server.Implementations.Activity
{
public class ActivityRepository : BaseSqliteRepository, IActivityRepository
{
- private IDbConnection _connection;
- private readonly IServerApplicationPaths _appPaths;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _saveActivityCommand;
-
- public ActivityRepository(ILogManager logManager, IServerApplicationPaths appPaths)
- : base(logManager)
+ public ActivityRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector)
+ : base(logManager, connector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "activitylog.db");
}
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "activitylog.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists ActivityLogEntries (Id GUID PRIMARY KEY, Name TEXT, Overview TEXT, ShortOverview TEXT, Type TEXT, ItemId TEXT, UserId TEXT, DateCreated DATETIME, LogSeverity TEXT)",
- "create index if not exists idx_ActivityLogEntries on ActivityLogEntries(Id)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_ActivityLogEntries on ActivityLogEntries(Id)"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _saveActivityCommand = _connection.CreateCommand();
- _saveActivityCommand.CommandText = "replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)";
-
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Id");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Name");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Overview");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@ShortOverview");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Type");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@ItemId");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@UserId");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@DateCreated");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@LogSeverity");
+ connection.RunQueries(queries, Logger);
+ }
}
private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLogEntries";
@@ -79,128 +51,145 @@ namespace MediaBrowser.Server.Implementations.Activity
throw new ArgumentNullException("entry");
}
- await WriteLock.WaitAsync().ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var saveActivityCommand = connection.CreateCommand())
+ {
+ saveActivityCommand.CommandText = "replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)";
- IDbTransaction transaction = null;
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Id");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Name");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Overview");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@ShortOverview");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Type");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@ItemId");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@UserId");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@DateCreated");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@LogSeverity");
- try
- {
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- var index = 0;
+ try
+ {
+ transaction = connection.BeginTransaction();
- _saveActivityCommand.GetParameter(index++).Value = new Guid(entry.Id);
- _saveActivityCommand.GetParameter(index++).Value = entry.Name;
- _saveActivityCommand.GetParameter(index++).Value = entry.Overview;
- _saveActivityCommand.GetParameter(index++).Value = entry.ShortOverview;
- _saveActivityCommand.GetParameter(index++).Value = entry.Type;
- _saveActivityCommand.GetParameter(index++).Value = entry.ItemId;
- _saveActivityCommand.GetParameter(index++).Value = entry.UserId;
- _saveActivityCommand.GetParameter(index++).Value = entry.Date;
- _saveActivityCommand.GetParameter(index++).Value = entry.Severity.ToString();
+ var index = 0;
- _saveActivityCommand.Transaction = transaction;
+ saveActivityCommand.GetParameter(index++).Value = new Guid(entry.Id);
+ saveActivityCommand.GetParameter(index++).Value = entry.Name;
+ saveActivityCommand.GetParameter(index++).Value = entry.Overview;
+ saveActivityCommand.GetParameter(index++).Value = entry.ShortOverview;
+ saveActivityCommand.GetParameter(index++).Value = entry.Type;
+ saveActivityCommand.GetParameter(index++).Value = entry.ItemId;
+ saveActivityCommand.GetParameter(index++).Value = entry.UserId;
+ saveActivityCommand.GetParameter(index++).Value = entry.Date;
+ saveActivityCommand.GetParameter(index++).Value = entry.Severity.ToString();
- _saveActivityCommand.ExecuteNonQuery();
+ saveActivityCommand.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ saveActivityCommand.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit)
{
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseActivitySelectText;
-
- var whereClauses = new List<string>();
-
- if (minDate.HasValue)
+ using (var cmd = connection.CreateCommand())
{
- whereClauses.Add("DateCreated>=@DateCreated");
- cmd.Parameters.Add(cmd, "@DateCreated", DbType.Date).Value = minDate.Value;
- }
+ cmd.CommandText = BaseActivitySelectText;
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ var whereClauses = new List<string>();
- if (startIndex.HasValue && startIndex.Value > 0)
- {
- var pagingWhereText = whereClauses.Count == 0 ?
+ if (minDate.HasValue)
+ {
+ whereClauses.Add("DateCreated>=@DateCreated");
+ cmd.Parameters.Add(cmd, "@DateCreated", DbType.Date).Value = minDate.Value;
+ }
+
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
-
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
- pagingWhereText,
- startIndex.Value.ToString(_usCulture)));
- }
- var whereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
-
- cmd.CommandText += whereText;
+ if (startIndex.HasValue && startIndex.Value > 0)
+ {
+ var pagingWhereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- cmd.CommandText += " ORDER BY DateCreated DESC";
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
+ pagingWhereText,
+ startIndex.Value.ToString(_usCulture)));
+ }
- if (limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + limit.Value.ToString(_usCulture);
- }
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- cmd.CommandText += "; select count (Id) from ActivityLogEntries" + whereTextWithoutPaging;
+ cmd.CommandText += whereText;
- var list = new List<ActivityLogEntry>();
- var count = 0;
+ cmd.CommandText += " ORDER BY DateCreated DESC";
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ if (limit.HasValue)
{
- list.Add(GetEntry(reader));
+ cmd.CommandText += " LIMIT " + limit.Value.ToString(_usCulture);
}
- if (reader.NextResult() && reader.Read())
+ cmd.CommandText += "; select count (Id) from ActivityLogEntries" + whereTextWithoutPaging;
+
+ var list = new List<ActivityLogEntry>();
+ var count = 0;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- count = reader.GetInt32(0);
+ while (reader.Read())
+ {
+ list.Add(GetEntry(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- }
- return new QueryResult<ActivityLogEntry>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
+ return new QueryResult<ActivityLogEntry>()
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+ }
}
}
@@ -260,19 +249,5 @@ namespace MediaBrowser.Server.Implementations.Activity
return info;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index 6a9842cb2..8dc209198 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -1307,6 +1307,7 @@ namespace MediaBrowser.Server.Implementations.Channels
item.OfficialRating = info.OfficialRating;
item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
item.Tags = info.Tags;
+ item.HomePageUrl = info.HomePageUrl;
}
var trailer = item as Trailer;
diff --git a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
index 561d46229..3e33066ae 100644
--- a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Server.Implementations.Collections
public bool IsHiddenFromUser(User user)
{
- return !user.Configuration.DisplayCollectionsView;
+ return !ConfigurationManager.Configuration.DisplayCollectionsView;
}
public override string CollectionType
diff --git a/MediaBrowser.Server.Implementations/Connect/Responses.cs b/MediaBrowser.Server.Implementations/Connect/Responses.cs
index e7c3f8154..f86527829 100644
--- a/MediaBrowser.Server.Implementations/Connect/Responses.cs
+++ b/MediaBrowser.Server.Implementations/Connect/Responses.cs
@@ -60,7 +60,6 @@ namespace MediaBrowser.Server.Implementations.Connect
{
return new ConnectUserPreferences
{
- GroupMoviesIntoBoxSets = config.GroupMoviesIntoBoxSets,
PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
SubtitleMode = config.SubtitleMode,
PreferredAudioLanguages = string.IsNullOrWhiteSpace(config.AudioLanguagePreference) ? new string[] { } : new[] { config.AudioLanguagePreference },
diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
index 947933561..3dfc04c26 100644
--- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
@@ -28,6 +28,7 @@ namespace MediaBrowser.Server.Implementations.Devices
return base.IsVisible(user) && HasChildren();
}
+ [IgnoreDataMember]
public override string CollectionType
{
get { return Model.Entities.CollectionType.Photos; }
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
index 6b1af8d2d..c3db9140c 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
@@ -51,6 +51,11 @@ namespace MediaBrowser.Server.Implementations.Devices
public async Task<DeviceInfo> RegisterDevice(string reportedId, string name, string appName, string appVersion, string usedByUserId)
{
+ if (string.IsNullOrWhiteSpace(reportedId))
+ {
+ throw new ArgumentNullException("reportedId");
+ }
+
var device = GetDevice(reportedId) ?? new DeviceInfo
{
Id = reportedId
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index dfbac47d5..95a235109 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -469,22 +469,36 @@ namespace MediaBrowser.Server.Implementations.Dto
{
if (item.IsFolder)
{
- var userData = _userDataRepository.GetUserData(user, item);
-
- // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice
- // TODO: Improve in future
- dto.UserData = GetUserItemDataDto(userData);
-
var folder = (Folder)item;
- if (item.SourceType == SourceType.Library)
+ if (fields.Contains(ItemFields.SyncInfo))
{
- dto.ChildCount = GetChildCount(folder, user);
+ var userData = _userDataRepository.GetUserData(user, item);
+
+ // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice
+ // TODO: Improve in future
+ dto.UserData = GetUserItemDataDto(userData);
- if (folder.SupportsUserDataFromChildren)
+ if (item.SourceType == SourceType.Library && folder.SupportsUserDataFromChildren)
{
SetSpecialCounts(folder, user, dto, fields, syncProgress);
}
+
+ dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100;
+ }
+ else if (item.SourceType == SourceType.Library)
+ {
+ dto.UserData = _userDataRepository.GetUserDataDto(item, user);
+ }
+ else
+ {
+ var userData = _userDataRepository.GetUserData(user, item);
+ dto.UserData = GetUserItemDataDto(userData);
+ }
+
+ if (item.SourceType == SourceType.Library)
+ {
+ dto.ChildCount = GetChildCount(folder, user);
}
if (fields.Contains(ItemFields.CumulativeRunTimeTicks))
@@ -496,8 +510,6 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.DateLastMediaAdded = folder.DateLastMediaAdded;
}
-
- dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100;
}
else
@@ -537,8 +549,7 @@ namespace MediaBrowser.Server.Implementations.Dto
private int GetChildCount(Folder folder, User user)
{
- return folder.GetChildren(user, true)
- .Count();
+ return folder.GetChildCount(user);
}
/// <summary>
@@ -969,30 +980,12 @@ namespace MediaBrowser.Server.Implementations.Dto
if (fields.Contains(ItemFields.Tags))
{
- var hasTags = item as IHasTags;
- if (hasTags != null)
- {
- dto.Tags = hasTags.Tags;
- }
-
- if (dto.Tags == null)
- {
- dto.Tags = new List<string>();
- }
+ dto.Tags = item.Tags;
}
if (fields.Contains(ItemFields.Keywords))
{
- var hasTags = item as IHasKeywords;
- if (hasTags != null)
- {
- dto.Keywords = hasTags.Keywords;
- }
-
- if (dto.Keywords == null)
- {
- dto.Keywords = new List<string>();
- }
+ dto.Keywords = item.Keywords;
}
if (fields.Contains(ItemFields.ProductionLocations))
@@ -1412,6 +1405,7 @@ namespace MediaBrowser.Server.Implementations.Dto
if (episode != null)
{
dto.IndexNumberEnd = episode.IndexNumberEnd;
+ dto.SeriesName = episode.SeriesName;
if (fields.Contains(ItemFields.AlternateEpisodeNumbers))
{
@@ -1427,74 +1421,65 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.AirsBeforeSeasonNumber = episode.AirsBeforeSeasonNumber;
}
+ var seasonId = episode.SeasonId;
+ if (seasonId.HasValue)
+ {
+ dto.SeasonId = seasonId.Value.ToString("N");
+ }
+
var episodeSeason = episode.Season;
if (episodeSeason != null)
{
- dto.SeasonId = episodeSeason.Id.ToString("N");
-
if (fields.Contains(ItemFields.SeasonName))
{
dto.SeasonName = episodeSeason.Name;
}
}
- if (fields.Contains(ItemFields.SeriesGenres))
+ var episodeSeries = episode.Series;
+
+ if (episodeSeries != null)
{
- var episodeseries = episode.Series;
- if (episodeseries != null)
+ if (fields.Contains(ItemFields.SeriesGenres))
{
- dto.SeriesGenres = episodeseries.Genres.ToList();
+ dto.SeriesGenres = episodeSeries.Genres.ToList();
}
- }
- }
-
- // Add SeriesInfo
- var series = item as Series;
- if (series != null)
- {
- dto.AirDays = series.AirDays;
- dto.AirTime = series.AirTime;
- dto.SeriesStatus = series.Status;
-
- if (fields.Contains(ItemFields.Settings))
- {
- dto.DisplaySpecialsWithSeasons = series.DisplaySpecialsWithSeasons;
- }
-
- dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
- }
-
- if (episode != null)
- {
- series = episode.Series;
- if (series != null)
- {
- dto.SeriesId = GetDtoId(series);
- dto.SeriesName = series.Name;
+ dto.SeriesId = GetDtoId(episodeSeries);
if (fields.Contains(ItemFields.AirTime))
{
- dto.AirTime = series.AirTime;
+ dto.AirTime = episodeSeries.AirTime;
}
if (options.GetImageLimit(ImageType.Thumb) > 0)
{
- dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb);
+ dto.SeriesThumbImageTag = GetImageCacheTag(episodeSeries, ImageType.Thumb);
}
if (options.GetImageLimit(ImageType.Primary) > 0)
{
- dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
+ dto.SeriesPrimaryImageTag = GetImageCacheTag(episodeSeries, ImageType.Primary);
}
if (fields.Contains(ItemFields.SeriesStudio))
{
- dto.SeriesStudio = series.Studios.FirstOrDefault();
+ dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
}
}
}
+ // Add SeriesInfo
+ var series = item as Series;
+ if (series != null)
+ {
+ dto.AirDays = series.AirDays;
+ dto.AirTime = series.AirTime;
+ dto.SeriesStatus = series.Status;
+
+ dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
+ }
+
// Add SeasonInfo
var season = item as Season;
if (season != null)
@@ -1612,12 +1597,18 @@ namespace MediaBrowser.Server.Implementations.Dto
/// <returns>Task.</returns>
private void SetSpecialCounts(Folder folder, User user, BaseItemDto dto, List<ItemFields> fields, Dictionary<string, SyncedItemProgress> syncProgress)
{
+ var addSyncInfo = fields.Contains(ItemFields.SyncInfo);
+
+ if (!addSyncInfo)
+ {
+ return;
+ }
+
var recursiveItemCount = 0;
var unplayed = 0;
double totalPercentPlayed = 0;
double totalSyncPercent = 0;
- var addSyncInfo = fields.Contains(ItemFields.SyncInfo);
var children = folder.GetItems(new InternalItemsQuery
{
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
index df6a9e654..f520316bc 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
@@ -8,6 +8,8 @@ using MediaBrowser.Model.Tasks;
using System;
using System.Linq;
using System.Threading;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Server.Implementations.EntryPoints
{
@@ -18,16 +20,18 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
private readonly ITaskManager _iTaskManager;
private readonly ISessionManager _sessionManager;
private readonly IServerConfigurationManager _config;
+ private readonly ILiveTvManager _liveTvManager;
private Timer _timer;
- public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config)
+ public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config, ILiveTvManager liveTvManager)
{
_appHost = appHost;
_logger = logger;
_iTaskManager = iTaskManager;
_sessionManager = sessionManager;
_config = config;
+ _liveTvManager = liveTvManager;
}
public void Run()
@@ -44,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
if (_appHost.HasPendingRestart)
{
- _timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
+ _timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
}
}
@@ -72,6 +76,22 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
return false;
}
+ if (_liveTvManager.Services.Count == 1)
+ {
+ try
+ {
+ var timers = _liveTvManager.GetTimers(new TimerQuery(), CancellationToken.None).Result;
+ if (timers.Items.Any(i => i.Status == RecordingStatus.InProgress))
+ {
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting timers", ex);
+ }
+ }
+
var now = DateTime.UtcNow;
return !_sessionManager.Sessions.Any(i => (now - i.LastActivityDate).TotalMinutes < 30);
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index 5777a0af7..50ad3cfbc 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -93,7 +93,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
NatUtility.UnhandledException += NatUtility_UnhandledException;
NatUtility.StartDiscovery();
- _timer = new PeriodicTimer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
+ _timer = new PeriodicTimer(ClearCreatedRules, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
_ssdp.MessageReceived += _ssdp_MessageReceived;
@@ -102,12 +102,43 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
_isStarted = true;
}
+ private void ClearCreatedRules(object state)
+ {
+ _createdRules = new List<string>();
+ _usnsHandled = new List<string>();
+ }
+
void _ssdp_MessageReceived(object sender, SsdpMessageEventArgs e)
{
var endpoint = e.EndPoint as IPEndPoint;
- if (endpoint != null && e.LocalEndPoint != null)
+ if (endpoint == null || e.LocalEndPoint == null)
{
+ return;
+ }
+
+ string usn;
+ if (!e.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
+
+ string nt;
+ if (!e.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
+
+ // Filter device type
+ if (usn.IndexOf("WANIPConnection:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ nt.IndexOf("WANIPConnection:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ usn.IndexOf("WANPPPConnection:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ nt.IndexOf("WANPPPConnection:", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ return;
+ }
+
+ var identifier = string.IsNullOrWhiteSpace(usn) ? nt : usn;
+
+ if (!_usnsHandled.Contains(identifier))
+ {
+ _usnsHandled.Add(identifier);
+
+ _logger.Debug("Calling Nat.Handle on " + identifier);
NatUtility.Handle(e.LocalEndPoint.Address, e.Message, endpoint, NatProtocol.Upnp);
}
}
@@ -151,6 +182,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
}
private List<string> _createdRules = new List<string>();
+ private List<string> _usnsHandled = new List<string>();
private void CreateRules(INatDevice device)
{
// On some systems the device discovered event seems to fire repeatedly
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs
new file mode 100644
index 000000000..cc4ef1972
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.EntryPoints
+{
+ public class RecordingNotifier : IServerEntryPoint
+ {
+ private readonly ILiveTvManager _liveTvManager;
+ private readonly ISessionManager _sessionManager;
+ private readonly IUserManager _userManager;
+ private readonly ILogger _logger;
+
+ public RecordingNotifier(ISessionManager sessionManager, IUserManager userManager, ILogger logger, ILiveTvManager liveTvManager)
+ {
+ _sessionManager = sessionManager;
+ _userManager = userManager;
+ _logger = logger;
+ _liveTvManager = liveTvManager;
+ }
+
+ public void Run()
+ {
+ _liveTvManager.TimerCancelled += _liveTvManager_TimerCancelled;
+ _liveTvManager.SeriesTimerCancelled += _liveTvManager_SeriesTimerCancelled;
+ _liveTvManager.TimerCreated += _liveTvManager_TimerCreated;
+ _liveTvManager.SeriesTimerCreated += _liveTvManager_SeriesTimerCreated;
+ }
+
+ private void _liveTvManager_SeriesTimerCreated(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("SeriesTimerCreated", e.Argument);
+ }
+
+ private void _liveTvManager_TimerCreated(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("TimerCreated", e.Argument);
+ }
+
+ private void _liveTvManager_SeriesTimerCancelled(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("SeriesTimerCancelled", e.Argument);
+ }
+
+ private void _liveTvManager_TimerCancelled(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("TimerCancelled", e.Argument);
+ }
+
+ private async void SendMessage(string name, TimerEventInfo info)
+ {
+ var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).ToList();
+
+ foreach (var user in users)
+ {
+ try
+ {
+ await _sessionManager.SendMessageToUserSessions<TimerEventInfo>(user.Id.ToString("N"), name, info, CancellationToken.None);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error sending message", ex);
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ _liveTvManager.TimerCancelled -= _liveTvManager_TimerCancelled;
+ _liveTvManager.SeriesTimerCancelled -= _liveTvManager_SeriesTimerCancelled;
+ _liveTvManager.TimerCreated -= _liveTvManager_TimerCreated;
+ _liveTvManager.SeriesTimerCreated -= _liveTvManager_SeriesTimerCreated;
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index 83801b3e7..2109f8d59 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -562,9 +562,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Series).Name },
- Recursive = true
- }).Cast<Series>()
- .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase));
+ Recursive = true,
+ Name = info.ItemName
+
+ }).Cast<Series>().FirstOrDefault();
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index c5cb810e5..f091f0f1f 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -106,7 +106,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
});
- HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger, () => _config.Configuration.DenyIFrameEmbedding).FilterResponse);
+ HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
}
public override void OnAfterInit()
diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
index ce8100025..bfbb228ed 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration)
{
var durationMs = duration.TotalMilliseconds;
- var logSuffix = durationMs >= 1000 ? "ms (slow)" : "ms";
+ var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url);
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs
index f993d4437..ee05702f4 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs
@@ -12,12 +12,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
private readonly ILogger _logger;
- private readonly Func<bool> _denyIframeEmbedding;
- public ResponseFilter(ILogger logger, Func<bool> denyIframeEmbedding)
+ public ResponseFilter(ILogger logger)
{
_logger = logger;
- _denyIframeEmbedding = denyIframeEmbedding;
}
/// <summary>
@@ -31,11 +29,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
// Try to prevent compatibility view
res.AddHeader("X-UA-Compatible", "IE=Edge");
- if (_denyIframeEmbedding())
- {
- res.AddHeader("X-Frame-Options", "SAMEORIGIN");
- }
-
var exception = dto as Exception;
if (exception != null)
diff --git a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
new file mode 100644
index 000000000..4bea6ad34
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
@@ -0,0 +1,289 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Implementations.ScheduledTasks;
+
+namespace MediaBrowser.Server.Implementations.IO
+{
+ public class FileRefresher : IDisposable
+ {
+ private ILogger Logger { get; set; }
+ private ITaskManager TaskManager { get; set; }
+ private ILibraryManager LibraryManager { get; set; }
+ private IServerConfigurationManager ConfigurationManager { get; set; }
+ private readonly IFileSystem _fileSystem;
+ private readonly List<string> _affectedPaths = new List<string>();
+ private Timer _timer;
+ private readonly object _timerLock = new object();
+ public string Path { get; private set; }
+
+ public event EventHandler<EventArgs> Completed;
+
+ public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger)
+ {
+ logger.Debug("New file refresher created for {0}", path);
+ Path = path;
+ _affectedPaths.Add(path);
+
+ _fileSystem = fileSystem;
+ ConfigurationManager = configurationManager;
+ LibraryManager = libraryManager;
+ TaskManager = taskManager;
+ Logger = logger;
+ }
+
+ private void AddAffectedPath(string path)
+ {
+ if (!_affectedPaths.Contains(path, StringComparer.Ordinal))
+ {
+ _affectedPaths.Add(path);
+ }
+ }
+
+ public void AddPath(string path)
+ {
+ lock (_timerLock)
+ {
+ AddAffectedPath(path);
+ }
+ RestartTimer();
+ }
+
+ public void RestartTimer()
+ {
+ lock (_timerLock)
+ {
+ if (_timer == null)
+ {
+ _timer = new Timer(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ }
+ else
+ {
+ _timer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ }
+ }
+ }
+
+ public void ResetPath(string path, string affectedFile)
+ {
+ lock (_timerLock)
+ {
+ Logger.Debug("Resetting file refresher from {0} to {1}", Path, path);
+
+ Path = path;
+ AddAffectedPath(path);
+
+ if (!string.IsNullOrWhiteSpace(affectedFile))
+ {
+ AddAffectedPath(affectedFile);
+ }
+ }
+ RestartTimer();
+ }
+
+ private async void OnTimerCallback(object state)
+ {
+ List<string> paths;
+
+ lock (_timerLock)
+ {
+ paths = _affectedPaths.ToList();
+ }
+
+ // Extend the timer as long as any of the paths are still being written to.
+ if (paths.Any(IsFileLocked))
+ {
+ Logger.Info("Timer extended.");
+ RestartTimer();
+ return;
+ }
+
+ Logger.Debug("Timer stopped.");
+
+ DisposeTimer();
+ EventHelper.FireEventIfNotNull(Completed, this, EventArgs.Empty, Logger);
+
+ try
+ {
+ await ProcessPathChanges(paths.ToList()).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error processing directory changes", ex);
+ }
+ }
+
+ private async Task ProcessPathChanges(List<string> paths)
+ {
+ var itemsToRefresh = paths
+ .Select(GetAffectedBaseItem)
+ .Where(item => item != null)
+ .Distinct()
+ .ToList();
+
+ foreach (var p in paths)
+ {
+ Logger.Info(p + " reports change.");
+ }
+
+ // If the root folder changed, run the library task so the user can see it
+ if (itemsToRefresh.Any(i => i is AggregateFolder))
+ {
+ TaskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
+ return;
+ }
+
+ foreach (var item in itemsToRefresh)
+ {
+ Logger.Info(item.Name + " (" + item.Path + ") will be refreshed.");
+
+ try
+ {
+ await item.ChangedExternally().ConfigureAwait(false);
+ }
+ catch (IOException ex)
+ {
+ // For now swallow and log.
+ // Research item: If an IOException occurs, the item may be in a disconnected state (media unavailable)
+ // Should we remove it from it's parent?
+ Logger.ErrorException("Error refreshing {0}", ex, item.Name);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error refreshing {0}", ex, item.Name);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the affected base item.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>BaseItem.</returns>
+ private BaseItem GetAffectedBaseItem(string path)
+ {
+ BaseItem item = null;
+
+ while (item == null && !string.IsNullOrEmpty(path))
+ {
+ item = LibraryManager.FindByPath(path, null);
+
+ path = System.IO.Path.GetDirectoryName(path);
+ }
+
+ if (item != null)
+ {
+ // If the item has been deleted find the first valid parent that still exists
+ while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
+ {
+ item = item.GetParent();
+
+ if (item == null)
+ {
+ break;
+ }
+ }
+ }
+
+ return item;
+ }
+
+ private bool IsFileLocked(string path)
+ {
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT)
+ {
+ // Causing lockups on linux
+ return false;
+ }
+
+ try
+ {
+ var data = _fileSystem.GetFileSystemInfo(path);
+
+ if (!data.Exists
+ || data.IsDirectory
+
+ // Opening a writable stream will fail with readonly files
+ || data.Attributes.HasFlag(FileAttributes.ReadOnly))
+ {
+ return false;
+ }
+ }
+ catch (IOException)
+ {
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error getting file system info for: {0}", ex, path);
+ return false;
+ }
+
+ // In order to determine if the file is being written to, we have to request write access
+ // But if the server only has readonly access, this is going to cause this entire algorithm to fail
+ // So we'll take a best guess about our access level
+ var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta
+ ? FileAccess.ReadWrite
+ : FileAccess.Read;
+
+ try
+ {
+ using (_fileSystem.GetFileStream(path, FileMode.Open, requestedFileAccess, FileShare.ReadWrite))
+ {
+ //file is not locked
+ return false;
+ }
+ }
+ catch (DirectoryNotFoundException)
+ {
+ // File may have been deleted
+ return false;
+ }
+ catch (FileNotFoundException)
+ {
+ // File may have been deleted
+ return false;
+ }
+ catch (IOException)
+ {
+ //the file is unavailable because it is:
+ //still being written to
+ //or being processed by another thread
+ //or does not exist (has already been processed)
+ Logger.Debug("{0} is locked.", path);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error determining if file is locked: {0}", ex, path);
+ return false;
+ }
+ }
+
+ private void DisposeTimer()
+ {
+ lock (_timerLock)
+ {
+ if (_timer != null)
+ {
+ _timer.Dispose();
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ DisposeTimer();
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 09ca134d1..0690d62dd 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -26,13 +26,9 @@ namespace MediaBrowser.Server.Implementations.IO
/// </summary>
private readonly ConcurrentDictionary<string, FileSystemWatcher> _fileSystemWatchers = new ConcurrentDictionary<string, FileSystemWatcher>(StringComparer.OrdinalIgnoreCase);
/// <summary>
- /// The update timer
- /// </summary>
- private Timer _updateTimer;
- /// <summary>
/// The affected paths
/// </summary>
- private readonly ConcurrentDictionary<string, string> _affectedPaths = new ConcurrentDictionary<string, string>();
+ private readonly List<FileRefresher> _activeRefreshers = new List<FileRefresher>();
/// <summary>
/// A dynamic list of paths that should be ignored. Added to during our own file sytem modifications.
@@ -44,8 +40,8 @@ namespace MediaBrowser.Server.Implementations.IO
/// </summary>
private readonly IReadOnlyList<string> _alwaysIgnoreFiles = new List<string>
{
- "thumbs.db",
- "small.jpg",
+ "thumbs.db",
+ "small.jpg",
"albumart.jpg",
// WMC temp recording directories that will constantly be written to
@@ -54,11 +50,6 @@ namespace MediaBrowser.Server.Implementations.IO
};
/// <summary>
- /// The timer lock
- /// </summary>
- private readonly object _timerLock = new object();
-
- /// <summary>
/// Add the path to our temporary ignore list. Use when writing to a path within our listening scope.
/// </summary>
/// <param name="path">The path.</param>
@@ -463,226 +454,58 @@ namespace MediaBrowser.Server.Implementations.IO
if (monitorPath)
{
// Avoid implicitly captured closure
- var affectedPath = path;
- _affectedPaths.AddOrUpdate(path, path, (key, oldValue) => affectedPath);
- }
-
- RestartTimer();
- }
-
- private void RestartTimer()
- {
- lock (_timerLock)
- {
- if (_updateTimer == null)
- {
- _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
- }
- else
- {
- _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
- }
- }
- }
-
- /// <summary>
- /// Timers the stopped.
- /// </summary>
- /// <param name="stateInfo">The state info.</param>
- private async void TimerStopped(object stateInfo)
- {
- // Extend the timer as long as any of the paths are still being written to.
- if (_affectedPaths.Any(p => IsFileLocked(p.Key)))
- {
- Logger.Info("Timer extended.");
- RestartTimer();
- return;
- }
-
- Logger.Debug("Timer stopped.");
-
- DisposeTimer();
-
- var paths = _affectedPaths.Keys.ToList();
- _affectedPaths.Clear();
-
- try
- {
- await ProcessPathChanges(paths).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error processing directory changes", ex);
+ CreateRefresher(path);
}
}
- private bool IsFileLocked(string path)
+ private void CreateRefresher(string path)
{
- if (Environment.OSVersion.Platform != PlatformID.Win32NT)
- {
- // Causing lockups on linux
- return false;
- }
+ var parentPath = Path.GetDirectoryName(path);
- try
+ lock (_activeRefreshers)
{
- var data = _fileSystem.GetFileSystemInfo(path);
-
- if (!data.Exists
- || data.IsDirectory
-
- // Opening a writable stream will fail with readonly files
- || data.Attributes.HasFlag(FileAttributes.ReadOnly))
+ var refreshers = _activeRefreshers.ToList();
+ foreach (var refresher in refreshers)
{
- return false;
- }
- }
- catch (IOException)
- {
- return false;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error getting file system info for: {0}", ex, path);
- return false;
- }
-
- // In order to determine if the file is being written to, we have to request write access
- // But if the server only has readonly access, this is going to cause this entire algorithm to fail
- // So we'll take a best guess about our access level
- var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta
- ? FileAccess.ReadWrite
- : FileAccess.Read;
+ // Path is already being refreshed
+ if (string.Equals(path, refresher.Path, StringComparison.Ordinal))
+ {
+ refresher.RestartTimer();
+ return;
+ }
- try
- {
- using (_fileSystem.GetFileStream(path, FileMode.Open, requestedFileAccess, FileShare.ReadWrite))
- {
- if (_updateTimer != null)
+ // Parent folder is already being refreshed
+ if (_fileSystem.ContainsSubPath(refresher.Path, path))
{
- //file is not locked
- return false;
+ refresher.AddPath(path);
+ return;
}
- }
- }
- catch (DirectoryNotFoundException)
- {
- // File may have been deleted
- return false;
- }
- catch (FileNotFoundException)
- {
- // File may have been deleted
- return false;
- }
- catch (IOException)
- {
- //the file is unavailable because it is:
- //still being written to
- //or being processed by another thread
- //or does not exist (has already been processed)
- Logger.Debug("{0} is locked.", path);
- return true;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error determining if file is locked: {0}", ex, path);
- return false;
- }
- return false;
- }
+ // New path is a parent
+ if (_fileSystem.ContainsSubPath(path, refresher.Path))
+ {
+ refresher.ResetPath(path, null);
+ return;
+ }
- private void DisposeTimer()
- {
- lock (_timerLock)
- {
- if (_updateTimer != null)
- {
- _updateTimer.Dispose();
- _updateTimer = null;
+ // They are siblings. Rebase the refresher to the parent folder.
+ if (string.Equals(parentPath, Path.GetDirectoryName(refresher.Path), StringComparison.Ordinal))
+ {
+ refresher.ResetPath(parentPath, path);
+ return;
+ }
}
- }
- }
-
- /// <summary>
- /// Processes the path changes.
- /// </summary>
- /// <param name="paths">The paths.</param>
- /// <returns>Task.</returns>
- private async Task ProcessPathChanges(List<string> paths)
- {
- var itemsToRefresh = paths
- .Select(GetAffectedBaseItem)
- .Where(item => item != null)
- .Distinct()
- .ToList();
-
- foreach (var p in paths)
- {
- Logger.Info(p + " reports change.");
- }
-
- // If the root folder changed, run the library task so the user can see it
- if (itemsToRefresh.Any(i => i is AggregateFolder))
- {
- TaskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
- return;
- }
-
- foreach (var item in itemsToRefresh)
- {
- Logger.Info(item.Name + " (" + item.Path + ") will be refreshed.");
- try
- {
- await item.ChangedExternally().ConfigureAwait(false);
- }
- catch (IOException ex)
- {
- // For now swallow and log.
- // Research item: If an IOException occurs, the item may be in a disconnected state (media unavailable)
- // Should we remove it from it's parent?
- Logger.ErrorException("Error refreshing {0}", ex, item.Name);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error refreshing {0}", ex, item.Name);
- }
+ var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger);
+ newRefresher.Completed += NewRefresher_Completed;
+ _activeRefreshers.Add(newRefresher);
}
}
- /// <summary>
- /// Gets the affected base item.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>BaseItem.</returns>
- private BaseItem GetAffectedBaseItem(string path)
+ private void NewRefresher_Completed(object sender, EventArgs e)
{
- BaseItem item = null;
-
- while (item == null && !string.IsNullOrEmpty(path))
- {
- item = LibraryManager.FindByPath(path, null);
-
- path = Path.GetDirectoryName(path);
- }
-
- if (item != null)
- {
- // If the item has been deleted find the first valid parent that still exists
- while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
- {
- item = item.GetParent();
-
- if (item == null)
- {
- break;
- }
- }
- }
-
- return item;
+ var refresher = (FileRefresher)sender;
+ DisposeRefresher(refresher);
}
/// <summary>
@@ -713,10 +536,29 @@ namespace MediaBrowser.Server.Implementations.IO
watcher.Dispose();
}
- DisposeTimer();
-
_fileSystemWatchers.Clear();
- _affectedPaths.Clear();
+ DisposeRefreshers();
+ }
+
+ private void DisposeRefresher(FileRefresher refresher)
+ {
+ lock (_activeRefreshers)
+ {
+ refresher.Dispose();
+ _activeRefreshers.Remove(refresher);
+ }
+ }
+
+ private void DisposeRefreshers()
+ {
+ lock (_activeRefreshers)
+ {
+ foreach (var refresher in _activeRefreshers.ToList())
+ {
+ refresher.Dispose();
+ }
+ _activeRefreshers.Clear();
+ }
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
index 49012c65a..7c7a535cd 100644
--- a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
+++ b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
@@ -63,16 +63,8 @@ namespace MediaBrowser.Server.Implementations.Intros
? null
: _localization.GetRatingLevel(item.OfficialRating);
- var random = new Random(Environment.TickCount + Guid.NewGuid().GetHashCode());
-
var candidates = new List<ItemWithTrailer>();
- var itemPeople = _libraryManager.GetPeople(item);
- var allPeople = _libraryManager.GetPeople(new InternalPeopleQuery
- {
- AppearsInItemId = item.Id
- });
-
var trailerTypes = new List<TrailerType>();
if (config.EnableIntrosFromMoviesInLibrary)
@@ -105,26 +97,25 @@ namespace MediaBrowser.Server.Implementations.Intros
var trailerResult = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Trailer).Name },
- TrailerTypes = trailerTypes.ToArray()
+ TrailerTypes = trailerTypes.ToArray(),
+ SimilarTo = item,
+ IsPlayed = config.EnableIntrosForWatchedContent ? (bool?) null : false,
+ MaxParentalRating = config.EnableIntrosParentalControl ? ratingLevel : null,
+ Limit = config.TrailerLimit
});
candidates.AddRange(trailerResult.Select(i => new ItemWithTrailer
{
Item = i,
Type = i.SourceType == SourceType.Channel ? ItemWithTrailerType.ChannelTrailer : ItemWithTrailerType.ItemWithTrailer,
- User = user,
- WatchingItem = item,
- WatchingItemPeople = itemPeople,
- AllPeople = allPeople,
- Random = random,
LibraryManager = _libraryManager
}));
}
- return GetResult(item, candidates, config, ratingLevel);
+ return GetResult(item, candidates, config);
}
- private IEnumerable<IntroInfo> GetResult(BaseItem item, IEnumerable<ItemWithTrailer> candidates, CinemaModeConfiguration config, int? ratingLevel)
+ private IEnumerable<IntroInfo> GetResult(BaseItem item, IEnumerable<ItemWithTrailer> candidates, CinemaModeConfiguration config)
{
var customIntros = !string.IsNullOrWhiteSpace(config.CustomIntroPath) ?
GetCustomIntros(config) :
@@ -134,48 +125,12 @@ namespace MediaBrowser.Server.Implementations.Intros
GetMediaInfoIntros(config, item) :
new List<IntroInfo>();
- var trailerLimit = config.TrailerLimit;
-
// Avoid implicitly captured closure
- return candidates.Where(i =>
- {
- if (config.EnableIntrosParentalControl && !FilterByParentalRating(ratingLevel, i.Item))
- {
- return false;
- }
-
- if (!config.EnableIntrosForWatchedContent && i.IsPlayed)
- {
- return false;
- }
- return !IsDuplicate(item, i.Item);
- })
- .OrderByDescending(i => i.Score)
- .ThenBy(i => Guid.NewGuid())
- .ThenByDescending(i => i.IsPlayed ? 0 : 1)
- .Select(i => i.IntroInfo)
- .Take(trailerLimit)
+ return candidates.Select(i => i.IntroInfo)
.Concat(customIntros.Take(1))
.Concat(mediaInfoIntros);
}
- private bool IsDuplicate(BaseItem playingContent, BaseItem test)
- {
- var id = playingContent.GetProviderId(MetadataProviders.Imdb);
- if (!string.IsNullOrWhiteSpace(id) && string.Equals(id, test.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- id = playingContent.GetProviderId(MetadataProviders.Tmdb);
- if (!string.IsNullOrWhiteSpace(id) && string.Equals(id, test.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- return false;
- }
-
private CinemaModeConfiguration GetOptions()
{
return _serverConfig.GetConfiguration<CinemaModeConfiguration>("cinemamode");
@@ -346,102 +301,6 @@ namespace MediaBrowser.Server.Implementations.Intros
return list.Distinct(StringComparer.OrdinalIgnoreCase);
}
- private bool FilterByParentalRating(int? ratingLevel, BaseItem item)
- {
- // Only content rated same or lower
- if (ratingLevel.HasValue)
- {
- var level = string.IsNullOrWhiteSpace(item.OfficialRating)
- ? (int?)null
- : _localization.GetRatingLevel(item.OfficialRating);
-
- return level.HasValue && level.Value <= ratingLevel.Value;
- }
-
- return true;
- }
-
- internal static int GetSimiliarityScore(BaseItem item1, List<PersonInfo> item1People, List<PersonInfo> allPeople, BaseItem item2, Random random, ILibraryManager libraryManager)
- {
- var points = 0;
-
- if (!string.IsNullOrEmpty(item1.OfficialRating) && string.Equals(item1.OfficialRating, item2.OfficialRating, StringComparison.OrdinalIgnoreCase))
- {
- points += 10;
- }
-
- // Find common genres
- points += item1.Genres.Where(i => item2.Genres.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
-
- // Find common tags
- points += GetTags(item1).Where(i => GetTags(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
-
- // Find common keywords
- points += GetKeywords(item1).Where(i => GetKeywords(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
-
- // Find common studios
- points += item1.Studios.Where(i => item2.Studios.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 5);
-
- var item2PeopleNames = allPeople.Where(i => i.ItemId == item2.Id)
- .Select(i => i.Name)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .DistinctNames()
- .ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- points += item1People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i =>
- {
- if (string.Equals(i.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase))
- {
- return 5;
- }
- if (string.Equals(i.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Actor, StringComparison.OrdinalIgnoreCase))
- {
- return 3;
- }
- if (string.Equals(i.Type, PersonType.Composer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Composer, StringComparison.OrdinalIgnoreCase))
- {
- return 3;
- }
- if (string.Equals(i.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
- {
- return 3;
- }
- if (string.Equals(i.Type, PersonType.Writer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase))
- {
- return 2;
- }
-
- return 1;
- });
-
- // Add some randomization so that you're not always seeing the same ones for a given movie
- points += random.Next(0, 50);
-
- return points;
- }
-
- private static IEnumerable<string> GetTags(BaseItem item)
- {
- var hasTags = item as IHasTags;
- if (hasTags != null)
- {
- return hasTags.Tags;
- }
-
- return new List<string>();
- }
-
- private static IEnumerable<string> GetKeywords(BaseItem item)
- {
- var hasTags = item as IHasKeywords;
- if (hasTags != null)
- {
- return hasTags.Keywords;
- }
-
- return new List<string>();
- }
-
public IEnumerable<string> GetAllIntroFiles()
{
return GetCustomIntroFiles(GetOptions(), true, true);
@@ -461,39 +320,8 @@ namespace MediaBrowser.Server.Implementations.Intros
{
internal BaseItem Item;
internal ItemWithTrailerType Type;
- internal User User;
- internal BaseItem WatchingItem;
- internal List<PersonInfo> WatchingItemPeople;
- internal List<PersonInfo> AllPeople;
- internal Random Random;
internal ILibraryManager LibraryManager;
- private bool? _isPlayed;
- public bool IsPlayed
- {
- get
- {
- if (!_isPlayed.HasValue)
- {
- _isPlayed = Item.IsPlayed(User);
- }
- return _isPlayed.Value;
- }
- }
-
- private int? _score;
- public int Score
- {
- get
- {
- if (!_score.HasValue)
- {
- _score = GetSimiliarityScore(WatchingItem, WatchingItemPeople, AllPeople, Item, Random, LibraryManager);
- }
- return _score.Value;
- }
- }
-
public IntroInfo IntroInfo
{
get
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 56d3bd4de..c0c40aa5b 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -362,6 +362,10 @@ namespace MediaBrowser.Server.Implementations.Library
return;
}
}
+ if (item is Photo)
+ {
+ return;
+ }
//if (!(item is Folder))
//{
// return;
@@ -1272,18 +1276,9 @@ namespace MediaBrowser.Server.Implementations.Library
return item;
}
- public BaseItem GetMemoryItemById(Guid id)
+ private bool EnableCaching
{
- if (id == Guid.Empty)
- {
- throw new ArgumentNullException("id");
- }
-
- BaseItem item;
-
- LibraryItemsCache.TryGetValue(id, out item);
-
- return item;
+ get { return true; }
}
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
@@ -1293,6 +1288,11 @@ namespace MediaBrowser.Server.Implementations.Library
AddUserToQuery(query, query.User);
}
+ if (!EnableCaching)
+ {
+ return ItemRepository.GetItemList(query);
+ }
+
var result = ItemRepository.GetItemIdsList(query);
return result.Select(GetItemById).Where(i => i != null);
@@ -1305,7 +1305,15 @@ namespace MediaBrowser.Server.Implementations.Library
AddUserToQuery(query, query.User);
}
- return ItemRepository.GetItems(query);
+ if (query.EnableTotalRecordCount)
+ {
+ return ItemRepository.GetItems(query);
+ }
+
+ return new QueryResult<BaseItem>
+ {
+ Items = ItemRepository.GetItemList(query).ToArray()
+ };
}
public List<Guid> GetItemIds(InternalItemsQuery query)
@@ -1324,6 +1332,11 @@ namespace MediaBrowser.Server.Implementations.Library
SetTopParentIdsOrAncestors(query, parents);
+ if (!EnableCaching)
+ {
+ return ItemRepository.GetItemList(query);
+ }
+
return GetItemIds(query).Select(GetItemById).Where(i => i != null);
}
@@ -1346,6 +1359,11 @@ namespace MediaBrowser.Server.Implementations.Library
if (query.EnableTotalRecordCount)
{
+ if (!EnableCaching)
+ {
+ return ItemRepository.GetItems(query);
+ }
+
var initialResult = ItemRepository.GetItemIds(query);
return new QueryResult<BaseItem>
@@ -1355,6 +1373,14 @@ namespace MediaBrowser.Server.Implementations.Library
};
}
+ if (!EnableCaching)
+ {
+ return new QueryResult<BaseItem>
+ {
+ Items = ItemRepository.GetItemList(query).ToArray()
+ };
+ }
+
return new QueryResult<BaseItem>
{
Items = ItemRepository.GetItemIdsList(query).Select(GetItemById).Where(i => i != null).ToArray()
@@ -2309,7 +2335,7 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
- var files = fileSystemChildren.Where(i => i.IsDirectory)
+ var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
.SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
.ToList();
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index 0ef7efe1b..1bcb02ac3 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -73,6 +73,10 @@ namespace MediaBrowser.Server.Implementations.Library
{
return false;
}
+ if (string.Equals(stream.Codec, "ssa", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
return true;
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index e62049821..14e5e446b 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -1,6 +1,9 @@
-using MediaBrowser.Controller.Entities.TV;
+using System;
+using System.IO;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using System.Linq;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{
@@ -37,7 +40,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
}
// If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something
- if (season != null || args.HasParent<Series>())
+ // Also handle flat tv folders
+ if (season != null || args.HasParent<Series>() || string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
var episode = ResolveVideo<Episode>(args, false);
diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
index e271fbcb2..262178790 100644
--- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
+++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
@@ -122,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.Library
AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name);
}
- if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase)))
+ if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase) || includeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase)))
{
if (!query.IncludeMedia)
{
diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
index 0e211937f..3dad7e7fc 100644
--- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
@@ -23,7 +23,8 @@ namespace MediaBrowser.Server.Implementations.Library
{
public event EventHandler<UserDataSaveEventArgs> UserDataSaved;
- private readonly Dictionary<string, UserItemData> _userData = new Dictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, UserItemData> _userData =
+ new ConcurrentDictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
@@ -64,13 +65,6 @@ namespace MediaBrowser.Server.Implementations.Library
try
{
await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
-
- var newValue = userData;
-
- lock (_userData)
- {
- _userData[GetCacheKey(userId, key)] = newValue;
- }
}
catch (Exception ex)
{
@@ -80,6 +74,9 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
+ var cacheKey = GetCacheKey(userId, item.Id);
+ _userData.AddOrUpdate(cacheKey, userData, (k, v) => userData);
+
EventHelper.FireEventIfNotNull(UserDataSaved, this, new UserDataSaveEventArgs
{
Keys = keys,
@@ -122,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw;
}
-
+
}
/// <summary>
@@ -140,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Library
return Repository.GetAllUserData(userId);
}
- public UserItemData GetUserData(Guid userId, List<string> keys)
+ public UserItemData GetUserData(Guid userId, Guid itemId, List<string> keys)
{
if (userId == Guid.Empty)
{
@@ -150,95 +147,44 @@ namespace MediaBrowser.Server.Implementations.Library
{
throw new ArgumentNullException("keys");
}
-
- lock (_userData)
+ if (keys.Count == 0)
{
- foreach (var key in keys)
- {
- var cacheKey = GetCacheKey(userId, key);
- UserItemData value;
- if (_userData.TryGetValue(cacheKey, out value))
- {
- return value;
- }
-
- value = Repository.GetUserData(userId, key);
-
- if (value != null)
- {
- _userData[cacheKey] = value;
- return value;
- }
- }
+ throw new ArgumentException("UserData keys cannot be empty.");
+ }
- if (keys.Count > 0)
- {
- var key = keys[0];
- var cacheKey = GetCacheKey(userId, key);
- var userdata = new UserItemData
- {
- UserId = userId,
- Key = key
- };
- _userData[cacheKey] = userdata;
- return userdata;
- }
+ var cacheKey = GetCacheKey(userId, itemId);
- return null;
- }
+ return _userData.GetOrAdd(cacheKey, k => GetUserDataInternal(userId, keys));
}
- /// <summary>
- /// Gets the user data.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="key">The key.</param>
- /// <returns>Task{UserItemData}.</returns>
- public UserItemData GetUserData(Guid userId, string key)
+ private UserItemData GetUserDataInternal(Guid userId, List<string> keys)
{
- if (userId == Guid.Empty)
- {
- throw new ArgumentNullException("userId");
- }
- if (string.IsNullOrEmpty(key))
+ var userData = Repository.GetUserData(userId, keys);
+
+ if (userData != null)
{
- throw new ArgumentNullException("key");
+ return userData;
}
- lock (_userData)
+ if (keys.Count > 0)
{
- var cacheKey = GetCacheKey(userId, key);
- UserItemData value;
- if (_userData.TryGetValue(cacheKey, out value))
+ return new UserItemData
{
- return value;
- }
-
- value = Repository.GetUserData(userId, key);
-
- if (value == null)
- {
- value = new UserItemData
- {
- UserId = userId,
- Key = key
- };
- }
-
- _userData[cacheKey] = value;
- return value;
+ UserId = userId,
+ Key = keys[0]
+ };
}
+
+ return null;
}
/// <summary>
/// Gets the internal key.
/// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="key">The key.</param>
/// <returns>System.String.</returns>
- private string GetCacheKey(Guid userId, string key)
+ private string GetCacheKey(Guid userId, Guid itemId)
{
- return userId + key;
+ return userId.ToString("N") + itemId.ToString("N");
}
public UserItemData GetUserData(IHasUserData user, IHasUserData item)
@@ -253,7 +199,7 @@ namespace MediaBrowser.Server.Implementations.Library
public UserItemData GetUserData(Guid userId, IHasUserData item)
{
- return GetUserData(userId, item.GetUserDataKeys());
+ return GetUserData(userId, item.Id, item.GetUserDataKeys());
}
public UserItemDataDto GetUserDataDto(IHasUserData item, User user)
@@ -262,7 +208,6 @@ namespace MediaBrowser.Server.Implementations.Library
var dto = GetUserItemDataDto(userData);
item.FillUserDataDtoValues(dto, userData, user);
-
return dto;
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index 1bba20ec5..319e715c3 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -105,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- if (user.Configuration.DisplayFoldersView)
+ if (_config.Configuration.EnableFolderView)
{
var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders);
list.Add(await _libraryManager.GetNamedView(name, CollectionType.Folders, string.Empty, cancellationToken).ConfigureAwait(false));
@@ -202,23 +202,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
var user = _userManager.GetUserById(request.UserId);
- var includeTypes = request.IncludeItemTypes;
-
- var currentUser = user;
-
- var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes, request.Limit ?? 10).Where(i =>
- {
- if (request.IsPlayed.HasValue)
- {
- var val = request.IsPlayed.Value;
- if (i is Video && i.IsPlayed(currentUser) != val)
- {
- return false;
- }
- }
-
- return true;
- });
+ var libraryItems = GetItemsForLatestItems(user, request);
var list = new List<Tuple<BaseItem, List<BaseItem>>>();
@@ -254,8 +238,13 @@ namespace MediaBrowser.Server.Implementations.Library
return list;
}
- private IEnumerable<BaseItem> GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes, int limit)
+ private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request)
{
+ var parentId = request.ParentId;
+
+ var includeItemTypes = request.IncludeItemTypes;
+ var limit = request.Limit ?? 10;
+
var parentIds = string.IsNullOrEmpty(parentId)
? new string[] { }
: new[] { parentId };
@@ -276,7 +265,12 @@ namespace MediaBrowser.Server.Implementations.Library
var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
{
- typeof(Person).Name, typeof(Studio).Name, typeof(Year).Name, typeof(GameGenre).Name, typeof(MusicGenre).Name, typeof(Genre).Name
+ typeof(Person).Name,
+ typeof(Studio).Name,
+ typeof(Year).Name,
+ typeof(GameGenre).Name,
+ typeof(MusicGenre).Name,
+ typeof(Genre).Name
} : new string[] { };
@@ -288,8 +282,9 @@ namespace MediaBrowser.Server.Implementations.Library
IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
ExcludeItemTypes = excludeItemTypes,
ExcludeLocationTypes = new[] { LocationType.Virtual },
- Limit = limit * 20,
- ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { }
+ Limit = limit * 5,
+ ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { },
+ IsPlayed = request.IsPlayed
}, parentIds);
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
index dccc7aa93..23560b1aa 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
@@ -41,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
- if (service != null)
+ if (service != null && !item.HasImage(ImageType.Primary))
{
try
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index de75aac9c..d38e9ad32 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -35,7 +35,7 @@ using Microsoft.Win32;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
- public class EmbyTV : ILiveTvService, IHasRegistrationInfo, IDisposable
+ public class EmbyTV : ILiveTvService, ISupportsNewTimerIds, IHasRegistrationInfo, IDisposable
{
private readonly IApplicationHost _appHpst;
private readonly ILogger _logger;
@@ -102,7 +102,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_timerProvider.RestartTimers();
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
-
CreateRecordingFolders();
}
@@ -111,7 +110,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
CreateRecordingFolders();
}
- private void CreateRecordingFolders()
+ internal void CreateRecordingFolders()
+ {
+ try
+ {
+ CreateRecordingFoldersInternal();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error creating recording folders", ex);
+ }
+ }
+
+ internal void CreateRecordingFoldersInternal()
{
var recordingFolders = GetRecordingFolders();
@@ -371,6 +382,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return list;
}
+ public async Task<List<ChannelInfo>> GetChannelsForListingsProvider(ListingsProviderInfo listingsProvider, CancellationToken cancellationToken)
+ {
+ var list = new List<ChannelInfo>();
+
+ foreach (var hostInstance in _liveTvManager.TunerHosts)
+ {
+ try
+ {
+ var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false);
+
+ list.AddRange(channels);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting channels", ex);
+ }
+ }
+
+ return list
+ .Where(i => IsListingProviderEnabledForTuner(listingsProvider, i.TunerHostId))
+ .ToList();
+ }
+
public Task<IEnumerable<ChannelInfo>> GetChannelsAsync(CancellationToken cancellationToken)
{
return GetChannelsAsync(false, cancellationToken);
@@ -424,12 +458,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
{
+ return CreateTimer(info, cancellationToken);
+ }
+
+ public Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
+ {
+ return CreateSeriesTimer(info, cancellationToken);
+ }
+
+ public Task<string> CreateTimer(TimerInfo info, CancellationToken cancellationToken)
+ {
info.Id = Guid.NewGuid().ToString("N");
_timerProvider.Add(info);
- return Task.FromResult(0);
+ return Task.FromResult(info.Id);
}
- public async Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
+ public async Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken)
{
info.Id = Guid.NewGuid().ToString("N");
@@ -459,6 +503,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_seriesTimerProvider.Add(info);
await UpdateTimersForSeriesTimer(epgData, info, false).ConfigureAwait(false);
+
+ return info.Id;
}
public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
@@ -537,9 +583,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
PostPaddingSeconds = Math.Max(config.PostPaddingSeconds, 0),
PrePaddingSeconds = Math.Max(config.PrePaddingSeconds, 0),
- RecordAnyChannel = false,
- RecordAnyTime = false,
- RecordNewOnly = false
+ RecordAnyChannel = true,
+ RecordAnyTime = true,
+ RecordNewOnly = false,
+
+ Days = new List<DayOfWeek>
+ {
+ DayOfWeek.Sunday,
+ DayOfWeek.Monday,
+ DayOfWeek.Tuesday,
+ DayOfWeek.Wednesday,
+ DayOfWeek.Thursday,
+ DayOfWeek.Friday,
+ DayOfWeek.Saturday
+ }
};
if (program != null)
@@ -603,7 +660,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Debug("Getting programs for channel {0}-{1} from {2}-{3}", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty);
- var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, channel.Name, startDateUtc, endDateUtc, cancellationToken)
+ var channelMappings = GetChannelMappings(provider.Item2);
+ var channelNumber = channel.Number;
+ string mappedChannelNumber;
+ if (channelMappings.TryGetValue(channelNumber, out mappedChannelNumber))
+ {
+ _logger.Debug("Found mapped channel on provider {0}. Tuner channel number: {1}, Mapped channel number: {2}", provider.Item1.Name, channelNumber, mappedChannelNumber);
+ channelNumber = mappedChannelNumber;
+ }
+
+ var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelNumber, channel.Name, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false);
var list = programs.ToList();
@@ -625,6 +691,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return new List<ProgramInfo>();
}
+ private Dictionary<string, string> GetChannelMappings(ListingsProviderInfo info)
+ {
+ var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
+ foreach (var mapping in info.ChannelMappings)
+ {
+ dict[mapping.Name] = mapping.Value;
+ }
+
+ return dict;
+ }
+
private List<Tuple<IListingsProvider, ListingsProviderInfo>> GetListingProviders()
{
return GetConfiguration().ListingProviders
@@ -918,10 +996,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
recordPath = EnsureFileUnique(recordPath, timer.Id);
- _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
- activeRecordingInfo.Path = recordPath;
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
+ activeRecordingInfo.Path = recordPath;
var duration = recordingEndDate - DateTime.UtcNow;
@@ -957,7 +1035,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
result.Item3.Release();
}
- _libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
+ _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
}
}
catch (OperationCanceledException)
@@ -1204,6 +1282,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (!seriesTimer.RecordAnyTime)
{
allPrograms = allPrograms.Where(epg => Math.Abs(seriesTimer.StartDate.TimeOfDay.Ticks - epg.StartDate.TimeOfDay.Ticks) < TimeSpan.FromMinutes(5).Ticks);
+
+ allPrograms = allPrograms.Where(i => seriesTimer.Days.Contains(i.StartDate.ToLocalTime().DayOfWeek));
}
if (seriesTimer.RecordNewOnly)
@@ -1216,8 +1296,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
allPrograms = allPrograms.Where(epg => string.Equals(epg.ChannelId, seriesTimer.ChannelId, StringComparison.OrdinalIgnoreCase));
}
- allPrograms = allPrograms.Where(i => seriesTimer.Days.Contains(i.StartDate.ToLocalTime().DayOfWeek));
-
if (string.IsNullOrWhiteSpace(seriesTimer.SeriesId))
{
_logger.Error("seriesTimer.SeriesId is null. Cannot find programs for series");
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index e9ea49fa3..13158d346 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -44,16 +44,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
{
- if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings)
- {
- // if the audio is aac_latm, stream copying to mp4 will fail
- var streams = mediaSource.MediaStreams ?? new List<MediaStream>();
- if (streams.Any(i => i.Type == MediaStreamType.Audio && (i.Codec ?? string.Empty).IndexOf("aac", StringComparison.OrdinalIgnoreCase) != -1))
- {
- return Path.ChangeExtension(targetFile, ".mkv");
- }
- }
-
return Path.ChangeExtension(targetFile, ".mp4");
}
@@ -145,7 +135,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
videoArgs = "-codec:v:0 copy";
}
- var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\" -t {4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
+ var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -re -i \"{0}\" -t {4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
if (mediaSource.ReadAtNativeFramerate)
{
@@ -159,9 +149,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private string GetAudioArgs(MediaSourceInfo mediaSource)
{
- var copyAudio = new[] { "aac", "mp3" };
+ // do not copy aac because many players have difficulty with aac_latm
+ var copyAudio = new[] { "mp3" };
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
- if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings || mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase)))
+ var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty;
+
+ if (copyAudio.Contains(inputAudioCodec, StringComparer.OrdinalIgnoreCase))
+ {
+ return "-codec:a:0 copy";
+ }
+ if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase))
{
return "-codec:a:0 copy";
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index ae2a85090..e37109c14 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -506,8 +506,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
}
private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(
- ListingsProviderInfo info,
- List<string> programIds,
+ ListingsProviderInfo info,
+ List<string> programIds,
CancellationToken cancellationToken)
{
var imageIdString = "[";
@@ -564,7 +564,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
try
{
- using (Stream responce = await Get(options, false, info).ConfigureAwait(false))
+ using (Stream responce = await Get(options, false, info).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.Headends>>(responce);
@@ -666,58 +666,60 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
}
}
- private async Task<HttpResponseInfo> Post(HttpRequestOptions options,
- bool enableRetry,
- ListingsProviderInfo providerInfo)
+ private async Task<HttpResponseInfo> Post(HttpRequestOptions options,
+ bool enableRetry,
+ ListingsProviderInfo providerInfo)
{
try
{
return await _httpClient.Post(options).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- _tokens.Clear();
-
- if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
- {
- enableRetry = false;
- }
-
- if (!enableRetry) {
- throw;
- }
- }
-
- var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false);
- options.RequestHeaders ["token"] = newToken;
- return await Post (options, false, providerInfo).ConfigureAwait (false);
+ }
+ catch (HttpException ex)
+ {
+ _tokens.Clear();
+
+ if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
+ {
+ enableRetry = false;
+ }
+
+ if (!enableRetry)
+ {
+ throw;
+ }
+ }
+
+ var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
+ options.RequestHeaders["token"] = newToken;
+ return await Post(options, false, providerInfo).ConfigureAwait(false);
}
- private async Task<Stream> Get(HttpRequestOptions options,
- bool enableRetry,
- ListingsProviderInfo providerInfo)
+ private async Task<Stream> Get(HttpRequestOptions options,
+ bool enableRetry,
+ ListingsProviderInfo providerInfo)
{
try
{
return await _httpClient.Get(options).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- _tokens.Clear();
-
- if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
- {
- enableRetry = false;
- }
-
- if (!enableRetry) {
- throw;
- }
- }
-
- var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false);
- options.RequestHeaders ["token"] = newToken;
- return await Get (options, false, providerInfo).ConfigureAwait (false);
+ }
+ catch (HttpException ex)
+ {
+ _tokens.Clear();
+
+ if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
+ {
+ enableRetry = false;
+ }
+
+ if (!enableRetry)
+ {
+ throw;
+ }
+ }
+
+ var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
+ options.RequestHeaders["token"] = newToken;
+ return await Get(options, false, providerInfo).ConfigureAwait(false);
}
private async Task<string> GetTokenInternal(string username, string password,
@@ -734,7 +736,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
//_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent);
- using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false))
+ using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Token>(responce.Content);
if (root.message == "OK")
@@ -816,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
try
{
- using (var response = await Get(options, false, null).ConfigureAwait(false))
+ using (var response = await Get(options, false, null).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Lineups>(response);
@@ -869,6 +871,75 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return GetHeadends(info, country, location, CancellationToken.None);
}
+ public async Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken)
+ {
+ var listingsId = info.ListingsId;
+ if (string.IsNullOrWhiteSpace(listingsId))
+ {
+ throw new Exception("ListingsId required");
+ }
+
+ await AddMetadata(info, new List<ChannelInfo>(), cancellationToken).ConfigureAwait(false);
+
+ var token = await GetToken(info, cancellationToken);
+
+ if (string.IsNullOrWhiteSpace(token))
+ {
+ throw new Exception("token required");
+ }
+
+ var httpOptions = new HttpRequestOptions()
+ {
+ Url = ApiUrl + "/lineups/" + listingsId,
+ UserAgent = UserAgent,
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true,
+ // The data can be large so give it some extra time
+ TimeoutMs = 60000
+ };
+
+ httpOptions.RequestHeaders["token"] = token;
+
+ var list = new List<ChannelInfo>();
+
+ using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
+ {
+ var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
+ _logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
+ _logger.Info("Mapping Stations to Channel");
+ foreach (ScheduleDirect.Map map in root.map)
+ {
+ var channelNumber = map.logicalChannelNumber;
+
+ if (string.IsNullOrWhiteSpace(channelNumber))
+ {
+ channelNumber = map.channel;
+ }
+ if (string.IsNullOrWhiteSpace(channelNumber))
+ {
+ channelNumber = map.atscMajor + "." + map.atscMinor;
+ }
+ channelNumber = channelNumber.TrimStart('0');
+
+ var name = channelNumber;
+ var station = GetStation(listingsId, channelNumber, null);
+
+ if (station != null)
+ {
+ name = station.name;
+ }
+
+ list.Add(new ChannelInfo
+ {
+ Number = channelNumber,
+ Name = name
+ });
+ }
+ }
+
+ return list;
+ }
+
public class ScheduleDirect
{
public class Token
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs
deleted file mode 100644
index ac316f9a1..000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.LiveTv;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.Listings
-{
- public class XmlTv : IListingsProvider
- {
- public string Name
- {
- get { return "XmlTV"; }
- }
-
- public string Type
- {
- get { return "xmltv"; }
- }
-
- public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
-
- public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
- {
- // Might not be needed
- }
-
- public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
- {
- // Check that the path or url is valid. If not, throw a file not found exception
- }
-
- public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
- {
- // In theory this should never be called because there is always only one lineup
- throw new NotImplementedException();
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
new file mode 100644
index 000000000..14e4e1093
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -0,0 +1,200 @@
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.LiveTv;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.XmlTv.Classes;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.LiveTv.Listings
+{
+ public class XmlTvListingsProvider : IListingsProvider
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly IHttpClient _httpClient;
+ private readonly ILogger _logger;
+
+ public XmlTvListingsProvider(IServerConfigurationManager config, IHttpClient httpClient, ILogger logger)
+ {
+ _config = config;
+ _httpClient = httpClient;
+ _logger = logger;
+ }
+
+ public string Name
+ {
+ get { return "XmlTV"; }
+ }
+
+ public string Type
+ {
+ get { return "xmltv"; }
+ }
+
+ private string GetLanguage()
+ {
+ return _config.Configuration.PreferredMetadataLanguage;
+ }
+
+ private async Task<string> GetXml(string path, CancellationToken cancellationToken)
+ {
+ _logger.Info("xmltv path: {0}", path);
+
+ if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
+ {
+ return path;
+ }
+
+ var cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml";
+ var cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename);
+ if (File.Exists(cacheFile))
+ {
+ return cacheFile;
+ }
+
+ _logger.Info("Downloading xmltv listings from {0}", path);
+
+ var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
+ {
+ CancellationToken = cancellationToken,
+ Url = path,
+ Progress = new Progress<Double>(),
+ DecompressionMethod = DecompressionMethods.GZip,
+
+ // It's going to come back gzipped regardless of this value
+ // So we need to make sure the decompression method is set to gzip
+ EnableHttpCompression = true
+
+ }).ConfigureAwait(false);
+
+ Directory.CreateDirectory(Path.GetDirectoryName(cacheFile));
+
+ using (var stream = File.OpenRead(tempFile))
+ {
+ using (var reader = new StreamReader(stream, Encoding.UTF8))
+ {
+ using (var fileStream = File.OpenWrite(cacheFile))
+ {
+ using (var writer = new StreamWriter(fileStream))
+ {
+ while (!reader.EndOfStream)
+ {
+ writer.WriteLine(reader.ReadLine());
+ }
+ }
+ }
+ }
+ }
+
+ _logger.Debug("Returning xmltv path {0}", cacheFile);
+ return cacheFile;
+ }
+
+ public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ {
+ var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+
+ var results = reader.GetProgrammes(channelNumber, startDateUtc, endDateUtc, cancellationToken);
+ return results.Select(p => new ProgramInfo()
+ {
+ ChannelId = p.ChannelId,
+ EndDate = p.EndDate,
+ EpisodeNumber = p.Episode == null ? null : p.Episode.Episode,
+ EpisodeTitle = p.Episode == null ? null : p.Episode.Title,
+ Genres = p.Categories,
+ Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate), // Construct an id from the channel and start date,
+ StartDate = p.StartDate,
+ Name = p.Title,
+ Overview = p.Description,
+ ShortOverview = p.Description,
+ ProductionYear = !p.CopyrightDate.HasValue ? (int?)null : p.CopyrightDate.Value.Year,
+ SeasonNumber = p.Episode == null ? null : p.Episode.Series,
+ IsSeries = p.Episode != null,
+ IsRepeat = p.IsRepeat,
+ IsPremiere = p.Premiere != null,
+ IsKids = p.Categories.Any(c => info.KidsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ IsMovie = p.Categories.Any(c => info.MovieCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ IsNews = p.Categories.Any(c => info.NewsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ IsSports = p.Categories.Any(c => info.SportsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ ImageUrl = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source) ? p.Icon.Source : null,
+ HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source),
+ OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null,
+ CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null,
+ SeriesId = p.Episode != null ? p.Title.GetMD5().ToString("N") : null
+ });
+ }
+
+ public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
+ {
+ // Add the channel image url
+ var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+ var results = reader.GetChannels().ToList();
+
+ if (channels != null)
+ {
+ channels.ForEach(c =>
+ {
+ var channelNumber = info.GetMappedChannel(c.Number);
+ var match = results.FirstOrDefault(r => string.Equals(r.Id, channelNumber, StringComparison.OrdinalIgnoreCase));
+
+ if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source))
+ {
+ c.ImageUrl = match.Icon.Source;
+ }
+ });
+ }
+ }
+
+ public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
+ {
+ // Assume all urls are valid. check files for existence
+ if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase) && !File.Exists(info.Path))
+ {
+ throw new FileNotFoundException("Could not find the XmlTv file specified:", info.Path);
+ }
+
+ return Task.FromResult(true);
+ }
+
+ public async Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
+ {
+ // In theory this should never be called because there is always only one lineup
+ var path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+ var results = reader.GetChannels();
+
+ // Should this method be async?
+ return results.Select(c => new NameIdPair() { Id = c.Id, Name = c.DisplayName }).ToList();
+ }
+
+ public async Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken)
+ {
+ // In theory this should never be called because there is always only one lineup
+ var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+ var results = reader.GetChannels();
+
+ // Should this method be async?
+ return results.Select(c => new ChannelInfo()
+ {
+ Id = c.Id,
+ Name = c.DisplayName,
+ ImageUrl = c.Icon != null && !String.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null,
+ Number = c.Id
+
+ }).ToList();
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index bf7f561ec..b3bd24d96 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -30,6 +30,8 @@ using System.Threading.Tasks;
using CommonIO;
using IniParser;
using IniParser.Model;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Model.Events;
namespace MediaBrowser.Server.Implementations.LiveTv
{
@@ -64,6 +66,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
private readonly IFileSystem _fileSystem;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
+
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem)
{
_config = config;
@@ -945,7 +952,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (query.Limit.HasValue)
{
- internalQuery.Limit = Math.Max(query.Limit.Value * 5, 300);
+ internalQuery.Limit = Math.Max(query.Limit.Value * 4, 200);
}
if (query.HasAired.HasValue)
@@ -1098,6 +1105,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken)
{
+ EmbyTV.EmbyTV.Current.CreateRecordingFolders();
+
var numComplete = 0;
double progressPerService = _services.Count == 0
? 0
@@ -1757,6 +1766,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
+
+ EventHelper.QueueEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ Id = id
+ }
+ }, _logger);
}
public async Task CancelSeriesTimer(string id)
@@ -1772,6 +1789,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
+
+ EventHelper.QueueEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ Id = id
+ }
+ }, _logger);
}
public async Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null)
@@ -1957,10 +1982,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var defaults = await GetNewTimerDefaultsInternal(cancellationToken, program).ConfigureAwait(false);
var info = _tvDtoService.GetSeriesTimerInfoDto(defaults.Item1, defaults.Item2, null);
- info.Days = new List<DayOfWeek>
- {
- program.StartDate.ToLocalTime().DayOfWeek
- };
+ info.Days = defaults.Item1.Days;
info.DayPattern = _tvDtoService.GetDayPattern(info.Days);
@@ -1991,9 +2013,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var defaultValues = await service.GetNewTimerDefaultsAsync(cancellationToken).ConfigureAwait(false);
info.Priority = defaultValues.Priority;
- await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ string newTimerId = null;
+ var supportsNewTimerIds = service as ISupportsNewTimerIds;
+ if (supportsNewTimerIds != null)
+ {
+ newTimerId = await supportsNewTimerIds.CreateTimer(info, cancellationToken).ConfigureAwait(false);
+ newTimerId = _tvDtoService.GetInternalTimerId(timer.ServiceName, newTimerId).ToString("N");
+ }
+ else
+ {
+ await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ }
+
_lastRecordingRefreshTime = DateTime.MinValue;
_logger.Info("New recording scheduled");
+
+ EventHelper.QueueEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ ProgramId = _tvDtoService.GetInternalProgramId(timer.ServiceName, info.ProgramId).ToString("N"),
+ Id = newTimerId
+ }
+ }, _logger);
}
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
@@ -2006,8 +2048,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var defaultValues = await service.GetNewTimerDefaultsAsync(cancellationToken).ConfigureAwait(false);
info.Priority = defaultValues.Priority;
- await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ string newTimerId = null;
+ var supportsNewTimerIds = service as ISupportsNewTimerIds;
+ if (supportsNewTimerIds != null)
+ {
+ newTimerId = await supportsNewTimerIds.CreateSeriesTimer(info, cancellationToken).ConfigureAwait(false);
+ newTimerId = _tvDtoService.GetInternalSeriesTimerId(timer.ServiceName, newTimerId).ToString("N");
+ }
+ else
+ {
+ await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ }
+
_lastRecordingRefreshTime = DateTime.MinValue;
+
+ EventHelper.QueueEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ ProgramId = _tvDtoService.GetInternalProgramId(timer.ServiceName, info.ProgramId).ToString("N"),
+ Id = newTimerId
+ }
+ }, _logger);
}
public async Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken)
@@ -2522,5 +2584,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
return new TunerHosts.SatIp.ChannelScan(_logger).Scan(info, cancellationToken);
}
+
+ public Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken)
+ {
+ var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
+ return EmbyTV.EmbyTV.Current.GetChannelsForListingsProvider(info, cancellationToken);
+ }
+
+ public Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken)
+ {
+ var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
+ var provider = _listingProviders.First(i => string.Equals(i.Type, info.Type, StringComparison.OrdinalIgnoreCase));
+ return provider.GetChannels(info, cancellationToken);
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 0aa499f69..066a8c3ca 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -46,17 +46,18 @@
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
</Reference>
<Reference Include="Emby.XmlTv, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Emby.XmlTv.1.0.0.48\lib\net45\Emby.XmlTv.dll</HintPath>
+ <HintPath>..\packages\Emby.XmlTv.1.0.0.53\lib\net45\Emby.XmlTv.dll</HintPath>
+ <Private>True</Private>
</Reference>
- <Reference Include="INIFileParser">
- <HintPath>..\packages\ini-parser.2.2.4\lib\net20\INIFileParser.dll</HintPath>
+ <Reference Include="INIFileParser, Version=2.3.0.0, Culture=neutral, PublicKeyToken=79af7b307b65cf3c, processorArchitecture=MSIL">
+ <HintPath>..\packages\ini-parser.2.3.0\lib\net20\INIFileParser.dll</HintPath>
+ <Private>True</Private>
</Reference>
<Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
- <Reference Include="MediaBrowser.Naming, Version=1.0.5981.21615, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\MediaBrowser.Naming.1.0.0.50\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
+ <Reference Include="MediaBrowser.Naming, Version=1.0.5996.42016, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\MediaBrowser.Naming.1.0.0.51\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MoreLinq">
@@ -68,8 +69,8 @@
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
- <Reference Include="SimpleInjector, Version=3.1.4.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
- <HintPath>..\packages\SimpleInjector.3.1.4\lib\net45\SimpleInjector.dll</HintPath>
+ <Reference Include="SimpleInjector, Version=3.1.5.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <HintPath>..\packages\SimpleInjector.3.1.5\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SocketHttpListener, Version=1.0.5955.1537, Culture=neutral, processorArchitecture=MSIL">
@@ -141,6 +142,7 @@
<Compile Include="EntryPoints\LoadRegistrations.cs" />
<Compile Include="EntryPoints\Notifications\Notifications.cs" />
<Compile Include="EntryPoints\Notifications\WebSocketNotifier.cs" />
+ <Compile Include="EntryPoints\RecordingNotifier.cs" />
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
<Compile Include="EntryPoints\UsageEntryPoint.cs" />
<Compile Include="Connect\ConnectEntryPoint.cs" />
@@ -180,6 +182,7 @@
<Compile Include="HttpServer\SocketSharp\WebSocketSharpRequest.cs" />
<Compile Include="HttpServer\SocketSharp\WebSocketSharpResponse.cs" />
<Compile Include="Intros\DefaultIntroProvider.cs" />
+ <Compile Include="IO\FileRefresher.cs" />
<Compile Include="IO\LibraryMonitor.cs" />
<Compile Include="Library\CoreResolutionIgnoreRule.cs" />
<Compile Include="Library\LibraryManager.cs" />
@@ -231,7 +234,7 @@
<Compile Include="LiveTv\EmbyTV\SeriesTimerManager.cs" />
<Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
<Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
- <Compile Include="LiveTv\Listings\XmlTv.cs" />
+ <Compile Include="LiveTv\Listings\XmlTvListingsProvider.cs" />
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
<Compile Include="LiveTv\LiveTvDtoService.cs" />
<Compile Include="LiveTv\LiveTvManager.cs" />
@@ -276,7 +279,6 @@
<Compile Include="Notifications\NotificationManager.cs" />
<Compile Include="Persistence\SqliteFileOrganizationRepository.cs" />
<Compile Include="Notifications\SqliteNotificationsRepository.cs" />
- <Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
<Compile Include="Persistence\TypeMapper.cs" />
<Compile Include="Photos\BaseDynamicImageProvider.cs" />
<Compile Include="Playlists\ManualPlaylistsFolder.cs" />
diff --git a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
index 10e8c5699..be8c6d48d 100644
--- a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
@@ -15,74 +15,28 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
public class SqliteNotificationsRepository : BaseSqliteRepository, INotificationsRepository
{
- private IDbConnection _connection;
- private readonly IServerApplicationPaths _appPaths;
+ public SqliteNotificationsRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector dbConnector) : base(logManager, dbConnector)
+ {
+ DbFilePath = Path.Combine(appPaths.DataPath, "notifications.db");
+ }
public event EventHandler<NotificationUpdateEventArgs> NotificationAdded;
public event EventHandler<NotificationReadEventArgs> NotificationsMarkedRead;
public event EventHandler<NotificationUpdateEventArgs> NotificationUpdated;
- private IDbCommand _replaceNotificationCommand;
- private IDbCommand _markReadCommand;
- private IDbCommand _markAllReadCommand;
-
- public SqliteNotificationsRepository(ILogManager logManager, IServerApplicationPaths appPaths)
- : base(logManager)
+ public async Task Initialize()
{
- _appPaths = appPaths;
- }
-
- public async Task Initialize(IDbConnector dbConnector)
- {
- var dbFile = Path.Combine(_appPaths.DataPath, "notifications.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists Notifications (Id GUID NOT NULL, UserId GUID NOT NULL, Date DATETIME NOT NULL, Name TEXT NOT NULL, Description TEXT, Url TEXT, Level TEXT NOT NULL, IsRead BOOLEAN NOT NULL, Category TEXT NOT NULL, RelatedId TEXT, PRIMARY KEY (Id, UserId))",
"create index if not exists idx_Notifications1 on Notifications(Id)",
- "create index if not exists idx_Notifications2 on Notifications(UserId)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_Notifications2 on Notifications(UserId)"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _replaceNotificationCommand = _connection.CreateCommand();
- _replaceNotificationCommand.CommandText = "replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)";
-
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Id");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Date");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Name");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Description");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Url");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Level");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Category");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@RelatedId");
-
- _markReadCommand = _connection.CreateCommand();
- _markReadCommand.CommandText = "update Notifications set IsRead=@IsRead where Id=@Id and UserId=@UserId";
-
- _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
- _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
- _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@Id");
-
- _markAllReadCommand = _connection.CreateCommand();
- _markAllReadCommand.CommandText = "update Notifications set IsRead=@IsRead where UserId=@UserId";
-
- _markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
- _markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
+ connection.RunQueries(queries, Logger);
+ }
}
/// <summary>
@@ -94,49 +48,52 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
var result = new NotificationResult();
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- var clauses = new List<string>();
-
- if (query.IsRead.HasValue)
+ using (var cmd = connection.CreateCommand())
{
- clauses.Add("IsRead=@IsRead");
- cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = query.IsRead.Value;
- }
+ var clauses = new List<string>();
- clauses.Add("UserId=@UserId");
- cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(query.UserId);
+ if (query.IsRead.HasValue)
+ {
+ clauses.Add("IsRead=@IsRead");
+ cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = query.IsRead.Value;
+ }
- var whereClause = " where " + string.Join(" And ", clauses.ToArray());
+ clauses.Add("UserId=@UserId");
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(query.UserId);
- cmd.CommandText = string.Format("select count(Id) from Notifications{0};select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause);
+ var whereClause = " where " + string.Join(" And ", clauses.ToArray());
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- if (reader.Read())
- {
- result.TotalRecordCount = reader.GetInt32(0);
- }
+ cmd.CommandText = string.Format("select count(Id) from Notifications{0};select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause);
- if (reader.NextResult())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- var notifications = GetNotifications(reader);
-
- if (query.StartIndex.HasValue)
+ if (reader.Read())
{
- notifications = notifications.Skip(query.StartIndex.Value);
+ result.TotalRecordCount = reader.GetInt32(0);
}
- if (query.Limit.HasValue)
+ if (reader.NextResult())
{
- notifications = notifications.Take(query.Limit.Value);
- }
+ var notifications = GetNotifications(reader);
+
+ if (query.StartIndex.HasValue)
+ {
+ notifications = notifications.Skip(query.StartIndex.Value);
+ }
+
+ if (query.Limit.HasValue)
+ {
+ notifications = notifications.Take(query.Limit.Value);
+ }
- result.Notifications = notifications.ToArray();
+ result.Notifications = notifications.ToArray();
+ }
}
- }
- return result;
+ return result;
+ }
}
}
@@ -144,31 +101,34 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
var result = new NotificationsSummary();
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = "select Level from Notifications where UserId=@UserId and IsRead=@IsRead";
-
- cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(userId);
- cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = false;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ using (var cmd = connection.CreateCommand())
{
- var levels = new List<NotificationLevel>();
+ cmd.CommandText = "select Level from Notifications where UserId=@UserId and IsRead=@IsRead";
- while (reader.Read())
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(userId);
+ cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = false;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- levels.Add(GetLevel(reader, 0));
- }
+ var levels = new List<NotificationLevel>();
+
+ while (reader.Read())
+ {
+ levels.Add(GetLevel(reader, 0));
+ }
- result.UnreadCount = levels.Count;
+ result.UnreadCount = levels.Count;
- if (levels.Count > 0)
- {
- result.MaxUnreadNotificationLevel = levels.Max();
+ if (levels.Count > 0)
+ {
+ result.MaxUnreadNotificationLevel = levels.Max();
+ }
}
- }
- return result;
+ return result;
+ }
}
}
@@ -179,10 +139,14 @@ namespace MediaBrowser.Server.Implementations.Notifications
/// <returns>IEnumerable{Notification}.</returns>
private IEnumerable<Notification> GetNotifications(IDataReader reader)
{
+ var list = new List<Notification>();
+
while (reader.Read())
{
- yield return GetNotification(reader);
+ list.Add(GetNotification(reader));
}
+
+ return list;
}
private Notification GetNotification(IDataReader reader)
@@ -273,59 +237,74 @@ namespace MediaBrowser.Server.Implementations.Notifications
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ using (var replaceNotificationCommand = connection.CreateCommand())
+ {
+ replaceNotificationCommand.CommandText = "replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)";
+
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Id");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@UserId");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Date");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Name");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Description");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Url");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Level");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@IsRead");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Category");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@RelatedId");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
- _replaceNotificationCommand.GetParameter(0).Value = new Guid(notification.Id);
- _replaceNotificationCommand.GetParameter(1).Value = new Guid(notification.UserId);
- _replaceNotificationCommand.GetParameter(2).Value = notification.Date.ToUniversalTime();
- _replaceNotificationCommand.GetParameter(3).Value = notification.Name;
- _replaceNotificationCommand.GetParameter(4).Value = notification.Description;
- _replaceNotificationCommand.GetParameter(5).Value = notification.Url;
- _replaceNotificationCommand.GetParameter(6).Value = notification.Level.ToString();
- _replaceNotificationCommand.GetParameter(7).Value = notification.IsRead;
- _replaceNotificationCommand.GetParameter(8).Value = string.Empty;
- _replaceNotificationCommand.GetParameter(9).Value = string.Empty;
+ replaceNotificationCommand.GetParameter(0).Value = new Guid(notification.Id);
+ replaceNotificationCommand.GetParameter(1).Value = new Guid(notification.UserId);
+ replaceNotificationCommand.GetParameter(2).Value = notification.Date.ToUniversalTime();
+ replaceNotificationCommand.GetParameter(3).Value = notification.Name;
+ replaceNotificationCommand.GetParameter(4).Value = notification.Description;
+ replaceNotificationCommand.GetParameter(5).Value = notification.Url;
+ replaceNotificationCommand.GetParameter(6).Value = notification.Level.ToString();
+ replaceNotificationCommand.GetParameter(7).Value = notification.IsRead;
+ replaceNotificationCommand.GetParameter(8).Value = string.Empty;
+ replaceNotificationCommand.GetParameter(9).Value = string.Empty;
- _replaceNotificationCommand.Transaction = transaction;
+ replaceNotificationCommand.Transaction = transaction;
- _replaceNotificationCommand.ExecuteNonQuery();
+ replaceNotificationCommand.ExecuteNonQuery();
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save notification:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save notification:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -366,51 +345,58 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var markAllReadCommand = connection.CreateCommand())
+ {
+ markAllReadCommand.CommandText = "update Notifications set IsRead=@IsRead where UserId=@UserId";
- IDbTransaction transaction = null;
+ markAllReadCommand.Parameters.Add(markAllReadCommand, "@UserId");
+ markAllReadCommand.Parameters.Add(markAllReadCommand, "@IsRead");
- try
- {
- cancellationToken.ThrowIfCancellationRequested();
+ IDbTransaction transaction = null;
- transaction = _connection.BeginTransaction();
+ try
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- _markAllReadCommand.GetParameter(0).Value = new Guid(userId);
- _markAllReadCommand.GetParameter(1).Value = isRead;
+ transaction = connection.BeginTransaction();
- _markAllReadCommand.ExecuteNonQuery();
+ markAllReadCommand.GetParameter(0).Value = new Guid(userId);
+ markAllReadCommand.GetParameter(1).Value = isRead;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ markAllReadCommand.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save notification:", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save notification:", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
@@ -418,72 +404,66 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- cancellationToken.ThrowIfCancellationRequested();
+ using (var markReadCommand = connection.CreateCommand())
+ {
+ markReadCommand.CommandText = "update Notifications set IsRead=@IsRead where Id=@Id and UserId=@UserId";
- transaction = _connection.BeginTransaction();
+ markReadCommand.Parameters.Add(markReadCommand, "@UserId");
+ markReadCommand.Parameters.Add(markReadCommand, "@IsRead");
+ markReadCommand.Parameters.Add(markReadCommand, "@Id");
- _markReadCommand.GetParameter(0).Value = new Guid(userId);
- _markReadCommand.GetParameter(1).Value = isRead;
+ IDbTransaction transaction = null;
- foreach (var id in notificationIdList)
- {
- _markReadCommand.GetParameter(2).Value = id;
+ try
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- _markReadCommand.Transaction = transaction;
+ transaction = connection.BeginTransaction();
- _markReadCommand.ExecuteNonQuery();
- }
+ markReadCommand.GetParameter(0).Value = new Guid(userId);
+ markReadCommand.GetParameter(1).Value = isRead;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ foreach (var id in notificationIdList)
+ {
+ markReadCommand.GetParameter(2).Value = id;
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save notification:", e);
+ markReadCommand.Transaction = transaction;
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ markReadCommand.ExecuteNonQuery();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
- }
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save notification:", e);
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- _connection.Dispose();
- _connection = null;
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
index 395907844..eec5b4b76 100644
--- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
@@ -9,13 +9,35 @@ namespace MediaBrowser.Server.Implementations.Persistence
public abstract class BaseSqliteRepository : IDisposable
{
protected readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1);
+ protected readonly IDbConnector DbConnector;
protected ILogger Logger;
- protected BaseSqliteRepository(ILogManager logManager)
+ protected string DbFilePath { get; set; }
+
+ protected BaseSqliteRepository(ILogManager logManager, IDbConnector dbConnector)
{
+ DbConnector = dbConnector;
Logger = logManager.GetLogger(GetType().Name);
}
+ protected virtual bool EnableConnectionPooling
+ {
+ get { return true; }
+ }
+
+ protected virtual async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
+ {
+ var connection = await DbConnector.Connect(DbFilePath, false, true).ConfigureAwait(false);
+
+ connection.RunQueries(new[]
+ {
+ "pragma temp_store = memory"
+
+ }, Logger);
+
+ return connection;
+ }
+
private bool _disposed;
protected void CheckDisposed()
{
@@ -84,6 +106,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- protected abstract void CloseConnection();
+ protected virtual void CloseConnection()
+ {
+
+ }
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
index cac9fe983..596cf8407 100644
--- a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
@@ -5,6 +5,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
public interface IDbConnector
{
- Task<IDbConnection> Connect(string dbPath);
+ Task<IDbConnection> Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null);
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
index 948e99cb8..1d9be2e0d 100644
--- a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
@@ -28,6 +28,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
AddNalColumn();
AddIsAvcColumn();
AddTitleColumn();
+ AddTimeBaseColumn();
+ AddCodecTimeBaseColumn();
}
private void AddIsAvcColumn()
@@ -61,6 +63,68 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.RunQueries(new[] { builder.ToString() }, _logger);
}
+ private void AddTimeBaseColumn()
+ {
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "PRAGMA table_info(mediastreams)";
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
+ {
+ if (!reader.IsDBNull(1))
+ {
+ var name = reader.GetString(1);
+
+ if (string.Equals(name, "TimeBase", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column TimeBase TEXT");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ private void AddCodecTimeBaseColumn()
+ {
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "PRAGMA table_info(mediastreams)";
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
+ {
+ if (!reader.IsDBNull(1))
+ {
+ var name = reader.GetString(1);
+
+ if (string.Equals(name, "CodecTimeBase", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column CodecTimeBase TEXT");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
private void AddTitleColumn()
{
using (var cmd = _connection.CreateCommand())
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
index 6077cfdba..40970dbe4 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
@@ -18,12 +18,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
{
- private IDbConnection _connection;
-
- public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths) : base(logManager)
+ public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IDbConnector dbConnector)
+ : base(logManager, dbConnector)
{
_jsonSerializer = jsonSerializer;
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db");
}
/// <summary>
@@ -44,32 +43,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
private readonly IJsonSerializer _jsonSerializer;
/// <summary>
- /// The _app paths
- /// </summary>
- private readonly IApplicationPaths _appPaths;
-
- /// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists userdisplaypreferences (id GUID, userId GUID, client text, data BLOB)",
- "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
+ }
}
/// <summary>
@@ -96,58 +84,57 @@ namespace MediaBrowser.Server.Implementations.Persistence
var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- using (var cmd = _connection.CreateCommand())
+ try
{
- cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
+ transaction = connection.BeginTransaction();
- cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreferences.Id);
- cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
- cmd.Parameters.Add(cmd, "@3", DbType.String).Value = client;
- cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
- cmd.Transaction = transaction;
+ cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreferences.Id);
+ cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
+ cmd.Parameters.Add(cmd, "@3", DbType.String).Value = client;
+ cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
- cmd.ExecuteNonQuery();
- }
+ cmd.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
+ cmd.ExecuteNonQuery();
+ }
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
{
- transaction.Rollback();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save display preferences:", e);
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save display preferences:", e);
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ throw;
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ finally
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- WriteLock.Release();
}
}
@@ -168,64 +155,63 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- foreach (var displayPreference in displayPreferences)
+ try
{
+ transaction = connection.BeginTransaction();
- var serialized = _jsonSerializer.SerializeToBytes(displayPreference);
-
- using (var cmd = _connection.CreateCommand())
+ foreach (var displayPreference in displayPreferences)
{
- cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
- cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreference.Id);
- cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
- cmd.Parameters.Add(cmd, "@3", DbType.String).Value = displayPreference.Client;
- cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
+ var serialized = _jsonSerializer.SerializeToBytes(displayPreference);
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
- cmd.ExecuteNonQuery();
+ cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreference.Id);
+ cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
+ cmd.Parameters.Add(cmd, "@3", DbType.String).Value = displayPreference.Client;
+ cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
+
+ cmd.Transaction = transaction;
+
+ cmd.ExecuteNonQuery();
+ }
}
- }
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
{
- transaction.Rollback();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save display preferences:", e);
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save display preferences:", e);
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ throw;
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ finally
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- WriteLock.Release();
}
}
@@ -246,28 +232,33 @@ namespace MediaBrowser.Server.Implementations.Persistence
var guidId = displayPreferencesId.GetMD5();
- var cmd = _connection.CreateCommand();
- cmd.CommandText = "select data from userdisplaypreferences where id = @id and userId=@userId and client=@client";
-
- cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = guidId;
- cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
- cmd.Parameters.Add(cmd, "@client", DbType.String).Value = client;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ using (var connection = CreateConnection(true).Result)
{
- if (reader.Read())
+ using (var cmd = connection.CreateCommand())
{
- using (var stream = reader.GetMemoryStream(0))
+ cmd.CommandText = "select data from userdisplaypreferences where id = @id and userId=@userId and client=@client";
+
+ cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = guidId;
+ cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
+ cmd.Parameters.Add(cmd, "@client", DbType.String).Value = client;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
+ if (reader.Read())
+ {
+ using (var stream = reader.GetMemoryStream(0))
+ {
+ return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
+ }
+ }
}
+
+ return new DisplayPreferences
+ {
+ Id = guidId.ToString("N")
+ };
}
}
-
- return new DisplayPreferences
- {
- Id = guidId.ToString("N")
- };
}
/// <summary>
@@ -278,36 +269,30 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// <exception cref="System.ArgumentNullException">item</exception>
public IEnumerable<DisplayPreferences> GetAllDisplayPreferences(Guid userId)
{
+ var list = new List<DisplayPreferences>();
- var cmd = _connection.CreateCommand();
- cmd.CommandText = "select data from userdisplaypreferences where userId=@userId";
-
- cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ using (var connection = CreateConnection(true).Result)
{
- while (reader.Read())
+ using (var cmd = connection.CreateCommand())
{
- using (var stream = reader.GetMemoryStream(0))
+ cmd.CommandText = "select data from userdisplaypreferences where userId=@userId";
+
+ cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
{
- yield return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
+ while (reader.Read())
+ {
+ using (var stream = reader.GetMemoryStream(0))
+ {
+ list.Add(_jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream));
+ }
+ }
}
}
}
- }
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
- _connection.Dispose();
- _connection = null;
- }
+ return list;
}
public Task SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
new file mode 100644
index 000000000..d5b582da5
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.SQLite;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+ /// <summary>
+ /// Class SQLiteExtensions
+ /// </summary>
+ public static class SqliteExtensions
+ {
+ /// <summary>
+ /// Connects to db.
+ /// </summary>
+ public static async Task<IDbConnection> ConnectToDb(string dbPath, bool isReadOnly, bool enablePooling, int? cacheSize, ILogger logger)
+ {
+ if (string.IsNullOrEmpty(dbPath))
+ {
+ throw new ArgumentNullException("dbPath");
+ }
+
+ SQLiteConnection.SetMemoryStatus(false);
+
+ var connectionstr = new SQLiteConnectionStringBuilder
+ {
+ PageSize = 4096,
+ CacheSize = cacheSize ?? 2000,
+ SyncMode = SynchronizationModes.Normal,
+ DataSource = dbPath,
+ JournalMode = SQLiteJournalModeEnum.Wal,
+
+ // This is causing crashing under linux
+ Pooling = enablePooling && Environment.OSVersion.Platform == PlatformID.Win32NT,
+ ReadOnly = isReadOnly
+ };
+
+ var connectionString = connectionstr.ConnectionString;
+
+ if (!enablePooling)
+ {
+ logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, connectionString);
+ }
+
+ var connection = new SQLiteConnection(connectionString);
+
+ await connection.OpenAsync().ConfigureAwait(false);
+
+ return connection;
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
index 037776997..7a5e00090 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
@@ -16,74 +16,29 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
{
- private IDbConnection _connection;
-
- private readonly IServerApplicationPaths _appPaths;
-
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _saveResultCommand;
- private IDbCommand _deleteResultCommand;
- private IDbCommand _deleteAllCommand;
-
- public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths) : base(logManager)
+ public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "fileorganization.db");
}
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists FileOrganizerResults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, FileLength INT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber, DuplicatePaths TEXT int null)",
- "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _saveResultCommand = _connection.CreateCommand();
- _saveResultCommand.CommandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)";
-
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ResultId");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@OriginalPath");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@TargetPath");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@FileLength");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@OrganizationDate");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@Status");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@OrganizationType");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@StatusMessage");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedName");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedYear");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedSeasonNumber");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEpisodeNumber");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEndingEpisodeNumber");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@DuplicatePaths");
-
- _deleteResultCommand = _connection.CreateCommand();
- _deleteResultCommand.CommandText = "delete from FileOrganizerResults where ResultId = @ResultId";
-
- _deleteResultCommand.Parameters.Add(_saveResultCommand, "@ResultId");
-
- _deleteAllCommand = _connection.CreateCommand();
- _deleteAllCommand.CommandText = "delete from FileOrganizerResults";
+ connection.RunQueries(queries, Logger);
+ }
}
public async Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
@@ -95,65 +50,84 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- _saveResultCommand.GetParameter(index++).Value = new Guid(result.Id);
- _saveResultCommand.GetParameter(index++).Value = result.OriginalPath;
- _saveResultCommand.GetParameter(index++).Value = result.TargetPath;
- _saveResultCommand.GetParameter(index++).Value = result.FileSize;
- _saveResultCommand.GetParameter(index++).Value = result.Date;
- _saveResultCommand.GetParameter(index++).Value = result.Status.ToString();
- _saveResultCommand.GetParameter(index++).Value = result.Type.ToString();
- _saveResultCommand.GetParameter(index++).Value = result.StatusMessage;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedName;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedYear;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedSeasonNumber;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedEpisodeNumber;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedEndingEpisodeNumber;
- _saveResultCommand.GetParameter(index).Value = string.Join("|", result.DuplicatePaths.ToArray());
-
- _saveResultCommand.Transaction = transaction;
-
- _saveResultCommand.ExecuteNonQuery();
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- if (transaction != null)
+ using (var saveResultCommand = connection.CreateCommand())
{
- transaction.Rollback();
- }
+ saveResultCommand.CommandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)";
+
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ResultId");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@OriginalPath");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@TargetPath");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@FileLength");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationDate");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@Status");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationType");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@StatusMessage");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedName");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedYear");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedSeasonNumber");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEpisodeNumber");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEndingEpisodeNumber");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@DuplicatePaths");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ var index = 0;
+
+ saveResultCommand.GetParameter(index++).Value = new Guid(result.Id);
+ saveResultCommand.GetParameter(index++).Value = result.OriginalPath;
+ saveResultCommand.GetParameter(index++).Value = result.TargetPath;
+ saveResultCommand.GetParameter(index++).Value = result.FileSize;
+ saveResultCommand.GetParameter(index++).Value = result.Date;
+ saveResultCommand.GetParameter(index++).Value = result.Status.ToString();
+ saveResultCommand.GetParameter(index++).Value = result.Type.ToString();
+ saveResultCommand.GetParameter(index++).Value = result.StatusMessage;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedName;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedYear;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedSeasonNumber;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedEpisodeNumber;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedEndingEpisodeNumber;
+ saveResultCommand.GetParameter(index).Value = string.Join("|", result.DuplicatePaths.ToArray());
+
+ saveResultCommand.Transaction = transaction;
+
+ saveResultCommand.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save FileOrganizationResult:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save FileOrganizationResult:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -164,100 +138,110 @@ namespace MediaBrowser.Server.Implementations.Persistence
throw new ArgumentNullException("id");
}
- await WriteLock.WaitAsync().ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var deleteResultCommand = connection.CreateCommand())
+ {
+ deleteResultCommand.CommandText = "delete from FileOrganizerResults where ResultId = @ResultId";
- IDbTransaction transaction = null;
+ deleteResultCommand.Parameters.Add(deleteResultCommand, "@ResultId");
- try
- {
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- _deleteResultCommand.GetParameter(0).Value = new Guid(id);
+ try
+ {
+ transaction = connection.BeginTransaction();
- _deleteResultCommand.Transaction = transaction;
+ deleteResultCommand.GetParameter(0).Value = new Guid(id);
- _deleteResultCommand.ExecuteNonQuery();
+ deleteResultCommand.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ deleteResultCommand.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
public async Task DeleteAll()
{
- await WriteLock.WaitAsync().ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "delete from FileOrganizerResults";
- IDbTransaction transaction = null;
+ IDbTransaction transaction = null;
- try
- {
- transaction = _connection.BeginTransaction();
-
- _deleteAllCommand.Transaction = transaction;
+ try
+ {
+ transaction = connection.BeginTransaction();
- _deleteAllCommand.ExecuteNonQuery();
+ cmd.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ cmd.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to delete results", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to delete results", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
-
+
public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
{
if (query == null)
@@ -265,46 +249,49 @@ namespace MediaBrowser.Server.Implementations.Persistence
throw new ArgumentNullException("query");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults";
-
- if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
+ using (var cmd = connection.CreateCommand())
{
- cmd.CommandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})",
- query.StartIndex.Value.ToString(_usCulture));
- }
+ cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults";
- cmd.CommandText += " ORDER BY OrganizationDate desc";
+ if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
+ {
+ cmd.CommandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})",
+ query.StartIndex.Value.ToString(_usCulture));
+ }
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ cmd.CommandText += " ORDER BY OrganizationDate desc";
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- cmd.CommandText += "; select count (ResultId) from FileOrganizerResults";
+ cmd.CommandText += "; select count (ResultId) from FileOrganizerResults";
- var list = new List<FileOrganizationResult>();
- var count = 0;
+ var list = new List<FileOrganizationResult>();
+ var count = 0;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(GetResult(reader));
+ while (reader.Read())
+ {
+ list.Add(GetResult(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<FileOrganizationResult>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<FileOrganizationResult>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -315,24 +302,27 @@ namespace MediaBrowser.Server.Implementations.Persistence
throw new ArgumentNullException("id");
}
- var guid = new Guid(id);
-
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = "select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@Id";
+ var guid = new Guid(id);
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ using (var cmd = connection.CreateCommand())
{
- if (reader.Read())
+ cmd.CommandText = "select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetResult(reader);
+ if (reader.Read())
+ {
+ return GetResult(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
public FileOrganizationResult GetResult(IDataReader reader)
@@ -414,19 +404,5 @@ namespace MediaBrowser.Server.Implementations.Persistence
return result;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index 57eb41bc2..437d16974 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -15,6 +15,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -84,16 +85,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _deleteItemValuesCommand;
private IDbCommand _saveItemValuesCommand;
+ private IDbCommand _deleteProviderIdsCommand;
+ private IDbCommand _saveProviderIdsCommand;
+
+ private IDbCommand _deleteImagesCommand;
+ private IDbCommand _saveImagesCommand;
+
private IDbCommand _updateInheritedRatingCommand;
private IDbCommand _updateInheritedTagsCommand;
- public const int LatestSchemaVersion = 79;
+ public const int LatestSchemaVersion = 92;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
/// </summary>
- public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager)
- : base(logManager)
+ public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager, IDbConnector connector)
+ : base(logManager, connector)
{
if (config == null)
{
@@ -108,27 +115,38 @@ namespace MediaBrowser.Server.Implementations.Persistence
_jsonSerializer = jsonSerializer;
_criticReviewsPath = Path.Combine(_config.ApplicationPaths.DataPath, "critic-reviews");
+ DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
}
private const string ChaptersTableName = "Chapters2";
+ protected override async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
+ {
+ var connection = await DbConnector.Connect(DbFilePath, false, false, 5000).ConfigureAwait(false);
+
+ connection.RunQueries(new[]
+ {
+ "pragma temp_store = memory"
+
+ }, Logger);
+
+ return connection;
+ }
+
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
+ _connection = await CreateConnection(false).ConfigureAwait(false);
var createMediaStreamsTableCommand
- = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
+ = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
string[] queries = {
"create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID, Path TEXT)",
- "create index if not exists idx_TypedBaseItems on TypedBaseItems(guid)",
"create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)",
"create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
@@ -141,6 +159,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
"create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT)",
"create index if not exists idx_ItemValues on ItemValues(ItemId)",
+ "create index if not exists idx_ItemValues2 on ItemValues(ItemId,Type)",
+
+ "create table if not exists ProviderIds (ItemId GUID, Name TEXT, Value TEXT, PRIMARY KEY (ItemId, Name))",
+ "create index if not exists Idx_ProviderIds on ProviderIds(ItemId)",
+
+ "create table if not exists Images (ItemId GUID NOT NULL, Path TEXT NOT NULL, ImageType INT NOT NULL, DateModified DATETIME, IsPlaceHolder BIT NOT NULL, SortOrder INT)",
+ "create index if not exists idx_Images on Images(ItemId)",
"create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)",
"create index if not exists idxPeopleItemId on People(ItemId)",
@@ -152,10 +177,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
createMediaStreamsTableCommand,
"create index if not exists idx_mediastreams1 on mediastreams(ItemId)",
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
};
_connection.RunQueries(queries, Logger);
@@ -239,15 +260,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME");
_connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "IsVirtualItem", "BIT");
+ _connection.AddColumn(Logger, "TypedBaseItems", "SeriesName", "Text");
_connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT");
string[] postQueries =
- {
+ {
"create index if not exists idx_PresentationUniqueKey on TypedBaseItems(PresentationUniqueKey)",
+ "create index if not exists idx_GuidType on TypedBaseItems(Guid,Type)",
"create index if not exists idx_Type on TypedBaseItems(Type)",
- "create index if not exists idx_TopParentId on TypedBaseItems(TopParentId)"
- };
+ "create index if not exists idx_TopParentId on TypedBaseItems(TopParentId)",
+ "create index if not exists idx_TypeTopParentId on TypedBaseItems(Type,TopParentId)",
+ "create index if not exists idx_TypeTopParentId2 on TypedBaseItems(TopParentId,MediaType,IsVirtualItem)",
+ "create index if not exists idx_TypeTopParentId3 on TypedBaseItems(TopParentId,IsFolder,IsVirtualItem)",
+ "create index if not exists idx_TypeTopParentId4 on TypedBaseItems(TopParentId,Type,IsVirtualItem)",
+ "create index if not exists idx_TypeTopParentId5 on TypedBaseItems(TopParentId,IsVirtualItem)"
+ };
_connection.RunQueries(postQueries, Logger);
@@ -255,53 +283,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
new MediaStreamColumns(_connection, Logger).AddColumns();
- var mediaStreamsDbFile = Path.Combine(_config.ApplicationPaths.DataPath, "mediainfo.db");
- if (File.Exists(mediaStreamsDbFile))
- {
- MigrateMediaStreams(mediaStreamsDbFile);
- }
-
DataExtensions.Attach(_connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb");
}
- private void MigrateMediaStreams(string file)
- {
- try
- {
- var backupFile = file + ".bak";
- File.Copy(file, backupFile, true);
- DataExtensions.Attach(_connection, backupFile, "MediaInfoOld");
-
- var columns = string.Join(",", _mediaStreamSaveColumns);
-
- string[] queries = {
- "REPLACE INTO mediastreams("+columns+") SELECT "+columns+" FROM MediaInfoOld.mediastreams;"
- };
-
- _connection.RunQueries(queries, Logger);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error migrating media info database", ex);
- }
- finally
- {
- TryDeleteFile(file);
- }
- }
-
- private void TryDeleteFile(string file)
- {
- try
- {
- File.Delete(file);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error deleting file {0}", ex, file);
- }
- }
-
private readonly string[] _retriveItemColumns =
{
"type",
@@ -396,7 +380,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
"Comment",
"NalLengthSize",
"IsAvc",
- "Title"
+ "Title",
+ "TimeBase",
+ "CodecTimeBase"
};
/// <summary>
@@ -478,7 +464,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"PrimaryVersionId",
"DateLastMediaAdded",
"Album",
- "IsVirtualItem"
+ "IsVirtualItem",
+ "SeriesName"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -586,6 +573,30 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Type");
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Value");
+ // provider ids
+ _deleteProviderIdsCommand = _connection.CreateCommand();
+ _deleteProviderIdsCommand.CommandText = "delete from ProviderIds where ItemId=@Id";
+ _deleteProviderIdsCommand.Parameters.Add(_deleteProviderIdsCommand, "@Id");
+
+ _saveProviderIdsCommand = _connection.CreateCommand();
+ _saveProviderIdsCommand.CommandText = "insert into ProviderIds (ItemId, Name, Value) values (@ItemId, @Name, @Value)";
+ _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@ItemId");
+ _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Name");
+ _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Value");
+
+ // images
+ _deleteImagesCommand = _connection.CreateCommand();
+ _deleteImagesCommand.CommandText = "delete from Images where ItemId=@Id";
+ _deleteImagesCommand.Parameters.Add(_deleteImagesCommand, "@Id");
+
+ _saveImagesCommand = _connection.CreateCommand();
+ _saveImagesCommand.CommandText = "insert into Images (ItemId, ImageType, Path, DateModified, IsPlaceHolder, SortOrder) values (@ItemId, @ImageType, @Path, @DateModified, @IsPlaceHolder, @SortOrder)";
+ _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ItemId");
+ _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ImageType");
+ _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@Path");
+ _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@DateModified");
+ _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@IsPlaceHolder");
+ _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@SortOrder");
}
/// <summary>
@@ -870,10 +881,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.Album;
- var season = item as Season;
- if (season != null && season.IsVirtualItem.HasValue)
+ _saveItemCommand.GetParameter(index++).Value = item.IsVirtualItem || (!item.IsFolder && item.LocationType == LocationType.Virtual);
+
+ var hasSeries = item as IHasSeries;
+ if (hasSeries != null)
{
- _saveItemCommand.GetParameter(index++).Value = season.IsVirtualItem.Value;
+ _saveItemCommand.GetParameter(index++).Value = hasSeries.SeriesName;
}
else
{
@@ -890,6 +903,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), transaction);
+ UpdateImages(item.Id, item.ImageInfos, transaction);
+ UpdateProviderIds(item.Id, item.ProviderIds, transaction);
UpdateItemValues(item.Id, GetItemValues(item), transaction);
}
@@ -966,7 +981,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (type == null)
{
- Logger.Debug("Unknown type {0}", typeString);
+ //Logger.Debug("Unknown type {0}", typeString);
return null;
}
@@ -1295,10 +1310,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.CriticRatingSummary = reader.GetString(57);
}
- var season = item as Season;
- if (season != null && !reader.IsDBNull(58))
+ if (!reader.IsDBNull(58))
{
- season.IsVirtualItem = reader.GetBoolean(58);
+ item.IsVirtualItem = reader.GetBoolean(58);
}
return item;
@@ -1450,7 +1464,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// or
/// cancellationToken
/// </exception>
- public async Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken)
+ public async Task SaveChapters(Guid id, List<ChapterInfo> chapters, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1549,14 +1563,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
private bool EnableJoinUserData(InternalItemsQuery query)
{
- if (_config.Configuration.SchemaVersion < 76)
+ if (query.User == null)
{
return false;
}
- if (query.User == null)
+ if (query.SimilarTo != null)
{
- return false;
+ return true;
}
if (query.SortBy != null && query.SortBy.Length > 0)
@@ -1611,7 +1625,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
return false;
}
- private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns)
+ private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns, IDbCommand cmd)
{
var list = startColumns.ToList();
@@ -1626,6 +1640,47 @@ namespace MediaBrowser.Server.Implementations.Persistence
list.Add("UserDataDb.UserData.rating");
}
+ if (query.SimilarTo != null)
+ {
+ var item = query.SimilarTo;
+
+ var builder = new StringBuilder();
+ builder.Append("(");
+
+ builder.Append("((OfficialRating=@ItemOfficialRating) * 10)");
+ //builder.Append("+ ((ProductionYear=@ItemProductionYear) * 10)");
+
+ builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 10 Then 2 Else 0 End )");
+ builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 5 Then 2 Else 0 End )");
+
+ //// genres
+ builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=2 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=2)) * 10)");
+
+ //// tags
+ builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=4 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=4)) * 10)");
+
+ builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=5 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=5)) * 10)");
+
+ builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=3 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=3)) * 3)");
+
+ //builder.Append("+ ((Select count(Name) from People where ItemId=Guid and Name in (select Name from People where ItemId=@SimilarItemId)) * 3)");
+
+ ////builder.Append("(select group_concat((Select Name from People where ItemId=Guid and Name in (Select Name from People where ItemId=@SimilarItemId)), '|'))");
+
+ builder.Append(") as SimilarityScore");
+
+ list.Add(builder.ToString());
+ cmd.Parameters.Add(cmd, "@ItemOfficialRating", DbType.String).Value = item.OfficialRating;
+ cmd.Parameters.Add(cmd, "@ItemProductionYear", DbType.Int32).Value = item.ProductionYear ?? 0;
+ cmd.Parameters.Add(cmd, "@SimilarItemId", DbType.Guid).Value = item.Id;
+
+ var excludeIds = query.ExcludeItemIds.ToList();
+ excludeIds.Add(item.Id.ToString("N"));
+ query.ExcludeItemIds = excludeIds.ToArray();
+
+ query.ExcludeProviderIds = item.ProviderIds;
+ }
+
return list.ToArray();
}
@@ -1639,6 +1694,33 @@ namespace MediaBrowser.Server.Implementations.Persistence
return " left join UserDataDb.UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserDataDb.UserData.Key";
}
+ private string GetGroupBy(InternalItemsQuery query)
+ {
+ var groups = new List<string>();
+
+ if (!string.IsNullOrWhiteSpace(query.GroupByAncestorOfType))
+ {
+ groups.Add("(Select PresentationUniqueKey from TypedBaseItems B where B.Type = 'MediaBrowser.Controller.Entities.TV.Series' And B.Guid in (Select AncestorId from AncestorIds where ItemId=A.Guid))");
+ }
+
+ if (EnableGroupByPresentationUniqueKey(query))
+ {
+ groups.Add("PresentationUniqueKey");
+ }
+
+ if (groups.Count > 0)
+ {
+ return " Group by " + string.Join(",", groups.ToArray());
+ }
+
+ return string.Empty;
+ }
+
+ private string GetFromText()
+ {
+ return " from TypedBaseItems A";
+ }
+
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
{
if (query == null)
@@ -1652,7 +1734,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns)) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + GetFromText();
cmd.CommandText += GetJoinUserDataText(query);
if (EnableJoinUserData(query))
@@ -1668,10 +1750,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
@@ -1710,7 +1789,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
var slowThreshold = 1000;
#if DEBUG
- slowThreshold = 200;
+ slowThreshold = 80;
#endif
if (elapsed >= slowThreshold)
@@ -1742,7 +1821,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns)) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + GetFromText();
cmd.CommandText += GetJoinUserDataText(query);
if (EnableJoinUserData(query))
@@ -1762,10 +1841,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
@@ -1781,13 +1857,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ cmd.CommandText += ";";
+
+ var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
+
+ if (isReturningZeroItems)
{
- cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems";
+ cmd.CommandText = "";
+ }
+
+ if (EnableGroupByPresentationUniqueKey(query))
+ {
+ cmd.CommandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
}
else
{
- cmd.CommandText += "; select count (guid) from TypedBaseItems";
+ cmd.CommandText += " select count (guid)" + GetFromText();
}
cmd.CommandText += GetJoinUserDataText(query);
@@ -1800,18 +1885,28 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
LogQueryTime("GetItems", cmd, now);
- while (reader.Read())
+ if (isReturningZeroItems)
{
- var item = GetItem(reader);
- if (item != null)
+ if (reader.Read())
{
- list.Add(item);
+ count = reader.GetInt32(0);
}
}
-
- if (reader.NextResult() && reader.Read())
+ else
{
- count = reader.GetInt32(0);
+ while (reader.Read())
+ {
+ var item = GetItem(reader);
+ if (item != null)
+ {
+ list.Add(item);
+ }
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
}
@@ -1825,6 +1920,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
private string GetOrderByText(InternalItemsQuery query)
{
+ if (query.SimilarTo != null)
+ {
+ if (query.SortBy == null || query.SortBy.Length == 0)
+ {
+ if (query.User != null)
+ {
+ query.SortBy = new[] { "SimilarityScore", "IsPlayed", "Random" };
+ }
+ else
+ {
+ query.SortBy = new[] { "SimilarityScore", "Random" };
+ }
+ query.SortOrder = SortOrder.Descending;
+ }
+ }
+
if (query.SortBy == null || query.SortBy.Length == 0)
{
return string.Empty;
@@ -1834,7 +1945,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
return " ORDER BY " + string.Join(",", query.SortBy.Select(i =>
{
- var columnMap = MapOrderByField(i, EnableJoinUserData(query));
+ var columnMap = MapOrderByField(i, query);
var columnAscending = isAscending;
if (columnMap.Item2)
{
@@ -1847,7 +1958,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}).ToArray());
}
- private Tuple<string, bool> MapOrderByField(string name, bool enableUserData)
+ private Tuple<string, bool> MapOrderByField(string name, InternalItemsQuery query)
{
if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase))
{
@@ -1862,58 +1973,30 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return new Tuple<string, bool>("RANDOM()", false);
}
+ if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("LastPlayedDate", false);
+ }
+ if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("PlayCount", false);
+ }
+ if (string.Equals(name, ItemSortBy.IsFavoriteOrLiked, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("IsFavorite", true);
+ }
if (string.Equals(name, ItemSortBy.IsFolder, StringComparison.OrdinalIgnoreCase))
{
return new Tuple<string, bool>("IsFolder", true);
}
-
- if (enableUserData)
+ if (string.Equals(name, ItemSortBy.IsPlayed, StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("LastPlayedDate", false);
- }
- if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("PlayCount", false);
- }
- if (string.Equals(name, ItemSortBy.IsFavoriteOrLiked, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("IsFavorite", true);
- }
- if (string.Equals(name, ItemSortBy.IsPlayed, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("played", true);
- }
- if (string.Equals(name, ItemSortBy.IsUnplayed, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("played", false);
- }
+ return new Tuple<string, bool>("played", true);
}
- else
+ if (string.Equals(name, ItemSortBy.IsUnplayed, StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("DateCreated", false);
- }
- if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("DateCreated", false);
- }
- if (string.Equals(name, ItemSortBy.IsFavoriteOrLiked, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("DateCreated", true);
- }
- if (string.Equals(name, ItemSortBy.IsPlayed, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("DateCreated", true);
- }
- if (string.Equals(name, ItemSortBy.IsUnplayed, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, bool>("DateCreated", false);
- }
+ return new Tuple<string, bool>("played", false);
}
-
if (string.Equals(name, ItemSortBy.DateLastContentAdded, StringComparison.OrdinalIgnoreCase))
{
return new Tuple<string, bool>("DateLastMediaAdded", false);
@@ -1926,6 +2009,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return new Tuple<string, bool>("(select value from itemvalues where ItemId=Guid and Type=1 LIMIT 1)", false);
}
+ if (string.Equals(name, ItemSortBy.OfficialRating, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("ParentalRatingValue", false);
+ }
+ if (string.Equals(name, ItemSortBy.Studio, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("(select value from itemvalues where ItemId=Guid and Type=3 LIMIT 1)", false);
+ }
+ if (string.Equals(name, ItemSortBy.SeriesDatePlayed, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("(Select MAX(LastPlayedDate) from TypedBaseItems B"+ GetJoinUserDataText(query) + " where B.Guid in (Select ItemId from AncestorIds where AncestorId in (select guid from typedbaseitems c where C.Type = 'MediaBrowser.Controller.Entities.TV.Series' And C.Guid in (Select AncestorId from AncestorIds where ItemId=A.Guid))))", false);
+ }
return new Tuple<string, bool>(name, false);
}
@@ -1943,7 +2038,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" })) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + GetFromText();
cmd.CommandText += GetJoinUserDataText(query);
if (EnableJoinUserData(query))
@@ -1959,10 +2054,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
@@ -2019,10 +2111,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
@@ -2086,7 +2175,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" })) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + GetFromText();
var whereClauses = GetWhereClauses(query, cmd);
cmd.CommandText += GetJoinUserDataText(query);
@@ -2102,10 +2191,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
@@ -2121,13 +2207,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ if (EnableGroupByPresentationUniqueKey(query))
{
- cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems";
+ cmd.CommandText += "; select count (distinct PresentationUniqueKey)" + GetFromText();
}
else
{
- cmd.CommandText += "; select count (guid) from TypedBaseItems";
+ cmd.CommandText += "; select count (guid)" + GetFromText();
}
cmd.CommandText += GetJoinUserDataText(query);
@@ -2196,7 +2282,24 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
if (query.IsMovie.HasValue)
{
- whereClauses.Add("IsMovie=@IsMovie");
+ var alternateTypes = new List<string>();
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
+ {
+ alternateTypes.Add(typeof(Movie).FullName);
+ }
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
+ {
+ alternateTypes.Add(typeof(Trailer).FullName);
+ }
+
+ if (alternateTypes.Count == 0)
+ {
+ whereClauses.Add("IsMovie=@IsMovie");
+ }
+ else
+ {
+ whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)");
+ }
cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
}
if (query.IsKids.HasValue)
@@ -2302,6 +2405,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("ParentIndexNumber=@ParentIndexNumber");
cmd.Parameters.Add(cmd, "@ParentIndexNumber", DbType.Int32).Value = query.ParentIndexNumber.Value;
}
+ if (query.ParentIndexNumberNotEquals.HasValue)
+ {
+ whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)");
+ cmd.Parameters.Add(cmd, "@ParentIndexNumberNotEquals", DbType.Int32).Value = query.ParentIndexNumberNotEquals.Value;
+ }
if (query.MinEndDate.HasValue)
{
whereClauses.Add("EndDate>=@MinEndDate");
@@ -2398,41 +2506,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (!string.IsNullOrWhiteSpace(query.SlugName))
{
- if (_config.Configuration.SchemaVersion >= 70)
- {
- whereClauses.Add("SlugName=@SlugName");
- }
- else
- {
- whereClauses.Add("Name=@SlugName");
- }
+ whereClauses.Add("SlugName=@SlugName");
cmd.Parameters.Add(cmd, "@SlugName", DbType.String).Value = query.SlugName;
}
if (!string.IsNullOrWhiteSpace(query.Name))
{
- if (_config.Configuration.SchemaVersion >= 66)
- {
- whereClauses.Add("CleanName=@Name");
- cmd.Parameters.Add(cmd, "@Name", DbType.String).Value = query.Name.RemoveDiacritics();
- }
- else
- {
- whereClauses.Add("Name=@Name");
- cmd.Parameters.Add(cmd, "@Name", DbType.String).Value = query.Name;
- }
+ whereClauses.Add("CleanName=@Name");
+ cmd.Parameters.Add(cmd, "@Name", DbType.String).Value = query.Name.RemoveDiacritics();
}
if (!string.IsNullOrWhiteSpace(query.NameContains))
{
- if (_config.Configuration.SchemaVersion >= 66)
- {
- whereClauses.Add("CleanName like @NameContains");
- }
- else
- {
- whereClauses.Add("Name like @NameContains");
- }
+ whereClauses.Add("CleanName like @NameContains");
cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + query.NameContains.RemoveDiacritics() + "%";
}
if (!string.IsNullOrWhiteSpace(query.NameStartsWith))
@@ -2453,48 +2539,61 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.Parameters.Add(cmd, "@NameLessThan", DbType.String).Value = query.NameLessThan.ToLower();
}
- if (EnableJoinUserData(query))
+ if (query.ImageTypes.Length > 0 && _config.Configuration.SchemaVersion >= 87)
{
- if (query.IsLiked.HasValue)
+ var requiredImageIndex = 0;
+
+ foreach (var requiredImage in query.ImageTypes)
{
- if (query.IsLiked.Value)
- {
- whereClauses.Add("rating>=@UserRating");
- cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue;
- }
- else
- {
- whereClauses.Add("(rating is null or rating<@UserRating)");
- cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue;
- }
+ var paramName = "@RequiredImageType" + requiredImageIndex;
+ whereClauses.Add("(select path from images where ItemId=Guid and ImageType=" + paramName + " limit 1) not null");
+ cmd.Parameters.Add(cmd, paramName, DbType.Int32).Value = (int)requiredImage;
+ requiredImageIndex++;
}
+ }
- if (query.IsFavoriteOrLiked.HasValue)
+ if (query.IsLiked.HasValue)
+ {
+ if (query.IsLiked.Value)
{
- if (query.IsFavoriteOrLiked.Value)
- {
- whereClauses.Add("IsFavorite=@IsFavoriteOrLiked");
- }
- else
- {
- whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavoriteOrLiked)");
- }
- cmd.Parameters.Add(cmd, "@IsFavoriteOrLiked", DbType.Boolean).Value = query.IsFavoriteOrLiked.Value;
+ whereClauses.Add("rating>=@UserRating");
+ cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue;
+ }
+ else
+ {
+ whereClauses.Add("(rating is null or rating<@UserRating)");
+ cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue;
+ }
+ }
+
+ if (query.IsFavoriteOrLiked.HasValue)
+ {
+ if (query.IsFavoriteOrLiked.Value)
+ {
+ whereClauses.Add("IsFavorite=@IsFavoriteOrLiked");
+ }
+ else
+ {
+ whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavoriteOrLiked)");
}
+ cmd.Parameters.Add(cmd, "@IsFavoriteOrLiked", DbType.Boolean).Value = query.IsFavoriteOrLiked.Value;
+ }
- if (query.IsFavorite.HasValue)
+ if (query.IsFavorite.HasValue)
+ {
+ if (query.IsFavorite.Value)
{
- if (query.IsFavorite.Value)
- {
- whereClauses.Add("IsFavorite=@IsFavorite");
- }
- else
- {
- whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavorite)");
- }
- cmd.Parameters.Add(cmd, "@IsFavorite", DbType.Boolean).Value = query.IsFavorite.Value;
+ whereClauses.Add("IsFavorite=@IsFavorite");
+ }
+ else
+ {
+ whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavorite)");
}
+ cmd.Parameters.Add(cmd, "@IsFavorite", DbType.Boolean).Value = query.IsFavorite.Value;
+ }
+ if (EnableJoinUserData(query))
+ {
if (query.IsPlayed.HasValue)
{
if (query.IsPlayed.Value)
@@ -2507,17 +2606,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
cmd.Parameters.Add(cmd, "@IsPlayed", DbType.Boolean).Value = query.IsPlayed.Value;
}
+ }
- if (query.IsResumable.HasValue)
+ if (query.IsResumable.HasValue)
+ {
+ if (query.IsResumable.Value)
{
- if (query.IsResumable.Value)
- {
- whereClauses.Add("playbackPositionTicks > 0");
- }
- else
- {
- whereClauses.Add("(playbackPositionTicks is null or playbackPositionTicks = 0)");
- }
+ whereClauses.Add("playbackPositionTicks > 0");
+ }
+ else
+ {
+ whereClauses.Add("(playbackPositionTicks is null or playbackPositionTicks = 0)");
}
}
@@ -2541,8 +2640,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var item in query.Genres)
{
- clauses.Add("Genres like @Genres" + index);
- cmd.Parameters.Add(cmd, "@Genres" + index, DbType.String).Value = "%" + item + "%";
+ clauses.Add("@Genre" + index + " in (select value from itemvalues where ItemId=Guid and Type=2)");
+ cmd.Parameters.Add(cmd, "@Genre" + index, DbType.String).Value = item;
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2555,8 +2654,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var item in query.Tags)
{
- clauses.Add("Tags like @Tags" + index);
- cmd.Parameters.Add(cmd, "@Tags" + index, DbType.String).Value = "%" + item + "%";
+ clauses.Add("@Tag" + index + " in (select value from itemvalues where ItemId=Guid and Type=4)");
+ cmd.Parameters.Add(cmd, "@Tag" + index, DbType.String).Value = item;
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2569,8 +2668,36 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var item in query.Studios)
{
- clauses.Add("Studios like @Studios" + index);
- cmd.Parameters.Add(cmd, "@Studios" + index, DbType.String).Value = "%" + item + "%";
+ clauses.Add("@Studio" + index + " in (select value from itemvalues where ItemId=Guid and Type=3)");
+ cmd.Parameters.Add(cmd, "@Studio" + index, DbType.String).Value = item;
+ index++;
+ }
+ var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+ whereClauses.Add(clause);
+ }
+
+ if (query.Keywords.Length > 0)
+ {
+ var clauses = new List<string>();
+ var index = 0;
+ foreach (var item in query.Keywords)
+ {
+ clauses.Add("@Keyword" + index + " in (select value from itemvalues where ItemId=Guid and Type=5)");
+ cmd.Parameters.Add(cmd, "@Keyword" + index, DbType.String).Value = item;
+ index++;
+ }
+ var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+ whereClauses.Add(clause);
+ }
+
+ if (query.OfficialRatings.Length > 0)
+ {
+ var clauses = new List<string>();
+ var index = 0;
+ foreach (var item in query.OfficialRatings)
+ {
+ clauses.Add("OfficialRating=@OfficialRating" + index);
+ cmd.Parameters.Add(cmd, "@OfficialRating" + index, DbType.String).Value = item;
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2635,8 +2762,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (query.LocationTypes.Length == 1)
{
- whereClauses.Add("LocationType=@LocationType");
- cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationTypes[0].ToString();
+ if (query.LocationTypes[0] == LocationType.Virtual && _config.Configuration.SchemaVersion >= 90)
+ {
+ query.IsVirtualItem = true;
+ }
+ else
+ {
+ whereClauses.Add("LocationType=@LocationType");
+ cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationTypes[0].ToString();
+ }
}
else if (query.LocationTypes.Length > 1)
{
@@ -2646,8 +2780,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
if (query.ExcludeLocationTypes.Length == 1)
{
- whereClauses.Add("LocationType<>@ExcludeLocationTypes");
- cmd.Parameters.Add(cmd, "@ExcludeLocationTypes", DbType.String).Value = query.ExcludeLocationTypes[0].ToString();
+ if (query.ExcludeLocationTypes[0] == LocationType.Virtual && _config.Configuration.SchemaVersion >= 90)
+ {
+ query.IsVirtualItem = false;
+ }
+ else
+ {
+ whereClauses.Add("LocationType<>@ExcludeLocationTypes");
+ cmd.Parameters.Add(cmd, "@ExcludeLocationTypes", DbType.String).Value = query.ExcludeLocationTypes[0].ToString();
+ }
}
else if (query.ExcludeLocationTypes.Length > 1)
{
@@ -2655,6 +2796,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("LocationType not in (" + val + ")");
}
+ if (query.IsVirtualItem.HasValue)
+ {
+ whereClauses.Add("IsVirtualItem=@IsVirtualItem");
+ cmd.Parameters.Add(cmd, "@IsVirtualItem", DbType.Boolean).Value = query.IsVirtualItem.Value;
+ }
if (query.MediaTypes.Length == 1)
{
whereClauses.Add("MediaType=@MediaTypes");
@@ -2666,6 +2812,59 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("MediaType in (" + val + ")");
}
+ if (query.ExcludeItemIds.Length > 0)
+ {
+ var excludeIds = new List<string>();
+
+ var index = 0;
+ foreach (var id in query.ExcludeItemIds)
+ {
+ excludeIds.Add("Guid <> @ExcludeId" + index);
+ cmd.Parameters.Add(cmd, "@ExcludeId" + index, DbType.Guid).Value = new Guid(id);
+ index++;
+ }
+
+ whereClauses.Add(string.Join(" AND ", excludeIds.ToArray()));
+ }
+
+ if (query.ExcludeProviderIds.Count > 0)
+ {
+ var excludeIds = new List<string>();
+
+ var index = 0;
+ foreach (var pair in query.ExcludeProviderIds)
+ {
+ if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ var paramName = "@ExcludeProviderId" + index;
+ excludeIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
+ cmd.Parameters.Add(cmd, paramName, DbType.String).Value = pair.Value;
+ index++;
+ }
+
+ whereClauses.Add(string.Join(" AND ", excludeIds.ToArray()));
+ }
+
+ if (query.HasImdbId.HasValue)
+ {
+ var fn = query.HasImdbId.Value ? "<>" : "=";
+ whereClauses.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = 'Imdb'), '') " + fn + " '')");
+ }
+
+ if (query.HasTmdbId.HasValue)
+ {
+ var fn = query.HasTmdbId.Value ? "<>" : "=";
+ whereClauses.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = 'Tmdb'), '') " + fn + " '')");
+ }
+
+ if (query.HasTvdbId.HasValue)
+ {
+ var fn = query.HasTvdbId.Value ? "<>" : "=";
+ whereClauses.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = 'Tvdb'), '') " + fn + " '')");
+ }
if (query.AlbumNames.Length > 0)
{
@@ -3077,6 +3276,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
_deleteItemValuesCommand.Transaction = transaction;
_deleteItemValuesCommand.ExecuteNonQuery();
+ // Delete provider ids
+ _deleteProviderIdsCommand.GetParameter(0).Value = id;
+ _deleteProviderIdsCommand.Transaction = transaction;
+ _deleteProviderIdsCommand.ExecuteNonQuery();
+
+ // Delete images
+ _deleteImagesCommand.GetParameter(0).Value = id;
+ _deleteImagesCommand.Transaction = transaction;
+ _deleteImagesCommand.ExecuteNonQuery();
+
// Delete the item
_deleteItemCommand.GetParameter(0).Value = id;
_deleteItemCommand.Transaction = transaction;
@@ -3285,9 +3494,91 @@ namespace MediaBrowser.Server.Implementations.Persistence
list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => new Tuple<int, string>(1, i)));
}
+ list.AddRange(item.Genres.Select(i => new Tuple<int, string>(2, i)));
+ list.AddRange(item.Studios.Select(i => new Tuple<int, string>(3, i)));
+ list.AddRange(item.Tags.Select(i => new Tuple<int, string>(4, i)));
+ list.AddRange(item.Keywords.Select(i => new Tuple<int, string>(5, i)));
+
return list;
}
+ private void UpdateImages(Guid itemId, List<ItemImageInfo> images, IDbTransaction transaction)
+ {
+ if (itemId == Guid.Empty)
+ {
+ throw new ArgumentNullException("itemId");
+ }
+
+ if (images == null)
+ {
+ throw new ArgumentNullException("images");
+ }
+
+ CheckDisposed();
+
+ // First delete
+ _deleteImagesCommand.GetParameter(0).Value = itemId;
+ _deleteImagesCommand.Transaction = transaction;
+
+ _deleteImagesCommand.ExecuteNonQuery();
+
+ var index = 0;
+ foreach (var image in images)
+ {
+ _saveImagesCommand.GetParameter(0).Value = itemId;
+ _saveImagesCommand.GetParameter(1).Value = image.Type;
+ _saveImagesCommand.GetParameter(2).Value = image.Path;
+
+ if (image.DateModified == default(DateTime))
+ {
+ _saveImagesCommand.GetParameter(3).Value = null;
+ }
+ else
+ {
+ _saveImagesCommand.GetParameter(3).Value = image.DateModified;
+ }
+
+ _saveImagesCommand.GetParameter(4).Value = image.IsPlaceholder;
+ _saveImagesCommand.GetParameter(5).Value = index;
+
+ _saveImagesCommand.Transaction = transaction;
+
+ _saveImagesCommand.ExecuteNonQuery();
+ index++;
+ }
+ }
+
+ private void UpdateProviderIds(Guid itemId, Dictionary<string, string> values, IDbTransaction transaction)
+ {
+ if (itemId == Guid.Empty)
+ {
+ throw new ArgumentNullException("itemId");
+ }
+
+ if (values == null)
+ {
+ throw new ArgumentNullException("values");
+ }
+
+ CheckDisposed();
+
+ // First delete
+ _deleteProviderIdsCommand.GetParameter(0).Value = itemId;
+ _deleteProviderIdsCommand.Transaction = transaction;
+
+ _deleteProviderIdsCommand.ExecuteNonQuery();
+
+ foreach (var pair in values)
+ {
+ _saveProviderIdsCommand.GetParameter(0).Value = itemId;
+ _saveProviderIdsCommand.GetParameter(1).Value = pair.Key;
+ _saveProviderIdsCommand.GetParameter(2).Value = pair.Value;
+ _saveProviderIdsCommand.Transaction = transaction;
+
+ _saveProviderIdsCommand.ExecuteNonQuery();
+ }
+ }
+
private void UpdateItemValues(Guid itemId, List<Tuple<int, string>> values, IDbTransaction transaction)
{
if (itemId == Guid.Empty)
@@ -3505,7 +3796,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
return list;
}
- public async Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken)
+ public async Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -3578,6 +3869,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveStreamCommand.GetParameter(index++).Value = stream.IsAVC;
_saveStreamCommand.GetParameter(index++).Value = stream.Title;
+ _saveStreamCommand.GetParameter(index++).Value = stream.TimeBase;
+ _saveStreamCommand.GetParameter(index++).Value = stream.CodecTimeBase;
+
_saveStreamCommand.Transaction = transaction;
_saveStreamCommand.ExecuteNonQuery();
}
@@ -3750,6 +4044,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.Title = reader.GetString(29);
}
+ if (!reader.IsDBNull(30))
+ {
+ item.TimeBase = reader.GetString(30);
+ }
+
+ if (!reader.IsDBNull(31))
+ {
+ item.CodecTimeBase = reader.GetString(31);
+ }
+
return item;
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
deleted file mode 100644
index 40d5c9586..000000000
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
+++ /dev/null
@@ -1,248 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Data;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Persistence
-{
- public class SqliteProviderInfoRepository : BaseSqliteRepository, IProviderRepository
- {
- private IDbConnection _connection;
-
- private IDbCommand _saveStatusCommand;
- private readonly IApplicationPaths _appPaths;
-
- public SqliteProviderInfoRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
- {
- _appPaths = appPaths;
- }
-
- /// <summary>
- /// Gets the name of the repository
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get
- {
- return "SQLite";
- }
- }
-
- /// <summary>
- /// Opens the connection to the database
- /// </summary>
- /// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
- {
- var dbFile = Path.Combine(_appPaths.DataPath, "refreshinfo.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
-
- "create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, ItemDateModified DateTimeNull)",
- "create index if not exists idx_MetadataStatus on MetadataStatus(ItemId)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
- };
-
- _connection.RunQueries(queries, Logger);
-
- AddItemDateModifiedCommand();
-
- PrepareStatements();
- }
-
- private static readonly string[] StatusColumns =
- {
- "ItemId",
- "DateLastMetadataRefresh",
- "DateLastImagesRefresh",
- "ItemDateModified"
- };
-
- private void AddItemDateModifiedCommand()
- {
- using (var cmd = _connection.CreateCommand())
- {
- cmd.CommandText = "PRAGMA table_info(MetadataStatus)";
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
- {
- while (reader.Read())
- {
- if (!reader.IsDBNull(1))
- {
- var name = reader.GetString(1);
-
- if (string.Equals(name, "ItemDateModified", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- }
- }
- }
- }
-
- var builder = new StringBuilder();
-
- builder.AppendLine("alter table MetadataStatus");
- builder.AppendLine("add column ItemDateModified DateTime NULL");
-
- _connection.RunQueries(new[] { builder.ToString() }, Logger);
- }
-
- /// <summary>
- /// Prepares the statements.
- /// </summary>
- private void PrepareStatements()
- {
- _saveStatusCommand = _connection.CreateCommand();
-
- _saveStatusCommand.CommandText = string.Format("replace into MetadataStatus ({0}) values ({1})",
- string.Join(",", StatusColumns),
- string.Join(",", StatusColumns.Select(i => "@" + i).ToArray()));
-
- foreach (var col in StatusColumns)
- {
- _saveStatusCommand.Parameters.Add(_saveStatusCommand, "@" + col);
- }
- }
-
- public MetadataStatus GetMetadataStatus(Guid itemId)
- {
- if (itemId == Guid.Empty)
- {
- throw new ArgumentNullException("itemId");
- }
-
- using (var cmd = _connection.CreateCommand())
- {
- var cmdText = "select " + string.Join(",", StatusColumns) + " from MetadataStatus where";
-
- cmdText += " ItemId=@ItemId";
- cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = itemId;
-
- cmd.CommandText = cmdText;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- while (reader.Read())
- {
- return GetStatus(reader);
- }
-
- return null;
- }
- }
- }
-
- private MetadataStatus GetStatus(IDataReader reader)
- {
- var result = new MetadataStatus
- {
- ItemId = reader.GetGuid(0)
- };
-
- if (!reader.IsDBNull(1))
- {
- result.DateLastMetadataRefresh = reader.GetDateTime(1).ToUniversalTime();
- }
-
- if (!reader.IsDBNull(2))
- {
- result.DateLastImagesRefresh = reader.GetDateTime(2).ToUniversalTime();
- }
-
- if (!reader.IsDBNull(3))
- {
- result.ItemDateModified = reader.GetDateTime(3).ToUniversalTime();
- }
-
- return result;
- }
-
- public async Task SaveMetadataStatus(MetadataStatus status, CancellationToken cancellationToken)
- {
- if (status == null)
- {
- throw new ArgumentNullException("status");
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- _saveStatusCommand.GetParameter(0).Value = status.ItemId;
- _saveStatusCommand.GetParameter(1).Value = status.DateLastMetadataRefresh;
- _saveStatusCommand.GetParameter(2).Value = status.DateLastImagesRefresh;
- _saveStatusCommand.GetParameter(3).Value = status.ItemDateModified;
-
- _saveStatusCommand.Transaction = transaction;
-
- _saveStatusCommand.ExecuteNonQuery();
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save provider info:", e);
-
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
-
- WriteLock.Release();
- }
- }
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
index 7f3b32e06..f40006b44 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
@@ -5,7 +5,9 @@ using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Data;
+using System.Globalization;
using System.IO;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -14,11 +16,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
{
private IDbConnection _connection;
- private readonly IApplicationPaths _appPaths;
- public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
+ public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "userdata_v2.db");
+ }
+
+ protected override bool EnableConnectionPooling
+ {
+ get { return false; }
}
/// <summary>
@@ -33,15 +39,26 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ protected override async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
+ {
+ var connection = await DbConnector.Connect(DbFilePath, false, false, 10000).ConfigureAwait(false);
+
+ connection.RunQueries(new[]
+ {
+ "pragma temp_store = memory"
+
+ }, Logger);
+
+ return connection;
+ }
+
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
+ _connection = await CreateConnection(false).ConfigureAwait(false);
string[] queries = {
@@ -300,6 +317,52 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ public UserItemData GetUserData(Guid userId, List<string> keys)
+ {
+ if (userId == Guid.Empty)
+ {
+ throw new ArgumentNullException("userId");
+ }
+ if (keys == null)
+ {
+ throw new ArgumentNullException("keys");
+ }
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ var index = 0;
+ var excludeIds = new List<string>();
+ var builder = new StringBuilder();
+ foreach (var key in keys)
+ {
+ var paramName = "@Key" + index;
+ excludeIds.Add("Key =" + paramName);
+ cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key;
+ builder.Append(" WHEN Key=" + paramName + " THEN " + index);
+ index++;
+ }
+
+ var keyText = string.Join(" OR ", excludeIds.ToArray());
+
+ cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") ";
+
+ cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )";
+ cmd.CommandText += " LIMIT 1";
+
+ cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ {
+ if (reader.Read())
+ {
+ return ReadRow(reader);
+ }
+ }
+
+ return null;
+ }
+ }
+
/// <summary>
/// Return all user-data associated with the given user
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
index f7ca39a54..25ab60ca5 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
@@ -17,14 +17,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
{
- private IDbConnection _connection;
- private readonly IServerApplicationPaths _appPaths;
private readonly IJsonSerializer _jsonSerializer;
- public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer) : base(logManager)
+ public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer, IDbConnector dbConnector) : base(logManager, dbConnector)
{
- _appPaths = appPaths;
_jsonSerializer = jsonSerializer;
+
+ DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
}
/// <summary>
@@ -43,25 +42,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists users (guid GUID primary key, data BLOB)",
"create index if not exists idx_users on users(guid)",
"create table if not exists schema_version (table_name primary key, version)",
- //pragmas
- "pragma temp_store = memory",
-
"pragma shrink_memory"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
+ }
}
/// <summary>
@@ -84,55 +79,54 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- using (var cmd = _connection.CreateCommand())
+ try
{
- cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
- cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = user.Id;
- cmd.Parameters.Add(cmd, "@2", DbType.Binary).Value = serialized;
+ transaction = connection.BeginTransaction();
+
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
+ cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = user.Id;
+ cmd.Parameters.Add(cmd, "@2", DbType.Binary).Value = serialized;
- cmd.Transaction = transaction;
+ cmd.Transaction = transaction;
- cmd.ExecuteNonQuery();
- }
+ cmd.ExecuteNonQuery();
+ }
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
{
- transaction.Rollback();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save user:", e);
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save user:", e);
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ throw;
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ finally
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- WriteLock.Release();
}
}
@@ -142,25 +136,32 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// <returns>IEnumerable{User}.</returns>
public IEnumerable<User> RetrieveAllUsers()
{
- using (var cmd = _connection.CreateCommand())
- {
- cmd.CommandText = "select guid,data from users";
+ var list = new List<User>();
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ using (var connection = CreateConnection(true).Result)
+ {
+ using (var cmd = connection.CreateCommand())
{
- while (reader.Read())
- {
- var id = reader.GetGuid(0);
+ cmd.CommandText = "select guid,data from users";
- using (var stream = reader.GetMemoryStream(1))
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
{
- var user = _jsonSerializer.DeserializeFromStream<User>(stream);
- user.Id = id;
- yield return user;
+ var id = reader.GetGuid(0);
+
+ using (var stream = reader.GetMemoryStream(1))
+ {
+ var user = _jsonSerializer.DeserializeFromStream<User>(stream);
+ user.Id = id;
+ list.Add(user);
+ }
}
}
}
}
+
+ return list;
}
/// <summary>
@@ -179,69 +180,54 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- using (var cmd = _connection.CreateCommand())
+ try
{
- cmd.CommandText = "delete from users where guid=@guid";
+ transaction = connection.BeginTransaction();
- cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = user.Id;
-
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "delete from users where guid=@guid";
- cmd.ExecuteNonQuery();
- }
+ cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = user.Id;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ cmd.Transaction = transaction;
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to delete user:", e);
+ cmd.ExecuteNonQuery();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ transaction.Commit();
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ catch (OperationCanceledException)
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to delete user:", e);
- WriteLock.Release();
- }
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
+ throw;
+ }
+ finally
{
- _connection.Close();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- _connection.Dispose();
- _connection = null;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
index e8d9814ec..74a552dcc 100644
--- a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
@@ -15,57 +15,30 @@ namespace MediaBrowser.Server.Implementations.Security
{
public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository
{
- private IDbConnection _connection;
private readonly IServerApplicationPaths _appPaths;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _saveInfoCommand;
-
- public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths)
- : base(logManager)
+ public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector)
+ : base(logManager, connector)
{
_appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "authentication.db");
}
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "authentication.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, AppVersion TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)",
- "create index if not exists idx_AccessTokens on AccessTokens(Id)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_AccessTokens on AccessTokens(Id)"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
- _connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT");
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _saveInfoCommand = _connection.CreateCommand();
- _saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)";
-
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@Id");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AccessToken");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceId");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppName");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppVersion");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceName");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@UserId");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@IsActive");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateCreated");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateRevoked");
+ connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT");
+ }
}
public Task Create(AuthenticationInfo info, CancellationToken cancellationToken)
@@ -84,61 +57,76 @@ namespace MediaBrowser.Server.Implementations.Security
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ using (var saveInfoCommand = connection.CreateCommand())
+ {
+ saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)";
+
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@Id");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@AccessToken");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceId");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppName");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppVersion");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceName");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@UserId");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@IsActive");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateCreated");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateRevoked");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
- var index = 0;
+ var index = 0;
- _saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id);
- _saveInfoCommand.GetParameter(index++).Value = info.AccessToken;
- _saveInfoCommand.GetParameter(index++).Value = info.DeviceId;
- _saveInfoCommand.GetParameter(index++).Value = info.AppName;
- _saveInfoCommand.GetParameter(index++).Value = info.AppVersion;
- _saveInfoCommand.GetParameter(index++).Value = info.DeviceName;
- _saveInfoCommand.GetParameter(index++).Value = info.UserId;
- _saveInfoCommand.GetParameter(index++).Value = info.IsActive;
- _saveInfoCommand.GetParameter(index++).Value = info.DateCreated;
- _saveInfoCommand.GetParameter(index++).Value = info.DateRevoked;
+ saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id);
+ saveInfoCommand.GetParameter(index++).Value = info.AccessToken;
+ saveInfoCommand.GetParameter(index++).Value = info.DeviceId;
+ saveInfoCommand.GetParameter(index++).Value = info.AppName;
+ saveInfoCommand.GetParameter(index++).Value = info.AppVersion;
+ saveInfoCommand.GetParameter(index++).Value = info.DeviceName;
+ saveInfoCommand.GetParameter(index++).Value = info.UserId;
+ saveInfoCommand.GetParameter(index++).Value = info.IsActive;
+ saveInfoCommand.GetParameter(index++).Value = info.DateCreated;
+ saveInfoCommand.GetParameter(index++).Value = info.DateRevoked;
- _saveInfoCommand.Transaction = transaction;
+ saveInfoCommand.Transaction = transaction;
- _saveInfoCommand.ExecuteNonQuery();
+ saveInfoCommand.ExecuteNonQuery();
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -151,101 +139,104 @@ namespace MediaBrowser.Server.Implementations.Security
throw new ArgumentNullException("query");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseSelectText;
-
- var whereClauses = new List<string>();
-
- var startIndex = query.StartIndex ?? 0;
-
- if (!string.IsNullOrWhiteSpace(query.AccessToken))
+ using (var cmd = connection.CreateCommand())
{
- whereClauses.Add("AccessToken=@AccessToken");
- cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken;
- }
+ cmd.CommandText = BaseSelectText;
- if (!string.IsNullOrWhiteSpace(query.UserId))
- {
- whereClauses.Add("UserId=@UserId");
- cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
- }
+ var whereClauses = new List<string>();
- if (!string.IsNullOrWhiteSpace(query.DeviceId))
- {
- whereClauses.Add("DeviceId=@DeviceId");
- cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId;
- }
+ var startIndex = query.StartIndex ?? 0;
- if (query.IsActive.HasValue)
- {
- whereClauses.Add("IsActive=@IsActive");
- cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value;
- }
+ if (!string.IsNullOrWhiteSpace(query.AccessToken))
+ {
+ whereClauses.Add("AccessToken=@AccessToken");
+ cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken;
+ }
- if (query.HasUser.HasValue)
- {
- if (query.HasUser.Value)
+ if (!string.IsNullOrWhiteSpace(query.UserId))
{
- whereClauses.Add("UserId not null");
+ whereClauses.Add("UserId=@UserId");
+ cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
}
- else
+
+ if (!string.IsNullOrWhiteSpace(query.DeviceId))
{
- whereClauses.Add("UserId is null");
+ whereClauses.Add("DeviceId=@DeviceId");
+ cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId;
}
- }
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ if (query.IsActive.HasValue)
+ {
+ whereClauses.Add("IsActive=@IsActive");
+ cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value;
+ }
- if (startIndex > 0)
- {
- var pagingWhereText = whereClauses.Count == 0 ?
+ if (query.HasUser.HasValue)
+ {
+ if (query.HasUser.Value)
+ {
+ whereClauses.Add("UserId not null");
+ }
+ else
+ {
+ whereClauses.Add("UserId is null");
+ }
+ }
+
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
- pagingWhereText,
- startIndex.ToString(_usCulture)));
- }
+ if (startIndex > 0)
+ {
+ var pagingWhereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- var whereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
+ pagingWhereText,
+ startIndex.ToString(_usCulture)));
+ }
- cmd.CommandText += whereText;
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- cmd.CommandText += " ORDER BY DateCreated";
+ cmd.CommandText += whereText;
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ cmd.CommandText += " ORDER BY DateCreated";
- cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging;
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- var list = new List<AuthenticationInfo>();
- var count = 0;
+ cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ var list = new List<AuthenticationInfo>();
+ var count = 0;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(Get(reader));
+ while (reader.Read())
+ {
+ list.Add(Get(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<AuthenticationInfo>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<AuthenticationInfo>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -256,24 +247,27 @@ namespace MediaBrowser.Server.Implementations.Security
throw new ArgumentNullException("id");
}
- var guid = new Guid(id);
-
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseSelectText + " where Id=@Id";
-
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+ var guid = new Guid(id);
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ using (var cmd = connection.CreateCommand())
{
- if (reader.Read())
+ cmd.CommandText = BaseSelectText + " where Id=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return Get(reader);
+ if (reader.Read())
+ {
+ return Get(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
private AuthenticationInfo Get(IDataReader reader)
@@ -319,19 +313,5 @@ namespace MediaBrowser.Server.Implementations.Security
return info;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 77843ef6b..098fe0b4d 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -404,6 +404,10 @@ namespace MediaBrowser.Server.Implementations.Session
/// <returns>SessionInfo.</returns>
private async Task<SessionInfo> GetSessionInfo(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
{
+ if (string.IsNullOrWhiteSpace(deviceId))
+ {
+ throw new ArgumentNullException("deviceId");
+ }
var key = GetSessionKey(appName, deviceId);
await _sessionLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
@@ -1447,7 +1451,7 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
- public async Task RevokeUserTokens(string userId)
+ public async Task RevokeUserTokens(string userId, string currentAccessToken)
{
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
@@ -1457,7 +1461,10 @@ namespace MediaBrowser.Server.Implementations.Session
foreach (var info in existing.Items)
{
- await Logout(info.AccessToken).ConfigureAwait(false);
+ if (!string.Equals(currentAccessToken, info.AccessToken, StringComparison.OrdinalIgnoreCase))
+ {
+ await Logout(info.AccessToken).ConfigureAwait(false);
+ }
}
}
@@ -1748,6 +1755,11 @@ namespace MediaBrowser.Server.Implementations.Session
public void ReportNowViewingItem(string sessionId, string itemId)
{
+ if (string.IsNullOrWhiteSpace(itemId))
+ {
+ throw new ArgumentNullException("itemId");
+ }
+
var item = _libraryManager.GetItemById(new Guid(itemId));
var info = GetItemInfo(item, null, null);
diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
index 602bc4876..ddd7ba53a 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -230,7 +230,12 @@ namespace MediaBrowser.Server.Implementations.Session
{
var vals = message.Data.Split('|');
- _sessionManager.ReportNowViewingItem(session.Id, vals[1]);
+ var itemId = vals[1];
+
+ if (!string.IsNullOrWhiteSpace(itemId))
+ {
+ _sessionManager.ReportNowViewingItem(session.Id, itemId);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
index 317743eb1..c4243c1a7 100644
--- a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
+++ b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
@@ -12,54 +12,30 @@ namespace MediaBrowser.Server.Implementations.Social
{
public class SharingRepository : BaseSqliteRepository
{
- private IDbConnection _connection;
- private IDbCommand _saveShareCommand;
- private readonly IApplicationPaths _appPaths;
-
- public SharingRepository(ILogManager logManager, IApplicationPaths appPaths)
- : base(logManager)
+ public SharingRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector dbConnector)
+ : base(logManager, dbConnector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "shares.db");
}
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "shares.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists Shares (Id GUID, ItemId TEXT, UserId TEXT, ExpirationDate DateTime, PRIMARY KEY (Id))",
"create index if not exists idx_Shares on Shares(Id)",
- //pragmas
- "pragma temp_store = memory",
-
"pragma shrink_memory"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- /// <summary>
- /// Prepares the statements.
- /// </summary>
- private void PrepareStatements()
- {
- _saveShareCommand = _connection.CreateCommand();
- _saveShareCommand.CommandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (@Id, @ItemId, @UserId, @ExpirationDate)";
-
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@Id");
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@ItemId");
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@UserId");
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@ExpirationDate");
+ connection.RunQueries(queries, Logger);
+ }
}
public async Task CreateShare(SocialShareInfo info)
@@ -77,53 +53,62 @@ namespace MediaBrowser.Server.Implementations.Social
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- _saveShareCommand.GetParameter(0).Value = new Guid(info.Id);
- _saveShareCommand.GetParameter(1).Value = info.ItemId;
- _saveShareCommand.GetParameter(2).Value = info.UserId;
- _saveShareCommand.GetParameter(3).Value = info.ExpirationDate;
-
- _saveShareCommand.Transaction = transaction;
-
- _saveShareCommand.ExecuteNonQuery();
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- catch (Exception e)
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- Logger.ErrorException("Failed to save share:", e);
-
- if (transaction != null)
+ using (var saveShareCommand = connection.CreateCommand())
{
- transaction.Rollback();
+ saveShareCommand.CommandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (@Id, @ItemId, @UserId, @ExpirationDate)";
+
+ saveShareCommand.Parameters.Add(saveShareCommand, "@Id");
+ saveShareCommand.Parameters.Add(saveShareCommand, "@ItemId");
+ saveShareCommand.Parameters.Add(saveShareCommand, "@UserId");
+ saveShareCommand.Parameters.Add(saveShareCommand, "@ExpirationDate");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ saveShareCommand.GetParameter(0).Value = new Guid(info.Id);
+ saveShareCommand.GetParameter(1).Value = info.ItemId;
+ saveShareCommand.GetParameter(2).Value = info.UserId;
+ saveShareCommand.GetParameter(3).Value = info.ExpirationDate;
+
+ saveShareCommand.Transaction = transaction;
+
+ saveShareCommand.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save share:", e);
+
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
-
- WriteLock.Release();
}
}
@@ -134,20 +119,23 @@ namespace MediaBrowser.Server.Implementations.Social
throw new ArgumentNullException("id");
}
- var cmd = _connection.CreateCommand();
- cmd.CommandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = @id";
+ using (var connection = CreateConnection(true).Result)
+ {
+ var cmd = connection.CreateCommand();
+ cmd.CommandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = @id";
- cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = new Guid(id);
+ cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = new Guid(id);
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- if (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetSocialShareInfo(reader);
+ if (reader.Read())
+ {
+ return GetSocialShareInfo(reader);
+ }
}
- }
- return null;
+ return null;
+ }
}
private SocialShareInfo GetSocialShareInfo(IDataReader reader)
@@ -164,21 +152,7 @@ namespace MediaBrowser.Server.Implementations.Social
public async Task DeleteShare(string id)
{
-
- }
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index bbba06870..886308d43 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -483,6 +483,11 @@ namespace MediaBrowser.Server.Implementations.Sync
private async Task ProcessJobItem(SyncJobItem jobItem, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
{
+ if (jobItem == null)
+ {
+ throw new ArgumentNullException("jobItem");
+ }
+
var item = _libraryManager.GetItemById(jobItem.ItemId);
if (item == null)
{
@@ -748,7 +753,7 @@ namespace MediaBrowser.Server.Implementations.Sync
_fileSystem.CreateDirectory(Path.GetDirectoryName(path));
- using (var stream = await _subtitleEncoder.GetSubtitles(streamInfo.ItemId, streamInfo.MediaSourceId, subtitleStreamIndex, subtitleStreamInfo.Format, 0, null, cancellationToken).ConfigureAwait(false))
+ using (var stream = await _subtitleEncoder.GetSubtitles(streamInfo.ItemId, streamInfo.MediaSourceId, subtitleStreamIndex, subtitleStreamInfo.Format, 0, null, false, cancellationToken).ConfigureAwait(false))
{
using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
index 739d1ab6e..a1ed66a99 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
@@ -18,34 +18,22 @@ namespace MediaBrowser.Server.Implementations.Sync
{
public class SyncRepository : BaseSqliteRepository, ISyncRepository
{
- private IDbConnection _connection;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _insertJobCommand;
- private IDbCommand _updateJobCommand;
- private IDbCommand _deleteJobCommand;
-
- private IDbCommand _deleteJobItemsCommand;
- private IDbCommand _insertJobItemCommand;
- private IDbCommand _updateJobItemCommand;
-
private readonly IJsonSerializer _json;
- private readonly IServerApplicationPaths _appPaths;
- public SyncRepository(ILogManager logManager, IJsonSerializer json, IServerApplicationPaths appPaths)
- : base(logManager)
+ public SyncRepository(ILogManager logManager, IJsonSerializer json, IServerApplicationPaths appPaths, IDbConnector connector)
+ : base(logManager, connector)
{
_json = json;
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "sync14.db");
}
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "sync14.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Profile TEXT, Quality TEXT, Bitrate INT, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)",
"create index if not exists idx_SyncJobs on SyncJobs(Id)",
@@ -55,120 +43,15 @@ namespace MediaBrowser.Server.Implementations.Sync
"create index if not exists idx_SyncJobItems1 on SyncJobItems(Id)",
"create index if not exists idx_SyncJobItems2 on SyncJobItems(TargetId)",
- //pragmas
- "pragma temp_store = memory",
-
"pragma shrink_memory"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
- _connection.AddColumn(Logger, "SyncJobs", "Profile", "TEXT");
- _connection.AddColumn(Logger, "SyncJobs", "Bitrate", "INT");
- _connection.AddColumn(Logger, "SyncJobItems", "ItemDateModifiedTicks", "BIGINT");
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- // _deleteJobCommand
- _deleteJobCommand = _connection.CreateCommand();
- _deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id";
- _deleteJobCommand.Parameters.Add(_deleteJobCommand, "@Id");
-
- // _deleteJobItemsCommand
- _deleteJobItemsCommand = _connection.CreateCommand();
- _deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId";
- _deleteJobItemsCommand.Parameters.Add(_deleteJobItemsCommand, "@JobId");
-
- // _insertJobCommand
- _insertJobCommand = _connection.CreateCommand();
- _insertJobCommand.CommandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)";
-
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Id");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@TargetId");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Name");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Profile");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Quality");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Bitrate");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Status");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Progress");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@UserId");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemIds");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Category");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ParentId");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@UnwatchedOnly");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemLimit");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@SyncNewContent");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@DateCreated");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@DateLastModified");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemCount");
-
- // _updateJobCommand
- _updateJobCommand = _connection.CreateCommand();
- _updateJobCommand.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@Id";
-
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Id");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@TargetId");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Name");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Profile");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Quality");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Bitrate");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Status");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Progress");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@UserId");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemIds");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Category");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ParentId");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@UnwatchedOnly");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemLimit");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@SyncNewContent");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@DateCreated");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@DateLastModified");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemCount");
-
- // _insertJobItemCommand
- _insertJobItemCommand = _connection.CreateCommand();
- _insertJobItemCommand.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex, @ItemDateModifiedTicks)";
-
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Id");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemName");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@MediaSourceId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@JobId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@TemporaryPath");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@OutputPath");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Status");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@TargetId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@DateCreated");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Progress");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@AdditionalFiles");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@MediaSource");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@IsMarkedForRemoval");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@JobItemIndex");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemDateModifiedTicks");
-
- // _updateJobItemCommand
- _updateJobItemCommand = _connection.CreateCommand();
- _updateJobItemCommand.CommandText = "update SyncJobItems set ItemId=@ItemId,ItemName=@ItemName,MediaSourceId=@MediaSourceId,JobId=@JobId,TemporaryPath=@TemporaryPath,OutputPath=@OutputPath,Status=@Status,TargetId=@TargetId,DateCreated=@DateCreated,Progress=@Progress,AdditionalFiles=@AdditionalFiles,MediaSource=@MediaSource,IsMarkedForRemoval=@IsMarkedForRemoval,JobItemIndex=@JobItemIndex,ItemDateModifiedTicks=@ItemDateModifiedTicks where Id=@Id";
-
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Id");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemName");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@MediaSourceId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@TemporaryPath");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@OutputPath");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Status");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@TargetId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@DateCreated");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Progress");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@AdditionalFiles");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@MediaSource");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@IsMarkedForRemoval");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobItemIndex");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemDateModifiedTicks");
+ connection.AddColumn(Logger, "SyncJobs", "Profile", "TEXT");
+ connection.AddColumn(Logger, "SyncJobs", "Bitrate", "INT");
+ connection.AddColumn(Logger, "SyncJobItems", "ItemDateModifiedTicks", "BIGINT");
+ }
}
private const string BaseJobSelectText = "select Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs";
@@ -182,7 +65,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
+
var guid = new Guid(id);
if (guid == Guid.Empty)
@@ -190,22 +73,25 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new ArgumentNullException("id");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseJobSelectText + " where Id=@Id";
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = BaseJobSelectText + " where Id=@Id";
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- if (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetJob(reader);
+ if (reader.Read())
+ {
+ return GetJob(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
private SyncJob GetJob(IDataReader reader)
@@ -283,15 +169,15 @@ namespace MediaBrowser.Server.Implementations.Sync
public Task Create(SyncJob job)
{
- return InsertOrUpdate(job, _insertJobCommand);
+ return InsertOrUpdate(job, true);
}
public Task Update(SyncJob job)
{
- return InsertOrUpdate(job, _updateJobCommand);
+ return InsertOrUpdate(job, false);
}
- private async Task InsertOrUpdate(SyncJob job, IDbCommand cmd)
+ private async Task InsertOrUpdate(SyncJob job, bool insert)
{
if (job == null)
{
@@ -299,70 +185,119 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- await WriteLock.WaitAsync().ConfigureAwait(false);
-
- IDbTransaction transaction = null;
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- cmd.GetParameter(index++).Value = new Guid(job.Id);
- cmd.GetParameter(index++).Value = job.TargetId;
- cmd.GetParameter(index++).Value = job.Name;
- cmd.GetParameter(index++).Value = job.Profile;
- cmd.GetParameter(index++).Value = job.Quality;
- cmd.GetParameter(index++).Value = job.Bitrate;
- cmd.GetParameter(index++).Value = job.Status.ToString();
- cmd.GetParameter(index++).Value = job.Progress;
- cmd.GetParameter(index++).Value = job.UserId;
- cmd.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray());
- cmd.GetParameter(index++).Value = job.Category;
- cmd.GetParameter(index++).Value = job.ParentId;
- cmd.GetParameter(index++).Value = job.UnwatchedOnly;
- cmd.GetParameter(index++).Value = job.ItemLimit;
- cmd.GetParameter(index++).Value = job.SyncNewContent;
- cmd.GetParameter(index++).Value = job.DateCreated;
- cmd.GetParameter(index++).Value = job.DateLastModified;
- cmd.GetParameter(index++).Value = job.ItemCount;
-
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ if (insert)
+ {
+ cmd.CommandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@Name");
+ cmd.Parameters.Add(cmd, "@Profile");
+ cmd.Parameters.Add(cmd, "@Quality");
+ cmd.Parameters.Add(cmd, "@Bitrate");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@UserId");
+ cmd.Parameters.Add(cmd, "@ItemIds");
+ cmd.Parameters.Add(cmd, "@Category");
+ cmd.Parameters.Add(cmd, "@ParentId");
+ cmd.Parameters.Add(cmd, "@UnwatchedOnly");
+ cmd.Parameters.Add(cmd, "@ItemLimit");
+ cmd.Parameters.Add(cmd, "@SyncNewContent");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@DateLastModified");
+ cmd.Parameters.Add(cmd, "@ItemCount");
+ }
+ else
+ {
+ cmd.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@Name");
+ cmd.Parameters.Add(cmd, "@Profile");
+ cmd.Parameters.Add(cmd, "@Quality");
+ cmd.Parameters.Add(cmd, "@Bitrate");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@UserId");
+ cmd.Parameters.Add(cmd, "@ItemIds");
+ cmd.Parameters.Add(cmd, "@Category");
+ cmd.Parameters.Add(cmd, "@ParentId");
+ cmd.Parameters.Add(cmd, "@UnwatchedOnly");
+ cmd.Parameters.Add(cmd, "@ItemLimit");
+ cmd.Parameters.Add(cmd, "@SyncNewContent");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@DateLastModified");
+ cmd.Parameters.Add(cmd, "@ItemCount");
+ }
- cmd.ExecuteNonQuery();
+ IDbTransaction transaction = null;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ var index = 0;
+
+ cmd.GetParameter(index++).Value = new Guid(job.Id);
+ cmd.GetParameter(index++).Value = job.TargetId;
+ cmd.GetParameter(index++).Value = job.Name;
+ cmd.GetParameter(index++).Value = job.Profile;
+ cmd.GetParameter(index++).Value = job.Quality;
+ cmd.GetParameter(index++).Value = job.Bitrate;
+ cmd.GetParameter(index++).Value = job.Status.ToString();
+ cmd.GetParameter(index++).Value = job.Progress;
+ cmd.GetParameter(index++).Value = job.UserId;
+ cmd.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray());
+ cmd.GetParameter(index++).Value = job.Category;
+ cmd.GetParameter(index++).Value = job.ParentId;
+ cmd.GetParameter(index++).Value = job.UnwatchedOnly;
+ cmd.GetParameter(index++).Value = job.ItemLimit;
+ cmd.GetParameter(index++).Value = job.SyncNewContent;
+ cmd.GetParameter(index++).Value = job.DateCreated;
+ cmd.GetParameter(index++).Value = job.DateLastModified;
+ cmd.GetParameter(index++).Value = job.ItemCount;
+
+ cmd.Transaction = transaction;
+
+ cmd.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -374,56 +309,66 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- await WriteLock.WaitAsync().ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- _deleteJobCommand.GetParameter(index++).Value = new Guid(id);
- _deleteJobCommand.Transaction = transaction;
- _deleteJobCommand.ExecuteNonQuery();
-
- index = 0;
- _deleteJobItemsCommand.GetParameter(index++).Value = id;
- _deleteJobItemsCommand.Transaction = transaction;
- _deleteJobItemsCommand.ExecuteNonQuery();
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
- throw;
- }
- catch (Exception e)
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- Logger.ErrorException("Failed to save record:", e);
-
- if (transaction != null)
+ using (var deleteJobCommand = connection.CreateCommand())
{
- transaction.Rollback();
- }
-
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ using (var deleteJobItemsCommand = connection.CreateCommand())
+ {
+ IDbTransaction transaction = null;
+
+ try
+ {
+ // _deleteJobCommand
+ deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id";
+ deleteJobCommand.Parameters.Add(deleteJobCommand, "@Id");
+
+ transaction = connection.BeginTransaction();
+
+ deleteJobCommand.GetParameter(0).Value = new Guid(id);
+ deleteJobCommand.Transaction = transaction;
+ deleteJobCommand.ExecuteNonQuery();
+
+ // _deleteJobItemsCommand
+ deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId";
+ deleteJobItemsCommand.Parameters.Add(deleteJobItemsCommand, "@JobId");
+
+ deleteJobItemsCommand.GetParameter(0).Value = id;
+ deleteJobItemsCommand.Transaction = transaction;
+ deleteJobItemsCommand.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
+
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -435,83 +380,86 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- using (var cmd = _connection.CreateCommand())
+
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseJobSelectText;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = BaseJobSelectText;
- var whereClauses = new List<string>();
+ var whereClauses = new List<string>();
- if (query.Statuses.Length > 0)
- {
- var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
+ if (query.Statuses.Length > 0)
+ {
+ var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
- whereClauses.Add(string.Format("Status in ({0})", statuses));
- }
- if (!string.IsNullOrWhiteSpace(query.TargetId))
- {
- whereClauses.Add("TargetId=@TargetId");
- cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
- }
- if (!string.IsNullOrWhiteSpace(query.UserId))
- {
- whereClauses.Add("UserId=@UserId");
- cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
- }
- if (query.SyncNewContent.HasValue)
- {
- whereClauses.Add("SyncNewContent=@SyncNewContent");
- cmd.Parameters.Add(cmd, "@SyncNewContent", DbType.Boolean).Value = query.SyncNewContent.Value;
- }
+ whereClauses.Add(string.Format("Status in ({0})", statuses));
+ }
+ if (!string.IsNullOrWhiteSpace(query.TargetId))
+ {
+ whereClauses.Add("TargetId=@TargetId");
+ cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
+ }
+ if (!string.IsNullOrWhiteSpace(query.UserId))
+ {
+ whereClauses.Add("UserId=@UserId");
+ cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
+ }
+ if (query.SyncNewContent.HasValue)
+ {
+ whereClauses.Add("SyncNewContent=@SyncNewContent");
+ cmd.Parameters.Add(cmd, "@SyncNewContent", DbType.Boolean).Value = query.SyncNewContent.Value;
+ }
- cmd.CommandText += " mainTable";
+ cmd.CommandText += " mainTable";
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- var startIndex = query.StartIndex ?? 0;
- if (startIndex > 0)
- {
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC LIMIT {0})",
- startIndex.ToString(_usCulture)));
- }
+ var startIndex = query.StartIndex ?? 0;
+ if (startIndex > 0)
+ {
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC LIMIT {0})",
+ startIndex.ToString(_usCulture)));
+ }
- if (whereClauses.Count > 0)
- {
- cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
- }
+ if (whereClauses.Count > 0)
+ {
+ cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
+ }
- cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC";
+ cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC";
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- cmd.CommandText += "; select count (Id) from SyncJobs" + whereTextWithoutPaging;
+ cmd.CommandText += "; select count (Id) from SyncJobs" + whereTextWithoutPaging;
- var list = new List<SyncJob>();
- var count = 0;
+ var list = new List<SyncJob>();
+ var count = 0;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(GetJob(reader));
+ while (reader.Read())
+ {
+ list.Add(GetJob(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<SyncJob>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<SyncJob>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -523,25 +471,28 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
+
var guid = new Guid(id);
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseJobItemSelectText + " where Id=@Id";
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = BaseJobItemSelectText + " where Id=@Id";
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- if (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetJobItem(reader);
+ if (reader.Read())
+ {
+ return GetJobItem(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
private QueryResult<T> GetJobItemReader<T>(SyncJobItemQuery query, string baseSelectText, Func<IDataReader, T> itemFactory)
@@ -551,81 +502,84 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new ArgumentNullException("query");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = baseSelectText;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = baseSelectText;
- var whereClauses = new List<string>();
+ var whereClauses = new List<string>();
- if (!string.IsNullOrWhiteSpace(query.JobId))
- {
- whereClauses.Add("JobId=@JobId");
- cmd.Parameters.Add(cmd, "@JobId", DbType.String).Value = query.JobId;
- }
- if (!string.IsNullOrWhiteSpace(query.ItemId))
- {
- whereClauses.Add("ItemId=@ItemId");
- cmd.Parameters.Add(cmd, "@ItemId", DbType.String).Value = query.ItemId;
- }
- if (!string.IsNullOrWhiteSpace(query.TargetId))
- {
- whereClauses.Add("TargetId=@TargetId");
- cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
- }
+ if (!string.IsNullOrWhiteSpace(query.JobId))
+ {
+ whereClauses.Add("JobId=@JobId");
+ cmd.Parameters.Add(cmd, "@JobId", DbType.String).Value = query.JobId;
+ }
+ if (!string.IsNullOrWhiteSpace(query.ItemId))
+ {
+ whereClauses.Add("ItemId=@ItemId");
+ cmd.Parameters.Add(cmd, "@ItemId", DbType.String).Value = query.ItemId;
+ }
+ if (!string.IsNullOrWhiteSpace(query.TargetId))
+ {
+ whereClauses.Add("TargetId=@TargetId");
+ cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
+ }
- if (query.Statuses.Length > 0)
- {
- var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
+ if (query.Statuses.Length > 0)
+ {
+ var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
- whereClauses.Add(string.Format("Status in ({0})", statuses));
- }
+ whereClauses.Add(string.Format("Status in ({0})", statuses));
+ }
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- var startIndex = query.StartIndex ?? 0;
- if (startIndex > 0)
- {
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobItems ORDER BY JobItemIndex, DateCreated LIMIT {0})",
- startIndex.ToString(_usCulture)));
- }
+ var startIndex = query.StartIndex ?? 0;
+ if (startIndex > 0)
+ {
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobItems ORDER BY JobItemIndex, DateCreated LIMIT {0})",
+ startIndex.ToString(_usCulture)));
+ }
- if (whereClauses.Count > 0)
- {
- cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
- }
+ if (whereClauses.Count > 0)
+ {
+ cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
+ }
- cmd.CommandText += " ORDER BY JobItemIndex, DateCreated";
+ cmd.CommandText += " ORDER BY JobItemIndex, DateCreated";
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging;
+ cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging;
- var list = new List<T>();
- var count = 0;
+ var list = new List<T>();
+ var count = 0;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(itemFactory(reader));
+ while (reader.Read())
+ {
+ list.Add(itemFactory(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<T>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<T>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -641,15 +595,15 @@ namespace MediaBrowser.Server.Implementations.Sync
public Task Create(SyncJobItem jobItem)
{
- return InsertOrUpdate(jobItem, _insertJobItemCommand);
+ return InsertOrUpdate(jobItem, true);
}
public Task Update(SyncJobItem jobItem)
{
- return InsertOrUpdate(jobItem, _updateJobItemCommand);
+ return InsertOrUpdate(jobItem, false);
}
- private async Task InsertOrUpdate(SyncJobItem jobItem, IDbCommand cmd)
+ private async Task InsertOrUpdate(SyncJobItem jobItem, bool insert)
{
if (jobItem == null)
{
@@ -657,68 +611,114 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- await WriteLock.WaitAsync().ConfigureAwait(false);
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- cmd.GetParameter(index++).Value = new Guid(jobItem.Id);
- cmd.GetParameter(index++).Value = jobItem.ItemId;
- cmd.GetParameter(index++).Value = jobItem.ItemName;
- cmd.GetParameter(index++).Value = jobItem.MediaSourceId;
- cmd.GetParameter(index++).Value = jobItem.JobId;
- cmd.GetParameter(index++).Value = jobItem.TemporaryPath;
- cmd.GetParameter(index++).Value = jobItem.OutputPath;
- cmd.GetParameter(index++).Value = jobItem.Status.ToString();
- cmd.GetParameter(index++).Value = jobItem.TargetId;
- cmd.GetParameter(index++).Value = jobItem.DateCreated;
- cmd.GetParameter(index++).Value = jobItem.Progress;
- cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles);
- cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource);
- cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval;
- cmd.GetParameter(index++).Value = jobItem.JobItemIndex;
- cmd.GetParameter(index++).Value = jobItem.ItemDateModifiedTicks;
-
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ if (insert)
+ {
+ cmd.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex, @ItemDateModifiedTicks)";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@ItemId");
+ cmd.Parameters.Add(cmd, "@ItemName");
+ cmd.Parameters.Add(cmd, "@MediaSourceId");
+ cmd.Parameters.Add(cmd, "@JobId");
+ cmd.Parameters.Add(cmd, "@TemporaryPath");
+ cmd.Parameters.Add(cmd, "@OutputPath");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@AdditionalFiles");
+ cmd.Parameters.Add(cmd, "@MediaSource");
+ cmd.Parameters.Add(cmd, "@IsMarkedForRemoval");
+ cmd.Parameters.Add(cmd, "@JobItemIndex");
+ cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks");
+ }
+ else
+ {
+ // cmd
+ cmd.CommandText = "update SyncJobItems set ItemId=@ItemId,ItemName=@ItemName,MediaSourceId=@MediaSourceId,JobId=@JobId,TemporaryPath=@TemporaryPath,OutputPath=@OutputPath,Status=@Status,TargetId=@TargetId,DateCreated=@DateCreated,Progress=@Progress,AdditionalFiles=@AdditionalFiles,MediaSource=@MediaSource,IsMarkedForRemoval=@IsMarkedForRemoval,JobItemIndex=@JobItemIndex,ItemDateModifiedTicks=@ItemDateModifiedTicks where Id=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@ItemId");
+ cmd.Parameters.Add(cmd, "@ItemName");
+ cmd.Parameters.Add(cmd, "@MediaSourceId");
+ cmd.Parameters.Add(cmd, "@JobId");
+ cmd.Parameters.Add(cmd, "@TemporaryPath");
+ cmd.Parameters.Add(cmd, "@OutputPath");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@AdditionalFiles");
+ cmd.Parameters.Add(cmd, "@MediaSource");
+ cmd.Parameters.Add(cmd, "@IsMarkedForRemoval");
+ cmd.Parameters.Add(cmd, "@JobItemIndex");
+ cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks");
+ }
- cmd.ExecuteNonQuery();
+ IDbTransaction transaction = null;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ var index = 0;
+
+ cmd.GetParameter(index++).Value = new Guid(jobItem.Id);
+ cmd.GetParameter(index++).Value = jobItem.ItemId;
+ cmd.GetParameter(index++).Value = jobItem.ItemName;
+ cmd.GetParameter(index++).Value = jobItem.MediaSourceId;
+ cmd.GetParameter(index++).Value = jobItem.JobId;
+ cmd.GetParameter(index++).Value = jobItem.TemporaryPath;
+ cmd.GetParameter(index++).Value = jobItem.OutputPath;
+ cmd.GetParameter(index++).Value = jobItem.Status.ToString();
+ cmd.GetParameter(index++).Value = jobItem.TargetId;
+ cmd.GetParameter(index++).Value = jobItem.DateCreated;
+ cmd.GetParameter(index++).Value = jobItem.Progress;
+ cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles);
+ cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource);
+ cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval;
+ cmd.GetParameter(index++).Value = jobItem.JobItemIndex;
+ cmd.GetParameter(index++).Value = jobItem.ItemDateModifiedTicks;
+
+ cmd.Transaction = transaction;
+
+ cmd.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -809,19 +809,5 @@ namespace MediaBrowser.Server.Implementations.Sync
return item;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
index ec91dc1b7..82232ffae 100644
--- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
+++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
@@ -111,24 +111,6 @@ namespace MediaBrowser.Server.Implementations.TV
.Select(i => GetNextUp(i, currentUser))
// Include if an episode was found, and either the series is not unwatched or the specific series was requested
.Where(i => i.Item1 != null && (!i.Item3 || !string.IsNullOrWhiteSpace(request.SeriesId)))
- //.OrderByDescending(i =>
- //{
- // var episode = i.Item1;
-
- // var seriesUserData = _userDataManager.GetUserData(user, episode.Series);
-
- // if (seriesUserData.IsFavorite)
- // {
- // return 2;
- // }
-
- // if (seriesUserData.Likes.HasValue)
- // {
- // return seriesUserData.Likes.Value ? 1 : -1;
- // }
-
- // return 0;
- //})
.OrderByDescending(i => i.Item2)
.ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
.Select(i => i.Item1);
@@ -142,52 +124,80 @@ namespace MediaBrowser.Server.Implementations.TV
/// <returns>Task{Episode}.</returns>
private Tuple<Episode, DateTime, bool> GetNextUp(Series series, User user)
{
- // Get them in display order, then reverse
- var allEpisodes = series.GetSeasons(user, true, true)
- .Where(i => !i.IndexNumber.HasValue || i.IndexNumber.Value != 0)
- .SelectMany(i => i.GetEpisodes(user))
- .Reverse()
- .ToList();
-
- Episode lastWatched = null;
- var lastWatchedDate = DateTime.MinValue;
- Episode nextUp = null;
+ var firstUnwatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ AncestorWithPresentationUniqueKey = series.PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ SortBy = new[] { ItemSortBy.SortName },
+ SortOrder = SortOrder.Ascending,
+ Limit = 1,
+ IsPlayed = false,
+ IsVirtualItem = false,
+ ParentIndexNumberNotEquals = 0
- var includeMissing = user.Configuration.DisplayMissingEpisodes;
+ }).Cast<Episode>().FirstOrDefault();
- // Go back starting with the most recent episodes
- foreach (var episode in allEpisodes)
+ // series is fully played
+ if (firstUnwatchedEpisode == null)
{
- var userData = _userDataManager.GetUserData(user, episode);
+ return new Tuple<Episode, DateTime, bool>(null, DateTime.MinValue, true);
+ }
- if (userData.Played)
- {
- if (lastWatched != null || nextUp == null)
- {
- break;
- }
+ var lastWatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ AncestorWithPresentationUniqueKey = series.PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ SortBy = new[] { ItemSortBy.DatePlayed },
+ SortOrder = SortOrder.Descending,
+ Limit = 1,
+ IsVirtualItem = false,
+ ParentIndexNumberNotEquals = 0
+
+ }).FirstOrDefault();
+
+ //// Get them in display order, then reverse
+ //var allEpisodes = series.GetEpisodes(user, false, false)
+ // .Where(i => !i.ParentIndexNumber.HasValue || i.ParentIndexNumber.Value != 0)
+ // .Reverse()
+ // .ToList();
+
+ //Episode lastWatched = null;
+ //var lastWatchedDate = DateTime.MinValue;
+ //Episode nextUp = null;
+
+ //// Go back starting with the most recent episodes
+ //foreach (var episode in allEpisodes)
+ //{
+ // var userData = _userDataManager.GetUserData(user, episode);
+
+ // if (userData.Played)
+ // {
+ // if (lastWatched != null || nextUp == null)
+ // {
+ // break;
+ // }
+
+ // lastWatched = episode;
+ // lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue;
+ // }
+ // else
+ // {
+ // nextUp = episode;
+ // }
+ //}
+
+ if (lastWatchedEpisode != null)
+ {
+ var userData = _userDataManager.GetUserData(user, lastWatchedEpisode);
- lastWatched = episode;
- lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue;
- }
- else
+ if (userData.LastPlayedDate.HasValue)
{
- if (!episode.IsVirtualUnaired && (includeMissing || !episode.IsMissingEpisode))
- {
- nextUp = episode;
- }
+ return new Tuple<Episode, DateTime, bool>(firstUnwatchedEpisode, userData.LastPlayedDate.Value, false);
}
}
- if (lastWatched != null)
- {
- return new Tuple<Episode, DateTime, bool>(nextUp, lastWatchedDate, false);
- }
-
- var firstEpisode = allEpisodes.LastOrDefault(i => !i.IsVirtualUnaired && (includeMissing || !i.IsMissingEpisode) && !i.IsPlayed(user));
-
// Return the first episode
- return new Tuple<Episode, DateTime, bool>(firstEpisode, DateTime.MinValue, true);
+ return new Tuple<Episode, DateTime, bool>(firstUnwatchedEpisode, DateTime.MinValue, true);
}
private QueryResult<BaseItem> GetResult(IEnumerable<BaseItem> items, int? totalRecordLimit, NextUpQuery query)
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index b877d41a8..42fc51a63 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
- <package id="Emby.XmlTv" version="1.0.0.48" targetFramework="net45" />
- <package id="ini-parser" version="2.2.4" targetFramework="net45" />
+ <package id="Emby.XmlTv" version="1.0.0.53" targetFramework="net45" />
+ <package id="ini-parser" version="2.3.0" targetFramework="net45" />
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
- <package id="MediaBrowser.Naming" version="1.0.0.50" targetFramework="net45" />
+ <package id="MediaBrowser.Naming" version="1.0.0.51" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
- <package id="SimpleInjector" version="3.1.4" targetFramework="net45" />
+ <package id="SimpleInjector" version="3.1.5" targetFramework="net45" />
<package id="SocketHttpListener" version="1.0.0.30" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index b71877e17..45071c9d9 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -82,11 +82,14 @@
</Reference>
</ItemGroup>
<ItemGroup>
+ <Compile Include="..\MediaBrowser.Server.Implementations\Persistence\SqliteExtensions.cs">
+ <Link>Native\SqliteExtensions.cs</Link>
+ </Compile>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Native\BaseMonoApp.cs" />
- <Compile Include="Native\SqliteExtensions.cs" />
+ <Compile Include="Native\DbConnector.cs" />
<Compile Include="Networking\CertificateGenerator.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/MediaBrowser.Server.Mono/Native/DbConnector.cs b/MediaBrowser.Server.Mono/Native/DbConnector.cs
new file mode 100644
index 000000000..5ad3ecfef
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Native/DbConnector.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Data;
+using System.Data.SQLite;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Implementations.Persistence;
+
+namespace MediaBrowser.Server.Mono.Native
+{
+ public class DbConnector : IDbConnector
+ {
+ private readonly ILogger _logger;
+
+ public DbConnector(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public Task<IDbConnection> Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null)
+ {
+ return SqliteExtensions.ConnectToDb(dbPath, isReadOnly, enablePooling, cacheSize, _logger);
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Mono/Native/SqliteExtensions.cs b/MediaBrowser.Server.Mono/Native/SqliteExtensions.cs
deleted file mode 100644
index 385a7d0c5..000000000
--- a/MediaBrowser.Server.Mono/Native/SqliteExtensions.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Data;
-using System.Data.SQLite;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations.Persistence;
-
-namespace MediaBrowser.Server.Mono.Native
-{
- /// <summary>
- /// Class SQLiteExtensions
- /// </summary>
- static class SqliteExtensions
- {
- /// <summary>
- /// Connects to db.
- /// </summary>
- /// <param name="dbPath">The db path.</param>
- /// <param name="logger">The logger.</param>
- /// <returns>Task{IDbConnection}.</returns>
- /// <exception cref="System.ArgumentNullException">dbPath</exception>
- public static async Task<IDbConnection> ConnectToDb(string dbPath, ILogger logger)
- {
- if (string.IsNullOrEmpty(dbPath))
- {
- throw new ArgumentNullException("dbPath");
- }
-
- logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, dbPath);
-
- var connectionstr = new SQLiteConnectionStringBuilder
- {
- PageSize = 4096,
- CacheSize = 2000,
- SyncMode = SynchronizationModes.Full,
- DataSource = dbPath,
- JournalMode = SQLiteJournalModeEnum.Wal
- };
-
- var connection = new SQLiteConnection(connectionstr.ConnectionString);
-
- await connection.OpenAsync().ConfigureAwait(false);
-
- return connection;
- }
- }
-
- public class DbConnector : IDbConnector
- {
- private readonly ILogger _logger;
-
- public DbConnector(ILogger logger)
- {
- _logger = logger;
- }
-
- public Task<IDbConnection> Connect(string dbPath)
- {
- return SqliteExtensions.ConnectToDb(dbPath, _logger);
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index ae839e6ee..196048f39 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -190,7 +190,6 @@ namespace MediaBrowser.Server.Startup.Common
internal IItemRepository ItemRepository { get; set; }
private INotificationsRepository NotificationsRepository { get; set; }
private IFileOrganizationRepository FileOrganizationRepository { get; set; }
- private IProviderRepository ProviderRepository { get; set; }
private INotificationManager NotificationManager { get; set; }
private ISubtitleManager SubtitleManager { get; set; }
@@ -339,7 +338,7 @@ namespace MediaBrowser.Server.Startup.Common
}
catch (Exception ex)
{
- Logger.ErrorException("Error in {0}", ex, entryPoint.GetType().Name);
+ Logger.ErrorException("Error in {0}", ex, entryPoint.GetType().FullName);
}
});
@@ -360,12 +359,18 @@ namespace MediaBrowser.Server.Startup.Common
{
var migrations = new List<IVersionMigration>
{
- new RenameXmlOptions(ServerConfigurationManager)
};
foreach (var task in migrations)
{
- task.Run();
+ try
+ {
+ task.Run();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error running migration", ex);
+ }
}
}
@@ -375,12 +380,22 @@ namespace MediaBrowser.Server.Startup.Common
{
new OmdbEpisodeProviderMigration(ServerConfigurationManager),
new MovieDbEpisodeProviderMigration(ServerConfigurationManager),
- new DbMigration(ServerConfigurationManager, TaskManager)
+ new DbMigration(ServerConfigurationManager, TaskManager),
+ new FolderViewSettingMigration(ServerConfigurationManager, UserManager),
+ new CollectionGroupingMigration(ServerConfigurationManager, UserManager),
+ new CollectionsViewMigration(ServerConfigurationManager, UserManager)
};
foreach (var task in migrations)
{
- task.Run();
+ try
+ {
+ task.Run();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error running migration", ex);
+ }
}
}
@@ -410,18 +425,14 @@ namespace MediaBrowser.Server.Startup.Common
UserRepository = await GetUserRepository().ConfigureAwait(false);
RegisterSingleInstance(UserRepository);
- var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths);
+ var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths, NativeApp.GetDbConnector());
DisplayPreferencesRepository = displayPreferencesRepo;
RegisterSingleInstance(DisplayPreferencesRepository);
- var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager);
+ var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager, NativeApp.GetDbConnector());
ItemRepository = itemRepo;
RegisterSingleInstance(ItemRepository);
- var providerRepo = new SqliteProviderInfoRepository(LogManager, ApplicationPaths);
- ProviderRepository = providerRepo;
- RegisterSingleInstance(ProviderRepository);
-
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
RegisterSingleInstance(FileOrganizationRepository);
@@ -543,8 +554,8 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance(NativeApp.GetPowerManagement());
- var sharingRepo = new SharingRepository(LogManager, ApplicationPaths);
- await sharingRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ var sharingRepo = new SharingRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
+ await sharingRepo.Initialize().ConfigureAwait(false);
RegisterSingleInstance<ISharingManager>(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
RegisterSingleInstance<ISsdpHandler>(new SsdpHandler(LogManager.GetLogger("SsdpHandler"), ServerConfigurationManager, this));
@@ -560,11 +571,10 @@ namespace MediaBrowser.Server.Startup.Common
SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager);
RegisterSingleInstance(SubtitleEncoder);
-
- await displayPreferencesRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+
+ await displayPreferencesRepo.Initialize().ConfigureAwait(false);
await ConfigureUserDataRepositories().ConfigureAwait(false);
- await itemRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
- await providerRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await itemRepo.Initialize().ConfigureAwait(false);
((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
await ConfigureNotificationsRepository().ConfigureAwait(false);
progress.Report(100);
@@ -661,9 +671,9 @@ namespace MediaBrowser.Server.Startup.Common
{
try
{
- var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer);
+ var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
@@ -680,36 +690,36 @@ namespace MediaBrowser.Server.Startup.Common
/// <returns>Task{IUserRepository}.</returns>
private async Task<IFileOrganizationRepository> GetFileOrganizationRepository()
{
- var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
+ var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
private async Task<IAuthenticationRepository> GetAuthenticationRepository()
{
- var repo = new AuthenticationRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
+ var repo = new AuthenticationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
private async Task<IActivityRepository> GetActivityLogRepository()
{
- var repo = new ActivityRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
+ var repo = new ActivityRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
private async Task<ISyncRepository> GetSyncRepository()
{
- var repo = new SyncRepository(LogManager, JsonSerializer, ServerConfigurationManager.ApplicationPaths);
+ var repo = new SyncRepository(LogManager, JsonSerializer, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
@@ -720,9 +730,9 @@ namespace MediaBrowser.Server.Startup.Common
/// <returns>Task.</returns>
private async Task ConfigureNotificationsRepository()
{
- var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths);
+ var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
NotificationsRepository = repo;
@@ -735,9 +745,9 @@ namespace MediaBrowser.Server.Startup.Common
/// <returns>Task.</returns>
private async Task ConfigureUserDataRepositories()
{
- var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths);
+ var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
((UserDataManager)UserDataManager).Repository = repo;
}
@@ -797,8 +807,6 @@ namespace MediaBrowser.Server.Startup.Common
ProviderManager.AddParts(GetExports<IImageProvider>(),
GetExports<IMetadataService>(),
- GetExports<IItemIdentityProvider>(),
- GetExports<IItemIdentityConverter>(),
GetExports<IMetadataProvider>(),
GetExports<IMetadataSaver>(),
GetExports<IImageSaver>(),
@@ -825,19 +833,57 @@ namespace MediaBrowser.Server.Startup.Common
private string CertificatePath { get; set; }
+ private string NormalizeConfiguredLocalAddress(string address)
+ {
+ var index = address.Trim('/').IndexOf('/');
+
+ if (index != -1)
+ {
+ address = address.Substring(index + 1);
+ }
+
+ return address.Trim('/');
+ }
private IEnumerable<string> GetUrlPrefixes()
{
- var prefixes = new List<string>
- {
- "http://+:" + ServerConfigurationManager.Configuration.HttpServerPortNumber + "/"
- };
+ var hosts = ServerConfigurationManager
+ .Configuration
+ .LocalNetworkAddresses
+ .Select(NormalizeConfiguredLocalAddress)
+ .ToList();
- if (!string.IsNullOrWhiteSpace(CertificatePath))
+ if (hosts.Count == 0)
{
- prefixes.Add("https://+:" + ServerConfigurationManager.Configuration.HttpsPortNumber + "/");
+ hosts.Add("+");
}
- return prefixes;
+ if (!hosts.Contains("+", StringComparer.OrdinalIgnoreCase))
+ {
+ if (!hosts.Contains("localhost", StringComparer.OrdinalIgnoreCase))
+ {
+ hosts.Add("localhost");
+ }
+
+ if (!hosts.Contains("127.0.0.1", StringComparer.OrdinalIgnoreCase))
+ {
+ hosts.Add("127.0.0.1");
+ }
+ }
+
+ return hosts.SelectMany(i =>
+ {
+ var prefixes = new List<string>
+ {
+ "http://"+i+":" + ServerConfigurationManager.Configuration.HttpServerPortNumber + "/"
+ };
+
+ if (!string.IsNullOrWhiteSpace(CertificatePath))
+ {
+ prefixes.Add("https://" + i + ":" + ServerConfigurationManager.Configuration.HttpsPortNumber + "/");
+ }
+
+ return prefixes;
+ });
}
/// <summary>
diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
index 19ce9ed9e..5b88a6bd9 100644
--- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
+++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
@@ -71,11 +71,13 @@
<Compile Include="FFMpeg\FFmpegValidator.cs" />
<Compile Include="INativeApp.cs" />
<Compile Include="MbLinkShortcutHandler.cs" />
+ <Compile Include="Migrations\CollectionGroupingMigration.cs" />
+ <Compile Include="Migrations\CollectionsViewMigration.cs" />
+ <Compile Include="Migrations\FolderViewSettingMigration.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
<Compile Include="Migrations\DbMigration.cs" />
<Compile Include="Migrations\MovieDbEpisodeProviderMigration.cs" />
<Compile Include="Migrations\OmdbEpisodeProviderMigration.cs" />
- <Compile Include="Migrations\RenameXmlOptions.cs" />
<Compile Include="NativeEnvironment.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StartupOptions.cs" />
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs
new file mode 100644
index 000000000..b497eeb42
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+ public class CollectionGroupingMigration : IVersionMigration
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly IUserManager _userManager;
+
+ public CollectionGroupingMigration(IServerConfigurationManager config, IUserManager userManager)
+ {
+ _config = config;
+ _userManager = userManager;
+ }
+
+ public void Run()
+ {
+ var migrationKey = this.GetType().Name;
+ var migrationKeyList = _config.Configuration.Migrations.ToList();
+
+ if (!migrationKeyList.Contains(migrationKey))
+ {
+ if (_config.Configuration.IsStartupWizardCompleted)
+ {
+ if (_userManager.Users.Any(i => i.Configuration.GroupMoviesIntoBoxSets))
+ {
+ _config.Configuration.EnableGroupingIntoCollections = true;
+ }
+ }
+
+ migrationKeyList.Add(migrationKey);
+ _config.Configuration.Migrations = migrationKeyList.ToArray();
+ _config.SaveConfiguration();
+ }
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs
new file mode 100644
index 000000000..c6186ce08
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+ public class CollectionsViewMigration : IVersionMigration
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly IUserManager _userManager;
+
+ public CollectionsViewMigration(IServerConfigurationManager config, IUserManager userManager)
+ {
+ _config = config;
+ _userManager = userManager;
+ }
+
+ public void Run()
+ {
+ var migrationKey = this.GetType().Name;
+ var migrationKeyList = _config.Configuration.Migrations.ToList();
+
+ if (!migrationKeyList.Contains(migrationKey))
+ {
+ if (_config.Configuration.IsStartupWizardCompleted)
+ {
+ if (_userManager.Users.Any(i => i.Configuration.DisplayCollectionsView))
+ {
+ _config.Configuration.DisplayCollectionsView = true;
+ }
+ }
+
+ migrationKeyList.Add(migrationKey);
+ _config.Configuration.Migrations = migrationKeyList.ToArray();
+ _config.SaveConfiguration();
+ }
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs
index 65517c09c..f0cb9e84e 100644
--- a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs
+++ b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs
@@ -18,6 +18,7 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
public void Run()
{
+ // If a forced migration is required, do that now
if (_config.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion)
{
if (!_config.Configuration.IsStartupWizardCompleted)
@@ -36,6 +37,25 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
_taskManager.Execute<CleanDatabaseScheduledTask>();
});
+
+ return;
+ }
+
+ if (_config.Configuration.SchemaVersion < SqliteItemRepository.LatestSchemaVersion)
+ {
+ if (!_config.Configuration.IsStartupWizardCompleted)
+ {
+ _config.Configuration.SchemaVersion = SqliteItemRepository.LatestSchemaVersion;
+ _config.SaveConfiguration();
+ return;
+ }
+
+ Task.Run(async () =>
+ {
+ await Task.Delay(1000).ConfigureAwait(false);
+
+ _taskManager.Execute<CleanDatabaseScheduledTask>();
+ });
}
}
}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs
new file mode 100644
index 000000000..12054864b
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs
@@ -0,0 +1,40 @@
+using System.Linq;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+ public class FolderViewSettingMigration : IVersionMigration
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly IUserManager _userManager;
+
+ public FolderViewSettingMigration(IServerConfigurationManager config, IUserManager userManager)
+ {
+ _config = config;
+ _userManager = userManager;
+ }
+
+ public void Run()
+ {
+ var migrationKey = this.GetType().Name;
+ var migrationKeyList = _config.Configuration.Migrations.ToList();
+
+ if (!migrationKeyList.Contains(migrationKey))
+ {
+ if (_config.Configuration.IsStartupWizardCompleted)
+ {
+ if (_userManager.Users.Any(i => i.Configuration.DisplayFoldersView))
+ {
+ _config.Configuration.EnableFolderView = true;
+ }
+ }
+
+ migrationKeyList.Add(migrationKey);
+ _config.Configuration.Migrations = migrationKeyList.ToArray();
+ _config.SaveConfiguration();
+ }
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs
deleted file mode 100644
index 49114b96f..000000000
--- a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using System;
-
-namespace MediaBrowser.Server.Startup.Common.Migrations
-{
- public class RenameXmlOptions : IVersionMigration
- {
- private readonly IServerConfigurationManager _config;
-
- public RenameXmlOptions(IServerConfigurationManager config)
- {
- _config = config;
- }
-
- public void Run()
- {
- var changed = false;
-
- foreach (var option in _config.Configuration.MetadataOptions)
- {
- if (Migrate(option.DisabledMetadataSavers))
- {
- changed = true;
- }
- if (Migrate(option.LocalMetadataReaderOrder))
- {
- changed = true;
- }
- }
-
- if (changed)
- {
- _config.SaveConfiguration();
- }
- }
-
- private bool Migrate(string[] options)
- {
- var changed = false;
-
- if (options != null)
- {
- for (var i = 0; i < options.Length; i++)
- {
- if (string.Equals(options[i], "Media Browser Legacy Xml", StringComparison.OrdinalIgnoreCase))
- {
- options[i] = "Emby Xml";
- changed = true;
- }
- else if (string.Equals(options[i], "Media Browser Xml", StringComparison.OrdinalIgnoreCase))
- {
- options[i] = "Emby Xml";
- changed = true;
- }
- }
- }
-
- return changed;
- }
- }
-}
diff --git a/MediaBrowser.ServerApplication/App.config b/MediaBrowser.ServerApplication/App.config
index a92d92300..6d840c191 100644
--- a/MediaBrowser.ServerApplication/App.config
+++ b/MediaBrowser.ServerApplication/App.config
@@ -52,6 +52,7 @@
<bindingRedirect oldVersion="0.0.0.0-2.3.6.0" newVersion="2.3.6.0"/>
</dependentAssembly>
</assemblyBinding>
+ <enforceFIPSPolicy enabled="false"/>
</runtime>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
diff --git a/MediaBrowser.ServerApplication/BackgroundServiceInstaller.cs b/MediaBrowser.ServerApplication/BackgroundServiceInstaller.cs
index 08c8a25b9..be381fe96 100644
--- a/MediaBrowser.ServerApplication/BackgroundServiceInstaller.cs
+++ b/MediaBrowser.ServerApplication/BackgroundServiceInstaller.cs
@@ -25,7 +25,7 @@ namespace MediaBrowser.ServerApplication
Description = "The windows background service for Emby Server.",
// Will ensure the network is available
- ServicesDependedOn = new[] { "LanmanServer", "Tcpip" }
+ ServicesDependedOn = new[] { "LanmanServer", "EventLog", "Tcpip", "http" }
};
// Microsoft didn't add the ability to add a
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index 63d2cf30d..3a3b10188 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -256,7 +256,7 @@ namespace MediaBrowser.ServerApplication
{
Task.WaitAll(task);
- task = InstallVcredistIfNeeded(_appHost, _logger);
+ task = InstallVcredist2013IfNeeded(_appHost, _logger);
Task.WaitAll(task);
task = InstallFrameworkV46IfNeeded(_logger);
@@ -681,7 +681,7 @@ namespace MediaBrowser.ServerApplication
}
}
- private static async Task InstallVcredistIfNeeded(ApplicationHost appHost, ILogger logger)
+ private static async Task InstallVcredist2013IfNeeded(ApplicationHost appHost, ILogger logger)
{
try
{
@@ -695,7 +695,7 @@ namespace MediaBrowser.ServerApplication
try
{
- await InstallVcredist().ConfigureAwait(false);
+ await InstallVcredist2013().ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -703,13 +703,13 @@ namespace MediaBrowser.ServerApplication
}
}
- private async static Task InstallVcredist()
+ private async static Task InstallVcredist2013()
{
var httpClient = _appHost.HttpClient;
var tmp = await httpClient.GetTempFile(new HttpRequestOptions
{
- Url = GetVcredistUrl(),
+ Url = GetVcredist2013Url(),
Progress = new Progress<double>()
}).ConfigureAwait(false);
@@ -735,7 +735,7 @@ namespace MediaBrowser.ServerApplication
}
}
- private static string GetVcredistUrl()
+ private static string GetVcredist2013Url()
{
if (Environment.Is64BitProcess)
{
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 366d4b608..35660b2b1 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -97,6 +97,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="..\MediaBrowser.Server.Implementations\Persistence\SqliteExtensions.cs">
+ <Link>Native\SqliteExtensions.cs</Link>
+ </Compile>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
@@ -114,7 +117,7 @@
</Compile>
<Compile Include="MainStartup.cs" />
<Compile Include="Native\LnkShortcutHandler.cs" />
- <Compile Include="Native\SqliteExtensions.cs" />
+ <Compile Include="Native\DbConnector.cs" />
<Compile Include="Native\Standby.cs" />
<Compile Include="Native\ServerAuthorization.cs" />
<Compile Include="Native\WindowsApp.cs" />
diff --git a/MediaBrowser.ServerApplication/Native/DbConnector.cs b/MediaBrowser.ServerApplication/Native/DbConnector.cs
new file mode 100644
index 000000000..9aaa96a80
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/DbConnector.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Data;
+using System.Data.SQLite;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Implementations.Persistence;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+ public class DbConnector : IDbConnector
+ {
+ private readonly ILogger _logger;
+
+ public DbConnector(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public Task<IDbConnection> Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null)
+ {
+ return SqliteExtensions.ConnectToDb(dbPath, isReadOnly, enablePooling, cacheSize, _logger);
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Native/SqliteExtensions.cs b/MediaBrowser.ServerApplication/Native/SqliteExtensions.cs
deleted file mode 100644
index 1cde2ea13..000000000
--- a/MediaBrowser.ServerApplication/Native/SqliteExtensions.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Data;
-using System.Data.SQLite;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations.Persistence;
-
-namespace MediaBrowser.ServerApplication.Native
-{
- /// <summary>
- /// Class SQLiteExtensions
- /// </summary>
- static class SqliteExtensions
- {
- /// <summary>
- /// Connects to db.
- /// </summary>
- /// <param name="dbPath">The db path.</param>
- /// <param name="logger">The logger.</param>
- /// <returns>Task{IDbConnection}.</returns>
- /// <exception cref="System.ArgumentNullException">dbPath</exception>
- public static async Task<IDbConnection> ConnectToDb(string dbPath, ILogger logger)
- {
- if (string.IsNullOrEmpty(dbPath))
- {
- throw new ArgumentNullException("dbPath");
- }
-
- logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, dbPath);
-
- var connectionstr = new SQLiteConnectionStringBuilder
- {
- PageSize = 4096,
- CacheSize = 2000,
- SyncMode = SynchronizationModes.Full,
- DataSource = dbPath,
- JournalMode = SQLiteJournalModeEnum.Wal
- };
-
- var connection = new SQLiteConnection(connectionstr.ConnectionString);
-
- await connection.OpenAsync().ConfigureAwait(false);
-
- return connection;
- }
- }
-
- public class DbConnector : IDbConnector
- {
- private readonly ILogger _logger;
-
- public DbConnector(ILogger logger)
- {
- _logger = logger;
- }
-
- public Task<IDbConnection> Connect(string dbPath)
- {
- return SqliteExtensions.ConnectToDb(dbPath, _logger);
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
index cc9061fcd..ed60de9d2 100644
--- a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
+++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
@@ -89,19 +89,21 @@ namespace MediaBrowser.ServerApplication.Networking
/// </summary>
/// <returns>Arraylist that represents all the SV_TYPE_WORKSTATION and SV_TYPE_SERVER
/// PC's in the Domain</returns>
- private IEnumerable<string> GetNetworkDevicesInternal()
+ private List<string> GetNetworkDevicesInternal()
{
//local fields
const int MAX_PREFERRED_LENGTH = -1;
var SV_TYPE_WORKSTATION = 1;
var SV_TYPE_SERVER = 2;
- var buffer = IntPtr.Zero;
- var tmpBuffer = IntPtr.Zero;
+ IntPtr buffer = IntPtr.Zero;
+ IntPtr tmpBuffer = IntPtr.Zero;
var entriesRead = 0;
var totalEntries = 0;
var resHandle = 0;
var sizeofINFO = Marshal.SizeOf(typeof(_SERVER_INFO_100));
+ var returnList = new List<string>();
+
try
{
//call the DllImport : NetServerEnum with all its required parameters
@@ -118,7 +120,7 @@ namespace MediaBrowser.ServerApplication.Networking
//get pointer to, Pointer to the buffer that received the data from
//the call to NetServerEnum. Must ensure to use correct size of
//STRUCTURE to ensure correct location in memory is pointed to
- tmpBuffer = new IntPtr((int)buffer + (i * sizeofINFO));
+ tmpBuffer = new IntPtr((Int64)buffer + (i * sizeofINFO));
//Have now got a pointer to the list of SV_TYPE_WORKSTATION and
//SV_TYPE_SERVER PC's, which is unmanaged memory
//Needs to Marshal data from an unmanaged block of memory to a
@@ -129,7 +131,7 @@ namespace MediaBrowser.ServerApplication.Networking
//add the PC names to the ArrayList
if (!string.IsNullOrEmpty(svrInfo.sv100_name))
{
- yield return svrInfo.sv100_name;
+ returnList.Add(svrInfo.sv100_name);
}
}
}
@@ -140,6 +142,8 @@ namespace MediaBrowser.ServerApplication.Networking
//the memory that the NetApiBufferAllocate function allocates
NativeMethods.NetApiBufferFree(buffer);
}
+
+ return returnList;
}
/// <summary>
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 1569c1fc5..809c3f1a5 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -342,7 +342,9 @@ namespace MediaBrowser.WebDashboard.Api
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
{
- DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents"), "fonts");
+ DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents", "fonts"), "montserrat");
+ DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents", "fonts"), "opensans");
+ DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents", "fonts"), "roboto");
}
_fileSystem.DeleteDirectory(Path.Combine(bowerPath, "jquery", "src"), true);
@@ -356,9 +358,6 @@ namespace MediaBrowser.WebDashboard.Api
DeleteFoldersByName(Path.Combine(bowerPath, "Sortable"), "meteor");
DeleteFoldersByName(Path.Combine(bowerPath, "Sortable"), "st");
DeleteFoldersByName(Path.Combine(bowerPath, "Swiper"), "src");
- DeleteFoldersByName(Path.Combine(bowerPath, "material-design-lite"), "src");
- DeleteFoldersByName(Path.Combine(bowerPath, "material-design-lite"), "utils");
- _fileSystem.DeleteFile(Path.Combine(bowerPath, "material-design-lite", "gulpfile.babel.js"));
_fileSystem.DeleteDirectory(Path.Combine(bowerPath, "marked"), true);
_fileSystem.DeleteDirectory(Path.Combine(bowerPath, "marked-element"), true);
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index d8de98abe..883c02914 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -274,7 +274,7 @@ namespace MediaBrowser.WebDashboard.Api
}
var mainFile = File.ReadAllText(GetDashboardResourcePath("index.html"));
- html = ReplaceFirst(mainFile, "<div class=\"mainAnimatedPage hide\"></div>", "<div class=\"mainAnimatedPage hide\">" + html + "</div>");
+ html = ReplaceFirst(mainFile, "<div class=\"mainAnimatedPages skinBody\"></div>", "<div class=\"mainAnimatedPages skinBody hide\">" + html + "</div>");
}
if (!string.IsNullOrWhiteSpace(localizationCulture))
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index e85f5a27b..3456ea2cc 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -104,6 +104,9 @@
<Content Include="dashboard-ui\components\apphost.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\components\channelmapper\channelmapper.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\components\chromecasthelpers.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -125,12 +128,6 @@
<Content Include="dashboard-ui\components\guestinviter\guestinviter.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\ironcardlist\ironcardlist.template.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\components\ironcardlist\ironcardlist.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\components\metadataeditor\metadataeditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -143,16 +140,19 @@
<Content Include="dashboard-ui\components\remotecontrolautoplay.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\scrollthreshold.js">
+ <Content Include="dashboard-ui\components\tvproviders\xmltv.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\tvproviders\xmltv.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\components\viewcontainer-lite.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\logo.png">
+ <Content Include="dashboard-ui\css\dashboard.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\polymer\paper-icon-button-light.css">
+ <Content Include="dashboard-ui\css\images\logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\devices\windowsphone\wp.css">
@@ -167,9 +167,6 @@
<Content Include="dashboard-ui\legacy\buttonenabled.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\collectioneditor\collectioneditor.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\components\directorybrowser\directorybrowser.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -218,9 +215,6 @@
<Content Include="dashboard-ui\components\metadataeditor\metadataeditor.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\playlisteditor\playlisteditor.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\devices\ie\ie.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -278,6 +272,9 @@
<Content Include="dashboard-ui\legacy\selectmenu.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\librarydisplay.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\livetvguideprovider.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -314,6 +311,9 @@
<Content Include="dashboard-ui\scripts\homeupcoming.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\librarydisplay.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\livetvguideprovider.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -362,6 +362,9 @@
<Content Include="dashboard-ui\scripts\supporterkeypage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\tvlatest.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\wizardlivetvguide.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -380,9 +383,6 @@
<Content Include="dashboard-ui\shared.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\subtitleeditor\subtitleeditor.template.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\devices\android\android.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -893,9 +893,6 @@
<Content Include="dashboard-ui\scripts\dlnasettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\subtitleeditor\subtitleeditor.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\encodingsettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -938,9 +935,6 @@
<Content Include="dashboard-ui\scripts\playlistedit.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\playlistmanager.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\playlists.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1131,9 +1125,6 @@
<Content Include="dashboard-ui\music.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\alphapicker.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\components\imageeditor\imageeditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1155,9 +1146,6 @@
<Content Include="dashboard-ui\scripts\search.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\tvlatest.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\moviecollections.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index d020a73fe..2e34135a6 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -919,11 +919,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
- var hasTags = item as IHasTags;
- if (hasTags != null)
- {
- hasTags.AddTag(val);
- }
+ item.AddTag(val);
}
break;
}
@@ -932,13 +928,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
var val = reader.ReadElementContentAsString();
- var hasKeywords = item as IHasKeywords;
- if (hasKeywords != null)
+ if (!string.IsNullOrWhiteSpace(val))
{
- if (!string.IsNullOrWhiteSpace(val))
- {
- hasKeywords.AddKeyword(val);
- }
+ item.AddKeyword(val);
}
break;
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index d2e09d4eb..42f0a3364 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -736,29 +736,21 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("studio", studio);
}
- var hasTags = item as IHasTags;
- if (hasTags != null)
+ foreach (var tag in item.Tags)
{
- foreach (var tag in hasTags.Tags)
+ if (item is MusicAlbum || item is MusicArtist)
{
- if (item is MusicAlbum || item is MusicArtist)
- {
- writer.WriteElementString("style", tag);
- }
- else
- {
- writer.WriteElementString("tag", tag);
- }
+ writer.WriteElementString("style", tag);
+ }
+ else
+ {
+ writer.WriteElementString("tag", tag);
}
}
- var hasKeywords = item as IHasKeywords;
- if (hasKeywords != null)
+ foreach (var tag in item.Keywords)
{
- foreach (var tag in hasKeywords.Keywords)
- {
- writer.WriteElementString("plotkeyword", tag);
- }
+ writer.WriteElementString("plotkeyword", tag);
}
var hasAwards = item as IHasAwards;
diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
index 18423f59e..63445b9c4 100644
--- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
@@ -44,6 +44,13 @@ namespace MediaBrowser.XbmcMetadata.Savers
}
else
{
+ // http://kodi.wiki/view/NFO_files/Movies
+ // movie.nfo will override all and any .nfo files in the same folder as the media files if you use the "Use foldernames for lookups" setting. If you don't, then moviename.nfo is used
+ //if (!item.IsInMixedFolder && item.ItemType == typeof(Movie))
+ //{
+ // list.Add(Path.Combine(item.ContainingFolderPath, "movie.nfo"));
+ //}
+
list.Add(Path.ChangeExtension(item.Path, ".nfo"));
}
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index 56429c6a6..a8ef26932 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.648</version>
+ <version>3.0.650</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,9 +12,9 @@
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.648" />
+ <dependency id="MediaBrowser.Common" version="3.0.650" />
<dependency id="NLog" version="4.3.4" />
- <dependency id="SimpleInjector" version="3.1.4" />
+ <dependency id="SimpleInjector" version="3.1.5" />
</dependencies>
</metadata>
<files>
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index d12984869..2bf899ad6 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.648</version>
+ <version>3.0.650</version>
<title>MediaBrowser.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index a9caab74c..3fdeeaf53 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.648</version>
+ <version>3.0.650</version>
<title>Media Browser.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.648" />
+ <dependency id="MediaBrowser.Common" version="3.0.650" />
<dependency id="Interfaces.IO" version="1.0.0.5" />
</dependencies>
</metadata>
diff --git a/SharedVersion.cs b/SharedVersion.cs
index ada1802b9..278469226 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-//[assembly: AssemblyVersion("3.0.*")]
-[assembly: AssemblyVersion("3.0.5973")]
+[assembly: AssemblyVersion("3.1.*")]
+//[assembly: AssemblyVersion("3.0.5960")]