mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-15 09:59:06 -07:00
implement dlna headers
This commit is contained in:
parent
1644d45dac
commit
f245fffad1
@ -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;
|
||||
|
||||
|
@ -851,7 +851,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
|
||||
}
|
||||
|
||||
// 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 \"{2},thumbnail=20\" -f image2 \"{1}\"", inputPath, "-", vf) :
|
||||
var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"thumbnail,{2}\" -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