2020-08-03 14:01:24 -04:00
using System ;
2020-04-19 14:26:38 -04:00
using System.ComponentModel.DataAnnotations ;
2020-06-20 20:02:07 -04:00
using System.Diagnostics.CodeAnalysis ;
2020-08-03 14:01:24 -04:00
using System.Globalization ;
using System.Linq ;
2020-06-22 09:44:11 -04:00
using Jellyfin.Api.Constants ;
2020-08-03 14:01:24 -04:00
using Jellyfin.Data.Entities ;
using Jellyfin.Data.Enums ;
2020-12-04 18:27:31 -05:00
using MediaBrowser.Common.Extensions ;
2020-08-03 14:01:24 -04:00
using MediaBrowser.Controller ;
2020-04-19 14:26:38 -04:00
using MediaBrowser.Model.Entities ;
2020-04-23 12:07:21 -04:00
using Microsoft.AspNetCore.Authorization ;
2020-04-19 14:26:38 -04:00
using Microsoft.AspNetCore.Http ;
2020-04-19 14:06:18 -04:00
using Microsoft.AspNetCore.Mvc ;
2020-12-10 09:41:00 -05:00
using Microsoft.Extensions.Logging ;
2020-04-19 14:06:18 -04:00
namespace Jellyfin.Api.Controllers
{
/// <summary>
/// Display Preferences Controller.
/// </summary>
2020-06-22 09:44:11 -04:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-04-19 14:06:18 -04:00
public class DisplayPreferencesController : BaseJellyfinApiController
{
2020-08-03 14:01:24 -04:00
private readonly IDisplayPreferencesManager _displayPreferencesManager ;
2020-12-10 09:41:00 -05:00
private readonly ILogger < DisplayPreferencesController > _logger ;
2020-04-19 14:26:38 -04:00
/// <summary>
/// Initializes a new instance of the <see cref="DisplayPreferencesController"/> class.
/// </summary>
2020-08-03 14:01:24 -04:00
/// <param name="displayPreferencesManager">Instance of <see cref="IDisplayPreferencesManager"/> interface.</param>
2020-12-10 09:41:00 -05:00
/// <param name="logger">Instance of <see cref="ILogger{DisplayPreferencesController}"/> interface.</param>
public DisplayPreferencesController ( IDisplayPreferencesManager displayPreferencesManager , ILogger < DisplayPreferencesController > logger )
2020-04-19 14:26:38 -04:00
{
2020-08-03 14:01:24 -04:00
_displayPreferencesManager = displayPreferencesManager ;
2020-12-10 09:41:00 -05:00
_logger = logger ;
2020-04-19 14:26:38 -04:00
}
/// <summary>
2020-04-19 14:30:10 -04:00
/// Get Display Preferences.
2020-04-19 14:26:38 -04:00
/// </summary>
/// <param name="displayPreferencesId">Display preferences id.</param>
/// <param name="userId">User id.</param>
/// <param name="client">Client.</param>
2020-05-02 19:06:29 -04:00
/// <response code="200">Display preferences retrieved.</response>
/// <returns>An <see cref="OkResult"/> containing the display preferences on success, or a <see cref="NotFoundResult"/> if the display preferences could not be found.</returns>
2020-06-20 20:02:07 -04:00
[HttpGet("{displayPreferencesId}")]
2020-04-21 16:01:47 -04:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-08-03 14:01:24 -04:00
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")]
public ActionResult < DisplayPreferencesDto > GetDisplayPreferences (
2020-09-07 20:45:06 -04:00
[FromRoute, Required] string displayPreferencesId ,
2020-09-07 20:46:14 -04:00
[FromQuery, Required] Guid userId ,
2020-09-09 16:28:30 -04:00
[FromQuery, Required] string client )
2020-04-19 14:26:38 -04:00
{
2020-12-04 18:27:31 -05:00
if ( ! Guid . TryParse ( displayPreferencesId , out var itemId ) )
{
itemId = displayPreferencesId . GetMD5 ( ) ;
}
2020-12-04 18:00:11 -05:00
var displayPreferences = _displayPreferencesManager . GetDisplayPreferences ( userId , itemId , client ) ;
2020-12-04 11:16:38 -05:00
var itemPreferences = _displayPreferencesManager . GetItemDisplayPreferences ( displayPreferences . UserId , itemId , displayPreferences . Client ) ;
itemPreferences . ItemId = itemId ;
2020-08-03 14:01:24 -04:00
var dto = new DisplayPreferencesDto
{
Client = displayPreferences . Client ,
2020-12-04 18:00:11 -05:00
Id = displayPreferences . ItemId . ToString ( ) ,
2020-08-03 14:01:24 -04:00
SortBy = itemPreferences . SortBy ,
SortOrder = itemPreferences . SortOrder ,
IndexBy = displayPreferences . IndexBy ? . ToString ( ) ,
RememberIndexing = itemPreferences . RememberIndexing ,
RememberSorting = itemPreferences . RememberSorting ,
ScrollDirection = displayPreferences . ScrollDirection ,
ShowBackdrop = displayPreferences . ShowBackdrop ,
ShowSidebar = displayPreferences . ShowSidebar
} ;
foreach ( var homeSection in displayPreferences . HomeSections )
{
dto . CustomPrefs [ "homesection" + homeSection . Order ] = homeSection . Type . ToString ( ) . ToLowerInvariant ( ) ;
}
dto . CustomPrefs [ "chromecastVersion" ] = displayPreferences . ChromecastVersion . ToString ( ) . ToLowerInvariant ( ) ;
dto . CustomPrefs [ "skipForwardLength" ] = displayPreferences . SkipForwardLength . ToString ( CultureInfo . InvariantCulture ) ;
dto . CustomPrefs [ "skipBackLength" ] = displayPreferences . SkipBackwardLength . ToString ( CultureInfo . InvariantCulture ) ;
dto . CustomPrefs [ "enableNextVideoInfoOverlay" ] = displayPreferences . EnableNextVideoInfoOverlay . ToString ( CultureInfo . InvariantCulture ) ;
dto . CustomPrefs [ "tvhome" ] = displayPreferences . TvHome ;
2020-12-03 15:51:12 -05:00
// Load all custom display preferences
2020-12-04 18:00:11 -05:00
var customDisplayPreferences = _displayPreferencesManager . ListCustomItemDisplayPreferences ( displayPreferences . UserId , itemId , displayPreferences . Client ) ;
2020-12-03 15:51:12 -05:00
if ( customDisplayPreferences ! = null )
{
foreach ( var ( key , value ) in customDisplayPreferences )
{
2020-12-03 16:35:18 -05:00
dto . CustomPrefs . TryAdd ( key , value ) ;
2020-12-03 15:51:12 -05:00
}
}
2020-11-02 03:23:29 -05:00
// This will essentially be a noop if no changes have been made, but new prefs must be saved at least.
_displayPreferencesManager . SaveChanges ( ) ;
2020-08-03 14:01:24 -04:00
return dto ;
2020-04-19 14:26:38 -04:00
}
/// <summary>
2020-04-19 14:30:10 -04:00
/// Update Display Preferences.
2020-04-19 14:26:38 -04:00
/// </summary>
/// <param name="displayPreferencesId">Display preferences id.</param>
/// <param name="userId">User Id.</param>
/// <param name="client">Client.</param>
/// <param name="displayPreferences">New Display Preferences object.</param>
2020-06-20 20:02:07 -04:00
/// <response code="204">Display preferences updated.</response>
2020-06-21 11:33:34 -04:00
/// <returns>An <see cref="NoContentResult"/> on success.</returns>
2020-06-20 20:02:07 -04:00
[HttpPost("{displayPreferencesId}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")]
2020-04-21 16:01:47 -04:00
public ActionResult UpdateDisplayPreferences (
2020-09-07 20:45:06 -04:00
[FromRoute, Required] string displayPreferencesId ,
2020-08-06 10:17:45 -04:00
[FromQuery, Required] Guid userId ,
2020-09-09 16:28:30 -04:00
[FromQuery, Required] string client ,
2020-08-06 10:17:45 -04:00
[FromBody, Required] DisplayPreferencesDto displayPreferences )
2020-04-19 14:26:38 -04:00
{
2020-08-03 14:01:24 -04:00
HomeSectionType [ ] defaults =
{
HomeSectionType . SmallLibraryTiles ,
HomeSectionType . Resume ,
HomeSectionType . ResumeAudio ,
HomeSectionType . LiveTv ,
HomeSectionType . NextUp ,
HomeSectionType . LatestMedia , HomeSectionType . None ,
} ;
2020-12-04 18:27:31 -05:00
if ( ! Guid . TryParse ( displayPreferencesId , out var itemId ) )
{
itemId = displayPreferencesId . GetMD5 ( ) ;
}
2020-12-04 18:00:11 -05:00
var existingDisplayPreferences = _displayPreferencesManager . GetDisplayPreferences ( userId , itemId , client ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . IndexBy = Enum . TryParse < IndexingKind > ( displayPreferences . IndexBy , true , out var indexBy ) ? indexBy : ( IndexingKind ? ) null ;
existingDisplayPreferences . ShowBackdrop = displayPreferences . ShowBackdrop ;
existingDisplayPreferences . ShowSidebar = displayPreferences . ShowSidebar ;
existingDisplayPreferences . ScrollDirection = displayPreferences . ScrollDirection ;
existingDisplayPreferences . ChromecastVersion = displayPreferences . CustomPrefs . TryGetValue ( "chromecastVersion" , out var chromecastVersion )
? Enum . Parse < ChromecastVersion > ( chromecastVersion , true )
: ChromecastVersion . Stable ;
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( "chromecastVersion" ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . EnableNextVideoInfoOverlay = displayPreferences . CustomPrefs . TryGetValue ( "enableNextVideoInfoOverlay" , out var enableNextVideoInfoOverlay )
? bool . Parse ( enableNextVideoInfoOverlay )
: true ;
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( "enableNextVideoInfoOverlay" ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . SkipBackwardLength = displayPreferences . CustomPrefs . TryGetValue ( "skipBackLength" , out var skipBackLength )
? int . Parse ( skipBackLength , CultureInfo . InvariantCulture )
: 10000 ;
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( "skipBackLength" ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . SkipForwardLength = displayPreferences . CustomPrefs . TryGetValue ( "skipForwardLength" , out var skipForwardLength )
? int . Parse ( skipForwardLength , CultureInfo . InvariantCulture )
: 30000 ;
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( "skipForwardLength" ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . DashboardTheme = displayPreferences . CustomPrefs . TryGetValue ( "dashboardTheme" , out var theme )
? theme
: string . Empty ;
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( "dashboardTheme" ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . TvHome = displayPreferences . CustomPrefs . TryGetValue ( "tvhome" , out var home )
? home
: string . Empty ;
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( "tvhome" ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . HomeSections . Clear ( ) ;
foreach ( var key in displayPreferences . CustomPrefs . Keys . Where ( key = > key . StartsWith ( "homesection" , StringComparison . OrdinalIgnoreCase ) ) )
{
var order = int . Parse ( key . AsSpan ( ) . Slice ( "homesection" . Length ) ) ;
if ( ! Enum . TryParse < HomeSectionType > ( displayPreferences . CustomPrefs [ key ] , true , out var type ) )
{
type = order < 7 ? defaults [ order ] : HomeSectionType . None ;
}
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( key ) ;
2020-08-03 14:01:24 -04:00
existingDisplayPreferences . HomeSections . Add ( new HomeSection { Order = order , Type = type } ) ;
}
foreach ( var key in displayPreferences . CustomPrefs . Keys . Where ( key = > key . StartsWith ( "landing-" , StringComparison . OrdinalIgnoreCase ) ) )
{
2020-12-10 09:41:00 -05:00
if ( ! Enum . TryParse < ViewType > ( displayPreferences . CustomPrefs [ key ] , true , out var type ) )
2020-12-03 15:51:12 -05:00
{
2020-12-10 22:35:00 -05:00
_logger . LogError ( "Invalid ViewType: {LandingScreenOption}" , displayPreferences . CustomPrefs [ key ] ) ;
2020-12-03 15:51:12 -05:00
displayPreferences . CustomPrefs . Remove ( key ) ;
}
2020-08-03 14:01:24 -04:00
}
2020-12-04 11:16:38 -05:00
var itemPrefs = _displayPreferencesManager . GetItemDisplayPreferences ( existingDisplayPreferences . UserId , itemId , existingDisplayPreferences . Client ) ;
2020-08-03 14:01:24 -04:00
itemPrefs . SortBy = displayPreferences . SortBy ;
itemPrefs . SortOrder = displayPreferences . SortOrder ;
itemPrefs . RememberIndexing = displayPreferences . RememberIndexing ;
itemPrefs . RememberSorting = displayPreferences . RememberSorting ;
2020-12-04 11:16:38 -05:00
itemPrefs . ItemId = itemId ;
2020-08-03 14:01:24 -04:00
2020-12-03 15:51:12 -05:00
// Set all remaining custom preferences.
2020-12-04 18:00:11 -05:00
_displayPreferencesManager . SetCustomItemDisplayPreferences ( userId , itemId , existingDisplayPreferences . Client , displayPreferences . CustomPrefs ) ;
2020-08-08 13:39:49 -04:00
_displayPreferencesManager . SaveChanges ( ) ;
2020-04-21 09:55:57 -04:00
2020-06-20 20:02:07 -04:00
return NoContent ( ) ;
2020-04-19 14:26:38 -04:00
}
2020-04-19 14:06:18 -04:00
}
}