Merge pull request #2476 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2017-02-18 03:33:34 -05:00 committed by GitHub
commit 0c4f78be3a
47 changed files with 469 additions and 357 deletions

View File

@ -863,7 +863,7 @@ namespace Emby.Server.Core
/// </summary> /// </summary>
private void ConfigureNotificationsRepository() private void ConfigureNotificationsRepository()
{ {
var repo = new SqliteNotificationsRepository(LogManager.GetLogger("SqliteNotificationsRepository"), ServerConfigurationManager.ApplicationPaths); var repo = new SqliteNotificationsRepository(LogManager.GetLogger("SqliteNotificationsRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
repo.Initialize(); repo.Initialize();

View File

@ -3874,6 +3874,25 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add(clause); whereClauses.Add(clause);
} }
if (query.AlbumIds.Length > 0)
{
var clauses = new List<string>();
var index = 0;
foreach (var albumId in query.AlbumIds)
{
var paramName = "@AlbumIds" + index;
clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
if (statement != null)
{
statement.TryBind(paramName, albumId.ToGuidParamValue());
}
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
whereClauses.Add(clause);
}
if (query.ExcludeArtistIds.Length > 0) if (query.ExcludeArtistIds.Length > 0)
{ {
var clauses = new List<string>(); var clauses = new List<string>();
@ -4227,30 +4246,6 @@ namespace Emby.Server.Implementations.Data
{ {
whereClauses.Add("ProviderIds like '%tvdb=%'"); whereClauses.Add("ProviderIds like '%tvdb=%'");
} }
if (query.AlbumNames.Length > 0)
{
var clause = "(";
var index = 0;
foreach (var name in query.AlbumNames)
{
if (index > 0)
{
clause += " OR ";
}
clause += "Album=@AlbumName" + index;
if (statement != null)
{
statement.TryBind("@AlbumName" + index, name);
}
index++;
}
clause += ")";
whereClauses.Add(clause);
}
if (query.HasThemeSong.HasValue) if (query.HasThemeSong.HasValue)
{ {
if (query.HasThemeSong.Value) if (query.HasThemeSong.Value)

View File

@ -492,7 +492,10 @@ namespace Emby.Server.Implementations.Dto
} }
} }
//if (!(item is LiveTvProgram))
{
dto.PlayAccess = item.GetPlayAccess(user); dto.PlayAccess = item.GetPlayAccess(user);
}
if (fields.Contains(ItemFields.BasicSyncInfo) || fields.Contains(ItemFields.SyncInfo)) if (fields.Contains(ItemFields.BasicSyncInfo) || fields.Contains(ItemFields.SyncInfo))
{ {
@ -994,7 +997,12 @@ namespace Emby.Server.Implementations.Dto
} }
dto.MediaType = item.MediaType; dto.MediaType = item.MediaType;
if (!(item is LiveTvProgram))
{
dto.LocationType = item.LocationType; dto.LocationType = item.LocationType;
}
if (item.IsHD.HasValue && item.IsHD.Value) if (item.IsHD.HasValue && item.IsHD.Value)
{ {
dto.IsHD = item.IsHD; dto.IsHD = item.IsHD;
@ -1102,7 +1110,10 @@ namespace Emby.Server.Implementations.Dto
} }
dto.Type = item.GetClientTypeName(); dto.Type = item.GetClientTypeName();
if ((item.CommunityRating ?? 0) > 0)
{
dto.CommunityRating = item.CommunityRating; dto.CommunityRating = item.CommunityRating;
}
if (fields.Contains(ItemFields.VoteCount)) if (fields.Contains(ItemFields.VoteCount))
{ {
@ -1410,8 +1421,6 @@ namespace Emby.Server.Implementations.Dto
dto.AirDays = series.AirDays; dto.AirDays = series.AirDays;
dto.AirTime = series.AirTime; dto.AirTime = series.AirTime;
dto.SeriesStatus = series.Status; dto.SeriesStatus = series.Status;
dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
} }
// Add SeasonInfo // Add SeasonInfo
@ -1473,10 +1482,13 @@ namespace Emby.Server.Implementations.Dto
SetBookProperties(dto, book); SetBookProperties(dto, book);
} }
if (fields.Contains(ItemFields.ProductionLocations))
{
if (item.ProductionLocations.Count > 0 || item is Movie) if (item.ProductionLocations.Count > 0 || item is Movie)
{ {
dto.ProductionLocations = item.ProductionLocations.ToArray(); dto.ProductionLocations = item.ProductionLocations.ToArray();
} }
}
var photo = item as Photo; var photo = item as Photo;
if (photo != null) if (photo != null)

View File

@ -409,17 +409,17 @@ namespace Emby.Server.Implementations.Library
if (options.DeleteFileLocation && locationType != LocationType.Remote && locationType != LocationType.Virtual) if (options.DeleteFileLocation && locationType != LocationType.Remote && locationType != LocationType.Virtual)
{ {
foreach (var path in item.GetDeletePaths().ToList()) foreach (var fileSystemInfo in item.GetDeletePaths().ToList())
{ {
if (_fileSystem.DirectoryExists(path)) if (fileSystemInfo.IsDirectory)
{ {
_logger.Debug("Deleting path {0}", path); _logger.Debug("Deleting path {0}", fileSystemInfo.FullName);
_fileSystem.DeleteDirectory(path, true); _fileSystem.DeleteDirectory(fileSystemInfo.FullName, true);
} }
else if (_fileSystem.FileExists(path)) else
{ {
_logger.Debug("Deleting path {0}", path); _logger.Debug("Deleting path {0}", fileSystemInfo.FullName);
_fileSystem.DeleteFile(path); _fileSystem.DeleteFile(fileSystemInfo.FullName);
} }
} }
@ -818,30 +818,6 @@ namespace Emby.Server.Implementations.Library
return _userRootFolder; return _userRootFolder;
} }
public Guid? FindIdByPath(string path, bool? isFolder)
{
// If this returns multiple items it could be tricky figuring out which one is correct.
// In most cases, the newest one will be and the others obsolete but not yet cleaned up
var query = new InternalItemsQuery
{
Path = path,
IsFolder = isFolder,
SortBy = new[] { ItemSortBy.DateCreated },
SortOrder = SortOrder.Descending,
Limit = 1
};
var id = GetItemIds(query);
if (id.Count == 0)
{
return null;
}
return id[0];
}
public BaseItem FindByPath(string path, bool? isFolder) public BaseItem FindByPath(string path, bool? isFolder)
{ {
// If this returns multiple items it could be tricky figuring out which one is correct. // If this returns multiple items it could be tricky figuring out which one is correct.

View File

@ -248,6 +248,13 @@ namespace Emby.Server.Implementations.Library
} }
} }
var isPlayed = request.IsPlayed;
if (parents.OfType<ICollectionFolder>().Any(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)))
{
isPlayed = null;
}
if (parents.Count == 0) if (parents.Count == 0)
{ {
parents = user.RootFolder.GetChildren(user, true) parents = user.RootFolder.GetChildren(user, true)
@ -282,7 +289,7 @@ namespace Emby.Server.Implementations.Library
IsVirtualItem = false, IsVirtualItem = false,
Limit = limit * 5, Limit = limit * 5,
SourceTypes = parents.Count == 0 ? new[] { SourceType.Library } : new SourceType[] { }, SourceTypes = parents.Count == 0 ? new[] { SourceType.Library } : new SourceType[] { },
IsPlayed = request.IsPlayed IsPlayed = isPlayed
}, parents); }, parents);
} }

