mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-05 21:37:10 -04:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
5548d17a3b
@ -1,6 +1,7 @@
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
@ -65,6 +66,7 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
protected IItemRepository ItemRepository { get; private set; }
|
||||
protected ILiveTvManager LiveTvManager { get; private set; }
|
||||
protected IDlnaManager DlnaManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||
@ -77,8 +79,9 @@ namespace MediaBrowser.Api.Playback
|
||||
/// <param name="dtoService">The dto service.</param>
|
||||
/// <param name="fileSystem">The file system.</param>
|
||||
/// <param name="itemRepository">The item repository.</param>
|
||||
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager)
|
||||
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager)
|
||||
{
|
||||
DlnaManager = dlnaManager;
|
||||
EncodingManager = encodingManager;
|
||||
LiveTvManager = liveTvManager;
|
||||
ItemRepository = itemRepository;
|
||||
@ -774,29 +777,24 @@ namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
var codec = request.AudioCodec;
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "aac -strict experimental";
|
||||
}
|
||||
if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "libmp3lame";
|
||||
}
|
||||
if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "libvorbis";
|
||||
}
|
||||
if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "wmav2";
|
||||
}
|
||||
|
||||
return codec.ToLower();
|
||||
return "aac -strict experimental";
|
||||
}
|
||||
if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "libmp3lame";
|
||||
}
|
||||
if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "libvorbis";
|
||||
}
|
||||
if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "wmav2";
|
||||
}
|
||||
|
||||
return "copy";
|
||||
return codec.ToLower();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1212,96 +1210,85 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
// Device profile name
|
||||
request.DeviceId = val;
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
request.DeviceId = val;
|
||||
request.MediaSourceId = val;
|
||||
}
|
||||
else if (i == 2)
|
||||
{
|
||||
request.MediaSourceId = val;
|
||||
}
|
||||
else if (i == 3)
|
||||
{
|
||||
request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else if (i == 4)
|
||||
else if (i == 3)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.VideoCodec = val;
|
||||
}
|
||||
}
|
||||
else if (i == 5)
|
||||
else if (i == 4)
|
||||
{
|
||||
request.AudioCodec = val;
|
||||
}
|
||||
else if (i == 6)
|
||||
else if (i == 5)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
|
||||
}
|
||||
}
|
||||
else if (i == 7)
|
||||
else if (i == 6)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
|
||||
}
|
||||
}
|
||||
else if (i == 8)
|
||||
else if (i == 7)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.VideoBitRate = int.Parse(val, UsCulture);
|
||||
}
|
||||
}
|
||||
else if (i == 9)
|
||||
else if (i == 8)
|
||||
{
|
||||
request.AudioBitRate = int.Parse(val, UsCulture);
|
||||
}
|
||||
else if (i == 10)
|
||||
else if (i == 9)
|
||||
{
|
||||
request.MaxAudioChannels = int.Parse(val, UsCulture);
|
||||
}
|
||||
else if (i == 11)
|
||||
else if (i == 10)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.MaxWidth = int.Parse(val, UsCulture);
|
||||
}
|
||||
}
|
||||
else if (i == 12)
|
||||
else if (i == 11)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.MaxHeight = int.Parse(val, UsCulture);
|
||||
}
|
||||
}
|
||||
else if (i == 13)
|
||||
else if (i == 12)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.Framerate = int.Parse(val, UsCulture);
|
||||
}
|
||||
}
|
||||
else if (i == 14)
|
||||
else if (i == 13)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
request.StartTimeTicks = long.Parse(val, UsCulture);
|
||||
}
|
||||
}
|
||||
else if (i == 15)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
videoRequest.Profile = val;
|
||||
}
|
||||
}
|
||||
else if (i == 16)
|
||||
else if (i == 14)
|
||||
{
|
||||
if (videoRequest != null)
|
||||
{
|
||||
@ -1487,9 +1474,172 @@ namespace MediaBrowser.Api.Playback
|
||||
state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
|
||||
state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
|
||||
|
||||
ApplyDeviceProfileSettings(state);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private void ApplyDeviceProfileSettings(StreamState state)
|
||||
{
|
||||
var headers = new Dictionary<string, string>();
|
||||
|
||||
foreach (var key in Request.Headers.AllKeys)
|
||||
{
|
||||
headers[key] = Request.Headers[key];
|
||||
}
|
||||
|
||||
var profile = DlnaManager.GetProfile(headers);
|
||||
|
||||
var container = Path.GetExtension(state.RequestedUrl);
|
||||
|
||||
if (string.IsNullOrEmpty(container))
|
||||
{
|
||||
container = Path.GetExtension(GetOutputFilePath(state));
|
||||
}
|
||||
|
||||
var audioCodec = state.Request.AudioCodec;
|
||||
|
||||
if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
|
||||
{
|
||||
audioCodec = state.AudioStream.Codec;
|
||||
}
|
||||
|
||||
var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
|
||||
|
||||
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
|
||||
{
|
||||
videoCodec = state.VideoStream.Codec;
|
||||
}
|
||||
|
||||
var mediaProfile = state.VideoRequest == null ?
|
||||
profile.GetAudioMediaProfile(container, audioCodec, state.AudioStream) :
|
||||
profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream);
|
||||
|
||||
if (mediaProfile != null)
|
||||
{
|
||||
state.MimeType = mediaProfile.MimeType;
|
||||
state.OrgPn = mediaProfile.OrgPn;
|
||||
}
|
||||
|
||||
var transcodingProfile = state.VideoRequest == null ?
|
||||
profile.GetAudioTranscodingProfile(container, audioCodec) :
|
||||
profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec);
|
||||
|
||||
if (transcodingProfile != null)
|
||||
{
|
||||
state.EstimateContentLength = transcodingProfile.EstimateContentLength;
|
||||
state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
|
||||
state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
|
||||
|
||||
foreach (var setting in transcodingProfile.Settings)
|
||||
{
|
||||
switch (setting.Name)
|
||||
{
|
||||
case TranscodingSettingType.VideoProfile:
|
||||
{
|
||||
if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.Profile))
|
||||
{
|
||||
state.VideoRequest.Profile = setting.Value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentException("Unrecognized TranscodingSettingType");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds the dlna headers.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
protected void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
|
||||
{
|
||||
var timeSeek = GetHeader("TimeSeekRange.dlna.org");
|
||||
|
||||
if (!string.IsNullOrEmpty(timeSeek))
|
||||
{
|
||||
ResultFactory.ThrowError(406, "Time seek not supported during encoding.", responseHeaders);
|
||||
return;
|
||||
}
|
||||
|
||||
var transferMode = GetHeader("transferMode.dlna.org");
|
||||
responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
|
||||
responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
|
||||
|
||||
var contentFeatures = string.Empty;
|
||||
var extension = GetOutputFileExtension(state);
|
||||
|
||||
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
|
||||
var orgOp = isStaticallyStreamed || state.TranscodeSeekInfo == TranscodeSeekInfo.Bytes ? ";DLNA.ORG_OP=01" : ";DLNA.ORG_OP=00";
|
||||
|
||||
// 0 = native, 1 = transcoded
|
||||
var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
||||
|
||||
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(state.OrgPn))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=" + state.OrgPn;
|
||||
}
|
||||
else if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MP3";
|
||||
}
|
||||
else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AAC_ISO";
|
||||
}
|
||||
else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=WMABASE";
|
||||
}
|
||||
else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AVI";
|
||||
}
|
||||
else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MATROSKA";
|
||||
}
|
||||
else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
|
||||
}
|
||||
else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||
}
|
||||
else if (string.Equals(extension, ".ts", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||
}
|
||||
//else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// // ??
|
||||
// contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
//}
|
||||
|
||||
if (!string.IsNullOrEmpty(contentFeatures))
|
||||
{
|
||||
responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
||||
}
|
||||
|
||||
foreach (var item in responseHeaders)
|
||||
{
|
||||
Request.Response.AddHeader(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enforces the resolution limit.
|
||||
/// </summary>
|
||||
@ -1605,7 +1755,7 @@ namespace MediaBrowser.Api.Playback
|
||||
return "vorbis";
|
||||
}
|
||||
|
||||
return null;
|
||||
return "copy";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2,13 +2,13 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -24,7 +24,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
/// </summary>
|
||||
public abstract class BaseHlsService : BaseStreamingService
|
||||
{
|
||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
|
||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.IO;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
@ -60,7 +60,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
|
||||
public class DynamicHlsService : BaseHlsService
|
||||
{
|
||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
|
||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
@ -52,7 +53,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
/// </summary>
|
||||
public class VideoHlsService : BaseHlsService
|
||||
{
|
||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
|
||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
@ -43,7 +44,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
/// </summary>
|
||||
public class AudioService : BaseProgressiveStreamingService
|
||||
{
|
||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, httpClient, imageProcessor)
|
||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.IO;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
@ -26,8 +26,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
protected readonly IImageProcessor ImageProcessor;
|
||||
protected readonly IHttpClient HttpClient;
|
||||
|
||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor)
|
||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager)
|
||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
||||
{
|
||||
HttpClient = httpClient;
|
||||
ImageProcessor = imageProcessor;
|
||||
@ -100,92 +99,6 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the dlna headers.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
private void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
|
||||
{
|
||||
var timeSeek = GetHeader("TimeSeekRange.dlna.org");
|
||||
|
||||
if (!string.IsNullOrEmpty(timeSeek))
|
||||
{
|
||||
ResultFactory.ThrowError(406, "Time seek not supported during encoding.", responseHeaders);
|
||||
return;
|
||||
}
|
||||
|
||||
var transferMode = GetHeader("transferMode.dlna.org");
|
||||
responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
|
||||
responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
|
||||
|
||||
var contentFeatures = string.Empty;
|
||||
var extension = GetOutputFileExtension(state);
|
||||
|
||||
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
|
||||
var orgOp = isStaticallyStreamed ? ";DLNA.ORG_OP=01" : ";DLNA.ORG_OP=00";
|
||||
|
||||
// 0 = native, 1 = transcoded
|
||||
var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
||||
|
||||
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
|
||||
|
||||
if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MP3";
|
||||
}
|
||||
else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AAC_ISO";
|
||||
}
|
||||
else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=WMABASE";
|
||||
}
|
||||
else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AVI";
|
||||
}
|
||||
else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MATROSKA";
|
||||
}
|
||||
else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
|
||||
}
|
||||
else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||
}
|
||||
else if (string.Equals(extension, ".ts", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||
}
|
||||
//else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
//}
|
||||
//else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// // ??
|
||||
// contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
|
||||
//}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(contentFeatures))
|
||||
{
|
||||
responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
||||
}
|
||||
|
||||
foreach (var item in responseHeaders)
|
||||
{
|
||||
Request.Response.AddHeader(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the transcoding job.
|
||||
/// </summary>
|
||||
|
@ -1,6 +1,7 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
@ -58,7 +59,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
/// </summary>
|
||||
public class VideoService : BaseProgressiveStreamingService
|
||||
{
|
||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, httpClient, imageProcessor)
|
||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using System.Collections.Generic;
|
||||
@ -77,8 +78,21 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
public string InputAudioCodec { get; set; }
|
||||
|
||||
public string MimeType { get; set; }
|
||||
public string OrgPn { get; set; }
|
||||
|
||||
// DLNA Settings
|
||||
public bool EstimateContentLength { get; set; }
|
||||
public bool EnableMpegtsM2TsMode { get; set; }
|
||||
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
|
||||
|
||||
public string GetMimeType(string outputPath)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(MimeType))
|
||||
{
|
||||
return MimeType;
|
||||
}
|
||||
|
||||
return MimeTypes.GetMimeType(outputPath);
|
||||
}
|
||||
}
|
||||
|
@ -41,9 +41,7 @@ namespace MediaBrowser.Controller.Dlna
|
||||
/// <summary>
|
||||
/// Gets or sets the manufacturer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The manufacturer.
|
||||
/// </value>
|
||||
/// <value>The manufacturer.</value>
|
||||
public string Manufacturer { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the manufacturer URL.
|
||||
|
@ -1,4 +1,7 @@
|
||||
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public class DeviceProfile
|
||||
@ -9,12 +12,6 @@ namespace MediaBrowser.Controller.Dlna
|
||||
/// <value>The name.</value>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the client.
|
||||
/// </summary>
|
||||
/// <value>The type of the client.</value>
|
||||
public string ClientType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the transcoding profiles.
|
||||
/// </summary>
|
||||
@ -76,5 +73,141 @@ namespace MediaBrowser.Controller.Dlna
|
||||
CodecProfiles = new CodecProfile[] { };
|
||||
ContainerProfiles = new ContainerProfile[] { };
|
||||
}
|
||||
|
||||
public TranscodingProfile GetAudioTranscodingProfile(string container, string audioCodec)
|
||||
{
|
||||
container = (container ?? string.Empty).TrimStart('.');
|
||||
|
||||
return TranscodingProfiles.FirstOrDefault(i =>
|
||||
{
|
||||
if (i.Type != DlnaProfileType.Audio)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(container, i.Container, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public TranscodingProfile GetVideoTranscodingProfile(string container, string audioCodec, string videoCodec)
|
||||
{
|
||||
container = (container ?? string.Empty).TrimStart('.');
|
||||
|
||||
return TranscodingProfiles.FirstOrDefault(i =>
|
||||
{
|
||||
if (i.Type != DlnaProfileType.Video)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(container, i.Container, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(videoCodec, i.VideoCodec, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public MediaProfile GetAudioMediaProfile(string container, string audioCodec, MediaStream audioStream)
|
||||
{
|
||||
container = (container ?? string.Empty).TrimStart('.');
|
||||
|
||||
return MediaProfiles.FirstOrDefault(i =>
|
||||
{
|
||||
if (i.Type != DlnaProfileType.Audio)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var containers = i.GetContainers().ToList();
|
||||
if (containers.Count > 0 && !containers.Contains(container))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var audioCodecs = i.GetAudioCodecs().ToList();
|
||||
if (audioCodecs.Count > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public MediaProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec, MediaStream audioStream, MediaStream videoStream)
|
||||
{
|
||||
container = (container ?? string.Empty).TrimStart('.');
|
||||
|
||||
return MediaProfiles.FirstOrDefault(i =>
|
||||
{
|
||||
if (i.Type != DlnaProfileType.Video)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var containers = i.GetContainers().ToList();
|
||||
if (containers.Count > 0 && !containers.Contains(container))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var audioCodecs = i.GetAudioCodecs().ToList();
|
||||
if (audioCodecs.Count > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var videoCodecs = i.GetVideoCodecs().ToList();
|
||||
if (videoCodecs.Count > 0 && !videoCodecs.Contains(videoCodec ?? string.Empty))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public MediaProfile GetPhotoMediaProfile(string container)
|
||||
{
|
||||
container = (container ?? string.Empty).TrimStart('.');
|
||||
|
||||
return MediaProfiles.FirstOrDefault(i =>
|
||||
{
|
||||
if (i.Type != DlnaProfileType.Photo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var containers = i.GetContainers().ToList();
|
||||
if (containers.Count > 0 && !containers.Contains(container))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,13 @@ namespace MediaBrowser.Controller.Dlna
|
||||
/// <returns>DlnaProfile.</returns>
|
||||
DeviceProfile GetDefaultProfile();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the profile.
|
||||
/// </summary>
|
||||
/// <param name="headers">The headers.</param>
|
||||
/// <returns>DeviceProfile.</returns>
|
||||
DeviceProfile GetProfile(IDictionary<string,string> headers);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the profile.
|
||||
/// </summary>
|
||||
|
@ -19,6 +19,11 @@ namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
Conditions = new ProfileCondition[] {};
|
||||
}
|
||||
|
||||
public List<string> GetContainers()
|
||||
{
|
||||
return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
|
||||
}
|
||||
|
||||
public List<string> GetAudioCodecs()
|
||||
{
|
||||
|
@ -1,4 +1,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public class TranscodingProfile
|
||||
@ -11,7 +13,7 @@ namespace MediaBrowser.Controller.Dlna
|
||||
public string AudioCodec { get; set; }
|
||||
|
||||
public bool EstimateContentLength { get; set; }
|
||||
|
||||
public bool EnableMpegtsM2TsMode { get; set; }
|
||||
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
|
||||
|
||||
public TranscodingSetting[] Settings { get; set; }
|
||||
@ -21,7 +23,11 @@ namespace MediaBrowser.Controller.Dlna
|
||||
Settings = new TranscodingSetting[] { };
|
||||
}
|
||||
|
||||
public bool EnableMpegtsM2TsMode { get; set; }
|
||||
|
||||
public List<string> GetAudioCodecs()
|
||||
{
|
||||
return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public class TranscodingSetting
|
||||
|
@ -1,5 +1,4 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
@ -284,22 +283,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
break;
|
||||
}
|
||||
|
||||
case "TagLine":
|
||||
{
|
||||
var tagline = reader.ReadElementContentAsString();
|
||||
|
||||
var hasTaglines = item as IHasTaglines;
|
||||
if (hasTaglines != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(tagline))
|
||||
{
|
||||
hasTaglines.AddTagline(tagline);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "Language":
|
||||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
@ -380,9 +363,7 @@ namespace MediaBrowser.Controller.Providers
|
||||
}
|
||||
|
||||
case "ContentRating":
|
||||
case "certification":
|
||||
case "MPAARating":
|
||||
case "ESRBRating":
|
||||
{
|
||||
var rating = reader.ReadElementContentAsString();
|
||||
|
||||
@ -415,7 +396,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
break;
|
||||
}
|
||||
|
||||
case "Runtime":
|
||||
case "RunningTime":
|
||||
{
|
||||
var text = reader.ReadElementContentAsString();
|
||||
@ -431,19 +411,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
break;
|
||||
}
|
||||
|
||||
case "Genre":
|
||||
{
|
||||
foreach (var name in SplitNames(reader.ReadElementContentAsString()))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
item.AddGenre(name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "AspectRatio":
|
||||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
@ -587,7 +554,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
break;
|
||||
}
|
||||
|
||||
case "ReleaseYear":
|
||||
case "ProductionYear":
|
||||
{
|
||||
var val = reader.ReadElementContentAsString();
|
||||
@ -606,7 +572,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
|
||||
case "Rating":
|
||||
case "IMDBrating":
|
||||
case "TGDBRating":
|
||||
{
|
||||
|
||||
var rating = reader.ReadElementContentAsString();
|
||||
@ -683,22 +648,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MusicbrainzId":
|
||||
{
|
||||
var mbz = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(mbz))
|
||||
{
|
||||
if (item is MusicAlbum)
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbz);
|
||||
}
|
||||
else if (item is MusicArtist)
|
||||
{
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzArtist, mbz);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MusicBrainzAlbumId":
|
||||
{
|
||||
var mbz = reader.ReadElementContentAsString();
|
||||
@ -802,9 +751,7 @@ namespace MediaBrowser.Controller.Providers
|
||||
}
|
||||
break;
|
||||
|
||||
case "IMDB_ID":
|
||||
case "IMDB":
|
||||
case "IMDbId":
|
||||
var imDbId = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(imDbId))
|
||||
{
|
||||
@ -856,15 +803,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
break;
|
||||
}
|
||||
|
||||
case "ParentalRating":
|
||||
{
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
{
|
||||
FetchFromParentalRatingNode(subtree, item);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "Studios":
|
||||
{
|
||||
using (var subtree = reader.ReadSubtree())
|
||||
@ -1227,32 +1165,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches from parental rating node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
private void FetchFromParentalRatingNode(XmlReader reader, T item)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
// Removed support for "Value" tag as it conflicted with MPAA rating but leaving this function for possible
|
||||
// future support of "Description" -ebr
|
||||
|
||||
default:
|
||||
reader.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the persons from XML node.
|
||||
/// </summary>
|
||||
|
@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Dlna.Profiles;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
@ -43,7 +44,8 @@ namespace MediaBrowser.Dlna
|
||||
new WdtvLiveProfile(),
|
||||
new DenonAvrProfile(),
|
||||
new LinksysDMA2100Profile(),
|
||||
new LgTvProfile()
|
||||
new LgTvProfile(),
|
||||
new Foobar2000Profile()
|
||||
};
|
||||
|
||||
foreach (var item in list)
|
||||
@ -124,5 +126,38 @@ namespace MediaBrowser.Dlna
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public DeviceProfile GetProfile(IDictionary<string, string> headers)
|
||||
{
|
||||
return GetProfiles().FirstOrDefault(i => IsMatch(headers, i.Identification)) ??
|
||||
GetDefaultProfile();
|
||||
}
|
||||
|
||||
private bool IsMatch(IDictionary<string, string> headers, DeviceIdentification profileInfo)
|
||||
{
|
||||
return profileInfo.Headers.Any(i => IsMatch(headers, i));
|
||||
}
|
||||
|
||||
private bool IsMatch(IDictionary<string, string> headers, HttpHeaderInfo header)
|
||||
{
|
||||
string value;
|
||||
|
||||
if (headers.TryGetValue(header.Name, out value))
|
||||
{
|
||||
switch (header.Match)
|
||||
{
|
||||
case HeaderMatchType.Equals:
|
||||
return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
|
||||
case HeaderMatchType.Substring:
|
||||
return value.IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
|
||||
case HeaderMatchType.Regex:
|
||||
return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
|
||||
default:
|
||||
throw new ArgumentException("Unrecognized HeaderMatchType");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -61,7 +61,6 @@
|
||||
<Compile Include="PlayTo\DeviceService.cs" />
|
||||
<Compile Include="PlayTo\DidlBuilder.cs" />
|
||||
<Compile Include="PlayTo\DlnaController.cs" />
|
||||
<Compile Include="PlayTo\DlnaControllerFactory.cs" />
|
||||
<Compile Include="PlayTo\Extensions.cs" />
|
||||
<Compile Include="PlayTo\PlaylistItem.cs">
|
||||
<SubType>Code</SubType>
|
||||
@ -70,7 +69,8 @@
|
||||
<Compile Include="PlayTo\PlayToManager.cs" />
|
||||
<Compile Include="PlayTo\PlayToServerEntryPoint.cs" />
|
||||
<Compile Include="PlayTo\ServiceAction.cs" />
|
||||
<Compile Include="PlayTo\SsdpHelper.cs" />
|
||||
<Compile Include="Profiles\Foobar2000Profile.cs" />
|
||||
<Compile Include="Ssdp\SsdpHelper.cs" />
|
||||
<Compile Include="PlayTo\SsdpHttpClient.cs" />
|
||||
<Compile Include="PlayTo\StateVariable.cs" />
|
||||
<Compile Include="PlayTo\StreamHelper.cs" />
|
||||
@ -100,7 +100,6 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Server\DlnaServerEntryPoint.cs" />
|
||||
<Compile Include="Server\Headers.cs" />
|
||||
<Compile Include="Server\RawHeaders.cs" />
|
||||
<Compile Include="Server\SsdpHandler.cs" />
|
||||
<Compile Include="Server\UpnpDevice.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -607,7 +607,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
url = "/" + url;
|
||||
|
||||
var httpClient = new SsdpHttpClient(_httpClient, _config);
|
||||
var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
|
||||
var document = await httpClient.GetDataAsync(Properties.BaseUrl + url);
|
||||
|
||||
AvCommands = TransportCommands.Create(document);
|
||||
}
|
||||
@ -625,7 +625,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
url = "/" + url;
|
||||
|
||||
var httpClient = new SsdpHttpClient(_httpClient, _config);
|
||||
var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url));
|
||||
var document = await httpClient.GetDataAsync(Properties.BaseUrl + url);
|
||||
|
||||
RendererCommands = TransportCommands.Create(document);
|
||||
}
|
||||
@ -646,7 +646,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
|
||||
|
||||
var document = await ssdpHttpClient.GetDataAsync(url).ConfigureAwait(false);
|
||||
var document = await ssdpHttpClient.GetDataAsync(url.ToString()).ConfigureAwait(false);
|
||||
|
||||
var deviceProperties = new DeviceInfo();
|
||||
|
||||
@ -681,10 +681,18 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
|
||||
if (presentationUrl != null)
|
||||
deviceProperties.PresentationUrl = presentationUrl.Value;
|
||||
|
||||
var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
|
||||
if (modelUrl != null)
|
||||
deviceProperties.ModelUrl = modelUrl.Value;
|
||||
|
||||
|
||||
var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault();
|
||||
if (serialNumber != null)
|
||||
deviceProperties.SerialNumber = serialNumber.Value;
|
||||
|
||||
var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault();
|
||||
if (modelDescription != null)
|
||||
deviceProperties.ModelDescription = modelDescription.Value;
|
||||
|
||||
deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port);
|
||||
|
||||
@ -724,7 +732,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
if (isRenderer)
|
||||
{
|
||||
|
||||
var device = new Device(deviceProperties, httpClient, logger, config);
|
||||
|
||||
await device.GetRenderingProtocolAsync().ConfigureAwait(false);
|
||||
|
@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
@ -17,27 +17,18 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
public string ClientType { get; set; }
|
||||
|
||||
private string _displayName = string.Empty;
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.IsNullOrEmpty(_displayName) ? Name : _displayName;
|
||||
}
|
||||
set
|
||||
{
|
||||
_displayName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string ModelName { get; set; }
|
||||
|
||||
public string ModelNumber { get; set; }
|
||||
|
||||
public string ModelDescription { get; set; }
|
||||
|
||||
public string ModelUrl { get; set; }
|
||||
|
||||
public string Manufacturer { get; set; }
|
||||
|
||||
public string SerialNumber { get; set; }
|
||||
|
||||
public string ManufacturerUrl { get; set; }
|
||||
|
||||
public string PresentationUrl { get; set; }
|
||||
@ -75,7 +66,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
ModelNumber = ModelNumber,
|
||||
FriendlyName = Name,
|
||||
ManufacturerUrl = ManufacturerUrl,
|
||||
ModelUrl = ModelUrl
|
||||
ModelUrl = ModelUrl,
|
||||
ModelDescription = ModelDescription,
|
||||
SerialNumber = SerialNumber
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,31 +9,27 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
internal class DidlBuilder
|
||||
{
|
||||
#region Constants
|
||||
const string CRLF = "\r\n";
|
||||
const string UNKNOWN = "Unknown";
|
||||
|
||||
internal const string CRLF = "\r\n";
|
||||
internal const string UNKNOWN = "Unknown";
|
||||
|
||||
internal const string DIDL_START = @"<item id=""{0}"" parentID=""{1}"" restricted=""1"" xmlns=""urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"">" + CRLF;
|
||||
internal const string DIDL_TITLE = @" <dc:title xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:title>" + CRLF;
|
||||
internal const string DIDL_ARTIST = @"<upnp:artist xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:artist>" + CRLF;
|
||||
internal const string DIDL_ALBUM = @"<upnp:album xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:album>" + CRLF;
|
||||
internal const string DIDL_TRACKNUM = @"<upnp:originalTrackNumber xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">0</upnp:originalTrackNumber>" + CRLF;
|
||||
internal const string DIDL_VIDEOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.videoItem</upnp:class>" + CRLF;
|
||||
internal const string DIDL_AUDIOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.audioItem.musicTrack</upnp:class>" + CRLF;
|
||||
internal const string DIDL_IMAGE = @" <upnp:albumArtURI dlna:profileID=""JPEG_TN"" xmlns:dlna=""urn:schemas-dlna-org:metadata-1-0/"" xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:albumArtURI>" + CRLF +
|
||||
@" <upnp:icon xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:icon>" + CRLF;
|
||||
internal const string DIDL_RELEASEDATE = @" <dc:date xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:date>" + CRLF;
|
||||
internal const string DIDL_GENRE = @" <upnp:genre xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:genre>" + CRLF;
|
||||
internal const string DESCRIPTION = @" <dc:description xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:description>" + CRLF;
|
||||
internal const string DIDL_VIDEO_RES = @" <res bitrate=""{0}"" duration=""{1}"" protocolInfo=""http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" resolution=""{2}x{3}"" size=""0"">{4}</res>" + CRLF;
|
||||
internal const string DIDL_AUDIO_RES = @" <res bitrate=""{0}"" duration=""{1}"" nrAudioChannels=""2"" protocolInfo=""http-get:*:audio/mp3:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" sampleFrequency=""{2}"" size=""0"">{3}</res>" + CRLF;
|
||||
internal const string DIDL_IMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""212x320"">{0}</res>" + CRLF;
|
||||
internal const string DIDL_ALBUMIMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""320x320"">{0}</res>" + CRLF;
|
||||
internal const string DIDL_RATING = @" <upnp:rating xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:rating>" + CRLF;
|
||||
internal const string DIDL_END = "</item>";
|
||||
|
||||
#endregion
|
||||
const string DIDL_START = @"<item id=""{0}"" parentID=""{1}"" restricted=""1"" xmlns=""urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"">" + CRLF;
|
||||
const string DIDL_TITLE = @" <dc:title xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:title>" + CRLF;
|
||||
const string DIDL_ARTIST = @"<upnp:artist xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:artist>" + CRLF;
|
||||
const string DIDL_ALBUM = @"<upnp:album xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:album>" + CRLF;
|
||||
const string DIDL_TRACKNUM = @"<upnp:originalTrackNumber xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:originalTrackNumber>" + CRLF;
|
||||
const string DIDL_VIDEOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.videoItem</upnp:class>" + CRLF;
|
||||
const string DIDL_AUDIOCLASS = @" <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.audioItem.musicTrack</upnp:class>" + CRLF;
|
||||
const string DIDL_IMAGE = @" <upnp:albumArtURI dlna:profileID=""JPEG_TN"" xmlns:dlna=""urn:schemas-dlna-org:metadata-1-0/"" xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:albumArtURI>" + CRLF +
|
||||
@" <upnp:icon xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:icon>" + CRLF;
|
||||
const string DIDL_RELEASEDATE = @" <dc:date xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:date>" + CRLF;
|
||||
const string DIDL_GENRE = @" <upnp:genre xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:genre>" + CRLF;
|
||||
const string DESCRIPTION = @" <dc:description xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:description>" + CRLF;
|
||||
const string DIDL_VIDEO_RES = @" <res bitrate=""{0}"" duration=""{1}"" protocolInfo=""http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" resolution=""{2}x{3}"" size=""0"">{4}</res>" + CRLF;
|
||||
const string DIDL_AUDIO_RES = @" <res bitrate=""{0}"" duration=""{1}"" nrAudioChannels=""2"" protocolInfo=""http-get:*:audio/mp3:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" sampleFrequency=""{2}"" size=""0"">{3}</res>" + CRLF;
|
||||
const string DIDL_IMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""212x320"">{0}</res>" + CRLF;
|
||||
const string DIDL_ALBUMIMAGE_RES = @" <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""320x320"">{0}</res>" + CRLF;
|
||||
const string DIDL_RATING = @" <upnp:rating xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:rating>" + CRLF;
|
||||
const string DIDL_END = "</item>";
|
||||
|
||||
/// <summary>
|
||||
/// Builds a Didl MetaData object for the specified dto.
|
||||
@ -44,7 +40,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
/// <param name="streamUrl">The stream URL.</param>
|
||||
/// <param name="streams">The streams.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
internal static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable<MediaStream> streams)
|
||||
public static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable<MediaStream> streams)
|
||||
{
|
||||
string response = string.Format(DIDL_START, dto.Id, userId);
|
||||
response += string.Format(DIDL_TITLE, dto.Name.Replace("&", "and"));
|
||||
@ -53,7 +49,12 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
else
|
||||
response += DIDL_AUDIOCLASS;
|
||||
|
||||
response += string.Format(DIDL_IMAGE, GetImageUrl(dto, serverAddress));
|
||||
var imageUrl = GetImageUrl(dto, serverAddress);
|
||||
|
||||
if (!string.IsNullOrEmpty(imageUrl))
|
||||
{
|
||||
response += string.Format(DIDL_IMAGE, imageUrl);
|
||||
}
|
||||
response += string.Format(DIDL_RELEASEDATE, GetDateString(dto.PremiereDate));
|
||||
|
||||
//TODO Add genres to didl;
|
||||
@ -63,7 +64,11 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
response += string.Format(DESCRIPTION, UNKNOWN);
|
||||
response += GetVideoDIDL(dto, streamUrl, streams);
|
||||
response += string.Format(DIDL_IMAGE_RES, GetImageUrl(dto, serverAddress));
|
||||
|
||||
if (!string.IsNullOrEmpty(imageUrl))
|
||||
{
|
||||
response += string.Format(DIDL_IMAGE_RES, imageUrl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -74,25 +79,25 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
response += string.Format(DIDL_ARTIST, audio.Artists.FirstOrDefault() ?? UNKNOWN);
|
||||
response += string.Format(DIDL_ALBUM, audio.Album);
|
||||
|
||||
// TODO: Bad format string?
|
||||
response += string.Format(DIDL_TRACKNUM, audio.IndexNumber ?? 0);
|
||||
}
|
||||
|
||||
response += GetAudioDIDL(dto, streamUrl, streams);
|
||||
response += string.Format(DIDL_ALBUMIMAGE_RES, GetImageUrl(dto, serverAddress));
|
||||
|
||||
if (!string.IsNullOrEmpty(imageUrl))
|
||||
{
|
||||
response += string.Format(DIDL_ALBUMIMAGE_RES, imageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
response += DIDL_END;
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
#region Private methods
|
||||
|
||||
private static string GetVideoDIDL(BaseItem dto, string streamUrl, IEnumerable<MediaStream> streams)
|
||||
{
|
||||
var videostream = streams.Where(stream => stream.Type == Model.Entities.MediaStreamType.Video).OrderBy(s => s.IsDefault).FirstOrDefault();
|
||||
var videostream = streams.Where(stream => stream.Type == MediaStreamType.Video).OrderBy(s => s.IsDefault ? 0 : 1).FirstOrDefault();
|
||||
|
||||
if (videostream == null)
|
||||
{
|
||||
@ -105,7 +110,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
private static string GetAudioDIDL(BaseItem dto, string streamUrl, IEnumerable<MediaStream> streams)
|
||||
{
|
||||
var audiostream = streams.Where(stream => stream.Type == MediaStreamType.Audio).OrderBy(s => s.IsDefault).FirstOrDefault();
|
||||
var audiostream = streams.Where(stream => stream.Type == MediaStreamType.Audio).OrderBy(s => s.IsDefault ? 0 : 1).FirstOrDefault();
|
||||
|
||||
if (audiostream == null)
|
||||
{
|
||||
@ -118,14 +123,14 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
private static string GetImageUrl(BaseItem dto, string serverAddress)
|
||||
{
|
||||
var imageType = ImageType.Primary;
|
||||
const ImageType imageType = ImageType.Primary;
|
||||
|
||||
if (!dto.HasImage(ImageType.Primary))
|
||||
if (!dto.HasImage(imageType))
|
||||
{
|
||||
dto = dto.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary));
|
||||
dto = dto.Parents.FirstOrDefault(i => i.HasImage(imageType));
|
||||
}
|
||||
|
||||
return string.Format("{0}/Items/{1}/Images/{2}", serverAddress, dto.Id, imageType);
|
||||
return dto == null ? null : string.Format("{0}/Items/{1}/Images/{2}", serverAddress, dto.Id, imageType);
|
||||
}
|
||||
|
||||
private static string GetDurationString(BaseItem dto)
|
||||
@ -148,7 +153,5 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
return string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +140,15 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
_updateTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
//Session is inactive, mark it for Disposal and don't start the elapsed timer.
|
||||
await _sessionManager.ReportSessionEnded(_session.Id);
|
||||
try
|
||||
{
|
||||
// Session is inactive, mark it for Disposal and don't start the elapsed timer.
|
||||
await _sessionManager.ReportSessionEnded(_session.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error in ReportSessionEnded", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,7 +163,15 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
if (!_playbackStarted)
|
||||
{
|
||||
await _sessionManager.OnPlaybackStart(new PlaybackInfo { Item = _currentItem, SessionId = _session.Id, CanSeek = true, QueueableMediaTypes = new List<string> { "Audio", "Video" } }).ConfigureAwait(false);
|
||||
await _sessionManager.OnPlaybackStart(new PlaybackInfo
|
||||
{
|
||||
Item = _currentItem,
|
||||
SessionId = _session.Id,
|
||||
CanSeek = true,
|
||||
QueueableMediaTypes = new List<string> { "Audio", "Video" }
|
||||
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
_playbackStarted = true;
|
||||
}
|
||||
|
||||
@ -403,7 +418,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
var playlistItem = GetPlaylistItem(item, streams, profile);
|
||||
playlistItem.StartPositionTicks = startPostionTicks;
|
||||
playlistItem.DeviceProfileName = profile.Name;
|
||||
|
||||
if (playlistItem.MediaType == DlnaProfileType.Audio)
|
||||
{
|
||||
@ -414,8 +428,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress);
|
||||
}
|
||||
|
||||
var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
|
||||
playlistItem.Didl = didl;
|
||||
playlistItem.Didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
|
||||
|
||||
return playlistItem;
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
public class PlayToControllerFactory : ISessionControllerFactory
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly IItemRepository _itemRepository;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILogger _logger;
|
||||
private readonly INetworkManager _networkManager;
|
||||
|
||||
public PlayToControllerFactory(ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogManager logManager, INetworkManager networkManager)
|
||||
{
|
||||
_itemRepository = itemRepository;
|
||||
_sessionManager = sessionManager;
|
||||
_libraryManager = libraryManager;
|
||||
_networkManager = networkManager;
|
||||
_logger = logManager.GetLogger("PlayTo");
|
||||
}
|
||||
|
||||
public ISessionController GetSessionController(SessionInfo session)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,16 +5,17 @@ using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Dlna.Ssdp;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Session;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -126,10 +127,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
if (receivedBytes > 0)
|
||||
{
|
||||
var rawData = Encoding.UTF8.GetString(receiveBuffer, 0, receivedBytes);
|
||||
var uri = SsdpHelper.ParseSsdpResponse(rawData);
|
||||
var headers = SsdpHelper.ParseSsdpResponse(receiveBuffer);
|
||||
|
||||
TryCreateController(uri);
|
||||
TryCreateController(headers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,13 +146,20 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}, _tokenSource.Token, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
private void TryCreateController(Uri uri)
|
||||
private void TryCreateController(IDictionary<string,string> headers)
|
||||
{
|
||||
string location;
|
||||
|
||||
if (!headers.TryGetValue("Location", out location))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await CreateController(uri).ConfigureAwait(false);
|
||||
await CreateController(new Uri(location)).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@ -221,46 +228,25 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
if (device != null && device.RendererCommands != null && !_sessionManager.Sessions.Any(s => string.Equals(s.DeviceId, device.Properties.UUID) && s.IsActive))
|
||||
{
|
||||
GetProfileSettings(device.Properties);
|
||||
|
||||
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, device.Properties.Name, device.Properties.UUID, device.Properties.DisplayName, uri.OriginalString, null)
|
||||
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
_sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities
|
||||
{
|
||||
PlayableMediaTypes = new[] { MediaType.Audio, MediaType.Video, MediaType.Photo },
|
||||
SupportsFullscreenToggle = false
|
||||
});
|
||||
|
||||
var controller = sessionInfo.SessionController as PlayToController;
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
sessionInfo.SessionController = controller = new PlayToController(sessionInfo, _sessionManager, _itemRepository, _libraryManager, _logger, _networkManager, _dlnaManager, _userManager, _appHost);
|
||||
|
||||
controller.Init(device);
|
||||
|
||||
_sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities
|
||||
{
|
||||
PlayableMediaTypes = new[] { MediaType.Audio, MediaType.Video, MediaType.Photo },
|
||||
SupportsFullscreenToggle = false
|
||||
});
|
||||
|
||||
_logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
|
||||
}
|
||||
|
||||
controller.Init(device);
|
||||
|
||||
_logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the profile settings.
|
||||
/// </summary>
|
||||
/// <param name="deviceProperties">The device properties.</param>
|
||||
/// <returns>The TranscodeSettings for the device</returns>
|
||||
private void GetProfileSettings(DeviceInfo deviceProperties)
|
||||
{
|
||||
var profile = _dlnaManager.GetProfile(deviceProperties.ToDeviceIdentification());
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(profile.Name))
|
||||
{
|
||||
deviceProperties.DisplayName = profile.Name;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(profile.ClientType))
|
||||
{
|
||||
deviceProperties.ClientType = profile.ClientType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
public int? SubtitleStreamIndex { get; set; }
|
||||
|
||||
public string DeviceProfileName { get; set; }
|
||||
|
||||
public int? MaxAudioChannels { get; set; }
|
||||
|
||||
public int? AudioBitrate { get; set; }
|
||||
|
@ -162,7 +162,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
|
||||
private void ApplyTranscodingConditions(PlaylistItem item, IEnumerable<ProfileCondition> conditions)
|
||||
{
|
||||
foreach (var condition in conditions.Where(i => !string.IsNullOrEmpty(i.Value)))
|
||||
foreach (var condition in conditions
|
||||
.Where(i => !string.IsNullOrEmpty(i.Value)))
|
||||
{
|
||||
var value = condition.Value;
|
||||
|
||||
@ -170,7 +171,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
case ProfileConditionValue.AudioBitrate:
|
||||
{
|
||||
var num = 0;
|
||||
int num;
|
||||
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
|
||||
{
|
||||
item.AudioBitrate = num;
|
||||
@ -179,7 +180,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
case ProfileConditionValue.AudioChannels:
|
||||
{
|
||||
var num = 0;
|
||||
int num;
|
||||
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
|
||||
{
|
||||
item.MaxAudioChannels = num;
|
||||
@ -199,7 +200,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
case ProfileConditionValue.Height:
|
||||
{
|
||||
var num = 0;
|
||||
int num;
|
||||
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
|
||||
{
|
||||
item.MaxHeight = num;
|
||||
@ -208,7 +209,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
case ProfileConditionValue.VideoBitrate:
|
||||
{
|
||||
var num = 0;
|
||||
int num;
|
||||
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
|
||||
{
|
||||
item.VideoBitrate = num;
|
||||
@ -217,7 +218,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
case ProfileConditionValue.VideoFramerate:
|
||||
{
|
||||
var num = 0;
|
||||
int num;
|
||||
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
|
||||
{
|
||||
item.MaxFramerate = num;
|
||||
@ -226,7 +227,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
case ProfileConditionValue.VideoLevel:
|
||||
{
|
||||
var num = 0;
|
||||
int num;
|
||||
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
|
||||
{
|
||||
item.VideoLevel = num;
|
||||
@ -235,7 +236,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
case ProfileConditionValue.Width:
|
||||
{
|
||||
var num = 0;
|
||||
int num;
|
||||
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
|
||||
{
|
||||
item.MaxWidth = num;
|
||||
|
@ -2,7 +2,6 @@
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
@ -14,8 +13,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
|
||||
private const string FriendlyName = "MediaBrowser";
|
||||
|
||||
private static readonly CookieContainer Container = new CookieContainer();
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
@ -31,7 +28,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
if (!serviceUrl.StartsWith("/"))
|
||||
serviceUrl = "/" + serviceUrl;
|
||||
|
||||
var response = await PostSoapDataAsync(new Uri(baseUrl + serviceUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header)
|
||||
var response = await PostSoapDataAsync(baseUrl + serviceUrl, "\"" + service.ServiceType + "#" + command + "\"", postData, header)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
using (var stream = response.Content)
|
||||
@ -43,11 +40,11 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SubscribeAsync(Uri url, string ip, int port, string localIp, int eventport, int timeOut = 3600)
|
||||
public async Task SubscribeAsync(string url, string ip, int port, string localIp, int eventport, int timeOut = 3600)
|
||||
{
|
||||
var options = new HttpRequestOptions
|
||||
{
|
||||
Url = url.ToString(),
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
|
||||
};
|
||||
@ -56,7 +53,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport + ">";
|
||||
options.RequestHeaders["NT"] = "upnp:event";
|
||||
options.RequestHeaders["TIMEOUT"] = "Second - " + timeOut;
|
||||
//request.CookieContainer = Container;
|
||||
|
||||
using (await _httpClient.Get(options).ConfigureAwait(false))
|
||||
{
|
||||
@ -75,24 +71,22 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport + ">";
|
||||
options.RequestHeaders["NT"] = "upnp:event";
|
||||
options.RequestHeaders["TIMEOUT"] = "Second - 3600";
|
||||
//request.CookieContainer = Container;
|
||||
|
||||
using (await _httpClient.Get(options).ConfigureAwait(false))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<XDocument> GetDataAsync(Uri url)
|
||||
public async Task<XDocument> GetDataAsync(string url)
|
||||
{
|
||||
var options = new HttpRequestOptions
|
||||
{
|
||||
Url = url.ToString(),
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
|
||||
};
|
||||
|
||||
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
|
||||
//request.CookieContainer = Container;
|
||||
|
||||
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
|
||||
{
|
||||
@ -103,14 +97,14 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
}
|
||||
}
|
||||
|
||||
private Task<HttpResponseInfo> PostSoapDataAsync(Uri url, string soapAction, string postData, string header = null, int timeOut = 20000)
|
||||
private Task<HttpResponseInfo> PostSoapDataAsync(string url, string soapAction, string postData, string header = null)
|
||||
{
|
||||
if (!soapAction.StartsWith("\""))
|
||||
soapAction = "\"" + soapAction + "\"";
|
||||
|
||||
var options = new HttpRequestOptions
|
||||
{
|
||||
Url = url.ToString(),
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
|
||||
};
|
||||
|
@ -43,15 +43,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
/// </summary>
|
||||
private static string BuildDlnaUrl(DeviceInfo deviceProperties, PlaylistItem item)
|
||||
{
|
||||
var profile = item.TranscodingSettings.Where(i => i.Name == TranscodingSettingType.VideoProfile)
|
||||
.Select(i => i.Value)
|
||||
.FirstOrDefault();
|
||||
|
||||
var usCulture = new CultureInfo("en-US");
|
||||
|
||||
var list = new List<string>
|
||||
{
|
||||
item.DeviceProfileName ?? string.Empty,
|
||||
deviceProperties.UUID ?? string.Empty,
|
||||
item.MediaSourceId ?? string.Empty,
|
||||
(!item.Transcode).ToString().ToLower(),
|
||||
@ -66,7 +61,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
item.MaxWidth.HasValue ? item.MaxWidth.Value.ToString(usCulture) : string.Empty,
|
||||
item.MaxHeight.HasValue ? item.MaxHeight.Value.ToString(usCulture) : string.Empty,
|
||||
item.StartPositionTicks.ToString(usCulture),
|
||||
profile ?? string.Empty,
|
||||
item.VideoLevel.HasValue ? item.VideoLevel.Value.ToString(usCulture) : string.Empty
|
||||
};
|
||||
|
||||
|
@ -6,9 +6,10 @@ namespace MediaBrowser.Dlna.Profiles
|
||||
{
|
||||
public DefaultProfile()
|
||||
{
|
||||
Name = "Generic Device";
|
||||
|
||||
ProtocolInfo = "DLNA";
|
||||
|
||||
ClientType = "DLNA";
|
||||
Manufacturer = "Media Browser";
|
||||
ModelDescription = "Media Browser";
|
||||
ModelName = "Media Browser";
|
||||
|
27
MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs
Normal file
27
MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
|
||||
namespace MediaBrowser.Dlna.Profiles
|
||||
{
|
||||
public class Foobar2000Profile : DefaultProfile
|
||||
{
|
||||
public Foobar2000Profile()
|
||||
{
|
||||
Name = "foobar2000";
|
||||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
FriendlyName = @"foobar",
|
||||
|
||||
Headers = new[]
|
||||
{
|
||||
new HttpHeaderInfo
|
||||
{
|
||||
Name = "User-Agent",
|
||||
Value = "foobar",
|
||||
Match = HeaderMatchType.Substring
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -302,6 +302,13 @@ namespace MediaBrowser.Dlna.Profiles
|
||||
|
||||
MediaProfiles = new[]
|
||||
{
|
||||
new MediaProfile
|
||||
{
|
||||
Container = "avi",
|
||||
MimeType = "video/x-msvideo",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
|
||||
new MediaProfile
|
||||
{
|
||||
Container = "mkv",
|
||||
|
@ -6,6 +6,8 @@ namespace MediaBrowser.Dlna.Profiles
|
||||
{
|
||||
public SonyBlurayPlayer2013Profile()
|
||||
{
|
||||
Name = "Sony Blu-ray Player 2013";
|
||||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
FriendlyName = @"Blu-ray Disc Player",
|
||||
|
@ -6,6 +6,8 @@ namespace MediaBrowser.Dlna.Profiles
|
||||
{
|
||||
public SonyBlurayPlayerProfile()
|
||||
{
|
||||
Name = "Sony Blu-ray Player";
|
||||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
FriendlyName = @"Blu-ray Disc Player",
|
||||
|
@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.Server
|
||||
private readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
|
||||
private readonly static Regex Validator = new Regex(@"^[a-z\d][a-z\d_.-]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
protected Headers(bool asIs)
|
||||
public Headers(bool asIs)
|
||||
{
|
||||
_asIs = asIs;
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Dlna.Server
|
||||
{
|
||||
public class RawHeaders : Headers
|
||||
{
|
||||
public RawHeaders()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -96,7 +96,7 @@ namespace MediaBrowser.Dlna.Server
|
||||
{
|
||||
break;
|
||||
}
|
||||
var parts = line.Split(new char[] { ':' }, 2);
|
||||
var parts = line.Split(new[] { ':' }, 2);
|
||||
headers[parts[0]] = parts[1].Trim();
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ namespace MediaBrowser.Dlna.Server
|
||||
|
||||
private void SendSearchResponse(IPEndPoint endpoint, UpnpDevice dev)
|
||||
{
|
||||
var headers = new RawHeaders();
|
||||
var headers = new Headers(true);
|
||||
headers.Add("CACHE-CONTROL", "max-age = 600");
|
||||
headers.Add("DATE", DateTime.Now.ToString("R"));
|
||||
headers.Add("EXT", "");
|
||||
@ -188,7 +188,7 @@ namespace MediaBrowser.Dlna.Server
|
||||
private void NotifyDevice(UpnpDevice dev, string type, bool sticky)
|
||||
{
|
||||
_logger.Debug("NotifyDevice");
|
||||
var headers = new RawHeaders();
|
||||
var headers = new Headers(true);
|
||||
headers.Add("HOST", "239.255.255.250:1900");
|
||||
headers.Add("CACHE-CONTROL", "max-age = 600");
|
||||
headers.Add("LOCATION", dev.Descriptor.ToString());
|
||||
|
@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Dlna.PlayTo
|
||||
namespace MediaBrowser.Dlna.Ssdp
|
||||
{
|
||||
public class SsdpHelper
|
||||
{
|
||||
@ -29,28 +30,29 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns></returns>
|
||||
public static Uri ParseSsdpResponse(string data)
|
||||
public static Dictionary<string,string> ParseSsdpResponse(byte[] data)
|
||||
{
|
||||
var res = (from line in data.Split(new[] { '\r', '\n' })
|
||||
where line.ToLowerInvariant().StartsWith("location:")
|
||||
select line).FirstOrDefault();
|
||||
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return !string.IsNullOrEmpty(res) ? new Uri(res.Substring(9).Trim()) : null;
|
||||
}
|
||||
using (var reader = new StreamReader(new MemoryStream(data), Encoding.ASCII))
|
||||
{
|
||||
for (var line = reader.ReadLine(); line != null; line = reader.ReadLine())
|
||||
{
|
||||
line = line.Trim();
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
break;
|
||||
}
|
||||
var parts = line.Split(new[] { ':' }, 2);
|
||||
|
||||
/// <summary>
|
||||
/// Parses data into SSDP event.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Not yet used", true)]
|
||||
public static string ParseSsdpEvent(string data)
|
||||
{
|
||||
var sid = (from line in data.Split(new[] { '\r', '\n' })
|
||||
where line.ToLowerInvariant().StartsWith("sid:")
|
||||
select line).FirstOrDefault();
|
||||
|
||||
return data;
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
headers[parts[0]] = parts[1].Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@ -75,16 +74,6 @@ namespace MediaBrowser.Providers.Savers
|
||||
|
||||
XmlSaverHelpers.AddCommonNodes(video, builder);
|
||||
|
||||
if (video.CommunityRating.HasValue)
|
||||
{
|
||||
builder.Append("<IMDBrating>" + SecurityElement.Escape(video.CommunityRating.Value.ToString(UsCulture)) + "</IMDBrating>");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(video.Overview))
|
||||
{
|
||||
builder.Append("<Description><![CDATA[" + video.Overview + "]]></Description>");
|
||||
}
|
||||
|
||||
var musicVideo = item as MusicVideo;
|
||||
|
||||
if (musicVideo != null)
|
||||
@ -117,8 +106,12 @@ namespace MediaBrowser.Providers.Savers
|
||||
|
||||
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
|
||||
{
|
||||
// Deprecated. No longer saving in this field.
|
||||
"IMDBrating",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"Description",
|
||||
|
||||
"Artist",
|
||||
"Album",
|
||||
"TmdbCollectionName"
|
||||
|
@ -60,11 +60,6 @@ namespace MediaBrowser.Providers.Savers
|
||||
builder.Append("<id>" + SecurityElement.Escape(tvdb) + "</id>");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(item.Name))
|
||||
{
|
||||
builder.Append("<SeriesName>" + SecurityElement.Escape(item.Name) + "</SeriesName>");
|
||||
}
|
||||
|
||||
if (series.Status.HasValue)
|
||||
{
|
||||
builder.Append("<Status>" + SecurityElement.Escape(series.Status.Value.ToString()) + "</Status>");
|
||||
@ -111,7 +106,6 @@ namespace MediaBrowser.Providers.Savers
|
||||
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
|
||||
{
|
||||
"id",
|
||||
"SeriesName",
|
||||
"Status",
|
||||
"Network",
|
||||
"Airs_Time",
|
||||
@ -120,6 +114,10 @@ namespace MediaBrowser.Providers.Savers
|
||||
|
||||
// Don't preserve old series node
|
||||
"Series",
|
||||
|
||||
"SeriesName",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"AnimeSeriesIndex"
|
||||
});
|
||||
}
|
||||
|
@ -28,7 +28,10 @@ namespace MediaBrowser.Providers.Savers
|
||||
"AwardSummary",
|
||||
"BirthDate",
|
||||
"Budget",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"certification",
|
||||
|
||||
"Chapters",
|
||||
"ContentRating",
|
||||
"CustomRating",
|
||||
@ -40,22 +43,31 @@ namespace MediaBrowser.Providers.Savers
|
||||
"Genres",
|
||||
"Genre",
|
||||
"GamesDbId",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"IMDB_ID",
|
||||
|
||||
"IMDB",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"IMDbId",
|
||||
|
||||
"Language",
|
||||
"LocalTitle",
|
||||
"LockData",
|
||||
"LockedFields",
|
||||
"Format3D",
|
||||
"Metascore",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"MPAARating",
|
||||
|
||||
"MusicBrainzArtistId",
|
||||
"MusicBrainzAlbumArtistId",
|
||||
"MusicBrainzAlbumId",
|
||||
"MusicBrainzReleaseGroupId",
|
||||
|
||||
// Old - not used anymore
|
||||
// Deprecated. No longer saving in this field.
|
||||
"MusicbrainzId",
|
||||
|
||||
"Overview",
|
||||
@ -67,15 +79,24 @@ namespace MediaBrowser.Providers.Savers
|
||||
"Revenue",
|
||||
"RottenTomatoesId",
|
||||
"RunningTime",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"Runtime",
|
||||
|
||||
"SortTitle",
|
||||
"Studios",
|
||||
"Tags",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"TagLine",
|
||||
|
||||
"Taglines",
|
||||
"TMDbCollectionId",
|
||||
"TMDbId",
|
||||
|
||||
// Deprecated. No longer saving in this field.
|
||||
"Trailer",
|
||||
|
||||
"Trailers",
|
||||
"TVcomId",
|
||||
"TvDbId",
|
||||
@ -207,8 +228,6 @@ namespace MediaBrowser.Providers.Savers
|
||||
if (!string.IsNullOrEmpty(item.OfficialRating))
|
||||
{
|
||||
builder.Append("<ContentRating>" + SecurityElement.Escape(item.OfficialRating) + "</ContentRating>");
|
||||
builder.Append("<MPAARating>" + SecurityElement.Escape(item.OfficialRating) + "</MPAARating>");
|
||||
builder.Append("<certification>" + SecurityElement.Escape(item.OfficialRating) + "</certification>");
|
||||
}
|
||||
|
||||
builder.Append("<Added>" + SecurityElement.Escape(item.DateCreated.ToLocalTime().ToString("G")) + "</Added>");
|
||||
@ -376,16 +395,13 @@ namespace MediaBrowser.Providers.Savers
|
||||
var timespan = TimeSpan.FromTicks(runTimeTicks.Value);
|
||||
|
||||
builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>");
|
||||
builder.Append("<Runtime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</Runtime>");
|
||||
}
|
||||
|
||||
var imdb = item.GetProviderId(MetadataProviders.Imdb);
|
||||
|
||||
if (!string.IsNullOrEmpty(imdb))
|
||||
{
|
||||
builder.Append("<IMDB_ID>" + SecurityElement.Escape(imdb) + "</IMDB_ID>");
|
||||
builder.Append("<IMDB>" + SecurityElement.Escape(imdb) + "</IMDB>");
|
||||
builder.Append("<IMDbId>" + SecurityElement.Escape(imdb) + "</IMDbId>");
|
||||
}
|
||||
|
||||
var tmdb = item.GetProviderId(MetadataProviders.Tmdb);
|
||||
|
@ -90,6 +90,8 @@ namespace MediaBrowser.Providers.TV
|
||||
break;
|
||||
}
|
||||
case "SeriesName":
|
||||
// TODO: Deprecate in mid-2014
|
||||
// No longer saving this tag but will still read it for a while
|
||||
item.Name = reader.ReadElementContentAsString();
|
||||
break;
|
||||
|
||||
|
@ -824,33 +824,34 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
|
||||
|
||||
// apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600.
|
||||
// This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar
|
||||
var vf = "crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,scale=600:600/dar";
|
||||
var vf = "scale=600:trunc(600/dar/2)*2";
|
||||
//crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,scale=600:(600/dar),thumbnail" -f image2
|
||||
|
||||
if (threedFormat.HasValue)
|
||||
{
|
||||
switch (threedFormat.Value)
|
||||
{
|
||||
case Video3DFormat.HalfSideBySide:
|
||||
vf = "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,scale=600:600/dar";
|
||||
vf = "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
|
||||
// hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to 600. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
|
||||
break;
|
||||
case Video3DFormat.FullSideBySide:
|
||||
vf = "crop=iw/2:ih:0:0,setdar=dar=a,,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,scale=600:600/dar";
|
||||
vf = "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
|
||||
//fsbs crop width in half,set the display aspect,crop out any black bars we may have made the scale width to 600.
|
||||
break;
|
||||
case Video3DFormat.HalfTopAndBottom:
|
||||
vf = "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,scale=600:600/dar";
|
||||
vf = "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
|
||||
//htab crop heigh in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to 600
|
||||
break;
|
||||
case Video3DFormat.FullTopAndBottom:
|
||||
vf = "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,scale=600:600/dar";
|
||||
vf = "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
|
||||
// ftab crop heigt in half, set the display aspect,crop out any black bars we may have made the scale width to 600
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
|
||||
var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"thumbnail,{2}\" -f image2 \"{1}\"", inputPath, "-", vf) :
|
||||
var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail\" -f image2 \"{1}\"", inputPath, "-", vf) :
|
||||
string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf);
|
||||
|
||||
var probeSize = GetProbeSizeArgument(type);
|
||||
|
Loading…
Reference in New Issue
Block a user