added dashboard tour

This commit is contained in:
Luke Pulverenti 2014-10-04 14:05:24 -04:00
parent e83a3e710b
commit 7a084a589e
13 changed files with 190 additions and 62 deletions

View File

@ -157,7 +157,12 @@ namespace MediaBrowser.Api
private Task MarkRead(string idList, string userId, bool read)
{
var ids = idList.Split(',');
var ids = (idList ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (ids.Length == 0)
{
return _notificationsRepo.MarkAllRead(userId, read, CancellationToken.None);
}
return _notificationsRepo.MarkRead(ids, userId, read, CancellationToken.None);
}

View File

@ -635,8 +635,7 @@ namespace MediaBrowser.Api.Playback.Hls
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
// TOOD: Switch to -bsf dump_extra?
return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf h264_mp4toannexb" : "-codec:v:0 copy";
return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",

View File

@ -139,8 +139,7 @@ namespace MediaBrowser.Api.Playback.Hls
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
// TOOD: Switch to -bsf dump_extra?
return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf h264_mp4toannexb" : "-codec:v:0 copy";
return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",

View File

@ -132,8 +132,7 @@ namespace MediaBrowser.Api.Playback.Progressive
// See if we can save come cpu cycles by avoiding encoding
if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
{
// TODO: Switch to -bsf dump_extra ?
return state.VideoStream != null && IsH264(state.VideoStream) ? args + " -bsf h264_mp4toannexb" : args;
return state.VideoStream != null && IsH264(state.VideoStream) ? args + " -bsf:v h264_mp4toannexb" : args;
}
var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",

View File

@ -33,6 +33,12 @@ namespace MediaBrowser.Controller.Entities
/// <value>The type of the location.</value>
LocationType LocationType { get; }
/// <summary>
/// Gets the locked fields.
/// </summary>
/// <value>The locked fields.</value>
List<MetadataFields> LockedFields { get; }
/// <summary>
/// Gets the images.
/// </summary>

View File

@ -1,6 +1,5 @@
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Threading;
@ -25,12 +24,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The date modified.</value>
DateTime DateModified { get; }
/// <summary>
/// Gets the locked fields.
/// </summary>
/// <value>The locked fields.</value>
List<MetadataFields> LockedFields { get; }
/// <summary>
/// Gets or sets the date last saved.
/// </summary>

View File

@ -51,6 +51,15 @@ namespace MediaBrowser.Controller.Notifications
/// <returns>Task.</returns>
Task MarkRead(IEnumerable<string> notificationIdList, string userId, bool isRead, CancellationToken cancellationToken);
/// <summary>
/// Marks all read.
/// </summary>
/// <param name="userId">The user identifier.</param>
/// <param name="isRead">if set to <c>true</c> [is read].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task MarkAllRead(string userId, bool isRead, CancellationToken cancellationToken);
/// <summary>
/// Gets the notifications summary.
/// </summary>

View File

@ -787,13 +787,6 @@ namespace MediaBrowser.Model.ApiClient
/// <value>The server address.</value>
string ServerAddress { get; }
/// <summary>
/// Changes the server location.
/// </summary>
/// <param name="address">The address.</param>
/// <param name="keepExistingAuth">Don't clear any existing authentication</param>
void ChangeServerLocation(string address, bool keepExistingAuth = false);
/// <summary>
/// Gets or sets the type of the client.
/// </summary>

View File

@ -123,7 +123,7 @@ namespace MediaBrowser.Providers.Manager
foreach (var imageType in images)
{
if (!savedOptions.IsEnabled(imageType)) continue;
if (!IsEnabled(savedOptions, imageType, item)) continue;
if (!item.HasImage(imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType)))
{
@ -224,14 +224,14 @@ namespace MediaBrowser.Providers.Manager
/// <param name="result">The result.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
private async Task RefreshFromProvider(IHasImages item,
IRemoteImageProvider provider,
ImageRefreshOptions refreshOptions,
MetadataOptions savedOptions,
int backdropLimit,
int screenshotLimit,
private async Task RefreshFromProvider(IHasImages item,
IRemoteImageProvider provider,
ImageRefreshOptions refreshOptions,
MetadataOptions savedOptions,
int backdropLimit,
int screenshotLimit,
ICollection<ImageType> downloadedImages,
RefreshResult result,
RefreshResult result,
CancellationToken cancellationToken)
{
try
@ -241,8 +241,8 @@ namespace MediaBrowser.Providers.Manager
return;
}
if (!refreshOptions.ReplaceAllImages &&
refreshOptions.ReplaceImages.Count == 0 &&
if (!refreshOptions.ReplaceAllImages &&
refreshOptions.ReplaceImages.Count == 0 &&
ContainsImages(item, provider.GetSupportedImages(item).ToList(), savedOptions, backdropLimit, screenshotLimit))
{
return;
@ -263,7 +263,7 @@ namespace MediaBrowser.Providers.Manager
foreach (var imageType in _singularImages)
{
if (!savedOptions.IsEnabled(imageType)) continue;
if (!IsEnabled(savedOptions, imageType, item)) continue;
if (!item.HasImage(imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType)))
{
@ -277,14 +277,20 @@ namespace MediaBrowser.Providers.Manager
}
}
minWidth = savedOptions.GetMinWidth(ImageType.Backdrop);
await DownloadBackdrops(item, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
var hasScreenshots = item as IHasScreenshots;
if (hasScreenshots != null)
if (!item.LockedFields.Contains(MetadataFields.Backdrops))
{
minWidth = savedOptions.GetMinWidth(ImageType.Screenshot);
await DownloadBackdrops(item, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
minWidth = savedOptions.GetMinWidth(ImageType.Backdrop);
await DownloadBackdrops(item, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
}
if (!item.LockedFields.Contains(MetadataFields.Screenshots))
{
var hasScreenshots = item as IHasScreenshots;
if (hasScreenshots != null)
{
minWidth = savedOptions.GetMinWidth(ImageType.Screenshot);
await DownloadBackdrops(item, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
}
}
}
catch (OperationCanceledException)
@ -299,6 +305,33 @@ namespace MediaBrowser.Providers.Manager
}
}
private bool IsEnabled(MetadataOptions options, ImageType type, IHasImages item)
{
if (type == ImageType.Backdrop)
{
if (item.LockedFields.Contains(MetadataFields.Backdrops))
{
return false;
}
}
else if (type == ImageType.Screenshot)
{
if (item.LockedFields.Contains(MetadataFields.Screenshots))
{
return false;
}
}
else
{
if (item.LockedFields.Contains(MetadataFields.Images))
{
return false;
}
}
return options.IsEnabled(type);
}
private void ClearImages(IHasImages item, ImageType type)
{
var deleted = false;
@ -397,12 +430,12 @@ namespace MediaBrowser.Providers.Manager
return changed;
}
private async Task<bool> DownloadImage(IHasImages item,
IRemoteImageProvider provider,
RefreshResult result,
IEnumerable<RemoteImageInfo> images,
int minWidth,
ImageType type,
private async Task<bool> DownloadImage(IHasImages item,
IRemoteImageProvider provider,
RefreshResult result,
IEnumerable<RemoteImageInfo> images,
int minWidth,
ImageType type,
CancellationToken cancellationToken)
{
foreach (var image in images.Where(i => i.Type == type))

View File

@ -579,18 +579,26 @@
"LabelFullReview": "Full review:",
"LabelShortRatingDescription": "Short rating summary:",
"OptionIRecommendThisItem": "I recommend this item",
"WebClientTourContent": "View your recently added media, next episodes, and more. The green circles indicate how many unplayed items you have.",
"WebClientTourMovies": "Play movies, trailers and more from any device with a web browser",
"WebClientTourMouseOver": "Hold the mouse over any poster for quick access to important information",
"WebClientTourTapHold": "Tap and hold or right click any poster for a context menu",
"WebClientTourMetadataManager": "Click edit to open the metadata manager",
"WebClientTourPlaylists": "Easily create playlists and instant mixes, and play them on any device",
"WebClientTourCollections": "Create movie collections to group box sets together",
"WebClientTourUserPreferences1": "User preferences allow you to customize the way your library is presented in all of your Media Browser apps",
"WebClientTourUserPreferences2": "Configure your audio and subtitle language settings once, for every Media Browser app",
"WebClientTourUserPreferences3": "Design the web client home page to your liking",
"WebClientTourUserPreferences4": "Configure backdrops, theme songs and external players",
"WebClientTourMobile1": "The web client works great on smartphones and tablets...",
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay"
"WebClientTourContent": "View your recently added media, next episodes, and more. The green circles indicate how many unplayed items you have.",
"WebClientTourMovies": "Play movies, trailers and more from any device with a web browser",
"WebClientTourMouseOver": "Hold the mouse over any poster for quick access to important information",
"WebClientTourTapHold": "Tap and hold or right click any poster for a context menu",
"WebClientTourMetadataManager": "Click edit to open the metadata manager",
"WebClientTourPlaylists": "Easily create playlists and instant mixes, and play them on any device",
"WebClientTourCollections": "Create movie collections to group box sets together",
"WebClientTourUserPreferences1": "User preferences allow you to customize the way your library is presented in all of your Media Browser apps",
"WebClientTourUserPreferences2": "Configure your audio and subtitle language settings once, for every Media Browser app",
"WebClientTourUserPreferences3": "Design the web client home page to your liking",
"WebClientTourUserPreferences4": "Configure backdrops, theme songs and external players",
"WebClientTourMobile1": "The web client works great on smartphones and tablets...",
"WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
"MessageEnjoyYourStay": "Enjoy your stay",
"DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
"DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
"DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
"DashboardTourSubtitles": "Automatically download subtitles for your videos in any language.",
"DashboardTourPlugins": "Install plugins such as internet video channels, live tv, metadata scanners, and more.",
"DashboardTourNotifications": "Automatically send notifications of server events to your mobile device, email and more.",
"DashboardTourScheduledTasks": "Easily manage long running operations with scheduled tasks. Decide when they run, and how often."
}

View File

@ -1206,5 +1206,6 @@
"LabelDisplayTrailersWithinMovieSuggestionsHelp": "Requires installation of the Trailer channel.",
"CinemaModeConfigurationHelp2": "Individual users will have the ability to disable cinema mode within their own preferences.",
"LabelEnableCinemaMode": "Enable cinema mode",
"HeaderCinemaMode": "Cinema Mode"
"HeaderCinemaMode": "Cinema Mode",
"HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Server Dashboard"
}

View File

@ -15,7 +15,7 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
public class SqliteNotificationsRepository : INotificationsRepository
{
private IDbConnection _connection;
private IDbConnection _connection;
private readonly ILogger _logger;
private readonly IServerApplicationPaths _appPaths;
@ -33,13 +33,14 @@ namespace MediaBrowser.Server.Implementations.Notifications
private IDbCommand _replaceNotificationCommand;
private IDbCommand _markReadCommand;
private IDbCommand _markAllReadCommand;
public async Task Initialize()
{
var dbFile = Path.Combine(_appPaths.DataPath, "notifications.db");
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
string[] queries = {
"create table if not exists Notifications (Id GUID NOT NULL, UserId GUID NOT NULL, Date DATETIME NOT NULL, Name TEXT NOT NULL, Description TEXT, Url TEXT, Level TEXT NOT NULL, IsRead BOOLEAN NOT NULL, Category TEXT NOT NULL, RelatedId TEXT, PRIMARY KEY (Id, UserId))",
@ -78,6 +79,12 @@ namespace MediaBrowser.Server.Implementations.Notifications
_markReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
_markReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
_markReadCommand.Parameters.Add(_replaceNotificationCommand, "@Id");
_markAllReadCommand = _connection.CreateCommand();
_markAllReadCommand.CommandText = "update Notifications set IsRead=@IsRead where UserId=@UserId";
_markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
_markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
}
/// <summary>
@ -357,6 +364,58 @@ namespace MediaBrowser.Server.Implementations.Notifications
}
}
public async Task MarkAllRead(string userId, bool isRead, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
IDbTransaction transaction = null;
try
{
cancellationToken.ThrowIfCancellationRequested();
transaction = _connection.BeginTransaction();
_markAllReadCommand.GetParameter(0).Value = new Guid(userId);
_markAllReadCommand.GetParameter(1).Value = isRead;
_markAllReadCommand.ExecuteNonQuery();
transaction.Commit();
}
catch (OperationCanceledException)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
catch (Exception e)
{
_logger.ErrorException("Failed to save notification:", e);
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
_writeLock.Release();
}
}
private async Task MarkReadInternal(IEnumerable<Guid> notificationIdList, string userId, bool isRead, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

View File

@ -275,6 +275,30 @@
<Content Include="dashboard-ui\css\images\media\play.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\chapters.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\cinemamode.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\dashboard.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\notifications.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\plugins.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\scheduledtasks.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\subtitles.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\dashboard\users.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\tour\enjoy.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>