浏览代码

support theme songs in the web client

Luke Pulverenti 11 年之前
父节点
当前提交
e89d4e605b

+ 3 - 9
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))
             {

+ 31 - 20
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -24,7 +24,8 @@ 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, 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);
         /// <summary>
         /// Processes the request async.
         /// </summary>
@@ -103,32 +105,41 @@ 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))
+            if (File.Exists(playlist))
             {
-                isPlaylistNewlyCreated = true;
-
+                ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
+            }
+            else
+            {
+                await FfmpegStartLock.WaitAsync().ConfigureAwait(false);
                 try
                 {
-                    await StartFfMpeg(state, playlist).ConfigureAwait(false);
+                    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);
                 }
-                catch
+                finally
                 {
-                    state.Dispose();
-                    throw;
+                    FfmpegStartLock.Release();
                 }
             }
-            else
-            {
-                ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
-            }
-
-            if (isPlaylistNewlyCreated)
-            {
-                await WaitForMinimumSegmentCount(playlist, GetSegmentWait()).ConfigureAwait(false);
-            }
 
             int audioBitrate;
             int videoBitrate;
@@ -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,

+ 3 - 0
MediaBrowser.Dlna/PlayTo/Device.cs

@@ -210,6 +210,9 @@ namespace MediaBrowser.Dlna.PlayTo
             return SetVolume(tmp);
         }
 
+        /// <summary>
+        /// Sets volume on a scale of 0-100
+        /// </summary>
         public async Task<bool> SetVolume(int value)
         {
             var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume");

+ 24 - 2
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);
                 }

+ 2 - 1
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()
                         }
                     });
 

+ 13 - 4
MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs

@@ -57,8 +57,17 @@ namespace MediaBrowser.Dlna.Server
         {
             builder.Append("<UDN>" + SecurityElement.Escape(_serverUdn) + "</UDN>");
             builder.Append("<dlna:X_DLNACAP>" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "</dlna:X_DLNACAP>");
-            builder.Append("<dlna:X_DLNADOC>M-DMS-1.50</dlna:X_DLNADOC>");
-            builder.Append("<dlna:X_DLNADOC>" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + "</dlna:X_DLNADOC>");
+
+            if (!string.IsNullOrWhiteSpace(_profile.XDlnaDoc))
+            {
+                builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">" +
+                               SecurityElement.Escape(_profile.XDlnaDoc) + "</dlna:X_DLNADOC>");
+            }
+            else
+            {
+                builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">DMS-1.50</dlna:X_DLNADOC>");
+            }
+
             builder.Append("<friendlyName>" + SecurityElement.Escape(_profile.FriendlyName ?? string.Empty) + "</friendlyName>");
             builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
             builder.Append("<manufacturer>" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
@@ -99,7 +108,7 @@ namespace MediaBrowser.Dlna.Server
 
             foreach (var service in GetServices())
             {
-                builder.Append("<icon>");
+                builder.Append("<service>");
 
                 builder.Append("<serviceType>" + SecurityElement.Escape(service.ServiceType ?? string.Empty) + "</serviceType>");
                 builder.Append("<serviceId>" + SecurityElement.Escape(service.ServiceId ?? string.Empty) + "</serviceId>");
@@ -107,7 +116,7 @@ namespace MediaBrowser.Dlna.Server
                 builder.Append("<controlURL>" + SecurityElement.Escape(service.ControlUrl ?? string.Empty) + "</controlURL>");
                 builder.Append("<eventSubURL>" + SecurityElement.Escape(service.EventSubUrl ?? string.Empty) + "</eventSubURL>");
 
-                builder.Append("</icon>");
+                builder.Append("</service>");
             }
 
             builder.Append("</serviceList>");

+ 9 - 3
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)

+ 3 - 3
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

+ 6 - 0
MediaBrowser.Model/Session/SessionInfoDto.cs

@@ -51,6 +51,12 @@ namespace MediaBrowser.Model.Session
         /// <value>The user id.</value>
         public string UserId { get; set; }
 
+        /// <summary>
+        /// Gets or sets the user primary image tag.
+        /// </summary>
+        /// <value>The user primary image tag.</value>
+        public Guid? UserPrimaryImageTag { get; set; }
+        
         /// <summary>
         /// Gets or sets the name of the user.
         /// </summary>

+ 4 - 1
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();
                     }

+ 66 - 1
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."
 }

+ 13 - 1
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);

+ 1 - 0
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",

+ 9 - 0
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -220,6 +220,9 @@
     <Content Include="dashboard-ui\css\images\media\tvflyout.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\css\images\nowplayingdefault.jpg">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\css\livetv.css">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -505,6 +508,9 @@
     <Content Include="dashboard-ui\livetvrecordings.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\nowplaying.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\advancedpaths.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -637,6 +643,9 @@
     <Content Include="dashboard-ui\scripts\livetvsuggested.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\scripts\thememediaplayer.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\tvupcoming.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>