mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-16 02:18:54 -07:00
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
This commit is contained in:
commit
7c5613fc51
@ -353,11 +353,9 @@ namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
crf = "12";
|
||||
profileScore = 2;
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
crf = "8";
|
||||
profileScore = 1;
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
crf = "4";
|
||||
@ -369,10 +367,11 @@ namespace MediaBrowser.Api.Playback
|
||||
if (isVc1)
|
||||
{
|
||||
profileScore++;
|
||||
// Max of 2
|
||||
profileScore = Math.Min(profileScore, 2);
|
||||
}
|
||||
|
||||
// Max of 2
|
||||
profileScore = Math.Min(profileScore, 2);
|
||||
|
||||
// http://www.webmproject.org/docs/encoder-parameters/
|
||||
param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1}",
|
||||
profileScore.ToString(UsCulture),
|
||||
@ -771,13 +770,31 @@ namespace MediaBrowser.Api.Playback
|
||||
return "copy";
|
||||
}
|
||||
|
||||
protected virtual bool SupportsThrottling
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input argument.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected virtual string GetInputArgument(StreamState state)
|
||||
protected string GetInputArgument(StreamState state)
|
||||
{
|
||||
if (state.InputProtocol == MediaProtocol.File &&
|
||||
state.RunTimeTicks.HasValue &&
|
||||
state.VideoType == VideoType.VideoFile &&
|
||||
!string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
|
||||
{
|
||||
var url = "http://localhost:8096/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
|
||||
|
||||
return string.Format("\"{0}\"", url);
|
||||
}
|
||||
}
|
||||
|
||||
var protocol = state.InputProtocol;
|
||||
|
||||
var inputPath = new[] { state.MediaPath };
|
||||
@ -1494,6 +1511,7 @@ namespace MediaBrowser.Api.Playback
|
||||
state.MediaPath = mediaSource.Path;
|
||||
state.RunTimeTicks = item.RunTimeTicks;
|
||||
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
|
||||
state.InputBitrate = mediaSource.Bitrate;
|
||||
mediaStreams = mediaSource.MediaStreams;
|
||||
}
|
||||
else
|
||||
@ -1508,6 +1526,7 @@ namespace MediaBrowser.Api.Playback
|
||||
state.MediaPath = mediaSource.Path;
|
||||
state.InputProtocol = mediaSource.Protocol;
|
||||
state.InputContainer = mediaSource.Container;
|
||||
state.InputBitrate = mediaSource.Bitrate;
|
||||
|
||||
if (item is Video)
|
||||
{
|
||||
|
@ -79,6 +79,14 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||
return ResultFactory.GetStaticFileResult(Request, file);
|
||||
}
|
||||
|
||||
protected override bool SupportsThrottling
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [begin request].
|
||||
/// </summary>
|
||||
|
@ -151,7 +151,9 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||
|
||||
using (state)
|
||||
{
|
||||
return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest);
|
||||
var throttleLimit = state.InputBitrate.HasValue ? (state.InputBitrate.Value / 8) : 0;
|
||||
|
||||
return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest, request.Throttle, throttleLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,8 @@ namespace MediaBrowser.Api.Playback
|
||||
public string DeviceProfileId { get; set; }
|
||||
|
||||
public string Params { get; set; }
|
||||
|
||||
public bool Throttle { get; set; }
|
||||
}
|
||||
|
||||
public class VideoStreamRequest : StreamRequest
|
||||
|
@ -68,6 +68,8 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
public long? RunTimeTicks;
|
||||
|
||||
public long? InputBitrate { get; set; }
|
||||
|
||||
public string OutputAudioSync = "1";
|
||||
public string OutputVideoSync = "vfr";
|
||||
|
||||
|
@ -38,8 +38,10 @@ namespace MediaBrowser.Api.System
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is currently not authenticated because the uninstaller needs to be able to shutdown the server.
|
||||
/// </summary>
|
||||
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
|
||||
[Authenticated]
|
||||
public class ShutdownApplication
|
||||
{
|
||||
}
|
||||
|
@ -1430,7 +1430,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
nextId = list[index + 1].Id;
|
||||
}
|
||||
|
||||
return list.Where(i => i.Id == previousId || i.Id == nextId);
|
||||
return list.Where(i => i.Id == previousId || i.Id == nextId || i.Id == adjacentToIdGuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -26,16 +26,13 @@ namespace MediaBrowser.Common.Implementations.Security
|
||||
|
||||
var mac = _networkManager.GetMacAddress();
|
||||
|
||||
var plugins = string.Join("|", _applicationHost.Plugins.Select(i => i.Name).ToArray());
|
||||
|
||||
var data = new Dictionary<string, string>
|
||||
{
|
||||
{ "feature", _applicationHost.Name },
|
||||
{ "mac", mac },
|
||||
{ "ver", _applicationHost.ApplicationVersion.ToString() },
|
||||
{ "platform", Environment.OSVersion.VersionString },
|
||||
{ "isservice", _applicationHost.IsRunningAsService.ToString().ToLower()},
|
||||
{ "plugins", plugins}
|
||||
{ "isservice", _applicationHost.IsRunningAsService.ToString().ToLower()}
|
||||
};
|
||||
|
||||
return _httpClient.Post(Constants.Constants.MbAdminUrl + "service/registration/ping", data, cancellationToken);
|
||||
|
9
MediaBrowser.Controller/Connect/IConnectManager.cs
Normal file
9
MediaBrowser.Controller/Connect/IConnectManager.cs
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
namespace MediaBrowser.Controller.Connect
|
||||
{
|
||||
public interface IConnectManager
|
||||
{
|
||||
string WanIpAddress { get; }
|
||||
string WanApiAddress { get; }
|
||||
}
|
||||
}
|
@ -71,39 +71,6 @@ namespace MediaBrowser.Controller.Drawing
|
||||
return Encoders.Length == 0 ? null : Encoders[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is pixel format supported by graphics object] [the specified format].
|
||||
/// </summary>
|
||||
/// <param name="format">The format.</param>
|
||||
/// <returns><c>true</c> if [is pixel format supported by graphics object] [the specified format]; otherwise, <c>false</c>.</returns>
|
||||
public static bool IsPixelFormatSupportedByGraphicsObject(PixelFormat format)
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/system.drawing.graphics.fromimage.aspx
|
||||
|
||||
if ((format & PixelFormat.Indexed) == PixelFormat.Indexed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((format & PixelFormat.Undefined) == PixelFormat.Undefined)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((format & PixelFormat.DontCare) == PixelFormat.DontCare)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((format & PixelFormat.Format16bppArgb1555) == PixelFormat.Format16bppArgb1555)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((format & PixelFormat.Format16bppGrayScale) == PixelFormat.Format16bppGrayScale)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crops an image by removing whitespace and transparency from the edges
|
||||
/// </summary>
|
||||
|
@ -20,7 +20,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
IHasMusicGenres,
|
||||
IHasLookupInfo<SongInfo>,
|
||||
IHasTags,
|
||||
IHasMediaSources
|
||||
IHasMediaSources,
|
||||
IThemeMedia
|
||||
{
|
||||
public string FormatName { get; set; }
|
||||
public long? Size { get; set; }
|
||||
@ -28,9 +29,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
public int? TotalBitrate { get; set; }
|
||||
public List<string> Tags { get; set; }
|
||||
|
||||
public bool IsThemeMedia { get; set; }
|
||||
|
||||
public Audio()
|
||||
{
|
||||
Artists = new List<string>();
|
||||
AlbumArtists = new List<string>();
|
||||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
@ -73,6 +77,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override Folder LatestItemsIndexContainer
|
||||
{
|
||||
get
|
||||
@ -87,12 +92,14 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// <value>The artist.</value>
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<string> AllArtists
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = AlbumArtists;
|
||||
var list = AlbumArtists.ToList();
|
||||
|
||||
list.AddRange(Artists);
|
||||
|
||||
@ -101,36 +108,11 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<string> AlbumArtists
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(AlbumArtist))
|
||||
{
|
||||
list.Add(AlbumArtist);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
set
|
||||
{
|
||||
AlbumArtist = value.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the album.
|
||||
/// </summary>
|
||||
/// <value>The album.</value>
|
||||
public string Album { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the album artist.
|
||||
/// </summary>
|
||||
/// <value>The album artist.</value>
|
||||
public string AlbumArtist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the media.
|
||||
|
@ -17,8 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
|
||||
public MusicAlbum()
|
||||
{
|
||||
Artists = new List<string>();
|
||||
SoundtrackIds = new List<Guid>();
|
||||
Artists = new List<string>();
|
||||
AlbumArtists = new List<string>();
|
||||
}
|
||||
|
||||
public override bool SupportsAddingToPlaylist
|
||||
@ -40,7 +41,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = AlbumArtists;
|
||||
var list = AlbumArtists.ToList();
|
||||
|
||||
list.AddRange(Artists);
|
||||
|
||||
@ -49,24 +50,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<string> AlbumArtists
|
||||
public string AlbumArtist
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(AlbumArtist))
|
||||
{
|
||||
list.Add(AlbumArtist);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
set
|
||||
{
|
||||
AlbumArtist = value.FirstOrDefault();
|
||||
}
|
||||
get { return AlbumArtists.FirstOrDefault(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -139,8 +128,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return AllArtists.Contains(artist, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public string AlbumArtist { get; set; }
|
||||
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -749,7 +749,18 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
|
||||
|
||||
var tasks = newThemeVideos.Select(i => i.RefreshMetadata(options, cancellationToken));
|
||||
var tasks = newThemeVideos.Select(i =>
|
||||
{
|
||||
var subOptions = new MetadataRefreshOptions(options);
|
||||
|
||||
if (!i.IsThemeMedia)
|
||||
{
|
||||
i.IsThemeMedia = true;
|
||||
subOptions.ForceSave = true;
|
||||
}
|
||||
|
||||
return i.RefreshMetadata(subOptions, cancellationToken);
|
||||
});
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
@ -768,7 +779,18 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
|
||||
|
||||
var tasks = newThemeSongs.Select(i => i.RefreshMetadata(options, cancellationToken));
|
||||
var tasks = newThemeSongs.Select(i =>
|
||||
{
|
||||
var subOptions = new MetadataRefreshOptions(options);
|
||||
|
||||
if (!i.IsThemeMedia)
|
||||
{
|
||||
i.IsThemeMedia = true;
|
||||
subOptions.ForceSave = true;
|
||||
}
|
||||
|
||||
return i.RefreshMetadata(subOptions, cancellationToken);
|
||||
});
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
|
8
MediaBrowser.Controller/Entities/IThemeMedia.cs
Normal file
8
MediaBrowser.Controller/Entities/IThemeMedia.cs
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IThemeMedia
|
||||
{
|
||||
bool IsThemeMedia { get; }
|
||||
}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
@ -13,6 +17,14 @@ namespace MediaBrowser.Controller.Entities
|
||||
Taglines = new List<string>();
|
||||
}
|
||||
|
||||
public override bool SupportsLocalMetadata
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
@ -20,5 +32,30 @@ namespace MediaBrowser.Controller.Entities
|
||||
return Model.Entities.MediaType.Photo;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override Folder LatestItemsIndexContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return Parents.OfType<PhotoAlbum>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public int? Width { get; set; }
|
||||
public int? Height { get; set; }
|
||||
public string CameraMake { get; set; }
|
||||
public string CameraModel { get; set; }
|
||||
public string Software { get; set; }
|
||||
public double? ExposureTime { get; set; }
|
||||
public double? FocalLength { get; set; }
|
||||
public ImageOrientation? Orientation { get; set; }
|
||||
public double? Aperture { get; set; }
|
||||
public double? ShutterSpeed { get; set; }
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
MediaBrowser.Controller/Entities/PhotoAlbum.cs
Normal file
21
MediaBrowser.Controller/Entities/PhotoAlbum.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class PhotoAlbum : Folder
|
||||
{
|
||||
public override bool SupportsLocalMetadata
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||
}
|
||||
}
|
||||
}
|
@ -95,6 +95,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override Folder LatestItemsIndexContainer
|
||||
{
|
||||
get
|
||||
|
@ -24,7 +24,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
IHasTags,
|
||||
ISupportsPlaceHolders,
|
||||
IHasMediaSources,
|
||||
IHasShortOverview
|
||||
IHasShortOverview,
|
||||
IThemeMedia
|
||||
{
|
||||
public bool IsMultiPart { get; set; }
|
||||
public bool HasLocalAlternateVersions { get; set; }
|
||||
@ -33,6 +34,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
public List<Guid> AdditionalPartIds { get; set; }
|
||||
public List<Guid> LocalAlternateVersionIds { get; set; }
|
||||
|
||||
public bool IsThemeMedia { get; set; }
|
||||
|
||||
public string FormatName { get; set; }
|
||||
public long? Size { get; set; }
|
||||
public string Container { get; set; }
|
||||
|
@ -99,6 +99,7 @@
|
||||
<Compile Include="Collections\CollectionCreationOptions.cs" />
|
||||
<Compile Include="Collections\CollectionEvents.cs" />
|
||||
<Compile Include="Collections\ICollectionManager.cs" />
|
||||
<Compile Include="Connect\IConnectManager.cs" />
|
||||
<Compile Include="Dlna\ControlRequest.cs" />
|
||||
<Compile Include="Dlna\ControlResponse.cs" />
|
||||
<Compile Include="Dlna\DlnaIconResponse.cs" />
|
||||
@ -150,10 +151,12 @@
|
||||
<Compile Include="Entities\ISupportsBoxSetGrouping.cs" />
|
||||
<Compile Include="Entities\ISupportsPlaceHolders.cs" />
|
||||
<Compile Include="Entities\ItemImageInfo.cs" />
|
||||
<Compile Include="Entities\IThemeMedia.cs" />
|
||||
<Compile Include="Entities\LinkedChild.cs" />
|
||||
<Compile Include="Entities\MusicVideo.cs" />
|
||||
<Compile Include="Entities\IHasAwards.cs" />
|
||||
<Compile Include="Entities\Photo.cs" />
|
||||
<Compile Include="Entities\PhotoAlbum.cs" />
|
||||
<Compile Include="Entities\UserView.cs" />
|
||||
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
|
||||
<Compile Include="Library\DeleteOptions.cs" />
|
||||
|
@ -127,8 +127,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
stream.BitDepth = GetBitDepth(stream.PixelFormat);
|
||||
|
||||
stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(stream.AspectRatio, "2.35:1", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -109,14 +109,18 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <param name="fileShare">The file share.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <param name="throttle">if set to <c>true</c> [throttle].</param>
|
||||
/// <param name="throttleLimit">The throttle limit.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
object GetStaticFileResult(IRequest requestContext,
|
||||
string path,
|
||||
string contentType,
|
||||
TimeSpan? cacheCuration = null,
|
||||
FileShare fileShare = FileShare.Read,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false);
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false,
|
||||
bool throttle = false,
|
||||
long throttleLimit = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the optimized serialized result using cache.
|
||||
|
@ -1,6 +1,7 @@
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
@ -23,6 +24,18 @@ namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
MetadataRefreshMode = MetadataRefreshMode.Default;
|
||||
}
|
||||
|
||||
public MetadataRefreshOptions(MetadataRefreshOptions copy)
|
||||
{
|
||||
MetadataRefreshMode = copy.MetadataRefreshMode;
|
||||
ForceSave = copy.ForceSave;
|
||||
ReplaceAllMetadata = copy.ReplaceAllMetadata;
|
||||
|
||||
ImageRefreshMode = copy.ImageRefreshMode;
|
||||
DirectoryService = copy.DirectoryService;
|
||||
ReplaceAllImages = copy.ReplaceAllImages;
|
||||
ReplaceImages = copy.ReplaceImages.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageRefreshOptions
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using System.Globalization;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using System;
|
||||
@ -188,6 +189,44 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
return string.Equals(extension, ".disc", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is multi disc album folder] [the specified path].
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns><c>true</c> if [is multi disc album folder] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||
public static bool IsMultiDiscAlbumFolder(string path)
|
||||
{
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize
|
||||
// Remove whitespace
|
||||
filename = filename.Replace("-", string.Empty);
|
||||
filename = Regex.Replace(filename, @"\s+", "");
|
||||
|
||||
var prefixes = new[] { "disc", "cd", "disk" };
|
||||
|
||||
foreach (var prefix in prefixes)
|
||||
{
|
||||
if (filename.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
{
|
||||
var tmp = filename.Substring(prefix.Length);
|
||||
|
||||
int val;
|
||||
if (int.TryParse(tmp, NumberStyles.Any, CultureInfo.InvariantCulture, out val))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures DateCreated and DateModified have values
|
||||
/// </summary>
|
||||
|
@ -156,7 +156,7 @@ namespace MediaBrowser.Controller.Session
|
||||
|
||||
public bool ContainsUser(Guid userId)
|
||||
{
|
||||
return (UserId ?? Guid.Empty) == UserId || AdditionalUsers.Any(i => userId == new Guid(i.UserId));
|
||||
return (UserId ?? Guid.Empty) == userId || AdditionalUsers.Any(i => userId == new Guid(i.UserId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error sending Datagram: " + Message, ex);
|
||||
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
||||
}
|
||||
++SendCount;
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Dlna.PlayTo;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -10,7 +8,6 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -75,7 +72,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
}
|
||||
}
|
||||
|
||||
void _ssdpHandler_MessageReceived(object sender, SsdpMessageEventArgs e)
|
||||
void _ssdpHandler_MessageReceived(object sender, SsdpMessageEventArgs e)
|
||||
{
|
||||
string nts;
|
||||
e.Headers.TryGetValue("NTS", out nts);
|
||||
@ -87,10 +84,16 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
EventHelper.FireEventIfNotNull(DeviceLeft, this, e, _logger);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
try
|
||||
{
|
||||
//TryCreateDevice(e, IPAddress.Parse(_networkManager.GetLocalIpAddresses().First()));
|
||||
//var ip = _networkManager.GetLocalIpAddresses().FirstOrDefault();
|
||||
|
||||
//if (ip != null)
|
||||
//{
|
||||
// e.LocalIp = IPAddress.Parse(ip);
|
||||
// TryCreateDevice(e);
|
||||
//}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@ -184,36 +187,6 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
|
||||
}
|
||||
|
||||
private void CreateNotifier(Socket socket)
|
||||
{
|
||||
Task.Factory.StartNew(async (o) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var msg = new SsdpMessageBuilder().BuildRendererDiscoveryMessage();
|
||||
var request = Encoding.UTF8.GetBytes(msg);
|
||||
|
||||
while (true)
|
||||
{
|
||||
socket.SendTo(request, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900));
|
||||
|
||||
var delay = _config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds * 1000;
|
||||
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error in notifier", ex);
|
||||
}
|
||||
|
||||
}, _tokenSource.Token, TaskCreationOptions.LongRunning);
|
||||
|
||||
}
|
||||
|
||||
private Socket GetMulticastSocket(int networkInterfaceIndex)
|
||||
{
|
||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
@ -223,7 +196,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
return socket;
|
||||
}
|
||||
|
||||
private void TryCreateDevice(SsdpMessageEventArgs args)
|
||||
private void TryCreateDevice(SsdpMessageEventArgs args)
|
||||
{
|
||||
string nts;
|
||||
args.Headers.TryGetValue("NTS", out nts);
|
||||
@ -262,7 +235,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
public void Dispose()
|
||||
{
|
||||
_ssdpHandler.MessageReceived -= _ssdpHandler_MessageReceived;
|
||||
|
||||
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
|
@ -146,21 +146,6 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
StartQueueTimer();
|
||||
}
|
||||
|
||||
public void SendDatagramFromDevices(string header,
|
||||
Dictionary<string, string> values,
|
||||
IPEndPoint endpoint,
|
||||
string deviceType)
|
||||
{
|
||||
foreach (var d in RegisteredDevices)
|
||||
{
|
||||
if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RespondToSearch(IPEndPoint endpoint, string deviceType)
|
||||
{
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
@ -185,7 +170,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
values["ST"] = d.Type;
|
||||
values["USN"] = d.USN;
|
||||
|
||||
SendDatagram(header, values, endpoint, null);
|
||||
SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0));
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Dlna.Ssdp
|
||||
@ -23,30 +22,5 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public string BuildDiscoveryMessage(string deviceSearchType, string mx)
|
||||
{
|
||||
const string header = "M-SEARCH * HTTP/1.1";
|
||||
|
||||
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
values["HOST"] = "239.255.255.250:1900";
|
||||
values["USER-AGENT"] = "UPnP/1.0 DLNADOC/1.50 Platinum/1.0.4.2";
|
||||
values["ST"] = "ssdp:all";
|
||||
values["MAN"] = "ssdp:discover";
|
||||
values["MX"] = "10";
|
||||
|
||||
return BuildMessage(header, values);
|
||||
}
|
||||
|
||||
public string BuildRendererDiscoveryMessage()
|
||||
{
|
||||
return BuildDiscoveryMessage("urn:schemas-upnp-org:device:MediaRenderer:1", "3");
|
||||
}
|
||||
|
||||
public string BuildMediaServerDiscoveryMessage()
|
||||
{
|
||||
return BuildDiscoveryMessage("urn:schemas-upnp-org:device:MediaRenderer:1", "3");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
}
|
||||
multiline.Add(line);
|
||||
}
|
||||
subEvent.Text = string.Join(@"\N", multiline);
|
||||
subEvent.Text = string.Join(@"\n", multiline);
|
||||
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
|
||||
subEvent.Text = Regex.Replace(subEvent.Text, "<", "<", RegexOptions.IgnoreCase);
|
||||
subEvent.Text = Regex.Replace(subEvent.Text, ">", ">", RegexOptions.IgnoreCase);
|
||||
|
@ -25,7 +25,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
var text = trackEvent.Text;
|
||||
|
||||
// TODO: Not sure how to handle these
|
||||
text = Regex.Replace(text, @"\\N", " ", RegexOptions.IgnoreCase);
|
||||
text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
|
||||
|
||||
writer.WriteLine(text);
|
||||
writer.WriteLine(string.Empty);
|
||||
|
@ -147,7 +147,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
public static string GetFormattedText(string text)
|
||||
{
|
||||
text = text.Replace("\\N", Environment.NewLine).Replace("\\n", Environment.NewLine);
|
||||
text = text.Replace("\\n", Environment.NewLine).Replace("\\n", Environment.NewLine);
|
||||
bool italic = false;
|
||||
|
||||
for (int i = 0; i < 10; i++) // just look ten times...
|
||||
|
@ -194,15 +194,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
MediaStream subtitleStream,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
const string extractedFormat = "srt";
|
||||
|
||||
if (!subtitleStream.IsExternal)
|
||||
{
|
||||
// Extract
|
||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".ass");
|
||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat);
|
||||
|
||||
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, false, outputPath, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return new Tuple<string, string>(outputPath, "ass");
|
||||
return new Tuple<string, string>(outputPath, extractedFormat);
|
||||
}
|
||||
|
||||
var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
|
||||
@ -211,12 +213,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
if (GetReader(currentFormat, false) == null)
|
||||
{
|
||||
// Convert
|
||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".ass");
|
||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat);
|
||||
|
||||
await ConvertTextSubtitleToAss(subtitleStream.Path, outputPath, subtitleStream.Language, cancellationToken)
|
||||
await ConvertTextSubtitleToSrt(subtitleStream.Path, outputPath, subtitleStream.Language, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return new Tuple<string, string>(outputPath, "ass");
|
||||
return new Tuple<string, string>(outputPath, extractedFormat);
|
||||
}
|
||||
|
||||
return new Tuple<string, string>(subtitleStream.Path, currentFormat);
|
||||
@ -303,14 +305,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the text subtitle to ass.
|
||||
/// Converts the text subtitle to SRT.
|
||||
/// </summary>
|
||||
/// <param name="inputPath">The input path.</param>
|
||||
/// <param name="outputPath">The output path.</param>
|
||||
/// <param name="language">The language.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task ConvertTextSubtitleToAss(string inputPath, string outputPath, string language,
|
||||
public async Task ConvertTextSubtitleToSrt(string inputPath, string outputPath, string language,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var semaphore = GetLock(outputPath);
|
||||
@ -321,7 +323,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
{
|
||||
if (!File.Exists(outputPath))
|
||||
{
|
||||
await ConvertTextSubtitleToAssInternal(inputPath, outputPath, language).ConfigureAwait(false);
|
||||
await ConvertTextSubtitleToSrtInternal(inputPath, outputPath, language).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@ -331,17 +333,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the text subtitle to ass.
|
||||
/// Converts the text subtitle to SRT internal.
|
||||
/// </summary>
|
||||
/// <param name="inputPath">The input path.</param>
|
||||
/// <param name="outputPath">The output path.</param>
|
||||
/// <param name="language">The language.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">inputPath
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// inputPath
|
||||
/// or
|
||||
/// outputPath</exception>
|
||||
/// outputPath
|
||||
/// </exception>
|
||||
/// <exception cref="System.ApplicationException"></exception>
|
||||
private async Task ConvertTextSubtitleToAssInternal(string inputPath, string outputPath, string language)
|
||||
private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string outputPath, string language)
|
||||
{
|
||||
if (string.IsNullOrEmpty(inputPath))
|
||||
{
|
||||
@ -375,7 +379,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
FileName = _mediaEncoder.EncoderPath,
|
||||
Arguments = string.Format("{0} -i \"{1}\" -c:s ass \"{2}\"", encodingParam, inputPath, outputPath),
|
||||
Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
|
||||
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
ErrorDialog = false
|
||||
@ -529,7 +533,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
|
||||
var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s ass \"{2}\"", inputPath,
|
||||
var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s srt \"{2}\"", inputPath,
|
||||
subtitleStreamIndex, outputPath);
|
||||
|
||||
if (copySubtitleStream)
|
||||
|
@ -34,7 +34,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
{
|
||||
var text = trackEvent.Text;
|
||||
|
||||
text = Regex.Replace(text, @"\\N", "<br/>", RegexOptions.IgnoreCase);
|
||||
text = Regex.Replace(text, @"\\n", "<br/>", RegexOptions.IgnoreCase);
|
||||
|
||||
writer.WriteLine("<p begin=\"{0}\" dur=\"{1}\">{2}</p>",
|
||||
trackEvent.StartPositionTicks,
|
||||
|
@ -18,12 +18,21 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff}", TimeSpan.FromTicks(trackEvent.StartPositionTicks), TimeSpan.FromTicks(trackEvent.EndPositionTicks));
|
||||
TimeSpan startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks);
|
||||
TimeSpan endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks);
|
||||
|
||||
// make sure the start and end times are different and seqential
|
||||
if (endTime.TotalMilliseconds <= startTime.TotalMilliseconds)
|
||||
{
|
||||
endTime = startTime.Add(TimeSpan.FromMilliseconds(1));
|
||||
}
|
||||
|
||||
writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff}", startTime, endTime);
|
||||
|
||||
var text = trackEvent.Text;
|
||||
|
||||
// TODO: Not sure how to handle these
|
||||
text = Regex.Replace(text, @"\\N", " ", RegexOptions.IgnoreCase);
|
||||
text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
|
||||
|
||||
writer.WriteLine(text);
|
||||
writer.WriteLine(string.Empty);
|
||||
|
@ -287,6 +287,9 @@
|
||||
<Compile Include="..\MediaBrowser.Model\Drawing\DrawingUtils.cs">
|
||||
<Link>Drawing\DrawingUtils.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Drawing\ImageOrientation.cs">
|
||||
<Link>Drawing\ImageOrientation.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Drawing\ImageOutputFormat.cs">
|
||||
<Link>Drawing\ImageOutputFormat.cs</Link>
|
||||
</Compile>
|
||||
@ -338,9 +341,6 @@
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\RecommendationType.cs">
|
||||
<Link>Dto\RecommendationType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\StreamOptions.cs">
|
||||
<Link>Dto\StreamOptions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\StudioDto.cs">
|
||||
<Link>Dto\StudioDto.cs</Link>
|
||||
</Compile>
|
||||
@ -353,9 +353,6 @@
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\UserItemDataDto.cs">
|
||||
<Link>Dto\UserItemDataDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\VideoStreamOptions.cs">
|
||||
<Link>Dto\VideoStreamOptions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Entities\BaseItemInfo.cs">
|
||||
<Link>Entities\BaseItemInfo.cs</Link>
|
||||
</Compile>
|
||||
|
@ -250,6 +250,9 @@
|
||||
<Compile Include="..\MediaBrowser.Model\Drawing\DrawingUtils.cs">
|
||||
<Link>Drawing\DrawingUtils.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Drawing\ImageOrientation.cs">
|
||||
<Link>Drawing\ImageOrientation.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Drawing\ImageOutputFormat.cs">
|
||||
<Link>Drawing\ImageOutputFormat.cs</Link>
|
||||
</Compile>
|
||||
@ -301,9 +304,6 @@
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\RecommendationType.cs">
|
||||
<Link>Dto\RecommendationType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\StreamOptions.cs">
|
||||
<Link>Dto\StreamOptions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\StudioDto.cs">
|
||||
<Link>Dto\StudioDto.cs</Link>
|
||||
</Compile>
|
||||
@ -316,9 +316,6 @@
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\UserItemDataDto.cs">
|
||||
<Link>Dto\UserItemDataDto.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\VideoStreamOptions.cs">
|
||||
<Link>Dto\VideoStreamOptions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Entities\BaseItemInfo.cs">
|
||||
<Link>Entities\BaseItemInfo.cs</Link>
|
||||
</Compile>
|
||||
|
@ -61,30 +61,6 @@ namespace MediaBrowser.Model.ApiClient
|
||||
Task<T> GetAsync<T>(string url, CancellationToken cancellationToken = default(CancellationToken))
|
||||
where T : class;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url needed to stream an audio file
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
/// <exception cref="ArgumentNullException">options</exception>
|
||||
string GetAudioStreamUrl(StreamOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url needed to stream a video file
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
/// <exception cref="ArgumentNullException">options</exception>
|
||||
string GetVideoStreamUrl(VideoStreamOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Formulates a url for streaming video using the HLS protocol
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
/// <exception cref="ArgumentNullException">options</exception>
|
||||
string GetHlsVideoStreamUrl(VideoStreamOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Reports the capabilities.
|
||||
/// </summary>
|
||||
@ -209,7 +185,7 @@ namespace MediaBrowser.Model.ApiClient
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Task<QueryResult<BaseItemDto>>.</returns>
|
||||
Task<QueryResult<BaseItemDto>> GetLatestItems(LatestItemsQuery query);
|
||||
Task<BaseItemDto[]> GetLatestItems(LatestItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the intros async.
|
||||
|
@ -176,10 +176,6 @@ namespace MediaBrowser.Model.Configuration
|
||||
|
||||
public double DownMixAudioBoost { get; set; }
|
||||
|
||||
public NotificationOptions NotificationOptions { get; set; }
|
||||
|
||||
public SubtitleOptions SubtitleOptions { get; set; }
|
||||
|
||||
public bool DefaultMetadataSettingsApplied { get; set; }
|
||||
|
||||
public bool EnableTokenAuthentication { get; set; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
@ -8,6 +8,11 @@ namespace MediaBrowser.Model.Dlna
|
||||
/// </summary>
|
||||
public class AudioOptions
|
||||
{
|
||||
public AudioOptions()
|
||||
{
|
||||
Context = EncodingContext.Streaming;
|
||||
}
|
||||
|
||||
public string ItemId { get; set; }
|
||||
public List<MediaSourceInfo> MediaSources { get; set; }
|
||||
public DeviceProfile Profile { get; set; }
|
||||
|
15
MediaBrowser.Model/Drawing/ImageOrientation.cs
Normal file
15
MediaBrowser.Model/Drawing/ImageOrientation.cs
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
namespace MediaBrowser.Model.Drawing
|
||||
{
|
||||
public enum ImageOrientation
|
||||
{
|
||||
TopLeft = 1,
|
||||
TopRight = 2,
|
||||
BottomRight = 3,
|
||||
BottomLeft = 4,
|
||||
LeftTop = 5,
|
||||
RightTop = 6,
|
||||
RightBottom = 7,
|
||||
LeftBottom = 8,
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MediaBrowser.Model.Providers;
|
||||
@ -721,6 +722,17 @@ namespace MediaBrowser.Model.Dto
|
||||
/// <value><c>true</c> if [enable internet providers]; otherwise, <c>false</c>.</value>
|
||||
public bool? LockData { get; set; }
|
||||
|
||||
public int? Width { get; set; }
|
||||
public int? Height { get; set; }
|
||||
public string CameraMake { get; set; }
|
||||
public string CameraModel { get; set; }
|
||||
public string Software { get; set; }
|
||||
public double? ExposureTime { get; set; }
|
||||
public double? FocalLength { get; set; }
|
||||
public ImageOrientation? ImageOrientation { get; set; }
|
||||
public double? Aperture { get; set; }
|
||||
public double? ShutterSpeed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance can resume.
|
||||
/// </summary>
|
||||
|
@ -1,64 +0,0 @@
|
||||
namespace MediaBrowser.Model.Dto
|
||||
{
|
||||
/// <summary>
|
||||
/// Class StreamOptions
|
||||
/// </summary>
|
||||
public class StreamOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the audio bit rate.
|
||||
/// </summary>
|
||||
/// <value>The audio bit rate.</value>
|
||||
public int? AudioBitRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio codec.
|
||||
/// Omit to copy the original stream
|
||||
/// </summary>
|
||||
/// <value>The audio encoding format.</value>
|
||||
public string AudioCodec { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item id.
|
||||
/// </summary>
|
||||
/// <value>The item id.</value>
|
||||
public string ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max audio channels.
|
||||
/// </summary>
|
||||
/// <value>The max audio channels.</value>
|
||||
public int? MaxAudioChannels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max audio sample rate.
|
||||
/// </summary>
|
||||
/// <value>The max audio sample rate.</value>
|
||||
public int? MaxAudioSampleRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the start time ticks.
|
||||
/// </summary>
|
||||
/// <value>The start time ticks.</value>
|
||||
public long? StartTimeTicks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the original media should be served statically
|
||||
/// Only used with progressive streaming
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if static; otherwise, <c>false</c>.</value>
|
||||
public bool? Static { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the output file extension.
|
||||
/// </summary>
|
||||
/// <value>The output file extension.</value>
|
||||
public string OutputFileExtension { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the device id.
|
||||
/// </summary>
|
||||
/// <value>The device id.</value>
|
||||
public string DeviceId { get; set; }
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
namespace MediaBrowser.Model.Dto
|
||||
{
|
||||
/// <summary>
|
||||
/// Class VideoStreamOptions
|
||||
/// </summary>
|
||||
public class VideoStreamOptions : StreamOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the video codec.
|
||||
/// Omit to copy
|
||||
/// </summary>
|
||||
/// <value>The video codec.</value>
|
||||
public string VideoCodec { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video bit rate.
|
||||
/// </summary>
|
||||
/// <value>The video bit rate.</value>
|
||||
public int? VideoBitRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the width.
|
||||
/// </summary>
|
||||
/// <value>The width.</value>
|
||||
public int? Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height.
|
||||
/// </summary>
|
||||
/// <value>The height.</value>
|
||||
public int? Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the max.
|
||||
/// </summary>
|
||||
/// <value>The width of the max.</value>
|
||||
public int? MaxWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height of the max.
|
||||
/// </summary>
|
||||
/// <value>The height of the max.</value>
|
||||
public int? MaxHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the frame rate.
|
||||
/// </summary>
|
||||
/// <value>The frame rate.</value>
|
||||
public double? FrameRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the index of the audio stream.
|
||||
/// </summary>
|
||||
/// <value>The index of the audio stream.</value>
|
||||
public int? AudioStreamIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the index of the video stream.
|
||||
/// </summary>
|
||||
/// <value>The index of the video stream.</value>
|
||||
public int? VideoStreamIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the index of the subtitle stream.
|
||||
/// </summary>
|
||||
/// <value>The index of the subtitle stream.</value>
|
||||
public int? SubtitleStreamIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the profile.
|
||||
/// </summary>
|
||||
/// <value>The profile.</value>
|
||||
public string Profile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level.
|
||||
/// </summary>
|
||||
/// <value>The level.</value>
|
||||
public string Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the baseline stream audio bit rate.
|
||||
/// </summary>
|
||||
/// <value>The baseline stream audio bit rate.</value>
|
||||
public int? BaselineStreamAudioBitRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [append baseline stream].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [append baseline stream]; otherwise, <c>false</c>.</value>
|
||||
public bool AppendBaselineStream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time stamp offset ms. Only used with HLS.
|
||||
/// </summary>
|
||||
/// <value>The time stamp offset ms.</value>
|
||||
public int? TimeStampOffsetMs { get; set; }
|
||||
}
|
||||
}
|
@ -81,6 +81,7 @@
|
||||
<Compile Include="Configuration\ChapterOptions.cs" />
|
||||
<Compile Include="Configuration\XbmcMetadataOptions.cs" />
|
||||
<Compile Include="Configuration\SubtitlePlaybackMode.cs" />
|
||||
<Compile Include="Drawing\ImageOrientation.cs" />
|
||||
<Compile Include="FileOrganization\AutoOrganizeOptions.cs" />
|
||||
<Compile Include="FileOrganization\TvFileOrganizationOptions.cs" />
|
||||
<Compile Include="Configuration\BaseApplicationConfiguration.cs" />
|
||||
@ -151,7 +152,6 @@
|
||||
<Compile Include="Dto\MediaSourceInfo.cs" />
|
||||
<Compile Include="Dto\RecommendationType.cs" />
|
||||
<Compile Include="Dto\SubtitleDownloadOptions.cs" />
|
||||
<Compile Include="Dto\VideoStreamOptions.cs" />
|
||||
<Compile Include="Entities\IsoType.cs" />
|
||||
<Compile Include="Entities\MediaInfo.cs" />
|
||||
<Compile Include="Entities\MediaStreamType.cs" />
|
||||
@ -284,7 +284,6 @@
|
||||
<Compile Include="Querying\ItemQuery.cs" />
|
||||
<Compile Include="Entities\LibraryUpdateInfo.cs" />
|
||||
<Compile Include="Entities\ParentalRating.cs" />
|
||||
<Compile Include="Dto\StreamOptions.cs" />
|
||||
<Compile Include="Entities\VirtualFolderInfo.cs" />
|
||||
<Compile Include="IO\IZipClient.cs" />
|
||||
<Compile Include="Logging\ILogger.cs" />
|
||||
|
@ -26,16 +26,12 @@ namespace MediaBrowser.Model.Notifications
|
||||
|
||||
public SendToUserType? SendToUserMode { get; set; }
|
||||
|
||||
public List<string> ExcludeUserIds { get; set; }
|
||||
|
||||
public NotificationRequest()
|
||||
{
|
||||
UserIds = new List<string>();
|
||||
Date = DateTime.UtcNow;
|
||||
|
||||
Variables = new Dictionary<string, string>();
|
||||
|
||||
ExcludeUserIds = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
@ -35,17 +35,7 @@ namespace MediaBrowser.Providers.FolderImages
|
||||
var playlist = item as Playlist;
|
||||
if (playlist != null)
|
||||
{
|
||||
var url = GetImageUrl(null);
|
||||
|
||||
return Task.FromResult<IEnumerable<RemoteImageInfo>>(new List<RemoteImageInfo>
|
||||
{
|
||||
new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Url = url,
|
||||
Type = ImageType.Primary
|
||||
}
|
||||
});
|
||||
return GetImages(string.Empty, cancellationToken);
|
||||
}
|
||||
|
||||
var view = item as UserView;
|
||||
|
@ -56,6 +56,9 @@
|
||||
<Reference Include="MoreLinq">
|
||||
<HintPath>..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="policy.2.0.taglib-sharp">
|
||||
<HintPath>..\packages\taglib.2.1.0.0\lib\policy.2.0.taglib-sharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Net" />
|
||||
@ -64,6 +67,10 @@
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="taglib-sharp">
|
||||
<HintPath>..\packages\taglib.2.1.0.0\lib\taglib-sharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs">
|
||||
@ -142,8 +149,6 @@
|
||||
<Compile Include="Music\MusicBrainzAlbumProvider.cs" />
|
||||
<Compile Include="People\PersonMetadataService.cs" />
|
||||
<Compile Include="People\MovieDbPersonProvider.cs" />
|
||||
<Compile Include="Photos\ExifReader.cs" />
|
||||
<Compile Include="Photos\ExifTags.cs" />
|
||||
<Compile Include="Photos\PhotoHelper.cs" />
|
||||
<Compile Include="Photos\PhotoMetadataService.cs" />
|
||||
<Compile Include="Photos\PhotoProvider.cs" />
|
||||
|
@ -168,6 +168,15 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item is Audio)
|
||||
{
|
||||
// Moved to plural AlbumArtists
|
||||
if (date < new DateTime(2014, 8, 28))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.SupportsLocalMetadata)
|
||||
{
|
||||
var video = item as Video;
|
||||
|
@ -9,8 +9,6 @@ using MediaBrowser.Providers.Manager;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
@ -104,17 +102,15 @@ namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
var updateType = ItemUpdateType.None;
|
||||
|
||||
var albumArtist = songs
|
||||
var albumArtists = songs
|
||||
.SelectMany(i => i.AlbumArtists)
|
||||
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
if (!string.IsNullOrEmpty(albumArtist))
|
||||
if (!item.AlbumArtists.SequenceEqual(albumArtists, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!string.Equals(item.AlbumArtist, albumArtist, StringComparison.Ordinal))
|
||||
{
|
||||
item.AlbumArtist = albumArtist;
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
item.AlbumArtists = albumArtists;
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
|
||||
return updateType;
|
||||
|
@ -70,7 +70,10 @@ namespace MediaBrowser.Providers.Music
|
||||
|
||||
private void ProcessResult(MusicAlbum item, Album result)
|
||||
{
|
||||
item.AlbumArtist = result.strArtist;
|
||||
if (!string.IsNullOrWhiteSpace(result.strArtist))
|
||||
{
|
||||
item.AlbumArtists = new List<string> { result.strArtist };
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(result.intYearReleased))
|
||||
{
|
||||
|
@ -8,15 +8,15 @@ namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public static string GetAlbumArtist(this AlbumInfo info)
|
||||
{
|
||||
var id = info.AlbumArtists.FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
return info.SongInfos.SelectMany(i => i.AlbumArtists)
|
||||
var id = info.SongInfos.SelectMany(i => i.AlbumArtists)
|
||||
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
if (!string.IsNullOrEmpty(id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
return id;
|
||||
return info.AlbumArtists.FirstOrDefault();
|
||||
}
|
||||
|
||||
public static string GetReleaseGroupId(this AlbumInfo info)
|
||||
|
@ -1,613 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Providers.Photos
|
||||
{
|
||||
/// <summary>
|
||||
/// A class for reading Exif data from a JPEG file. The file will be open for reading for as long as the class exists.
|
||||
/// <seealso cref="http://gvsoft.homedns.org/exif/Exif-explanation.html"/>
|
||||
/// </summary>
|
||||
public class ExifReader : IDisposable
|
||||
{
|
||||
private readonly FileStream fileStream = null;
|
||||
private readonly BinaryReader reader = null;
|
||||
|
||||
/// <summary>
|
||||
/// The catalogue of tag ids and their absolute offsets within the
|
||||
/// file
|
||||
/// </summary>
|
||||
private Dictionary<ushort, long> catalogue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether to read data using big or little endian byte aligns
|
||||
/// </summary>
|
||||
private bool isLittleEndian;
|
||||
|
||||
/// <summary>
|
||||
/// The position in the filestream at which the TIFF header starts
|
||||
/// </summary>
|
||||
private long tiffHeaderStart;
|
||||
|
||||
public ExifReader(string fileName)
|
||||
{
|
||||
// JPEG encoding uses big endian (i.e. Motorola) byte aligns. The TIFF encoding
|
||||
// found later in the document will specify the byte aligns used for the
|
||||
// rest of the document.
|
||||
isLittleEndian = false;
|
||||
|
||||
try
|
||||
{
|
||||
// Open the file in a stream
|
||||
fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
reader = new BinaryReader(fileStream);
|
||||
|
||||
// Make sure the file's a JPEG.
|
||||
if (ReadUShort() != 0xFFD8)
|
||||
throw new Exception("File is not a valid JPEG");
|
||||
|
||||
// Scan to the start of the Exif content
|
||||
ReadToExifStart();
|
||||
|
||||
// Create an index of all Exif tags found within the document
|
||||
CreateTagIndex();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// If instantiation fails, make sure there's no mess left behind
|
||||
Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region TIFF methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length (in bytes) per component of the specified TIFF data type
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private byte GetTIFFFieldLength(ushort tiffDataType)
|
||||
{
|
||||
switch (tiffDataType)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 6:
|
||||
return 1;
|
||||
case 3:
|
||||
case 8:
|
||||
return 2;
|
||||
case 4:
|
||||
case 7:
|
||||
case 9:
|
||||
case 11:
|
||||
return 4;
|
||||
case 5:
|
||||
case 10:
|
||||
case 12:
|
||||
return 8;
|
||||
default:
|
||||
throw new Exception(string.Format("Unknown TIFF datatype: {0}", tiffDataType));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods for reading data directly from the filestream
|
||||
|
||||
/// <summary>
|
||||
/// Gets a 2 byte unsigned integer from the file
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private ushort ReadUShort()
|
||||
{
|
||||
return ToUShort(ReadBytes(2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a 4 byte unsigned integer from the file
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private uint ReadUint()
|
||||
{
|
||||
return ToUint(ReadBytes(4));
|
||||
}
|
||||
|
||||
private string ReadString(int chars)
|
||||
{
|
||||
return Encoding.ASCII.GetString(ReadBytes(chars));
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(int byteCount)
|
||||
{
|
||||
return reader.ReadBytes(byteCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads some bytes from the specified TIFF offset
|
||||
/// </summary>
|
||||
/// <param name="tiffOffset"></param>
|
||||
/// <param name="byteCount"></param>
|
||||
/// <returns></returns>
|
||||
private byte[] ReadBytes(ushort tiffOffset, int byteCount)
|
||||
{
|
||||
// Keep the current file offset
|
||||
long originalOffset = fileStream.Position;
|
||||
|
||||
// Move to the TIFF offset and retrieve the data
|
||||
fileStream.Seek(tiffOffset + tiffHeaderStart, SeekOrigin.Begin);
|
||||
|
||||
byte[] data = reader.ReadBytes(byteCount);
|
||||
|
||||
// Restore the file offset
|
||||
fileStream.Position = originalOffset;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data conversion methods for interpreting datatypes from a byte array
|
||||
|
||||
/// <summary>
|
||||
/// Converts 2 bytes to a ushort using the current byte aligns
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private ushort ToUShort(byte[] data)
|
||||
{
|
||||
if (isLittleEndian != BitConverter.IsLittleEndian)
|
||||
Array.Reverse(data);
|
||||
|
||||
return BitConverter.ToUInt16(data, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts 8 bytes to an unsigned rational using the current byte aligns.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
/// <seealso cref="ToRational"/>
|
||||
private double ToURational(byte[] data)
|
||||
{
|
||||
var numeratorData = new byte[4];
|
||||
var denominatorData = new byte[4];
|
||||
|
||||
Array.Copy(data, numeratorData, 4);
|
||||
Array.Copy(data, 4, denominatorData, 0, 4);
|
||||
|
||||
uint numerator = ToUint(numeratorData);
|
||||
uint denominator = ToUint(denominatorData);
|
||||
|
||||
return numerator / (double)denominator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts 8 bytes to a signed rational using the current byte aligns.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A TIFF rational contains 2 4-byte integers, the first of which is
|
||||
/// the numerator, and the second of which is the denominator.
|
||||
/// </remarks>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
private double ToRational(byte[] data)
|
||||
{
|
||||
var numeratorData = new byte[4];
|
||||
var denominatorData = new byte[4];
|
||||
|
||||
Array.Copy(data, numeratorData, 4);
|
||||
Array.Copy(data, 4, denominatorData, 0, 4);
|
||||
|
||||
int numerator = ToInt(numeratorData);
|
||||
int denominator = ToInt(denominatorData);
|
||||
|
||||
return numerator / (double)denominator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts 4 bytes to a uint using the current byte aligns
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private uint ToUint(byte[] data)
|
||||
{
|
||||
if (isLittleEndian != BitConverter.IsLittleEndian)
|
||||
Array.Reverse(data);
|
||||
|
||||
return BitConverter.ToUInt32(data, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts 4 bytes to an int using the current byte aligns
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private int ToInt(byte[] data)
|
||||
{
|
||||
if (isLittleEndian != BitConverter.IsLittleEndian)
|
||||
Array.Reverse(data);
|
||||
|
||||
return BitConverter.ToInt32(data, 0);
|
||||
}
|
||||
|
||||
private double ToDouble(byte[] data)
|
||||
{
|
||||
if (isLittleEndian != BitConverter.IsLittleEndian)
|
||||
Array.Reverse(data);
|
||||
|
||||
return BitConverter.ToDouble(data, 0);
|
||||
}
|
||||
|
||||
private float ToSingle(byte[] data)
|
||||
{
|
||||
if (isLittleEndian != BitConverter.IsLittleEndian)
|
||||
Array.Reverse(data);
|
||||
|
||||
return BitConverter.ToSingle(data, 0);
|
||||
}
|
||||
|
||||
private short ToShort(byte[] data)
|
||||
{
|
||||
if (isLittleEndian != BitConverter.IsLittleEndian)
|
||||
Array.Reverse(data);
|
||||
|
||||
return BitConverter.ToInt16(data, 0);
|
||||
}
|
||||
|
||||
private sbyte ToSByte(byte[] data)
|
||||
{
|
||||
// An sbyte should just be a byte with an offset range.
|
||||
return (sbyte)(data[0] - byte.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an array from a byte array using the supplied converter
|
||||
/// to read each individual element from the supplied byte array
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="elementLengthBytes"></param>
|
||||
/// <param name="converter"></param>
|
||||
/// <returns></returns>
|
||||
private Array GetArray<T>(byte[] data, int elementLengthBytes, ConverterMethod<T> converter)
|
||||
{
|
||||
Array convertedData = Array.CreateInstance(typeof(T), data.Length / elementLengthBytes);
|
||||
|
||||
var buffer = new byte[elementLengthBytes];
|
||||
|
||||
// Read each element from the array
|
||||
for (int elementCount = 0; elementCount < data.Length / elementLengthBytes; elementCount++)
|
||||
{
|
||||
// Place the data for the current element into the buffer
|
||||
Array.Copy(data, elementCount * elementLengthBytes, buffer, 0, elementLengthBytes);
|
||||
|
||||
// Process the data and place it into the output array
|
||||
convertedData.SetValue(converter(buffer), elementCount);
|
||||
}
|
||||
|
||||
return convertedData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate used to invoke any of the data conversion methods
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
private delegate T ConverterMethod<out T>(byte[] data);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream seek methods - used to get to locations within the JPEG
|
||||
|
||||
/// <summary>
|
||||
/// Scans to the Exif block
|
||||
/// </summary>
|
||||
private void ReadToExifStart()
|
||||
{
|
||||
// The file has a number of blocks (Exif/JFIF), each of which
|
||||
// has a tag number followed by a length. We scan the document until the required tag (0xFFE1)
|
||||
// is found. All tags start with FF, so a non FF tag indicates an error.
|
||||
|
||||
// Get the next tag.
|
||||
byte markerStart;
|
||||
byte markerNumber = 0;
|
||||
while (((markerStart = reader.ReadByte()) == 0xFF) && (markerNumber = reader.ReadByte()) != 0xE1)
|
||||
{
|
||||
// Get the length of the data.
|
||||
ushort dataLength = ReadUShort();
|
||||
|
||||
// Jump to the end of the data (note that the size field includes its own size)!
|
||||
reader.BaseStream.Seek(dataLength - 2, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// It's only success if we found the 0xFFE1 marker
|
||||
if (markerStart != 0xFF || markerNumber != 0xE1)
|
||||
throw new Exception("Could not find Exif data block");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads through the Exif data and builds an index of all Exif tags in the document
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void CreateTagIndex()
|
||||
{
|
||||
// The next 4 bytes are the size of the Exif data.
|
||||
ReadUShort();
|
||||
|
||||
// Next is the Exif data itself. It starts with the ASCII "Exif" followed by 2 zero bytes.
|
||||
if (ReadString(4) != "Exif")
|
||||
throw new Exception("Exif data not found");
|
||||
|
||||
// 2 zero bytes
|
||||
if (ReadUShort() != 0)
|
||||
throw new Exception("Malformed Exif data");
|
||||
|
||||
// We're now into the TIFF format
|
||||
tiffHeaderStart = reader.BaseStream.Position;
|
||||
|
||||
// What byte align will be used for the TIFF part of the document? II for Intel, MM for Motorola
|
||||
isLittleEndian = ReadString(2) == "II";
|
||||
|
||||
// Next 2 bytes are always the same.
|
||||
if (ReadUShort() != 0x002A)
|
||||
throw new Exception("Error in TIFF data");
|
||||
|
||||
// Get the offset to the IFD (image file directory)
|
||||
uint ifdOffset = ReadUint();
|
||||
|
||||
// Note that this offset is from the first byte of the TIFF header. Jump to the IFD.
|
||||
fileStream.Position = ifdOffset + tiffHeaderStart;
|
||||
|
||||
// Catalogue this first IFD (there will be another IFD)
|
||||
CatalogueIFD();
|
||||
|
||||
// There's more data stored in the subifd, the offset to which is found in tag 0x8769.
|
||||
// As with all TIFF offsets, it will be relative to the first byte of the TIFF header.
|
||||
uint offset;
|
||||
if (!GetTagValue(0x8769, out offset))
|
||||
throw new Exception("Unable to locate Exif data");
|
||||
|
||||
// Jump to the exif SubIFD
|
||||
fileStream.Position = offset + tiffHeaderStart;
|
||||
|
||||
// Add the subIFD to the catalogue too
|
||||
CatalogueIFD();
|
||||
|
||||
// Go to the GPS IFD and catalogue that too. It's an optional
|
||||
// section.
|
||||
if (GetTagValue(0x8825, out offset))
|
||||
{
|
||||
// Jump to the GPS SubIFD
|
||||
fileStream.Position = offset + tiffHeaderStart;
|
||||
|
||||
// Add the subIFD to the catalogue too
|
||||
CatalogueIFD();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Exif data catalog and retrieval methods
|
||||
|
||||
public bool GetTagValue<T>(ExifTags tag, out T result)
|
||||
{
|
||||
return GetTagValue((ushort)tag, out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an Exif value with the requested tag ID
|
||||
/// </summary>
|
||||
/// <param name="tagID"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetTagValue<T>(ushort tagID, out T result)
|
||||
{
|
||||
ushort tiffDataType;
|
||||
uint numberOfComponents;
|
||||
byte[] tagData = GetTagBytes(tagID, out tiffDataType, out numberOfComponents);
|
||||
|
||||
if (tagData == null)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
byte fieldLength = GetTIFFFieldLength(tiffDataType);
|
||||
|
||||
// Convert the data to the appropriate datatype. Note the weird boxing via object.
|
||||
// The compiler doesn't like it otherwise.
|
||||
switch (tiffDataType)
|
||||
{
|
||||
case 1:
|
||||
// unsigned byte
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)tagData[0];
|
||||
else
|
||||
result = (T)(object)tagData;
|
||||
return true;
|
||||
case 2:
|
||||
// ascii string
|
||||
string str = Encoding.ASCII.GetString(tagData);
|
||||
|
||||
// There may be a null character within the string
|
||||
int nullCharIndex = str.IndexOf('\0');
|
||||
if (nullCharIndex != -1)
|
||||
str = str.Substring(0, nullCharIndex);
|
||||
|
||||
// Special processing for dates.
|
||||
if (typeof(T) == typeof(DateTime))
|
||||
{
|
||||
result =
|
||||
(T)(object)DateTime.ParseExact(str, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = (T)(object)str;
|
||||
return true;
|
||||
case 3:
|
||||
// unsigned short
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToUShort(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToUShort);
|
||||
return true;
|
||||
case 4:
|
||||
// unsigned long
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToUint(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToUint);
|
||||
return true;
|
||||
case 5:
|
||||
// unsigned rational
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToURational(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToURational);
|
||||
return true;
|
||||
case 6:
|
||||
// signed byte
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToSByte(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToSByte);
|
||||
return true;
|
||||
case 7:
|
||||
// undefined. Treat it as an unsigned integer.
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToUint(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToUint);
|
||||
return true;
|
||||
case 8:
|
||||
// Signed short
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToShort(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToShort);
|
||||
return true;
|
||||
case 9:
|
||||
// Signed long
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToInt(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToInt);
|
||||
return true;
|
||||
case 10:
|
||||
// signed rational
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToRational(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToRational);
|
||||
return true;
|
||||
case 11:
|
||||
// single float
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToSingle(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToSingle);
|
||||
return true;
|
||||
case 12:
|
||||
// double float
|
||||
if (numberOfComponents == 1)
|
||||
result = (T)(object)ToDouble(tagData);
|
||||
else
|
||||
result = (T)(object)GetArray(tagData, fieldLength, ToDouble);
|
||||
return true;
|
||||
default:
|
||||
throw new Exception(string.Format("Unknown TIFF datatype: {0}", tiffDataType));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data in the specified tag ID, starting from before the IFD block.
|
||||
/// </summary>
|
||||
/// <param name="tiffDataType"></param>
|
||||
/// <param name="numberOfComponents">The number of items which make up the data item - i.e. for a string, this will be the
|
||||
/// number of characters in the string</param>
|
||||
/// <param name="tagID"></param>
|
||||
private byte[] GetTagBytes(ushort tagID, out ushort tiffDataType, out uint numberOfComponents)
|
||||
{
|
||||
// Get the tag's offset from the catalogue and do some basic error checks
|
||||
if (fileStream == null || reader == null || catalogue == null || !catalogue.ContainsKey(tagID))
|
||||
{
|
||||
tiffDataType = 0;
|
||||
numberOfComponents = 0;
|
||||
return null;
|
||||
}
|
||||
|
||||
long tagOffset = catalogue[tagID];
|
||||
|
||||
// Jump to the TIFF offset
|
||||
fileStream.Position = tagOffset;
|
||||
|
||||
// Read the tag number from the file
|
||||
ushort currentTagID = ReadUShort();
|
||||
|
||||
if (currentTagID != tagID)
|
||||
throw new Exception("Tag number not at expected offset");
|
||||
|
||||
// Read the offset to the Exif IFD
|
||||
tiffDataType = ReadUShort();
|
||||
numberOfComponents = ReadUint();
|
||||
byte[] tagData = ReadBytes(4);
|
||||
|
||||
// If the total space taken up by the field is longer than the
|
||||
// 2 bytes afforded by the tagData, tagData will contain an offset
|
||||
// to the actual data.
|
||||
var dataSize = (int)(numberOfComponents * GetTIFFFieldLength(tiffDataType));
|
||||
|
||||
if (dataSize > 4)
|
||||
{
|
||||
ushort offsetAddress = ToUShort(tagData);
|
||||
return ReadBytes(offsetAddress, dataSize);
|
||||
}
|
||||
|
||||
// The value is stored in the tagData starting from the left
|
||||
Array.Resize(ref tagData, dataSize);
|
||||
|
||||
return tagData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Records all Exif tags and their offsets within
|
||||
/// the file from the current IFD
|
||||
/// </summary>
|
||||
private void CatalogueIFD()
|
||||
{
|
||||
if (catalogue == null)
|
||||
catalogue = new Dictionary<ushort, long>();
|
||||
|
||||
// Assume we're just before the IFD.
|
||||
|
||||
// First 2 bytes is the number of entries in this IFD
|
||||
ushort entryCount = ReadUShort();
|
||||
|
||||
for (ushort currentEntry = 0; currentEntry < entryCount; currentEntry++)
|
||||
{
|
||||
ushort currentTagNumber = ReadUShort();
|
||||
|
||||
// Record this in the catalogue
|
||||
catalogue[currentTagNumber] = fileStream.Position - 2;
|
||||
|
||||
// Go to the end of this item (10 bytes, as each entry is 12 bytes long)
|
||||
reader.BaseStream.Seek(10, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Make sure the file handle is released
|
||||
if (reader != null)
|
||||
reader.Close();
|
||||
if (fileStream != null)
|
||||
fileStream.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
|
||||
namespace MediaBrowser.Providers.Photos
|
||||
{
|
||||
/// <summary>
|
||||
/// All exif tags as per the Exif standard 2.2, JEITA CP-2451
|
||||
/// </summary>
|
||||
public enum ExifTags : ushort
|
||||
{
|
||||
// IFD0 items
|
||||
ImageWidth = 0x100,
|
||||
ImageLength = 0x101,
|
||||
BitsPerSample = 0x102,
|
||||
Compression = 0x103,
|
||||
PhotometricInterpretation = 0x106,
|
||||
ImageDescription = 0x10E,
|
||||
Make = 0x10F,
|
||||
Model = 0x110,
|
||||
StripOffsets = 0x111,
|
||||
Orientation = 0x112,
|
||||
SamplesPerPixel = 0x115,
|
||||
RowsPerStrip = 0x116,
|
||||
StripByteCounts = 0x117,
|
||||
XResolution = 0x11A,
|
||||
YResolution = 0x11B,
|
||||
PlanarConfiguration = 0x11C,
|
||||
ResolutionUnit = 0x128,
|
||||
TransferFunction = 0x12D,
|
||||
Software = 0x131,
|
||||
DateTime = 0x132,
|
||||
Artist = 0x13B,
|
||||
WhitePoint = 0x13E,
|
||||
PrimaryChromaticities = 0x13F,
|
||||
JPEGInterchangeFormat = 0x201,
|
||||
JPEGInterchangeFormatLength = 0x202,
|
||||
YCbCrCoefficients = 0x211,
|
||||
YCbCrSubSampling = 0x212,
|
||||
YCbCrPositioning = 0x213,
|
||||
ReferenceBlackWhite = 0x214,
|
||||
Copyright = 0x8298,
|
||||
|
||||
// SubIFD items
|
||||
ExposureTime = 0x829A,
|
||||
FNumber = 0x829D,
|
||||
ExposureProgram = 0x8822,
|
||||
SpectralSensitivity = 0x8824,
|
||||
ISOSpeedRatings = 0x8827,
|
||||
OECF = 0x8828,
|
||||
ExifVersion = 0x9000,
|
||||
DateTimeOriginal = 0x9003,
|
||||
DateTimeDigitized = 0x9004,
|
||||
ComponentsConfiguration = 0x9101,
|
||||
CompressedBitsPerPixel = 0x9102,
|
||||
ShutterSpeedValue = 0x9201,
|
||||
ApertureValue = 0x9202,
|
||||
BrightnessValue = 0x9203,
|
||||
ExposureBiasValue = 0x9204,
|
||||
MaxApertureValue = 0x9205,
|
||||
SubjectDistance = 0x9206,
|
||||
MeteringMode = 0x9207,
|
||||
LightSource = 0x9208,
|
||||
Flash = 0x9209,
|
||||
FocalLength = 0x920A,
|
||||
SubjectArea = 0x9214,
|
||||
MakerNote = 0x927C,
|
||||
UserComment = 0x9286,
|
||||
SubsecTime = 0x9290,
|
||||
SubsecTimeOriginal = 0x9291,
|
||||
SubsecTimeDigitized = 0x9292,
|
||||
FlashpixVersion = 0xA000,
|
||||
ColorSpace = 0xA001,
|
||||
PixelXDimension = 0xA002,
|
||||
PixelYDimension = 0xA003,
|
||||
RelatedSoundFile = 0xA004,
|
||||
FlashEnergy = 0xA20B,
|
||||
SpatialFrequencyResponse = 0xA20C,
|
||||
FocalPlaneXResolution = 0xA20E,
|
||||
FocalPlaneYResolution = 0xA20F,
|
||||
FocalPlaneResolutionUnit = 0xA210,
|
||||
SubjectLocation = 0xA214,
|
||||
ExposureIndex = 0xA215,
|
||||
SensingMethod = 0xA217,
|
||||
FileSource = 0xA300,
|
||||
SceneType = 0xA301,
|
||||
CFAPattern = 0xA302,
|
||||
CustomRendered = 0xA401,
|
||||
ExposureMode = 0xA402,
|
||||
WhiteBalance = 0xA403,
|
||||
DigitalZoomRatio = 0xA404,
|
||||
FocalLengthIn35mmFilm = 0xA405,
|
||||
SceneCaptureType = 0xA406,
|
||||
GainControl = 0xA407,
|
||||
Contrast = 0xA408,
|
||||
Saturation = 0xA409,
|
||||
Sharpness = 0xA40A,
|
||||
DeviceSettingDescription = 0xA40B,
|
||||
SubjectDistanceRange = 0xA40C,
|
||||
ImageUniqueID = 0xA420,
|
||||
|
||||
// GPS subifd items
|
||||
GPSVersionID = 0x0,
|
||||
GPSLatitudeRef = 0x1,
|
||||
GPSLatitude = 0x2,
|
||||
GPSLongitudeRef = 0x3,
|
||||
GPSLongitude = 0x4,
|
||||
GPSAltitudeRef = 0x5,
|
||||
GPSAltitude = 0x6,
|
||||
GPSTimeStamp = 0x7,
|
||||
GPSSatellites = 0x8,
|
||||
GPSStatus = 0x9,
|
||||
GPSMeasureMode = 0xA,
|
||||
GPSDOP = 0xB,
|
||||
GPSSpeedRef = 0xC,
|
||||
GPSSpeed = 0xD,
|
||||
GPSTrackRef = 0xE,
|
||||
GPSTrack = 0xF,
|
||||
GPSImgDirectionRef = 0x10,
|
||||
GPSImgDirection = 0x11,
|
||||
GPSMapDatum = 0x12,
|
||||
GPSDestLatitudeRef = 0x13,
|
||||
GPSDestLatitude = 0x14,
|
||||
GPSDestLongitudeRef = 0x15,
|
||||
GPSDestLongitude = 0x16,
|
||||
GPSDestBearingRef = 0x17,
|
||||
GPSDestBearing = 0x18,
|
||||
GPSDestDistanceRef = 0x19,
|
||||
GPSDestDistance = 0x1A,
|
||||
GPSProcessingMethod = 0x1B,
|
||||
GPSAreaInformation = 0x1C,
|
||||
GPSDateStamp = 0x1D,
|
||||
GPSDifferential = 0x1E
|
||||
}
|
||||
}
|
@ -1,25 +1,10 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Providers.Photos
|
||||
{
|
||||
public static class PhotoHelper
|
||||
{
|
||||
public static List<BaseItem> ShuffleList(List<BaseItem> list)
|
||||
{
|
||||
var rnd = new Random(DateTime.Now.Second);
|
||||
for (var i = 1; i < list.Count; i++)
|
||||
{
|
||||
var pos = rnd.Next(i + 1);
|
||||
var x = list[i];
|
||||
list[i] = list[pos];
|
||||
list[pos] = x;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static string Dec2Frac(double dbl)
|
||||
{
|
||||
char neg = ' ';
|
||||
|
@ -5,9 +5,13 @@ using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TagLib;
|
||||
using TagLib.IFD;
|
||||
using TagLib.IFD.Entries;
|
||||
using TagLib.IFD.Tags;
|
||||
|
||||
namespace MediaBrowser.Providers.Photos
|
||||
{
|
||||
@ -25,102 +29,109 @@ namespace MediaBrowser.Providers.Photos
|
||||
public Task<ItemUpdateType> FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
item.SetImagePath(ImageType.Primary, item.Path);
|
||||
item.SetImagePath(ImageType.Backdrop, item.Path);
|
||||
|
||||
if (item.Path.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || item.Path.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase))
|
||||
// Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
var file = File.Create(item.Path);
|
||||
|
||||
var image = file as TagLib.Image.File;
|
||||
|
||||
var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag;
|
||||
|
||||
if (tag != null)
|
||||
{
|
||||
using (var reader = new ExifReader(item.Path))
|
||||
var structure = tag.Structure;
|
||||
|
||||
if (structure != null)
|
||||
{
|
||||
double aperture = 0;
|
||||
double shutterSpeed = 0;
|
||||
var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
|
||||
|
||||
DateTime dateTaken;
|
||||
|
||||
string manufacturer;
|
||||
string model;
|
||||
|
||||
reader.GetTagValue(ExifTags.FNumber, out aperture);
|
||||
reader.GetTagValue(ExifTags.ExposureTime, out shutterSpeed);
|
||||
reader.GetTagValue(ExifTags.DateTimeOriginal, out dateTaken);
|
||||
|
||||
reader.GetTagValue(ExifTags.Make, out manufacturer);
|
||||
reader.GetTagValue(ExifTags.Model, out model);
|
||||
|
||||
if (dateTaken > DateTime.MinValue)
|
||||
if (exif != null)
|
||||
{
|
||||
item.DateCreated = dateTaken;
|
||||
item.PremiereDate = dateTaken;
|
||||
item.ProductionYear = dateTaken.Year;
|
||||
var exifStructure = exif.Structure;
|
||||
|
||||
if (exifStructure != null)
|
||||
{
|
||||
var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry;
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
double val = entry.Value.Numerator;
|
||||
val /= entry.Value.Denominator;
|
||||
item.Aperture = val;
|
||||
}
|
||||
|
||||
entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry;
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
double val = entry.Value.Numerator;
|
||||
val /= entry.Value.Denominator;
|
||||
item.ShutterSpeed = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cameraModel = manufacturer ?? string.Empty;
|
||||
cameraModel += " ";
|
||||
cameraModel += model ?? string.Empty;
|
||||
|
||||
var size = _imageProcessor.GetImageSize(item.Path);
|
||||
var xResolution = size.Width;
|
||||
var yResolution = size.Height;
|
||||
|
||||
item.Overview = "Taken " + dateTaken.ToString("F") + "\n" +
|
||||
(!string.IsNullOrWhiteSpace(cameraModel) ? "With a " + cameraModel : "") +
|
||||
(aperture > 0 && shutterSpeed > 0 ? " at f" + aperture.ToString(CultureInfo.InvariantCulture) + " and " + PhotoHelper.Dec2Frac(shutterSpeed) + "s" : "") + "\n"
|
||||
+ (xResolution > 0 ? "\n<br/>Resolution: " + xResolution + "x" + yResolution : "");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
item.CameraMake = image.ImageTag.Make;
|
||||
item.CameraModel = image.ImageTag.Model;
|
||||
|
||||
var rating = image.ImageTag.Rating;
|
||||
if (rating.HasValue)
|
||||
{
|
||||
_logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path);
|
||||
item.CommunityRating = rating;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.CommunityRating = null;
|
||||
}
|
||||
|
||||
item.Overview = image.ImageTag.Comment;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(image.ImageTag.Title))
|
||||
{
|
||||
item.Name = image.ImageTag.Title;
|
||||
}
|
||||
|
||||
var dateTaken = image.ImageTag.DateTime;
|
||||
if (dateTaken.HasValue)
|
||||
{
|
||||
item.DateCreated = dateTaken.Value;
|
||||
item.PremiereDate = dateTaken.Value;
|
||||
item.ProductionYear = dateTaken.Value.Year;
|
||||
}
|
||||
|
||||
item.Genres = image.ImageTag.Genres.ToList();
|
||||
item.Tags = image.ImageTag.Keywords.ToList();
|
||||
item.Software = image.ImageTag.Software;
|
||||
|
||||
if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
|
||||
{
|
||||
item.Orientation = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Model.Drawing.ImageOrientation orientation;
|
||||
if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation))
|
||||
{
|
||||
item.Orientation = orientation;
|
||||
}
|
||||
}
|
||||
|
||||
item.ExposureTime = image.ImageTag.ExposureTime;
|
||||
item.FocalLength = image.ImageTag.FocalLength;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path);
|
||||
}
|
||||
|
||||
//// Get additional tags from xmp
|
||||
//try
|
||||
//{
|
||||
// using (var fs = new FileStream(item.Path, FileMode.Open, FileAccess.Read))
|
||||
// {
|
||||
// var bf = BitmapFrame.Create(fs);
|
||||
|
||||
// if (bf != null)
|
||||
// {
|
||||
// var data = (BitmapMetadata)bf.Metadata;
|
||||
// if (data != null)
|
||||
// {
|
||||
|
||||
// DateTime dateTaken;
|
||||
// var cameraModel = "";
|
||||
|
||||
// DateTime.TryParse(data.DateTaken, out dateTaken);
|
||||
// if (dateTaken > DateTime.MinValue) item.DateCreated = dateTaken;
|
||||
// cameraModel = data.CameraModel;
|
||||
|
||||
// item.PremiereDate = dateTaken;
|
||||
// item.ProductionYear = dateTaken.Year;
|
||||
// item.Overview = "Taken " + dateTaken.ToString("F") + "\n" +
|
||||
// (cameraModel != "" ? "With a " + cameraModel : "") +
|
||||
// (aperture > 0 && shutterSpeed > 0 ? " at f" + aperture.ToString(CultureInfo.InvariantCulture) + " and " + PhotoHelper.Dec2Frac(shutterSpeed) + "s" : "") + "\n"
|
||||
// + (bf.Width > 0 ? "\n<br/>Resolution: " + (int)bf.Width + "x" + (int)bf.Height : "");
|
||||
|
||||
// var photo = item as Photo;
|
||||
// if (data.Keywords != null) item.Genres = photo.Tags = new List<string>(data.Keywords);
|
||||
// item.Name = !string.IsNullOrWhiteSpace(data.Title) ? data.Title : item.Name;
|
||||
// item.CommunityRating = data.Rating;
|
||||
// if (!string.IsNullOrWhiteSpace(data.Subject)) photo.AddTagline(data.Subject);
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
//catch (NotSupportedException)
|
||||
//{
|
||||
// // No problem - move on
|
||||
//}
|
||||
//catch (Exception e)
|
||||
//{
|
||||
// _logger.ErrorException("Error trying to read extended data from {0}", e, item.Path);
|
||||
//}
|
||||
var size = _imageProcessor.GetImageSize(item.Path);
|
||||
item.Height = Convert.ToInt32(size.Height);
|
||||
item.Width = Convert.ToInt32(size.Width);
|
||||
|
||||
const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport;
|
||||
return Task.FromResult(result);
|
||||
@ -133,6 +144,13 @@ namespace MediaBrowser.Providers.Photos
|
||||
|
||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
||||
{
|
||||
// Moved to plural AlbumArtists
|
||||
if (date < new DateTime(2014, 8, 28))
|
||||
{
|
||||
// Revamped vaptured metadata
|
||||
return true;
|
||||
}
|
||||
|
||||
return item.DateModified > date;
|
||||
}
|
||||
}
|
||||
|
@ -2,4 +2,5 @@
|
||||
<packages>
|
||||
<package id="MediaBrowser.BdInfo" version="1.0.0.10" targetFramework="net45" />
|
||||
<package id="morelinq" version="1.0.16006" targetFramework="net45" />
|
||||
<package id="taglib" version="2.1.0.0" targetFramework="net45" />
|
||||
</packages>
|
@ -230,7 +230,8 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||
if (item.IsVideo && response.ContentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var extension = response.ContentType.Split('/')
|
||||
.Last();
|
||||
.Last()
|
||||
.Replace("quicktime", "mov", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
destination += "." + extension;
|
||||
}
|
||||
|
17
MediaBrowser.Server.Implementations/Connect/ConnectData.cs
Normal file
17
MediaBrowser.Server.Implementations/Connect/ConnectData.cs
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Connect
|
||||
{
|
||||
public class ConnectData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the server identifier.
|
||||
/// </summary>
|
||||
/// <value>The server identifier.</value>
|
||||
public string ServerId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the access key.
|
||||
/// </summary>
|
||||
/// <value>The access key.</value>
|
||||
public string AccessKey { get; set; }
|
||||
}
|
||||
}
|
125
MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
Normal file
125
MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
Normal file
@ -0,0 +1,125 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Connect;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Connect
|
||||
{
|
||||
public class ConnectEntryPoint : IServerEntryPoint
|
||||
{
|
||||
private Timer _timer;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IConnectManager _connectManager;
|
||||
|
||||
private readonly INetworkManager _networkManager;
|
||||
|
||||
public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appPaths = appPaths;
|
||||
_logger = logger;
|
||||
_networkManager = networkManager;
|
||||
_connectManager = connectManager;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
LoadCachedAddress();
|
||||
|
||||
_timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(30), TimeSpan.FromHours(24));
|
||||
}
|
||||
|
||||
private async void TimerCallback(object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = await _httpClient.Get(new HttpRequestOptions
|
||||
{
|
||||
Url = "http://bot.whatismyipaddress.com/"
|
||||
|
||||
}).ConfigureAwait(false))
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
var address = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
if (IsValid(address))
|
||||
{
|
||||
((ConnectManager) _connectManager).OnWanAddressResolved(address);
|
||||
CacheAddress(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private string CacheFilePath
|
||||
{
|
||||
get { return Path.Combine(_appPaths.DataPath, "wan.txt"); }
|
||||
}
|
||||
|
||||
private void CacheAddress(string address)
|
||||
{
|
||||
var path = CacheFilePath;
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
File.WriteAllText(path, address, Encoding.UTF8);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error saving data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCachedAddress()
|
||||
{
|
||||
var path = CacheFilePath;
|
||||
|
||||
try
|
||||
{
|
||||
var endpoint = File.ReadAllText(path, Encoding.UTF8);
|
||||
|
||||
if (IsValid(endpoint))
|
||||
{
|
||||
((ConnectManager)_connectManager).OnWanAddressResolved(endpoint);
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// File isn't there. no biggie
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error loading data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsValid(string address)
|
||||
{
|
||||
IPAddress ipAddress;
|
||||
return IPAddress.TryParse(address, out ipAddress);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_timer != null)
|
||||
{
|
||||
_timer.Dispose();
|
||||
_timer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
204
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
Normal file
204
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
Normal file
@ -0,0 +1,204 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Connect;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Connect
|
||||
{
|
||||
public class ConnectManager : IConnectManager
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IJsonSerializer _json;
|
||||
private readonly IEncryptionManager _encryption;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
public string ConnectServerId { get; set; }
|
||||
public string ConnectAccessKey { get; set; }
|
||||
|
||||
public string WanIpAddress { get; private set; }
|
||||
|
||||
public string WanApiAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
var ip = WanIpAddress;
|
||||
|
||||
if (!string.IsNullOrEmpty(ip))
|
||||
{
|
||||
if (!ip.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
|
||||
!ip.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ip = "http://" + ip;
|
||||
}
|
||||
|
||||
return ip + ":" + _config.Configuration.HttpServerPortNumber.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectManager(ILogger logger,
|
||||
IApplicationPaths appPaths,
|
||||
IJsonSerializer json,
|
||||
IEncryptionManager encryption,
|
||||
IHttpClient httpClient,
|
||||
IServerApplicationHost appHost,
|
||||
IServerConfigurationManager config)
|
||||
{
|
||||
_logger = logger;
|
||||
_appPaths = appPaths;
|
||||
_json = json;
|
||||
_encryption = encryption;
|
||||
_httpClient = httpClient;
|
||||
_appHost = appHost;
|
||||
_config = config;
|
||||
|
||||
LoadCachedData();
|
||||
}
|
||||
|
||||
internal void OnWanAddressResolved(string address)
|
||||
{
|
||||
WanIpAddress = address;
|
||||
|
||||
UpdateConnectInfo();
|
||||
}
|
||||
|
||||
private async void UpdateConnectInfo()
|
||||
{
|
||||
var wanApiAddress = WanApiAddress;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(wanApiAddress))
|
||||
{
|
||||
_logger.Warn("Cannot update Media Browser Connect information without a WanApiAddress");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) &&
|
||||
!string.IsNullOrWhiteSpace(ConnectAccessKey);
|
||||
|
||||
if (hasExistingRecord)
|
||||
{
|
||||
//await UpdateServerRegistration(wanApiAddress).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//await CreateServerRegistration(wanApiAddress).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error registering with Connect", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateServerRegistration(string wanApiAddress)
|
||||
{
|
||||
var url = "Servers";
|
||||
url = GetConnectUrl(url);
|
||||
url += "?Name=" + WebUtility.UrlEncode(_appHost.FriendlyName);
|
||||
url += "&Url=" + WebUtility.UrlEncode(wanApiAddress);
|
||||
|
||||
using (var stream = await _httpClient.Post(url, new Dictionary<string, string>(), CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
var data = _json.DeserializeFromStream<ServerRegistrationResponse>(stream);
|
||||
|
||||
ConnectServerId = data.Id;
|
||||
ConnectAccessKey = data.AccessKey;
|
||||
|
||||
CacheData();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateServerRegistration(string wanApiAddress)
|
||||
{
|
||||
var url = "Servers/" + ConnectServerId;
|
||||
url = GetConnectUrl(url);
|
||||
url += "?Name=" + WebUtility.UrlEncode(_appHost.FriendlyName);
|
||||
url += "&Url=" + WebUtility.UrlEncode(wanApiAddress);
|
||||
|
||||
// TODO: Add AccessKey http request header
|
||||
|
||||
// No need to examine the response
|
||||
using (var stream = await _httpClient.Post(url, new Dictionary<string, string>(), CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private string CacheFilePath
|
||||
{
|
||||
get { return Path.Combine(_appPaths.DataPath, "connect.txt"); }
|
||||
}
|
||||
|
||||
private void CacheData()
|
||||
{
|
||||
var path = CacheFilePath;
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
var json = _json.SerializeToString(new ConnectData
|
||||
{
|
||||
AccessKey = ConnectAccessKey,
|
||||
ServerId = ConnectServerId
|
||||
});
|
||||
|
||||
var encrypted = _encryption.EncryptString(json);
|
||||
|
||||
File.WriteAllText(path, encrypted, Encoding.UTF8);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error saving data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCachedData()
|
||||
{
|
||||
var path = CacheFilePath;
|
||||
|
||||
try
|
||||
{
|
||||
var encrypted = File.ReadAllText(path, Encoding.UTF8);
|
||||
|
||||
var json = _encryption.DecryptString(encrypted);
|
||||
|
||||
var data = _json.DeserializeFromString<ConnectData>(json);
|
||||
|
||||
ConnectAccessKey = data.AccessKey;
|
||||
ConnectServerId = data.ServerId;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// File isn't there. no biggie
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error loading data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetConnectUrl(string handler)
|
||||
{
|
||||
return "http://mb3admin.com/admin/connect/" + handler;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Connect
|
||||
{
|
||||
public class ServerRegistrationResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string AccessKey { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateServerRegistrationResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using Imazen.WebP;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
@ -210,7 +211,12 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||
var newHeight = Convert.ToInt32(newSize.Height);
|
||||
|
||||
// Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
|
||||
using (var thumbnail = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppPArgb))
|
||||
// Also, Webp only supports Format32bppArgb and Format32bppRgb
|
||||
var pixelFormat = options.OutputFormat == ImageOutputFormat.Webp
|
||||
? PixelFormat.Format32bppArgb
|
||||
: PixelFormat.Format32bppPArgb;
|
||||
|
||||
using (var thumbnail = new Bitmap(newWidth, newHeight, pixelFormat))
|
||||
{
|
||||
// Mono throw an exeception if assign 0 to SetResolution
|
||||
if (originalImage.HorizontalResolution > 0 && originalImage.VerticalResolution > 0)
|
||||
@ -242,8 +248,15 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||
// Save to the cache location
|
||||
using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
|
||||
{
|
||||
// Save to the memory stream
|
||||
thumbnail.Save(outputFormat, cacheFileStream, quality);
|
||||
if (options.OutputFormat == ImageOutputFormat.Webp)
|
||||
{
|
||||
new SimpleEncoder().Encode(thumbnail, cacheFileStream, quality, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save to the memory stream
|
||||
thumbnail.Save(outputFormat, cacheFileStream, quality);
|
||||
}
|
||||
}
|
||||
|
||||
return cacheFilePath;
|
||||
@ -260,31 +273,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches the resized image.
|
||||
/// </summary>
|
||||
/// <param name="cacheFilePath">The cache file path.</param>
|
||||
/// <param name="bytes">The bytes.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private async Task CacheResizedImage(string cacheFilePath, byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
||||
|
||||
// Save to the cache location
|
||||
using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
||||
{
|
||||
// Save to the filestream
|
||||
await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error writing to image cache file {0}", ex, cacheFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color of the background.
|
||||
/// </summary>
|
||||
|
@ -357,6 +357,19 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
{
|
||||
dto.SeriesName = item.SeriesName;
|
||||
}
|
||||
private void SetPhotoProperties(BaseItemDto dto, Photo item)
|
||||
{
|
||||
dto.Width = item.Width;
|
||||
dto.Height = item.Height;
|
||||
dto.CameraMake = item.CameraMake;
|
||||
dto.CameraModel = item.CameraModel;
|
||||
dto.Software = item.Software;
|
||||
dto.ExposureTime = item.ExposureTime;
|
||||
dto.FocalLength = item.FocalLength;
|
||||
dto.ImageOrientation = item.Orientation;
|
||||
dto.Aperture = item.Aperture;
|
||||
dto.ShutterSpeed = item.ShutterSpeed;
|
||||
}
|
||||
|
||||
private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
|
||||
{
|
||||
@ -501,7 +514,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
{
|
||||
return _libraryManager.GetPerson(c);
|
||||
}
|
||||
catch (IOException ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting person {0}", ex, c);
|
||||
return null;
|
||||
@ -1187,21 +1200,24 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
}
|
||||
|
||||
var book = item as Book;
|
||||
|
||||
if (book != null)
|
||||
{
|
||||
SetBookProperties(dto, book);
|
||||
}
|
||||
|
||||
var tvChannel = item as LiveTvChannel;
|
||||
var photo = item as Photo;
|
||||
if (photo != null)
|
||||
{
|
||||
SetPhotoProperties(dto, photo);
|
||||
}
|
||||
|
||||
var tvChannel = item as LiveTvChannel;
|
||||
if (tvChannel != null)
|
||||
{
|
||||
dto.MediaSources = tvChannel.GetMediaSources(true).ToList();
|
||||
}
|
||||
|
||||
var channelItem = item as IChannelItem;
|
||||
|
||||
if (channelItem != null)
|
||||
{
|
||||
dto.ChannelId = channelItem.ChannelId;
|
||||
|
@ -117,6 +117,13 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
return;
|
||||
}
|
||||
|
||||
var themeMedia = item as IThemeMedia;
|
||||
if (themeMedia != null && themeMedia.IsThemeMedia)
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Users.Count == 0)
|
||||
{
|
||||
return;
|
||||
@ -142,6 +149,13 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
return;
|
||||
}
|
||||
|
||||
var themeMedia = item as IThemeMedia;
|
||||
if (themeMedia != null && themeMedia.IsThemeMedia)
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Users.Count == 0)
|
||||
{
|
||||
return;
|
||||
|
@ -61,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
|
||||
// Mono.Nat does never rise this event. The event is there however it is useless.
|
||||
// You could remove it with no risk.
|
||||
// NatUtility.DeviceLost += NatUtility_DeviceLost;
|
||||
NatUtility.DeviceLost += NatUtility_DeviceLost;
|
||||
|
||||
|
||||
// it is hard to say what one should do when an unhandled exception is raised
|
||||
@ -71,7 +71,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
|
||||
_isStarted = true;
|
||||
|
||||
_timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromHours(6), TimeSpan.FromHours(6));
|
||||
_timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
if (!_createdRules.Contains(address))
|
||||
{
|
||||
_createdRules.Add(address);
|
||||
|
||||
|
||||
var info = _appHost.GetSystemInfo();
|
||||
|
||||
CreatePortMap(device, info.HttpServerPortNumber);
|
||||
@ -141,11 +141,11 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
}
|
||||
|
||||
// As I said before, this method will be never invoked. You can remove it.
|
||||
//void NatUtility_DeviceLost(object sender, DeviceEventArgs e)
|
||||
//{
|
||||
// var device = e.Device;
|
||||
// _logger.Debug("NAT device lost: {0}", device.LocalAddress.ToString());
|
||||
//}
|
||||
void NatUtility_DeviceLost(object sender, DeviceEventArgs e)
|
||||
{
|
||||
var device = e.Device;
|
||||
_logger.Debug("NAT device lost: {0}", device.LocalAddress.ToString());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@ -167,7 +167,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
// This is not a significant improvement
|
||||
NatUtility.StopDiscovery();
|
||||
NatUtility.DeviceFound -= NatUtility_DeviceFound;
|
||||
//NatUtility.DeviceLost -= NatUtility_DeviceLost;
|
||||
NatUtility.DeviceLost -= NatUtility_DeviceLost;
|
||||
NatUtility.UnhandledException -= NatUtility_UnhandledException;
|
||||
}
|
||||
// Statements in try-block will no fail because StopDiscovery is a one-line
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.ScheduledTasks;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller;
|
||||
@ -42,7 +43,9 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
||||
private Timer LibraryUpdateTimer { get; set; }
|
||||
private readonly object _libraryChangedSyncLock = new object();
|
||||
|
||||
public Notifications(IInstallationManager installationManager, IUserManager userManager, ILogger logger, ITaskManager taskManager, INotificationManager notificationManager, ILibraryManager libraryManager, ISessionManager sessionManager, IServerApplicationHost appHost)
|
||||
private readonly IConfigurationManager _config;
|
||||
|
||||
public Notifications(IInstallationManager installationManager, IUserManager userManager, ILogger logger, ITaskManager taskManager, INotificationManager notificationManager, ILibraryManager libraryManager, ISessionManager sessionManager, IServerApplicationHost appHost, IConfigurationManager config)
|
||||
{
|
||||
_installationManager = installationManager;
|
||||
_userManager = userManager;
|
||||
@ -52,6 +55,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
||||
_libraryManager = libraryManager;
|
||||
_sessionManager = sessionManager;
|
||||
_appHost = appHost;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
@ -160,20 +164,25 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
||||
await SendNotification(notification).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
|
||||
{
|
||||
var item = e.MediaInfo;
|
||||
private NotificationOptions GetOptions()
|
||||
{
|
||||
return _config.GetConfiguration<NotificationOptions>("notifications");
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
_logger.Warn("PlaybackStart reported with null media info.");
|
||||
return;
|
||||
}
|
||||
void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
|
||||
{
|
||||
var item = e.MediaInfo;
|
||||
|
||||
var type = GetPlaybackNotificationType(item.MediaType);
|
||||
if (item == null)
|
||||
{
|
||||
_logger.Warn("PlaybackStart reported with null media info.");
|
||||
return;
|
||||
}
|
||||
|
||||
SendPlaybackNotification(type, e);
|
||||
}
|
||||
var type = GetPlaybackNotificationType(item.MediaType);
|
||||
|
||||
SendPlaybackNotification(type, e);
|
||||
}
|
||||
|
||||
void _sessionManager_PlaybackStopped(object sender, PlaybackStopEventArgs e)
|
||||
{
|
||||
@ -194,20 +203,24 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
|
||||
{
|
||||
var user = e.Users.FirstOrDefault();
|
||||
|
||||
var item = e.MediaInfo;
|
||||
|
||||
if (e.Item != null && e.Item.Parent == null)
|
||||
if (user != null && !GetOptions().IsEnabledToMonitorUser(type, user.Id.ToString("N")))
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
// TODO: This will also cause movie specials to not be reported
|
||||
return;
|
||||
}
|
||||
|
||||
var item = e.MediaInfo;
|
||||
var themeMedia = item as IThemeMedia;
|
||||
|
||||
if (themeMedia != null && themeMedia.IsThemeMedia)
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var notification = new NotificationRequest
|
||||
{
|
||||
NotificationType = type,
|
||||
|
||||
ExcludeUserIds = e.Users.Select(i => i.Id.ToString("N")).ToList()
|
||||
NotificationType = type
|
||||
};
|
||||
|
||||
notification.Variables["ItemName"] = item.Name;
|
||||
|
@ -26,7 +26,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
private Timer _timer;
|
||||
private readonly TimeSpan _frequency = TimeSpan.FromHours(24);
|
||||
|
||||
private const string DefaultDeviceVersion = "Unknown version";
|
||||
private readonly ConcurrentDictionary<Guid, ClientInfo> _apps = new ConcurrentDictionary<Guid, ClientInfo>();
|
||||
|
||||
public UsageEntryPoint(ILogger logger, IApplicationHost applicationHost, INetworkManager networkManager, IHttpClient httpClient, ISessionManager sessionManager)
|
||||
|
@ -1,55 +0,0 @@
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
{
|
||||
public class WanAddressEntryPoint : IServerEntryPoint
|
||||
{
|
||||
public static string WanAddress;
|
||||
private Timer _timer;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
public WanAddressEntryPoint(IHttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
_timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromHours(24));
|
||||
}
|
||||
|
||||
private async void TimerCallback(object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = await _httpClient.Get(new HttpRequestOptions
|
||||
{
|
||||
Url = "http://bot.whatismyipaddress.com/"
|
||||
|
||||
}).ConfigureAwait(false))
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
WanAddress = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_timer != null)
|
||||
{
|
||||
_timer.Dispose();
|
||||
_timer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -298,8 +298,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
/// <exception cref="ArgumentNullException">path</exception>
|
||||
/// <exception cref="System.ArgumentNullException">path</exception>
|
||||
public object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary<string, string> responseHeaders = null, bool isHeadRequest = false)
|
||||
public object GetStaticFileResult(IRequest requestContext,
|
||||
string path,
|
||||
FileShare fileShare = FileShare.Read,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
@ -309,13 +314,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
return GetStaticFileResult(requestContext, path, MimeTypes.GetMimeType(path), null, fileShare, responseHeaders, isHeadRequest);
|
||||
}
|
||||
|
||||
public object GetStaticFileResult(IRequest requestContext,
|
||||
string path,
|
||||
public object GetStaticFileResult(IRequest requestContext,
|
||||
string path,
|
||||
string contentType,
|
||||
TimeSpan? cacheCuration = null,
|
||||
FileShare fileShare = FileShare.Read,
|
||||
FileShare fileShare = FileShare.Read,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false)
|
||||
bool isHeadRequest = false,
|
||||
bool throttle = false,
|
||||
long throttleLimit = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
@ -331,7 +338,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
|
||||
var cacheKey = path + dateModified.Ticks;
|
||||
|
||||
return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, cacheCuration, contentType, () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest);
|
||||
return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, cacheCuration, contentType, () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest, throttle, throttleLimit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -360,7 +367,29 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
/// <exception cref="System.ArgumentNullException">cacheKey
|
||||
/// or
|
||||
/// factoryFn</exception>
|
||||
public object GetStaticResult(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType, Func<Task<Stream>> factoryFn, IDictionary<string, string> responseHeaders = null, bool isHeadRequest = false)
|
||||
public object GetStaticResult(IRequest requestContext,
|
||||
Guid cacheKey,
|
||||
DateTime? lastDateModified,
|
||||
TimeSpan? cacheDuration,
|
||||
string contentType,
|
||||
Func<Task<Stream>> factoryFn,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false)
|
||||
{
|
||||
return GetStaticResult(requestContext, cacheKey, lastDateModified, cacheDuration, contentType, factoryFn,
|
||||
responseHeaders, isHeadRequest, false, 0);
|
||||
}
|
||||
|
||||
public object GetStaticResult(IRequest requestContext,
|
||||
Guid cacheKey,
|
||||
DateTime? lastDateModified,
|
||||
TimeSpan? cacheDuration,
|
||||
string contentType,
|
||||
Func<Task<Stream>> factoryFn,
|
||||
IDictionary<string, string> responseHeaders = null,
|
||||
bool isHeadRequest = false,
|
||||
bool throttle = false,
|
||||
long throttleLimit = 0)
|
||||
{
|
||||
if (cacheKey == Guid.Empty)
|
||||
{
|
||||
@ -386,15 +415,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
return result;
|
||||
}
|
||||
|
||||
return GetNonCachedResult(requestContext, contentType, factoryFn, responseHeaders, isHeadRequest);
|
||||
}
|
||||
|
||||
private async Task<IHasOptions> GetNonCachedResult(IRequest requestContext, string contentType, Func<Task<Stream>> factoryFn, IDictionary<string, string> responseHeaders = null, bool isHeadRequest = false)
|
||||
{
|
||||
var compress = ShouldCompressResponse(requestContext, contentType);
|
||||
|
||||
var hasOptions = await GetStaticResult(requestContext, responseHeaders, contentType, factoryFn, compress, isHeadRequest).ConfigureAwait(false);
|
||||
|
||||
var hasOptions = GetStaticResult(requestContext, responseHeaders, contentType, factoryFn, compress, isHeadRequest, throttle, throttleLimit).Result;
|
||||
AddResponseHeaders(hasOptions, responseHeaders);
|
||||
|
||||
return hasOptions;
|
||||
@ -460,8 +482,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
/// <param name="factoryFn">The factory fn.</param>
|
||||
/// <param name="compress">if set to <c>true</c> [compress].</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <param name="throttle">if set to <c>true</c> [throttle].</param>
|
||||
/// <param name="throttleLimit">The throttle limit.</param>
|
||||
/// <returns>Task{IHasOptions}.</returns>
|
||||
private async Task<IHasOptions> GetStaticResult(IRequest requestContext, IDictionary<string, string> responseHeaders, string contentType, Func<Task<Stream>> factoryFn, bool compress, bool isHeadRequest)
|
||||
private async Task<IHasOptions> GetStaticResult(IRequest requestContext, IDictionary<string, string> responseHeaders, string contentType, Func<Task<Stream>> factoryFn, bool compress, bool isHeadRequest, bool throttle, long throttleLimit = 0)
|
||||
{
|
||||
var requestedCompressionType = requestContext.GetCompressionType();
|
||||
|
||||
@ -473,7 +497,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
|
||||
if (!string.IsNullOrEmpty(rangeHeader))
|
||||
{
|
||||
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest);
|
||||
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest)
|
||||
{
|
||||
Throttle = throttle,
|
||||
ThrottleLimit = throttleLimit
|
||||
};
|
||||
}
|
||||
|
||||
responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
|
||||
@ -485,7 +513,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
return GetHttpResult(new byte[] { }, contentType);
|
||||
}
|
||||
|
||||
return new StreamWriter(stream, contentType, _logger);
|
||||
return new StreamWriter(stream, contentType, _logger)
|
||||
{
|
||||
Throttle = throttle,
|
||||
ThrottleLimit = throttleLimit
|
||||
};
|
||||
}
|
||||
|
||||
string content;
|
||||
|
@ -1,10 +1,10 @@
|
||||
using System.Threading;
|
||||
using ServiceStack.Web;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
@ -24,6 +24,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
private long RangeLength { get; set; }
|
||||
private long TotalContentLength { get; set; }
|
||||
|
||||
public bool Throttle { get; set; }
|
||||
public long ThrottleLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _options
|
||||
/// </summary>
|
||||
@ -159,6 +162,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
/// <param name="responseStream">The response stream.</param>
|
||||
public void WriteTo(Stream responseStream)
|
||||
{
|
||||
if (Throttle)
|
||||
{
|
||||
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
|
||||
{
|
||||
MinThrottlePosition = ThrottleLimit * 180
|
||||
};
|
||||
}
|
||||
var task = WriteToAsync(responseStream);
|
||||
|
||||
Task.WaitAll(task);
|
||||
|
@ -36,6 +36,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
get { return _options; }
|
||||
}
|
||||
|
||||
public bool Throttle { get; set; }
|
||||
public long ThrottleLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
|
||||
/// </summary>
|
||||
@ -77,6 +80,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
/// <param name="responseStream">The response stream.</param>
|
||||
public void WriteTo(Stream responseStream)
|
||||
{
|
||||
if (Throttle)
|
||||
{
|
||||
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
|
||||
{
|
||||
MinThrottlePosition = ThrottleLimit * 180
|
||||
};
|
||||
}
|
||||
var task = WriteToAsync(responseStream);
|
||||
|
||||
Task.WaitAll(task);
|
||||
@ -98,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error streaming media", ex);
|
||||
Logger.ErrorException("Error streaming data", ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
|
@ -0,0 +1,389 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for streaming data with throttling support.
|
||||
/// </summary>
|
||||
public class ThrottledStream : Stream
|
||||
{
|
||||
/// <summary>
|
||||
/// A constant used to specify an infinite number of bytes that can be transferred per second.
|
||||
/// </summary>
|
||||
public const long Infinite = 0;
|
||||
|
||||
#region Private members
|
||||
/// <summary>
|
||||
/// The base stream.
|
||||
/// </summary>
|
||||
private readonly Stream _baseStream;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum bytes per second that can be transferred through the base stream.
|
||||
/// </summary>
|
||||
private long _maximumBytesPerSecond;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes that has been transferred since the last throttle.
|
||||
/// </summary>
|
||||
private long _byteCount;
|
||||
|
||||
/// <summary>
|
||||
/// The start time in milliseconds of the last throttle.
|
||||
/// </summary>
|
||||
private long _start;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Gets the current milliseconds.
|
||||
/// </summary>
|
||||
/// <value>The current milliseconds.</value>
|
||||
protected long CurrentMilliseconds
|
||||
{
|
||||
get
|
||||
{
|
||||
return Environment.TickCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum bytes per second that can be transferred through the base stream.
|
||||
/// </summary>
|
||||
/// <value>The maximum bytes per second.</value>
|
||||
public long MaximumBytesPerSecond
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maximumBytesPerSecond;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (MaximumBytesPerSecond != value)
|
||||
{
|
||||
_maximumBytesPerSecond = value;
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports reading.
|
||||
/// </summary>
|
||||
/// <returns>true if the stream supports reading; otherwise, false.</returns>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return _baseStream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports seeking.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns>true if the stream supports seeking; otherwise, false.</returns>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return _baseStream.CanSeek;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current stream supports writing.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns>true if the stream supports writing; otherwise, false.</returns>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return _baseStream.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length in bytes of the stream.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns>A long value representing the length of the stream in bytes.</returns>
|
||||
/// <exception cref="T:System.NotSupportedException">The base stream does not support seeking. </exception>
|
||||
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return _baseStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the current stream.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns>The current position within the stream.</returns>
|
||||
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
|
||||
/// <exception cref="T:System.NotSupportedException">The base stream does not support seeking. </exception>
|
||||
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _baseStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
_baseStream.Position = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public long MinThrottlePosition;
|
||||
|
||||
#region Ctor
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:ThrottledStream"/> class.
|
||||
/// </summary>
|
||||
/// <param name="baseStream">The base stream.</param>
|
||||
/// <param name="maximumBytesPerSecond">The maximum bytes per second that can be transferred through the base stream.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <see cref="baseStream"/> is a null reference.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="maximumBytesPerSecond"/> is a negative value.</exception>
|
||||
public ThrottledStream(Stream baseStream, long maximumBytesPerSecond)
|
||||
{
|
||||
if (baseStream == null)
|
||||
{
|
||||
throw new ArgumentNullException("baseStream");
|
||||
}
|
||||
|
||||
if (maximumBytesPerSecond < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("maximumBytesPerSecond",
|
||||
maximumBytesPerSecond, "The maximum number of bytes per second can't be negative.");
|
||||
}
|
||||
|
||||
_baseStream = baseStream;
|
||||
_maximumBytesPerSecond = maximumBytesPerSecond;
|
||||
_start = CurrentMilliseconds;
|
||||
_byteCount = 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public methods
|
||||
/// <summary>
|
||||
/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
|
||||
/// </summary>
|
||||
/// <exception cref="T:System.IO.IOException">An I/O error occurs.</exception>
|
||||
public override void Flush()
|
||||
{
|
||||
_baseStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
|
||||
/// </summary>
|
||||
/// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param>
|
||||
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
|
||||
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
|
||||
/// <returns>
|
||||
/// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
|
||||
/// </returns>
|
||||
/// <exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </exception>
|
||||
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
|
||||
/// <exception cref="T:System.NotSupportedException">The base stream does not support reading. </exception>
|
||||
/// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
|
||||
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
|
||||
/// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
Throttle(count);
|
||||
|
||||
return _baseStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position within the current stream.
|
||||
/// </summary>
|
||||
/// <param name="offset">A byte offset relative to the origin parameter.</param>
|
||||
/// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"></see> indicating the reference point used to obtain the new position.</param>
|
||||
/// <returns>
|
||||
/// The new position within the current stream.
|
||||
/// </returns>
|
||||
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
|
||||
/// <exception cref="T:System.NotSupportedException">The base stream does not support seeking, such as if the stream is constructed from a pipe or console output. </exception>
|
||||
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return _baseStream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the current stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The desired length of the current stream in bytes.</param>
|
||||
/// <exception cref="T:System.NotSupportedException">The base stream does not support both writing and seeking, such as if the stream is constructed from a pipe or console output. </exception>
|
||||
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
|
||||
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
_baseStream.SetLength(value);
|
||||
}
|
||||
|
||||
private long _bytesWritten;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
|
||||
/// </summary>
|
||||
/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
|
||||
/// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
|
||||
/// <param name="count">The number of bytes to be written to the current stream.</param>
|
||||
/// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
|
||||
/// <exception cref="T:System.NotSupportedException">The base stream does not support writing. </exception>
|
||||
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
|
||||
/// <exception cref="T:System.ArgumentNullException">buffer is null. </exception>
|
||||
/// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length. </exception>
|
||||
/// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
Throttle(count);
|
||||
|
||||
_baseStream.Write(buffer, offset, count);
|
||||
|
||||
_bytesWritten += count;
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
await ThrottleAsync(count, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await _baseStream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_bytesWritten += count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return _baseStream.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Protected methods
|
||||
/// <summary>
|
||||
/// Throttles for the specified buffer size in bytes.
|
||||
/// </summary>
|
||||
/// <param name="bufferSizeInBytes">The buffer size in bytes.</param>
|
||||
protected void Throttle(int bufferSizeInBytes)
|
||||
{
|
||||
if (_bytesWritten < MinThrottlePosition)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the buffer isn't empty.
|
||||
if (_maximumBytesPerSecond <= 0 || bufferSizeInBytes <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_byteCount += bufferSizeInBytes;
|
||||
long elapsedMilliseconds = CurrentMilliseconds - _start;
|
||||
|
||||
if (elapsedMilliseconds > 0)
|
||||
{
|
||||
// Calculate the current bps.
|
||||
long bps = _byteCount * 1000L / elapsedMilliseconds;
|
||||
|
||||
// If the bps are more then the maximum bps, try to throttle.
|
||||
if (bps > _maximumBytesPerSecond)
|
||||
{
|
||||
// Calculate the time to sleep.
|
||||
long wakeElapsed = _byteCount * 1000L / _maximumBytesPerSecond;
|
||||
int toSleep = (int)(wakeElapsed - elapsedMilliseconds);
|
||||
|
||||
if (toSleep > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
// The time to sleep is more then a millisecond, so sleep.
|
||||
Thread.Sleep(toSleep);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
// Eatup ThreadAbortException.
|
||||
}
|
||||
|
||||
// A sleep has been done, reset.
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task ThrottleAsync(int bufferSizeInBytes, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_bytesWritten < MinThrottlePosition)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the buffer isn't empty.
|
||||
if (_maximumBytesPerSecond <= 0 || bufferSizeInBytes <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_byteCount += bufferSizeInBytes;
|
||||
long elapsedMilliseconds = CurrentMilliseconds - _start;
|
||||
|
||||
if (elapsedMilliseconds > 0)
|
||||
{
|
||||
// Calculate the current bps.
|
||||
long bps = _byteCount * 1000L / elapsedMilliseconds;
|
||||
|
||||
// If the bps are more then the maximum bps, try to throttle.
|
||||
if (bps > _maximumBytesPerSecond)
|
||||
{
|
||||
// Calculate the time to sleep.
|
||||
long wakeElapsed = _byteCount * 1000L / _maximumBytesPerSecond;
|
||||
int toSleep = (int)(wakeElapsed - elapsedMilliseconds);
|
||||
|
||||
if (toSleep > 1)
|
||||
{
|
||||
// The time to sleep is more then a millisecond, so sleep.
|
||||
await Task.Delay(toSleep, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// A sleep has been done, reset.
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will reset the bytecount to 0 and reset the start time to the current time.
|
||||
/// </summary>
|
||||
protected void Reset()
|
||||
{
|
||||
long difference = CurrentMilliseconds - _start;
|
||||
|
||||
// Only reset counters when a known history is available of more then 1 second.
|
||||
if (difference > 1000)
|
||||
{
|
||||
_byteCount = 0;
|
||||
_start = CurrentMilliseconds;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -114,11 +114,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="fileSystem">The file system.</param>
|
||||
/// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns>
|
||||
private static bool ContainsMusic(IEnumerable<FileSystemInfo> list,
|
||||
private static bool ContainsMusic(IEnumerable<FileSystemInfo> list,
|
||||
bool isMusicMediaFolder,
|
||||
bool allowSubfolders,
|
||||
IDirectoryService directoryService,
|
||||
ILogger logger,
|
||||
bool allowSubfolders,
|
||||
IDirectoryService directoryService,
|
||||
ILogger logger,
|
||||
IFileSystem fileSystem)
|
||||
{
|
||||
// If list contains at least 2 audio files or at least one and no video files consider it to contain music
|
||||
@ -154,7 +154,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
|
||||
}
|
||||
else if (EntityResolutionHelper.IsVideoFile(fullName)) return false;
|
||||
else if (EntityResolutionHelper.IsVideoPlaceHolder(fullName)) return false;
|
||||
|
||||
|
||||
if (foundAudio >= 2)
|
||||
{
|
||||
return true;
|
||||
@ -179,10 +179,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsMultiDiscFolder(string path)
|
||||
public static bool IsMultiDiscFolder(string path)
|
||||
{
|
||||
return false;
|
||||
//return EntityResolutionHelper.IsMultiPartFolder(path);
|
||||
return EntityResolutionHelper.IsMultiDiscAlbumFolder(path);
|
||||
}
|
||||
|
||||
private static bool IsAdditionalSubfolderAllowed(FileSystemInfo directory)
|
||||
|
@ -0,0 +1,39 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||
{
|
||||
public class PhotoAlbumResolver : FolderResolver<PhotoAlbum>
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves the specified args.
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <returns>Trailer.</returns>
|
||||
protected override PhotoAlbum Resolve(ItemResolveArgs args)
|
||||
{
|
||||
// Must be an image file within a photo collection
|
||||
if (!args.IsRoot && args.IsDirectory && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (HasPhotos(args))
|
||||
{
|
||||
return new PhotoAlbum
|
||||
{
|
||||
Path = args.Path
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool HasPhotos(ItemResolveArgs args)
|
||||
{
|
||||
return args.FileSystemChildren.Any(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && PhotoResolver.IsImageFile(i.FullName));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +1,14 @@
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||
{
|
||||
public class PhotoResolver : ItemResolver<Photo>
|
||||
{
|
||||
private readonly IServerApplicationPaths _applicationPaths;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PhotoResolver" /> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationPaths">The application paths.</param>
|
||||
public PhotoResolver(IServerApplicationPaths applicationPaths)
|
||||
{
|
||||
_applicationPaths = applicationPaths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the specified args.
|
||||
/// </summary>
|
||||
@ -27,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||
protected override Photo Resolve(ItemResolveArgs args)
|
||||
{
|
||||
// Must be an image file within a photo collection
|
||||
if (!args.IsDirectory && IsImageFile(args.Path) && string.Equals(args.GetCollectionType(), "photos", StringComparison.OrdinalIgnoreCase))
|
||||
if (!args.IsDirectory && IsImageFile(args.Path) && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new Photo
|
||||
{
|
||||
@ -39,10 +29,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||
}
|
||||
|
||||
protected static string[] ImageExtensions = { ".tiff", ".jpeg", ".jpg", ".png", ".aiff" };
|
||||
protected bool IsImageFile(string path)
|
||||
internal static bool IsImageFile(string path)
|
||||
{
|
||||
return !path.EndsWith("folder.jpg", StringComparison.OrdinalIgnoreCase)
|
||||
&& ImageExtensions.Any(p => path.EndsWith(p, StringComparison.OrdinalIgnoreCase));
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
return !string.Equals(filename, "folder.jpg", StringComparison.OrdinalIgnoreCase)
|
||||
&& ImageExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -475,13 +475,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
}
|
||||
|
||||
item.ChannelType = channelInfo.ChannelType;
|
||||
item.ProviderImageUrl = channelInfo.ImageUrl;
|
||||
item.HasProviderImage = channelInfo.HasImage;
|
||||
item.ProviderImagePath = channelInfo.ImagePath;
|
||||
item.ExternalId = channelInfo.Id;
|
||||
item.ServiceName = serviceName;
|
||||
item.Number = channelInfo.Number;
|
||||
|
||||
var replaceImages = new List<ImageType>();
|
||||
|
||||
if (!string.Equals(item.ProviderImageUrl, channelInfo.ImageUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
isNew = true;
|
||||
replaceImages.Add(ImageType.Primary);
|
||||
}
|
||||
if (!string.Equals(item.ProviderImagePath, channelInfo.ImagePath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
isNew = true;
|
||||
replaceImages.Add(ImageType.Primary);
|
||||
}
|
||||
|
||||
item.ProviderImageUrl = channelInfo.ImageUrl;
|
||||
item.HasProviderImage = channelInfo.HasImage;
|
||||
item.ProviderImagePath = channelInfo.ImagePath;
|
||||
|
||||
if (string.IsNullOrEmpty(item.Name))
|
||||
{
|
||||
item.Name = channelInfo.Name;
|
||||
@ -489,7 +503,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
|
||||
await item.RefreshMetadata(new MetadataRefreshOptions
|
||||
{
|
||||
ForceSave = isNew
|
||||
ForceSave = isNew,
|
||||
ReplaceImages = replaceImages.Distinct().ToList()
|
||||
|
||||
}, cancellationToken);
|
||||
|
||||
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Movies",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "\u0627\u0644\u062d\u0644\u0642\u0627\u062a",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "\u0627\u0644\u0628\u0648\u0645\u0627\u062a",
|
||||
"TabSongs": "\u0627\u0644\u0627\u063a\u0627\u0646\u0649",
|
||||
"TabMusicVideos": "\u0645\u0648\u0633\u064a\u0642\u0649 \u0627\u0644\u0641\u064a\u062f\u064a\u0648",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Movies",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "Episodes",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Songs",
|
||||
"TabMusicVideos": "Music Videos",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "\u010c\u00edslo s\u00e9rie",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "\u010c\u00edslo epizody",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Filmy",
|
||||
"TabSeries": "S\u00e9rie",
|
||||
"TabEpisodes": "Epizody",
|
||||
"TabTrailers": "Uk\u00e1zky\/trailery",
|
||||
"TabGames": "Hry",
|
||||
"TabAlbums": "Alba",
|
||||
"TabSongs": "Skladby",
|
||||
"TabMusicVideos": "Hudebn\u00ed videa",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Film",
|
||||
"TabSeries": "Serier",
|
||||
"TabEpisodes": "Episoder",
|
||||
"TabTrailers": "Trailere",
|
||||
"TabGames": "Spil",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Sange",
|
||||
"TabMusicVideos": "Musik Videoer",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -25,23 +25,23 @@
|
||||
"NoPluginConfigurationMessage": "Bei diesem Plugin kann nichts eingestellt werden.",
|
||||
"NoPluginsInstalledMessage": "Sie haben keine Plugins installiert.",
|
||||
"BrowsePluginCatalogMessage": "Durchsuchen Sie unsere Bibliothek um alle verf\u00fcgbaren Plugins anzuzeigen.",
|
||||
"MessageKeyEmailedTo": "Key emailed to {0}.",
|
||||
"MessageKeyEmailedTo": "E-Mail mit Zugangsschl\u00fcssel an: {0}.",
|
||||
"MessageKeysLinked": "Schl\u00fcssel verkn\u00fcpft.",
|
||||
"HeaderConfirmation": "Best\u00e4tigung",
|
||||
"MessageKeyUpdated": "Danke. Ihr Unterst\u00fctzerschl\u00fcssel wurde aktualisiert.",
|
||||
"MessageKeyRemoved": "Danke. Ihr Unterst\u00fctzerschl\u00fcssel wurde entfernt.",
|
||||
"ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
|
||||
"ErrorLaunchingChromecast": "W\u00e4hrend des startens von Chromecast ist ein Fehler aufgetreten. Bitte stelle sicher, dass dein Ger\u00e4te mit dem WLAN verbunden ist.",
|
||||
"HeaderSearch": "Suche",
|
||||
"LabelArtist": "K\u00fcnstler",
|
||||
"LabelArtist": "Interpret",
|
||||
"LabelMovie": "Film",
|
||||
"LabelMusicVideo": "Musikvideo",
|
||||
"LabelEpisode": "Episode",
|
||||
"LabelSeries": "Serie",
|
||||
"LabelStopping": "Stopping",
|
||||
"LabelStopping": "Stoppe",
|
||||
"LabelCancelled": "(abgebrochen)",
|
||||
"LabelFailed": "(fehlgeschlagen)",
|
||||
"LabelAbortedByServerShutdown": "(Durch herunterfahrenden Server abgebrochen)",
|
||||
"LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
|
||||
"LabelScheduledTaskLastRan": "Zuletzt ausgef\u00fchrt vor: {0}. Ben\u00f6tigte Zeit: {1}.",
|
||||
"HeaderDeleteTaskTrigger": "Entferne Aufgabenausl\u00f6ser",
|
||||
"HeaderTaskTriggers": "Aufgabenausl\u00f6ser",
|
||||
"MessageDeleteTaskTrigger": "Sind Sie sicher, dass sie diesen Aufgabenausl\u00f6ser entfernen wollen?",
|
||||
@ -52,8 +52,8 @@
|
||||
"HeaderSelectAudio": "W\u00e4hle Audio",
|
||||
"HeaderSelectSubtitles": "W\u00f6hle Untertitel",
|
||||
"LabelDefaultStream": "(Default)",
|
||||
"LabelForcedStream": "(Forced)",
|
||||
"LabelDefaultForcedStream": "(Default\/Forced)",
|
||||
"LabelForcedStream": "(Erzwungen)",
|
||||
"LabelDefaultForcedStream": "(Standard\/Erzwungen)",
|
||||
"LabelUnknownLanguage": "Unbekannte Sprache",
|
||||
"ButtonMute": "Stumm",
|
||||
"ButtonUnmute": "Ton ein",
|
||||
@ -63,31 +63,31 @@
|
||||
"ButtonPlay": "Abspielen",
|
||||
"ButtonEdit": "Bearbeiten",
|
||||
"ButtonQueue": "Warteschlange",
|
||||
"ButtonPlayTrailer": "Spiele Trailer",
|
||||
"ButtonPlayTrailer": "Trailer abspielen",
|
||||
"ButtonPlaylist": "Wiedergabeliste",
|
||||
"ButtonPreviousTrack": "Vorheriges St\u00fcck",
|
||||
"LabelEnabled": "Aktivieren",
|
||||
"LabelDisabled": "Deaktivieren",
|
||||
"ButtonMoreInformation": "mehr Informationen",
|
||||
"LabelNoUnreadNotifications": "keine ungelesenen Benachrichtigungen",
|
||||
"LabelNoUnreadNotifications": "Keine ungelesenen Benachrichtigungen",
|
||||
"ButtonViewNotifications": "Benachrichtigungen anschauen",
|
||||
"ButtonMarkTheseRead": "Mark these read",
|
||||
"ButtonClose": "Close",
|
||||
"LabelAllPlaysSentToPlayer": "All plays will be sent to the selected player.",
|
||||
"MessageInvalidUser": "Invalid user or password.",
|
||||
"ButtonMarkTheseRead": "Als gelesen markieren",
|
||||
"ButtonClose": "Schlie\u00dfen",
|
||||
"LabelAllPlaysSentToPlayer": "Alle Wiedergaben werden zum ausgew\u00e4hlten Abspielger\u00e4t gesendet.",
|
||||
"MessageInvalidUser": "Falscher Benutzername oder Passwort.",
|
||||
"HeaderAllRecordings": "Alle Aufnahmen",
|
||||
"RecommendationBecauseYouLike": "Because you like {0}",
|
||||
"RecommendationBecauseYouWatched": "Because you watched {0}",
|
||||
"RecommendationDirectedBy": "Directed by {0}",
|
||||
"RecommendationStarring": "Starring {0}",
|
||||
"HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation",
|
||||
"MessageConfirmRecordingCancellation": "Are you sure you wish to cancel this recording?",
|
||||
"MessageRecordingCancelled": "Recording cancelled.",
|
||||
"HeaderConfirmSeriesCancellation": "Confirm Series Cancellation",
|
||||
"MessageConfirmSeriesCancellation": "Are you sure you wish to cancel this series?",
|
||||
"MessageSeriesCancelled": "Series cancelled.",
|
||||
"HeaderConfirmRecordingDeletion": "Confirm Recording Deletion",
|
||||
"MessageConfirmRecordingDeletion": "Are you sure you wish to delete this recording?",
|
||||
"RecommendationBecauseYouLike": "Weil du auch {0} magst",
|
||||
"RecommendationBecauseYouWatched": "Weil du auch {0} angesehen hast",
|
||||
"RecommendationDirectedBy": "Unter der Regie von {0}",
|
||||
"RecommendationStarring": "In der Hauptrolle {0}",
|
||||
"HeaderConfirmRecordingCancellation": "Best\u00e4tige Aufzeichnungsabbruch",
|
||||
"MessageConfirmRecordingCancellation": "Bis du dir sicher, diese Aufzeichnung abzubrechen?",
|
||||
"MessageRecordingCancelled": "Aufzeichnung abgebrochen.",
|
||||
"HeaderConfirmSeriesCancellation": "Best\u00e4tige Serienabbruch",
|
||||
"MessageConfirmSeriesCancellation": "Bis du dir sicher, diese Serie abzubrechen?",
|
||||
"MessageSeriesCancelled": "Serie abgebrochen.",
|
||||
"HeaderConfirmRecordingDeletion": "Best\u00e4tige L\u00f6schung der Aufzeichnung",
|
||||
"MessageConfirmRecordingDeletion": "Bis du dir sicher, diese Aufzeichnung zu l\u00f6schen?",
|
||||
"MessageRecordingDeleted": "Aufnahme gel\u00f6scht",
|
||||
"ButonCancelRecording": "Aufnahme abbrechen",
|
||||
"MessageRecordingSaved": "Aufnahme gespeichert",
|
||||
@ -105,65 +105,65 @@
|
||||
"ButtonResetTuner": "Tuner zur\u00fccksetzen",
|
||||
"HeaderResetTuner": "Tuner zur\u00fccksetzen",
|
||||
"MessageConfirmResetTuner": "sind Sie sicher, dass Sie diesen Tuner zur\u00fccksetzen wollen? Alle aktiven Wiedergaben und Aufnahmen werden sofort beendet.",
|
||||
"ButtonCancelSeries": "Cancel Series",
|
||||
"HeaderSeriesRecordings": "Series Recordings",
|
||||
"ButtonCancelSeries": "Serien abbrechen",
|
||||
"HeaderSeriesRecordings": "Aufgezeichnete Serien",
|
||||
"LabelAnytime": "Jederzeit",
|
||||
"StatusRecording": "Aufnehmen",
|
||||
"StatusWatching": "Anschauing",
|
||||
"StatusRecordingProgram": "Recording {0}",
|
||||
"StatusWatchingProgram": "Watching {0}",
|
||||
"StatusRecordingProgram": "Aufzeichnung {0}",
|
||||
"StatusWatchingProgram": "Gesehen {0}",
|
||||
"HeaderSplitMedia": "Trenne Medien ab",
|
||||
"MessageConfirmSplitMedia": "Sind Sie sicher, dass Sie die Medienquellen in seperate Elemente aufteilen wollen?",
|
||||
"HeaderError": "Fehler",
|
||||
"MessagePleaseSelectOneItem": "Please select at least one item.",
|
||||
"MessagePleaseSelectOneItem": "Bitte w\u00e4hle mindestens eine Option aus.",
|
||||
"MessagePleaseSelectTwoItems": "Bitte w\u00e4hle mindestens zwei Optionen aus.",
|
||||
"MessageTheFollowingItemsWillBeGrouped": "Die folgenden Titel werden zu einem Element gruppiert:",
|
||||
"MessageConfirmItemGrouping": "Media Browser clients will automatically choose the optimal version to play based on device and network performance. Are you sure you wish to continue?",
|
||||
"MessageConfirmItemGrouping": "Media Browser Abspielger\u00e4te werden automatisch die optimale Version, basierend auf dem Endger\u00e4t und der Netzwerkperformance, f\u00fcr die Wiedergabe ausw\u00e4hlen. M\u00f6chtest du fortfahren?",
|
||||
"HeaderResume": "Fortsetzen",
|
||||
"HeaderMyViews": "Meine Ansichten",
|
||||
"HeaderLibraryFolders": "Media Folders",
|
||||
"HeaderLatestMedia": "Letzte Medien",
|
||||
"ButtonMoreItems": "More...",
|
||||
"HeaderLibraryFolders": "Medienverzeichnisse",
|
||||
"HeaderLatestMedia": "Neueste Medien",
|
||||
"ButtonMoreItems": "Mehr...",
|
||||
"ButtonMore": "Mehr",
|
||||
"HeaderFavoriteMovies": "Lieblingsfilme",
|
||||
"HeaderFavoriteShows": "Favorite Shows",
|
||||
"HeaderFavoriteShows": "Lieblingsserien",
|
||||
"HeaderFavoriteEpisodes": "Lieblingsepisoden",
|
||||
"HeaderFavoriteGames": "Lieblingsspiele",
|
||||
"HeaderRatingsDownloads": "Bewertung \/ Downloads",
|
||||
"HeaderConfirmProfileDeletion": "Best\u00e4tige Profill\u00f6schung",
|
||||
"MessageConfirmProfileDeletion": "Sind Sie sicher, dass Sie dieses Profil l\u00f6schen wollen?",
|
||||
"HeaderSelectServerCachePath": "W\u00e4hle Server Cache Pfad:",
|
||||
"HeaderSelectTranscodingPath": "Select Transcoding Temporary Path",
|
||||
"HeaderSelectTranscodingPath": "W\u00e4hle Pfad f\u00fcr tempor\u00e4re Transkodierdateien",
|
||||
"HeaderSelectImagesByNamePath": "W\u00e4hle 'Images By Name' Pfad",
|
||||
"HeaderSelectMetadataPath": "W\u00e4hle Metadaten Pfad",
|
||||
"HeaderSelectServerCachePathHelp": "Browse or enter the path to use for server cache files. The folder must be writeable.",
|
||||
"HeaderSelectTranscodingPathHelp": "Browse or enter the path to use for transcoding temporary files. The folder must be writeable.",
|
||||
"HeaderSelectImagesByNamePathHelp": "Browse or enter the path to your items by name folder. The folder must be writeable.",
|
||||
"HeaderSelectMetadataPathHelp": "Browse or enter the path you'd like to store metadata within. The folder must be writeable.",
|
||||
"HeaderSelectChannelDownloadPath": "Select Channel Download Path",
|
||||
"HeaderSelectChannelDownloadPathHelp": "Browse or enter the path to use for storing channel cache files. The folder must be writeable.",
|
||||
"HeaderSelectServerCachePathHelp": "Suche oder gib den Pfad f\u00fcr die Speicherung von Server Cache Dateien an. Das Verzeichnis muss beschreibbar sein.",
|
||||
"HeaderSelectTranscodingPathHelp": "Suche oder gib den Pfad f\u00fcr die Speicherung von tempor\u00e4ren Transkodierdateien an. Das Verzeichnis muss beschreibbar sein.",
|
||||
"HeaderSelectImagesByNamePathHelp": "Suche oder gib den Pfad f\u00fcr die Speicherung von Namensdaten an. Das Verzeichnis muss beschreibbar sein.",
|
||||
"HeaderSelectMetadataPathHelp": "Suche oder gib den Pfad f\u00fcr die Speicherung von Metadaten an. Das Verzeichnis muss beschreibbar sein.",
|
||||
"HeaderSelectChannelDownloadPath": "W\u00e4hle den Downloadpfad f\u00fcr Channel Plugins",
|
||||
"HeaderSelectChannelDownloadPathHelp": "Suche oder gib den Pfad f\u00fcr die Speicherung von Channel Cache Dateien an. Das Verzeichnis muss beschreibbar sein.",
|
||||
"OptionNewCollection": "Neu...",
|
||||
"ButtonAdd": "Hinzuf\u00fcgen",
|
||||
"ButtonRemove": "Entfernen",
|
||||
"LabelChapterDownloaders": "Chapter downloaders:",
|
||||
"LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.",
|
||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
||||
"HeaderLatestChannelMedia": "Latest Channel Items",
|
||||
"ButtonOrganizeFile": "Organize File",
|
||||
"ButtonDeleteFile": "Delete File",
|
||||
"HeaderOrganizeFile": "Organize File",
|
||||
"HeaderDeleteFile": "Delete File",
|
||||
"StatusSkipped": "Skipped",
|
||||
"StatusFailed": "Failed",
|
||||
"LabelChapterDownloaders": "Kapitel Downloader:",
|
||||
"LabelChapterDownloadersHelp": "Aktiviere und ordne die Kapitel Downloader nach deinen Pr\u00e4ferenzen. Downloader mit geringer Priorit\u00e4t werden nur genutzt um fehlende Informationen zu erg\u00e4nzen.",
|
||||
"HeaderFavoriteAlbums": "Lieblingsalben",
|
||||
"HeaderLatestChannelMedia": "Neueste Channel Inhalte",
|
||||
"ButtonOrganizeFile": "Organisiere Datei",
|
||||
"ButtonDeleteFile": "L\u00f6sche Datei",
|
||||
"HeaderOrganizeFile": "Organisiere Datei",
|
||||
"HeaderDeleteFile": "L\u00f6sche Datei",
|
||||
"StatusSkipped": "\u00dcbersprungen",
|
||||
"StatusFailed": "Fehlgeschlagen",
|
||||
"StatusSuccess": "Erfolgreich",
|
||||
"MessageFileWillBeDeleted": "Die folgende Datei wird gel\u00f6scht:",
|
||||
"MessageSureYouWishToProceed": "Bis du dir sicher fortfahren zu wollen?",
|
||||
"MessageDuplicatesWillBeDeleted": "Zus\u00e4tzlich werden folgende Duplikate gel\u00f6scht:",
|
||||
"MessageFollowingFileWillBeMovedFrom": "Die folgende Datei wird verschoben von:",
|
||||
"MessageDestinationTo": "nach:",
|
||||
"HeaderSelectWatchFolder": "Select Watch Folder",
|
||||
"HeaderSelectWatchFolderHelp": "Browse or enter the path to your watch folder. The folder must be writeable.",
|
||||
"OrganizePatternResult": "Result: {0}",
|
||||
"HeaderSelectWatchFolder": "W\u00e4hle \"Gesehen\" Verzeichnis",
|
||||
"HeaderSelectWatchFolderHelp": "Suche oder gib den Pfad f\u00fcr die Speicherung von \"Gesehen\" Informationen an. Das Verzeichnis muss beschreibbar sein.",
|
||||
"OrganizePatternResult": "Ergebnis: {0}",
|
||||
"HeaderRestart": "Neustart",
|
||||
"HeaderShutdown": "Herunterfahren",
|
||||
"MessageConfirmRestart": "Bist du dir sicher Media Browser Server neustarten zu wollen?",
|
||||
@ -193,146 +193,146 @@
|
||||
"LabelCurrentPath": "Aktueller Pfad:",
|
||||
"HeaderSelectMediaPath": "W\u00e4hle einen Medienpfad:",
|
||||
"ButtonNetwork": "Netzwerk",
|
||||
"MessageDirectoryPickerInstruction": "Network paths can be entered manually in the event the Network button fails to locate your devices. For example, {0} or {1}.",
|
||||
"HeaderMenu": "Menu",
|
||||
"ButtonOpen": "Open",
|
||||
"ButtonOpenInNewTab": "Open in new tab",
|
||||
"ButtonShuffle": "Shuffle",
|
||||
"ButtonInstantMix": "Instant mix",
|
||||
"ButtonResume": "Resume",
|
||||
"MessageDirectoryPickerInstruction": "Falls der Netzwerk Button deine Endger\u00e4te nicht automatisch findet, kannst du deren Netzwerkpfade auch manuell eintragen. Zum Beispiel {0} oder {1}.",
|
||||
"HeaderMenu": "Men\u00fc",
|
||||
"ButtonOpen": "\u00d6ffnen",
|
||||
"ButtonOpenInNewTab": "\u00d6ffne in neuem Tab",
|
||||
"ButtonShuffle": "Zufallswiedergabe",
|
||||
"ButtonInstantMix": "Schnellmix",
|
||||
"ButtonResume": "Wiederholen",
|
||||
"HeaderScenes": "Szenen",
|
||||
"HeaderAudioTracks": "Audio Tracks",
|
||||
"HeaderSubtitles": "Subtitles",
|
||||
"HeaderVideoQuality": "Video Quality",
|
||||
"MessageErrorPlayingVideo": "There was an error playing the video.",
|
||||
"MessageEnsureOpenTuner": "Please ensure there is an open tuner availalble.",
|
||||
"HeaderAudioTracks": "Audiospuren",
|
||||
"HeaderSubtitles": "Untertitel",
|
||||
"HeaderVideoQuality": "Videoqualit\u00e4t",
|
||||
"MessageErrorPlayingVideo": "Es gab einen Fehler bei der Videowiedergabe.",
|
||||
"MessageEnsureOpenTuner": "Bitte stelle sicher, dass ein freier Empf\u00e4nger verf\u00fcgbar ist.",
|
||||
"ButtonHome": "Home",
|
||||
"ButtonDashboard": "Dashboard",
|
||||
"ButtonReports": "Reports",
|
||||
"ButtonMetadataManager": "Metadata Manager",
|
||||
"HeaderTime": "Time",
|
||||
"ButtonDashboard": "Optionsleiste",
|
||||
"ButtonReports": "Meldungen",
|
||||
"ButtonMetadataManager": "Metadaten Manager",
|
||||
"HeaderTime": "Zeit",
|
||||
"HeaderName": "Name",
|
||||
"HeaderAlbum": "Album",
|
||||
"HeaderAlbumArtist": "Album Artist",
|
||||
"HeaderArtist": "Artist",
|
||||
"LabelAddedOnDate": "Added {0}",
|
||||
"HeaderAlbumArtist": "Album-Interpret",
|
||||
"HeaderArtist": "Interpret",
|
||||
"LabelAddedOnDate": "Hinzugef\u00fcgt {0}",
|
||||
"ButtonStart": "Start",
|
||||
"HeaderChannels": "Kan\u00e4le",
|
||||
"HeaderMediaFolders": "Medien Ordner",
|
||||
"HeaderBlockItemsWithNoRating": "Block items with no rating information:",
|
||||
"OptionBlockOthers": "Others",
|
||||
"OptionBlockTvShows": "TV Shows",
|
||||
"OptionBlockTrailers": "Trailers",
|
||||
"OptionBlockMusic": "Music",
|
||||
"OptionBlockMovies": "Movies",
|
||||
"OptionBlockBooks": "Books",
|
||||
"OptionBlockGames": "Games",
|
||||
"OptionBlockLiveTvPrograms": "Live TV Programs",
|
||||
"OptionBlockLiveTvChannels": "Live TV Channels",
|
||||
"OptionBlockChannelContent": "Internet Channel Content",
|
||||
"ButtonRevoke": "Revoke",
|
||||
"MessageConfirmRevokeApiKey": "Are you sure you wish to revoke this api key? The application's connection to Media Browser will be abruptly terminated.",
|
||||
"HeaderConfirmRevokeApiKey": "Revoke Api Key",
|
||||
"HeaderMediaFolders": "Medienverzeichnisse",
|
||||
"HeaderBlockItemsWithNoRating": "Blockiere Elemente ohne Bewertungsinformationen:",
|
||||
"OptionBlockOthers": "Andere",
|
||||
"OptionBlockTvShows": "TV Serien",
|
||||
"OptionBlockTrailers": "Trailer",
|
||||
"OptionBlockMusic": "Musik",
|
||||
"OptionBlockMovies": "Filme",
|
||||
"OptionBlockBooks": "B\u00fccher",
|
||||
"OptionBlockGames": "Spiele",
|
||||
"OptionBlockLiveTvPrograms": "Live-TV Programm",
|
||||
"OptionBlockLiveTvChannels": "Live-TV Kan\u00e4le",
|
||||
"OptionBlockChannelContent": "Internet Channelinhalte",
|
||||
"ButtonRevoke": "Zur\u00fccknehmen",
|
||||
"MessageConfirmRevokeApiKey": "Bist du dir sicher den API Schl\u00fcssel zur\u00fccknehmen zu wollen? Anwendungen die mit Media Browser verbunden sind werden umgehend gestoppt.",
|
||||
"HeaderConfirmRevokeApiKey": "Nehme API Schl\u00fcssel zur\u00fcck",
|
||||
"ValueContainer": "Container: {0}",
|
||||
"ValueAudioCodec": "Audio Codec: {0}",
|
||||
"ValueVideoCodec": "Video Codec: {0}",
|
||||
"ValueCodec": "Codec: {0}",
|
||||
"ValueConditions": "Conditions: {0}",
|
||||
"LabelAll": "All",
|
||||
"HeaderDeleteImage": "Delete Image",
|
||||
"MessageFileNotFound": "File not found.",
|
||||
"MessageFileReadError": "An error occurred reading this file.",
|
||||
"ButtonNextPage": "Next Page",
|
||||
"ButtonPreviousPage": "Previous Page",
|
||||
"ButtonMoveLeft": "Move left",
|
||||
"ButtonMoveRight": "Move right",
|
||||
"ButtonBrowseOnlineImages": "Browse online images",
|
||||
"HeaderDeleteItem": "Delete Item",
|
||||
"ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
|
||||
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
|
||||
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
|
||||
"MessageItemSaved": "Item saved.",
|
||||
"ValueConditions": "Bedingungen: {0}",
|
||||
"LabelAll": "Alle",
|
||||
"HeaderDeleteImage": "L\u00f6sche Bild",
|
||||
"MessageFileNotFound": "Datei nicht gefunden.",
|
||||
"MessageFileReadError": "Fehler beim lesen der Datei",
|
||||
"ButtonNextPage": "N\u00e4chste Seite",
|
||||
"ButtonPreviousPage": "Vorherige Seite",
|
||||
"ButtonMoveLeft": "Nach links",
|
||||
"ButtonMoveRight": "Nach rechts",
|
||||
"ButtonBrowseOnlineImages": "Durchsuche Onlinebilder",
|
||||
"HeaderDeleteItem": "L\u00f6sche Element",
|
||||
"ConfirmDeleteItem": "Bist du dir sicher dieses Element aus deiner Bibliothek zu l\u00f6schen?",
|
||||
"MessagePleaseEnterNameOrId": "Bitte gib einen Namen oder eine externe Id an.",
|
||||
"MessageValueNotCorrect": "Der eingegeben Wert ist nicht korrekt. Bitte versuche es noch einmal.",
|
||||
"MessageItemSaved": "Element gespeichert",
|
||||
"OptionEnded": "Beendent",
|
||||
"OptionContinuing": "Fortdauernd",
|
||||
"OptionOff": "Aus",
|
||||
"OptionOn": "Ein",
|
||||
"HeaderFields": "Fields",
|
||||
"HeaderFieldsHelp": "Slide a field to 'off' to lock it and prevent it's data from being changed.",
|
||||
"HeaderLiveTV": "Live TV",
|
||||
"MissingLocalTrailer": "Missing local trailer.",
|
||||
"MissingPrimaryImage": "Missing primary image.",
|
||||
"MissingBackdropImage": "Missing backdrop image.",
|
||||
"MissingLogoImage": "Missing logo image.",
|
||||
"MissingEpisode": "Missing episode.",
|
||||
"HeaderFields": "Felder",
|
||||
"HeaderFieldsHelp": "Verschiebe ein Feld zu \"Aus\" um es zu sperren und \u00c4nderungen an dessen Daten zu verhindern.",
|
||||
"HeaderLiveTV": "Live-TV",
|
||||
"MissingLocalTrailer": "Fehlender lokaler Trailer.",
|
||||
"MissingPrimaryImage": "Fehlendes Hauptbild.",
|
||||
"MissingBackdropImage": "Fehlendes Hintergrundbild.",
|
||||
"MissingLogoImage": "Fehlendes Logobild.",
|
||||
"MissingEpisode": "Fehlende Episode",
|
||||
"OptionScreenshots": "Screenshots",
|
||||
"OptionBackdrops": "Backdrops",
|
||||
"OptionImages": "Images",
|
||||
"OptionKeywords": "Keywords",
|
||||
"OptionBackdrops": "Hintergr\u00fcnde",
|
||||
"OptionImages": "Bilder",
|
||||
"OptionKeywords": "Stichworte",
|
||||
"OptionTags": "Tags",
|
||||
"OptionStudios": "Studios",
|
||||
"OptionName": "Name",
|
||||
"OptionOverview": "Overview",
|
||||
"OptionOverview": "\u00dcbersicht:",
|
||||
"OptionGenres": "Genres",
|
||||
"OptionParentalRating": "Altersfreigabe",
|
||||
"OptionPeople": "People",
|
||||
"OptionPeople": "Personen",
|
||||
"OptionRuntime": "Dauer",
|
||||
"OptionProductionLocations": "Production Locations",
|
||||
"OptionBirthLocation": "Birth Location",
|
||||
"LabelAllChannels": "Alle Channel",
|
||||
"OptionProductionLocations": "Produktionsst\u00e4tten",
|
||||
"OptionBirthLocation": "Geburtsort",
|
||||
"LabelAllChannels": "Alle Kan\u00e4le",
|
||||
"LabelLiveProgram": "LIVE",
|
||||
"LabelNewProgram": "NEW",
|
||||
"LabelNewProgram": "NEU",
|
||||
"LabelPremiereProgram": "PREMIERE",
|
||||
"LabelHDProgram": "HD",
|
||||
"HeaderChangeFolderType": "Change Folder Type",
|
||||
"HeaderChangeFolderTypeHelp": "To change the folder type, please remove and rebuild the collection with the new type.",
|
||||
"HeaderAlert": "Alert",
|
||||
"MessagePleaseRestart": "Please restart to finish updating.",
|
||||
"HeaderChangeFolderType": "\u00c4ndere Verzeichnistyp",
|
||||
"HeaderChangeFolderTypeHelp": "Um den Verzeichnistyp zu \u00e4ndern, entferne diesen bitte und erstelle die Bibliothek mit dem neuen Typ erneut.",
|
||||
"HeaderAlert": "Alarm",
|
||||
"MessagePleaseRestart": "Dr\u00fccke auf Neustart um das Update abzuschlie\u00dfen",
|
||||
"ButtonRestart": "Neu starten",
|
||||
"MessagePleaseRefreshPage": "Please refresh this page to receive new updates from the server.",
|
||||
"ButtonHide": "Hide",
|
||||
"MessageSettingsSaved": "Settings saved.",
|
||||
"ButtonSignOut": "Sign Out",
|
||||
"ButtonMyProfile": "My Profile",
|
||||
"ButtonMyPreferences": "My Preferences",
|
||||
"MessageBrowserDoesNotSupportWebSockets": "This browser does not support web sockets. For a better experience, try a newer browser such as Chrome, Firefox, IE10+, Safari (iOS) or Opera.",
|
||||
"LabelInstallingPackage": "Installing {0}",
|
||||
"LabelPackageInstallCompleted": "{0} installation completed.",
|
||||
"LabelPackageInstallFailed": "{0} installation failed.",
|
||||
"LabelPackageInstallCancelled": "{0} installation cancelled.",
|
||||
"MessagePleaseRefreshPage": "Bitte aktualisiere diese Seite um neue Updates vom Server zu erhalten.",
|
||||
"ButtonHide": "Verstecke",
|
||||
"MessageSettingsSaved": "Einstellungen gespeichert",
|
||||
"ButtonSignOut": "Abmelden",
|
||||
"ButtonMyProfile": "Mein Profil",
|
||||
"ButtonMyPreferences": "Meine Einstellungen",
|
||||
"MessageBrowserDoesNotSupportWebSockets": "Dieser Browser unterst\u00fctzt keine Websockets. Versuche f\u00fcr ein besseres Nutzungserlebnis einen neueren Browser wie beispielsweise Chrome, Firefox, IE10+, Safari (iOS) oder Opera.",
|
||||
"LabelInstallingPackage": "Installiere {0}",
|
||||
"LabelPackageInstallCompleted": "{0} Installation abgeschlossen",
|
||||
"LabelPackageInstallFailed": "{0} Installation fehlgeschlagen",
|
||||
"LabelPackageInstallCancelled": "{0} Installation abgebrochen",
|
||||
"TabServer": "Server",
|
||||
"TabUsers": "Users",
|
||||
"TabLibrary": "Library",
|
||||
"TabUsers": "Benutzer",
|
||||
"TabLibrary": "Bibliothek",
|
||||
"TabMetadata": "Metadata",
|
||||
"TabDLNA": "DLNA",
|
||||
"TabLiveTV": "Live TV",
|
||||
"TabAutoOrganize": "Auto-Organize",
|
||||
"TabLiveTV": "Live-TV",
|
||||
"TabAutoOrganize": "Automatische Organisation",
|
||||
"TabPlugins": "Plugins",
|
||||
"TabAdvanced": "Erweitert",
|
||||
"TabHelp": "Help",
|
||||
"TabScheduledTasks": "Scheduled Tasks",
|
||||
"ButtonFullscreen": "Fullscreen",
|
||||
"ButtonAudioTracks": "Audio Tracks",
|
||||
"TabHelp": "Hilfe",
|
||||
"TabScheduledTasks": "Geplante Aufgaben",
|
||||
"ButtonFullscreen": "Vollbild",
|
||||
"ButtonAudioTracks": "Audiospuren",
|
||||
"ButtonSubtitles": "Untertitel",
|
||||
"ButtonScenes": "Szenen",
|
||||
"ButtonQuality": "Quality",
|
||||
"HeaderNotifications": "Notifications",
|
||||
"HeaderSelectPlayer": "Select Player:",
|
||||
"ButtonQuality": "Qualit\u00e4t",
|
||||
"HeaderNotifications": "Benachrichtigungen",
|
||||
"HeaderSelectPlayer": "W\u00e4hle Abspielger\u00e4t:",
|
||||
"ButtonSelect": "Ausw\u00e4hlen",
|
||||
"ButtonNew": "Neu",
|
||||
"MessageInternetExplorerWebm": "For best results with Internet Explorer please install the WebM playback plugin.",
|
||||
"HeaderVideoError": "Video Error",
|
||||
"ButtonAddToPlaylist": "Add to playlist",
|
||||
"HeaderAddToPlaylist": "Add to Playlist",
|
||||
"MessageInternetExplorerWebm": "Installiere f\u00fcr die besten Ergebnisse mit dem Internet Explorer bitte das WebM Playback Plugin.",
|
||||
"HeaderVideoError": "Video Fehler",
|
||||
"ButtonAddToPlaylist": "Hinzuf\u00fcgen zur Wiedergabeliste",
|
||||
"HeaderAddToPlaylist": "Zur Wiedergabeliste hinzuf\u00fcgen",
|
||||
"LabelName": "Name:",
|
||||
"ButtonSubmit": "Best\u00e4tigen",
|
||||
"LabelSelectPlaylist": "Playlist:",
|
||||
"OptionNewPlaylist": "New playlist...",
|
||||
"LabelSelectPlaylist": "Wiedergabeliste",
|
||||
"OptionNewPlaylist": "Neue Wiedergabeliste...",
|
||||
"MessageAddedToPlaylistSuccess": "Ok",
|
||||
"ButtonViewSeriesRecording": "View series recording",
|
||||
"ValueOriginalAirDate": "Original air date: {0}",
|
||||
"ButtonRemoveFromPlaylist": "Remove from playlist",
|
||||
"ButtonViewSeriesRecording": "Zeige Serienaufnahmen an",
|
||||
"ValueOriginalAirDate": "Urspr\u00fcngliches Ausstrahlungsdatum: {0}",
|
||||
"ButtonRemoveFromPlaylist": "Von Wiedergabeliste entfernen",
|
||||
"HeaderSpecials": "Extras",
|
||||
"HeaderTrailers": "Trailers",
|
||||
"HeaderTrailers": "Trailer",
|
||||
"HeaderAudio": "Audio",
|
||||
"HeaderResolution": "Aufl\u00f6sung",
|
||||
"HeaderVideo": "Video",
|
||||
@ -346,8 +346,8 @@
|
||||
"HeaderSeasonNumber": "Staffel Nummer",
|
||||
"HeaderNetwork": "Netzwerk",
|
||||
"HeaderYear": "Jahr",
|
||||
"HeaderGameSystem": "Game system",
|
||||
"HeaderPlayers": "Players",
|
||||
"HeaderGameSystem": "Spielesystem",
|
||||
"HeaderPlayers": "Abspielger\u00e4te",
|
||||
"HeaderEmbeddedImage": "Integriertes Bild",
|
||||
"HeaderTrack": "St\u00fcck",
|
||||
"HeaderDisc": "Disc",
|
||||
@ -358,7 +358,7 @@
|
||||
"OptionEpisodes": "Episoden",
|
||||
"OptionGames": "Spiele",
|
||||
"OptionGameSystems": "Spielsysteme",
|
||||
"OptionMusicArtists": "Musik-K\u00fcnstler",
|
||||
"OptionMusicArtists": "Musik-Interpreten",
|
||||
"OptionMusicAlbums": "Musik-Alben",
|
||||
"OptionMusicVideos": "Musik-Videos",
|
||||
"OptionSongs": "Lieder",
|
||||
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadatenspeicherer:",
|
||||
"LabelMetadataSaversHelp": "W\u00e4hle das Dateiformat in dem deine Metadaten gespeichert werden sollen.",
|
||||
"LabelImageFetchers": "Bildquellen",
|
||||
"LabelImageFetchersHelp": "Aktiviere und ordne deine bevorzugten Bildquellen nach Pr\u00e4ferenzen."
|
||||
"LabelImageFetchersHelp": "Aktiviere und ordne deine bevorzugten Bildquellen nach Pr\u00e4ferenzen.",
|
||||
"ButtonQueueAllFromHere": "Setze alles von hier auf Warteschlange",
|
||||
"ButtonPlayAllFromHere": "Spiele alles von hier",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identifiziere Element",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Reihenfolge Titeldarstellung:",
|
||||
"OptionSortName": "Sortiername",
|
||||
"OptionReleaseDate": "Ver\u00f6ffentlichungsdatum",
|
||||
"LabelSeasonNumber": "Staffelnummer:",
|
||||
"LabelDiscNumber": "Disc Nummer",
|
||||
"LabelParentNumber": "Ursprungsnummer",
|
||||
"LabelEpisodeNumber": "Episodennummer:",
|
||||
"LabelTrackNumber": "St\u00fcck Nummer:",
|
||||
"LabelNumber": "Nummer:",
|
||||
"LabelReleaseDate": "Ver\u00f6ffentlichungsdatum:",
|
||||
"LabelEndDate": "Endzeit:",
|
||||
"LabelYear": "Jahr:",
|
||||
"LabelDateOfBirth": "Geburtsatum:",
|
||||
"LabelBirthYear": "Geburtsjahr:",
|
||||
"LabelDeathDate": "Todesdatum:",
|
||||
"HeaderRemoveMediaLocation": "Entferne Medienquelle",
|
||||
"MessageConfirmRemoveMediaLocation": "Bist du dir sicher diese Medienquelle entfernen zu wollen?",
|
||||
"HeaderRenameMediaFolder": "Benenne Medienverzeichnis um",
|
||||
"LabelNewName": "Neuer Name:",
|
||||
"HeaderAddMediaFolder": "F\u00fcge Medienverzeichnis hinzu",
|
||||
"HeaderAddMediaFolderHelp": "Name (Filme, Musik, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Entferne Medienverzeichnis",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "Die folgenden Medienverzeichnisse werden aus deiner Bibliothek entfernt:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Bist du dir sicher dieses Medienverzeichnis entfernen zu wollen?",
|
||||
"ButtonRename": "Umbenennen",
|
||||
"ButtonChangeType": "\u00c4ndere Typ",
|
||||
"HeaderMediaLocations": "Medienquellen",
|
||||
"LabelFolderTypeValue": "Verzeichnistyp: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Die Pfadersetzung kann Serverpfade zu Netzwerkfreigaben umleiten, die von Endger\u00e4ten f\u00fcr die direkte Wiedergabe genutzt werden k\u00f6nnen.",
|
||||
"FolderTypeMixed": "Filme & Serien gemischt",
|
||||
"FolderTypeMovies": "Filme",
|
||||
"FolderTypeMusic": "Musik",
|
||||
"FolderTypeAdultVideos": "Videos f\u00fcr Erwachsene",
|
||||
"FolderTypePhotos": "Fotos",
|
||||
"FolderTypeMusicVideos": "Musikvideos",
|
||||
"FolderTypeHomeVideos": "Heimvideos",
|
||||
"FolderTypeGames": "Spiele",
|
||||
"FolderTypeBooks": "B\u00fccher",
|
||||
"FolderTypeTvShows": "TV Serien",
|
||||
"TabMovies": "Filme",
|
||||
"TabSeries": "Serie",
|
||||
"TabEpisodes": "Episoden",
|
||||
"TabTrailers": "Trailer",
|
||||
"TabGames": "Spiele",
|
||||
"TabAlbums": "Alben",
|
||||
"TabSongs": "Songs",
|
||||
"TabMusicVideos": "Musikvideos",
|
||||
"BirthPlaceValue": "Geburtsort: {0}",
|
||||
"DeathDateValue": "Gestorben: {0}",
|
||||
"BirthDateValue": "Geboren: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Movies",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "\u03ac\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
|
||||
"TabSongs": "\u03c4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
|
||||
"TabMusicVideos": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u03b2\u03af\u03bd\u03c4\u03b5\u03bf",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -125,10 +125,10 @@
|
||||
"HeaderLatestMedia": "Latest Media",
|
||||
"ButtonMoreItems": "More...",
|
||||
"ButtonMore": "More",
|
||||
"HeaderFavoriteMovies": "Favorite Movies",
|
||||
"HeaderFavoriteShows": "Favorite Shows",
|
||||
"HeaderFavoriteEpisodes": "Favorite Episodes",
|
||||
"HeaderFavoriteGames": "Favorite Games",
|
||||
"HeaderFavoriteMovies": "Favourite Movies",
|
||||
"HeaderFavoriteShows": "Favourite Shows",
|
||||
"HeaderFavoriteEpisodes": "Favourite Episodes",
|
||||
"HeaderFavoriteGames": "Favourite Games",
|
||||
"HeaderRatingsDownloads": "Rating \/ Downloads",
|
||||
"HeaderConfirmProfileDeletion": "Confirm Profile Deletion",
|
||||
"MessageConfirmProfileDeletion": "Are you sure you wish to delete this profile?",
|
||||
@ -147,11 +147,11 @@
|
||||
"ButtonRemove": "Remove",
|
||||
"LabelChapterDownloaders": "Chapter downloaders:",
|
||||
"LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.",
|
||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
||||
"HeaderFavoriteAlbums": "Favourite Albums",
|
||||
"HeaderLatestChannelMedia": "Latest Channel Items",
|
||||
"ButtonOrganizeFile": "Organize File",
|
||||
"ButtonOrganizeFile": "Organise File",
|
||||
"ButtonDeleteFile": "Delete File",
|
||||
"HeaderOrganizeFile": "Organize File",
|
||||
"HeaderOrganizeFile": "Organise File",
|
||||
"HeaderDeleteFile": "Delete File",
|
||||
"StatusSkipped": "Skipped",
|
||||
"StatusFailed": "Failed",
|
||||
@ -305,7 +305,7 @@
|
||||
"TabMetadata": "Metadata",
|
||||
"TabDLNA": "DLNA",
|
||||
"TabLiveTV": "Live TV",
|
||||
"TabAutoOrganize": "Auto-Organize",
|
||||
"TabAutoOrganize": "Auto-Organise",
|
||||
"TabPlugins": "Plugins",
|
||||
"TabAdvanced": "Advanced",
|
||||
"TabHelp": "Help",
|
||||
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Movies",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "Episodes",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Songs",
|
||||
"TabMusicVideos": "Music Videos",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Movies",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "Episodes",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Songs",
|
||||
"TabMusicVideos": "Music Videos",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Temporada n\u00famero:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episodio n\u00famero:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Pel\u00edculas",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "Episodios",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Juegos",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Canciones",
|
||||
"TabMusicVideos": "Videos Musicales",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -189,7 +189,7 @@
|
||||
"HeaderLatestTvRecordings": "\u00daltimas Grabaciones",
|
||||
"ButtonOk": "Ok",
|
||||
"ButtonCancel": "Cancelar",
|
||||
"ButtonRefresh": "Refrescar",
|
||||
"ButtonRefresh": "Actualizar",
|
||||
"LabelCurrentPath": "Ruta actual:",
|
||||
"HeaderSelectMediaPath": "Seleccionar ruta a medios",
|
||||
"ButtonNetwork": "Red",
|
||||
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Grabadores de metadatos:",
|
||||
"LabelMetadataSaversHelp": "Seleccione los formatos de archivo con los que se guardaran sus metadatos.",
|
||||
"LabelImageFetchers": "Recolectores de im\u00e1genes:",
|
||||
"LabelImageFetchersHelp": "Habilite y priorice sus recolectores de im\u00e1genes preferidos."
|
||||
"LabelImageFetchersHelp": "Habilite y priorice sus recolectores de im\u00e1genes preferidos.",
|
||||
"ButtonQueueAllFromHere": "Encolar todos desde aqu\u00ed",
|
||||
"ButtonPlayAllFromHere": "Reproducir todos desde aqu\u00ed",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identificar \u00edtem",
|
||||
"PersonTypePerson": "Persona",
|
||||
"LabelTitleDisplayOrder": "Ordenamiento de despliegue de t\u00edtulos:",
|
||||
"OptionSortName": "Nombre para ordenar",
|
||||
"OptionReleaseDate": "Fecha de estreno",
|
||||
"LabelSeasonNumber": "N\u00famero de temporada:",
|
||||
"LabelDiscNumber": "N\u00famero de disco",
|
||||
"LabelParentNumber": "N\u00famero antecesor",
|
||||
"LabelEpisodeNumber": "N\u00famero de episodio:",
|
||||
"LabelTrackNumber": "N\u00famero de Pista:",
|
||||
"LabelNumber": "N\u00famero",
|
||||
"LabelReleaseDate": "Fecha de estreno:",
|
||||
"LabelEndDate": "Fecha de Fin:",
|
||||
"LabelYear": "A\u00f1o:",
|
||||
"LabelDateOfBirth": "Fecha de nacimiento:",
|
||||
"LabelBirthYear": "A\u00f1o de nacimiento:",
|
||||
"LabelDeathDate": "Fecha de defunci\u00f3n:",
|
||||
"HeaderRemoveMediaLocation": "Eliminar Ubicaci\u00f3n de Medios",
|
||||
"MessageConfirmRemoveMediaLocation": "\u00bfEsta seguro de querer eliminar esta ubicaci\u00f3n?",
|
||||
"HeaderRenameMediaFolder": "Renombrar Carpeta de Medios",
|
||||
"LabelNewName": "Nuevo nombre:",
|
||||
"HeaderAddMediaFolder": "Agregar Carpeta de Medios",
|
||||
"HeaderAddMediaFolderHelp": "Nombre (Pel\u00edculas, M\u00fascia, TV, etc.):",
|
||||
"HeaderRemoveMediaFolder": "Eliminar Carpteta de Medios",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "Las siguientes ubicaciones de medios ser\u00e1n eliminadas de su biblioteca:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "\u00bfEsta seguro de querer eliminar esta carpeta de medios?",
|
||||
"ButtonRename": "Renombrar",
|
||||
"ButtonChangeType": "Cambiar tipo",
|
||||
"HeaderMediaLocations": "Ubicaciones de Medios",
|
||||
"LabelFolderTypeValue": "Tipo de carpeta: {0}",
|
||||
"LabelPathSubstitutionHelp": "Opcional: La sustituci\u00f3n de trayectoras puede mapear trayectorias del servidor a recursos de red comaprtidos que los clientes pueden acceder para reproducir de manera directa.",
|
||||
"FolderTypeMixed": "Pel\u00edculas y TV mezclados",
|
||||
"FolderTypeMovies": "Pel\u00edculas",
|
||||
"FolderTypeMusic": "M\u00fasica",
|
||||
"FolderTypeAdultVideos": "Videos para adultos",
|
||||
"FolderTypePhotos": "Fotos",
|
||||
"FolderTypeMusicVideos": "Videos musicales",
|
||||
"FolderTypeHomeVideos": "Videos caseros",
|
||||
"FolderTypeGames": "Juegos",
|
||||
"FolderTypeBooks": "Libros",
|
||||
"FolderTypeTvShows": "Programas de TV",
|
||||
"TabMovies": "Pel\u00edculas",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "Episodios",
|
||||
"TabTrailers": "Avances",
|
||||
"TabGames": "Juegos",
|
||||
"TabAlbums": "\u00c1lbums",
|
||||
"TabSongs": "Canciones",
|
||||
"TabMusicVideos": "Videos Musicales",
|
||||
"BirthPlaceValue": "Lugar de nacimiento: {0}",
|
||||
"DeathDateValue": "Fallcimiento: {0}",
|
||||
"BirthDateValue": "Nacimiento: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Num\u00e9ro de saison",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Num\u00e9ro d'\u00e9pisode",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date de naissance:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Renommer le r\u00e9pertoire de m\u00e9dia",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Supprimer le r\u00e9pertoire de m\u00e9dia",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "\u00cates-vous s\u00fbr de vouloir supprimer ce r\u00e9pertoire de m\u00e9dia?",
|
||||
"ButtonRename": "Renommer",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Films",
|
||||
"FolderTypeMusic": "Musique",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Jeux",
|
||||
"FolderTypeBooks": "Livres",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Films",
|
||||
"TabSeries": "S\u00e9ries",
|
||||
"TabEpisodes": "\u00c9pisodes",
|
||||
"TabTrailers": "Bandes-annonces",
|
||||
"TabGames": "Jeux",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Chansons",
|
||||
"TabMusicVideos": "Videos musicales",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "\u05de\u05e1\u05e4\u05e8 \u05e2\u05d5\u05e0\u05d4:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "\u05de\u05e1\u05e4\u05e8 \u05e4\u05e8\u05e7:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "\u05e1\u05e8\u05d8\u05d9\u05dd",
|
||||
"TabSeries": "\u05e1\u05d3\u05e8\u05d5\u05ea",
|
||||
"TabEpisodes": "\u05e4\u05e8\u05e7\u05d9\u05dd",
|
||||
"TabTrailers": "\u05d8\u05e8\u05d9\u05d9\u05dc\u05e8\u05d9\u05dd",
|
||||
"TabGames": "\u05de\u05e9\u05d7\u05e7\u05d9\u05dd",
|
||||
"TabAlbums": "\u05d0\u05dc\u05d1\u05d5\u05de\u05d9\u05dd",
|
||||
"TabSongs": "\u05e9\u05d9\u05e8\u05d9\u05dd",
|
||||
"TabMusicVideos": "\u05e7\u05dc\u05d9\u05e4\u05d9\u05dd",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Numero Stagione",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Numero Episodio",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Film",
|
||||
"TabSeries": "Serie TV",
|
||||
"TabEpisodes": "Episodi",
|
||||
"TabTrailers": "Trailer",
|
||||
"TabGames": "Giochi",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Canzoni",
|
||||
"TabMusicVideos": "Video Musicali",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -189,7 +189,7 @@
|
||||
"HeaderLatestTvRecordings": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440",
|
||||
"ButtonOk": "\u0416\u0430\u0440\u0430\u0439\u0434\u044b",
|
||||
"ButtonCancel": "\u0411\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
|
||||
"ButtonRefresh": "\u0416\u0430\u04a3\u0430\u0440\u0442\u0443",
|
||||
"ButtonRefresh": "\u041a\u04e9\u043a\u0435\u0439\u0442\u0435\u0441\u0442\u0456 \u0435\u0442\u0443",
|
||||
"LabelCurrentPath": "\u0410\u0493\u044b\u043c\u0434\u044b\u049b \u0436\u043e\u043b:",
|
||||
"HeaderSelectMediaPath": "\u0422\u0430\u0441\u0443\u0448\u044b \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
|
||||
"ButtonNetwork": "\u0416\u0435\u043b\u0456",
|
||||
@ -288,7 +288,7 @@
|
||||
"HeaderAlert": "\u0415\u0441\u043a\u0435\u0440\u0442\u0443",
|
||||
"MessagePleaseRestart": "\u0416\u0430\u04a3\u0430\u0440\u0442\u0443\u0434\u044b \u0430\u044f\u049b\u0442\u0430\u0443 \u04af\u0448\u0456\u043d \u049b\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u04a3\u044b\u0437.",
|
||||
"ButtonRestart": "\u049a\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u0443",
|
||||
"MessagePleaseRefreshPage": "\u0416\u0430\u04a3\u0430 \u0436\u0430\u04a3\u0430\u0440\u0442\u0443\u043b\u0430\u0440\u0434\u044b \u0430\u043b\u0443 \u04af\u0448\u0456\u043d \u043e\u0441\u044b \u0431\u0435\u0442\u0442\u0456 \u049b\u0430\u0439\u0442\u0430 \u0436\u04af\u043a\u0442\u0435\u04a3\u0456\u0437.",
|
||||
"MessagePleaseRefreshPage": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0435\u043d \u0436\u0430\u04a3\u0430 \u0436\u0430\u04a3\u0430\u0440\u0442\u0443\u043b\u0430\u0440\u0434\u044b \u0430\u043b\u0443 \u04af\u0448\u0456\u043d \u043e\u0441\u044b \u0431\u0435\u0442\u0442\u0456 \u043a\u04e9\u043a\u0435\u0439\u0442\u0435\u0441\u0442\u0456 \u0435\u0442\u0456\u04a3\u0456\u0437.",
|
||||
"ButtonHide": "\u0416\u0430\u0441\u044b\u0440\u0443",
|
||||
"MessageSettingsSaved": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440 \u0441\u0430\u049b\u0442\u0430\u043b\u0434\u044b.",
|
||||
"ButtonSignOut": "\u0428\u044b\u0493\u0443",
|
||||
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a \u0441\u0430\u049b\u0442\u0430\u0443\u0448\u044b\u043b\u0430\u0440\u044b:",
|
||||
"LabelMetadataSaversHelp": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u049b\u0430\u0439\u0434\u0430 \u0441\u0430\u049b\u0442\u0430\u0439\u0442\u044b\u043d \u0444\u0430\u0439\u043b \u043f\u0456\u0448\u0456\u043c\u0434\u0435\u0440\u0456\u043d \u0442\u0430\u04a3\u0434\u0430\u0443.",
|
||||
"LabelImageFetchers": "\u0421\u0443\u0440\u0435\u0442 \u0456\u0440\u0456\u043a\u0442\u0435\u0443\u0448\u0456\u043b\u0435\u0440\u0456:",
|
||||
"LabelImageFetchersHelp": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0441\u0443\u0440\u0435\u0442 \u0456\u0440\u0456\u043a\u0442\u0435\u0443\u0448\u0456\u043b\u0435\u0440\u0456\u043d \u049b\u043e\u0441\u044b\u04a3\u044b\u0437 \u0436\u04d9\u043d\u0435 \u0431\u0430\u0441\u044b\u043c\u0434\u044b\u043b\u044b\u049b \u0440\u0435\u0442\u0456 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0434\u04d9\u0440\u0435\u0436\u0435 \u0431\u0435\u0440\u0456\u04a3\u0456\u0437."
|
||||
"LabelImageFetchersHelp": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0441\u0443\u0440\u0435\u0442 \u0456\u0440\u0456\u043a\u0442\u0435\u0443\u0448\u0456\u043b\u0435\u0440\u0456\u043d \u049b\u043e\u0441\u044b\u04a3\u044b\u0437 \u0436\u04d9\u043d\u0435 \u0431\u0430\u0441\u044b\u043c\u0434\u044b\u043b\u044b\u049b \u0440\u0435\u0442\u0456 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0434\u04d9\u0440\u0435\u0436\u0435 \u0431\u0435\u0440\u0456\u04a3\u0456\u0437.",
|
||||
"ButtonQueueAllFromHere": "\u0411\u04b1\u043b \u0430\u0440\u0430\u0434\u0430\u043d \u0431\u04d9\u0440\u0456\u043d \u043a\u0435\u0437\u0435\u043a\u0442\u0435\u0443",
|
||||
"ButtonPlayAllFromHere": "\u0411\u04b1\u043b \u0430\u0440\u0430\u0434\u0430\u043d \u0431\u04d9\u0440\u0456\u043d \u043e\u0439\u043d\u0430\u0442\u0443",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0456 \u0430\u043d\u044b\u049b\u0442\u0430\u0443",
|
||||
"PersonTypePerson": "\u0422\u04b1\u043b\u0493\u0430",
|
||||
"LabelTitleDisplayOrder": "\u0422\u0443\u044b\u043d\u0434\u044b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u0440\u0435\u0442\u0456:",
|
||||
"OptionSortName": "\u0421\u04b1\u0440\u044b\u043f\u0442\u0430\u043b\u0430\u0442\u044b\u043d \u0430\u0442\u044b",
|
||||
"OptionReleaseDate": "\u0428\u044b\u0493\u0430\u0440\u0443 \u043a\u04af\u043d-\u0430\u0439\u044b",
|
||||
"LabelSeasonNumber": "\u041c\u0430\u0443\u0441\u044b\u043c \u043d\u04e9\u043c\u0456\u0440\u0456:",
|
||||
"LabelDiscNumber": "\u0414\u0438\u0441\u043a\u0456 \u043d\u04e9\u043c\u0456\u0440\u0456",
|
||||
"LabelParentNumber": "\u0422\u0435\u043a\u0442\u0456\u043a \u043d\u04e9\u043c\u0456\u0440:",
|
||||
"LabelEpisodeNumber": "\u042d\u043f\u0438\u0437\u043e\u0434 \u043d\u04e9\u043c\u0456\u0440\u0456:",
|
||||
"LabelTrackNumber": "\u0416\u043e\u043b\u0448\u044b\u049b \u043d\u04e9\u043c\u0456\u0440\u0456:",
|
||||
"LabelNumber": "\u041d\u04e9\u043c\u0456\u0440\u0456:",
|
||||
"LabelReleaseDate": "\u0428\u044b\u0493\u0430\u0440\u0443 \u043a\u04af\u043d-\u0430\u0439\u044b:",
|
||||
"LabelEndDate": "\u0410\u044f\u049b\u0442\u0430\u043b\u0443 \u043a\u04af\u043d-\u0430\u0439\u044b:",
|
||||
"LabelYear": "\u0416\u044b\u043b\u044b:",
|
||||
"LabelDateOfBirth": "\u0422\u0443\u0493\u0430\u043d \u043a\u04af\u043d-\u0430\u0439\u044b:",
|
||||
"LabelBirthYear": "\u0422\u0443\u0493\u0430\u043d \u0436\u044b\u043b\u044b:",
|
||||
"LabelDeathDate": "\u04e8\u043b\u0433\u0435\u043d \u0436\u044b\u043b\u044b:",
|
||||
"HeaderRemoveMediaLocation": "\u0422\u0430\u0441\u0443\u0448\u044b\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u044b\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443",
|
||||
"MessageConfirmRemoveMediaLocation": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u0434\u044b \u0430\u043b\u0430\u0441\u0442\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
|
||||
"HeaderRenameMediaFolder": "\u0422\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d \u049b\u0430\u0439\u0442\u0430 \u0430\u0442\u0430\u0443",
|
||||
"LabelNewName": "\u0416\u0430\u04a3\u0430 \u0430\u0442\u044b",
|
||||
"HeaderAddMediaFolder": "\u0422\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d \u04af\u0441\u0442\u0435\u0443",
|
||||
"HeaderAddMediaFolderHelp": "\u0410\u0442\u044b (\u041a\u0438\u043d\u043e, \u041c\u0443\u0437\u044b\u043a\u0430, \u0422\u0414, \u0442.\u0431.):",
|
||||
"HeaderRemoveMediaFolder": "\u0422\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0442\u0430\u0441\u0443\u0448\u044b \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456\u04a3 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u043b\u0430\u0440\u044b \u0442\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0430\u0434\u044b:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u0442\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
|
||||
"ButtonRename": "\u049a\u0430\u0439\u0442\u0430 \u0430\u0442\u0430\u0443",
|
||||
"ButtonChangeType": "\u0422\u04af\u0440\u0456\u043d \u04e9\u0437\u0433\u0435\u0440\u0442\u0443",
|
||||
"HeaderMediaLocations": "\u0422\u0430\u0441\u0443\u0448\u044b \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u043b\u0430\u0440\u044b",
|
||||
"LabelFolderTypeValue": "\u049a\u0430\u043b\u0442\u0430 \u0442\u04af\u0440\u0456: {0}",
|
||||
"LabelPathSubstitutionHelp": "\u049a\u0430\u043b\u0430\u0443 \u0431\u043e\u0439\u044b\u043d\u0448\u0430: \u0416\u043e\u043b \u0430\u043b\u043c\u0430\u0441\u0442\u044b\u0440\u0443 \u0430\u0440\u049b\u044b\u043b\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0435\u0433\u0456 \u0436\u043e\u043b\u0434\u0430\u0440\u0434\u044b \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0430 \u0430\u043b\u0430\u0442\u044b\u043d \u0436\u0435\u043b\u0456\u043b\u0456\u043a \u049b\u043e\u0440 \u043a\u04e9\u0437\u0434\u0435\u0440\u0456\u043c\u0435\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
|
||||
"FolderTypeMixed": "\u0410\u0440\u0430\u043b\u0430\u0441 (\u043a\u0438\u043d\u043e \u0436\u04d9\u043d\u0435 \u0442\u0434)",
|
||||
"FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
|
||||
"FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
|
||||
"FolderTypeAdultVideos": "\u0415\u0440\u0435\u0441\u0435\u043a\u0442\u0456\u043a \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440",
|
||||
"FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440",
|
||||
"FolderTypeMusicVideos": "\u041c\u0443\u0437\u044b\u043a\u0430\u043b\u044b\u049b \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440",
|
||||
"FolderTypeHomeVideos": "\u04ae\u0439 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0456",
|
||||
"FolderTypeGames": "\u041e\u0439\u044b\u043d\u0434\u0430\u0440",
|
||||
"FolderTypeBooks": "\u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440",
|
||||
"FolderTypeTvShows": "\u0422\u0414 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440\u0456",
|
||||
"TabMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
|
||||
"TabSeries": "\u0421\u0435\u0440\u0438\u0430\u043b",
|
||||
"TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u0442\u0430\u0440",
|
||||
"TabTrailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440",
|
||||
"TabGames": "\u041e\u0439\u044b\u043d\u0434\u0430\u0440",
|
||||
"TabAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u0434\u0435\u0440",
|
||||
"TabSongs": "\u04d8\u0443\u0435\u043d\u0434\u0435\u0440",
|
||||
"TabMusicVideos": "\u0411\u0435\u0439\u043d\u0435\u043a\u043b\u0438\u043f\u0442\u0435\u0440",
|
||||
"BirthPlaceValue": "\u0422\u0443\u0493\u0430\u043d \u043e\u0440\u043d\u044b: {0}",
|
||||
"DeathDateValue": "\u04e8\u043b\u0433\u0435\u043d\u0456: {0}",
|
||||
"BirthDateValue": "\u0422\u0443\u0493\u0430\u043d\u044b: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Movies",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "Episodes",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Songs",
|
||||
"TabMusicVideos": "Music Videos",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Sesong nummer",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode nummer",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Filmer",
|
||||
"TabSeries": "Serier",
|
||||
"TabEpisodes": "Episoder",
|
||||
"TabTrailers": "Trailere",
|
||||
"TabGames": "Spill",
|
||||
"TabAlbums": "Album",
|
||||
"TabSongs": "Sanger",
|
||||
"TabMusicVideos": "Musikk-videoer",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -338,7 +338,7 @@
|
||||
"HeaderVideo": "Video",
|
||||
"HeaderRuntime": "Speelduur",
|
||||
"HeaderCommunityRating": "Gemeenschap cijfer",
|
||||
"HeaderParentalRating": "Kijkwijzer classificering",
|
||||
"HeaderParentalRating": "Kijkwijzer classificatie",
|
||||
"HeaderReleaseDate": "Releasedatum ",
|
||||
"HeaderDateAdded": "Datum toegevoegd",
|
||||
"HeaderSeries": "Series",
|
||||
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata Opslag:",
|
||||
"LabelMetadataSaversHelp": "Kies de bestandsindeling om uw metadata op te slaan.",
|
||||
"LabelImageFetchers": "Afbeeldingen Downloaders:",
|
||||
"LabelImageFetchersHelp": "Schakelen in en rangschik uw voorkeurs Afbeeldingen downloader, gerangschikt in volgorde van prioriteit."
|
||||
"LabelImageFetchersHelp": "Schakelen in en rangschik uw voorkeurs Afbeeldingen downloader, gerangschikt in volgorde van prioriteit.",
|
||||
"ButtonQueueAllFromHere": "Plaats in de wachtrij vanaf hier",
|
||||
"ButtonPlayAllFromHere": "Speel allemaal vanaf hier",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identificeer item",
|
||||
"PersonTypePerson": "Persoon",
|
||||
"LabelTitleDisplayOrder": "Titel weergave volgorde:",
|
||||
"OptionSortName": "Sorteerbaar",
|
||||
"OptionReleaseDate": "Uitgave datum",
|
||||
"LabelSeasonNumber": "Seizoen:",
|
||||
"LabelDiscNumber": "Disc nummer",
|
||||
"LabelParentNumber": "Bovenliggend nummer",
|
||||
"LabelEpisodeNumber": "Aflevering:",
|
||||
"LabelTrackNumber": "Tracknummer:",
|
||||
"LabelNumber": "Nummer:",
|
||||
"LabelReleaseDate": "Uitgave datum:",
|
||||
"LabelEndDate": "Eind datum|",
|
||||
"LabelYear": "Jaar:",
|
||||
"LabelDateOfBirth": "Geboortedatum:",
|
||||
"LabelBirthYear": "Geboorte jaar:",
|
||||
"LabelDeathDate": "Overlijdens datum:",
|
||||
"HeaderRemoveMediaLocation": "Verwijder media locatie",
|
||||
"MessageConfirmRemoveMediaLocation": "Weet je zeker dat je deze locatie wilt verwijderen?",
|
||||
"HeaderRenameMediaFolder": "Hernoem media map",
|
||||
"LabelNewName": "Nieuwe naam:",
|
||||
"HeaderAddMediaFolder": "Voeg media map toe",
|
||||
"HeaderAddMediaFolderHelp": "Naam (Films, Muziek, TV etc):",
|
||||
"HeaderRemoveMediaFolder": "Verwijder media map",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "De volgende media locaties worden uit de bibliotheek verwijderd:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Weet je zeker dat je deze media map wilt verwijderen?",
|
||||
"ButtonRename": "Hernoem",
|
||||
"ButtonChangeType": "Verander soort",
|
||||
"HeaderMediaLocations": "Media Locaties",
|
||||
"LabelFolderTypeValue": "Map type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optioneel: Pad vervanging kan server paden naar netwerk locaties verwijzen zodat clients direct kunnen afspelen.",
|
||||
"FolderTypeMixed": "Gemixte films en TV",
|
||||
"FolderTypeMovies": "Films",
|
||||
"FolderTypeMusic": "Muziek",
|
||||
"FolderTypeAdultVideos": "Adult video's",
|
||||
"FolderTypePhotos": "Foto's",
|
||||
"FolderTypeMusicVideos": "Muziek video's",
|
||||
"FolderTypeHomeVideos": "Thuis video's",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Boeken",
|
||||
"FolderTypeTvShows": "TV programma's",
|
||||
"TabMovies": "Films",
|
||||
"TabSeries": "Serie",
|
||||
"TabEpisodes": "Afleveringen",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "Albums",
|
||||
"TabSongs": "Songs",
|
||||
"TabMusicVideos": "Music Videos",
|
||||
"BirthPlaceValue": "Geboorte plaats: {0})",
|
||||
"DeathDateValue": "Overleden: {0}",
|
||||
"BirthDateValue": "Geboren: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Filmy",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "Odcinki",
|
||||
"TabTrailers": "Zwiastuny",
|
||||
"TabGames": "Gry",
|
||||
"TabAlbums": "Albumy",
|
||||
"TabSongs": "Utwory",
|
||||
"TabMusicVideos": "Teledyski",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -58,14 +58,14 @@
|
||||
"ButtonMute": "Mudo",
|
||||
"ButtonUnmute": "Remover Mudo",
|
||||
"ButtonStop": "Parar",
|
||||
"ButtonNextTrack": "Faixa Seguinte",
|
||||
"ButtonNextTrack": "Faixa seguinte",
|
||||
"ButtonPause": "Pausar",
|
||||
"ButtonPlay": "Reproduzir",
|
||||
"ButtonEdit": "Editar",
|
||||
"ButtonQueue": "Adicionar \u00e0 fila",
|
||||
"ButtonPlayTrailer": "Reproduzir trailer",
|
||||
"ButtonPlaylist": "Lista de reprodu\u00e7\u00e3o",
|
||||
"ButtonPreviousTrack": "Faixa Anterior",
|
||||
"ButtonPreviousTrack": "Faixa anterior",
|
||||
"LabelEnabled": "Ativada",
|
||||
"LabelDisabled": "Desativada",
|
||||
"ButtonMoreInformation": "Mais informa\u00e7\u00f5es",
|
||||
@ -146,7 +146,7 @@
|
||||
"ButtonAdd": "Adicionar",
|
||||
"ButtonRemove": "Remover",
|
||||
"LabelChapterDownloaders": "Downloaders de cap\u00edtulos:",
|
||||
"LabelChapterDownloadersHelp": "Habilite e classifique seus downloaders de cap\u00edtulos preferidos em ordem de prioridade. Downloaders de menor prioridade s\u00f3 ser\u00e3o usados para preencher informa\u00e7\u00f5es faltantes.",
|
||||
"LabelChapterDownloadersHelp": "Habilite e classifique seus downloaders de cap\u00edtulos preferidos em ordem de prioridade. Downloaders de menor prioridade s\u00f3 ser\u00e3o usados para preencher informa\u00e7\u00f5es que ainda n\u00e3o existam.",
|
||||
"HeaderFavoriteAlbums": "\u00c1lbuns Favoritos",
|
||||
"HeaderLatestChannelMedia": "Itens de Canais Recentes",
|
||||
"ButtonOrganizeFile": "Organizar Arquivo",
|
||||
@ -221,7 +221,7 @@
|
||||
"HeaderMediaFolders": "Pastas de M\u00eddia",
|
||||
"HeaderBlockItemsWithNoRating": "Bloquear itens sem informa\u00e7\u00e3o de classifica\u00e7\u00e3o:",
|
||||
"OptionBlockOthers": "Outros",
|
||||
"OptionBlockTvShows": "S\u00e9ries",
|
||||
"OptionBlockTvShows": "S\u00e9ries de TV",
|
||||
"OptionBlockTrailers": "Trailers",
|
||||
"OptionBlockMusic": "M\u00fasica",
|
||||
"OptionBlockMovies": "Filmes",
|
||||
@ -260,7 +260,7 @@
|
||||
"HeaderFieldsHelp": "Deslize um campo para 'off' para bloquear e evitar que seus dados sejam alterados.",
|
||||
"HeaderLiveTV": "TV ao Vivo",
|
||||
"MissingLocalTrailer": "Faltando trailer local.",
|
||||
"MissingPrimaryImage": "Faltando imagem principal.",
|
||||
"MissingPrimaryImage": "Faltando imagem prim\u00e1ria.",
|
||||
"MissingBackdropImage": "Faltando imagem de fundo.",
|
||||
"MissingLogoImage": "Faltando imagem do logo.",
|
||||
"MissingEpisode": "Faltando epis\u00f3dio.",
|
||||
@ -370,9 +370,64 @@
|
||||
"LabelMetadataReaders": "Leitores de metadados:",
|
||||
"LabelMetadataReadersHelp": "Classifique por ordem de prioridade suas fontes de metadados locais preferidas. O primeiro arquivo encontrado ser\u00e1 lido.",
|
||||
"LabelMetadataDownloaders": "Downloaders de metadados:",
|
||||
"LabelMetadataDownloadersHelp": "Ative e classifique por ordem de prioridade seus downloaders de metadados preferidos. Downloaders com prioridade mais baixa s\u00f3 ser\u00e3o usados para baixar informa\u00e7\u00e3o que ainda n\u00e3o existe.",
|
||||
"LabelMetadataDownloadersHelp": "Ative e classifique por ordem de prioridade seus downloaders de metadados preferidos. Downloaders com prioridade mais baixa s\u00f3 ser\u00e3o usados para baixar informa\u00e7\u00f5es que ainda n\u00e3o existam.",
|
||||
"LabelMetadataSavers": "Gravadores de metadados:",
|
||||
"LabelMetadataSaversHelp": "Escolha os formatos de arquivos nos quais deseja gravar seus metadados.",
|
||||
"LabelImageFetchers": "Buscadores de imagem:",
|
||||
"LabelImageFetchersHelp": "Ative e classifique por ordem de prioridade seus buscadores de imagem preferidos."
|
||||
"LabelImageFetchersHelp": "Ative e classifique por ordem de prioridade seus buscadores de imagem preferidos.",
|
||||
"ButtonQueueAllFromHere": "Enfileirar todas a partir daqui",
|
||||
"ButtonPlayAllFromHere": "Reproduzir todas a partir daqui",
|
||||
"LabelDynamicExternalId": "Id de {0}:",
|
||||
"HeaderIdentify": "Identificar Item",
|
||||
"PersonTypePerson": "Pessoa",
|
||||
"LabelTitleDisplayOrder": "Ordem de exibi\u00e7\u00e3o do t\u00edtulo: ",
|
||||
"OptionSortName": "Nome para ordena\u00e7\u00e3o",
|
||||
"OptionReleaseDate": "Data de lan\u00e7amento",
|
||||
"LabelSeasonNumber": "N\u00famero da temporada:",
|
||||
"LabelDiscNumber": "N\u00famero do disco",
|
||||
"LabelParentNumber": "N\u00famero do superior",
|
||||
"LabelEpisodeNumber": "N\u00famero do epis\u00f3dio:",
|
||||
"LabelTrackNumber": "N\u00famero da faixa:",
|
||||
"LabelNumber": "N\u00famero:",
|
||||
"LabelReleaseDate": "Data do lan\u00e7amento:",
|
||||
"LabelEndDate": "Data final:",
|
||||
"LabelYear": "Ano:",
|
||||
"LabelDateOfBirth": "Data de nascimento:",
|
||||
"LabelBirthYear": "Ano de nascimento:",
|
||||
"LabelDeathDate": "Data da morte:",
|
||||
"HeaderRemoveMediaLocation": "Remover Localiza\u00e7\u00e3o da M\u00eddia",
|
||||
"MessageConfirmRemoveMediaLocation": "Deseja realmente remover esta localiza\u00e7\u00e3o?",
|
||||
"HeaderRenameMediaFolder": "Renomear Pasta de M\u00eddia",
|
||||
"LabelNewName": "Novo nome:",
|
||||
"HeaderAddMediaFolder": "Adicionar Pasta de M\u00eddia",
|
||||
"HeaderAddMediaFolderHelp": "Nome (Filmes, M\u00fasica, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Excluir Pasta de M\u00eddia",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "As localiza\u00e7\u00f5es de m\u00eddia abaixo ser\u00e3o exclu\u00eddas de sua biblioteca:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Deseja realmente excluir esta pasta de m\u00eddia?",
|
||||
"ButtonRename": "Renomear",
|
||||
"ButtonChangeType": "Alterar tipo",
|
||||
"HeaderMediaLocations": "Localiza\u00e7\u00f5es de M\u00eddia",
|
||||
"LabelFolderTypeValue": "Tipo de pasta: {0}",
|
||||
"LabelPathSubstitutionHelp": "Opcional: Substitui\u00e7\u00e3o de caminho pode mapear caminhos do servidor para compartilhamentos de rede de forma a que os clientes possam acessar para reprodu\u00e7\u00e3o direta.",
|
||||
"FolderTypeMixed": "Filmes & tv misturados",
|
||||
"FolderTypeMovies": "Filmes",
|
||||
"FolderTypeMusic": "M\u00fasica",
|
||||
"FolderTypeAdultVideos": "V\u00eddeos adultos",
|
||||
"FolderTypePhotos": "Fotos",
|
||||
"FolderTypeMusicVideos": "V\u00eddeos musicais",
|
||||
"FolderTypeHomeVideos": "V\u00eddeos caseiros",
|
||||
"FolderTypeGames": "Jogos",
|
||||
"FolderTypeBooks": "Livros",
|
||||
"FolderTypeTvShows": "S\u00e9ries de TV",
|
||||
"TabMovies": "Filmes",
|
||||
"TabSeries": "S\u00e9ries",
|
||||
"TabEpisodes": "Epis\u00f3dios",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Jogos",
|
||||
"TabAlbums": "\u00c1lbuns",
|
||||
"TabSongs": "M\u00fasicas",
|
||||
"TabMusicVideos": "V\u00eddeos Musicais",
|
||||
"BirthPlaceValue": "Local de nascimento: {0}",
|
||||
"DeathDateValue": "Morte: {0}",
|
||||
"BirthDateValue": "Nascimento: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "N\u00famero da temporada",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "N\u00famero do epis\u00f3dio",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Filmes",
|
||||
"TabSeries": "S\u00e9ries",
|
||||
"TabEpisodes": "Epis\u00f3dios",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Jogos",
|
||||
"TabAlbums": "\u00c1lbuns",
|
||||
"TabSongs": "M\u00fasicas",
|
||||
"TabMusicVideos": "Videos Musicais",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -108,17 +108,17 @@
|
||||
"ButtonCancelSeries": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b",
|
||||
"HeaderSeriesRecordings": "\u0417\u0430\u043f\u0438\u0441\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u043e\u0432",
|
||||
"LabelAnytime": "\u041b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f",
|
||||
"StatusRecording": "\u0417\u0430\u043f\u0438\u0441\u044c",
|
||||
"StatusWatching": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440",
|
||||
"StatusRecording": "\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f",
|
||||
"StatusWatching": "\u041f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f",
|
||||
"StatusRecordingProgram": "\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f {0}",
|
||||
"StatusWatchingProgram": "\u041f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f {0}",
|
||||
"HeaderSplitMedia": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u043e\u0441\u0438\u0442\u0435\u043b\u0438 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438",
|
||||
"MessageConfirmSplitMedia": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u043d\u043e\u0441\u0438\u0442\u0435\u043b\u0435\u0439 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b?",
|
||||
"HeaderSplitMedia": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438",
|
||||
"MessageConfirmSplitMedia": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c?",
|
||||
"HeaderError": "\u041e\u0448\u0438\u0431\u043a\u0430",
|
||||
"MessagePleaseSelectOneItem": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435, \u043f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435, \u043e\u0434\u0438\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442.",
|
||||
"MessagePleaseSelectTwoItems": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435, \u043f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435, \u0434\u0432\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.",
|
||||
"MessageTheFollowingItemsWillBeGrouped": "\u0412 \u0435\u0434\u0438\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0431\u0443\u0434\u0443\u0442 \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f :",
|
||||
"MessageConfirmItemGrouping": "\u041a\u043b\u0438\u0435\u043d\u0442\u044b Media Browser \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0434\u043b\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u0435\u0442\u0438. \u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?",
|
||||
"MessageConfirmItemGrouping": "\u041a\u043b\u0438\u0435\u043d\u0442\u044b Media Browser \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0434\u043b\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u0441\u0435\u0442\u0438. \u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?",
|
||||
"HeaderResume": "\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u043c\u044b\u0435",
|
||||
"HeaderMyViews": "\u041c\u043e\u0438 \u0430\u0441\u043f\u0435\u043a\u0442\u044b",
|
||||
"HeaderLibraryFolders": "\u041c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0438",
|
||||
@ -177,7 +177,7 @@
|
||||
"LabelPlayMethodDirectPlay": "\u041f\u0440\u044f\u043c\u043e\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435",
|
||||
"LabelAudioCodec": "\u0410\u0443\u0434\u0438\u043e: {0}",
|
||||
"LabelVideoCodec": "\u0412\u0438\u0434\u0435\u043e: {0}",
|
||||
"LabelRemoteAccessUrl": "\u0414\u043b\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430: {0}",
|
||||
"LabelRemoteAccessUrl": "\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f: {0}",
|
||||
"LabelRunningOnPort": "\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 {0}.",
|
||||
"HeaderLatestFromChannel": "\u041d\u043e\u0432\u0438\u043d\u043a\u0438 \u0438\u0437 {0}",
|
||||
"ButtonDownload": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c",
|
||||
@ -191,7 +191,7 @@
|
||||
"ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0430",
|
||||
"ButtonRefresh": "\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c",
|
||||
"LabelCurrentPath": "\u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0443\u0442\u044c:",
|
||||
"HeaderSelectMediaPath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044f",
|
||||
"HeaderSelectMediaPath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
|
||||
"ButtonNetwork": "\u0421\u0435\u0442\u044c",
|
||||
"MessageDirectoryPickerInstruction": "\u0421\u0435\u0442\u0435\u0432\u044b\u0435 \u043f\u0443\u0442\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438 \u0421\u0435\u0442\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u0431\u043e\u0439 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: {0} \u0438\u043b\u0438 {1}.",
|
||||
"HeaderMenu": "\u041c\u0435\u043d\u044e",
|
||||
@ -205,7 +205,7 @@
|
||||
"HeaderSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b",
|
||||
"HeaderVideoQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0438\u0434\u0435\u043e",
|
||||
"MessageErrorPlayingVideo": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0438 \u0432\u0438\u0434\u0435\u043e.",
|
||||
"MessageEnsureOpenTuner": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0442\u0430\u043c \u043e\u0442\u043a\u0440\u044b\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0442\u044e\u043d\u0435\u0440.",
|
||||
"MessageEnsureOpenTuner": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u044e\u043d\u0435\u0440.",
|
||||
"ButtonHome": "\u0413\u043b\u0430\u0432\u043d\u0430\u044f",
|
||||
"ButtonDashboard": "\u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u044c",
|
||||
"ButtonReports": "\u041e\u0442\u0447\u0451\u0442\u044b",
|
||||
@ -237,7 +237,7 @@
|
||||
"ValueAudioCodec": "\u0410\u0443\u0434\u0438\u043e \u043a\u043e\u0434\u0435\u043a: {0}",
|
||||
"ValueVideoCodec": "\u0412\u0438\u0434\u0435\u043e \u043a\u043e\u0434\u0435\u043a: {0}",
|
||||
"ValueCodec": "\u041a\u043e\u0434\u0435\u043a: {0}",
|
||||
"ValueConditions": "\u0423\u0441\u043b\u043e\u0432\u0438\u044f: {0}",
|
||||
"ValueConditions": "\u041e\u0431\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430: {0}",
|
||||
"LabelAll": "\u0412\u0441\u0435",
|
||||
"HeaderDeleteImage": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0440\u0438\u0441\u0443\u043d\u043a\u0430",
|
||||
"MessageFileNotFound": "\u0424\u0430\u0439\u043b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d.",
|
||||
@ -290,14 +290,14 @@
|
||||
"ButtonRestart": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c",
|
||||
"MessagePleaseRefreshPage": "\u041f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.",
|
||||
"ButtonHide": "\u0421\u043a\u0440\u044b\u0442\u044c",
|
||||
"MessageSettingsSaved": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0431\u044b\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b.",
|
||||
"MessageSettingsSaved": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b.",
|
||||
"ButtonSignOut": "\u0412\u044b\u0439\u0442\u0438",
|
||||
"ButtonMyProfile": "\u041c\u043e\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c",
|
||||
"ButtonMyPreferences": "\u041c\u043e\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438",
|
||||
"MessageBrowserDoesNotSupportWebSockets": "\u0414\u0430\u043d\u043d\u044b\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u044b. \u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u0441 \u0431\u043e\u043b\u0435\u0435 \u043d\u043e\u0432\u044b\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Chrome, Firefox, IE10+, Safari (iOS) \u0438\u043b\u0438 Opera.",
|
||||
"LabelInstallingPackage": "\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f {0}",
|
||||
"LabelPackageInstallCompleted": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {0} \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430.",
|
||||
"LabelPackageInstallFailed": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {0} \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e.",
|
||||
"LabelPackageInstallFailed": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {0} \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u0430.",
|
||||
"LabelPackageInstallCancelled": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {0} \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430.",
|
||||
"TabServer": "\u0421\u0435\u0440\u0432\u0435\u0440",
|
||||
"TabUsers": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438",
|
||||
@ -323,7 +323,7 @@
|
||||
"HeaderVideoError": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u0438\u0434\u0435\u043e",
|
||||
"ButtonAddToPlaylist": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440-\u0438\u044f",
|
||||
"HeaderAddToPlaylist": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440-\u0438\u044f",
|
||||
"LabelName": "\u0418\u043c\u044f:",
|
||||
"LabelName": "\u0418\u043c\u044f (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435):",
|
||||
"ButtonSubmit": "\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c",
|
||||
"LabelSelectPlaylist": "\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440-\u0438\u044f:",
|
||||
"OptionNewPlaylist": "\u041d\u043e\u0432\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440-\u0438\u044f...",
|
||||
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "\u0425\u0440\u0430\u043d\u0438\u0442\u0435\u043b\u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445:",
|
||||
"LabelMetadataSaversHelp": "\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0444\u0430\u0439\u043b\u043e\u0432, \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435.",
|
||||
"LabelImageFetchers": "\u041e\u0442\u0431\u043e\u0440\u0449\u0438\u043a\u0438 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432:",
|
||||
"LabelImageFetchersHelp": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0438 \u0440\u0430\u043d\u0436\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0431\u043e\u0440\u0449\u0438\u043a\u0438 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u0430."
|
||||
"LabelImageFetchersHelp": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0438 \u0440\u0430\u043d\u0436\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0431\u043e\u0440\u0449\u0438\u043a\u0438 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u0430.",
|
||||
"ButtonQueueAllFromHere": "\u041f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432\u0441\u0435 \u043e\u0442\u0441\u044e\u0434\u0430",
|
||||
"ButtonPlayAllFromHere": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0432\u0441\u0435 \u043e\u0442\u0441\u044e\u0434\u0430",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430",
|
||||
"PersonTypePerson": "\u041f\u0435\u0440\u0441\u043e\u043d\u0430",
|
||||
"LabelTitleDisplayOrder": "\u041f\u043e\u0440\u044f\u0434\u043e\u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439:",
|
||||
"OptionSortName": "\u0421\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435",
|
||||
"OptionReleaseDate": "\u0414\u0430\u0442\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430",
|
||||
"LabelSeasonNumber": "\u041d\u043e\u043c\u0435\u0440 \u0441\u0435\u0437\u043e\u043d\u0430:",
|
||||
"LabelDiscNumber": "\u041d\u043e\u043c\u0435\u0440 \u0434\u0438\u0441\u043a\u0430",
|
||||
"LabelParentNumber": "\u0420\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043d\u043e\u043c\u0435\u0440",
|
||||
"LabelEpisodeNumber": "\u041d\u043e\u043c\u0435\u0440 \u044d\u043f\u0438\u0437\u043e\u0434\u0430:",
|
||||
"LabelTrackNumber": "\u041d\u043e\u043c\u0435\u0440 \u0434\u043e\u0440\u043e\u0436\u043a\u0438:",
|
||||
"LabelNumber": "\u041d\u043e\u043c\u0435\u0440:",
|
||||
"LabelReleaseDate": "\u0414\u0430\u0442\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430:",
|
||||
"LabelEndDate": "\u041a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0434\u0430\u0442\u0430:",
|
||||
"LabelYear": "\u0413\u043e\u0434:",
|
||||
"LabelDateOfBirth": "\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:",
|
||||
"LabelBirthYear": "\u0413\u043e\u0434 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:",
|
||||
"LabelDeathDate": "\u0413\u043e\u0434 \u0441\u043c\u0435\u0440\u0442\u0438:",
|
||||
"HeaderRemoveMediaLocation": "\u0418\u0437\u044a\u044f\u0442\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
|
||||
"MessageConfirmRemoveMediaLocation": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0437\u044a\u044f\u0442\u044c \u044d\u0442\u043e \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435?",
|
||||
"HeaderRenameMediaFolder": "\u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0438",
|
||||
"LabelNewName": "\u041d\u043e\u0432\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435:",
|
||||
"HeaderAddMediaFolder": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0438",
|
||||
"HeaderAddMediaFolderHelp": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 (\u041a\u0438\u043d\u043e, \u041c\u0443\u0437\u044b\u043a\u0430, \u0422\u0412 \u0438 \u0442.\u043f.).",
|
||||
"HeaderRemoveMediaFolder": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0438",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "\u0418\u0437 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u044a\u044f\u0442\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 :",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0437\u044a\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0443?",
|
||||
"ButtonRename": "\u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u0442\u044c",
|
||||
"ButtonChangeType": "\u0421\u043c\u0435\u043d\u0438\u0442\u044c \u0442\u0438\u043f",
|
||||
"HeaderMediaLocations": "\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
|
||||
"LabelFolderTypeValue": "\u0422\u0438\u043f \u043f\u0430\u043f\u043a\u0438: {0}",
|
||||
"LabelPathSubstitutionHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e: \u041f\u0440\u0438 \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043f\u0443\u0442\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0441 \u0441\u0435\u0442\u0435\u0432\u044b\u043c\u0438 \u043e\u0431\u0449\u0438\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0441\u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f.",
|
||||
"FolderTypeMixed": "\u0421\u043c\u0435\u0448\u0430\u043d\u043d\u044b\u0439 (\u0444\u0438\u043b\u044c\u043c\u044b \u0438 \u0422\u0412)",
|
||||
"FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
|
||||
"FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
|
||||
"FolderTypeAdultVideos": "\u0412\u0437\u0440\u043e\u0441\u043b\u043e\u0435 \u0432\u0438\u0434\u0435\u043e",
|
||||
"FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438",
|
||||
"FolderTypeMusicVideos": "\u041c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e",
|
||||
"FolderTypeHomeVideos": "\u0414\u043e\u043c\u0430\u0448\u043d\u0435\u0435 \u0432\u0438\u0434\u0435\u043e",
|
||||
"FolderTypeGames": "\u0418\u0433\u0440\u044b",
|
||||
"FolderTypeBooks": "\u041a\u043d\u0438\u0433\u0438",
|
||||
"FolderTypeTvShows": "\u0422\u0412 \u0446\u0438\u043a\u043b\u044b",
|
||||
"TabMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
|
||||
"TabSeries": "\u0421\u0435\u0440\u0438\u0430\u043b\u044b",
|
||||
"TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u044b",
|
||||
"TabTrailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u044b",
|
||||
"TabGames": "\u0418\u0433\u0440\u044b",
|
||||
"TabAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u044b",
|
||||
"TabSongs": "\u041c\u0435\u043b\u043e\u0434\u0438\u0438",
|
||||
"TabMusicVideos": "\u041a\u043b\u0438\u043f\u044b",
|
||||
"BirthPlaceValue": "\u041c\u0435\u0441\u0442\u043e \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f: {0}",
|
||||
"DeathDateValue": "\u041a\u043e\u043d\u0447\u0438\u043d\u0430: {0}",
|
||||
"BirthDateValue": "\u0420\u043e\u0436\u0434\u0435\u043d\u0438\u0435: {0}"
|
||||
}
|
@ -328,8 +328,8 @@
|
||||
"LabelSelectPlaylist": "Spellista:",
|
||||
"OptionNewPlaylist": "Ny spellista...",
|
||||
"MessageAddedToPlaylistSuccess": "Ok",
|
||||
"ButtonViewSeriesRecording": "View series recording",
|
||||
"ValueOriginalAirDate": "Original air date: {0}",
|
||||
"ButtonViewSeriesRecording": "Visa serieinspelning",
|
||||
"ValueOriginalAirDate": "Ursprungligt s\u00e4ndningsdatum: {0}",
|
||||
"ButtonRemoveFromPlaylist": "Remove from playlist",
|
||||
"HeaderSpecials": "Specials",
|
||||
"HeaderTrailers": "Trailers",
|
||||
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "S\u00e4songsnummer:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Avsnittsnummer:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Filmer",
|
||||
"TabSeries": "Serie",
|
||||
"TabEpisodes": "Avsnitt",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Spel",
|
||||
"TabAlbums": "Album",
|
||||
"TabSongs": "L\u00e5tar",
|
||||
"TabMusicVideos": "Musikvideor",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "Filmler",
|
||||
"TabSeries": "Seriler",
|
||||
"TabEpisodes": "B\u00f6l\u00fcmler",
|
||||
"TabTrailers": "Fragmanlar",
|
||||
"TabGames": "Oyunlar",
|
||||
"TabAlbums": "Alb\u00fcm",
|
||||
"TabSongs": "\u015eark\u0131lar",
|
||||
"TabMusicVideos": "Klipler",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
@ -374,5 +374,60 @@
|
||||
"LabelMetadataSavers": "Metadata savers:",
|
||||
"LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
|
||||
"LabelImageFetchers": "Image fetchers:",
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority."
|
||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||
"ButtonQueueAllFromHere": "Queue all from here",
|
||||
"ButtonPlayAllFromHere": "Play all from here",
|
||||
"LabelDynamicExternalId": "{0} Id:",
|
||||
"HeaderIdentify": "Identify Item",
|
||||
"PersonTypePerson": "Person",
|
||||
"LabelTitleDisplayOrder": "Title display order:",
|
||||
"OptionSortName": "Sort name",
|
||||
"OptionReleaseDate": "Release date",
|
||||
"LabelSeasonNumber": "Season number:",
|
||||
"LabelDiscNumber": "Disc number",
|
||||
"LabelParentNumber": "Parent number",
|
||||
"LabelEpisodeNumber": "Episode number:",
|
||||
"LabelTrackNumber": "Track number:",
|
||||
"LabelNumber": "Number:",
|
||||
"LabelReleaseDate": "Release date:",
|
||||
"LabelEndDate": "End date:",
|
||||
"LabelYear": "Year:",
|
||||
"LabelDateOfBirth": "Date of birth:",
|
||||
"LabelBirthYear": "Birth year:",
|
||||
"LabelDeathDate": "Death date:",
|
||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||
"HeaderRenameMediaFolder": "Rename Media Folder",
|
||||
"LabelNewName": "New name:",
|
||||
"HeaderAddMediaFolder": "Add Media Folder",
|
||||
"HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
|
||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
|
||||
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
|
||||
"ButtonRename": "Rename",
|
||||
"ButtonChangeType": "Change type",
|
||||
"HeaderMediaLocations": "Media Locations",
|
||||
"LabelFolderTypeValue": "Folder type: {0}",
|
||||
"LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
|
||||
"FolderTypeMixed": "Mixed movies & tv",
|
||||
"FolderTypeMovies": "Movies",
|
||||
"FolderTypeMusic": "Music",
|
||||
"FolderTypeAdultVideos": "Adult videos",
|
||||
"FolderTypePhotos": "Photos",
|
||||
"FolderTypeMusicVideos": "Music videos",
|
||||
"FolderTypeHomeVideos": "Home videos",
|
||||
"FolderTypeGames": "Games",
|
||||
"FolderTypeBooks": "Books",
|
||||
"FolderTypeTvShows": "TV shows",
|
||||
"TabMovies": "C\u00e1c phim",
|
||||
"TabSeries": "Series",
|
||||
"TabEpisodes": "C\u00e1c t\u1eadp phim",
|
||||
"TabTrailers": "Trailers",
|
||||
"TabGames": "Games",
|
||||
"TabAlbums": "C\u00e1c Album",
|
||||
"TabSongs": "C\u00e1c ca kh\u00fac",
|
||||
"TabMusicVideos": "C\u00e1c video \u00e2m nh\u1ea1c",
|
||||
"BirthPlaceValue": "Birth place: {0}",
|
||||
"DeathDateValue": "Died: {0}",
|
||||
"BirthDateValue": "Born: {0}"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user