View File

@ -1172,7 +1172,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}; };
var isAudio = false; var isAudio = false;
await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, false, cancellationToken).ConfigureAwait(false); await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
return new List<MediaSourceInfo> return new List<MediaSourceInfo>
{ {

View File

@ -260,7 +260,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
_logger.Info("Calling recording process.WaitForExit for {0}", _targetPath); _logger.Info("Calling recording process.WaitForExit for {0}", _targetPath);
if (_process.WaitForExit(5000)) if (_process.WaitForExit(10000))
{ {
return; return;
} }

View File

@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.LiveTv
_logger = logger; _logger = logger;
} }
public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, bool assumeInterlaced, CancellationToken cancellationToken) public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
{ {
var originalRuntime = mediaSource.RunTimeTicks; var originalRuntime = mediaSource.RunTimeTicks;
@ -96,17 +96,6 @@ namespace Emby.Server.Implementations.LiveTv
videoStream.IsAVC = null; videoStream.IsAVC = null;
} }
if (assumeInterlaced)
{
foreach (var mediaStream in mediaSource.MediaStreams)
{
if (mediaStream.Type == MediaStreamType.Video)
{
mediaStream.IsInterlaced = true;
}
}
}
// Try to estimate this // Try to estimate this
mediaSource.InferTotalBitrate(true); mediaSource.InferTotalBitrate(true);
} }

View File

@ -607,6 +607,10 @@ namespace Emby.Server.Implementations.LiveTv
item.Audio = info.Audio; item.Audio = info.Audio;
item.ChannelId = channel.Id.ToString("N"); item.ChannelId = channel.Id.ToString("N");
item.CommunityRating = item.CommunityRating ?? info.CommunityRating; item.CommunityRating = item.CommunityRating ?? info.CommunityRating;
if ((item.CommunityRating ?? 0).Equals(0))
{
item.CommunityRating = null;
}
item.EpisodeTitle = info.EpisodeTitle; item.EpisodeTitle = info.EpisodeTitle;
item.ExternalId = info.Id; item.ExternalId = info.Id;

View File

@ -126,14 +126,12 @@ namespace Emby.Server.Implementations.LiveTv
var keys = openToken.Split(new[] { StreamIdDelimeter }, 3); var keys = openToken.Split(new[] { StreamIdDelimeter }, 3);
var mediaSourceId = keys.Length >= 3 ? keys[2] : null; var mediaSourceId = keys.Length >= 3 ? keys[2] : null;
IDirectStreamProvider directStreamProvider = null; IDirectStreamProvider directStreamProvider = null;
var assumeInterlaced = false;
if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase)) if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase))
{ {
var info = await _liveTvManager.GetChannelStream(keys[1], mediaSourceId, cancellationToken).ConfigureAwait(false); var info = await _liveTvManager.GetChannelStream(keys[1], mediaSourceId, cancellationToken).ConfigureAwait(false);
stream = info.Item1; stream = info.Item1;
directStreamProvider = info.Item2; directStreamProvider = info.Item2;
assumeInterlaced = info.Item3;
} }
else else
{ {
@ -148,7 +146,7 @@ namespace Emby.Server.Implementations.LiveTv
} }
else else
{ {
await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, assumeInterlaced, cancellationToken).ConfigureAwait(false); await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
} }
} }
catch (Exception ex) catch (Exception ex)

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Data;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Notifications;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Notifications; using MediaBrowser.Model.Notifications;
using SQLitePCL.pretty; using SQLitePCL.pretty;
@ -16,8 +17,11 @@ namespace Emby.Server.Implementations.Notifications
{ {
public class SqliteNotificationsRepository : BaseSqliteRepository, INotificationsRepository public class SqliteNotificationsRepository : BaseSqliteRepository, INotificationsRepository
{ {
public SqliteNotificationsRepository(ILogger logger, IServerApplicationPaths appPaths) : base(logger) protected IFileSystem FileSystem { get; private set; }
public SqliteNotificationsRepository(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem) : base(logger)
{ {
FileSystem = fileSystem;
DbFilePath = Path.Combine(appPaths.DataPath, "notifications.db"); DbFilePath = Path.Combine(appPaths.DataPath, "notifications.db");
} }
@ -26,6 +30,22 @@ namespace Emby.Server.Implementations.Notifications
////public event EventHandler<NotificationUpdateEventArgs> NotificationUpdated; ////public event EventHandler<NotificationUpdateEventArgs> NotificationUpdated;
public void Initialize() public void Initialize()
{
try
{
InitializeInternal();
}
catch (Exception ex)
{
Logger.ErrorException("Error loading notifications database file. Will reset and retry.", ex);
FileSystem.DeleteFile(DbFilePath);
InitializeInternal();
}
}
private void InitializeInternal()
{ {
using (var connection = CreateConnection()) using (var connection = CreateConnection())
{ {

View File

@ -59,6 +59,7 @@
<Compile Include="IHasDtoOptions.cs" /> <Compile Include="IHasDtoOptions.cs" />
<Compile Include="Playback\MediaInfoService.cs" /> <Compile Include="Playback\MediaInfoService.cs" />
<Compile Include="Playback\TranscodingThrottler.cs" /> <Compile Include="Playback\TranscodingThrottler.cs" />
<Compile Include="Playback\UniversalAudioService.cs" />
<Compile Include="PlaylistService.cs" /> <Compile Include="PlaylistService.cs" />
<Compile Include="Reports\Activities\ReportActivitiesBuilder.cs" /> <Compile Include="Reports\Activities\ReportActivitiesBuilder.cs" />
<Compile Include="Reports\Common\HeaderActivitiesMetadata.cs" /> <Compile Include="Reports\Common\HeaderActivitiesMetadata.cs" />

View File

@ -126,14 +126,10 @@ namespace MediaBrowser.Api.Playback
/// <summary> /// <summary>
/// Gets the output file path. /// Gets the output file path.
/// </summary> /// </summary>
/// <param name="state">The state.</param> private string GetOutputFilePath(StreamState state, string outputFileExtension)
/// <returns>System.String.</returns>
private string GetOutputFilePath(StreamState state)
{ {
var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath; var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
var outputFileExtension = GetOutputFileExtension(state);
var data = GetCommandLineArguments("dummy\\dummy", state, false); var data = GetCommandLineArguments("dummy\\dummy", state, false);
data += "-" + (state.Request.DeviceId ?? string.Empty); data += "-" + (state.Request.DeviceId ?? string.Empty);
@ -876,11 +872,16 @@ namespace MediaBrowser.Api.Playback
var container = Path.GetExtension(state.RequestedUrl); var container = Path.GetExtension(state.RequestedUrl);
if (string.IsNullOrEmpty(container))
{
container = request.Container;
}
if (string.IsNullOrEmpty(container)) if (string.IsNullOrEmpty(container))
{ {
container = request.Static ? container = request.Static ?
state.InputContainer : state.InputContainer :
(Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.'); GetOutputFileExtension(state);
} }
state.OutputContainer = (container ?? string.Empty).TrimStart('.'); state.OutputContainer = (container ?? string.Empty).TrimStart('.');
@ -923,7 +924,10 @@ namespace MediaBrowser.Api.Playback
ApplyDeviceProfileSettings(state); ApplyDeviceProfileSettings(state);
} }
state.OutputFilePath = GetOutputFilePath(state); var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
? GetOutputFileExtension(state)
: ("." + state.OutputContainer);
state.OutputFilePath = GetOutputFilePath(state, ext);
return state; return state;
} }

View File

@ -18,9 +18,6 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes; using MimeTypes = MediaBrowser.Model.Net.MimeTypes;

View File

@ -146,7 +146,7 @@ namespace MediaBrowser.Api.Playback
Task.WaitAll(task); Task.WaitAll(task);
} }
public async Task<object> Post(GetPostedPlaybackInfo request) public async Task<PlaybackInfoResponse> GetPlaybackInfo(GetPostedPlaybackInfo request)
{ {
var authInfo = _authContext.GetAuthorizationInfo(Request); var authInfo = _authContext.GetAuthorizationInfo(Request);
@ -172,7 +172,14 @@ namespace MediaBrowser.Api.Playback
SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.MaxAudioChannels, request.UserId); SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.MaxAudioChannels, request.UserId);
} }
return ToOptimizedResult(info); return info;
}
public async Task<object> Post(GetPostedPlaybackInfo request)
{
var result = await GetPlaybackInfo(request).ConfigureAwait(false);
return ToOptimizedResult(result);
} }
private T Clone<T>(T obj) private T Clone<T>(T obj)

View File

@ -26,8 +26,6 @@ namespace MediaBrowser.Api.Playback.Progressive
[Route("/Audio/{Id}/stream", "HEAD", Summary = "Gets an audio stream")] [Route("/Audio/{Id}/stream", "HEAD", Summary = "Gets an audio stream")]
public class GetAudioStream : StreamRequest public class GetAudioStream : StreamRequest
{ {
[ApiMember(Name = "Container", Description = "Container", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Container { get; set; }
} }
/// <summary> /// <summary>

View File

@ -22,6 +22,9 @@ namespace MediaBrowser.Api.Playback
[ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string DeviceId { get; set; } public string DeviceId { get; set; }
[ApiMember(Name = "Container", Description = "Container", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Container { get; set; }
/// <summary> /// <summary>
/// Gets or sets the audio codec. /// Gets or sets the audio codec.
/// </summary> /// </summary>

View File

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Api.Playback.Hls;
using MediaBrowser.Api.Playback.Progressive;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Api.Playback
{
public class BaseUniversalRequest
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
[ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string MediaSourceId { get; set; }
[ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string DeviceId { get; set; }
public string Token { get; set; }
public string UserId { get; set; }
public string AudioCodec { get; set; }
public string Container { get; set; }
public int? MaxAudioChannels { get; set; }
public long? MaxStreamingBitrate { get; set; }
[ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public long? StartTimeTicks { get; set; }
}
[Route("/Audio/{Id}/universal.{Container}", "GET", Summary = "Gets an audio stream")]
[Route("/Audio/{Id}/universal", "GET", Summary = "Gets an audio stream")]
[Route("/Audio/{Id}/universal.{Container}", "HEAD", Summary = "Gets an audio stream")]
[Route("/Audio/{Id}/universal", "HEAD", Summary = "Gets an audio stream")]
public class GetUniversalAudioStream : BaseUniversalRequest
{
}
//[Authenticated]
public class UniversalAudioService : BaseApiService
{
public UniversalAudioService(IServerConfigurationManager serverConfigurationManager, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, IDeviceManager deviceManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, INetworkManager networkManager)
{
ServerConfigurationManager = serverConfigurationManager;
UserManager = userManager;
LibraryManager = libraryManager;
IsoManager = isoManager;
MediaEncoder = mediaEncoder;
FileSystem = fileSystem;
DlnaManager = dlnaManager;
DeviceManager = deviceManager;
SubtitleEncoder = subtitleEncoder;
MediaSourceManager = mediaSourceManager;
ZipClient = zipClient;
JsonSerializer = jsonSerializer;
AuthorizationContext = authorizationContext;
ImageProcessor = imageProcessor;
NetworkManager = networkManager;
}
protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
protected IUserManager UserManager { get; private set; }
protected ILibraryManager LibraryManager { get; private set; }
protected IIsoManager IsoManager { get; private set; }
protected IMediaEncoder MediaEncoder { get; private set; }
protected IFileSystem FileSystem { get; private set; }
protected IDlnaManager DlnaManager { get; private set; }
protected IDeviceManager DeviceManager { get; private set; }
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
protected IMediaSourceManager MediaSourceManager { get; private set; }
protected IZipClient ZipClient { get; private set; }
protected IJsonSerializer JsonSerializer { get; private set; }
protected IAuthorizationContext AuthorizationContext { get; private set; }
protected IImageProcessor ImageProcessor { get; private set; }
protected INetworkManager NetworkManager { get; private set; }
public Task<object> Get(GetUniversalAudioStream request)
{
return GetUniversalStream(request, false);
}
public Task<object> Head(GetUniversalAudioStream request)
{
return GetUniversalStream(request, true);
}
private DeviceProfile GetDeviceProfile(GetUniversalAudioStream request)
{
var deviceProfile = new DeviceProfile();
var directPlayProfiles = new List<DirectPlayProfile>();
directPlayProfiles.Add(new DirectPlayProfile
{
Type = DlnaProfileType.Audio,
Container = request.Container
});
deviceProfile.DirectPlayProfiles = directPlayProfiles.ToArray();
deviceProfile.TranscodingProfiles = new[]
{
new TranscodingProfile
{
Type = DlnaProfileType.Audio,
Context = EncodingContext.Streaming,
Container = "ts",
AudioCodec = "aac",
Protocol = "hls"
}
};
return deviceProfile;
}
private async Task<object> GetUniversalStream(GetUniversalAudioStream request, bool isHeadRequest)
{
var deviceProfile = GetDeviceProfile(request);
AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext)
{
Request = Request
};
var playbackInfoResult = await mediaInfoService.GetPlaybackInfo(new GetPostedPlaybackInfo
{
Id = request.Id,
MaxAudioChannels = request.MaxAudioChannels,
MaxStreamingBitrate = request.MaxStreamingBitrate,
StartTimeTicks = request.StartTimeTicks,
UserId = request.UserId,
DeviceProfile = deviceProfile,
MediaSourceId = request.MediaSourceId
}).ConfigureAwait(false);
var mediaSource = playbackInfoResult.MediaSources[0];
var isStatic = mediaSource.SupportsDirectStream;
if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
{
var service = new DynamicHlsService(ServerConfigurationManager,
UserManager,
LibraryManager,
IsoManager,
MediaEncoder,
FileSystem,
DlnaManager,
SubtitleEncoder,
DeviceManager,
MediaSourceManager,
ZipClient,
JsonSerializer,
AuthorizationContext,
NetworkManager)
{
Request = Request
};
var transcodingProfile = deviceProfile.TranscodingProfiles[0];
var newRequest = new GetMasterHlsAudioPlaylist
{
AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(request.MaxStreamingBitrate ?? 192000, int.MaxValue)),
AudioCodec = transcodingProfile.AudioCodec,
Container = ".m3u8",
DeviceId = request.DeviceId,
Id = request.Id,
MaxAudioChannels = request.MaxAudioChannels,
MediaSourceId = mediaSource.Id,
PlaySessionId = playbackInfoResult.PlaySessionId,
StartTimeTicks = request.StartTimeTicks,
Static = isStatic
};
if (isHeadRequest)
{
return service.Head(newRequest);
}
return service.Get(newRequest);
}
else
{
var service = new AudioService(ServerConfigurationManager,
UserManager,
LibraryManager,
IsoManager,
MediaEncoder,
FileSystem,
DlnaManager,
SubtitleEncoder,
DeviceManager,
MediaSourceManager,
ZipClient,
JsonSerializer,
AuthorizationContext,
ImageProcessor)
{
Request = Request
};
var newRequest = new GetAudioStream
{
AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(request.MaxStreamingBitrate ?? 192000, int.MaxValue)),
//AudioCodec = request.AudioCodec,
Container = isStatic ? null : ("." + mediaSource.TranscodingContainer),
DeviceId = request.DeviceId,
Id = request.Id,
MaxAudioChannels = request.MaxAudioChannels,
MediaSourceId = mediaSource.Id,
PlaySessionId = playbackInfoResult.PlaySessionId,
StartTimeTicks = request.StartTimeTicks,
Static = isStatic
};
if (isHeadRequest)
{
return service.Head(newRequest);
}
return service.Get(newRequest);
}
}
}
}

View File

@ -317,12 +317,6 @@ namespace MediaBrowser.Api.Reports
query.MaxParentalRating = _localization.GetRatingLevel(request.MaxOfficialRating); query.MaxParentalRating = _localization.GetRatingLevel(request.MaxOfficialRating);
} }
// Albums
if (!string.IsNullOrEmpty(request.Albums))
{
query.AlbumNames = request.Albums.Split('|');
}
return query; return query;
} }

View File

@ -245,25 +245,15 @@ namespace MediaBrowser.Api.UserLibrary
User user = null; User user = null;
BaseItem parentItem; BaseItem parentItem;
List<BaseItem> libraryItems = null;
if (!string.IsNullOrWhiteSpace(request.UserId)) if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
user = UserManager.GetUserById(request.UserId); user = UserManager.GetUserById(request.UserId);
parentItem = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : LibraryManager.GetItemById(request.ParentId); parentItem = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : LibraryManager.GetItemById(request.ParentId);
if (RequiresLibraryItems(request, dtoOptions))
{
libraryItems = user.RootFolder.GetRecursiveChildren(user).ToList();
}
} }
else else
{ {
parentItem = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId); parentItem = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
if (RequiresLibraryItems(request, dtoOptions))
{
libraryItems = LibraryManager.RootFolder.GetRecursiveChildren().ToList();
}
} }
IEnumerable<BaseItem> items; IEnumerable<BaseItem> items;
@ -307,8 +297,6 @@ namespace MediaBrowser.Api.UserLibrary
var filteredItems = FilterItems(request, extractedItems, user); var filteredItems = FilterItems(request, extractedItems, user);
filteredItems = FilterByLibraryItems(request, filteredItems.Cast<IItemByName>(), user, libraryItems).Cast<BaseItem>();
filteredItems = LibraryManager.Sort(filteredItems, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending); filteredItems = LibraryManager.Sort(filteredItems, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending);
var ibnItemsArray = filteredItems.ToList(); var ibnItemsArray = filteredItems.ToList();
@ -334,15 +322,7 @@ namespace MediaBrowser.Api.UserLibrary
} }
IEnumerable<Tuple<BaseItem, List<BaseItem>>> tuples; var tuples = ibnItems.Select(i => new Tuple<BaseItem, List<BaseItem>>(i, new List<BaseItem>()));
if (dtoOptions.Fields.Contains(ItemFields.ItemCounts))
{
tuples = ibnItems.Select(i => new Tuple<BaseItem, List<BaseItem>>(i, ((IItemByName)i).GetTaggedItems(libraryItems).ToList()));
}
else
{
tuples = ibnItems.Select(i => new Tuple<BaseItem, List<BaseItem>>(i, new List<BaseItem>()));
}
var syncProgess = DtoService.GetSyncedItemProgress(dtoOptions); var syncProgess = DtoService.GetSyncedItemProgress(dtoOptions);
var dtos = tuples.Select(i => DtoService.GetItemByNameDto(i.Item1, dtoOptions, i.Item2, syncProgess, user)); var dtos = tuples.Select(i => DtoService.GetItemByNameDto(i.Item1, dtoOptions, i.Item2, syncProgess, user));
@ -352,52 +332,6 @@ namespace MediaBrowser.Api.UserLibrary
return result; return result;
} }
private bool RequiresLibraryItems(GetItemsByName request, DtoOptions options)
{
var filters = request.GetFilters().ToList();
if (filters.Contains(ItemFilter.IsPlayed))
{
return true;
}
if (filters.Contains(ItemFilter.IsUnplayed))
{
return true;
}
if (request.IsPlayed.HasValue)
{
return true;
}
return options.Fields.Contains(ItemFields.ItemCounts);
}
private IEnumerable<IItemByName> FilterByLibraryItems(GetItemsByName request, IEnumerable<IItemByName> items, User user, IEnumerable<BaseItem> libraryItems)
{
var filters = request.GetFilters().ToList();
if (filters.Contains(ItemFilter.IsPlayed))
{
items = items.Where(i => i.GetTaggedItems(libraryItems).All(l => l.IsPlayed(user)));
}
if (filters.Contains(ItemFilter.IsUnplayed))
{
items = items.Where(i => i.GetTaggedItems(libraryItems).All(l => l.IsUnplayed(user)));
}
if (request.IsPlayed.HasValue)
{
var val = request.IsPlayed.Value;
items = items.Where(i => i.GetTaggedItems(libraryItems).All(l => l.IsPlayed(user)) == val);
}
return items;
}
/// <summary> /// <summary>
/// Filters the items. /// Filters the items.
/// </summary> /// </summary>

