@ -4,6 +4,7 @@ using System.IO;
using System.Linq ;
using System.Linq ;
using System.Text ;
using System.Text ;
using System.Threading ;
using System.Threading ;
using System.Threading.Tasks ;
using System.Xml ;
using System.Xml ;
using MediaBrowser.Controller.Configuration ;
using MediaBrowser.Controller.Configuration ;
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Controller.Entities ;
@ -20,11 +21,6 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <inheritdoc />
/// <inheritdoc />
public abstract class BaseXmlSaver : IMetadataFileSaver
public abstract class BaseXmlSaver : IMetadataFileSaver
{
{
/// <summary>
/// Gets the date added format.
/// </summary>
public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss" ;
/// <summary>
/// <summary>
/// Initializes a new instance of the <see cref="BaseXmlSaver"/> class.
/// Initializes a new instance of the <see cref="BaseXmlSaver"/> class.
/// </summary>
/// </summary>
@ -82,9 +78,7 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="item">The item.</param>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
/// <returns>System.String.</returns>
protected virtual string GetRootElementName ( BaseItem item )
protected virtual string GetRootElementName ( BaseItem item )
{
= > "Item" ;
return "Item" ;
}
/// <summary>
/// <summary>
/// Determines whether [is enabled for] [the specified item].
/// Determines whether [is enabled for] [the specified item].
@ -95,23 +89,10 @@ namespace MediaBrowser.LocalMetadata.Savers
public abstract bool IsEnabledFor ( BaseItem item , ItemUpdateType updateType ) ;
public abstract bool IsEnabledFor ( BaseItem item , ItemUpdateType updateType ) ;
/// <inheritdoc />
/// <inheritdoc />
public void Save ( BaseItem item , CancellationToken cancellationToken )
public async Task SaveAsync ( BaseItem item , CancellationToken cancellationToken )
{
{
var path = GetSavePath ( item ) ;
var path = GetSavePath ( item ) ;
var directory = Path . GetDirectoryName ( path ) ? ? throw new InvalidDataException ( $"Provided path ({path}) is not valid." ) ;
using var memoryStream = new MemoryStream ( ) ;
Save ( item , memoryStream ) ;
memoryStream . Position = 0 ;
cancellationToken . ThrowIfCancellationRequested ( ) ;
SaveToFile ( memoryStream , path ) ;
}
private void SaveToFile ( Stream stream , string path )
{
var directory = Path . GetDirectoryName ( path ) ? ? throw new ArgumentException ( $"Provided path ({path}) is not valid." , nameof ( path ) ) ;
Directory . CreateDirectory ( directory ) ;
Directory . CreateDirectory ( directory ) ;
// On Windows, savint the file will fail if the file is hidden or readonly
// On Windows, savint the file will fail if the file is hidden or readonly
@ -121,13 +102,41 @@ namespace MediaBrowser.LocalMetadata.Savers
{
{
Mode = FileMode . Create ,
Mode = FileMode . Create ,
Access = FileAccess . Write ,
Access = FileAccess . Write ,
Share = FileShare . None ,
Share = FileShare . None
PreallocationSize = stream . Length
} ;
} ;
using ( var filestream = new FileStream ( path , fileStreamOptions ) )
var filestream = new FileStream ( path , fileStreamOptions ) ;
await using ( filestream . ConfigureAwait ( false ) )
{
{
stream . CopyTo ( filestream ) ;
var settings = new XmlWriterSettings
{
Indent = true ,
Encoding = Encoding . UTF8 ,
Async = true
} ;
var writer = XmlWriter . Create ( filestream , settings ) ;
await using ( writer . ConfigureAwait ( false ) )
{
var root = GetRootElementName ( item ) ;
await writer . WriteStartDocumentAsync ( true ) . ConfigureAwait ( false ) ;
await writer . WriteStartElementAsync ( null , root , null ) . ConfigureAwait ( false ) ;
var baseItem = item ;
if ( baseItem ! = null )
{
await AddCommonNodesAsync ( baseItem , writer ) . ConfigureAwait ( false ) ;
}
await WriteCustomElementsAsync ( item , writer ) . ConfigureAwait ( false ) ;
await writer . WriteEndElementAsync ( ) . ConfigureAwait ( false ) ;
await writer . WriteEndDocumentAsync ( ) . ConfigureAwait ( false ) ;
}
}
}
if ( ConfigurationManager . Configuration . SaveMetadataHidden )
if ( ConfigurationManager . Configuration . SaveMetadataHidden )
@ -148,107 +157,76 @@ namespace MediaBrowser.LocalMetadata.Savers
}
}
}
}
private void Save ( BaseItem item , Stream stream )
{
var settings = new XmlWriterSettings
{
Indent = true ,
Encoding = Encoding . UTF8 ,
CloseOutput = false
} ;
using ( var writer = XmlWriter . Create ( stream , settings ) )
{
var root = GetRootElementName ( item ) ;
writer . WriteStartDocument ( true ) ;
writer . WriteStartElement ( root ) ;
var baseItem = item ;
if ( baseItem ! = null )
{
AddCommonNodes ( baseItem , writer , LibraryManager ) ;
}
WriteCustomElements ( item , writer ) ;
writer . WriteEndElement ( ) ;
writer . WriteEndDocument ( ) ;
}
}
/// <summary>
/// <summary>
/// Write custom elements.
/// Write custom elements.
/// </summary>
/// </summary>
/// <param name="item">The item.</param>
/// <param name="item">The item.</param>
/// <param name="writer">The xml writer.</param>
/// <param name="writer">The xml writer.</param>
protected abstract void WriteCustomElements ( BaseItem item , XmlWriter writer ) ;
/// <returns>The task object representing the asynchronous operation.</returns>
protected abstract Task WriteCustomElementsAsync ( BaseItem item , XmlWriter writer ) ;
/// <summary>
/// <summary>
/// Adds the common nodes.
/// Adds the common nodes.
/// </summary>
/// </summary>
/// <param name="item">The item.</param>
/// <param name="item">The item.</param>
/// <param name="writer">The xml writer.</param>
/// <param name="writer">The xml writer.</param>
/// < param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param >
/// <returns>The task object representing the asynchronous operation.</returns>
p ublic static void AddCommonNodes ( BaseItem item , XmlWriter writ er, ILibraryManager libraryManag er)
private async Task AddCommonNodesAsync ( BaseItem item , XmlWriter writer )
{
{
if ( ! string . IsNullOrEmpty ( item . OfficialRating ) )
if ( ! string . IsNullOrEmpty ( item . OfficialRating ) )
{
{
writer . WriteElementString ( "ContentRating" , item . OfficialRating ) ;
await writer . WriteElementStringAsync ( null , "ContentRating" , null , item . OfficialRating ) . ConfigureAwait ( false ) ;
}
}
writer . WriteElementString ( "Added" , item . DateCreated . ToLocalTime ( ) . ToString ( "G" , CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementStringAsync ( null , "Added" , null , item . DateCreated . ToLocalTime ( ) . ToString ( "G" , CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
writer . WriteElementString ( "LockData" , item . IsLocked . ToString ( CultureInfo . InvariantCulture ) . ToLowerInvariant ( ) ) ;
await writer . WriteElementStringAsync ( null , "LockData" , null , item . IsLocked . ToString ( CultureInfo . InvariantCulture ) . ToLowerInvariant ( ) ) . ConfigureAwait ( false ) ;
if ( item . LockedFields . Length > 0 )
if ( item . LockedFields . Length > 0 )
{
{
writer . WriteElementString ( "LockedFields" , string . Join ( '|' , item . LockedFields ) ) ;
await writer . WriteElementStringAsync ( null , "LockedFields" , null , string . Join ( '|' , item . LockedFields ) ) . ConfigureAwait ( false ) ;
}
}
if ( item . CriticRating . HasValue )
if ( item . CriticRating . HasValue )
{
{
writer . WriteElementString ( "CriticRating" , item . CriticRating . Value . ToString ( CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "CriticRating" , null , item . CriticRating . Value . ToString ( CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
if ( ! string . IsNullOrEmpty ( item . Overview ) )
if ( ! string . IsNullOrEmpty ( item . Overview ) )
{
{
writer . WriteElementString ( "Overview" , item . Overview ) ;
await writer . WriteElementString Async ( null , "Overview" , null , item . Overview ) . ConfigureAwait ( false ) ;
}
}
if ( ! string . IsNullOrEmpty ( item . OriginalTitle ) )
if ( ! string . IsNullOrEmpty ( item . OriginalTitle ) )
{
{
writer . WriteElementString ( "OriginalTitle" , item . OriginalTitl e) ;
await writer . WriteElementString Async ( null , "OriginalTitle" , null , item . OriginalTitl e) . ConfigureAwait ( fals e) ;
}
}
if ( ! string . IsNullOrEmpty ( item . CustomRating ) )
if ( ! string . IsNullOrEmpty ( item . CustomRating ) )
{
{
writer . WriteElementString ( "CustomRating" , item . CustomRating ) ;
await writer . WriteElementString Async ( null , "CustomRating" , null , item . CustomRating ) . ConfigureAwait ( false ) ;
}
}
if ( ! string . IsNullOrEmpty ( item . Name ) & & item is not Episode )
if ( ! string . IsNullOrEmpty ( item . Name ) & & item is not Episode )
{
{
writer . WriteElementString ( "LocalTitle" , item . Nam e) ;
await writer . WriteElementString Async ( null , "LocalTitle" , null , item . Nam e) . ConfigureAwait ( fals e) ;
}
}
var forcedSortName = item . ForcedSortName ;
var forcedSortName = item . ForcedSortName ;
if ( ! string . IsNullOrEmpty ( forcedSortName ) )
if ( ! string . IsNullOrEmpty ( forcedSortName ) )
{
{
writer . WriteElementString ( "SortTitle" , forcedSortNam e) ;
await writer . WriteElementString Async ( null , "SortTitle" , null , forcedSortNam e) . ConfigureAwait ( fals e) ;
}
}
if ( item . PremiereDate . HasValue )
if ( item . PremiereDate . HasValue )
{
{
if ( item is Person )
if ( item is Person )
{
{
writer . WriteElementString ( "BirthDate" , item . PremiereDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "BirthDate" , null , item . PremiereDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
else if ( item is not Episode )
else if ( item is not Episode )
{
{
writer . WriteElementString ( "PremiereDate" , item . PremiereDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "PremiereDate" , null , item . PremiereDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
}
}
@ -256,69 +234,69 @@ namespace MediaBrowser.LocalMetadata.Savers
{
{
if ( item is Person )
if ( item is Person )
{
{
writer . WriteElementString ( "DeathDate" , item . EndDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "DeathDate" , null , item . EndDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
else if ( item is not Episode )
else if ( item is not Episode )
{
{
writer . WriteElementString ( "EndDate" , item . EndDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "EndDate" , null , item . EndDate . Value . ToLocalTime ( ) . ToString ( "yyyy-MM-dd" , CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
}
}
if ( item . RemoteTrailers . Count > 0 )
if ( item . RemoteTrailers . Count > 0 )
{
{
writer . WriteStartElement ( "Trailers" ) ;
await writer . WriteStartElement Async ( null , "Trailers" , null ) . ConfigureAwait ( false ) ;
foreach ( var trailer in item . RemoteTrailers )
foreach ( var trailer in item . RemoteTrailers )
{
{
writer . WriteElementString ( "Trailer" , trailer . Url ) ;
await writer . WriteElementString Async ( null , "Trailer" , null , trailer . Url ) . ConfigureAwait ( false ) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
if ( item . ProductionLocations . Length > 0 )
if ( item . ProductionLocations . Length > 0 )
{
{
writer . WriteStartElement ( "Countries" ) ;
await writer . WriteStartElement Async ( null , "Countries" , null ) . ConfigureAwait ( false ) ;
foreach ( var name in item . ProductionLocations )
foreach ( var name in item . ProductionLocations )
{
{
writer . WriteElementString ( "Country" , nam e) ;
await writer . WriteElementString Async ( null , "Country" , null , nam e) . ConfigureAwait ( fals e) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
if ( item is IHasDisplayOrder hasDisplayOrder & & ! string . IsNullOrEmpty ( hasDisplayOrder . DisplayOrder ) )
if ( item is IHasDisplayOrder hasDisplayOrder & & ! string . IsNullOrEmpty ( hasDisplayOrder . DisplayOrder ) )
{
{
writer . WriteElementString ( "DisplayOrder" , hasDisplayOrder . DisplayOrder ) ;
await writer . WriteElementString Async ( null , "DisplayOrder" , null , hasDisplayOrder . DisplayOrder ) . ConfigureAwait ( false ) ;
}
}
if ( item . CommunityRating . HasValue )
if ( item . CommunityRating . HasValue )
{
{
writer . WriteElementString ( "Rating" , item . CommunityRating . Value . ToString ( CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "Rating" , null , item . CommunityRating . Value . ToString ( CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
if ( item . ProductionYear . HasValue & & item is not Person )
if ( item . ProductionYear . HasValue & & item is not Person )
{
{
writer . WriteElementString ( "ProductionYear" , item . ProductionYear . Value . ToString ( CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "ProductionYear" , null , item . ProductionYear . Value . ToString ( CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
if ( item is IHasAspectRatio hasAspectRatio )
if ( item is IHasAspectRatio hasAspectRatio )
{
{
if ( ! string . IsNullOrEmpty ( hasAspectRatio . AspectRatio ) )
if ( ! string . IsNullOrEmpty ( hasAspectRatio . AspectRatio ) )
{
{
writer . WriteElementString ( "AspectRatio" , hasAspectRatio . AspectRatio ) ;
await writer . WriteElementString Async ( null , "AspectRatio" , null , hasAspectRatio . AspectRatio ) . ConfigureAwait ( false ) ;
}
}
}
}
if ( ! string . IsNullOrEmpty ( item . PreferredMetadataLanguage ) )
if ( ! string . IsNullOrEmpty ( item . PreferredMetadataLanguage ) )
{
{
writer . WriteElementString ( "Language" , item . PreferredMetadataLanguag e) ;
await writer . WriteElementString Async ( null , "Language" , null , item . PreferredMetadataLanguag e) . ConfigureAwait ( fals e) ;
}
}
if ( ! string . IsNullOrEmpty ( item . PreferredMetadataCountryCode ) )
if ( ! string . IsNullOrEmpty ( item . PreferredMetadataCountryCode ) )
{
{
writer . WriteElementString ( "CountryCode" , item . PreferredMetadataCountryCod e) ;
await writer . WriteElementString Async ( null , "CountryCode" , null , item . PreferredMetadataCountryCod e) . ConfigureAwait ( fals e) ;
}
}
// Use original runtime here, actual file runtime later in MediaInfo
// Use original runtime here, actual file runtime later in MediaInfo
@ -328,7 +306,7 @@ namespace MediaBrowser.LocalMetadata.Savers
{
{
var timespan = TimeSpan . FromTicks ( runTimeTicks . Value ) ;
var timespan = TimeSpan . FromTicks ( runTimeTicks . Value ) ;
writer . WriteElementString ( "RunningTime" , Math . Floor ( timespan . TotalMinutes ) . ToString ( CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "RunningTime" , null , Math . Floor ( timespan . TotalMinutes ) . ToString ( CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
if ( item . ProviderIds ! = null )
if ( item . ProviderIds ! = null )
@ -338,94 +316,94 @@ namespace MediaBrowser.LocalMetadata.Savers
var providerId = item . ProviderIds [ providerKey ] ;
var providerId = item . ProviderIds [ providerKey ] ;
if ( ! string . IsNullOrEmpty ( providerId ) )
if ( ! string . IsNullOrEmpty ( providerId ) )
{
{
writer . WriteElementString ( providerKey + "Id" , providerId ) ;
await writer . WriteElementString Async ( null , providerKey + "Id" , null , providerId ) . ConfigureAwait ( false ) ;
}
}
}
}
}
}
if ( ! string . IsNullOrWhiteSpace ( item . Tagline ) )
if ( ! string . IsNullOrWhiteSpace ( item . Tagline ) )
{
{
writer . WriteStartElement ( "Taglines" ) ;
await writer . WriteStartElement Async ( null , "Taglines" , null ) . ConfigureAwait ( false ) ;
writer . WriteElementString ( "Tagline" , item . Taglin e) ;
await writer . WriteElementString Async ( null , "Tagline" , null , item . Taglin e) . ConfigureAwait ( fals e) ;
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
if ( item . Genres . Length > 0 )
if ( item . Genres . Length > 0 )
{
{
writer . WriteStartElement ( "Genres" ) ;
await writer . WriteStartElement Async ( null , "Genres" , null ) . ConfigureAwait ( false ) ;
foreach ( var genre in item . Genres )
foreach ( var genre in item . Genres )
{
{
writer . WriteElementString ( "Genre" , genr e) ;
await writer . WriteElementString Async ( null , "Genre" , null , genr e) . ConfigureAwait ( fals e) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
if ( item . Studios . Length > 0 )
if ( item . Studios . Length > 0 )
{
{
writer . WriteStartElement ( "Studios" ) ;
await writer . WriteStartElement Async ( null , "Studios" , null ) . ConfigureAwait ( false ) ;
foreach ( var studio in item . Studios )
foreach ( var studio in item . Studios )
{
{
writer . WriteElementString ( "Studio" , studio ) ;
await writer . WriteElementString Async ( null , "Studio" , null , studio ) . ConfigureAwait ( false ) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
if ( item . Tags . Length > 0 )
if ( item . Tags . Length > 0 )
{
{
writer . WriteStartElement ( "Tags" ) ;
await writer . WriteStartElement Async ( null , "Tags" , null ) . ConfigureAwait ( false ) ;
foreach ( var tag in item . Tags )
foreach ( var tag in item . Tags )
{
{
writer . WriteElementString ( "Tag" , tag ) ;
await writer . WriteElementString Async ( null , "Tag" , null , tag ) . ConfigureAwait ( false ) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
var people = l ibraryManager. GetPeople ( item ) ;
var people = L ibraryManager. GetPeople ( item ) ;
if ( people . Count > 0 )
if ( people . Count > 0 )
{
{
writer . WriteStartElement ( "Persons" ) ;
await writer . WriteStartElement Async ( null , "Persons" , null ) . ConfigureAwait ( false ) ;
foreach ( var person in people )
foreach ( var person in people )
{
{
writer . WriteStartElement ( "Person" ) ;
await writer . WriteStartElement Async ( null , "Person" , null ) . ConfigureAwait ( false ) ;
writer . WriteElementString ( "Name" , person . Nam e) ;
await writer . WriteElementString Async ( null , "Name" , null , person . Nam e) . ConfigureAwait ( fals e) ;
writer . WriteElementString ( "Type" , person . Typ e) ;
await writer . WriteElementString Async ( null , "Type" , null , person . Typ e) . ConfigureAwait ( fals e) ;
writer . WriteElementString ( "Role" , person . Rol e) ;
await writer . WriteElementString Async ( null , "Role" , null , person . Rol e) . ConfigureAwait ( fals e) ;
if ( person . SortOrder . HasValue )
if ( person . SortOrder . HasValue )
{
{
writer . WriteElementString ( "SortOrder" , person . SortOrder . Value . ToString ( CultureInfo . InvariantCulture ) ) ;
await writer . WriteElementString Async ( null , "SortOrder" , null , person . SortOrder . Value . ToString ( CultureInfo . InvariantCulture ) ) . ConfigureAwait ( false ) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
if ( item is BoxSet boxset )
if ( item is BoxSet boxset )
{
{
AddLinkedChildren ( boxset , writer , "CollectionItems" , "CollectionItem" ) ;
await AddLinkedChildren ( boxset , writer , "CollectionItems" , "CollectionItem" ) . ConfigureAwait ( false ) ;
}
}
if ( item is Playlist playlist & & ! Playlist . IsPlaylistFile ( playlist . Path ) )
if ( item is Playlist playlist & & ! Playlist . IsPlaylistFile ( playlist . Path ) )
{
{
AddLinkedChildren ( playlist , writer , "PlaylistItems" , "PlaylistItem" ) ;
await AddLinkedChildren ( playlist , writer , "PlaylistItems" , "PlaylistItem" ) . ConfigureAwait ( false ) ;
}
}
if ( item is IHasShares hasShares )
if ( item is IHasShares hasShares )
{
{
AddShares ( hasShares , writer ) ;
await AddShares Async ( hasShares , writer ) . ConfigureAwait ( false ) ;
}
}
AddMediaInfo ( item , writer ) ;
await AddMediaInfo ( item , writer ) . ConfigureAwait ( false ) ;
}
}
/// <summary>
/// <summary>
@ -433,23 +411,26 @@ namespace MediaBrowser.LocalMetadata.Savers
/// </summary>
/// </summary>
/// <param name="item">The item.</param>
/// <param name="item">The item.</param>
/// <param name="writer">The xml writer.</param>
/// <param name="writer">The xml writer.</param>
public static void AddShares ( IHasShares item , XmlWriter writer )
/// <returns>The task object representing the asynchronous operation.</returns>
private static async Task AddSharesAsync ( IHasShares item , XmlWriter writer )
{
{
writer . WriteStartElement ( "Shares" ) ;
await writer . WriteStartElement Async ( null , "Shares" , null ) . ConfigureAwait ( false ) ;
foreach ( var share in item . Shares )
foreach ( var share in item . Shares )
{
{
writer . WriteStartElement ( "Share" ) ;
await writer . WriteStartElement Async ( null , "Share" , null ) . ConfigureAwait ( false ) ;
writer . WriteElementString ( "UserId" , share . UserId ) ;
await writer . WriteElementStringAsync ( null , "UserId" , null , share . UserId ) . ConfigureAwait ( false ) ;
writer . WriteElementString (
await writer . WriteElementStringAsync (
null ,
"CanEdit" ,
"CanEdit" ,
share . CanEdit . ToString ( CultureInfo . InvariantCulture ) . ToLowerInvariant ( ) ) ;
null ,
share . CanEdit . ToString ( CultureInfo . InvariantCulture ) . ToLowerInvariant ( ) ) . ConfigureAwait ( false ) ;
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
/// <summary>
/// <summary>
@ -458,33 +439,29 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="item">The item.</param>
/// <param name="item">The item.</param>
/// <param name="writer">The xml writer.</param>
/// <param name="writer">The xml writer.</param>
/// <typeparam name="T">Type of item.</typeparam>
/// <typeparam name="T">Type of item.</typeparam>
public static void AddMediaInfo < T > ( T item , XmlWriter writer )
/// <returns>The task object representing the asynchronous operation.</returns>
private static Task AddMediaInfo < T > ( T item , XmlWriter writer )
where T : BaseItem
where T : BaseItem
{
{
if ( item is Video video )
if ( item is Video video & & video . Video3DFormat . HasValue )
{
{
if ( video . Video3DFormat . HasValue )
return video . Video3DFormat switch
{
{
switch ( video . Video3DFormat . Value )
Video3DFormat . FullSideBySide = >
{
writer . WriteElementStringAsync ( null , "Format3D" , null , "FSBS" ) ,
case Video3DFormat . FullSideBySide :
Video3DFormat . FullTopAndBottom = >
writer . WriteElementString ( "Format3D" , "FSBS" ) ;
writer . WriteElementStringAsync ( null , "Format3D" , null , "FTAB" ) ,
break ;
Video3DFormat . HalfSideBySide = >
case Video3DFormat . FullTopAndBottom :
writer . WriteElementStringAsync ( null , "Format3D" , null , "HSBS" ) ,
writer . WriteElementString ( "Format3D" , "FTAB" ) ;
Video3DFormat . HalfTopAndBottom = >
break ;
writer . WriteElementStringAsync ( null , "Format3D" , null , "HTAB" ) ,
case Video3DFormat . HalfSideBySide :
Video3DFormat . MVC = >
writer . WriteElementString ( "Format3D" , "HSBS" ) ;
writer . WriteElementStringAsync ( null , "Format3D" , null , "MVC" ) ,
break ;
_ = > Task . CompletedTask
case Video3DFormat . HalfTopAndBottom :
} ;
writer . WriteElementString ( "Format3D" , "HTAB" ) ;
}
break ;
case Video3DFormat . MVC :
return Task . CompletedTask ;
writer . WriteElementString ( "Format3D" , "MVC" ) ;
break ;
}
}
}
}
}
/// <summary>
/// <summary>
@ -494,7 +471,8 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="writer">The xml writer.</param>
/// <param name="writer">The xml writer.</param>
/// <param name="pluralNodeName">The plural node name.</param>
/// <param name="pluralNodeName">The plural node name.</param>
/// <param name="singularNodeName">The singular node name.</param>
/// <param name="singularNodeName">The singular node name.</param>
public static void AddLinkedChildren ( Folder item , XmlWriter writer , string pluralNodeName , string singularNodeName )
/// <returns>The task object representing the asynchronous operation.</returns>
private static async Task AddLinkedChildren ( Folder item , XmlWriter writer , string pluralNodeName , string singularNodeName )
{
{
var items = item . LinkedChildren
var items = item . LinkedChildren
. Where ( i = > i . Type = = LinkedChildType . Manual )
. Where ( i = > i . Type = = LinkedChildType . Manual )
@ -505,28 +483,28 @@ namespace MediaBrowser.LocalMetadata.Savers
return ;
return ;
}
}
writer . WriteStartElement ( pluralNodeNam e) ;
await writer . WriteStartElement Async ( null , pluralNodeNam e, null ) . ConfigureAwait ( fals e) ;
foreach ( var link in items )
foreach ( var link in items )
{
{
if ( ! string . IsNullOrWhiteSpace ( link . Path ) | | ! string . IsNullOrWhiteSpace ( link . LibraryItemId ) )
if ( ! string . IsNullOrWhiteSpace ( link . Path ) | | ! string . IsNullOrWhiteSpace ( link . LibraryItemId ) )
{
{
writer . WriteStartElement ( singularNodeNam e) ;
await writer . WriteStartElement Async ( null , singularNodeNam e, null ) . ConfigureAwait ( fals e) ;
if ( ! string . IsNullOrWhiteSpace ( link . Path ) )
if ( ! string . IsNullOrWhiteSpace ( link . Path ) )
{
{
writer . WriteElementString ( "Path" , link . Path ) ;
await writer . WriteElementString Async ( null , "Path" , null , link . Path ) . ConfigureAwait ( false ) ;
}
}
if ( ! string . IsNullOrWhiteSpace ( link . LibraryItemId ) )
if ( ! string . IsNullOrWhiteSpace ( link . LibraryItemId ) )
{
{
writer . WriteElementString ( "ItemId" , link . LibraryItemId ) ;
await writer . WriteElementString Async ( null , "ItemId" , null , link . LibraryItemId ) . ConfigureAwait ( false ) ;
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
}
}
writer . WriteEndElement ( ) ;
await writer . WriteEndElement Async ( ) . ConfigureAwait ( false ) ;
}
}
}
}
}
}