diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index b950625673..e588068d0d 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -187,7 +187,7 @@ namespace MediaBrowser.Api.Playback
if (!state.HasMediaStreams)
{
- return state.IsInputVideo ? "-map -0:s" : string.Empty;
+ return state.IsInputVideo ? "-sn" : string.Empty;
}
if (state.VideoStream != null)
@@ -1493,7 +1493,7 @@ namespace MediaBrowser.Api.Playback
if (videoRequest != null)
{
- if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream, state.VideoType))
+ if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
{
videoRequest.VideoCodec = "copy";
}
@@ -1507,19 +1507,13 @@ namespace MediaBrowser.Api.Playback
return state;
}
- private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream, VideoType videoType)
+ private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
{
if (videoStream.IsInterlaced)
{
return false;
}
- // Not going to attempt this with folder rips
- if (videoType != VideoType.VideoFile)
- {
- return false;
- }
-
// Source and target codecs must match
if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase))
{
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 6e71e503f3..b5cd1bd409 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -24,7 +24,8 @@ namespace MediaBrowser.Api.Playback.Hls
///
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, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
+ 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)
{
}
@@ -77,6 +78,7 @@ namespace MediaBrowser.Api.Playback.Hls
return ProcessRequestAsync(request).Result;
}
+ private static readonly SemaphoreSlim FfmpegStartLock = new SemaphoreSlim(1, 1);
///
/// Processes the request async.
///
@@ -103,31 +105,40 @@ namespace MediaBrowser.Api.Playback.Hls
}
var playlist = GetOutputFilePath(state);
- var isPlaylistNewlyCreated = false;
- // If the playlist doesn't already exist, startup ffmpeg
- if (!File.Exists(playlist))
- {
- isPlaylistNewlyCreated = true;
-
- try
- {
- await StartFfMpeg(state, playlist).ConfigureAwait(false);
- }
- catch
- {
- state.Dispose();
- throw;
- }
- }
- else
+ if (File.Exists(playlist))
{
ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
}
-
- if (isPlaylistNewlyCreated)
+ else
{
- await WaitForMinimumSegmentCount(playlist, GetSegmentWait()).ConfigureAwait(false);
+ await FfmpegStartLock.WaitAsync().ConfigureAwait(false);
+ try
+ {
+ if (File.Exists(playlist))
+ {
+ ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
+ }
+ else
+ {
+ // If the playlist doesn't already exist, startup ffmpeg
+ try
+ {
+ await StartFfMpeg(state, playlist).ConfigureAwait(false);
+ }
+ catch
+ {
+ state.Dispose();
+ throw;
+ }
+ }
+
+ await WaitForMinimumSegmentCount(playlist, GetSegmentWait()).ConfigureAwait(false);
+ }
+ finally
+ {
+ FfmpegStartLock.Release();
+ }
}
int audioBitrate;
@@ -295,7 +306,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If performSubtitleConversions is true we're actually starting ffmpeg
var startNumberParam = performSubtitleConversions ? GetStartNumber(state).ToString(UsCulture) : "0";
-
+
var args = string.Format("{0} {1} -i {2}{3} -map_metadata -1 -threads {4} {5} {6} -sc_threshold 0 {7} -hls_time {8} -start_number {9} -hls_list_size {10} \"{11}\"",
itsOffset,
inputModifier,
diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs
index 2d0b3955bd..fc62f9780a 100644
--- a/MediaBrowser.Dlna/PlayTo/Device.cs
+++ b/MediaBrowser.Dlna/PlayTo/Device.cs
@@ -210,6 +210,9 @@ namespace MediaBrowser.Dlna.PlayTo
return SetVolume(tmp);
}
+ ///
+ /// Sets volume on a scale of 0-100
+ ///
public async Task SetVolume(int value)
{
var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume");
diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
index 96c92b830b..830d478297 100644
--- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs
+++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using System.Globalization;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Entities;
@@ -206,7 +207,8 @@ namespace MediaBrowser.Dlna.PlayTo
IsPaused = _device.IsPaused,
MediaSourceId = playlistItem.MediaSourceId,
AudioStreamIndex = playlistItem.AudioStreamIndex,
- SubtitleStreamIndex = playlistItem.SubtitleStreamIndex
+ SubtitleStreamIndex = playlistItem.SubtitleStreamIndex,
+ VolumeLevel = _device.Volume
}).ConfigureAwait(false);
}
@@ -614,6 +616,8 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
{
GeneralCommandType commandType;
@@ -632,6 +636,24 @@ namespace MediaBrowser.Dlna.PlayTo
return _device.VolumeUp(true);
case GeneralCommandType.ToggleMute:
return _device.ToggleMute();
+ case GeneralCommandType.SetVolume:
+ {
+ string volumeArg;
+
+ if (command.Arguments.TryGetValue("Volume", out volumeArg))
+ {
+ int volume;
+
+ if (int.TryParse(volumeArg, NumberStyles.Any, _usCulture, out volume))
+ {
+ return _device.SetVolume(volume);
+ }
+
+ throw new ArgumentException("Unsupported volume value supplied.");
+ }
+
+ throw new ArgumentException("Volume argument cannot be null");
+ }
default:
return Task.FromResult(true);
}
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index 1730245be7..5cc3f13e54 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -265,7 +265,8 @@ namespace MediaBrowser.Dlna.PlayTo
GeneralCommandType.VolumeUp.ToString(),
GeneralCommandType.Mute.ToString(),
GeneralCommandType.Unmute.ToString(),
- GeneralCommandType.ToggleMute.ToString()
+ GeneralCommandType.ToggleMute.ToString(),
+ GeneralCommandType.SetVolume.ToString()
}
});
diff --git a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
index 2e8d9044d3..2c0b3a2c94 100644
--- a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
@@ -57,8 +57,17 @@ namespace MediaBrowser.Dlna.Server
{
builder.Append("" + SecurityElement.Escape(_serverUdn) + "");
builder.Append("" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "");
- builder.Append("M-DMS-1.50");
- builder.Append("" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + "");
+
+ if (!string.IsNullOrWhiteSpace(_profile.XDlnaDoc))
+ {
+ builder.Append("" +
+ SecurityElement.Escape(_profile.XDlnaDoc) + "");
+ }
+ else
+ {
+ builder.Append("DMS-1.50");
+ }
+
builder.Append("" + SecurityElement.Escape(_profile.FriendlyName ?? string.Empty) + "");
builder.Append("urn:schemas-upnp-org:device:MediaServer:1");
builder.Append("" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "");
@@ -99,7 +108,7 @@ namespace MediaBrowser.Dlna.Server
foreach (var service in GetServices())
{
- builder.Append("");
+ builder.Append("");
builder.Append("" + SecurityElement.Escape(service.ServiceType ?? string.Empty) + "");
builder.Append("" + SecurityElement.Escape(service.ServiceId ?? string.Empty) + "");
@@ -107,7 +116,7 @@ namespace MediaBrowser.Dlna.Server
builder.Append("" + SecurityElement.Escape(service.ControlUrl ?? string.Empty) + "");
builder.Append("" + SecurityElement.Escape(service.EventSubUrl ?? string.Empty) + "");
- builder.Append("");
+ builder.Append("");
}
builder.Append("");
diff --git a/MediaBrowser.Dlna/Server/SsdpHandler.cs b/MediaBrowser.Dlna/Server/SsdpHandler.cs
index 10f0101efa..c908eb4a8e 100644
--- a/MediaBrowser.Dlna/Server/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Server/SsdpHandler.cs
@@ -147,7 +147,7 @@ namespace MediaBrowser.Dlna.Server
foreach (var d in Devices)
{
- if (!string.IsNullOrEmpty(req) && req != d.Type)
+ if (!string.IsNullOrEmpty(req) && !string.Equals(req, d.Type, StringComparison.OrdinalIgnoreCase))
{
continue;
}
@@ -263,13 +263,19 @@ namespace MediaBrowser.Dlna.Server
}
}
- foreach (var t in new[] { "upnp:rootdevice", "urn:schemas-upnp-org:device:MediaServer:1", "urn:schemas-upnp-org:service:ContentDirectory:1", "uuid:" + uuid })
+ foreach (var t in new[]
+ {
+ "upnp:rootdevice",
+ "urn:schemas-upnp-org:device:MediaServer:1",
+ "urn:schemas-upnp-org:service:ContentDirectory:1",
+ "uuid:" + uuid
+ })
{
list.Add(new UpnpDevice(uuid, t, descriptor, address));
}
NotifyAll();
- _logger.Debug("Registered mount {0}", uuid);
+ _logger.Debug("Registered mount {0} at {1}", uuid, descriptor);
}
private void UnregisterNotification(Guid uuid)
diff --git a/MediaBrowser.Model/Dto/UserDto.cs b/MediaBrowser.Model/Dto/UserDto.cs
index dcf0843fec..efbd64343d 100644
--- a/MediaBrowser.Model/Dto/UserDto.cs
+++ b/MediaBrowser.Model/Dto/UserDto.cs
@@ -1,7 +1,7 @@
-using System.ComponentModel;
-using System.Diagnostics;
-using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Configuration;
using System;
+using System.ComponentModel;
+using System.Diagnostics;
using System.Runtime.Serialization;
namespace MediaBrowser.Model.Dto
diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs
index f235cebb30..df7bdd7ecb 100644
--- a/MediaBrowser.Model/Session/SessionInfoDto.cs
+++ b/MediaBrowser.Model/Session/SessionInfoDto.cs
@@ -51,6 +51,12 @@ namespace MediaBrowser.Model.Session
/// The user id.
public string UserId { get; set; }
+ ///
+ /// Gets or sets the user primary image tag.
+ ///
+ /// The user primary image tag.
+ public Guid? UserPrimaryImageTag { get; set; }
+
///
/// Gets or sets the name of the user.
///
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
index b92e823859..372e4addf4 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
@@ -34,7 +34,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
var collectionType = args.GetCollectionType();
- if (string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
+ var isStandalone = args.Parent == null;
+
+ if (isStandalone ||
+ string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
{
return new Controller.Entities.Audio.Audio();
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index fe120737f3..d16e0be991 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -450,5 +450,70 @@
"LabelMinResumeDuration": "Min resume duration (seconds):",
"LabelMinResumePercentageHelp": "Titles are assumed unplayed if stopped before this time",
"LabelMaxResumePercentageHelp": "Titles are assumed fully played if stopped after this time",
- "LabelMinResumeDurationHelp": "Titles shorter than this will not be resumable"
+ "LabelMinResumeDurationHelp": "Titles shorter than this will not be resumable",
+ "TitleAutoOrganize": "Auto-Organize",
+ "TabActivityLog": "Activity Log",
+ "HeaderName": "Name",
+ "HeaderDate": "Date",
+ "HeaderSource": "Source",
+ "HeaderStatus": "Status",
+ "HeaderDestination": "Destination",
+ "HeaderProgram": "Program",
+ "HeaderClients": "Clients",
+ "LabelCompleted": "Completed",
+ "LabelFailed": "Failed",
+ "LabelSkipped": "Skipped",
+ "HeaderEpisodeOrganization": "Episode Organization",
+ "LabelSeries": "Series:",
+ "LabelSeasonNumber": "Season number:",
+ "LabelEpisodeNumber": "Episode number:",
+ "LabelEndingEpisodeNumber": "Ending episode number:",
+ "LabelEndingEpisodeNumberHelp": "Only required for multi-episode files",
+ "HeaderSupportTheTeam": "Support the Media Browser Team",
+ "LabelSupportAmount": "Amount (USD)",
+ "HeaderSupportTheTeamHelp": "Help ensure the continued development of this project by donating. A portion of all donations will be contributed to other free tools we depend on.",
+ "ButtonEnterSupporterKey": "Enter supporter key",
+ "DonationNextStep": "Once complete, please return and enter your supporter key, which you will receive by email.",
+ "AutoOrganizeHelp": "Auto-organize monitors your download folders for new files and moves them to your media directories.",
+ "AutoOrganizeTvHelp": "TV file organizing will only add episodes to existing series. It will not create new series folders.",
+ "OptionEnableEpisodeOrganization": "Enable new episode organization",
+ "LabelWatchFolder": "Watch folder:",
+ "LabelWatchFolderHelp": "The server will poll this folder during the 'Organize new media files' scheduled task.",
+ "ButtonViewScheduledTasks": "View scheduled tasks",
+ "LabelMinFileSizeForOrganize": "Minimum file size (MB):",
+ "LabelMinFileSizeForOrganizeHelp": "Files under this size will be ignored.",
+ "LabelSeasonFolderPattern": "Season folder pattern:",
+ "LabelSeasonZeroFolderName": "Season zero folder name:",
+ "HeaderEpisodeFilePattern": "Episode file pattern",
+ "LabelEpisodePattern": "Episode pattern:",
+ "LabelMultiEpisodePattern": "Multi-Episode pattern:",
+ "HeaderSupportedPatterns": "Supported Patterns",
+ "HeaderTerm": "Term",
+ "HeaderPattern": "Pattern",
+ "HeaderResult": "Result",
+ "LabelDeleteEmptyFolders": "Delete empty folders after organizing",
+ "LabelDeleteEmptyFoldersHelp": "Enable this to keep the download directory clean.",
+ "LabelDeleteLeftOverFiles": "Delete left over files with the following extensions:",
+ "LabelDeleteLeftOverFilesHelp": "Separate with ;. For example: .nfo;.txt",
+ "OptionOverwriteExistingEpisodes": "Overwrite existing episodes",
+ "LabelTransferMethod": "Transfer method",
+ "OptionCopy": "Copy",
+ "OptionMove": "Move",
+ "LabelTransferMethodHelp": "Copy or move files from the watch folder",
+ "HeaderLatestNews": "Latest News",
+ "HeaderHelpImproveMediaBrowser": "Help Improve Media Browser",
+ "HeaderRunningTasks": "Running Tasks",
+ "HeaderActiveDevices": "Active Devices",
+ "HeaderPendingInstallations": "Pending Installations",
+ "HeaerServerInformation": "Server Information",
+ "ButtonRestartNow": "Restart Now",
+ "ButtonRestart": "Restart",
+ "ButtonShutdown": "Shutdown",
+ "ButtonUpdateNow": "Update Now",
+ "PleaseUpdateManually": "Please shutdown the server and update manually.",
+ "NewServerVersionAvailable": "A new version of Media Browser Server is available!",
+ "ServerUpToDate": "Media Browser Server is up to date",
+ "ErrorConnectingToMediaBrowserRepository": "There was an error connecting to the remote Media Browser repository.",
+ "LabelComponentsUpdated": "The following components have been installed or updated:",
+ "MessagePleaseRestartServerToFinishUpdating": "Please restart the server to finish applying updates."
}
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 3e741f41b0..6f0a71c8cc 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -1182,6 +1182,13 @@ namespace MediaBrowser.Server.Implementations.Session
if (session.UserId.HasValue)
{
dto.UserId = session.UserId.Value.ToString("N");
+
+ var user = _userManager.GetUserById(session.UserId.Value);
+
+ if (user != null)
+ {
+ dto.UserPrimaryImageTag = GetImageCacheTag(user, ImageType.Primary);
+ }
}
return dto;
@@ -1311,6 +1318,11 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
+ if (backropItem == null)
+ {
+ backropItem = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Backdrop));
+ }
+
if (thumbItem == null)
{
thumbItem = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Thumb));
@@ -1322,7 +1334,7 @@ namespace MediaBrowser.Server.Implementations.Session
info.ThumbItemId = GetDtoId(thumbItem);
}
- if (thumbItem != null)
+ if (backropItem != null)
{
info.BackdropImageTag = GetImageCacheTag(backropItem, ImageType.Backdrop);
info.BackdropItemId = GetDtoId(backropItem);
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 8df247ac04..931bb6a102 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -608,6 +608,7 @@ namespace MediaBrowser.WebDashboard.Api
"supporterkeypage.js",
"supporterpage.js",
"episodes.js",
+ "thememediaplayer.js",
"tvgenres.js",
"tvlatest.js",
"tvpeople.js",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 10ed2b7f4d..b1cfab37a3 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -220,6 +220,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -505,6 +508,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
@@ -637,6 +643,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest