commit
d61258f290
|
@ -1453,7 +1453,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
// Make sure we don't request a bitrate higher than the source
|
// Make sure we don't request a bitrate higher than the source
|
||||||
var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value;
|
var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value;
|
||||||
|
|
||||||
return request.AudioBitRate.Value;
|
// Don't encode any higher than this
|
||||||
|
return Math.Min(384000, request.AudioBitRate.Value);
|
||||||
//return Math.Min(currentBitrate, request.AudioBitRate.Value);
|
//return Math.Min(currentBitrate, request.AudioBitRate.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
args += GetGraphicalSubtitleParam(state, codec);
|
args += GetGraphicalSubtitleParam(state, codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args += " -flags -global_header";
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
using MediaBrowser.Model.LiveTv;
|
using MediaBrowser.Model.LiveTv;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.LiveTv
|
namespace MediaBrowser.Controller.LiveTv
|
||||||
{
|
{
|
||||||
public class TimerInfo
|
public class TimerInfo
|
||||||
{
|
{
|
||||||
|
public TimerInfo()
|
||||||
|
{
|
||||||
|
Genres = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id of the recording.
|
/// Id of the recording.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -15,7 +21,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The series timer identifier.</value>
|
/// <value>The series timer identifier.</value>
|
||||||
public string SeriesTimerId { get; set; }
|
public string SeriesTimerId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ChannelId of the recording.
|
/// ChannelId of the recording.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -26,7 +32,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The program identifier.</value>
|
/// <value>The program identifier.</value>
|
||||||
public string ProgramId { get; set; }
|
public string ProgramId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name of the recording.
|
/// Name of the recording.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -76,7 +82,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
|
||||||
public bool IsPostPaddingRequired { get; set; }
|
public bool IsPostPaddingRequired { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the priority.
|
/// Gets or sets the priority.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -98,5 +104,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
public string EpisodeTitle { get; set; }
|
public string EpisodeTitle { get; set; }
|
||||||
public DateTime? OriginalAirDate { get; set; }
|
public DateTime? OriginalAirDate { get; set; }
|
||||||
public bool IsProgramSeries { get; set; }
|
public bool IsProgramSeries { get; set; }
|
||||||
|
public string HomePageUrl { get; set; }
|
||||||
|
public float? CommunityRating { get; set; }
|
||||||
|
public string ShortOverview { get; set; }
|
||||||
|
public string OfficialRating { get; set; }
|
||||||
|
public List<string> Genres { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -393,6 +393,20 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string NormalizeSubtitleCodec(string codec)
|
||||||
|
{
|
||||||
|
if ((codec ?? string.Empty).IndexOf("PGS", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
|
{
|
||||||
|
codec = "PGSSUB";
|
||||||
|
}
|
||||||
|
else if ((codec ?? string.Empty).IndexOf("DVD", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
|
{
|
||||||
|
codec = "DVDSUB";
|
||||||
|
}
|
||||||
|
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts ffprobe stream info to our MediaStream class
|
/// Converts ffprobe stream info to our MediaStream class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -474,6 +488,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
stream.Type = MediaStreamType.Subtitle;
|
stream.Type = MediaStreamType.Subtitle;
|
||||||
|
stream.Codec = NormalizeSubtitleCodec(stream.Codec);
|
||||||
}
|
}
|
||||||
else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
|
|
@ -609,26 +609,13 @@ namespace MediaBrowser.Model.Dlna
|
||||||
defaultBitrate = StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3") ? 192000 : 128000;
|
defaultBitrate = StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3") ? 192000 : 128000;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetAudioChannels.HasValue)
|
if (StringHelper.EqualsIgnoreCase(subProtocol, "hls"))
|
||||||
{
|
{
|
||||||
if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 1200000)
|
defaultBitrate = Math.Min(384000, defaultBitrate);
|
||||||
{
|
}
|
||||||
if (StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3"))
|
else
|
||||||
{
|
{
|
||||||
if (StringHelper.EqualsIgnoreCase(subProtocol, "hls"))
|
defaultBitrate = Math.Min(448000, defaultBitrate);
|
||||||
{
|
|
||||||
defaultBitrate = Math.Max(384000, defaultBitrate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
defaultBitrate = Math.Max(448000, defaultBitrate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
defaultBitrate = Math.Max(320000, defaultBitrate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int encoderAudioBitrateLimit = int.MaxValue;
|
int encoderAudioBitrateLimit = int.MaxValue;
|
||||||
|
@ -647,6 +634,14 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maxTotalBitrate.HasValue)
|
||||||
|
{
|
||||||
|
if (maxTotalBitrate.Value < 640000)
|
||||||
|
{
|
||||||
|
defaultBitrate = Math.Min(128000, defaultBitrate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Server.Implementations.ScheduledTasks;
|
using MediaBrowser.Server.Implementations.ScheduledTasks;
|
||||||
|
using MoreLinq;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.IO
|
namespace MediaBrowser.Server.Implementations.IO
|
||||||
{
|
{
|
||||||
|
@ -136,9 +137,10 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
private async Task ProcessPathChanges(List<string> paths)
|
private async Task ProcessPathChanges(List<string> paths)
|
||||||
{
|
{
|
||||||
var itemsToRefresh = paths
|
var itemsToRefresh = paths
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(GetAffectedBaseItem)
|
.Select(GetAffectedBaseItem)
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.Distinct()
|
.DistinctBy(i => i.Id)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach (var p in paths)
|
foreach (var p in paths)
|
||||||
|
|
|
@ -404,7 +404,20 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
{
|
{
|
||||||
Logger.Debug("Changed detected of type " + e.ChangeType + " to " + e.FullPath);
|
Logger.Debug("Changed detected of type " + e.ChangeType + " to " + e.FullPath);
|
||||||
|
|
||||||
ReportFileSystemChanged(e.FullPath);
|
var path = e.FullPath;
|
||||||
|
|
||||||
|
// For deletes, use the parent path
|
||||||
|
if (e.ChangeType == WatcherChangeTypes.Deleted)
|
||||||
|
{
|
||||||
|
var parentPath = Path.GetDirectoryName(path);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(parentPath))
|
||||||
|
{
|
||||||
|
path = parentPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportFileSystemChanged(path);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -89,7 +89,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IgnoreFiles.Any(i => filename.IndexOf("-" + i, StringComparison.OrdinalIgnoreCase) != -1))
|
if (IgnoreFiles.Any(i => filename.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using CommonIO;
|
using CommonIO;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
|
@ -1026,6 +1027,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
result.Item3.Release();
|
result.Item3.Release();
|
||||||
isResourceOpen = false;
|
isResourceOpen = false;
|
||||||
|
|
||||||
|
SaveNfo(timer, recordPath, seriesPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
var pathWithDuration = result.Item2.ApplyDuration(mediaStreamInfo.Path, duration);
|
var pathWithDuration = result.Item2.ApplyDuration(mediaStreamInfo.Path, duration);
|
||||||
|
@ -1071,7 +1074,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
timer.Status = RecordingStatus.Completed;
|
timer.Status = RecordingStatus.Completed;
|
||||||
_timerProvider.Delete(timer);
|
_timerProvider.Delete(timer);
|
||||||
|
|
||||||
OnSuccessfulRecording(timer, recordPath, seriesPath);
|
OnSuccessfulRecording(timer, recordPath);
|
||||||
}
|
}
|
||||||
else if (DateTime.UtcNow < timer.EndDate)
|
else if (DateTime.UtcNow < timer.EndDate)
|
||||||
{
|
{
|
||||||
|
@ -1139,7 +1142,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
return new DirectRecorder(_logger, _httpClient, _fileSystem);
|
return new DirectRecorder(_logger, _httpClient, _fileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnSuccessfulRecording(TimerInfo timer, string path, string seriesPath)
|
private async void OnSuccessfulRecording(TimerInfo timer, string path)
|
||||||
{
|
{
|
||||||
if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize)
|
if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize)
|
||||||
{
|
{
|
||||||
|
@ -1163,15 +1166,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
_logger.ErrorException("Error processing new recording", ex);
|
_logger.ErrorException("Error processing new recording", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveNfo(timer, path, seriesPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveNfo(TimerInfo timer, string recordingPath, string seriesPath)
|
private void SaveNfo(TimerInfo timer, string recordingPath, string seriesPath)
|
||||||
{
|
{
|
||||||
if (timer.IsProgramSeries)
|
try
|
||||||
{
|
{
|
||||||
SaveSeriesNfo(timer, recordingPath, seriesPath);
|
if (timer.IsProgramSeries)
|
||||||
|
{
|
||||||
|
SaveSeriesNfo(timer, recordingPath, seriesPath);
|
||||||
|
}
|
||||||
|
else if (!timer.IsMovie || timer.IsSports)
|
||||||
|
{
|
||||||
|
SaveVideoNfo(timer, recordingPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error saving nfo", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1209,6 +1221,79 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
private void SaveVideoNfo(TimerInfo timer, string recordingPath)
|
||||||
|
{
|
||||||
|
var nfoPath = Path.ChangeExtension(recordingPath, ".nfo");
|
||||||
|
|
||||||
|
if (File.Exists(nfoPath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var stream = _fileSystem.GetFileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||||
|
{
|
||||||
|
var settings = new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Indent = true,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
CloseOutput = false
|
||||||
|
};
|
||||||
|
|
||||||
|
using (XmlWriter writer = XmlWriter.Create(stream, settings))
|
||||||
|
{
|
||||||
|
writer.WriteStartDocument(true);
|
||||||
|
writer.WriteStartElement("movie");
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(timer.Name))
|
||||||
|
{
|
||||||
|
writer.WriteElementString("title", timer.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteElementString("dateadded", DateTime.UtcNow.ToLocalTime().ToString(DateAddedFormat));
|
||||||
|
|
||||||
|
if (timer.ProductionYear.HasValue)
|
||||||
|
{
|
||||||
|
writer.WriteElementString("year", timer.ProductionYear.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(timer.OfficialRating))
|
||||||
|
{
|
||||||
|
writer.WriteElementString("mpaa", timer.OfficialRating);
|
||||||
|
}
|
||||||
|
|
||||||
|
var overview = (timer.Overview ?? string.Empty)
|
||||||
|
.StripHtml()
|
||||||
|
.Replace(""", "'");
|
||||||
|
|
||||||
|
writer.WriteElementString("plot", overview);
|
||||||
|
writer.WriteElementString("lockdata", true.ToString().ToLower());
|
||||||
|
|
||||||
|
if (timer.CommunityRating.HasValue)
|
||||||
|
{
|
||||||
|
writer.WriteElementString("rating", timer.CommunityRating.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var genre in timer.Genres)
|
||||||
|
{
|
||||||
|
writer.WriteElementString("genre", genre);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(timer.ShortOverview))
|
||||||
|
{
|
||||||
|
writer.WriteElementString("outline", timer.ShortOverview);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(timer.HomePageUrl))
|
||||||
|
{
|
||||||
|
writer.WriteElementString("website", timer.HomePageUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndElement();
|
||||||
|
writer.WriteEndDocument();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ProgramInfo GetProgramInfoFromCache(string channelId, string programId)
|
private ProgramInfo GetProgramInfoFromCache(string channelId, string programId)
|
||||||
{
|
{
|
||||||
var epgData = GetEpgDataForChannel(channelId);
|
var epgData = GetEpgDataForChannel(channelId);
|
||||||
|
|
|
@ -46,6 +46,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
timerInfo.EpisodeTitle = programInfo.EpisodeTitle;
|
timerInfo.EpisodeTitle = programInfo.EpisodeTitle;
|
||||||
timerInfo.OriginalAirDate = programInfo.OriginalAirDate;
|
timerInfo.OriginalAirDate = programInfo.OriginalAirDate;
|
||||||
timerInfo.IsProgramSeries = programInfo.IsSeries;
|
timerInfo.IsProgramSeries = programInfo.IsSeries;
|
||||||
|
|
||||||
|
timerInfo.HomePageUrl = programInfo.HomePageUrl;
|
||||||
|
timerInfo.CommunityRating = programInfo.CommunityRating;
|
||||||
|
timerInfo.ShortOverview = programInfo.ShortOverview;
|
||||||
|
timerInfo.OfficialRating = programInfo.OfficialRating;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetRecordingName(TimerInfo info)
|
public static string GetRecordingName(TimerInfo info)
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
||||||
var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
|
var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
|
||||||
data = data.OrderByDescending(GetSizeOrder).ToList();
|
data = data.OrderByDescending(GetSizeOrder).ToList();
|
||||||
|
|
||||||
programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 1280);
|
programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 800);
|
||||||
//programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
|
//programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
|
||||||
//programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
|
//programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
|
||||||
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
|
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
|
||||||
|
@ -536,7 +536,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}) ?? matches.FirstOrDefault();
|
});
|
||||||
|
|
||||||
|
if (match == null)
|
||||||
|
{
|
||||||
|
// Get the second lowest quality image, when possible
|
||||||
|
if (matches.Count > 1)
|
||||||
|
{
|
||||||
|
match = matches[matches.Count - 2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match = matches.FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (match == null)
|
if (match == null)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user