aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs2
-rw-r--r--MediaBrowser.Api/Movies/TrailersService.cs93
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs4
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs37
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs6
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs18
-rw-r--r--MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs4
-rw-r--r--MediaBrowser.Model/ApiClient/IConnectionManager.cs4
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs2
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs3
-rw-r--r--MediaBrowser.Providers/Music/MusicVideoMetadataService.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs27
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/server.json7
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs6
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs35
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs549
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs574
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj1
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs4
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Model.Signed.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
27 files changed, 820 insertions, 593 deletions
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 1fa1a5509..65c51beff 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -237,7 +237,7 @@ namespace MediaBrowser.Api
if (musicVideo != null)
{
- musicVideo.Artist = request.Artists[0];
+ musicVideo.Artists = request.Artists.ToList();
musicVideo.Album = request.Album;
}
diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs
index b0ee6b6d5..a6024d461 100644
--- a/MediaBrowser.Api/Movies/TrailersService.cs
+++ b/MediaBrowser.Api/Movies/TrailersService.cs
@@ -1,10 +1,20 @@
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Api.UserLibrary;
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Channels;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using ServiceStack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Api.Movies
{
@@ -16,6 +26,17 @@ namespace MediaBrowser.Api.Movies
{
}
+ [Route("/Trailers", "GET", Summary = "Finds movies and trailers similar to a given trailer.")]
+ public class Getrailers : BaseItemsRequest, IReturn<ItemsResult>
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public Guid? UserId { get; set; }
+ }
+
/// <summary>
/// Class TrailersService
/// </summary>
@@ -38,6 +59,7 @@ namespace MediaBrowser.Api.Movies
private readonly IItemRepository _itemRepo;
private readonly IDtoService _dtoService;
+ private readonly IChannelManager _channelManager;
/// <summary>
/// Initializes a new instance of the <see cref="TrailersService"/> class.
@@ -45,13 +67,14 @@ namespace MediaBrowser.Api.Movies
/// <param name="userManager">The user manager.</param>
/// <param name="userDataRepository">The user data repository.</param>
/// <param name="libraryManager">The library manager.</param>
- public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
+ public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IChannelManager channelManager)
{
_userManager = userManager;
_userDataRepository = userDataRepository;
_libraryManager = libraryManager;
_itemRepo = itemRepo;
_dtoService = dtoService;
+ _channelManager = channelManager;
}
/// <summary>
@@ -75,5 +98,71 @@ namespace MediaBrowser.Api.Movies
return ToOptimizedSerializedResultUsingCache(result);
}
+
+ public async Task<object> Get(Getrailers request)
+ {
+ var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
+ var result = await GetAllTrailers(user).ConfigureAwait(false);
+
+ IEnumerable<BaseItem> items = result.Items;
+
+ // Apply filters
+ // Run them starting with the ones that are likely to reduce the list the most
+ foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f))
+ {
+ items = ItemsService.ApplyFilter(items, filter, user, _userDataRepository);
+ }
+
+ items = _libraryManager.Sort(items, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending);
+
+ var itemsArray = items.ToList();
+
+ var pagedItems = ApplyPaging(request, itemsArray);
+
+ var fields = request.GetItemFields().ToList();
+
+ var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray();
+
+ return new ItemsResult
+ {
+ TotalRecordCount = itemsArray.Count,
+ Items = returnItems
+ };
+ }
+
+ private IEnumerable<BaseItem> ApplyPaging(Getrailers request, IEnumerable<BaseItem> items)
+ {
+ // Start at
+ if (request.StartIndex.HasValue)
+ {
+ items = items.Skip(request.StartIndex.Value);
+ }
+
+ // Return limit
+ if (request.Limit.HasValue)
+ {
+ items = items.Take(request.Limit.Value);
+ }
+
+ return items;
+ }
+
+ private async Task<QueryResult<BaseItem>> GetAllTrailers(User user)
+ {
+ var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
+ {
+ ContentTypes = new[] { ChannelMediaContentType.MovieExtra },
+ ExtraTypes = new[] { ExtraType.Trailer },
+ UserId = user.Id.ToString("N")
+
+ }, CancellationToken.None).ConfigureAwait(false);
+
+
+ return new QueryResult<BaseItem>
+ {
+ Items = trailerResult.Items,
+ TotalRecordCount = trailerResult.TotalRecordCount
+ };
+ }
}
}
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 24b2bebd3..8f45c95da 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -97,7 +97,12 @@ namespace MediaBrowser.Api.Playback
public bool ReadInputAtNativeFramerate
{
- get { return InputProtocol == MediaProtocol.Rtmp || string.Equals(InputContainer, "wtv", StringComparison.OrdinalIgnoreCase); }
+ get {
+
+ return InputProtocol == MediaProtocol.Rtmp ||
+ string.Equals(InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) ||
+ !string.IsNullOrEmpty(LiveTvStreamId);
+ }
}
public TransportStreamTimestamp InputTimestamp { get; set; }
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 897a68a65..9cad64bfa 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Collections;
+using System.Threading;
+using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -8,6 +9,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using ServiceStack;
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 070572b9b..2d9e052b1 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -226,7 +226,9 @@ namespace MediaBrowser.Controller.Entities.Audio
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
{
- return inputItems.OfType<IHasArtist>().Where(i => i.HasArtist(Name)).Cast<BaseItem>();
+ return inputItems.OfType<IHasArtist>()
+ .Where(i => i.HasArtist(Name))
+ .Cast<BaseItem>();
}
}
}
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index d36bfd7c4..307117fdd 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -12,12 +12,6 @@ namespace MediaBrowser.Controller.Entities
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasProductionLocations, IHasBudget, IHasLookupInfo<MusicVideoInfo>
{
/// <summary>
- /// Gets or sets the artist.
- /// </summary>
- /// <value>The artist.</value>
- public string Artist { get; set; }
-
- /// <summary>
/// Gets or sets the album.
/// </summary>
/// <value>The album.</value>
@@ -35,27 +29,12 @@ namespace MediaBrowser.Controller.Entities
/// <value>The revenue.</value>
public double? Revenue { get; set; }
public List<string> ProductionLocations { get; set; }
+ public List<string> Artists { get; set; }
public MusicVideo()
{
ProductionLocations = new List<string>();
- }
-
- [IgnoreDataMember]
- public List<string> Artists
- {
- get
- {
- var list = new List<string>();
-
- if (!string.IsNullOrEmpty(Artist))
- {
- list.Add(Artist);
- }
-
- return list;
-
- }
+ Artists = new List<string>();
}
[IgnoreDataMember]
@@ -63,15 +42,7 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- var list = new List<string>();
-
- if (!string.IsNullOrEmpty(Artist))
- {
- list.Add(Artist);
- }
-
- return list;
-
+ return Artists;
}
}
@@ -82,7 +53,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns><c>true</c> if the specified name has artist; otherwise, <c>false</c>.</returns>
public bool HasArtist(string name)
{
- return string.Equals(Artist, name, StringComparison.OrdinalIgnoreCase);
+ return AllArtists.Contains(name, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index 28aebae79..6bc50b1ea 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -671,10 +671,10 @@ namespace MediaBrowser.Dlna.Didl
if (musicVideo != null)
{
- if (!string.IsNullOrEmpty(musicVideo.Artist))
+ foreach (var artist in musicVideo.Artists)
{
- AddValue(element, "upnp", "artist", musicVideo.Artist, NS_UPNP);
- AddAlbumArtist(element, musicVideo.Artist);
+ AddValue(element, "upnp", "artist", artist, NS_UPNP);
+ AddAlbumArtist(element, artist);
}
if (!string.IsNullOrEmpty(musicVideo.Album))
diff --git a/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs
index b88ff6c3a..f695487c5 100644
--- a/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs
@@ -1,7 +1,8 @@
-using System.Xml;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
+using System;
+using System.Xml;
namespace MediaBrowser.LocalMetadata.Parsers
{
@@ -26,8 +27,17 @@ namespace MediaBrowser.LocalMetadata.Parsers
switch (reader.Name)
{
case "Artist":
- item.Artist = reader.ReadElementContentAsString();
- break;
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ var artists = val.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+ item.Artists.AddRange(artists);
+ }
+
+ break;
+ }
case "Album":
item.Album = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs
index 40ed156bc..84d41c8e2 100644
--- a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs
@@ -78,9 +78,9 @@ namespace MediaBrowser.LocalMetadata.Savers
if (musicVideo != null)
{
- if (!string.IsNullOrEmpty(musicVideo.Artist))
+ if (musicVideo.Artists.Count > 0)
{
- builder.Append("<Artist>" + SecurityElement.Escape(musicVideo.Artist) + "</Artist>");
+ builder.Append("<Artist>" + SecurityElement.Escape(string.Join(";", musicVideo.Artists.ToArray())) + "</Artist>");
}
if (!string.IsNullOrEmpty(musicVideo.Album))
{
diff --git a/MediaBrowser.Model/ApiClient/IConnectionManager.cs b/MediaBrowser.Model/ApiClient/IConnectionManager.cs
index c649ef756..93aef7a7d 100644
--- a/MediaBrowser.Model/ApiClient/IConnectionManager.cs
+++ b/MediaBrowser.Model/ApiClient/IConnectionManager.cs
@@ -30,7 +30,9 @@ namespace MediaBrowser.Model.ApiClient
/// Occurs when [connect user sign out].
/// </summary>
event EventHandler<EventArgs> ConnectUserSignOut;
-
+ [Obsolete]
+ event EventHandler<EventArgs> RemoteLoggedOut;
+
/// <summary>
/// Gets the connect user.
/// </summary>
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 2e7dc2e40..230680ff2 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -180,6 +180,8 @@ namespace MediaBrowser.Model.Configuration
public bool SaveMetadataHidden { get; set; }
+ public bool PlaylistImagesDeleted { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 80fda4bc2..e37334c6c 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -43,7 +43,8 @@ namespace MediaBrowser.Model.Dto
public DateTime? DateCreated { get; set; }
public DateTime? DateLastMediaAdded { get; set; }
-
+ public ExtraType? ExtraType { get; set; }
+
public int? AirsBeforeSeasonNumber { get; set; }
public int? AirsAfterSeasonNumber { get; set; }
public int? AirsBeforeEpisodeNumber { get; set; }
diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
index 1fa0ed05e..bbb456b2b 100644
--- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
+++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
@@ -1,15 +1,13 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Linq;
namespace MediaBrowser.Providers.Music
{
@@ -36,9 +34,9 @@ namespace MediaBrowser.Providers.Music
target.Album = source.Album;
}
- if (replaceData || string.IsNullOrEmpty(target.Artist))
+ if (replaceData || target.Artists.Count == 0)
{
- target.Artist = source.Artist;
+ target.Artists = source.Artists.ToList();
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index 206ba5922..1370b2bf2 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -3,8 +3,6 @@ using MediaBrowser.Common.Events;
using MediaBrowser.Common.Implementations.Configuration;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Configuration;
@@ -215,9 +213,7 @@ namespace MediaBrowser.Server.Implementations.Configuration
{
DisableMetadataService(typeof(Movie), Configuration, service);
DisableMetadataService(typeof(Episode), Configuration, service);
- DisableMetadataService(typeof(Season), Configuration, service);
DisableMetadataService(typeof(Series), Configuration, service);
- DisableMetadataService(typeof(Video), Configuration, service);
}
private void DisableMetadataService(Type type, ServerConfiguration config, string service)
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index 366a5558b..3393876fc 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -72,22 +72,9 @@ namespace MediaBrowser.Server.Implementations.Dto
if (byName != null && !(item is LiveTvChannel))
{
- IEnumerable<BaseItem> libraryItems;
-
- var artist = item as MusicArtist;
-
- if (artist == null || artist.IsAccessedByName)
- {
- libraryItems = user != null ?
- user.RootFolder.GetRecursiveChildren(user) :
- _libraryManager.RootFolder.RecursiveChildren;
- }
- else
- {
- libraryItems = user != null ?
- artist.GetRecursiveChildren(user) :
- artist.RecursiveChildren;
- }
+ var libraryItems = user != null ?
+ user.RootFolder.GetRecursiveChildren(user) :
+ _libraryManager.RootFolder.RecursiveChildren;
SetItemByNameInfo(item, dto, byName.GetTaggedItems(libraryItems).ToList(), user);
@@ -398,7 +385,7 @@ namespace MediaBrowser.Server.Implementations.Dto
}
dto.Album = item.Album;
- dto.Artists = string.IsNullOrEmpty(item.Artist) ? new List<string>() : new List<string> { item.Artist };
+ dto.Artists = item.Artists;
}
private void SetGameProperties(BaseItemDto dto, Game item)
@@ -1232,6 +1219,12 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.ChannelId = channelItem.ChannelId;
dto.ChannelName = _channelManagerFactory().GetChannel(channelItem.ChannelId).Name;
}
+
+ var channelMediaItem = item as IChannelMediaItem;
+ if (channelMediaItem != null)
+ {
+ dto.ExtraType = channelMediaItem.ExtraType;
+ }
}
private void AttachLinkedChildImages(BaseItemDto dto, Folder folder, User user)
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index 6c2d756e4..575b38c53 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -1247,5 +1247,10 @@
"OptionWeekdays": "Weekdays",
"OptionWeekends": "Weekends",
"MessageProfileInfoSynced": "User profile information synced with Media Browser Connect.",
- "HeaderOptionalLinkMediaBrowserAccount": "Optional: Link your Media Browser account"
+ "HeaderOptionalLinkMediaBrowserAccount": "Optional: Link your Media Browser account",
+ "ButtonTrailerReel": "Trailer reel",
+ "HeaderTrailerReel": "Trailer Reel",
+ "OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
+ "HeaderTrailerReelHelp": "Start a trailer reel to play a long running playlist of trailers.",
+ "MessageNoTrailersFound": "No trailers found. Install the Trailer channel plugin to import a library of internet trailers."
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index cf204a5ba..a0cd60067 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -1546,11 +1546,7 @@ namespace MediaBrowser.Server.Implementations.Session
if (musicVideo != null)
{
info.Album = musicVideo.Album;
-
- if (!string.IsNullOrWhiteSpace(musicVideo.Artist))
- {
- info.Artists.Add(musicVideo.Artist);
- }
+ info.Artists = musicVideo.Artists.ToList();
}
var backropItem = item.HasImage(ImageType.Backdrop) ? item : null;
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 2c873f926..6ba5f4c53 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -324,6 +324,41 @@ namespace MediaBrowser.ServerApplication
private void PerformVersionMigration()
{
DeleteDeprecatedModules();
+
+ if (!ServerConfigurationManager.Configuration.PlaylistImagesDeleted)
+ {
+ DeletePlaylistImages();
+ ServerConfigurationManager.Configuration.PlaylistImagesDeleted = true;
+ ServerConfigurationManager.SaveConfiguration();
+ }
+ }
+
+ private void DeletePlaylistImages()
+ {
+ try
+ {
+ var path = Path.Combine(ApplicationPaths.DataPath, "playlists");
+
+ var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories)
+ .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i) ?? string.Empty))
+ .ToList();
+
+ foreach (var file in files)
+ {
+ try
+ {
+ File.Delete(file);
+ }
+ catch (IOException)
+ {
+
+ }
+ }
+ }
+ catch (IOException)
+ {
+
+ }
}
private void DeleteDeprecatedModules()
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 1b8e21e20..7f58a63bb 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -14,10 +14,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Text;
using System.Threading.Tasks;
-using WebMarkupMin.Core.Minifiers;
-using WebMarkupMin.Core.Settings;
namespace MediaBrowser.WebDashboard.Api
{
@@ -49,6 +46,12 @@ namespace MediaBrowser.WebDashboard.Api
public string Name { get; set; }
}
+ [Route("/web/Package", "GET")]
+ [Route("/dashboard/Package", "GET")]
+ public class GetDashboardPackage
+ {
+ }
+
/// <summary>
/// Class GetDashboardResource
/// </summary>
@@ -121,35 +124,6 @@ namespace MediaBrowser.WebDashboard.Api
}
/// <summary>
- /// Gets the dashboard UI path.
- /// </summary>
- /// <value>The dashboard UI path.</value>
- public string DashboardUIPath
- {
- get
- {
- if (!string.IsNullOrEmpty(_serverConfigurationManager.Configuration.DashboardSourcePath))
- {
- return _serverConfigurationManager.Configuration.DashboardSourcePath;
- }
-
- var runningDirectory = Path.GetDirectoryName(_serverConfigurationManager.ApplicationPaths.ApplicationPath);
-
- return Path.Combine(runningDirectory, "dashboard-ui");
- }
- }
-
- /// <summary>
- /// Gets the dashboard resource path.
- /// </summary>
- /// <param name="virtualPath">The virtual path.</param>
- /// <returns>System.String.</returns>
- private string GetDashboardResourcePath(string virtualPath)
- {
- return Path.Combine(DashboardUIPath, virtualPath.Replace('/', Path.DirectorySeparatorChar));
- }
-
- /// <summary>
/// Gets the specified request.
/// </summary>
/// <param name="request">The request.</param>
@@ -158,7 +132,7 @@ namespace MediaBrowser.WebDashboard.Api
{
var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
- return ResultFactory.GetStaticResult(Request, page.Plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => ModifyHtml(page.GetHtmlStream(), null));
+ return ResultFactory.GetStaticResult(Request, page.Plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml(page.GetHtmlStream(), null));
}
/// <summary>
@@ -228,7 +202,7 @@ namespace MediaBrowser.WebDashboard.Api
{
Request.Response.Redirect("wizardstart.html");
return null;
- }
+ }
}
path = path.Replace("scripts/jquery.mobile-1.4.4.min.map", "thirdparty/jquerymobile-1.4.4/jquery.mobile-1.4.4.min.map", StringComparison.OrdinalIgnoreCase);
@@ -241,7 +215,7 @@ namespace MediaBrowser.WebDashboard.Api
!contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) &&
!contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase))
{
- return ResultFactory.GetResult(GetResourceStream(path, isHtml, localizationCulture).Result, contentType);
+ return ResultFactory.GetResult(GetResourceStream(path, localizationCulture).Result, contentType);
}
TimeSpan? cacheDuration = null;
@@ -257,7 +231,7 @@ namespace MediaBrowser.WebDashboard.Api
var cacheKey = (assembly.Version + (localizationCulture ?? string.Empty) + path).GetMD5();
- return ResultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path, isHtml, localizationCulture));
+ return ResultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path, localizationCulture));
}
private string GetLocalizationCulture()
@@ -269,47 +243,17 @@ namespace MediaBrowser.WebDashboard.Api
/// Gets the resource stream.
/// </summary>
/// <param name="path">The path.</param>
- /// <param name="isHtml">if set to <c>true</c> [is HTML].</param>
/// <param name="localizationCulture">The localization culture.</param>
/// <returns>Task{Stream}.</returns>
- private async Task<Stream> GetResourceStream(string path, bool isHtml, string localizationCulture)
+ private Task<Stream> GetResourceStream(string path, string localizationCulture)
{
- Stream resourceStream;
-
- if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
- {
- resourceStream = await GetAllJavascript().ConfigureAwait(false);
- }
- else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
- {
- resourceStream = await GetAllCss().ConfigureAwait(false);
- }
- else
- {
- resourceStream = GetRawResourceStream(path);
- }
-
- if (resourceStream != null)
- {
- // Don't apply any caching for html pages
- // jQuery ajax doesn't seem to handle if-modified-since correctly
- if (isHtml)
- {
- resourceStream = await ModifyHtml(resourceStream, localizationCulture).ConfigureAwait(false);
- }
- }
-
- return resourceStream;
+ return GetPackageCreator()
+ .GetResource(path, localizationCulture, _appHost.ApplicationVersion.ToString());
}
- /// <summary>
- /// Gets the raw resource stream.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>Task{Stream}.</returns>
- private Stream GetRawResourceStream(string path)
+ private PackageCreator GetPackageCreator()
{
- return _fileSystem.GetFileStream(GetDashboardResourcePath(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
+ return new PackageCreator(_fileSystem, _localization, Logger, _serverConfigurationManager, _jsonSerializer);
}
/// <summary>
@@ -322,466 +266,67 @@ namespace MediaBrowser.WebDashboard.Api
return Path.GetExtension(path).EndsWith("html", StringComparison.OrdinalIgnoreCase);
}
- /// <summary>
- /// Modifies the HTML by adding common meta tags, css and js.
- /// </summary>
- /// <param name="sourceStream">The source stream.</param>
- /// <param name="userId">The user identifier.</param>
- /// <param name="localizationCulture">The localization culture.</param>
- /// <returns>Task{Stream}.</returns>
- private async Task<Stream> ModifyHtml(Stream sourceStream, string localizationCulture)
+ public async Task<object> Get(GetDashboardPackage request)
{
- using (sourceStream)
- {
- string html;
-
- using (var memoryStream = new MemoryStream())
- {
- await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
- html = Encoding.UTF8.GetString(memoryStream.ToArray());
-
- if (!string.IsNullOrWhiteSpace(localizationCulture))
- {
- var lang = localizationCulture.Split('-').FirstOrDefault();
-
- html = _localization.LocalizeDocument(html, localizationCulture, GetLocalizationToken);
-
- html = html.Replace("<html>", "<html lang=\"" + lang + "\">");
- }
-
- //try
- //{
- // var minifier = new HtmlMinifier(new HtmlMinificationSettings(true));
-
- // html = minifier.Minify(html).MinifiedContent;
- //}
- //catch (Exception ex)
- //{
- // Logger.ErrorException("Error minifying html", ex);
- //}
- }
-
- var version = GetType().Assembly.GetName().Version;
-
- html = html.Replace("<head>", "<head>" + GetMetaTags() + GetCommonCss(version) + GetCommonJavascript(version));
-
- var bytes = Encoding.UTF8.GetBytes(html);
-
- return new MemoryStream(bytes);
- }
- }
-
- private string GetLocalizationToken(string phrase)
- {
- return "${" + phrase + "}";
- }
-
- /// <summary>
- /// Gets the meta tags.
- /// </summary>
- /// <returns>System.String.</returns>
- private static string GetMetaTags()
- {
- var sb = new StringBuilder();
-
- sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
- sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">");
- //sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
- sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
- sb.Append("<meta name=\"application-name\" content=\"Media Browser\">");
- //sb.Append("<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\">");
-
- sb.Append("<link rel=\"icon\" sizes=\"114x114\" href=\"css/images/touchicon114.png\" />");
-
- // http://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html
- sb.Append("<link rel=\"apple-touch-icon\" href=\"css/images/touchicon.png\" />");
- sb.Append("<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"css/images/touchicon72.png\" />");
- sb.Append("<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"css/images/touchicon114.png\" />");
- sb.Append("<link rel=\"apple-touch-startup-image\" href=\"css/images/iossplash.png\" />");
- sb.Append("<link rel=\"shortcut icon\" href=\"css/images/favicon.ico\" />");
+ var path = Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath,
+ "webclient-dump");
- return sb.ToString();
- }
-
- /// <summary>
- /// Gets the common CSS.
- /// </summary>
- /// <param name="version">The version.</param>
- /// <returns>System.String.</returns>
- private static string GetCommonCss(Version version)
- {
- var versionString = "?v=" + version;
-
- var files = new[]
- {
- "thirdparty/jquerymobile-1.4.4/jquery.mobile-1.4.4.min.css",
- "thirdparty/swipebox-master/css/swipebox.min.css" + versionString,
- "css/all.css" + versionString
- };
-
- var tags = files.Select(s => string.Format("<link rel=\"stylesheet\" href=\"{0}\" />", s)).ToArray();
-
- return string.Join(string.Empty, tags);
- }
-
- /// <summary>
- /// Gets the common javascript.
- /// </summary>
- /// <param name="version">The version.</param>
- /// <returns>System.String.</returns>
- private static string GetCommonJavascript(Version version)
- {
- var builder = new StringBuilder();
-
- var versionString = "?v=" + version;
-
- var files = new[]
- {
- "scripts/all.js" + versionString,
- "thirdparty/jstree1.0/jquery.jstree.min.js",
- "thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
- };
-
- var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
-
- builder.Append(string.Join(string.Empty, tags));
-
- return builder.ToString();
- }
-
- /// <summary>
- /// Gets a stream containing all concatenated javascript
- /// </summary>
- /// <returns>Task{Stream}.</returns>
- private async Task<Stream> GetAllJavascript()
- {
- var memoryStream = new MemoryStream();
- var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
-
- // jQuery + jQuery mobile
- await AppendResource(memoryStream, "thirdparty/jquery-2.1.1.min.js", newLineBytes).ConfigureAwait(false);
- await AppendResource(memoryStream, "thirdparty/jquerymobile-1.4.4/jquery.mobile-1.4.4.min.js", newLineBytes).ConfigureAwait(false);
-
- await AppendResource(memoryStream, "thirdparty/jquery.unveil-custom.js", newLineBytes).ConfigureAwait(false);
-
- // This script produces errors in older versions of safari
- if ((Request.UserAgent ?? string.Empty).IndexOf("chrome/", StringComparison.OrdinalIgnoreCase) != -1)
- {
- await AppendResource(memoryStream, "thirdparty/cast_sender.js", newLineBytes).ConfigureAwait(false);
- }
-
- await AppendLocalization(memoryStream).ConfigureAwait(false);
- await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
-
- // Write the version string for the dashboard comparison function
- var versionString = string.Format("window.dashboardVersion='{0}';", _appHost.ApplicationVersion);
- var versionBytes = Encoding.UTF8.GetBytes(versionString);
-
- await memoryStream.WriteAsync(versionBytes, 0, versionBytes.Length).ConfigureAwait(false);
- await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
-
- var builder = new StringBuilder();
-
- foreach (var file in new[]
- {
- "thirdparty/apiclient/sha1.js",
- "thirdparty/apiclient/mediabrowser.apiclient.js",
- "thirdparty/apiclient/connectionmanager.js"
- })
+ try
{
- using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
- {
- using (var streamReader = new StreamReader(fs))
- {
- var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
- builder.Append(text);
- builder.Append(Environment.NewLine);
- }
- }
+ Directory.Delete(path, true);
}
-
- foreach (var file in GetScriptFiles())
+ catch (IOException)
{
- var path = GetDashboardResourcePath("scripts/" + file);
- using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
- {
- using (var streamReader = new StreamReader(fs))
- {
- var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
- builder.Append(text);
- builder.Append(Environment.NewLine);
- }
- }
}
- var js = builder.ToString();
+ var creator = GetPackageCreator();
- try
- {
- var result = new CrockfordJsMinifier().Minify(js, false, Encoding.UTF8);
+ CopyDirectory(creator.DashboardUIPath, path);
- js = result.MinifiedContent;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error minifying javascript", ex);
- }
+ var culture = "en-US";
- var bytes = Encoding.UTF8.GetBytes(js);
- await memoryStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ await DumpHtml(creator.DashboardUIPath, path, culture, _appHost.ApplicationVersion.ToString());
- memoryStream.Position = 0;
- return memoryStream;
+ return "";
}
- private IEnumerable<string> GetScriptFiles()
+ private async Task DumpHtml(string source, string destination, string culture, string appVersion)
{
- return new[]
- {
- "extensions.js",
- "site.js",
- "librarybrowser.js",
- "librarylist.js",
- "editorsidebar.js",
- "librarymenu.js",
- "mediacontroller.js",
- "chromecast.js",
- "backdrops.js",
- "sync.js",
- "playlistmanager.js",
-
- "mediaplayer.js",
- "mediaplayer-video.js",
- "nowplayingbar.js",
- "nowplayingpage.js",
-
- "ratingdialog.js",
- "aboutpage.js",
- "alphapicker.js",
- "addpluginpage.js",
- "advancedconfigurationpage.js",
- "metadataadvanced.js",
- "autoorganizetv.js",
- "autoorganizelog.js",
- "channels.js",
- "channelslatest.js",
- "channelitems.js",
- "channelsettings.js",
- "dashboardgeneral.js",
- "dashboardpage.js",
- "dashboardsync.js",
- "device.js",
- "devices.js",
- "devicesupload.js",
- "directorybrowser.js",
- "dlnaprofile.js",
- "dlnaprofiles.js",
- "dlnasettings.js",
- "dlnaserversettings.js",
- "editcollectionitems.js",
- "edititemmetadata.js",
- "edititemimages.js",
- "edititemsubtitles.js",
-
- "playbackconfiguration.js",
- "cinemamodeconfiguration.js",
- "encodingsettings.js",
-
- "externalplayer.js",
- "favorites.js",
- "gamesrecommendedpage.js",
- "gamesystemspage.js",
- "gamespage.js",
- "gamegenrepage.js",
- "gamestudiospage.js",
- "homelatest.js",
- "indexpage.js",
- "itembynamedetailpage.js",
- "itemdetailpage.js",
- "itemgallery.js",
- "itemlistpage.js",
- "librarypathmapping.js",
- "reports.js",
- "librarysettings.js",
- "livetvchannel.js",
- "livetvchannels.js",
- "livetvguide.js",
- "livetvnewrecording.js",
- "livetvprogram.js",
- "livetvrecording.js",
- "livetvrecordinglist.js",
- "livetvrecordings.js",
- "livetvtimer.js",
- "livetvseriestimer.js",
- "livetvseriestimers.js",
- "livetvsettings.js",
- "livetvsuggested.js",
- "livetvstatus.js",
- "livetvtimers.js",
-
- "loginpage.js",
- "logpage.js",
- "medialibrarypage.js",
- "metadataconfigurationpage.js",
- "metadataimagespage.js",
- "metadatasubtitles.js",
- "metadatakodi.js",
- "moviegenres.js",
- "moviecollections.js",
- "movies.js",
- "movieslatest.js",
- "moviepeople.js",
- "moviesrecommended.js",
- "moviestudios.js",
- "movietrailers.js",
- "musicalbums.js",
- "musicalbumartists.js",
- "musicartists.js",
- "musicgenres.js",
- "musicrecommended.js",
- "musicvideos.js",
-
- "mypreferencesdisplay.js",
- "mypreferenceslanguages.js",
- "mypreferenceswebclient.js",
-
- "notifications.js",
- "notificationlist.js",
- "notificationsetting.js",
- "notificationsettings.js",
- "playlist.js",
- "playlists.js",
- "playlistedit.js",
-
- "plugincatalogpage.js",
- "pluginspage.js",
- "remotecontrol.js",
- "scheduledtaskpage.js",
- "scheduledtaskspage.js",
- "search.js",
- "serversecurity.js",
- "songs.js",
- "supporterkeypage.js",
- "supporterpage.js",
- "episodes.js",
- "thememediaplayer.js",
- "tvgenres.js",
- "tvlatest.js",
- "tvpeople.js",
- "tvrecommended.js",
- "tvshows.js",
- "tvstudios.js",
- "tvupcoming.js",
- "useredit.js",
- "userpassword.js",
- "myprofile.js",
- "userprofilespage.js",
- "userparentalcontrol.js",
- "userlibraryaccess.js",
- "wizardfinishpage.js",
- "wizardservice.js",
- "wizardstartpage.js",
- "wizardsettings.js",
- "wizarduserpage.js"
- };
+ foreach (var file in Directory.GetFiles(source, "*.html", SearchOption.TopDirectoryOnly))
+ {
+ await DumpHtmlFile(file, destination, culture, appVersion).ConfigureAwait(false);
+ }
}
- private async Task AppendLocalization(Stream stream)
+ private async Task DumpHtmlFile(string file, string destination, string culture, string appVersion)
{
- var js = "window.localizationGlossary=" + _jsonSerializer.SerializeToString(_localization.GetJavaScriptLocalizationDictionary(GetLocalizationCulture()));
+ var filename = Path.GetFileName(file);
- var bytes = Encoding.UTF8.GetBytes(js);
- await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
- }
+ var targetPath = Path.Combine(destination, filename);
- /// <summary>
- /// Gets all CSS.
- /// </summary>
- /// <returns>Task{Stream}.</returns>
- private async Task<Stream> GetAllCss()
- {
- var files = new[]
- {
- "site.css",
- "chromecast.css",
- "mediaplayer.css",
- "mediaplayer-video.css",
- "librarymenu.css",
- "librarybrowser.css",
- "detailtable.css",
- "card.css",
- "tileitem.css",
- "metadataeditor.css",
- "notifications.css",
- "search.css",
- "pluginupdates.css",
- "remotecontrol.css",
- "userimage.css",
- "livetv.css",
- "nowplaying.css",
- "icons.css"
- };
-
- var builder = new StringBuilder();
-
- foreach (var file in files)
+ using (var stream = await GetPackageCreator().GetResource(filename, culture, appVersion).ConfigureAwait(false))
{
- var path = GetDashboardResourcePath("css/" + file);
-
- using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
+ using (var fs = _fileSystem.GetFileStream(targetPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
- using (var streamReader = new StreamReader(fs))
- {
- var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
- builder.Append(text);
- builder.Append(Environment.NewLine);
- }
+ stream.CopyTo(fs);
}
}
-
- var css = builder.ToString();
-
- //try
- //{
- // var result = new KristensenCssMinifier().Minify(builder.ToString(), false, Encoding.UTF8);
-
- // css = result.MinifiedContent;
- //}
- //catch (Exception ex)
- //{
- // Logger.ErrorException("Error minifying css", ex);
- //}
-
- var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(css));
-
- memoryStream.Position = 0;
- return memoryStream;
}
- /// <summary>
- /// Appends the resource.
- /// </summary>
- /// <param name="outputStream">The output stream.</param>
- /// <param name="path">The path.</param>
- /// <param name="newLineBytes">The new line bytes.</param>
- /// <returns>Task.</returns>
- private async Task AppendResource(Stream outputStream, string path, byte[] newLineBytes)
+ private void CopyDirectory(string source, string destination)
{
- path = GetDashboardResourcePath(path);
+ Directory.CreateDirectory(destination);
- using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
- {
- using (var streamReader = new StreamReader(fs))
- {
- var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
- var bytes = Encoding.UTF8.GetBytes(text);
- await outputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
- }
- }
+ //Now Create all of the directories
+ foreach (string dirPath in Directory.GetDirectories(source, "*",
+ SearchOption.AllDirectories))
+ Directory.CreateDirectory(dirPath.Replace(source, destination));
- await outputStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
+ //Copy all the files & Replaces any files with the same name
+ foreach (string newPath in Directory.GetFiles(source, "*.*",
+ SearchOption.AllDirectories))
+ File.Copy(newPath, newPath.Replace(source, destination), true);
}
}
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
new file mode 100644
index 000000000..c1316223e
--- /dev/null
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -0,0 +1,574 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Localization;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using WebMarkupMin.Core.Minifiers;
+
+namespace MediaBrowser.WebDashboard.Api
+{
+ public class PackageCreator
+ {
+ private readonly IFileSystem _fileSystem;
+ private readonly ILocalizationManager _localization;
+ private readonly ILogger _logger;
+ private readonly IServerConfigurationManager _config;
+ private readonly IJsonSerializer _jsonSerializer;
+
+ public PackageCreator(IFileSystem fileSystem, ILocalizationManager localization, ILogger logger, IServerConfigurationManager config, IJsonSerializer jsonSerializer)
+ {
+ _fileSystem = fileSystem;
+ _localization = localization;
+ _logger = logger;
+ _config = config;
+ _jsonSerializer = jsonSerializer;
+ }
+
+ public async Task<Stream> GetResource(string path,
+ string localizationCulture,
+ string appVersion)
+ {
+ var isHtml = IsHtml(path);
+
+ Stream resourceStream;
+
+ if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
+ {
+ resourceStream = await GetAllJavascript(localizationCulture, appVersion).ConfigureAwait(false);
+ }
+ else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
+ {
+ resourceStream = await GetAllCss().ConfigureAwait(false);
+ }
+ else
+ {
+ resourceStream = GetRawResourceStream(path);
+ }
+
+ if (resourceStream != null)
+ {
+ // Don't apply any caching for html pages
+ // jQuery ajax doesn't seem to handle if-modified-since correctly
+ if (isHtml)
+ {
+ resourceStream = await ModifyHtml(resourceStream, localizationCulture).ConfigureAwait(false);
+ }
+ }
+
+ return resourceStream;
+ }
+
+ /// <summary>
+ /// Determines whether the specified path is HTML.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if the specified path is HTML; otherwise, <c>false</c>.</returns>
+ private bool IsHtml(string path)
+ {
+ return Path.GetExtension(path).EndsWith("html", StringComparison.OrdinalIgnoreCase);
+ }
+
+ /// <summary>
+ /// Gets the dashboard UI path.
+ /// </summary>
+ /// <value>The dashboard UI path.</value>
+ public string DashboardUIPath
+ {
+ get
+ {
+ if (!string.IsNullOrEmpty(_config.Configuration.DashboardSourcePath))
+ {
+ return _config.Configuration.DashboardSourcePath;
+ }
+
+ var runningDirectory = Path.GetDirectoryName(_config.ApplicationPaths.ApplicationPath);
+
+ return Path.Combine(runningDirectory, "dashboard-ui");
+ }
+ }
+
+ /// <summary>
+ /// Gets the dashboard resource path.
+ /// </summary>
+ /// <param name="virtualPath">The virtual path.</param>
+ /// <returns>System.String.</returns>
+ private string GetDashboardResourcePath(string virtualPath)
+ {
+ return Path.Combine(DashboardUIPath, virtualPath.Replace('/', Path.DirectorySeparatorChar));
+ }
+
+ /// <summary>
+ /// Modifies the HTML by adding common meta tags, css and js.
+ /// </summary>
+ /// <param name="sourceStream">The source stream.</param>
+ /// <param name="localizationCulture">The localization culture.</param>
+ /// <returns>Task{Stream}.</returns>
+ public async Task<Stream> ModifyHtml(Stream sourceStream, string localizationCulture)
+ {
+ using (sourceStream)
+ {
+ string html;
+
+ using (var memoryStream = new MemoryStream())
+ {
+ await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
+
+ html = Encoding.UTF8.GetString(memoryStream.ToArray());
+
+ if (!string.IsNullOrWhiteSpace(localizationCulture))
+ {
+ var lang = localizationCulture.Split('-').FirstOrDefault();
+
+ html = _localization.LocalizeDocument(html, localizationCulture, GetLocalizationToken);
+
+ html = html.Replace("<html>", "<html lang=\"" + lang + "\">");
+ }
+
+ //try
+ //{
+ // var minifier = new HtmlMinifier(new HtmlMinificationSettings(true));
+
+ // html = minifier.Minify(html).MinifiedContent;
+ //}
+ //catch (Exception ex)
+ //{
+ // Logger.ErrorException("Error minifying html", ex);
+ //}
+ }
+
+ var version = GetType().Assembly.GetName().Version;
+
+ html = html.Replace("<head>", "<head>" + GetMetaTags() + GetCommonCss(version) + GetCommonJavascript(version));
+
+ var bytes = Encoding.UTF8.GetBytes(html);
+
+ return new MemoryStream(bytes);
+ }
+ }
+
+ private string GetLocalizationToken(string phrase)
+ {
+ return "${" + phrase + "}";
+ }
+
+ /// <summary>
+ /// Gets the meta tags.
+ /// </summary>
+ /// <returns>System.String.</returns>
+ private static string GetMetaTags()
+ {
+ var sb = new StringBuilder();
+
+ sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
+ sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">");
+ //sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
+ sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
+ sb.Append("<meta name=\"application-name\" content=\"Media Browser\">");
+ //sb.Append("<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\">");
+
+ sb.Append("<link rel=\"icon\" sizes=\"114x114\" href=\"css/images/touchicon114.png\" />");
+
+ // http://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html
+ sb.Append("<link rel=\"apple-touch-icon\" href=\"css/images/touchicon.png\" />");
+ sb.Append("<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"css/images/touchicon72.png\" />");
+ sb.Append("<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"css/images/touchicon114.png\" />");
+ sb.Append("<link rel=\"apple-touch-startup-image\" href=\"css/images/iossplash.png\" />");
+ sb.Append("<link rel=\"shortcut icon\" href=\"css/images/favicon.ico\" />");
+
+ return sb.ToString();
+ }
+
+ /// <summary>
+ /// Gets the common CSS.
+ /// </summary>
+ /// <param name="version">The version.</param>
+ /// <returns>System.String.</returns>
+ private string GetCommonCss(Version version)
+ {
+ var versionString = "?v=" + version;
+
+ var files = new[]
+ {
+ "thirdparty/jquerymobile-1.4.4/jquery.mobile-1.4.4.min.css",
+ "thirdparty/swipebox-master/css/swipebox.min.css" + versionString,
+ "css/all.css" + versionString
+ };
+
+ var tags = files.Select(s => string.Format("<link rel=\"stylesheet\" href=\"{0}\" />", s)).ToArray();
+
+ return string.Join(string.Empty, tags);
+ }
+
+ /// <summary>
+ /// Gets the common javascript.
+ /// </summary>
+ /// <param name="version">The version.</param>
+ /// <returns>System.String.</returns>
+ private string GetCommonJavascript(Version version)
+ {
+ var builder = new StringBuilder();
+
+ var versionString = "?v=" + version;
+
+ var files = new[]
+ {
+ "scripts/all.js" + versionString,
+ "thirdparty/jstree1.0/jquery.jstree.min.js",
+ "thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
+ };
+
+ var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
+
+ builder.Append(string.Join(string.Empty, tags));
+
+ return builder.ToString();
+ }
+
+ /// <summary>
+ /// Gets a stream containing all concatenated javascript
+ /// </summary>
+ /// <returns>Task{Stream}.</returns>
+ private async Task<Stream> GetAllJavascript(string culture, string version)
+ {
+ var memoryStream = new MemoryStream();
+ var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
+
+ // jQuery + jQuery mobile
+ await AppendResource(memoryStream, "thirdparty/jquery-2.1.1.min.js", newLineBytes).ConfigureAwait(false);
+ await AppendResource(memoryStream, "thirdparty/jquerymobile-1.4.4/jquery.mobile-1.4.4.min.js", newLineBytes).ConfigureAwait(false);
+
+ await AppendResource(memoryStream, "thirdparty/jquery.unveil-custom.js", newLineBytes).ConfigureAwait(false);
+
+ await AppendResource(memoryStream, "thirdparty/cast_sender.js", newLineBytes).ConfigureAwait(false);
+
+ await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
+ await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
+
+ // Write the version string for the dashboard comparison function
+ var versionString = string.Format("window.dashboardVersion='{0}';", version);
+ var versionBytes = Encoding.UTF8.GetBytes(versionString);
+
+ await memoryStream.WriteAsync(versionBytes, 0, versionBytes.Length).ConfigureAwait(false);
+ await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
+
+ var builder = new StringBuilder();
+
+ foreach (var file in new[]
+ {
+ "thirdparty/apiclient/sha1.js",
+ "thirdparty/apiclient/mediabrowser.apiclient.js",
+ "thirdparty/apiclient/connectionmanager.js"
+ })
+ {
+ using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
+ {
+ using (var streamReader = new StreamReader(fs))
+ {
+ var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
+ builder.Append(text);
+ builder.Append(Environment.NewLine);
+ }
+ }
+ }
+
+ foreach (var file in GetScriptFiles())
+ {
+ var path = GetDashboardResourcePath("scripts/" + file);
+
+ using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
+ {
+ using (var streamReader = new StreamReader(fs))
+ {
+ var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
+ builder.Append(text);
+ builder.Append(Environment.NewLine);
+ }
+ }
+ }
+
+ var js = builder.ToString();
+
+ try
+ {
+ var result = new CrockfordJsMinifier().Minify(js, false, Encoding.UTF8);
+
+ js = result.MinifiedContent;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error minifying javascript", ex);
+ }
+
+ var bytes = Encoding.UTF8.GetBytes(js);
+ await memoryStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+
+ memoryStream.Position = 0;
+ return memoryStream;
+ }
+ private IEnumerable<string> GetScriptFiles()
+ {
+ return new[]
+ {
+ "extensions.js",
+ "site.js",
+ "librarybrowser.js",
+ "librarylist.js",
+ "editorsidebar.js",
+ "librarymenu.js",
+ "mediacontroller.js",
+ "chromecast.js",
+ "backdrops.js",
+ "sync.js",
+ "playlistmanager.js",
+
+ "mediaplayer.js",
+ "mediaplayer-video.js",
+ "nowplayingbar.js",
+ "nowplayingpage.js",
+
+ "ratingdialog.js",
+ "aboutpage.js",
+ "alphapicker.js",
+ "addpluginpage.js",
+ "advancedconfigurationpage.js",
+ "metadataadvanced.js",
+ "autoorganizetv.js",
+ "autoorganizelog.js",
+ "channels.js",
+ "channelslatest.js",
+ "channelitems.js",
+ "channelsettings.js",
+ "dashboardgeneral.js",
+ "dashboardpage.js",
+ "dashboardsync.js",
+ "device.js",
+ "devices.js",
+ "devicesupload.js",
+ "directorybrowser.js",
+ "dlnaprofile.js",
+ "dlnaprofiles.js",
+ "dlnasettings.js",
+ "dlnaserversettings.js",
+ "editcollectionitems.js",
+ "edititemmetadata.js",
+ "edititemimages.js",
+ "edititemsubtitles.js",
+
+ "playbackconfiguration.js",
+ "cinemamodeconfiguration.js",
+ "encodingsettings.js",
+
+ "externalplayer.js",
+ "favorites.js",
+ "gamesrecommendedpage.js",
+ "gamesystemspage.js",
+ "gamespage.js",
+ "gamegenrepage.js",
+ "gamestudiospage.js",
+ "homelatest.js",
+ "indexpage.js",
+ "itembynamedetailpage.js",
+ "itemdetailpage.js",
+ "itemgallery.js",
+ "itemlistpage.js",
+ "librarypathmapping.js",
+ "reports.js",
+ "librarysettings.js",
+ "livetvchannel.js",
+ "livetvchannels.js",
+ "livetvguide.js",
+ "livetvnewrecording.js",
+ "livetvprogram.js",
+ "livetvrecording.js",
+ "livetvrecordinglist.js",
+ "livetvrecordings.js",
+ "livetvtimer.js",
+ "livetvseriestimer.js",
+ "livetvseriestimers.js",
+ "livetvsettings.js",
+ "livetvsuggested.js",
+ "livetvstatus.js",
+ "livetvtimers.js",
+
+ "loginpage.js",
+ "logpage.js",
+ "medialibrarypage.js",
+ "metadataconfigurationpage.js",
+ "metadataimagespage.js",
+ "metadatasubtitles.js",
+ "metadatakodi.js",
+ "moviegenres.js",
+ "moviecollections.js",
+ "movies.js",
+ "movieslatest.js",
+ "moviepeople.js",
+ "moviesrecommended.js",
+ "moviestudios.js",
+ "movietrailers.js",
+ "musicalbums.js",
+ "musicalbumartists.js",
+ "musicartists.js",
+ "musicgenres.js",
+ "musicrecommended.js",
+ "musicvideos.js",
+
+ "mypreferencesdisplay.js",
+ "mypreferenceslanguages.js",
+ "mypreferenceswebclient.js",
+
+ "notifications.js",
+ "notificationlist.js",
+ "notificationsetting.js",
+ "notificationsettings.js",
+ "playlist.js",
+ "playlists.js",
+ "playlistedit.js",
+
+ "plugincatalogpage.js",
+ "pluginspage.js",
+ "remotecontrol.js",
+ "scheduledtaskpage.js",
+ "scheduledtaskspage.js",
+ "search.js",
+ "serversecurity.js",
+ "songs.js",
+ "supporterkeypage.js",
+ "supporterpage.js",
+ "episodes.js",
+ "thememediaplayer.js",
+ "tvgenres.js",
+ "tvlatest.js",
+ "tvpeople.js",
+ "tvrecommended.js",
+ "tvshows.js",
+ "tvstudios.js",
+ "tvupcoming.js",
+ "useredit.js",
+ "userpassword.js",
+ "myprofile.js",
+ "userprofilespage.js",
+ "userparentalcontrol.js",
+ "userlibraryaccess.js",
+ "wizardfinishpage.js",
+ "wizardservice.js",
+ "wizardstartpage.js",
+ "wizardsettings.js",
+ "wizarduserpage.js"
+ };
+ }
+
+ private async Task AppendLocalization(Stream stream, string culture)
+ {
+ var js = "window.localizationGlossary=" + _jsonSerializer.SerializeToString(_localization.GetJavaScriptLocalizationDictionary(culture));
+
+ var bytes = Encoding.UTF8.GetBytes(js);
+ await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ }
+
+ /// <summary>
+ /// Appends the resource.
+ /// </summary>
+ /// <param name="outputStream">The output stream.</param>
+ /// <param name="path">The path.</param>
+ /// <param name="newLineBytes">The new line bytes.</param>
+ /// <returns>Task.</returns>
+ private async Task AppendResource(Stream outputStream, string path, byte[] newLineBytes)
+ {
+ path = GetDashboardResourcePath(path);
+
+ using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
+ {
+ using (var streamReader = new StreamReader(fs))
+ {
+ var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
+ var bytes = Encoding.UTF8.GetBytes(text);
+ await outputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ }
+ }
+
+ await outputStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
+ }
+
+
+ /// <summary>
+ /// Gets all CSS.
+ /// </summary>
+ /// <returns>Task{Stream}.</returns>
+ private async Task<Stream> GetAllCss()
+ {
+ var files = new[]
+ {
+ "site.css",
+ "chromecast.css",
+ "mediaplayer.css",
+ "mediaplayer-video.css",
+ "librarymenu.css",
+ "librarybrowser.css",
+ "detailtable.css",
+ "card.css",
+ "tileitem.css",
+ "metadataeditor.css",
+ "notifications.css",
+ "search.css",
+ "pluginupdates.css",
+ "remotecontrol.css",
+ "userimage.css",
+ "livetv.css",
+ "nowplaying.css",
+ "icons.css"
+ };
+
+ var builder = new StringBuilder();
+
+ foreach (var file in files)
+ {
+ var path = GetDashboardResourcePath("css/" + file);
+
+ using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
+ {
+ using (var streamReader = new StreamReader(fs))
+ {
+ var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
+ builder.Append(text);
+ builder.Append(Environment.NewLine);
+ }
+ }
+ }
+
+ var css = builder.ToString();
+
+ //try
+ //{
+ // var result = new KristensenCssMinifier().Minify(builder.ToString(), false, Encoding.UTF8);
+
+ // css = result.MinifiedContent;
+ //}
+ //catch (Exception ex)
+ //{
+ // Logger.ErrorException("Error minifying css", ex);
+ //}
+
+ var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(css));
+
+ memoryStream.Position = 0;
+ return memoryStream;
+ }
+
+ /// <summary>
+ /// Gets the raw resource stream.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>Task{Stream}.</returns>
+ private Stream GetRawResourceStream(string path)
+ {
+ return _fileSystem.GetFileStream(GetDashboardResourcePath(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
+ }
+
+ }
+}
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index e80c2c375..719b1abd8 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -67,6 +67,7 @@
</Compile>
<Compile Include="Api\ConfigurationPageInfo.cs" />
<Compile Include="Api\DashboardService.cs" />
+ <Compile Include="Api\PackageCreator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServerEntryPoint.cs" />
</ItemGroup>
diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
index d2bfeeb7e..7cf987f9c 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
@@ -66,7 +66,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val) && movie != null)
{
- movie.Artist = val;
+ movie.Artists.Add(val);
}
break;
diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
index a4e8544ed..ce913c524 100644
--- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
@@ -74,9 +74,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (musicVideo != null)
{
- if (!string.IsNullOrEmpty(musicVideo.Artist))
+ foreach (var artist in musicVideo.Artists)
{
- writer.WriteElementString("artist", musicVideo.Artist);
+ writer.WriteElementString("artist", artist);
}
if (!string.IsNullOrEmpty(musicVideo.Album))
{
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index d2ce27c83..dc425327e 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.496</version>
+ <version>3.0.497</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.496" />
+ <dependency id="MediaBrowser.Common" version="3.0.497" />
<dependency id="NLog" version="3.1.0.0" />
<dependency id="SimpleInjector" version="2.6.0" />
<dependency id="sharpcompress" version="0.10.2" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 8e6fcc097..c1de3d884 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.496</version>
+ <version>3.0.497</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index f87b967fb..887e35a57 100644
--- a/Nuget/MediaBrowser.Model.Signed.nuspec
+++ b/Nuget/MediaBrowser.Model.Signed.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Model.Signed</id>
- <version>3.0.496</version>
+ <version>3.0.497</version>
<title>MediaBrowser.Model - Signed Edition</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index 028013454..172ab335a 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.496</version>
+ <version>3.0.497</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.496" />
+ <dependency id="MediaBrowser.Common" version="3.0.497" />
</dependencies>
</metadata>
<files>