Merge pull request #1821 from MediaBrowser/dev

Dev
pull/702/head
Luke 8 years ago
commit ee9c6c5664

@ -1207,7 +1207,7 @@ namespace MediaBrowser.Api.Playback
}
}
private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream)
private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream, string outputVideoCodec)
{
var bitrate = request.VideoBitRate;
@ -1232,6 +1232,12 @@ namespace MediaBrowser.Api.Playback
}
}
if (bitrate.HasValue)
{
var inputVideoCodec = videoStream == null ? null : videoStream.Codec;
bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
}
return bitrate;
}
@ -1692,7 +1698,7 @@ namespace MediaBrowser.Api.Playback
if (videoRequest != null)
{
state.OutputVideoCodec = state.VideoRequest.VideoCodec;
state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream);
state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
if (state.OutputVideoBitrate.HasValue)
{

@ -221,7 +221,7 @@ namespace MediaBrowser.Api.Subtitles
if (string.Equals(request.Format, "vtt", StringComparison.OrdinalIgnoreCase) && request.AddVttTimeMap)
{
text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
//text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000");
}
return ResultFactory.GetResult(text, MimeTypes.GetMimeType("file." + request.Format));

@ -385,7 +385,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("User not found");
}
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), null).ConfigureAwait(false);
await _userManager.DeleteUser(user).ConfigureAwait(false);
}
@ -465,6 +465,10 @@ namespace MediaBrowser.Api
}
await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
}
@ -602,7 +606,8 @@ namespace MediaBrowser.Api
throw new ArgumentException("There must be at least one enabled user in the system.");
}
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false);

@ -875,7 +875,7 @@ namespace MediaBrowser.Controller.Entities
return true;
}
if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User))
if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User, ConfigurationManager))
{
Logger.Debug("Query requires post-filtering due to CollapseBoxSetItems");
return true;
@ -983,7 +983,7 @@ namespace MediaBrowser.Controller.Entities
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query)
{
return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager);
return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager);
}
public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)

@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Entities
parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
}
return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager, PlaylistManager)
return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager, PlaylistManager)
.GetUserItems(parent, this, ViewType, query);
}

@ -18,6 +18,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Controller.Entities
{
@ -30,10 +32,10 @@ namespace MediaBrowser.Controller.Entities
private readonly ILogger _logger;
private readonly IUserDataManager _userDataManager;
private readonly ITVSeriesManager _tvSeriesManager;
private readonly ICollectionManager _collectionManager;
private readonly IServerConfigurationManager _config;
private readonly IPlaylistManager _playlistManager;
public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager, IPlaylistManager playlistManager)
public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, IServerConfigurationManager config, IPlaylistManager playlistManager)
{
_userViewManager = userViewManager;
_liveTvManager = liveTvManager;
@ -42,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
_logger = logger;
_userDataManager = userDataManager;
_tvSeriesManager = tvSeriesManager;
_collectionManager = collectionManager;
_config = config;
_playlistManager = playlistManager;
}
@ -159,7 +161,7 @@ namespace MediaBrowser.Controller.Entities
return await GetTvGenres(queryParent, user, query).ConfigureAwait(false);
case SpecialFolder.TvGenre:
return await GetTvGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false);
return GetTvGenreItems(queryParent, displayParent, user, query);
case SpecialFolder.TvResume:
return GetTvResume(queryParent, user, query);
@ -740,7 +742,7 @@ namespace MediaBrowser.Controller.Entities
return GetResult(genres, parent, query);
}
private async Task<QueryResult<BaseItem>> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
{
query.Recursive = true;
query.ParentId = queryParent.Id;
@ -769,7 +771,7 @@ namespace MediaBrowser.Controller.Entities
{
items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
return PostFilterAndSort(items, queryParent, null, query, _libraryManager);
return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config);
}
public static bool FilterItem(BaseItem item, InternalItemsQuery query)
@ -782,14 +784,15 @@ namespace MediaBrowser.Controller.Entities
int? totalRecordLimit,
InternalItemsQuery query)
{
return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager);
return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config);
}
public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items,
BaseItem queryParent,
int? totalRecordLimit,
InternalItemsQuery query,
ILibraryManager libraryManager)
ILibraryManager libraryManager,
IServerConfigurationManager configurationManager)
{
var user = query.User;
@ -798,7 +801,7 @@ namespace MediaBrowser.Controller.Entities
query.IsVirtualUnaired,
query.IsUnaired);
items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user);
items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager);
// This must be the last filter
if (!string.IsNullOrEmpty(query.AdjacentTo))
@ -812,14 +815,15 @@ namespace MediaBrowser.Controller.Entities
public static IEnumerable<BaseItem> CollapseBoxSetItemsIfNeeded(IEnumerable<BaseItem> items,
InternalItemsQuery query,
BaseItem queryParent,
User user)
User user,
IServerConfigurationManager configurationManager)
{
if (items == null)
{
throw new ArgumentNullException("items");
}
if (CollapseBoxSetItems(query, queryParent, user))
if (CollapseBoxSetItems(query, queryParent, user, configurationManager))
{
items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user);
}
@ -852,7 +856,8 @@ namespace MediaBrowser.Controller.Entities
public static bool CollapseBoxSetItems(InternalItemsQuery query,
BaseItem queryParent,
User user)
User user,
IServerConfigurationManager configurationManager)
{
// Could end up stuck in a loop like this
if (queryParent is BoxSet)
@ -864,7 +869,7 @@ namespace MediaBrowser.Controller.Entities
if (!param.HasValue)
{
if (user != null && !user.Configuration.GroupMoviesIntoBoxSets)
if (user != null && !configurationManager.Configuration.EnableGroupingIntoCollections)
{
return false;
}

@ -315,9 +315,8 @@ namespace MediaBrowser.Controller.Session
/// <summary>
/// Revokes the user tokens.
/// </summary>
/// <param name="userId">The user identifier.</param>
/// <returns>Task.</returns>
Task RevokeUserTokens(string userId);
Task RevokeUserTokens(string userId, string currentAccessToken);
/// <summary>
/// Revokes the token.

@ -99,7 +99,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (videoRequest != null)
{
state.OutputVideoCodec = state.Options.VideoCodec;
state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream);
state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream, state.OutputVideoCodec);
if (state.OutputVideoBitrate.HasValue)
{
@ -396,7 +396,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return request.AudioChannels;
}
private int? GetVideoBitrateParamValue(EncodingJobOptions request, MediaStream videoStream)
private int? GetVideoBitrateParamValue(EncodingJobOptions request, MediaStream videoStream, string outputVideoCodec)
{
var bitrate = request.VideoBitRate;
@ -421,6 +421,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
if (bitrate.HasValue)
{
var inputVideoCodec = videoStream == null ? null : videoStream.Codec;
bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
}
return bitrate;
}

@ -199,6 +199,7 @@ namespace MediaBrowser.Model.Configuration
public bool EnableStandaloneMusicKeys { get; set; }
public bool EnableLocalizedGuids { get; set; }
public bool EnableFolderView { get; set; }
public bool EnableGroupingIntoCollections { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.

@ -56,5 +56,25 @@ namespace MediaBrowser.Model.Dlna
MaxHeight = maxHeight
};
}
private static double GetVideoBitrateScaleFactor(string codec)
{
if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) ||
string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
{
return .5;
}
return 1;
}
public static int ScaleBitrate(int bitrate, string inputVideoCodec, string outputVideoCodec)
{
var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec);
var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec);
var scaleFactor = outputScaleFactor/inputScaleFactor;
var newBitrate = scaleFactor*bitrate;
return Convert.ToInt32(newBitrate);
}
}
}