View File

@ -277,6 +277,8 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] [ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Albums { get; set; } public string Albums { get; set; }
public string AlbumIds { get; set; }
/// <summary> /// <summary>
/// Gets or sets the item ids. /// Gets or sets the item ids.
/// </summary> /// </summary>

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
@ -359,15 +360,30 @@ namespace MediaBrowser.Api.UserLibrary
} }
// ExcludeArtistIds // ExcludeArtistIds
if (!string.IsNullOrEmpty(request.ExcludeArtistIds)) if (!string.IsNullOrWhiteSpace(request.ExcludeArtistIds))
{ {
query.ExcludeArtistIds = request.ExcludeArtistIds.Split('|'); query.ExcludeArtistIds = request.ExcludeArtistIds.Split('|');
} }
if (!string.IsNullOrWhiteSpace(request.AlbumIds))
{
query.AlbumIds = request.AlbumIds.Split('|');
}
// Albums // Albums
if (!string.IsNullOrEmpty(request.Albums)) if (!string.IsNullOrEmpty(request.Albums))
{ {
query.AlbumNames = request.Albums.Split('|'); query.AlbumIds = request.Albums.Split('|').Select(i =>
{
return _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(MusicAlbum).Name },
Name = i,
Limit = 1
}).Select(album => album.Id.ToString("N")).FirstOrDefault();
}).ToArray();
} }
// Studios // Studios

View File

@ -360,7 +360,8 @@ namespace MediaBrowser.Api.UserLibrary
var currentUser = user; var currentUser = user;
var dtos = series var dtos = series
.GetRecursiveChildren(i => i is Episode && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0) .GetEpisodes(user)
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
.OrderBy(i => .OrderBy(i =>
{ {
if (i.PremiereDate.HasValue) if (i.PremiereDate.HasValue)

View File

@ -2078,9 +2078,31 @@ namespace MediaBrowser.Controller.Entities
/// Gets the file system path to delete when the item is to be deleted /// Gets the file system path to delete when the item is to be deleted
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public virtual IEnumerable<string> GetDeletePaths() public virtual IEnumerable<FileSystemMetadata> GetDeletePaths()
{ {
return new[] { Path }; return new[] {
new FileSystemMetadata
{
FullName = Path,
IsDirectory = IsFolder
}
}.Concat(GetLocalMetadataFilesToDelete());
}
protected List<FileSystemMetadata> GetLocalMetadataFilesToDelete()
{
if (IsFolder || !IsInMixedFolder)
{
return new List<FileSystemMetadata>();
}
var filename = System.IO.Path.GetFileNameWithoutExtension(Path);
var extensions = new[] { ".nfo", ".xml", ".srt" }.ToList();
extensions.AddRange(SupportedImageExtensionsList);
return FileSystem.GetFiles(System.IO.Path.GetDirectoryName(Path))
.Where(i => extensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase) && System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase))
.ToList();
} }
public bool AllowsMultipleImages(ImageType type) public bool AllowsMultipleImages(ImageType type)

View File

@ -4,6 +4,7 @@ using MediaBrowser.Model.Entities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
@ -97,11 +98,17 @@ namespace MediaBrowser.Controller.Entities
return list; return list;
} }
public override IEnumerable<string> GetDeletePaths() public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{ {
if (!DetectIsInMixedFolder()) if (!DetectIsInMixedFolder())
{ {
return new[] { System.IO.Path.GetDirectoryName(Path) }; return new[] {
new FileSystemMetadata
{
FullName = System.IO.Path.GetDirectoryName(Path),
IsDirectory = true
}
};
} }
return base.GetDeletePaths(); return base.GetDeletePaths();

View File

@ -141,7 +141,7 @@ namespace MediaBrowser.Controller.Entities
public string ExternalSeriesId { get; set; } public string ExternalSeriesId { get; set; }
public string ExternalId { get; set; } public string ExternalId { get; set; }
public string[] AlbumNames { get; set; } public string[] AlbumIds { get; set; }
public string[] ArtistIds { get; set; } public string[] ArtistIds { get; set; }
public string[] ExcludeArtistIds { get; set; } public string[] ExcludeArtistIds { get; set; }
public string AncestorWithPresentationUniqueKey { get; set; } public string AncestorWithPresentationUniqueKey { get; set; }
@ -202,7 +202,7 @@ namespace MediaBrowser.Controller.Entities
EnableTotalRecordCount = true; EnableTotalRecordCount = true;
DtoOptions = new DtoOptions(); DtoOptions = new DtoOptions();
AlbumNames = new string[] { }; AlbumIds = new string[] { };
ArtistIds = new string[] { }; ArtistIds = new string[] { };
ExcludeArtistIds = new string[] { }; ExcludeArtistIds = new string[] { };
ExcludeProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); ExcludeProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities.TV namespace MediaBrowser.Controller.Entities.TV
@ -319,9 +320,15 @@ namespace MediaBrowser.Controller.Entities.TV
return list; return list;
} }
public override IEnumerable<string> GetDeletePaths() public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{ {
return new[] { Path }; return new[] {
new FileSystemMetadata
{
FullName = Path,
IsDirectory = IsFolder
}
}.Concat(GetLocalMetadataFilesToDelete());
} }
public override UnratedItem GetBlockUnratedType() public override UnratedItem GetBlockUnratedType()
@ -338,7 +345,6 @@ namespace MediaBrowser.Controller.Entities.TV
if (series != null) if (series != null)
{ {
id.SeriesProviderIds = series.ProviderIds; id.SeriesProviderIds = series.ProviderIds;
id.AnimeSeriesIndex = series.AnimeSeriesIndex;
} }
id.IsMissingEpisode = IsMissingEpisode; id.IsMissingEpisode = IsMissingEpisode;

View File

@ -251,7 +251,6 @@ namespace MediaBrowser.Controller.Entities.TV
if (series != null) if (series != null)
{ {
id.SeriesProviderIds = series.ProviderIds; id.SeriesProviderIds = series.ProviderIds;
id.AnimeSeriesIndex = series.AnimeSeriesIndex;
} }
return id; return id;