@ -1,4 +1,5 @@
using System.Collections.Generic;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.LiveTv
{
@ -73,17 +74,21 @@ namespace MediaBrowser.Model.LiveTv
public string[] EnabledTuners { get; set; }
public bool EnableAllTuners { get; set; }
public string[] NewsGenres { get; set; }
public string[] SportsGenres { get; set; }
public string[] KidsGenres { get; set; }
public string[] NewsCategories { get; set; }
public string[] SportsCategories { get; set; }
public string[] KidsCategories { get; set; }
public string[] MovieCategories { get; set; }
public NameValuePair[] ChannelMappings { get; set; }
public ListingsProviderInfo()
{
NewsGenres = new string[] { "news" };
SportsGenres = new string[] { "sports", "basketball", "baseball", "football" };
KidsGenres = new string[] { "kids", "family", "children" };
NewsCategories = new string[] { "news", "journalism", "documentary", "current affairs" };
SportsCategories = new string[] { "sports", "basketball", "baseball", "football" };
KidsCategories = new string[] { "kids", "family", "children", "childrens", "disney" };
MovieCategories = new string[] { "movie" };
EnabledTuners = new string[] { };
EnableAllTuners = true;
ChannelMappings = new NameValuePair[] {};
}
}
}

@ -60,7 +60,6 @@ namespace MediaBrowser.Server.Implementations.Connect
{
return new ConnectUserPreferences
{
GroupMoviesIntoBoxSets = config.GroupMoviesIntoBoxSets,
PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
SubtitleMode = config.SubtitleMode,
PreferredAudioLanguages = string.IsNullOrWhiteSpace(config.AudioLanguagePreference) ? new string[] { } : new[] { config.AudioLanguagePreference },

@ -41,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
if (service != null)
if (service != null && !item.HasImage(ImageType.Primary))
{
try
{

@ -625,7 +625,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Debug("Getting programs for channel {0}-{1} from {2}-{3}", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty);
var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, channel.Name, startDateUtc, endDateUtc, cancellationToken)
var channelMappings = GetChannelMappings(provider.Item2);
var channelNumber = channel.Number;
string mappedChannelNumber;
if (channelMappings.TryGetValue(channelNumber, out mappedChannelNumber))
{
_logger.Debug("Found mapped channel on provider {0}. Tuner channel number: {1}, Mapped channel number: {2}", provider.Item1.Name, channelNumber, mappedChannelNumber);
channelNumber = mappedChannelNumber;
}
var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelNumber, channel.Name, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false);
var list = programs.ToList();
@ -647,6 +656,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return new List<ProgramInfo>();
}
private Dictionary<string, string> GetChannelMappings(ListingsProviderInfo info)
{
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var mapping in info.ChannelMappings)
{
dict[mapping.Name] = mapping.Value;
}
return dict;
}
private List<Tuple<IListingsProvider, ListingsProviderInfo>> GetListingProviders()
{
return GetConfiguration().ListingProviders

@ -1,44 +0,0 @@
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
public class XmlTv : IListingsProvider
{
public string Name
{
get { return "XmlTV"; }
}
public string Type
{
get { return "xmltv"; }
}
public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
{
// Might not be needed
}
public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
{
// Check that the path or url is valid. If not, throw a file not found exception
}
public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
{
// In theory this should never be called because there is always only one lineup
throw new NotImplementedException();
}
}
}

@ -0,0 +1,112 @@
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Emby.XmlTv.Classes;
using MediaBrowser.Controller.Configuration;
namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
public class XmlTvListingsProvider : IListingsProvider
{
private readonly IServerConfigurationManager _config;
public XmlTvListingsProvider(IServerConfigurationManager config)
{
_config = config;
}
public string Name
{
get { return "XmlTV"; }
}
public string Type
{
get { return "xmltv"; }
}
private string GetLanguage()
{
return _config.Configuration.PreferredMetadataLanguage;
}
// TODO: Should this method be async?
public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
var reader = new XmlTvReader(info.Path, GetLanguage(), null);
string mappedChannel = channelNumber;
var results = reader.GetProgrammes(mappedChannel, startDateUtc, endDateUtc, cancellationToken);
return Task.FromResult(results.Select(p => new ProgramInfo()
{
ChannelId = p.ChannelId,
EndDate = p.EndDate,
EpisodeNumber = p.Episode == null ? null : p.Episode.Episode,
EpisodeTitle = p.Episode == null ? null : p.Episode.Title,
Genres = p.Categories,
Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate), // Construct an id from the channel and start date,
StartDate = p.StartDate,
Name = p.Title,
Overview = p.Description,
ShortOverview = p.Description,
ProductionYear = !p.CopyrightDate.HasValue ? (int?)null : p.CopyrightDate.Value.Year,
SeasonNumber = p.Episode == null ? null : p.Episode.Series,
IsSeries = p.IsSeries,
IsRepeat = p.IsRepeat,
// IsPremiere = !p.PreviouslyShown.HasValue,
IsKids = p.Categories.Any(info.KidsCategories.Contains),
IsMovie = p.Categories.Any(info.MovieCategories.Contains),
IsNews = p.Categories.Any(info.NewsCategories.Contains),
IsSports = p.Categories.Any(info.SportsCategories.Contains),
ImageUrl = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source) ? p.Icon.Source : null,
HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source),
OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null,
CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null
}));
}
public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
{
// Add the channel image url
var reader = new XmlTvReader(info.Path, GetLanguage(), null);
var results = reader.GetChannels().ToList();
if (channels != null && channels.Count > 0)
{
channels.ForEach(c => {
var match = results.FirstOrDefault(r => r.Id == c.Id);
if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source))
{
c.ImageUrl = match.Icon.Source;
}
});
}
}
public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
{
// Check that the path or url is valid. If not, throw a file not found exception
if (!File.Exists(info.Path))
{
throw new FileNotFoundException("Could not find the XmlTv file specified:", info.Path);
}
}
public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
{
// In theory this should never be called because there is always only one lineup
var reader = new XmlTvReader(info.Path, GetLanguage(), null);
var results = reader.GetChannels();
// Should this method be async?
return Task.FromResult(results.Select(c => new NameIdPair() { Id = c.Id, Name = c.DisplayName }).ToList());
}
}
}

@ -233,7 +233,7 @@
<Compile Include="LiveTv\EmbyTV\SeriesTimerManager.cs" />
<Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
<Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
<Compile Include="LiveTv\Listings\XmlTv.cs" />
<Compile Include="LiveTv\Listings\XmlTvListingsProvider.cs" />
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
<Compile Include="LiveTv\LiveTvDtoService.cs" />
<Compile Include="LiveTv\LiveTvManager.cs" />

@ -1451,7 +1451,7 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
public async Task RevokeUserTokens(string userId)
public async Task RevokeUserTokens(string userId, string currentAccessToken)
{
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
@ -1461,7 +1461,10 @@ namespace MediaBrowser.Server.Implementations.Session
foreach (var info in existing.Items)
{
await Logout(info.AccessToken).ConfigureAwait(false);
if (!string.Equals(currentAccessToken, info.AccessToken, StringComparison.OrdinalIgnoreCase))
{
await Logout(info.AccessToken).ConfigureAwait(false);
}
}
}

@ -71,6 +71,7 @@
<Compile Include="FFMpeg\FFmpegValidator.cs" />
<Compile Include="INativeApp.cs" />
<Compile Include="MbLinkShortcutHandler.cs" />
<Compile Include="Migrations\CollectionGroupingMigration.cs" />
<Compile Include="Migrations\FolderViewSettingMigration.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
<Compile Include="Migrations\DbMigration.cs" />

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Server.Startup.Common.Migrations
{
public class CollectionGroupingMigration : IVersionMigration
{
private readonly IServerConfigurationManager _config;
private readonly IUserManager _userManager;
public CollectionGroupingMigration(IServerConfigurationManager config, IUserManager userManager)
{
_config = config;
_userManager = userManager;
}
public void Run()
{
var migrationKey = this.GetType().Name;
var migrationKeyList = _config.Configuration.Migrations.ToList();
if (!migrationKeyList.Contains(migrationKey))
{
if (_config.Configuration.IsStartupWizardCompleted)
{
if (_userManager.Users.Any(i => i.Configuration.GroupMoviesIntoBoxSets))
{
_config.Configuration.EnableGroupingIntoCollections = true;
}
}
migrationKeyList.Add(migrationKey);
_config.Configuration.Migrations = migrationKeyList.ToArray();
_config.SaveConfiguration();
}
}
}
}

@ -152,9 +152,6 @@
<Content Include="dashboard-ui\css\images\logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\polymer\paper-icon-button-light.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\devices\windowsphone\wp.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

Loading…
Cancel
Save