View File

@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Entities.TV
/// </summary> /// </summary>
public class Series : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IMetadataContainer public class Series : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IMetadataContainer
{ {
public int? AnimeSeriesIndex { get; set; }
public Series() public Series()
{ {
AirDays = new List<DayOfWeek>(); AirDays = new List<DayOfWeek>();
@ -554,8 +552,6 @@ namespace MediaBrowser.Controller.Entities.TV
{ {
var info = GetItemLookupInfo<SeriesInfo>(); var info = GetItemLookupInfo<SeriesInfo>();
info.AnimeSeriesIndex = AnimeSeriesIndex;
return info; return info;
} }

View File

@ -1719,53 +1719,6 @@ namespace MediaBrowser.Controller.Entities
} }
} }
// Artists
if (query.ArtistIds.Length > 0)
{
var audio = item as IHasArtist;
//if (!(audio != null && query.ArtistNames.Any(audio.HasAnyArtist)))
//{
// return false;
//}
}
// Albums
if (query.AlbumNames.Length > 0)
{
var audio = item as Audio.Audio;
if (audio != null)
{
if (!query.AlbumNames.Any(a => string.Equals(a, audio.Album, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
}
var album = item as MusicAlbum;
if (album != null)
{
if (!query.AlbumNames.Any(a => string.Equals(a, album.Name, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
}
var musicVideo = item as MusicVideo;
if (musicVideo != null)
{
if (!query.AlbumNames.Any(a => string.Equals(a, musicVideo.Album, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
}
return false;
}
return true; return true;
} }

View File

@ -477,11 +477,17 @@ namespace MediaBrowser.Controller.Entities
} }
} }
public override IEnumerable<string> GetDeletePaths() public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{ {
if (!DetectIsInMixedFolder()) if (!DetectIsInMixedFolder())
{ {
return new[] { ContainingFolderPath }; return new[] {
new FileSystemMetadata
{
FullName = System.IO.Path.GetDirectoryName(Path),
IsDirectory = true
}
};
} }
return base.GetDeletePaths(); return base.GetDeletePaths();

View File

@ -62,8 +62,6 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns> /// <returns>BaseItem.</returns>
BaseItem FindByPath(string path, bool? isFolder); BaseItem FindByPath(string path, bool? isFolder);
Guid? FindIdByPath(string path, bool? isFolder);
/// <summary> /// <summary>
/// Gets the artist. /// Gets the artist.
/// </summary> /// </summary>

View File

@ -8,7 +8,6 @@ namespace MediaBrowser.Controller.Providers
public Dictionary<string, string> SeriesProviderIds { get; set; } public Dictionary<string, string> SeriesProviderIds { get; set; }
public int? IndexNumberEnd { get; set; } public int? IndexNumberEnd { get; set; }
public int? AnimeSeriesIndex { get; set; }
public bool IsMissingEpisode { get; set; } public bool IsMissingEpisode { get; set; }
public bool IsVirtualUnaired { get; set; } public bool IsVirtualUnaired { get; set; }

View File

@ -6,7 +6,6 @@ namespace MediaBrowser.Controller.Providers
public class SeasonInfo : ItemLookupInfo public class SeasonInfo : ItemLookupInfo
{ {
public Dictionary<string, string> SeriesProviderIds { get; set; } public Dictionary<string, string> SeriesProviderIds { get; set; }
public int? AnimeSeriesIndex { get; set; }
public SeasonInfo() public SeasonInfo()
{ {

View File

@ -2,6 +2,5 @@ namespace MediaBrowser.Controller.Providers
{ {
public class SeriesInfo : ItemLookupInfo public class SeriesInfo : ItemLookupInfo
{ {
public int? AnimeSeriesIndex { get; set; }
} }
} }

View File

@ -69,21 +69,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
break; break;
} }
case "AnimeSeriesIndex":
{
var number = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(number))
{
int num;
if (int.TryParse(number, out num))
{
item.AnimeSeriesIndex = num;
}
}
break;
}
case "Status": case "Status":
{ {
var status = reader.ReadElementContentAsString(); var status = reader.ReadElementContentAsString();

View File

@ -606,9 +606,20 @@ namespace MediaBrowser.Model.Dlna
return playlistItem; return playlistItem;
} }
private int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
{
if ((audioStream.Channels ?? 0) >= 6)
{
return 384000;
}
return 192000;
}
private int GetAudioBitrate(string subProtocol, long? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream) private int GetAudioBitrate(string subProtocol, long? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream)
{ {
int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? 192000; int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
// Reduce the bitrate if we're downmixing // Reduce the bitrate if we're downmixing
if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value) if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
{ {

View File

@ -85,8 +85,6 @@ namespace MediaBrowser.Model.Dto
public float? Metascore { get; set; } public float? Metascore { get; set; }
public bool? HasDynamicCategories { get; set; } public bool? HasDynamicCategories { get; set; }
public int? AnimeSeriesIndex { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [supports synchronize]. /// Gets or sets a value indicating whether [supports synchronize].
/// </summary> /// </summary>
@ -263,7 +261,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the play access. /// Gets or sets the play access.
/// </summary> /// </summary>
/// <value>The play access.</value> /// <value>The play access.</value>
public PlayAccess PlayAccess { get; set; } public PlayAccess? PlayAccess { get; set; }
/// <summary> /// <summary>
/// Gets or sets the aspect ratio. /// Gets or sets the aspect ratio.
@ -759,7 +757,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the type of the location. /// Gets or sets the type of the location.
/// </summary> /// </summary>
/// <value>The type of the location.</value> /// <value>The type of the location.</value>
public LocationType LocationType { get; set; } public LocationType? LocationType { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type of the iso. /// Gets or sets the type of the iso.

View File

@ -96,8 +96,7 @@ namespace MediaBrowser.Providers.TV
try try
{ {
int seasonNumber = AdjustForSeriesOffset(series, season.IndexNumber.Value); AddImages(list, season.IndexNumber.Value, path, cancellationToken);
AddImages(list, seasonNumber, path, cancellationToken);
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@ -139,15 +138,6 @@ namespace MediaBrowser.Providers.TV
.ThenByDescending(i => i.VoteCount ?? 0); .ThenByDescending(i => i.VoteCount ?? 0);
} }
private int AdjustForSeriesOffset(Series series, int seasonNumber)
{
var offset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds);
if (offset != null)
return (int)(seasonNumber + offset);
return seasonNumber;
}
private void AddImages(List<RemoteImageInfo> list, int seasonNumber, string path, CancellationToken cancellationToken) private void AddImages(List<RemoteImageInfo> list, int seasonNumber, string path, CancellationToken cancellationToken)
{ {
var root = _json.DeserializeFromFile<FanartSeriesProvider.RootObject>(path); var root = _json.DeserializeFromFile<FanartSeriesProvider.RootObject>(path);

View File

@ -203,9 +203,8 @@ namespace MediaBrowser.Providers.TV
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var existingEpisodes = (from s in series var existingEpisodes = (from s in series
let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1)
from c in s.GetRecursiveChildren().OfType<Episode>() from c in s.GetRecursiveChildren().OfType<Episode>()
select new Tuple<int, Episode>((c.ParentIndexNumber ?? 0) + seasonOffset, c)) select new Tuple<int, Episode>((c.ParentIndexNumber ?? 0) , c))
.ToList(); .ToList();
var lookup = episodeLookup as IList<Tuple<int, int>> ?? episodeLookup.ToList(); var lookup = episodeLookup as IList<Tuple<int, int>> ?? episodeLookup.ToList();
@ -248,7 +247,6 @@ namespace MediaBrowser.Providers.TV
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var targetSeries = DetermineAppropriateSeries(series, tuple.Item1); var targetSeries = DetermineAppropriateSeries(series, tuple.Item1);
var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(targetSeries.ProviderIds) ?? ((targetSeries.AnimeSeriesIndex ?? 1) - 1);
var unairedThresholdDays = 2; var unairedThresholdDays = 2;
now = now.AddDays(0 - unairedThresholdDays); now = now.AddDays(0 - unairedThresholdDays);
@ -259,7 +257,7 @@ namespace MediaBrowser.Providers.TV
{ {
// tvdb has a lot of nearly blank episodes // tvdb has a lot of nearly blank episodes
_logger.Info("Creating virtual missing episode {0} {1}x{2}", targetSeries.Name, tuple.Item1, tuple.Item2); _logger.Info("Creating virtual missing episode {0} {1}x{2}", targetSeries.Name, tuple.Item1, tuple.Item2);
await AddEpisode(targetSeries, tuple.Item1 - seasonOffset, tuple.Item2, cancellationToken).ConfigureAwait(false); await AddEpisode(targetSeries, tuple.Item1, tuple.Item2, cancellationToken).ConfigureAwait(false);
hasChanges = true; hasChanges = true;
} }
@ -268,7 +266,7 @@ namespace MediaBrowser.Providers.TV
{ {
// tvdb has a lot of nearly blank episodes // tvdb has a lot of nearly blank episodes
_logger.Info("Creating virtual unaired episode {0} {1}x{2}", targetSeries.Name, tuple.Item1, tuple.Item2); _logger.Info("Creating virtual unaired episode {0} {1}x{2}", targetSeries.Name, tuple.Item1, tuple.Item2);
await AddEpisode(targetSeries, tuple.Item1 - seasonOffset, tuple.Item2, cancellationToken).ConfigureAwait(false); await AddEpisode(targetSeries, tuple.Item1, tuple.Item2, cancellationToken).ConfigureAwait(false);
hasChanges = true; hasChanges = true;
} }
@ -279,13 +277,11 @@ namespace MediaBrowser.Providers.TV
private Series DetermineAppropriateSeries(IEnumerable<Series> series, int seasonNumber) private Series DetermineAppropriateSeries(IEnumerable<Series> series, int seasonNumber)
{ {
var seriesAndOffsets = series.Select(s => new { Series = s, SeasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1) }).ToList(); var seriesAndOffsets = series.ToList();
var bestMatch = seriesAndOffsets.FirstOrDefault(s => s.Series.GetRecursiveChildren().OfType<Season>().Any(season => (season.IndexNumber + s.SeasonOffset) == seasonNumber)) ?? return seriesAndOffsets.FirstOrDefault(s => s.GetRecursiveChildren().OfType<Season>().Any(season => (season.IndexNumber) == seasonNumber)) ??
seriesAndOffsets.FirstOrDefault(s => s.Series.GetRecursiveChildren().OfType<Season>().Any(season => (season.IndexNumber + s.SeasonOffset) == 1)) ?? seriesAndOffsets.FirstOrDefault(s => s.GetRecursiveChildren().OfType<Season>().Any(season => (season.IndexNumber) == 1)) ??
seriesAndOffsets.OrderBy(s => s.Series.GetRecursiveChildren().OfType<Season>().Select(season => season.IndexNumber + s.SeasonOffset).Min()).First(); seriesAndOffsets.OrderBy(s => s.GetRecursiveChildren().OfType<Season>().Select(season => season.IndexNumber).Min()).First();
return bestMatch.Series;
} }
/// <summary> /// <summary>
@ -296,9 +292,8 @@ namespace MediaBrowser.Providers.TV
bool allowMissingEpisodes) bool allowMissingEpisodes)
{ {
var existingEpisodes = (from s in series var existingEpisodes = (from s in series
let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1)
from c in s.GetRecursiveChildren().OfType<Episode>() from c in s.GetRecursiveChildren().OfType<Episode>()
select new { SeasonOffset = seasonOffset, Episode = c }) select new { Episode = c })
.ToList(); .ToList();
var physicalEpisodes = existingEpisodes var physicalEpisodes = existingEpisodes
@ -314,12 +309,12 @@ namespace MediaBrowser.Providers.TV
{ {
if (i.Episode.IndexNumber.HasValue && i.Episode.ParentIndexNumber.HasValue) if (i.Episode.IndexNumber.HasValue && i.Episode.ParentIndexNumber.HasValue)
{ {
var seasonNumber = i.Episode.ParentIndexNumber.Value + i.SeasonOffset; var seasonNumber = i.Episode.ParentIndexNumber.Value;
var episodeNumber = i.Episode.IndexNumber.Value; var episodeNumber = i.Episode.IndexNumber.Value;
// If there's a physical episode with the same season and episode number, delete it // If there's a physical episode with the same season and episode number, delete it
if (physicalEpisodes.Any(p => if (physicalEpisodes.Any(p =>
p.Episode.ParentIndexNumber.HasValue && (p.Episode.ParentIndexNumber.Value + p.SeasonOffset) == seasonNumber && p.Episode.ParentIndexNumber.HasValue && (p.Episode.ParentIndexNumber.Value) == seasonNumber &&
p.Episode.ContainsEpisodeNumber(episodeNumber))) p.Episode.ContainsEpisodeNumber(episodeNumber)))
{ {
return true; return true;
@ -371,28 +366,27 @@ namespace MediaBrowser.Providers.TV
IEnumerable<Tuple<int, int>> episodeLookup) IEnumerable<Tuple<int, int>> episodeLookup)
{ {
var existingSeasons = (from s in series var existingSeasons = (from s in series
let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1)
from c in s.Children.OfType<Season>() from c in s.Children.OfType<Season>()
select new { SeasonOffset = seasonOffset, Season = c }) select c)
.ToList(); .ToList();
var physicalSeasons = existingSeasons var physicalSeasons = existingSeasons
.Where(i => i.Season.LocationType != LocationType.Virtual) .Where(i => i.LocationType != LocationType.Virtual)
.ToList(); .ToList();
var virtualSeasons = existingSeasons var virtualSeasons = existingSeasons
.Where(i => i.Season.LocationType == LocationType.Virtual) .Where(i => i.LocationType == LocationType.Virtual)
.ToList(); .ToList();
var seasonsToRemove = virtualSeasons var seasonsToRemove = virtualSeasons
.Where(i => .Where(i =>
{ {
if (i.Season.IndexNumber.HasValue) if (i.IndexNumber.HasValue)
{ {
var seasonNumber = i.Season.IndexNumber.Value + i.SeasonOffset; var seasonNumber = i.IndexNumber.Value;
// If there's a physical season with the same number, delete it // If there's a physical season with the same number, delete it
if (physicalSeasons.Any(p => p.Season.IndexNumber.HasValue && (p.Season.IndexNumber.Value + p.SeasonOffset) == seasonNumber && string.Equals(p.Season.Series.PresentationUniqueKey, i.Season.Series.PresentationUniqueKey, StringComparison.Ordinal))) if (physicalSeasons.Any(p => p.IndexNumber.HasValue && (p.IndexNumber.Value) == seasonNumber && string.Equals(p.Series.PresentationUniqueKey, i.Series.PresentationUniqueKey, StringComparison.Ordinal)))
{ {
return true; return true;
} }
@ -408,13 +402,13 @@ namespace MediaBrowser.Providers.TV
// Season does not have a number // Season does not have a number
// Remove if there are no episodes directly in series without a season number // Remove if there are no episodes directly in series without a season number
return i.Season.Series.GetRecursiveChildren().OfType<Episode>().All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder); return i.Series.GetRecursiveChildren().OfType<Episode>().All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder);
}) })
.ToList(); .ToList();
var hasChanges = false; var hasChanges = false;
foreach (var seasonToRemove in seasonsToRemove.Select(s => s.Season)) foreach (var seasonToRemove in seasonsToRemove)
{ {
_logger.Info("Removing virtual season {0} {1}", seasonToRemove.Series.Name, seasonToRemove.IndexNumber); _logger.Info("Removing virtual season {0} {1}", seasonToRemove.Series.Name, seasonToRemove.IndexNumber);

View File

@ -59,7 +59,6 @@ namespace MediaBrowser.Providers.TV
{ {
// Process images // Process images
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, series.ProviderIds); var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, series.ProviderIds);
var indexOffset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds) ?? 0;
var nodes = TvdbEpisodeProvider.Current.GetEpisodeXmlNodes(seriesDataPath, episode.GetLookupInfo()); var nodes = TvdbEpisodeProvider.Current.GetEpisodeXmlNodes(seriesDataPath, episode.GetLookupInfo());

View File

@ -99,15 +99,6 @@ namespace MediaBrowser.Providers.TV
return new RemoteImageInfo[] { }; return new RemoteImageInfo[] { };
} }
private int AdjustForSeriesOffset(Series series, int seasonNumber)
{
var offset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds);
if (offset != null)
return (seasonNumber + offset.Value);
return seasonNumber;
}
internal static IEnumerable<RemoteImageInfo> GetImages(string xmlPath, string preferredLanguage, int seasonNumber, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem, CancellationToken cancellationToken) internal static IEnumerable<RemoteImageInfo> GetImages(string xmlPath, string preferredLanguage, int seasonNumber, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem, CancellationToken cancellationToken)
{ {
var settings = xmlReaderSettingsFactory.Create(false); var settings = xmlReaderSettingsFactory.Create(false);

View File

@ -76,10 +76,6 @@ namespace MediaBrowser.Providers.TV
try try
{ {
var seriesOffset = TvdbSeriesProvider.GetSeriesOffset(item.ProviderIds);
if (seriesOffset != null && seriesOffset.Value != 0)
return TvdbSeasonImageProvider.GetImages(path, language, seriesOffset.Value + 1, _xmlReaderSettingsFactory, _fileSystem, cancellationToken);
return GetImages(path, language, cancellationToken); return GetImages(path, language, cancellationToken);
} }
catch (FileNotFoundException) catch (FileNotFoundException)

View File

@ -27,9 +27,6 @@ namespace MediaBrowser.Providers.TV
{ {
public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{ {
private const string TvdbSeriesOffset = "TvdbSeriesOffset";
private const string TvdbSeriesOffsetFormat = "{0}-{1}";
internal readonly SemaphoreSlim TvDbResourcePool = new SemaphoreSlim(2, 2); internal readonly SemaphoreSlim TvDbResourcePool = new SemaphoreSlim(2, 2);
internal static TvdbSeriesProvider Current { get; private set; } internal static TvdbSeriesProvider Current { get; private set; }
private readonly IZipClient _zipClient; private readonly IZipClient _zipClient;
@ -123,23 +120,6 @@ namespace MediaBrowser.Providers.TV
return result; return result;
} }
internal static int? GetSeriesOffset(Dictionary<string, string> seriesProviderIds)
{
string idString;
if (!seriesProviderIds.TryGetValue(TvdbSeriesOffset, out idString))
return null;
var parts = idString.Split('-');
if (parts.Length < 2)
return null;
int offset;
if (int.TryParse(parts[1], out offset))
return offset;
return null;
}
/// <summary> /// <summary>
/// Fetches the series data. /// Fetches the series data.
/// </summary> /// </summary>

View File

@ -65,22 +65,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break; break;
} }
case "animeseriesindex":
{
var number = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(number))
{
int num;
if (int.TryParse(number, out num))
{
item.AnimeSeriesIndex = num;
}
}
break;
}
case "status": case "status":
{ {
var status = reader.ReadElementContentAsString(); var status = reader.ReadElementContentAsString();

View File

@ -83,11 +83,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
writer.WriteElementString("airs_dayofweek", series.AirDays[0].ToString()); writer.WriteElementString("airs_dayofweek", series.AirDays[0].ToString());
} }
if (series.AnimeSeriesIndex.HasValue)
{
writer.WriteElementString("animeseriesindex", series.AnimeSeriesIndex.Value.ToString(CultureInfo.InvariantCulture));
}
} }
protected override List<string> GetTagsUsed(IHasMetadata item) protected override List<string> GetTagsUsed(IHasMetadata item)
@ -101,8 +96,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
"episode", "episode",
"status", "status",
"airs_time", "airs_time",
"airs_dayofweek", "airs_dayofweek"
"animeseriesindex"
}); });
return list; return list;
} }

View File

@ -1,3 +1,3 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.2.1.108")] [assembly: AssemblyVersion("3.2.1.109")]