aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke <luke.pulverenti@gmail.com>2017-11-20 13:02:59 -0500
committerGitHub <noreply@github.com>2017-11-20 13:02:59 -0500
commit8f78652398ad4e9e9af53a1bd065afe4b9d9260e (patch)
tree32bc4144212d7f6ee3941c9c2471b56ab9c5d3e2
parent7d15b140cfe4f761e03f661f82cf946f327863f5 (diff)
parent71ff88284be60fb39a7389e0c4990c94f2207ed4 (diff)
Merge pull request #3032 from MediaBrowser/beta
Beta
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs53
-rw-r--r--Emby.Dlna/DlnaManager.cs1
-rw-r--r--Emby.Dlna/Emby.Dlna.csproj2
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs2
-rw-r--r--Emby.Dlna/Profiles/DefaultProfile.cs6
-rw-r--r--Emby.Dlna/Profiles/WdtvLiveProfile.cs10
-rw-r--r--Emby.Dlna/Profiles/Xbox360Profile.cs326
-rw-r--r--Emby.Dlna/Profiles/XboxOneProfile.cs4
-rw-r--r--Emby.Dlna/Profiles/Xml/Default.xml4
-rw-r--r--Emby.Dlna/Profiles/Xml/WDTV Live.xml10
-rw-r--r--Emby.Dlna/Profiles/Xml/Xbox 360.xml116
-rw-r--r--Emby.Dlna/Profiles/Xml/Xbox One.xml4
-rw-r--r--Emby.Drawing.Skia/Emby.Drawing.Skia.csproj4
-rw-r--r--Emby.Drawing.Skia/packages.config2
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs5
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs16
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj3
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs8
-rw-r--r--Emby.Server.Implementations/IO/ProgressStream.cs240
-rw-r--r--Emby.Server.Implementations/IO/SharpCifsFileSystem.cs42
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs14
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs251
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs37
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs30
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs28
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs114
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs11
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs32
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs (renamed from Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs)73
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/bg-BG.json91
-rw-r--r--Emby.Server.Implementations/Localization/Core/ca.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/cs.json9
-rw-r--r--Emby.Server.Implementations/Localization/Core/da.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/de.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-GB.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-AR.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-MX.json9
-rw-r--r--Emby.Server.Implementations/Localization/Core/es.json13
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr-CA.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr.json9
-rw-r--r--Emby.Server.Implementations/Localization/Core/he.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/hr.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/it.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/kk.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/ko.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/lt-LT.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/ms.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/nb.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/nl.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/pl.json9
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-BR.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-PT.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/ru.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/sk.json143
-rw-r--r--Emby.Server.Implementations/Localization/Core/sl-SI.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json9
-rw-r--r--Emby.Server.Implementations/Localization/Core/tr.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-CN.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-HK.json7
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs28
-rw-r--r--Emby.Server.Implementations/MediaEncoder/EncodingManager.cs9
-rw-r--r--Emby.Server.Implementations/Net/SocketFactory.cs12
-rw-r--r--Emby.Server.Implementations/Networking/NetworkManager.cs20
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs5
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs2
-rw-r--r--Emby.Server.Implementations/Session/HttpSessionController.cs12
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs11
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs15
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs33
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs35
-rw-r--r--MediaBrowser.Api/VideosService.cs6
-rw-r--r--MediaBrowser.Common/Net/HttpRequestOptions.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs7
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs15
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs12
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs78
-rw-r--r--MediaBrowser.Controller/IO/StreamHelper.cs23
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs16
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs3
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs3
-rw-r--r--MediaBrowser.Controller/Providers/DirectoryService.cs52
-rw-r--r--MediaBrowser.Controller/Providers/IDirectoryService.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs104
-rw-r--r--MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs14
-rw-r--r--MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs1
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs18
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs2
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs82
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvOptions.cs1
-rw-r--r--MediaBrowser.Model/Session/GeneralCommandType.cs3
-rw-r--r--MediaBrowser.Model/Session/PlayRequest.cs10
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs14
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs8
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs6
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs115
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Subtitles/SubtitleManager.cs97
-rw-r--r--MediaBrowser.Server.Mono/ImageEncoderHelper.cs4
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj4
-rw-r--r--MediaBrowser.Server.Mono/packages.config2
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj8
-rw-r--r--MediaBrowser.ServerApplication/packages.config2
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs4
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs14
-rw-r--r--RSSDP/SsdpCommunicationsServer.cs6
111 files changed, 1356 insertions, 1523 deletions
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 7db282dc86..5d6ef1adfe 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -491,18 +491,27 @@ namespace Emby.Dlna.ContentDirectory
return GetGenreItems(item, null, user, sort, startIndex, limit);
}
- var collectionFolder = item as ICollectionFolder;
- if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+ if (!stubType.HasValue || stubType.Value != StubType.Folder)
{
- return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
- }
- if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
- {
- return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
- }
- if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
- {
- return GetTvFolders(item, user, stubType, sort, startIndex, limit);
+ var collectionFolder = item as ICollectionFolder;
+ if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+ {
+ return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
+ }
+ if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+ {
+ return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
+ }
+ if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+ {
+ return GetTvFolders(item, user, stubType, sort, startIndex, limit);
+ }
+
+ var userView = item as UserView;
+ if (userView != null && string.Equals(CollectionType.Folders, userView.ViewType, StringComparison.OrdinalIgnoreCase))
+ {
+ return GetFolders(item, user, stubType, sort, startIndex, limit);
+ }
}
if (stubType.HasValue)
@@ -513,7 +522,10 @@ namespace Emby.Dlna.ContentDirectory
return GetItemsFromPerson(person, user, startIndex, limit);
}
- return ApplyPaging(new QueryResult<ServerItem>(), startIndex, limit);
+ if (stubType.Value != StubType.Folder)
+ {
+ return ApplyPaging(new QueryResult<ServerItem>(), startIndex, limit);
+ }
}
var folder = (Folder)item;
@@ -733,6 +745,23 @@ namespace Emby.Dlna.ContentDirectory
};
}
+ private QueryResult<ServerItem> GetFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
+ {
+ var folders = user.RootFolder.GetChildren(user, true)
+ .OrderBy(i => i.SortName)
+ .Select(i => new ServerItem(i)
+ {
+ StubType = StubType.Folder
+ })
+ .ToArray();
+
+ return new QueryResult<ServerItem>
+ {
+ Items = folders,
+ TotalRecordCount = folders.Length
+ };
+ }
+
private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
{
var query = new InternalItemsQuery(user)
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index bdc523c8bc..8caa086ee2 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -554,7 +554,6 @@ namespace Emby.Dlna
var list = new List<DeviceProfile>
{
new SamsungSmartTvProfile(),
- new Xbox360Profile(),
new XboxOneProfile(),
new SonyPs3Profile(),
new SonyPs4Profile(),
diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj
index 365774b0d9..eb8b178a85 100644
--- a/Emby.Dlna/Emby.Dlna.csproj
+++ b/Emby.Dlna/Emby.Dlna.csproj
@@ -105,7 +105,6 @@
<Compile Include="Profiles\SonyPs3Profile.cs" />
<Compile Include="Profiles\SonyPs4Profile.cs" />
<Compile Include="Profiles\WdtvLiveProfile.cs" />
- <Compile Include="Profiles\Xbox360Profile.cs" />
<Compile Include="Profiles\XboxOneProfile.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Server\DescriptionXmlBuilder.cs" />
@@ -175,7 +174,6 @@
<EmbeddedResource Include="Profiles\Xml\Sony PlayStation 3.xml" />
<EmbeddedResource Include="Profiles\Xml\Sony PlayStation 4.xml" />
<EmbeddedResource Include="Profiles\Xml\WDTV Live.xml" />
- <EmbeddedResource Include="Profiles\Xml\Xbox 360.xml" />
<EmbeddedResource Include="Profiles\Xml\Xbox One.xml" />
</ItemGroup>
<ItemGroup>
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index ba1d3a6de2..bd0a9e1f42 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -328,7 +328,7 @@ namespace Emby.Dlna.PlayTo
{
if (isFirst && command.StartPositionTicks.HasValue)
{
- playlist.Add(CreatePlaylistItem(item, user, command.StartPositionTicks.Value, null, null, null));
+ playlist.Add(CreatePlaylistItem(item, user, command.StartPositionTicks.Value, command.MediaSourceId, command.AudioStreamIndex, command.SubtitleStreamIndex));
isFirst = false;
}
else
diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs
index 46639ee424..75204b234d 100644
--- a/Emby.Dlna/Profiles/DefaultProfile.cs
+++ b/Emby.Dlna/Profiles/DefaultProfile.cs
@@ -65,13 +65,15 @@ namespace Emby.Dlna.Profiles
{
new DirectPlayProfile
{
- Container = "m4v,mpegts,ts,3gp,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm,wtv,m2ts,dvr-ms",
+ // play all
+ Container = "",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
- Container = "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac,m4a",
+ // play all
+ Container = "",
Type = DlnaProfileType.Audio
}
};
diff --git a/Emby.Dlna/Profiles/WdtvLiveProfile.cs b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
index 01e77baa25..61819c57d2 100644
--- a/Emby.Dlna/Profiles/WdtvLiveProfile.cs
+++ b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
@@ -58,7 +58,7 @@ namespace Emby.Dlna.Profiles
Container = "avi",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
- AudioCodec = "ac3,dca,mp2,mp3,pcm,dts"
+ AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts"
},
new DirectPlayProfile
@@ -66,7 +66,7 @@ namespace Emby.Dlna.Profiles
Container = "mpeg",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video",
- AudioCodec = "ac3,dca,mp2,mp3,pcm,dts"
+ AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts"
},
new DirectPlayProfile
@@ -74,7 +74,7 @@ namespace Emby.Dlna.Profiles
Container = "mkv",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
- AudioCodec = "ac3,dca,aac,mp2,mp3,pcm,dts"
+ AudioCodec = "ac3,eac3,dca,aac,mp2,mp3,pcm,dts"
},
new DirectPlayProfile
@@ -82,7 +82,7 @@ namespace Emby.Dlna.Profiles
Container = "ts,m2ts",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
- AudioCodec = "ac3,dca,mp2,mp3,aac,dts"
+ AudioCodec = "ac3,eac3,dca,mp2,mp3,aac,dts"
},
new DirectPlayProfile
@@ -90,7 +90,7 @@ namespace Emby.Dlna.Profiles
Container = "mp4,mov,m4v",
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
- AudioCodec = "ac3,aac,mp2,mp3,dca,dts"
+ AudioCodec = "ac3,eac3,aac,mp2,mp3,dca,dts"
},
new DirectPlayProfile
diff --git a/Emby.Dlna/Profiles/Xbox360Profile.cs b/Emby.Dlna/Profiles/Xbox360Profile.cs
deleted file mode 100644
index 7bdcd2a6f8..0000000000
--- a/Emby.Dlna/Profiles/Xbox360Profile.cs
+++ /dev/null
@@ -1,326 +0,0 @@
-using MediaBrowser.Model.Dlna;
-using System.Xml.Serialization;
-
-namespace Emby.Dlna.Profiles
-{
- /// <summary>
- /// Good info on xbox 360 requirements: https://code.google.com/p/jems/wiki/XBox360Notes
- /// </summary>
- [XmlRoot("Profile")]
- public class Xbox360Profile : DefaultProfile
- {
- public Xbox360Profile()
- {
- Name = "Xbox 360";
-
- // Required according to above
- ModelName = "Windows Media Player Sharing";
-
- ModelNumber = "12.0";
-
- FriendlyName = "${HostName}: 1";
-
- ModelUrl = "http://go.microsoft.com/fwlink/?LinkId=105926";
- Manufacturer = "Microsoft Corporation";
- ManufacturerUrl = "http://www.microsoft.com";
- XDlnaDoc = "DMS-1.50";
- ModelDescription = "Emby : UPnP Media Server";
-
- TimelineOffsetSeconds = 40;
- RequiresPlainFolders = true;
- RequiresPlainVideoItems = true;
- EnableMSMediaReceiverRegistrar = true;
-
- Identification = new DeviceIdentification
- {
- ModelName = "Xbox 360",
-
- Headers = new[]
- {
- new HttpHeaderInfo {Name = "User-Agent", Value = "Xbox", Match = HeaderMatchType.Substring},
- new HttpHeaderInfo {Name = "User-Agent", Value = "Xenon", Match = HeaderMatchType.Substring}
- }
- };
-
- TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
- new TranscodingProfile
- {
- Container = "asf",
- VideoCodec = "wmv2",
- AudioCodec = "wmav2",
- Type = DlnaProfileType.Video,
- TranscodeSeekInfo = TranscodeSeekInfo.Bytes,
- EstimateContentLength = true
- },
- new TranscodingProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
-
- DirectPlayProfiles = new[]
- {
- new DirectPlayProfile
- {
- Container = "avi",
- VideoCodec = "mpeg4",
- AudioCodec = "ac3,mp3",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "avi",
- VideoCodec = "h264",
- AudioCodec = "aac",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "mp4,mov",
- VideoCodec = "h264,mpeg4",
- AudioCodec = "aac,ac3",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "asf",
- VideoCodec = "wmv2,wmv3,vc1",
- AudioCodec = "wmav2,wmapro",
- Type = DlnaProfileType.Video
- },
- new DirectPlayProfile
- {
- Container = "asf",
- AudioCodec = "wmav2,wmapro,wmavoice",
- Type = DlnaProfileType.Audio
- },
- new DirectPlayProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
- new DirectPlayProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
-
- ResponseProfiles = new[]
- {
- new ResponseProfile
- {
- Container = "avi",
- MimeType = "video/avi",
- Type = DlnaProfileType.Video
- }
- };
-
- ContainerProfiles = new[]
- {
- new ContainerProfile
- {
- Type = DlnaProfileType.Video,
- Container = "mp4,mov",
-
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.Equals,
- Property = ProfileConditionValue.Has64BitOffsets,
- Value = "false",
- IsRequired = false
- }
- }
- },
-
- new ContainerProfile
- {
- Type = DlnaProfileType.Photo,
-
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1920"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "1080"
- }
- }
- }
- };
-
- CodecProfiles = new[]
- {
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "mpeg4",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1280"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "720"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoFramerate,
- Value = "30",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoBitrate,
- Value = "5120000",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "h264",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1920"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "1080"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoLevel,
- Value = "41",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoBitrate,
- Value = "10240000",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.Video,
- Codec = "wmv2,wmv3,vc1",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1920"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "1080"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoFramerate,
- Value = "30",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoBitrate,
- Value = "15360000",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.VideoAudio,
- Codec = "ac3,wmav2,wmapro",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.AudioChannels,
- Value = "6",
- IsRequired = false
- }
- }
- },
-
- new CodecProfile
- {
- Type = CodecType.VideoAudio,
- Codec = "aac",
- Conditions = new []
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.AudioChannels,
- Value = "2",
- IsRequired = false
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.Equals,
- Property = ProfileConditionValue.AudioProfile,
- Value = "lc",
- IsRequired = false
- }
- }
- }
- };
-
- SubtitleProfiles = new[]
- {
- new SubtitleProfile
- {
- Format = "srt",
- Method = SubtitleDeliveryMethod.Embed
- }
- };
- }
- }
-}
diff --git a/Emby.Dlna/Profiles/XboxOneProfile.cs b/Emby.Dlna/Profiles/XboxOneProfile.cs
index e17640f2fa..99e52510f7 100644
--- a/Emby.Dlna/Profiles/XboxOneProfile.cs
+++ b/Emby.Dlna/Profiles/XboxOneProfile.cs
@@ -60,7 +60,7 @@ namespace Emby.Dlna.Profiles
new DirectPlayProfile
{
Container = "ts",
- VideoCodec = "h264,mpeg2video",
+ VideoCodec = "h264,mpeg2video,hevc",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
@@ -81,7 +81,7 @@ namespace Emby.Dlna.Profiles
new DirectPlayProfile
{
Container = "mp4,mov,mkv,m4v",
- VideoCodec = "h264,mpeg4,mpeg2video",
+ VideoCodec = "h264,mpeg4,mpeg2video,hevc",
AudioCodec = "aac,ac3",
Type = DlnaProfileType.Video
},
diff --git a/Emby.Dlna/Profiles/Xml/Default.xml b/Emby.Dlna/Profiles/Xml/Default.xml
index b07a2f7c26..133f4abf1a 100644
--- a/Emby.Dlna/Profiles/Xml/Default.xml
+++ b/Emby.Dlna/Profiles/Xml/Default.xml
@@ -29,8 +29,8 @@
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="m4v,mpegts,ts,3gp,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm,wtv,m2ts,dvr-ms" type="Video" />
- <DirectPlayProfile container="aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac,m4a" type="Audio" />
+ <DirectPlayProfile container="" type="Video" />
+ <DirectPlayProfile container="" type="Audio" />
</DirectPlayProfiles>
<TranscodingProfiles>
<TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
diff --git a/Emby.Dlna/Profiles/Xml/WDTV Live.xml b/Emby.Dlna/Profiles/Xml/WDTV Live.xml
index 71b3463187..44d130e929 100644
--- a/Emby.Dlna/Profiles/Xml/WDTV Live.xml
+++ b/Emby.Dlna/Profiles/Xml/WDTV Live.xml
@@ -36,11 +36,11 @@
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
- <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video" type="Video" />
- <DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
- <DirectPlayProfile container="ts,m2ts" audioCodec="ac3,dca,mp2,mp3,aac,dts" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
- <DirectPlayProfile container="mp4,mov,m4v" audioCodec="ac3,aac,mp2,mp3,dca,dts" videoCodec="h264,mpeg4" type="Video" />
+ <DirectPlayProfile container="avi" audioCodec="ac3,eac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
+ <DirectPlayProfile container="mpeg" audioCodec="ac3,eac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="ac3,eac3,dca,aac,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
+ <DirectPlayProfile container="ts,m2ts" audioCodec="ac3,eac3,dca,mp2,mp3,aac,dts" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
+ <DirectPlayProfile container="mp4,mov,m4v" audioCodec="ac3,eac3,aac,mp2,mp3,dca,dts" videoCodec="h264,mpeg4" type="Video" />
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="vc1" type="Video" />
<DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
diff --git a/Emby.Dlna/Profiles/Xml/Xbox 360.xml b/Emby.Dlna/Profiles/Xml/Xbox 360.xml
deleted file mode 100644
index 3b7d2963f2..0000000000
--- a/Emby.Dlna/Profiles/Xml/Xbox 360.xml
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0"?>
-<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <Name>Xbox 360</Name>
- <Identification>
- <ModelName>Xbox 360</ModelName>
- <Headers>
- <HttpHeaderInfo name="User-Agent" value="Xbox" match="Substring" />
- <HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
- </Headers>
- </Identification>
- <FriendlyName>${HostName}: 1</FriendlyName>
- <Manufacturer>Microsoft Corporation</Manufacturer>
- <ManufacturerUrl>http://www.microsoft.com</ManufacturerUrl>
- <ModelName>Windows Media Player Sharing</ModelName>
- <ModelDescription>Emby : UPnP Media Server</ModelDescription>
- <ModelNumber>12.0</ModelNumber>
- <ModelUrl>http://go.microsoft.com/fwlink/?LinkId=105926</ModelUrl>
- <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
- <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
- <EnableSingleSubtitleLimit>false</EnableSingleSubtitleLimit>
- <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
- <AlbumArtPn>JPEG_SM</AlbumArtPn>
- <MaxAlbumArtWidth>480</MaxAlbumArtWidth>
- <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
- <MaxIconWidth>48</MaxIconWidth>
- <MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
- <MaxStaticBitrate>40000000</MaxStaticBitrate>
- <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
- <MaxStaticMusicBitrate xsi:nil="true" />
- <XDlnaDoc>DMS-1.50</XDlnaDoc>
- <ProtocolInfo>http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_HD_50_AC3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_BASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_FULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-matroska:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_1080i_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_HP_HD_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_LPCM;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_ASP_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_SP_L6_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_NDSD;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_LPCM_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000</ProtocolInfo>
- <TimelineOffsetSeconds>40</TimelineOffsetSeconds>
- <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
- <RequiresPlainFolders>true</RequiresPlainFolders>
- <EnableMSMediaReceiverRegistrar>true</EnableMSMediaReceiverRegistrar>
- <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
- <XmlRootAttributes />
- <DirectPlayProfiles>
- <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
- <DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
- <DirectPlayProfile container="mp4,mov" audioCodec="aac,ac3" videoCodec="h264,mpeg4" type="Video" />
- <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="wmv2,wmv3,vc1" type="Video" />
- <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
- <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
- <DirectPlayProfile container="jpeg" type="Photo" />
- </DirectPlayProfiles>
- <TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
- <TranscodingProfile container="asf" type="Video" videoCodec="wmv2" audioCodec="wmav2" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Bytes" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
- </TranscodingProfiles>
- <ContainerProfiles>
- <ContainerProfile type="Video" container="mp4,mov">
- <Conditions>
- <ProfileCondition condition="Equals" property="Has64BitOffsets" value="false" isRequired="false" />
- </Conditions>
- </ContainerProfile>
- <ContainerProfile type="Photo">
- <Conditions>
- <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
- <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
- </Conditions>
- </ContainerProfile>
- </ContainerProfiles>
- <CodecProfiles>
- <CodecProfile type="Video" codec="mpeg4">
- <Conditions>
- <ProfileCondition condition="LessThanEqual" property="Width" value="1280" isRequired="true" />
- <ProfileCondition condition="LessThanEqual" property="Height" value="720" isRequired="true" />
- <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
- <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="5120000" isRequired="false" />
- </Conditions>
- <ApplyConditions />
- </CodecProfile>
- <CodecProfile type="Video" codec="h264">
- <Conditions>
- <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
- <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
- <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" />
- <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="10240000" isRequired="false" />
- </Conditions>
- <ApplyConditions />
- </CodecProfile>
- <CodecProfile type="Video" codec="wmv2,wmv3,vc1">
- <Conditions>
- <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
- <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
- <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" />
- <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" />
- </Conditions>
- <ApplyConditions />
- </CodecProfile>
- <CodecProfile type="VideoAudio" codec="ac3,wmav2,wmapro">
- <Conditions>
- <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" />
- </Conditions>
- <ApplyConditions />
- </CodecProfile>
- <CodecProfile type="VideoAudio" codec="aac">
- <Conditions>
- <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="false" />
- <ProfileCondition condition="Equals" property="AudioProfile" value="lc" isRequired="false" />
- </Conditions>
- <ApplyConditions />
- </CodecProfile>
- </CodecProfiles>
- <ResponseProfiles>
- <ResponseProfile container="avi" type="Video" mimeType="video/avi">
- <Conditions />
- </ResponseProfile>
- </ResponseProfiles>
- <SubtitleProfiles>
- <SubtitleProfile format="srt" method="Embed" />
- </SubtitleProfiles>
-</Profile> \ No newline at end of file
diff --git a/Emby.Dlna/Profiles/Xml/Xbox One.xml b/Emby.Dlna/Profiles/Xml/Xbox One.xml
index 423327a389..6354232342 100644
--- a/Emby.Dlna/Profiles/Xml/Xbox One.xml
+++ b/Emby.Dlna/Profiles/Xml/Xbox One.xml
@@ -36,10 +36,10 @@
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg2video" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg2video,hevc" type="Video" />
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
<DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
- <DirectPlayProfile container="mp4,mov,mkv,m4v" audioCodec="aac,ac3" videoCodec="h264,mpeg4,mpeg2video" type="Video" />
+ <DirectPlayProfile container="mp4,mov,mkv,m4v" audioCodec="aac,ac3" videoCodec="h264,mpeg4,mpeg2video,hevc" type="Video" />
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="wmv2,wmv3,vc1" type="Video" />
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
<DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
index 6024c3d2c0..f2b32d52cb 100644
--- a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
+++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
@@ -63,8 +63,8 @@
<EmbeddedResource Include="fonts\robotoregular.ttf" />
</ItemGroup>
<ItemGroup>
- <Reference Include="SkiaSharp, Version=1.59.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
- <HintPath>..\packages\SkiaSharp.1.59.2\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll</HintPath>
+ <Reference Include="SkiaSharp, Version=1.58.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
+ <HintPath>..\packages\SkiaSharp.1.58.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
diff --git a/Emby.Drawing.Skia/packages.config b/Emby.Drawing.Skia/packages.config
index 1aa3653cd7..2b9b0aee43 100644
--- a/Emby.Drawing.Skia/packages.config
+++ b/Emby.Drawing.Skia/packages.config
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="SkiaSharp" version="1.59.2" targetFramework="portable45-net45+win8" />
+ <package id="SkiaSharp" version="1.58.1" targetFramework="portable45-net45+win8" />
</packages> \ No newline at end of file
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index c1ab9ec222..745d83eb5f 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -799,7 +799,7 @@ namespace Emby.Server.Implementations
protected abstract IConnectManager CreateConnectManager();
protected abstract ISyncManager CreateSyncManager();
-
+
protected virtual IHttpClient CreateHttpClient()
{
return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
@@ -953,6 +953,7 @@ namespace Emby.Server.Implementations
var deviceRepo = new SqliteDeviceRepository(LogManager.GetLogger("DeviceManager"), ServerConfigurationManager, FileSystemManager, JsonSerializer);
deviceRepo.Initialize();
DeviceManager = new DeviceManager(deviceRepo, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
+ RegisterSingleInstance<IDeviceRepository>(deviceRepo);
RegisterSingleInstance(DeviceManager);
var newsService = new Emby.Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
@@ -996,7 +997,7 @@ namespace Emby.Server.Implementations
NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
RegisterSingleInstance(NotificationManager);
- SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager);
+ SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager, ServerConfigurationManager);
RegisterSingleInstance(SubtitleManager);
RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, SocketFactory, TimerFactory));
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index c42f22804b..c566ca25bd 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -296,7 +296,7 @@ namespace Emby.Server.Implementations.Channels
if (requiresCallback != null)
{
- results = await GetChannelItemMediaSourcesInternal(requiresCallback, GetItemExternalId(item), cancellationToken)
+ results = await GetChannelItemMediaSourcesInternal(requiresCallback, item.ExternalId, cancellationToken)
.ConfigureAwait(false);
}
else
@@ -990,18 +990,6 @@ namespace Emby.Server.Implementations.Channels
return result;
}
- private string GetItemExternalId(BaseItem item)
- {
- var externalId = item.ExternalId;
-
- if (string.IsNullOrWhiteSpace(externalId))
- {
- externalId = item.GetProviderId("ProviderExternalId");
- }
-
- return externalId;
- }
-
private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1);
private async Task<ChannelItemResult> GetChannelItems(IChannel channel,
User user,
@@ -1080,7 +1068,7 @@ namespace Emby.Server.Implementations.Channels
{
var categoryItem = _libraryManager.GetItemById(new Guid(folderId));
- query.FolderId = GetItemExternalId(categoryItem);
+ query.FolderId = categoryItem.ExternalId;
}
var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 8ff1b63c03..7ccf54d20f 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -117,7 +117,6 @@
<Compile Include="IO\ManagedFileSystem.cs" />
<Compile Include="IO\MbLinkShortcutHandler.cs" />
<Compile Include="IO\MemoryStreamProvider.cs" />
- <Compile Include="IO\ProgressStream.cs" />
<Compile Include="IO\SharpCifsFileSystem.cs" />
<Compile Include="IO\SharpCifs\Config.cs" />
<Compile Include="IO\SharpCifs\Dcerpc\DcerpcBind.cs" />
@@ -405,11 +404,11 @@
<Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunManager.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" />
- <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHttpStream.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" />
<Compile Include="LiveTv\TunerHosts\LiveStream.cs" />
<Compile Include="LiveTv\TunerHosts\M3uParser.cs" />
<Compile Include="LiveTv\TunerHosts\M3UTunerHost.cs" />
+ <Compile Include="LiveTv\TunerHosts\SharedHttpStream.cs" />
<Compile Include="Localization\LocalizationManager.cs" />
<Compile Include="Localization\TextLocalizer.cs" />
<Compile Include="Logging\ConsoleLogger.cs" />
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index cd7c98dc85..4a9e417f2e 100644
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
+using MediaBrowser.Controller.IO;
namespace Emby.Server.Implementations.HttpClientManager
{
@@ -633,12 +634,9 @@ namespace Emby.Server.Implementations.HttpClientManager
}
else
{
- using (var stream = ProgressStream.CreateReadProgressStream(httpResponse.GetResponseStream(), options.Progress.Report, contentLength.Value))
+ using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
{
- using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
- {
- await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
- }
+ await StreamHelper.CopyToAsync(httpResponse.GetResponseStream(), fs, StreamDefaults.DefaultCopyToBufferSize, options.Progress, contentLength.Value, options.CancellationToken).ConfigureAwait(false);
}
}
diff --git a/Emby.Server.Implementations/IO/ProgressStream.cs b/Emby.Server.Implementations/IO/ProgressStream.cs
deleted file mode 100644
index be1ff72f8e..0000000000
--- a/Emby.Server.Implementations/IO/ProgressStream.cs
+++ /dev/null
@@ -1,240 +0,0 @@
-using System;
-using System.IO;
-
-namespace Emby.Server.Implementations.IO
-{
- /// <summary>
- /// Measures progress when reading from a stream or writing to one
- /// </summary>
- public class ProgressStream : Stream
- {
- /// <summary>
- /// Gets the base stream.
- /// </summary>
- /// <value>The base stream.</value>
- public Stream BaseStream { get; private set; }
-
- /// <summary>
- /// Gets or sets the bytes processed.
- /// </summary>
- /// <value>The bytes processed.</value>
- private long BytesProcessed { get; set; }
- /// <summary>
- /// Gets or sets the length of the write.
- /// </summary>
- /// <value>The length of the write.</value>
- private long WriteLength { get; set; }
-
- /// <summary>
- /// Gets or sets the length of the read.
- /// </summary>
- /// <value>The length of the read.</value>
- private long? ReadLength { get; set; }
-
- /// <summary>
- /// Gets or sets the progress action.
- /// </summary>
- /// <value>The progress action.</value>
- private Action<double> ProgressAction { get; set; }
-
- /// <summary>
- /// Creates the read progress stream.
- /// </summary>
- /// <param name="baseStream">The base stream.</param>
- /// <param name="progressAction">The progress action.</param>
- /// <param name="readLength">Length of the read.</param>
- /// <returns>ProgressStream.</returns>
- public static ProgressStream CreateReadProgressStream(Stream baseStream, Action<double> progressAction, long? readLength = null)
- {
- return new ProgressStream
- {
- BaseStream = baseStream,
- ProgressAction = progressAction,
- ReadLength = readLength
- };
- }
-
- /// <summary>
- /// Creates the write progress stream.
- /// </summary>
- /// <param name="baseStream">The base stream.</param>
- /// <param name="progressAction">The progress action.</param>
- /// <param name="writeLength">Length of the write.</param>
- /// <returns>ProgressStream.</returns>
- public static ProgressStream CreateWriteProgressStream(Stream baseStream, Action<double> progressAction, long writeLength)
- {
- return new ProgressStream
- {
- BaseStream = baseStream,
- ProgressAction = progressAction,
- WriteLength = writeLength
- };
- }
-
- /// <summary>
- /// When overridden in a derived class, gets a value indicating whether the current stream supports reading.
- /// </summary>
- /// <value><c>true</c> if this instance can read; otherwise, <c>false</c>.</value>
- /// <returns>true if the stream supports reading; otherwise, false.</returns>
- public override bool CanRead
- {
- get { return BaseStream.CanRead; }
- }
-
- /// <summary>
- /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking.
- /// </summary>
- /// <value><c>true</c> if this instance can seek; otherwise, <c>false</c>.</value>
- /// <returns>true if the stream supports seeking; otherwise, false.</returns>
- public override bool CanSeek
- {
- get { return BaseStream.CanSeek; }
- }
-
- /// <summary>
- /// When overridden in a derived class, gets a value indicating whether the current stream supports writing.
- /// </summary>
- /// <value><c>true</c> if this instance can write; otherwise, <c>false</c>.</value>
- /// <returns>true if the stream supports writing; otherwise, false.</returns>
- public override bool CanWrite
- {
- get { return BaseStream.CanWrite; }
- }
-
- /// <summary>
- /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device.
- /// </summary>
- public override void Flush()
- {
- BaseStream.Flush();
- }
-
- /// <summary>
- /// When overridden in a derived class, gets the length in bytes of the stream.
- /// </summary>
- /// <value>The length.</value>
- /// <returns>A long value representing the length of the stream in bytes.</returns>
- public override long Length
- {
- get { return BaseStream.Length; }
- }
-
- /// <summary>
- /// When overridden in a derived class, gets or sets the position within the current stream.
- /// </summary>
- /// <value>The position.</value>
- /// <returns>The current position within the stream.</returns>
- public override long Position
- {
- get { return BaseStream.Position; }
- set
- {
- BaseStream.Position = value;
- }
- }
-
- /// <summary>
- /// When overridden in a derived class, 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 <paramref name="offset" /> and (<paramref name="offset" /> + <paramref name="count" /> - 1) replaced by the bytes read from the current source.</param>
- /// <param name="offset">The zero-based byte offset in <paramref name="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>
- public override int Read(byte[] buffer, int offset, int count)
- {
- var read = BaseStream.Read(buffer, offset, count);
-
- BytesProcessed += read;
-
- double percent = BytesProcessed;
- percent /= ReadLength ?? BaseStream.Length;
- percent *= 100;
-
- ProgressAction(percent);
-
- return read;
- }
-
- public override int EndRead(IAsyncResult asyncResult)
- {
- var read = base.EndRead(asyncResult);
-
- BytesProcessed += read;
-
- double percent = BytesProcessed;
- percent /= ReadLength ?? BaseStream.Length;
- percent *= 100;
-
- ProgressAction(percent);
-
- return read;
- }
-
- /// <summary>
- /// When overridden in a derived class, sets the position within the current stream.
- /// </summary>
- /// <param name="offset">A byte offset relative to the <paramref name="origin" /> parameter.</param>
- /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin" /> indicating the reference point used to obtain the new position.</param>
- /// <returns>The new position within the current stream.</returns>
- public override long Seek(long offset, SeekOrigin origin)
- {
- return BaseStream.Seek(offset, origin);
- }
-
- /// <summary>
- /// When overridden in a derived class, sets the length of the current stream.
- /// </summary>
- /// <param name="value">The desired length of the current stream in bytes.</param>
- public override void SetLength(long value)
- {
- BaseStream.SetLength(value);
- }
-
- /// <summary>
- /// When overridden in a derived class, 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 <paramref name="count" /> bytes from <paramref name="buffer" /> to the current stream.</param>
- /// <param name="offset">The zero-based byte offset in <paramref name="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>
- public override void Write(byte[] buffer, int offset, int count)
- {
- BaseStream.Write(buffer, offset, count);
-
- BytesProcessed += count;
-
- double percent = BytesProcessed;
- percent /= WriteLength;
- percent *= 100;
-
- ProgressAction(percent);
- }
-
- public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
- {
- var result = base.BeginWrite(buffer, offset, count, callback, state);
-
- BytesProcessed += count;
-
- double percent = BytesProcessed;
- percent /= WriteLength;
- percent *= 100;
-
- ProgressAction(percent);
-
- return result;
- }
-
- /// <summary>
- /// Releases the unmanaged resources used by the <see cref="T:System.IO.Stream" /> and optionally releases the managed resources.
- /// </summary>
- /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- BaseStream.Dispose();
- }
- base.Dispose(disposing);
- }
- }
-}
diff --git a/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs
index 1d21796b1a..0e1f6bb008 100644
--- a/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs
+++ b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs
@@ -487,14 +487,17 @@ namespace Emby.Server.Implementations.IO
AssertDirectoryExists(dir, path);
var list = ListFiles(dir, recursive);
+ var result = new List<FileSystemMetadata>();
foreach (var file in list)
{
if (file.IsDirectory())
{
- yield return ToMetadata(file);
+ result.Add(ToMetadata(file));
}
}
+
+ return result;
}
public IEnumerable<FileSystemMetadata> GetFiles(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
@@ -503,6 +506,7 @@ namespace Emby.Server.Implementations.IO
AssertDirectoryExists(dir, path);
var list = ListFiles(dir, recursive);
+ var result = new List<FileSystemMetadata>();
foreach (var file in list)
{
@@ -513,10 +517,12 @@ namespace Emby.Server.Implementations.IO
if (extensions == null || extensions.Length == 0 || extensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- yield return ToMetadata(file);
+ result.Add(ToMetadata(file));
}
}
}
+
+ return result;
}
public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false)
@@ -525,15 +531,19 @@ namespace Emby.Server.Implementations.IO
AssertDirectoryExists(dir, path);
var list = ListFiles(dir, recursive);
+ var result = new List<FileSystemMetadata>();
foreach (var file in list)
{
- yield return ToMetadata(file);
+ result.Add(ToMetadata(file));
}
+
+ return result;
}
- public IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false)
+ public List<string> GetFileSystemEntryPaths(string path, bool recursive = false)
{
+ var result = new List<string>();
var dir = CreateSmbDirectoryForListFiles(path);
AssertDirectoryExists(dir, path);
@@ -541,16 +551,18 @@ namespace Emby.Server.Implementations.IO
foreach (var file in list)
{
- yield return GetReturnPath(file);
+ result.Add(GetReturnPath(file));
}
+ return result;
}
- public IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
+ public List<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
{
var dir = CreateSmbDirectoryForListFiles(path);
AssertDirectoryExists(dir, path);
var list = ListFiles(dir, recursive);
+ var result = new List<string>();
foreach (var file in list)
{
@@ -561,44 +573,52 @@ namespace Emby.Server.Implementations.IO
if (extensions == null || extensions.Length == 0 || extensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- yield return filePath;
+ result.Add(filePath);
}
}
}
+
+ return result;
}
- public IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false)
+ public List<string> GetDirectoryPaths(string path, bool recursive = false)
{
var dir = CreateSmbDirectoryForListFiles(path);
AssertDirectoryExists(dir, path);
var list = ListFiles(dir, recursive);
+ var result = new List<string>();
foreach (var file in list)
{
if (file.IsDirectory())
{
- yield return GetReturnPath(file);
+ result.Add(GetReturnPath(file));
}
}
+
+ return result;
}
private IEnumerable<SmbFile> ListFiles(SmbFile dir, bool recursive)
{
var list = dir.ListFiles();
+ var result = new List<SmbFile>();
foreach (var file in list)
{
- yield return file;
+ result.Add(file);
if (recursive && file.IsDirectory())
{
foreach (var subFile in ListFiles(file, recursive))
{
- yield return subFile;
+ result.Add(subFile);
}
}
}
+
+ return result;
}
}
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index bd8a095503..f71e2714ac 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -709,6 +709,13 @@ namespace Emby.Server.Implementations.Library
var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
+ // In case program data folder was moved
+ if (!string.Equals(rootFolder.Path, rootFolderPath, StringComparison.Ordinal))
+ {
+ _logger.Info("Resetting root folder path to {0}", rootFolderPath);
+ rootFolder.Path = rootFolderPath;
+ }
+
// Add in the plug-in folders
foreach (var child in PluginFolderCreators)
{
@@ -771,6 +778,13 @@ namespace Emby.Server.Implementations.Library
tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath));
}
+ // In case program data folder was moved
+ if (!string.Equals(tmpItem.Path, userRootPath, StringComparison.Ordinal))
+ {
+ _logger.Info("Resetting user root folder path to {0}", userRootPath);
+ tmpItem.Path = userRootPath;
+ }
+
_userRootFolder = tmpItem;
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
index e2f2946db1..d30aaa133b 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
@@ -4,19 +4,26 @@ using MediaBrowser.Model.Entities;
using System;
using MediaBrowser.Controller.Entities;
using System.IO;
+using System.Linq;
+using MediaBrowser.Controller.Providers;
+using System.Collections.Generic;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
+using Emby.Naming.Video;
+using Emby.Naming.AudioBook;
namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
/// <summary>
/// Class AudioResolver
/// </summary>
- public class AudioResolver : ItemResolver<MediaBrowser.Controller.Entities.Audio.Audio>
+ public class AudioResolver : ItemResolver<MediaBrowser.Controller.Entities.Audio.Audio>, IMultiItemResolver
{
- private readonly ILibraryManager _libraryManager;
+ private readonly ILibraryManager LibraryManager;
public AudioResolver(ILibraryManager libraryManager)
{
- _libraryManager = libraryManager;
+ LibraryManager = libraryManager;
}
/// <summary>
@@ -25,7 +32,38 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// <value>The priority.</value>
public override ResolverPriority Priority
{
- get { return ResolverPriority.Last; }
+ get { return ResolverPriority.Fourth; }
+ }
+
+ public MultiItemResolverResult ResolveMultiple(Folder parent,
+ List<FileSystemMetadata> files,
+ string collectionType,
+ IDirectoryService directoryService)
+ {
+ var result = ResolveMultipleInternal(parent, files, collectionType, directoryService);
+
+ if (result != null)
+ {
+ foreach (var item in result.Items)
+ {
+ SetInitialItemValues((MediaBrowser.Controller.Entities.Audio.Audio)item, null);
+ }
+ }
+
+ return result;
+ }
+
+ private MultiItemResolverResult ResolveMultipleInternal(Folder parent,
+ List<FileSystemMetadata> files,
+ string collectionType,
+ IDirectoryService directoryService)
+ {
+ if (string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
+ {
+ return ResolveMultipleAudio<AudioBook>(parent, files, directoryService, false, collectionType, true);
+ }
+
+ return null;
}
/// <summary>
@@ -37,46 +75,199 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
// Return audio if the path is a file and has a matching extension
- if (!args.IsDirectory)
+ var libraryOptions = args.GetLibraryOptions();
+ var collectionType = args.GetCollectionType();
+
+ var isBooksCollectionType = string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase);
+
+ if (args.IsDirectory)
{
- var libraryOptions = args.GetLibraryOptions();
+ if (!isBooksCollectionType)
+ {
+ return null;
+ }
+
+ var files = args.FileSystemChildren
+ .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
+ .ToList();
- if (_libraryManager.IsAudioFile(args.Path, libraryOptions))
+ if (isBooksCollectionType)
{
- if (string.Equals(Path.GetExtension(args.Path), ".cue", StringComparison.OrdinalIgnoreCase))
- {
- // if audio file exists of same name, return null
+ return FindAudio<AudioBook>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
+ }
+
+ return null;
+ }
+
+ if (LibraryManager.IsAudioFile(args.Path, libraryOptions))
+ {
+ if (string.Equals(Path.GetExtension(args.Path), ".cue", StringComparison.OrdinalIgnoreCase))
+ {
+ // if audio file exists of same name, return null
+ return null;
+ }
+
+ var isMixedCollectionType = string.IsNullOrWhiteSpace(collectionType);
+
+ // For conflicting extensions, give priority to videos
+ if (isMixedCollectionType && LibraryManager.IsVideoFile(args.Path, libraryOptions))
+ {
+ return null;
+ }
+
+ MediaBrowser.Controller.Entities.Audio.Audio item = null;
+
+ var isMusicCollectionType = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
+
+ // Use regular audio type for mixed libraries, owned items and music
+ if (isMixedCollectionType ||
+ args.Parent == null ||
+ isMusicCollectionType)
+ {
+ item = new MediaBrowser.Controller.Entities.Audio.Audio();
+ }
+
+ else if (isBooksCollectionType)
+ {
+ item = new AudioBook();
+ }
+
+ if (item != null)
+ {
+ item.IsInMixedFolder = true;
+ }
+
+ return item;
+ }
+
+ return null;
+ }
- return null;
- }
+ private T FindAudio<T>(ItemResolveArgs args, string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool parseName)
+ where T : MediaBrowser.Controller.Entities.Audio.Audio, new()
+ {
+ var multiDiscFolders = new List<FileSystemMetadata>();
- var collectionType = args.GetCollectionType();
+ var libraryOptions = args.GetLibraryOptions();
+ var filesFromOtherItems = new List<FileSystemMetadata>();
- var isMixed = string.IsNullOrWhiteSpace(collectionType);
+ // TODO: Allow GetMultiDiscMovie in here
+ var supportsMultiVersion = false;
- // For conflicting extensions, give priority to videos
- if (isMixed && _libraryManager.IsVideoFile(args.Path, libraryOptions))
- {
- return null;
- }
+ var result = ResolveMultipleAudio<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType, parseName) ??
+ new MultiItemResolverResult();
- var isStandalone = args.Parent == null;
+ if (result.Items.Count == 1)
+ {
+ var videoPath = result.Items[0].Path;
- if (isStandalone ||
- string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) ||
- isMixed)
- {
- return new MediaBrowser.Controller.Entities.Audio.Audio();
- }
+ // If we were supporting this we'd be checking filesFromOtherItems
+ var hasOtherItems = false;
- if (string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
- {
- return new AudioBook();
- }
+ if (!hasOtherItems)
+ {
+ var item = (T)result.Items[0];
+ item.IsInMixedFolder = false;
+ item.Name = Path.GetFileName(item.ContainingFolderPath);
+ return item;
}
}
+ if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
+ {
+ //return GetMultiDiscAudio<T>(multiDiscFolders, directoryService);
+ }
+
return null;
}
+
+ private MultiItemResolverResult ResolveMultipleAudio<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions, string collectionType, bool parseName)
+ where T : MediaBrowser.Controller.Entities.Audio.Audio, new()
+ {
+ var files = new List<FileSystemMetadata>();
+ var items = new List<BaseItem>();
+ var leftOver = new List<FileSystemMetadata>();
+
+ // Loop through each child file/folder and see if we find a video
+ foreach (var child in fileSystemEntries)
+ {
+ if (child.IsDirectory)
+ {
+ leftOver.Add(child);
+ }
+ else if (IsIgnored(child.Name))
+ {
+
+ }
+ else
+ {
+ files.Add(child);
+ }
+ }
+
+ var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
+
+ var resolver = new AudioBookListResolver(namingOptions);
+ var resolverResult = resolver.Resolve(files).ToList();
+
+ var result = new MultiItemResolverResult
+ {
+ ExtraFiles = leftOver,
+ Items = items
+ };
+
+ var isInMixedFolder = resolverResult.Count > 1 || (parent != null && parent.IsTopParent);
+
+ foreach (var resolvedItem in resolverResult)
+ {
+ if (resolvedItem.Files.Count > 1)
+ {
+ // For now, until we sort out naming for multi-part books
+ continue;
+ }
+
+ var firstMedia = resolvedItem.Files.First();
+
+ var libraryItem = new T
+ {
+ Path = firstMedia.Path,
+ IsInMixedFolder = isInMixedFolder,
+ ProductionYear = resolvedItem.Year,
+ Name = parseName ?
+ resolvedItem.Name :
+ Path.GetFileNameWithoutExtension(firstMedia.Path),
+ //AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(),
+ //LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray()
+ };
+
+ result.Items.Add(libraryItem);
+ }
+
+ result.ExtraFiles.AddRange(files.Where(i => !ContainsFile(resolverResult, i)));
+
+ return result;
+ }
+
+ private bool ContainsFile(List<AudioBookInfo> result, FileSystemMetadata file)
+ {
+ return result.Any(i => ContainsFile(i, file));
+ }
+
+ private bool ContainsFile(AudioBookInfo result, FileSystemMetadata file)
+ {
+ return result.Files.Any(i => ContainsFile(i, file)) ||
+ result.AlternateVersions.Any(i => ContainsFile(i, file)) ||
+ result.Extras.Any(i => ContainsFile(i, file));
+ }
+
+ private bool ContainsFile(AudioBookFileInfo result, FileSystemMetadata file)
+ {
+ return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase);
+ }
+
+ private bool IsIgnored(string filename)
+ {
+ return false;
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index e3200a0995..7e960f85e6 100644
--- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -274,7 +274,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return false;
}
- return FileSystem.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
+ return directoryService.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
}
/// <summary>
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index d69a2b2404..6676164142 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -202,14 +202,14 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
var collectionType = args.GetCollectionType();
- if (IsInvalid(args.Parent, collectionType))
- {
- return null;
- }
-
// Find movies with their own folders
if (args.IsDirectory)
{
+ if (IsInvalid(args.Parent, collectionType))
+ {
+ return null;
+ }
+
var files = args.FileSystemChildren
.Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
.ToList();
@@ -251,9 +251,14 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return null;
}
- // Owned items will be caught by the plain video resolver
+ // Handle owned items
if (args.Parent == null)
{
+ return base.Resolve(args);
+ }
+
+ if (IsInvalid(args.Parent, collectionType))
+ {
return null;
}
@@ -528,6 +533,15 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return returnVideo;
}
+ private string[] ValidCollectionTypes = new[]
+ {
+ CollectionType.Movies,
+ CollectionType.HomeVideos,
+ CollectionType.MusicVideos,
+ CollectionType.Movies,
+ CollectionType.Photos
+ };
+
private bool IsInvalid(Folder parent, string collectionType)
{
if (parent != null)
@@ -538,21 +552,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
}
}
- var validCollectionTypes = new[]
- {
- CollectionType.Movies,
- CollectionType.HomeVideos,
- CollectionType.MusicVideos,
- CollectionType.Movies,
- CollectionType.Photos
- };
-
if (string.IsNullOrWhiteSpace(collectionType))
{
return false;
}
- return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
+ return !ValidCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
}
private IImageProcessor _imageProcessor;
diff --git a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
index 5c7a528f54..030ff88f7d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
@@ -5,36 +5,6 @@ using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library.Resolvers
{
- /// <summary>
- /// Resolves a Path into a Video
- /// </summary>
- public class VideoResolver : BaseVideoResolver<Video>
- {
- protected override Video Resolve(ItemResolveArgs args)
- {
- if (args.Parent != null)
- {
- // The movie resolver will handle this
- return null;
- }
-
- return base.Resolve(args);
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.Last; }
- }
-
- public VideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
- {
- }
- }
-
public class GenericVideoResolver<T> : BaseVideoResolver<T>
where T : Video, new ()
{
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index be5e57539b..9992c71ecf 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -1052,10 +1052,27 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
_liveStreamsSemaphore.Release();
}
+ }
+
+ public async Task<List<ILiveStream>> GetLiveStreams(TunerHostInfo host, CancellationToken cancellationToken)
+ {
+ //await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+ //try
+ //{
+ var hostId = host.Id;
+
+ return _liveStreams
+ .Where(i => string.Equals(i.TunerHostId, hostId, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+ //}
+ //finally
+ //{
+ // _liveStreamsSemaphore.Release();
+ //}
}
- private async Task<Tuple<ILiveStream, MediaSourceInfo, ITunerHost>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
+ private async Task<Tuple<ILiveStream, MediaSourceInfo>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
{
_logger.Info("Streaming Channel " + channelId);
@@ -1072,7 +1089,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount);
- return new Tuple<ILiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, result.TunerHost);
+ return new Tuple<ILiveStream, MediaSourceInfo>(result, openedMediaSource);
}
foreach (var hostInstance in _liveTvManager.TunerHosts)
@@ -1086,13 +1103,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
result.SharedStreamIds.Add(openedMediaSource.Id);
_liveStreams.Add(result);
- result.TunerHost = hostInstance;
result.OriginalStreamId = streamId;
_logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}",
streamId, openedMediaSource.Id, openedMediaSource.LiveStreamId);
- return new Tuple<ILiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, hostInstance);
+ return new Tuple<ILiveStream, MediaSourceInfo>(result, openedMediaSource);
}
catch (FileNotFoundException)
{
@@ -2445,6 +2461,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
existingTimer.Status = RecordingStatus.Cancelled;
}
+ else if (!existingTimer.IsManual)
+ {
+ existingTimer.Status = RecordingStatus.New;
+ }
if (existingTimer.Status != RecordingStatus.Cancelled)
{
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 718620ab57..7e72d1b1a1 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1232,6 +1232,8 @@ namespace Emby.Server.Implementations.LiveTv
var newChannelIdList = new List<Guid>();
var newProgramIdList = new List<Guid>();
+ var cleanDatabase = true;
+
foreach (var service in _services)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -1254,6 +1256,7 @@ namespace Emby.Server.Implementations.LiveTv
}
catch (Exception ex)
{
+ cleanDatabase = false;
_logger.ErrorException("Error refreshing channels for service", ex);
}
@@ -1264,8 +1267,11 @@ namespace Emby.Server.Implementations.LiveTv
progress.Report(100 * percent);
}
- await CleanDatabaseInternal(newChannelIdList.ToArray(), new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
- await CleanDatabaseInternal(newProgramIdList.ToArray(), new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
+ if (cleanDatabase)
+ {
+ await CleanDatabaseInternal(newChannelIdList.ToArray(), new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
+ await CleanDatabaseInternal(newProgramIdList.ToArray(), new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
+ }
var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault();
@@ -1291,8 +1297,9 @@ namespace Emby.Server.Implementations.LiveTv
{
progress.Report(10);
- var allChannels = await GetChannels(service, cancellationToken).ConfigureAwait(false);
- var allChannelsList = allChannels.ToList();
+ var allChannelsList = (await service.GetChannelsAsync(cancellationToken).ConfigureAwait(false))
+ .Select(i => new Tuple<string, ChannelInfo>(service.Name, i))
+ .ToList();
var list = new List<LiveTvChannel>();
@@ -1507,13 +1514,6 @@ namespace Emby.Server.Implementations.LiveTv
return 7;
}
- private async Task<IEnumerable<Tuple<string, ChannelInfo>>> GetChannels(ILiveTvService service, CancellationToken cancellationToken)
- {
- var channels = await service.GetChannelsAsync(cancellationToken).ConfigureAwait(false);
-
- return channels.Select(i => new Tuple<string, ChannelInfo>(service.Name, i));
- }
-
private DateTime _lastRecordingRefreshTime;
private async Task RefreshRecordings(Guid internalLiveTvFolderId, CancellationToken cancellationToken)
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 59346cdec2..74758e906c 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -105,7 +105,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private class HdHomerunChannelInfo : ChannelInfo
{
public bool IsLegacyTuner { get; set; }
- public string Url { get; set; }
}
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
@@ -124,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
VideoCodec = i.VideoCodec,
ChannelType = ChannelType.TV,
IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase),
- Url = i.URL
+ Path = i.URL
}).Cast<ChannelInfo>().ToList();
}
@@ -148,7 +147,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
using (var response = await _httpClient.SendAsync(new HttpRequestOptions()
{
- Url = string.Format("{0}/discover.json", GetApiUrl(info, false)),
+ Url = string.Format("{0}/discover.json", GetApiUrl(info)),
CancellationToken = cancellationToken,
TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds),
BufferContent = false
@@ -195,13 +194,80 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- private async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken)
+ private async Task<List<LiveTvTunerInfo>> GetTunerInfosHttp(TunerHostInfo info, CancellationToken cancellationToken)
+ {
+ var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
+
+ using (var stream = await _httpClient.Get(new HttpRequestOptions()
+ {
+ Url = string.Format("{0}/tuners.html", GetApiUrl(info)),
+ CancellationToken = cancellationToken,
+ TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds),
+ BufferContent = false
+ }))
+ {
+ var tuners = new List<LiveTvTunerInfo>();
+ using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8))
+ {
+ while (!sr.EndOfStream)
+ {
+ string line = StripXML(sr.ReadLine());
+ if (line.Contains("Channel"))
+ {
+ LiveTvTunerStatus status;
+ var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
+ var name = line.Substring(0, index - 1);
+ var currentChannel = line.Substring(index + 7);
+ if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; }
+ tuners.Add(new LiveTvTunerInfo
+ {
+ Name = name,
+ SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
+ ProgramName = currentChannel,
+ Status = status
+ });
+ }
+ }
+ }
+ return tuners;
+ }
+ }
+
+ private static string StripXML(string source)
+ {
+ char[] buffer = new char[source.Length];
+ int bufferIndex = 0;
+ bool inside = false;
+
+ for (int i = 0; i < source.Length; i++)
+ {
+ char let = source[i];
+ if (let == '<')
+ {
+ inside = true;
+ continue;
+ }
+ if (let == '>')
+ {
+ inside = false;
+ continue;
+ }
+ if (!inside)
+ {
+ buffer[bufferIndex] = let;
+ bufferIndex++;
+ }
+ }
+ return new string(buffer, 0, bufferIndex);
+ }
+
+ private async Task<List<LiveTvTunerInfo>> GetTunerInfosUdp(TunerHostInfo info, CancellationToken cancellationToken)
{
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
var tuners = new List<LiveTvTunerInfo>();
- var uri = new Uri(GetApiUrl(info, false));
+ var uri = new Uri(GetApiUrl(info));
using (var manager = new HdHomerunManager(_socketFactory, Logger))
{
@@ -246,7 +312,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return list;
}
- private string GetApiUrl(TunerHostInfo info, bool isPlayback)
+ public async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken)
+ {
+ // TODO Need faster way to determine UDP vs HTTP
+ var channels = await GetChannels(info, true, cancellationToken);
+
+ var hdHomerunChannelInfo = channels.FirstOrDefault() as HdHomerunChannelInfo;
+
+ if (hdHomerunChannelInfo == null || hdHomerunChannelInfo.IsLegacyTuner)
+ {
+ return await GetTunerInfosUdp(info, cancellationToken).ConfigureAwait(false);
+ }
+
+ return await GetTunerInfosHttp(info, cancellationToken).ConfigureAwait(false);
+ }
+
+ private string GetApiUrl(TunerHostInfo info)
{
var url = info.Url;
@@ -260,16 +341,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
url = "http://" + url;
}
- var uri = new Uri(url);
-
- if (isPlayback)
- {
- var builder = new UriBuilder(uri);
- builder.Port = 5004;
- uri = builder.Uri;
- }
-
- return uri.AbsoluteUri.TrimEnd('/');
+ return new Uri(url).AbsoluteUri.TrimEnd('/');
}
private class Channels
@@ -392,7 +464,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
nal = "0";
}
- var url = GetApiUrl(info, false);
+ var url = GetApiUrl(info);
var id = profile;
if (string.IsNullOrWhiteSpace(id))
@@ -526,7 +598,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
{
- return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
+ return new HdHomerunUdpStream(mediaSource, info, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Path), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
}
// The UDP method is not working reliably on OSX, and on BSD it hasn't been tested yet
@@ -537,7 +609,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
mediaSource.Protocol = MediaProtocol.Http;
- var httpUrl = GetApiUrl(info, true) + "/auto/v" + hdhrId;
+ var httpUrl = channelInfo.Path;
// If raw was used, the tuner doesn't support params
if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
@@ -546,10 +618,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
mediaSource.Path = httpUrl;
- return new HdHomerunHttpStream(mediaSource, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment);
+ return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment);
}
- return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
+ return new HdHomerunUdpStream(mediaSource, info, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
}
public async Task Validate(TunerHostInfo info)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 06326d26c6..6e93055be0 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -11,6 +11,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
+using MediaBrowser.Model.LiveTv;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
@@ -23,8 +24,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private readonly int _numTuners;
private readonly INetworkManager _networkManager;
- public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment)
- : base(mediaSource, environment, fileSystem, logger, appPaths)
+ public HdHomerunUdpStream(MediaSourceInfo mediaSource, TunerHostInfo tunerHostInfo, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment)
+ : base(mediaSource, tunerHostInfo, environment, fileSystem, logger, appPaths)
{
_appHost = appHost;
_socketFactory = socketFactory;
@@ -32,6 +33,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
OriginalStreamId = originalStreamId;
_channelCommands = channelCommands;
_numTuners = numTuners;
+ EnableStreamSharing = true;
}
public override async Task Open(CancellationToken openCancellationToken)
@@ -105,9 +107,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await taskCompletionSource.Task.ConfigureAwait(false);
}
- public override void Close()
+ protected override void CloseInternal()
{
- Logger.Info("Closing HDHR UDP live stream");
LiveStreamCancellationTokenSource.Cancel();
}
@@ -134,6 +135,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
openTaskCompletionSource.TrySetException(ex);
}
+ EnableStreamSharing = false;
+
try
{
await hdHomerunManager.StopStreaming().ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
index 8620987355..f6758e94e2 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
+using MediaBrowser.Model.LiveTv;
namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
@@ -21,7 +22,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
get { return SharedStreamIds.Count; }
}
- public ITunerHost TunerHost { get; set; }
+
public string OriginalStreamId { get; set; }
public bool EnableStreamSharing { get; set; }
public string UniqueId { get; private set; }
@@ -29,12 +30,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public List<string> SharedStreamIds { get; private set; }
protected readonly IEnvironmentInfo Environment;
protected readonly IFileSystem FileSystem;
+ protected readonly IServerApplicationPaths AppPaths;
- protected readonly string TempFilePath;
+ protected string TempFilePath;
protected readonly ILogger Logger;
protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource();
- public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths)
+ public string TunerHostId { get; private set; }
+
+ public LiveStream(MediaSourceInfo mediaSource, TunerHostInfo tuner, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths)
{
OriginalMediaSource = mediaSource;
Environment = environment;
@@ -44,7 +48,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
EnableStreamSharing = true;
SharedStreamIds = new List<string>();
UniqueId = Guid.NewGuid().ToString("N");
- TempFilePath = Path.Combine(appPaths.GetTranscodingTempPath(), UniqueId + ".ts");
+ TunerHostId = tuner.Id;
+
+ AppPaths = appPaths;
+
+ SetTempFilePath("ts");
+ }
+
+ protected void SetTempFilePath(string extension)
+ {
+ TempFilePath = Path.Combine(AppPaths.GetTranscodingTempPath(), UniqueId + "." + extension);
}
public virtual Task Open(CancellationToken openCancellationToken)
@@ -52,7 +65,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return Task.FromResult(true);
}
- public virtual void Close()
+ public void Close()
+ {
+ EnableStreamSharing = false;
+
+ Logger.Info("Closing " + GetType().Name);
+
+ CloseInternal();
+ }
+
+ protected virtual void CloseInternal()
{
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 9fc6687d14..c96d1f3592 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -77,10 +77,28 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
{
+ var tunerCount = info.TunerCount;
+
+ if (tunerCount > 0)
+ {
+ var liveStreams = await EmbyTV.EmbyTV.Current.GetLiveStreams(info, cancellationToken).ConfigureAwait(false);
+
+ if (liveStreams.Count >= info.TunerCount)
+ {
+ throw new LiveTvConflictException();
+ }
+ }
+
var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false);
- var liveStream = new LiveStream(sources.First(), _environment, FileSystem, Logger, Config.ApplicationPaths);
- return liveStream;
+ var mediaSource = sources.First();
+
+ if (mediaSource.Protocol == MediaProtocol.Http && !mediaSource.RequiresLooping)
+ {
+ return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment);
+ }
+
+ return new LiveStream(mediaSource, info, _environment, FileSystem, Logger, Config.ApplicationPaths);
}
public async Task Validate(TunerHostInfo info)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index 7e0e5fc5c9..cc2cb3e5ee 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -14,20 +14,22 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
using System.Globalization;
using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.LiveTv;
-namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
+namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
- public class HdHomerunHttpStream : LiveStream, IDirectStreamProvider
+ public class SharedHttpStream : LiveStream, IDirectStreamProvider
{
private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost;
- public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment)
- : base(mediaSource, environment, fileSystem, logger, appPaths)
+ public SharedHttpStream(MediaSourceInfo mediaSource, TunerHostInfo tunerHostInfo, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment)
+ : base(mediaSource, tunerHostInfo, environment, fileSystem, logger, appPaths)
{
_httpClient = httpClient;
_appHost = appHost;
OriginalStreamId = originalStreamId;
+ EnableStreamSharing = true;
}
public override async Task Open(CancellationToken openCancellationToken)
@@ -40,7 +42,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath));
- Logger.Info("Opening HDHR Live stream from {0}", url);
+ var typeName = GetType().Name;
+ Logger.Info("Opening " + typeName + " Live stream from {0}", url);
var response = await _httpClient.SendAsync(new HttpRequestOptions
{
@@ -51,13 +54,41 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// Increase a little bit
TimeoutMs = 30000,
- EnableHttpCompression = false
+ EnableHttpCompression = false,
+
+ LogResponse = true,
+ LogResponseHeaders = true
}, "GET").ConfigureAwait(false);
- Logger.Info("Opened HDHR stream from {0}", url);
+ var extension = "ts";
+ var requiresRemux = false;
+
+ var contentType = response.ContentType ?? string.Empty;
+ if (contentType.IndexOf("matroska", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ requiresRemux = true;
+ }
+ else if (contentType.IndexOf("mp4", StringComparison.OrdinalIgnoreCase) != -1 ||
+ contentType.IndexOf("dash", StringComparison.OrdinalIgnoreCase) != -1 ||
+ contentType.IndexOf("mpegURL", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ requiresRemux = true;
+ }
+
+ // Close the stream without any sharing features
+ if (requiresRemux)
+ {
+ using (response)
+ {
+ return;
+ }
+ }
+
+ SetTempFilePath(extension);
- StartStreaming(response, LiveStreamCancellationTokenSource.Token);
+ var taskCompletionSource = new TaskCompletionSource<bool>();
+ StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
//OpenedMediaSource.Protocol = MediaProtocol.File;
//OpenedMediaSource.Path = tempFile;
@@ -66,20 +97,28 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
OpenedMediaSource.Protocol = MediaProtocol.Http;
+ if (OpenedMediaSource.SupportsProbing)
+ {
+ await Task.Delay(3000).ConfigureAwait(false);
+ }
+
+ //OpenedMediaSource.Path = TempFilePath;
+ //OpenedMediaSource.Protocol = MediaProtocol.File;
+
//OpenedMediaSource.Path = _tempFilePath;
//OpenedMediaSource.Protocol = MediaProtocol.File;
//OpenedMediaSource.SupportsDirectPlay = false;
//OpenedMediaSource.SupportsDirectStream = true;
//OpenedMediaSource.SupportsTranscoding = true;
+ await taskCompletionSource.Task.ConfigureAwait(false);
}
- public override void Close()
+ protected override void CloseInternal()
{
- Logger.Info("Closing HDHR live stream");
LiveStreamCancellationTokenSource.Cancel();
}
- private Task StartStreaming(HttpResponseInfo response, CancellationToken cancellationToken)
+ private Task StartStreaming(HttpResponseInfo response, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
return Task.Run(async () =>
{
@@ -89,12 +128,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
using (var stream = response.Content)
{
- Logger.Info("Beginning HdHomerunHttpStream stream to file");
+ Logger.Info("Beginning {0} stream to {1}", GetType().Name, TempFilePath);
- FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath));
using (var fileStream = FileSystem.GetFileStream(TempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None))
{
- StreamHelper.CopyTo(stream, fileStream, 81920, null, cancellationToken);
+ StreamHelper.CopyTo(stream, fileStream, 81920, () => Resolve(openTaskCompletionSource), cancellationToken);
}
}
}
@@ -106,17 +144,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
Logger.ErrorException("Error copying live stream.", ex);
}
-
+ EnableStreamSharing = false;
await DeleteTempFile(TempFilePath).ConfigureAwait(false);
});
}
private void Resolve(TaskCompletionSource<bool> openTaskCompletionSource)
{
- Task.Run(() =>
- {
- openTaskCompletionSource.TrySetResult(true);
- });
+ openTaskCompletionSource.TrySetResult(true);
}
}
}
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index 0c2ab1f6d8..54200605dd 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -87,10 +87,5 @@
"User": "\u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645",
"System": "\u0627\u0644\u0646\u0638\u0627\u0645",
"Application": "\u0627\u0644\u062a\u0637\u0628\u064a\u0642",
- "Plugin": "\u0627\u0644\u0645\u0644\u062d\u0642",
- "LabelExit": "\u062e\u0631\u0648\u062c",
- "LabelVisitCommunity": "\u0632\u064a\u0627\u0631\u0629 \u0627\u0644\u0645\u062c\u062a\u0645\u0639",
- "LabelBrowseLibrary": "\u062a\u0635\u0641\u062d \u0627\u0644\u0645\u0643\u062a\u0628\u0629",
- "LabelConfigureServer": "\u0636\u0628\u0637 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0623\u0645\u0628\u064a",
- "LabelRestartServer": "\u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u062e\u0627\u062f\u0645"
+ "Plugin": "\u0627\u0644\u0645\u0644\u062d\u0642"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json
index 40899caabf..02c03f5781 100644
--- a/Emby.Server.Implementations/Localization/Core/bg-BG.json
+++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json
@@ -1,12 +1,12 @@
{
"Latest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438",
"ValueSpecialEpisodeName": "\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u043d\u0438 - {0}",
- "Inherit": "Inherit",
+ "Inherit": "\u041d\u0430\u0441\u043b\u0435\u0434\u044f\u0432\u0430\u043d\u0435",
"Books": "\u041a\u043d\u0438\u0433\u0438",
"Music": "\u041c\u0443\u0437\u0438\u043a\u0430",
"Games": "\u0418\u0433\u0440\u0438",
"Photos": "\u0421\u043d\u0438\u043c\u043a\u0438",
- "MixedContent": "Mixed content",
+ "MixedContent": "\u0421\u043c\u0435\u0441\u0435\u043d\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435",
"MusicVideos": "\u041c\u0443\u0437\u0438\u043a\u0430\u043b\u043d\u0438 \u043a\u043b\u0438\u043f\u043e\u0432\u0435",
"HomeVideos": "\u0414\u043e\u043c\u0430\u0448\u043d\u0438 \u043a\u043b\u0438\u043f\u043e\u0432\u0435",
"Playlists": "\u0421\u043f\u0438\u0441\u044a\u0446\u0438",
@@ -17,8 +17,8 @@
"HeaderAlbumArtists": "\u0418\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u043d\u0430 \u0430\u043b\u0431\u0443\u043c\u0438",
"HeaderFavoriteAlbums": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0430\u043b\u0431\u0443\u043c\u0438",
"HeaderFavoriteEpisodes": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0435\u043f\u0438\u0437\u043e\u0434\u0438",
- "HeaderFavoriteShows": "Favorite Shows",
- "HeaderNextUp": "Next Up",
+ "HeaderFavoriteShows": "\u041b\u044e\u0431\u0438\u043c\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438",
+ "HeaderNextUp": "\u0421\u043b\u0435\u0434\u0432\u0430",
"Favorites": "\u041b\u044e\u0431\u0438\u043c\u0438",
"Collections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0438\u0438",
"Channels": "\u041a\u0430\u043d\u0430\u043b\u0438",
@@ -27,70 +27,65 @@
"Artists": "\u0418\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438",
"Folders": "\u041f\u0430\u043f\u043a\u0438",
"Songs": "\u041f\u0435\u0441\u043d\u0438",
- "TvShows": "TV Shows",
+ "TvShows": "\u0422\u0435\u043b\u0435\u0432\u0438\u0437\u0438\u043e\u043d\u043d\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438",
"Shows": "\u0421\u0435\u0440\u0438\u0430\u043b\u0438",
"Genres": "\u0416\u0430\u043d\u0440\u043e\u0432\u0435",
"NameSeasonNumber": "\u0421\u0435\u0437\u043e\u043d {0}",
- "AppDeviceValues": "App: {0}, Device: {1}",
+ "AppDeviceValues": "\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0430: {0}, \u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e: {1}",
"UserDownloadingItemWithValues": "{0} is downloading {1}",
- "HeaderLiveTV": "Live TV",
- "ChapterNameValue": "Chapter {0}",
- "ScheduledTaskFailedWithName": "{0} failed",
+ "HeaderLiveTV": "\u0422\u0435\u043b\u0435\u0432\u0438\u0437\u0438\u044f \u043d\u0430 \u0436\u0438\u0432\u043e",
+ "ChapterNameValue": "\u0413\u043b\u0430\u0432\u0430 {0}",
+ "ScheduledTaskFailedWithName": "{0} \u0441\u0435 \u043f\u0440\u043e\u0432\u0430\u043b\u0438",
"LabelRunningTimeValue": "Running time: {0}",
"ScheduledTaskStartedWithName": "{0} \u0437\u0430\u043f\u043e\u0447\u043d\u0430",
- "VersionNumber": "Version {0}",
- "PluginInstalledWithName": "{0} was installed",
- "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly.",
- "PluginUpdatedWithName": "{0} was updated",
+ "VersionNumber": "\u0412\u0435\u0440\u0441\u0438\u044f {0}",
+ "PluginInstalledWithName": "{0} \u0435 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u043e",
+ "StartupEmbyServerIsLoading": "\u0421\u044a\u0440\u0432\u044a\u0440\u044a\u0442 \u0437\u0430\u0440\u0435\u0436\u0434\u0430. \u041c\u043e\u043b\u044f, \u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e \u0441\u043b\u0435\u0434 \u043c\u0430\u043b\u043a\u043e.",
+ "PluginUpdatedWithName": "{0} \u0435 \u043e\u0431\u043d\u043e\u0432\u0435\u043d\u043e",
"PluginUninstalledWithName": "{0} \u0435 \u0434\u0435\u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u043e",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
- "LabelIpAddressValue": "Ip address: {0}",
- "DeviceOnlineWithName": "{0} is connected",
- "UserOnlineFromDevice": "{0} is online from {1}",
- "ProviderValue": "Provider: {0}",
- "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
- "UserCreatedWithName": "User {0} has been created",
- "UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserDeletedWithName": "User {0} has been deleted",
+ "ItemAddedWithName": "{0} \u0435 \u0434\u043e\u0431\u0430\u0432\u0435\u043d\u043e \u043a\u044a\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0442\u0430",
+ "ItemRemovedWithName": "{0} \u0435 \u043f\u0440\u0435\u043c\u0430\u0445\u043d\u0430\u0442\u043e \u043e\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0442\u0430",
+ "LabelIpAddressValue": "\u0418\u041f \u0430\u0434\u0440\u0435\u0441: {0}",
+ "DeviceOnlineWithName": "{0} \u0435 \u0441\u0432\u044a\u0440\u0437\u0430\u043d",
+ "UserOnlineFromDevice": "{0} \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f \u043e\u0442 {1}",
+ "ProviderValue": "\u0414\u043e\u0441\u0442\u0430\u0432\u0447\u0438\u043a: {0}",
+ "SubtitlesDownloadedForItem": "\u0418\u0437\u0442\u0435\u0433\u043b\u0435\u043d\u0438 \u0441\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438 \u0437\u0430 {0}",
+ "UserCreatedWithName": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u0442 {0} \u0435 \u0441\u044a\u0437\u0434\u0430\u0434\u0435\u043d",
+ "UserPasswordChangedWithName": "\u041f\u0430\u0440\u043e\u043b\u0430\u0442\u0430 \u043d\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f {0} \u0435 \u043f\u0440\u043e\u043c\u0435\u043d\u0435\u043d\u0430",
+ "UserDeletedWithName": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u0442 {0} \u0435 \u0438\u0437\u0442\u0440\u0438\u0442",
"UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
"MessageServerConfigurationUpdated": "Server configuration has been updated",
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageApplicationUpdated": "Emby Server has been updated",
+ "MessageApplicationUpdated": "\u0421\u044a\u0440\u0432\u044a\u0440\u044a\u0442 \u0435 \u043e\u0431\u043d\u043e\u0432\u0435\u043d",
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
- "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
- "UserOfflineFromDevice": "{0} has disconnected from {1}",
- "DeviceOfflineWithName": "{0} has disconnected",
+ "AuthenticationSucceededWithUserName": "{0} \u0441\u0435 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e",
+ "UserOfflineFromDevice": "{0} \u0441\u0435 \u0440\u0430\u0437\u043a\u0430\u0447\u0438 \u043e\u0442 {1}",
+ "DeviceOfflineWithName": "{0} \u0441\u0435 \u0440\u0430\u0437\u043a\u0430\u0447\u0438",
"UserStartedPlayingItemWithValues": "{0} has started playing {1}",
"UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
- "NotificationOptionPluginError": "Plugin failure",
- "NotificationOptionApplicationUpdateAvailable": "Application update available",
- "NotificationOptionApplicationUpdateInstalled": "Application update installed",
+ "NotificationOptionPluginError": "\u0413\u0440\u0435\u0448\u043a\u0430 \u0432 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430",
+ "NotificationOptionApplicationUpdateAvailable": "\u041d\u0430\u043b\u0438\u0447\u043d\u043e \u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0430\u0442\u0430",
+ "NotificationOptionApplicationUpdateInstalled": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u0442\u043e \u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0430\u0442\u0430 \u0435 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u043e",
"NotificationOptionPluginUpdateInstalled": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u0442\u043e \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430\u0442\u0430 \u0435 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u043e",
"NotificationOptionPluginInstalled": "\u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430\u0442\u0430 \u0435 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0430",
"NotificationOptionPluginUninstalled": "\u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430\u0442\u0430 \u0435 \u0434\u0435\u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0430",
- "NotificationOptionVideoPlayback": "Video playback started",
- "NotificationOptionAudioPlayback": "Audio playback started",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
- "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
- "NotificationOptionTaskFailed": "Scheduled task failure",
- "NotificationOptionInstallationFailed": "Installation failure",
- "NotificationOptionNewLibraryContent": "New content added",
- "NotificationOptionCameraImageUploaded": "Camera image uploaded",
+ "NotificationOptionVideoPlayback": "\u0412\u044a\u0437\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u0438\u0434\u0435\u043e \u0437\u0430\u043f\u043e\u0447\u043d\u0430",
+ "NotificationOptionAudioPlayback": "\u0412\u044a\u0437\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0437\u0432\u0443\u043a \u0437\u0430\u043f\u043e\u0447\u043d\u0430",
+ "NotificationOptionGamePlayback": "\u0412\u044a\u0437\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0438\u0433\u0440\u0430\u0442\u0430 \u0437\u0430\u043f\u043e\u0447\u043d\u0430",
+ "NotificationOptionVideoPlaybackStopped": "\u0412\u044a\u0437\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u0438\u0434\u0435\u043e \u0435 \u0441\u043f\u0440\u044f\u043d\u043e",
+ "NotificationOptionAudioPlaybackStopped": "\u0412\u044a\u0437\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0437\u0432\u0443\u043a \u0435 \u0441\u043f\u0440\u044f\u043d\u043e",
+ "NotificationOptionGamePlaybackStopped": "\u0412\u044a\u0437\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0438\u0433\u0440\u0430\u0442\u0430 \u0435 \u0441\u043f\u0440\u044f\u043d\u0430",
+ "NotificationOptionTaskFailed": "\u0413\u0440\u0435\u0448\u043a\u0430 \u0432 \u043f\u043b\u0430\u043d\u0438\u0440\u0430\u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430",
+ "NotificationOptionInstallationFailed": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435",
+ "NotificationOptionNewLibraryContent": "\u0414\u043e\u0431\u0430\u0432\u0435\u043d\u043e \u0435 \u043d\u043e\u0432\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435",
+ "NotificationOptionCameraImageUploaded": "\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u0442\u043e \u043e\u0442 \u0444\u043e\u0442\u043e\u0430\u043f\u0430\u0440\u0430\u0442\u0430 \u0435 \u043a\u0430\u0447\u0435\u043d\u043e",
"NotificationOptionUserLockedOut": "User locked out",
"NotificationOptionServerRestartRequired": "\u041d\u0443\u0436\u043d\u043e \u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0440\u0432\u044a\u0440\u0430",
"UserLockedOutWithName": "User {0} has been locked out",
- "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
+ "SubtitleDownloadFailureForItem": "\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435 \u043d\u0430 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0438 \u0437\u0430 {0}",
"Sync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0430\u043d\u0435",
"User": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b",
"System": "\u0421\u0438\u0441\u0442\u0435\u043c\u0430",
- "Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "\u041f\u043e\u0441\u0435\u0442\u0435\u0442\u0435 \u043e\u0431\u0449\u043d\u043e\u0441\u0442\u0442\u0430",
- "LabelBrowseLibrary": "\u0420\u0430\u0437\u0433\u043b\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0442\u0430",
- "LabelConfigureServer": "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0415\u043c\u0431\u0438",
- "LabelRestartServer": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0440\u0432\u044a\u0440\u0430"
+ "Application": "\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0430",
+ "Plugin": "\u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/ca.json b/Emby.Server.Implementations/Localization/Core/ca.json
index cc2c00234f..f21a0b2953 100644
--- a/Emby.Server.Implementations/Localization/Core/ca.json
+++ b/Emby.Server.Implementations/Localization/Core/ca.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/cs.json b/Emby.Server.Implementations/Localization/Core/cs.json
index abbfde3800..d59e40ed35 100644
--- a/Emby.Server.Implementations/Localization/Core/cs.json
+++ b/Emby.Server.Implementations/Localization/Core/cs.json
@@ -27,7 +27,7 @@
"Artists": "Um\u011blci",
"Folders": "Slo\u017eky",
"Songs": "Skladby",
- "TvShows": "TV Shows",
+ "TvShows": "TV seri\u00e1ly",
"Shows": "Seri\u00e1ly",
"Genres": "\u017d\u00e1nry",
"NameSeasonNumber": "Sez\u00f3na {0}",
@@ -87,10 +87,5 @@
"User": "U\u017eivatel",
"System": "Syst\u00e9m",
"Application": "Aplikace",
- "Plugin": "Z\u00e1suvn\u00fd modul",
- "LabelExit": "Uko\u010dit",
- "LabelVisitCommunity": "Nav\u0161t\u00edvit komunitu",
- "LabelBrowseLibrary": "Proch\u00e1zet knihovnu",
- "LabelConfigureServer": "Konfigurovat Emby",
- "LabelRestartServer": "Restartovat Server"
+ "Plugin": "Z\u00e1suvn\u00fd modul"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index ed9652c33d..eb05943f94 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -87,10 +87,5 @@
"User": "Bruger",
"System": "System",
"Application": "Applikation",
- "Plugin": "Plugin",
- "LabelExit": "Afslut",
- "LabelVisitCommunity": "Bes\u00f8g F\u00e6llesskab",
- "LabelBrowseLibrary": "Gennemse Bibliotek",
- "LabelConfigureServer": "Konfigurer Emby",
- "LabelRestartServer": "Genstart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json
index 183b4aaf8a..7bab689ebb 100644
--- a/Emby.Server.Implementations/Localization/Core/de.json
+++ b/Emby.Server.Implementations/Localization/Core/de.json
@@ -87,10 +87,5 @@
"User": "Benutzer",
"System": "System",
"Application": "Anwendung",
- "Plugin": "Plugin",
- "LabelExit": "Beenden",
- "LabelVisitCommunity": "Besuche die Community",
- "LabelBrowseLibrary": "Bibliothek durchsuchen",
- "LabelConfigureServer": "Konfiguriere Emby",
- "LabelRestartServer": "Server neustarten"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/en-GB.json b/Emby.Server.Implementations/Localization/Core/en-GB.json
index 8dc9abf012..62db5a358a 100644
--- a/Emby.Server.Implementations/Localization/Core/en-GB.json
+++ b/Emby.Server.Implementations/Localization/Core/en-GB.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json
index e4a49abf64..c48042d9a3 100644
--- a/Emby.Server.Implementations/Localization/Core/es-AR.json
+++ b/Emby.Server.Implementations/Localization/Core/es-AR.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json
index 45cc2c69b2..2cc1dd759d 100644
--- a/Emby.Server.Implementations/Localization/Core/es-MX.json
+++ b/Emby.Server.Implementations/Localization/Core/es-MX.json
@@ -27,7 +27,7 @@
"Artists": "Artistas",
"Folders": "Carpetas",
"Songs": "Canciones",
- "TvShows": "TV Shows",
+ "TvShows": "Programas de TV",
"Shows": "Programas",
"Genres": "G\u00e9neros",
"NameSeasonNumber": "Temporada {0}",
@@ -87,10 +87,5 @@
"User": "Usuario",
"System": "Sistema",
"Application": "Aplicaci\u00f3n",
- "Plugin": "Complemento",
- "LabelExit": "Salir",
- "LabelVisitCommunity": "Visitar la Comunidad",
- "LabelBrowseLibrary": "Explorar Biblioteca",
- "LabelConfigureServer": "Configurar Emby",
- "LabelRestartServer": "Reiniciar el Servidor"
+ "Plugin": "Complemento"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/es.json b/Emby.Server.Implementations/Localization/Core/es.json
index 68975d6322..c7fa51c03c 100644
--- a/Emby.Server.Implementations/Localization/Core/es.json
+++ b/Emby.Server.Implementations/Localization/Core/es.json
@@ -27,7 +27,7 @@
"Artists": "Artistas",
"Folders": "Carpetas",
"Songs": "Canciones",
- "TvShows": "TV Shows",
+ "TvShows": "Series TV",
"Shows": "Series",
"Genres": "G\u00e9neros",
"NameSeasonNumber": "Temporada {0}",
@@ -61,8 +61,8 @@
"AuthenticationSucceededWithUserName": "{0} autenticado correctamente",
"UserOfflineFromDevice": "{0} se ha desconectado de {1}",
"DeviceOfflineWithName": "{0} se ha desconectado",
- "UserStartedPlayingItemWithValues": "{0} ha comenzado jugando {1}",
- "UserStoppedPlayingItemWithValues": "{0} ha dejado de reproducir {1}",
+ "UserStartedPlayingItemWithValues": "{0} ha comenzado reproducir {1}",
+ "UserStoppedPlayingItemWithValues": "{0} ha parado de reproducir {1}",
"NotificationOptionPluginError": "Error en plugin",
"NotificationOptionApplicationUpdateAvailable": "Actualizaci\u00f3n de la aplicaci\u00f3n disponible",
"NotificationOptionApplicationUpdateInstalled": "Actualizaci\u00f3n de la aplicaci\u00f3n instalada",
@@ -87,10 +87,5 @@
"User": "Usuario",
"System": "Sistema",
"Application": "Aplicaci\u00f3n",
- "Plugin": "Plugin",
- "LabelExit": "Salida",
- "LabelVisitCommunity": "Visita la Comunidad",
- "LabelBrowseLibrary": "Navegar la biblioteca",
- "LabelConfigureServer": "Configurar Emby",
- "LabelRestartServer": "Configurar Emby"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json
index 795bc98cc5..7743905f0e 100644
--- a/Emby.Server.Implementations/Localization/Core/fr-CA.json
+++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json
index 5ea01fcdbb..6552a47abb 100644
--- a/Emby.Server.Implementations/Localization/Core/fr.json
+++ b/Emby.Server.Implementations/Localization/Core/fr.json
@@ -27,7 +27,7 @@
"Artists": "Artistes",
"Folders": "Dossiers",
"Songs": "Chansons",
- "TvShows": "TV Shows",
+ "TvShows": "S\u00e9ries T\u00e9l\u00e9",
"Shows": "\u00c9missions",
"Genres": "Genres",
"NameSeasonNumber": "Saison {0}",
@@ -87,10 +87,5 @@
"User": "Utilisateur",
"System": "Syst\u00e8me",
"Application": "Application",
- "Plugin": "Extension",
- "LabelExit": "Quitter",
- "LabelVisitCommunity": "Visiter la communaut\u00e9",
- "LabelBrowseLibrary": "Parcourir la m\u00e9diath\u00e8que",
- "LabelConfigureServer": "Configurer Emby",
- "LabelRestartServer": "Red\u00e9marrer le serveur"
+ "Plugin": "Extension"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json
index f287dc4222..c679ed289c 100644
--- a/Emby.Server.Implementations/Localization/Core/he.json
+++ b/Emby.Server.Implementations/Localization/Core/he.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json
index 143e3ab820..c807e53b40 100644
--- a/Emby.Server.Implementations/Localization/Core/hr.json
+++ b/Emby.Server.Implementations/Localization/Core/hr.json
@@ -87,10 +87,5 @@
"User": "Korisnik",
"System": "Sistem",
"Application": "Aplikacija",
- "Plugin": "Dodatak",
- "LabelExit": "Izlaz",
- "LabelVisitCommunity": "Posjeti zajednicu",
- "LabelBrowseLibrary": "Pregledaj biblioteku",
- "LabelConfigureServer": "Podesi Emby",
- "LabelRestartServer": "Restartiraj Server"
+ "Plugin": "Dodatak"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index 39d0f80613..dc8f2b7029 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Kil\u00e9p\u00e9s",
- "LabelVisitCommunity": "K\u00f6z\u00f6ss\u00e9g",
- "LabelBrowseLibrary": "M\u00e9diat\u00e1r tall\u00f3z\u00e1sa",
- "LabelConfigureServer": "Emby konfigur\u00e1l\u00e1sa",
- "LabelRestartServer": "Szerver \u00fajraindit\u00e1sa"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json
index 4ff0d98d83..42605acdb2 100644
--- a/Emby.Server.Implementations/Localization/Core/it.json
+++ b/Emby.Server.Implementations/Localization/Core/it.json
@@ -87,10 +87,5 @@
"User": "Utente",
"System": "Sistema",
"Application": "Applicazione",
- "Plugin": "Plug-in",
- "LabelExit": "Esci",
- "LabelVisitCommunity": "Visita il forum di discussione",
- "LabelBrowseLibrary": "Esplora la libreria",
- "LabelConfigureServer": "Configura Emby",
- "LabelRestartServer": "Riavvia Server"
+ "Plugin": "Plug-in"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json
index c24ee3d13b..a991fe3634 100644
--- a/Emby.Server.Implementations/Localization/Core/kk.json
+++ b/Emby.Server.Implementations/Localization/Core/kk.json
@@ -87,10 +87,5 @@
"User": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b",
"System": "\u0416\u04af\u0439\u0435",
"Application": "\u049a\u043e\u043b\u0434\u0430\u043d\u0431\u0430",
- "Plugin": "\u041f\u043b\u0430\u0433\u0438\u043d",
- "LabelExit": "\u0428\u044b\u0493\u0443",
- "LabelVisitCommunity": "\u049a\u0430\u0443\u044b\u043c\u0434\u0430\u0441\u0442\u044b\u049b\u049b\u0430 \u0431\u0430\u0440\u0443",
- "LabelBrowseLibrary": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u043d\u044b \u0448\u043e\u043b\u0443",
- "LabelConfigureServer": "Emby \u0442\u0435\u04a3\u0448\u0435\u0443",
- "LabelRestartServer": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u049b\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u0443"
+ "Plugin": "\u041f\u043b\u0430\u0433\u0438\u043d"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/ko.json b/Emby.Server.Implementations/Localization/Core/ko.json
index 6c5ed0260a..0f99c8432a 100644
--- a/Emby.Server.Implementations/Localization/Core/ko.json
+++ b/Emby.Server.Implementations/Localization/Core/ko.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json
index 21ed36d7c6..9e1fede1d8 100644
--- a/Emby.Server.Implementations/Localization/Core/lt-LT.json
+++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json
index e4a49abf64..c48042d9a3 100644
--- a/Emby.Server.Implementations/Localization/Core/ms.json
+++ b/Emby.Server.Implementations/Localization/Core/ms.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json
index d0482315d8..5cd9894bed 100644
--- a/Emby.Server.Implementations/Localization/Core/nb.json
+++ b/Emby.Server.Implementations/Localization/Core/nb.json
@@ -87,10 +87,5 @@
"User": "Bruker",
"System": "System",
"Application": "Applikasjon",
- "Plugin": "Plugin",
- "LabelExit": "Avslutt",
- "LabelVisitCommunity": "Bes\u00f8k Samfunnet",
- "LabelBrowseLibrary": "Bla i biblioteket",
- "LabelConfigureServer": "Konfigurere Emby",
- "LabelRestartServer": "Start om serveren"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json
index daba9bed5c..d79fcf7474 100644
--- a/Emby.Server.Implementations/Localization/Core/nl.json
+++ b/Emby.Server.Implementations/Localization/Core/nl.json
@@ -87,10 +87,5 @@
"User": "Gebruiker",
"System": "Systeem",
"Application": "Toepassing",
- "Plugin": "Plug-in",
- "LabelExit": "Afsluiten",
- "LabelVisitCommunity": "Bezoek Gemeenschap",
- "LabelBrowseLibrary": "Bekijk bibliotheek",
- "LabelConfigureServer": "Emby Configureren",
- "LabelRestartServer": "Server herstarten"
+ "Plugin": "Plug-in"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/pl.json b/Emby.Server.Implementations/Localization/Core/pl.json
index 24ac0d973e..896df24dd2 100644
--- a/Emby.Server.Implementations/Localization/Core/pl.json
+++ b/Emby.Server.Implementations/Localization/Core/pl.json
@@ -27,7 +27,7 @@
"Artists": "Wykonawcy",
"Folders": "Foldery",
"Songs": "Utwory",
- "TvShows": "TV Shows",
+ "TvShows": "Seriale",
"Shows": "Seriale",
"Genres": "Gatunki",
"NameSeasonNumber": "Sezon {0}",
@@ -87,10 +87,5 @@
"User": "U\u017cytkownik",
"System": "System",
"Application": "Aplikacja",
- "Plugin": "Wtyczka",
- "LabelExit": "Wyj\u015bcie",
- "LabelVisitCommunity": "Odwied\u017a spo\u0142eczno\u015b\u0107",
- "LabelBrowseLibrary": "Przegl\u0105daj bibliotek\u0119",
- "LabelConfigureServer": "Konfiguracja Emby",
- "LabelRestartServer": "Uruchom serwer ponownie"
+ "Plugin": "Wtyczka"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json
index 196a6b78b3..fa4eac1c49 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-BR.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json
@@ -87,10 +87,5 @@
"User": "Usu\u00e1rio",
"System": "Sistema",
"Application": "Aplicativo",
- "Plugin": "Plugin",
- "LabelExit": "Sair",
- "LabelVisitCommunity": "Visite a Comunidade",
- "LabelBrowseLibrary": "Explorar Biblioteca",
- "LabelConfigureServer": "Configurar Emby",
- "LabelRestartServer": "Reiniciar Servidor"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/pt-PT.json b/Emby.Server.Implementations/Localization/Core/pt-PT.json
index 7a6b8f4195..ac20fa1e54 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-PT.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-PT.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Aplica\u00e7\u00e3o",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json
index d27b1ca93d..12345ca145 100644
--- a/Emby.Server.Implementations/Localization/Core/ru.json
+++ b/Emby.Server.Implementations/Localization/Core/ru.json
@@ -87,10 +87,5 @@
"User": "\u041f\u043e\u043b\u044c\u0437-\u043b\u044c",
"System": "\u0421\u0438\u0441\u0442\u0435\u043c\u0430",
"Application": "\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435",
- "Plugin": "\u041f\u043b\u0430\u0433\u0438\u043d",
- "LabelExit": "\u0412\u044b\u0445\u043e\u0434",
- "LabelVisitCommunity": "\u041f\u043e\u0441\u0435\u0449\u0435\u043d\u0438\u0435 \u0421\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430",
- "LabelBrowseLibrary": "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u043f\u043e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435",
- "LabelConfigureServer": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Emby",
- "LabelRestartServer": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430"
+ "Plugin": "\u041f\u043b\u0430\u0433\u0438\u043d"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/sk.json b/Emby.Server.Implementations/Localization/Core/sk.json
index 98f60e5e1d..f09eb15068 100644
--- a/Emby.Server.Implementations/Localization/Core/sk.json
+++ b/Emby.Server.Implementations/Localization/Core/sk.json
@@ -1,96 +1,91 @@
{
- "Latest": "Latest",
- "ValueSpecialEpisodeName": "Special - {0}",
- "Inherit": "Inherit",
- "Books": "Books",
- "Music": "Music",
- "Games": "Games",
- "Photos": "Photos",
- "MixedContent": "Mixed content",
- "MusicVideos": "Music videos",
- "HomeVideos": "Home videos",
- "Playlists": "Playlists",
+ "Latest": "Najnov\u0161ie",
+ "ValueSpecialEpisodeName": "\u0160peci\u00e1l - {0}",
+ "Inherit": "Zdedi\u0165",
+ "Books": "Knihy",
+ "Music": "Hudba",
+ "Games": "Hry",
+ "Photos": "Fotky",
+ "MixedContent": "Zmie\u0161an\u00fd obsah",
+ "MusicVideos": "Hudobn\u00e9 vide\u00e1",
+ "HomeVideos": "Dom\u00e1ce vide\u00e1",
+ "Playlists": "Zoznamy skladieb",
"HeaderRecordingGroups": "Recording Groups",
- "HeaderContinueWatching": "Continue Watching",
- "HeaderFavoriteArtists": "Favorite Artists",
+ "HeaderContinueWatching": "Pokra\u010dujte v pozeran\u00ed",
+ "HeaderFavoriteArtists": "Ob\u013e\u00faben\u00ed umelci",
"HeaderFavoriteSongs": "Ob\u013e\u00faben\u00e9 pesni\u010dky",
"HeaderAlbumArtists": "Album Artists",
- "HeaderFavoriteAlbums": "Favorite Albums",
- "HeaderFavoriteEpisodes": "Favorite Episodes",
+ "HeaderFavoriteAlbums": "Ob\u013e\u00faben\u00e9 albumy",
+ "HeaderFavoriteEpisodes": "Ob\u013e\u00faben\u00e9 epiz\u00f3dy",
"HeaderFavoriteShows": "Ob\u013e\u00faben\u00e9 seri\u00e1ly",
- "HeaderNextUp": "Next Up",
+ "HeaderNextUp": "Nasleduje",
"Favorites": "Ob\u013e\u00faben\u00e9",
- "Collections": "Collections",
- "Channels": "Channels",
- "Movies": "Movies",
- "Albums": "Albums",
- "Artists": "Artists",
- "Folders": "Folders",
- "Songs": "Songs",
+ "Collections": "Zbierky",
+ "Channels": "Kan\u00e1ly",
+ "Movies": "Filmy",
+ "Albums": "Albumy",
+ "Artists": "Umelci",
+ "Folders": "Prie\u010dinky",
+ "Songs": "Skladby",
"TvShows": "TV Shows",
"Shows": "Series",
- "Genres": "Genres",
- "NameSeasonNumber": "Season {0}",
- "AppDeviceValues": "App: {0}, Device: {1}",
- "UserDownloadingItemWithValues": "{0} is downloading {1}",
+ "Genres": "\u017d\u00e1nre",
+ "NameSeasonNumber": "Sez\u00f3na {0}",
+ "AppDeviceValues": "Aplik\u00e1cia: {0}, Zariadenie: {1}",
+ "UserDownloadingItemWithValues": "{0} s\u0165ahuje {1}",
"HeaderLiveTV": "Live TV",
- "ChapterNameValue": "Chapter {0}",
- "ScheduledTaskFailedWithName": "{0} failed",
- "LabelRunningTimeValue": "Running time: {0}",
+ "ChapterNameValue": "Kapitola {0}",
+ "ScheduledTaskFailedWithName": "{0} zlyhalo",
+ "LabelRunningTimeValue": "D\u013a\u017eka: {0}",
"ScheduledTaskStartedWithName": "{0} started",
- "VersionNumber": "Version {0}",
- "PluginInstalledWithName": "{0} was installed",
- "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly.",
- "PluginUpdatedWithName": "{0} was updated",
- "PluginUninstalledWithName": "{0} was uninstalled",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
- "LabelIpAddressValue": "Ip address: {0}",
- "DeviceOnlineWithName": "{0} is connected",
- "UserOnlineFromDevice": "{0} is online from {1}",
+ "VersionNumber": "Verzia {0}",
+ "PluginInstalledWithName": "{0} bol nain\u0161talovan\u00fd",
+ "StartupEmbyServerIsLoading": "Emby Server sa sp\u00fa\u0161\u0165a. Sk\u00faste to pros\u00edm o chv\u00ed\u013eu znova.",
+ "PluginUpdatedWithName": "{0} bol aktualizovan\u00fd",
+ "PluginUninstalledWithName": "{0} bol odin\u0161talovan\u00fd",
+ "ItemAddedWithName": "{0} bol pridan\u00fd do kni\u017enice",
+ "ItemRemovedWithName": "{0} bol odstr\u00e1nen\u00fd z kni\u017enice",
+ "LabelIpAddressValue": "IP adresa: {0}",
+ "DeviceOnlineWithName": "{0} je pripojen\u00fd",
+ "UserOnlineFromDevice": "{0} je online z {1}",
"ProviderValue": "Provider: {0}",
- "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
- "UserCreatedWithName": "User {0} has been created",
- "UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserDeletedWithName": "User {0} has been deleted",
+ "SubtitlesDownloadedForItem": "Titulky pre {0} stiahnut\u00e9",
+ "UserCreatedWithName": "Pou\u017e\u00edvate\u013e {0} bol vytvoren\u00fd",
+ "UserPasswordChangedWithName": "Heslo pou\u017e\u00edvate\u013ea {0} zmenen\u00e9",
+ "UserDeletedWithName": "Pou\u017e\u00edvate\u013e {0} bol vymazan\u00fd",
"UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
- "MessageServerConfigurationUpdated": "Server configuration has been updated",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageApplicationUpdated": "Emby Server has been updated",
- "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
- "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
- "UserOfflineFromDevice": "{0} has disconnected from {1}",
- "DeviceOfflineWithName": "{0} has disconnected",
- "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
- "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
+ "MessageServerConfigurationUpdated": "Konfigur\u00e1cia servera aktualizovan\u00e1",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Sekcia {0} konfigur\u00e1cie servera bola aktualizovan\u00e1",
+ "MessageApplicationUpdated": "Emby Server bol aktualizovan\u00fd",
+ "FailedLoginAttemptWithUserName": "Ne\u00faspe\u0161n\u00fd pokus o prihl\u00e1senie z {0}",
+ "AuthenticationSucceededWithUserName": "{0} \u00faspe\u0161ne overen\u00fd",
+ "UserOfflineFromDevice": "{0} sa odpojil od {1}",
+ "DeviceOfflineWithName": "{0} je odpojen\u00fd",
+ "UserStartedPlayingItemWithValues": "{0} spustil prehr\u00e1vanie {1}",
+ "UserStoppedPlayingItemWithValues": "{0} zastavil prehr\u00e1vanie {1}",
"NotificationOptionPluginError": "Plugin failure",
- "NotificationOptionApplicationUpdateAvailable": "Application update available",
- "NotificationOptionApplicationUpdateInstalled": "Application update installed",
+ "NotificationOptionApplicationUpdateAvailable": "Je dostupn\u00e1 aktualiz\u00e1cia aplik\u00e1cie",
+ "NotificationOptionApplicationUpdateInstalled": "Aktualiz\u00e1cia aplik\u00e1cie nain\u0161talovan\u00e1",
"NotificationOptionPluginUpdateInstalled": "Plugin update installed",
"NotificationOptionPluginInstalled": "Plugin installed",
"NotificationOptionPluginUninstalled": "Plugin uninstalled",
- "NotificationOptionVideoPlayback": "Video playback started",
- "NotificationOptionAudioPlayback": "Audio playback started",
+ "NotificationOptionVideoPlayback": "Spusten\u00e9 prehr\u00e1vanie videa",
+ "NotificationOptionAudioPlayback": "Spusten\u00e9 prehr\u00e1vanie audia",
"NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
- "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
- "NotificationOptionTaskFailed": "Scheduled task failure",
- "NotificationOptionInstallationFailed": "Installation failure",
- "NotificationOptionNewLibraryContent": "New content added",
+ "NotificationOptionVideoPlaybackStopped": "Zastaven\u00e9 prehr\u00e1vanie videa",
+ "NotificationOptionAudioPlaybackStopped": "Zastaven\u00e9 prehr\u00e1vanie audia",
+ "NotificationOptionGamePlaybackStopped": "Hra ukon\u010den\u00e1",
+ "NotificationOptionTaskFailed": "Napl\u00e1novan\u00e1 \u00faloha zlyhala",
+ "NotificationOptionInstallationFailed": "Chyba in\u0161tal\u00e1cie",
+ "NotificationOptionNewLibraryContent": "Pridan\u00fd nov\u00fd obsah",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionUserLockedOut": "User locked out",
- "NotificationOptionServerRestartRequired": "Server restart required",
+ "NotificationOptionServerRestartRequired": "Vy\u017eaduje sa re\u0161tart servera",
"UserLockedOutWithName": "User {0} has been locked out",
- "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
+ "SubtitleDownloadFailureForItem": "S\u0165ahovanie titulkov pre {0} zlyhalo",
"Sync": "Sync",
- "User": "User",
- "System": "System",
- "Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "User": "Pou\u017e\u00edvate\u013e",
+ "System": "Syst\u00e9m",
+ "Application": "Aplik\u00e1cia",
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json
index cb8e080e45..27561a890b 100644
--- a/Emby.Server.Implementations/Localization/Core/sl-SI.json
+++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index a038811837..ed18670249 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -27,7 +27,7 @@
"Artists": "Artister",
"Folders": "Mappar",
"Songs": "L\u00e5tar",
- "TvShows": "TV Shows",
+ "TvShows": "TV-serier",
"Shows": "Serier",
"Genres": "Genrer",
"NameSeasonNumber": "S\u00e4song {0}",
@@ -87,10 +87,5 @@
"User": "Anv\u00e4ndare",
"System": "System",
"Application": "App",
- "Plugin": "Till\u00e4gg",
- "LabelExit": "Avsluta",
- "LabelVisitCommunity": "Bes\u00f6k v\u00e5rt diskussionsforum",
- "LabelBrowseLibrary": "Bl\u00e4ddra i biblioteket",
- "LabelConfigureServer": "Konfigurera Emby",
- "LabelRestartServer": "Starta om servern"
+ "Plugin": "Till\u00e4gg"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json
index a0a5151707..71af4110d6 100644
--- a/Emby.Server.Implementations/Localization/Core/tr.json
+++ b/Emby.Server.Implementations/Localization/Core/tr.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json
index 42126ca1b6..0f248f3cd2 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-CN.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json
@@ -87,10 +87,5 @@
"User": "\u7528\u6237",
"System": "\u7cfb\u7edf",
"Application": "\u5e94\u7528\u7a0b\u5e8f",
- "Plugin": "\u63d2\u4ef6",
- "LabelExit": "\u9000\u51fa",
- "LabelVisitCommunity": "\u8bbf\u95ee\u793e\u533a",
- "LabelBrowseLibrary": "\u6d4f\u89c8\u5a92\u4f53\u5e93",
- "LabelConfigureServer": "\u914d\u7f6e Emby",
- "LabelRestartServer": "\u91cd\u542f\u670d\u52a1\u5668"
+ "Plugin": "\u63d2\u4ef6"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json
index 37afc47e61..b60edb176e 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-HK.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json
@@ -87,10 +87,5 @@
"User": "User",
"System": "System",
"Application": "Application",
- "Plugin": "Plugin",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "\u8a2a\u554f\u8a0e\u8ad6\u5340",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server"
+ "Plugin": "Plugin"
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index 2eb4743cd0..6d271c0e1c 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -64,7 +64,7 @@ namespace Emby.Server.Implementations.Localization
var localizationPath = LocalizationPath;
- _fileSystem.CreateDirectory(localizationPath);
+ _fileSystem.CreateDirectory(localizationPath);
var existingFiles = GetRatingsFiles(localizationPath)
.Select(Path.GetFileName)
@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.Localization
}
}
}
-
+
foreach (var file in GetRatingsFiles(localizationPath))
{
LoadRatings(file);
@@ -128,12 +128,20 @@ namespace Emby.Server.Implementations.Localization
return _textLocalizer.NormalizeFormKD(text);
}
+ private CultureDto[] _cultures;
+
/// <summary>
/// Gets the cultures.
/// </summary>
/// <returns>IEnumerable{CultureDto}.</returns>
public CultureDto[] GetCultures()
{
+ var result = _cultures;
+ if (result != null)
+ {
+ return result;
+ }
+
var type = GetType();
var path = type.Namespace + ".iso6392.txt";
@@ -166,10 +174,14 @@ namespace Emby.Server.Implementations.Localization
}
}
- return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
- !string.IsNullOrWhiteSpace(i.DisplayName) &&
- !string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) &&
- !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToArray();
+ result = list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
+ !string.IsNullOrWhiteSpace(i.DisplayName) &&
+ !string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) &&
+ !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToArray();
+
+ _cultures = result;
+
+ return result;
}
/// <summary>
@@ -239,7 +251,7 @@ namespace Emby.Server.Implementations.Localization
/// <returns>Dictionary{System.StringParentalRating}.</returns>
private void LoadRatings(string file)
{
- var dict = _fileSystem.ReadAllLines(file).Select(i =>
+ var dict = _fileSystem.ReadAllLines(file).Select(i =>
{
if (!string.IsNullOrWhiteSpace(i))
{
@@ -269,7 +281,7 @@ namespace Emby.Server.Implementations.Localization
_allParentalRatings.TryAdd(countryCode, dict);
}
- private readonly string[] _unratedValues = {"n/a", "unrated", "not rated"};
+ private readonly string[] _unratedValues = { "n/a", "unrated", "not rated" };
/// <summary>
/// Gets the rating level.
diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
index 9a9e619a62..6e0e55bef4 100644
--- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -17,6 +17,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
namespace Emby.Server.Implementations.MediaEncoder
{
@@ -89,7 +90,7 @@ namespace Emby.Server.Implementations.MediaEncoder
/// </summary>
private static readonly long FirstChapterTicks = TimeSpan.FromSeconds(15).Ticks;
- public async Task<bool> RefreshChapterImages(Video video, List<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken)
+ public async Task<bool> RefreshChapterImages(Video video, IDirectoryService directoryService, List<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken)
{
if (!IsEligibleForChapterImageExtraction(video))
{
@@ -101,7 +102,7 @@ namespace Emby.Server.Implementations.MediaEncoder
var runtimeTicks = video.RunTimeTicks ?? 0;
- var currentImages = GetSavedChapterImages(video);
+ var currentImages = GetSavedChapterImages(video, directoryService);
foreach (var chapter in chapters)
{
@@ -194,13 +195,13 @@ namespace Emby.Server.Implementations.MediaEncoder
return Path.Combine(GetChapterImagesPath(video), filename);
}
- private List<string> GetSavedChapterImages(Video video)
+ private List<string> GetSavedChapterImages(Video video, IDirectoryService directoryService)
{
var path = GetChapterImagesPath(video);
try
{
- return _fileSystem.GetFilePaths(path)
+ return directoryService.GetFilePaths(path)
.ToList();
}
catch (IOException)
diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs
index f78fbdfd72..bdae1728f9 100644
--- a/Emby.Server.Implementations/Net/SocketFactory.cs
+++ b/Emby.Server.Implementations/Net/SocketFactory.cs
@@ -196,8 +196,18 @@ namespace Emby.Server.Implementations.Net
try
{
- //retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
+ // seeing occasional exceptions thrown on qnap
+ // System.Net.Sockets.SocketException (0x80004005): Protocol not available
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ }
+ catch (SocketException)
+ {
+
+ }
+
+ try
+ {
+ //retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
var localIp = IPAddress.Any;
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index 72d0154aa5..fbdb5c128c 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -59,7 +59,13 @@ namespace Emby.Server.Implementations.Networking
list.AddRange(GetLocalIpAddressesFallback().Result);
}
- return list.Where(FilterIpAddress).DistinctBy(i => i.ToString());
+ var listClone = list.ToList();
+
+ return list
+ .OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1)
+ .ThenBy(i => listClone.IndexOf(i))
+ .Where(FilterIpAddress)
+ .DistinctBy(i => i.ToString());
}
private bool FilterIpAddress(IPAddress address)
@@ -106,16 +112,16 @@ namespace Emby.Server.Implementations.Networking
endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
+ //endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
IsInPrivateAddressSpaceAndLocalSubnet(endpoint);
}
public bool IsInPrivateAddressSpaceAndLocalSubnet(string endpoint)
{
- var endpointFirstPart = endpoint.Split('.')[0];
-
if (endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase))
{
+ var endpointFirstPart = endpoint.Split('.')[0];
+
var subnets = GetSubnets(endpointFirstPart);
foreach (var subnet_Match in subnets)
@@ -217,7 +223,7 @@ namespace Emby.Server.Implementations.Networking
}
else if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
- lengthMatch = 10;
+ lengthMatch = 9;
if (IsInPrivateAddressSpace(endpoint))
{
return true;
@@ -317,7 +323,7 @@ namespace Emby.Server.Implementations.Networking
return ipProperties.UnicastAddresses
//.Where(i => i.IsDnsEligible)
.Select(i => i.Address)
- .Where(i => i.AddressFamily == AddressFamily.InterNetwork)
+ .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6)
.ToList();
}
catch (Exception ex)
@@ -337,7 +343,7 @@ namespace Emby.Server.Implementations.Networking
// Reverse them because the last one is usually the correct one
// It's not fool-proof so ultimately the consumer will have to examine them and decide
return host.AddressList
- .Where(i => i.AddressFamily == AddressFamily.InterNetwork)
+ .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6)
.Reverse();
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index bf7bf9ff8b..fe0652f668 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Extensions;
+using MediaBrowser.Controller.Providers;
namespace Emby.Server.Implementations.ScheduledTasks
{
@@ -120,6 +121,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
previouslyFailedImages = new List<string>();
}
+ var directoryService = new DirectoryService(_fileSystem);
+
foreach (var video in videos)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -132,7 +135,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
var chapters = _itemRepo.GetChapters(video.Id);
- var success = await _encodingManager.RefreshChapterImages(video, chapters, extract, true, CancellationToken.None);
+ var success = await _encodingManager.RefreshChapterImages(video, directoryService, chapters, extract, true, CancellationToken.None);
if (!success)
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index d7d048110e..bdc29c16b7 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -464,6 +464,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <param name="e">The e.</param>
void progress_ProgressChanged(object sender, double e)
{
+ e = Math.Min(e, 100);
+
CurrentProgress = e;
EventHelper.FireEventIfNotNull(TaskProgress, this, new GenericEventArgs<double>
diff --git a/Emby.Server.Implementations/Session/HttpSessionController.cs b/Emby.Server.Implementations/Session/HttpSessionController.cs
index 940c821e2f..e1c1bbe2b8 100644
--- a/Emby.Server.Implementations/Session/HttpSessionController.cs
+++ b/Emby.Server.Implementations/Session/HttpSessionController.cs
@@ -109,6 +109,18 @@ namespace Emby.Server.Implementations.Session
{
dict["StartPositionTicks"] = command.StartPositionTicks.Value.ToString(CultureInfo.InvariantCulture);
}
+ if (command.AudioStreamIndex.HasValue)
+ {
+ dict["AudioStreamIndex"] = command.AudioStreamIndex.Value.ToString(CultureInfo.InvariantCulture);
+ }
+ if (command.SubtitleStreamIndex.HasValue)
+ {
+ dict["SubtitleStreamIndex"] = command.SubtitleStreamIndex.Value.ToString(CultureInfo.InvariantCulture);
+ }
+ if (!string.IsNullOrWhiteSpace(command.MediaSourceId))
+ {
+ dict["MediaSourceId"] = command.MediaSourceId;
+ }
return SendMessage(command.PlayCommand.ToString(), dict, cancellationToken);
}
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 2c15351656..30f6e65218 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -972,7 +972,6 @@ namespace Emby.Server.Implementations.Session
if (command.PlayCommand == PlayCommand.PlayInstantMix)
{
items = command.ItemIds.SelectMany(i => TranslateItemForInstantMix(i, user))
- .Where(i => i.LocationType != LocationType.Virtual)
.ToList();
command.PlayCommand = PlayCommand.PlayNow;
@@ -986,9 +985,7 @@ namespace Emby.Server.Implementations.Session
list.AddRange(subItems);
}
- items = list
- .Where(i => i.LocationType != LocationType.Virtual)
- .ToList();
+ items = list;
}
if (command.PlayCommand == PlayCommand.PlayShuffle)
@@ -1074,7 +1071,8 @@ namespace Emby.Server.Implementations.Session
{
ItemFields.SortName
}
- }
+ },
+ IsVirtualItem = false
});
return FilterToSingleMediaType(items)
@@ -1097,7 +1095,8 @@ namespace Emby.Server.Implementations.Session
{
ItemFields.SortName
}
- }
+ },
+ IsVirtualItem = false
});
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 6152ea20b8..a036a00a6e 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -335,7 +335,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields,
Id = request.Id,
Limit = request.Limit,
- UserId = request.UserId
+ UserId = request.UserId,
+ ImageTypeLimit = request.ImageTypeLimit
});
}
if (item is MusicAlbum)
@@ -350,7 +351,8 @@ namespace MediaBrowser.Api.Library
Id = request.Id,
Limit = request.Limit,
UserId = request.UserId,
- ExcludeArtistIds = request.ExcludeArtistIds
+ ExcludeArtistIds = request.ExcludeArtistIds,
+ ImageTypeLimit = request.ImageTypeLimit
});
}
if (item is MusicArtist)
@@ -364,7 +366,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields,
Id = request.Id,
Limit = request.Limit,
- UserId = request.UserId
+ UserId = request.UserId,
+ ImageTypeLimit = request.ImageTypeLimit
});
}
@@ -381,7 +384,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields,
Id = request.Id,
Limit = request.Limit,
- UserId = request.UserId
+ UserId = request.UserId,
+ ImageTypeLimit = request.ImageTypeLimit
});
}
@@ -396,7 +400,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields,
Id = request.Id,
Limit = request.Limit,
- UserId = request.UserId
+ UserId = request.UserId,
+ ImageTypeLimit = request.ImageTypeLimit
});
}
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index e961f9d516..35c29cd15b 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -66,7 +66,7 @@ namespace MediaBrowser.Api.Session
[Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")]
[Authenticated]
- public class Play : IReturnVoid
+ public class Play : PlayRequest
{
/// <summary>
/// Gets or sets the id.
@@ -74,27 +74,6 @@ namespace MediaBrowser.Api.Session
/// <value>The id.</value>
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Id { get; set; }
-
- /// <summary>
- /// Artist, Genre, Studio, Person, or any kind of BaseItem
- /// </summary>
- /// <value>The type of the item.</value>
- [ApiMember(Name = "ItemIds", Description = "The ids of the items to play, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
- public string ItemIds { get; set; }
-
- /// <summary>
- /// Gets or sets the start position ticks that the first item should be played at
- /// </summary>
- /// <value>The start position ticks.</value>
- [ApiMember(Name = "StartPositionTicks", Description = "The starting position of the first item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public long? StartPositionTicks { get; set; }
-
- /// <summary>
- /// Gets or sets the play command.
- /// </summary>
- /// <value>The play command.</value>
- [ApiMember(Name = "PlayCommand", Description = "The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public PlayCommand PlayCommand { get; set; }
}
[Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")]
@@ -471,15 +450,7 @@ namespace MediaBrowser.Api.Session
/// <param name="request">The request.</param>
public void Post(Play request)
{
- var command = new PlayRequest
- {
- ItemIds = request.ItemIds.Split(','),
-
- PlayCommand = request.PlayCommand,
- StartPositionTicks = request.StartPositionTicks
- };
-
- var task = _sessionManager.SendPlayCommand(GetSession(_sessionContext).Result.Id, request.Id, command, CancellationToken.None);
+ var task = _sessionManager.SendPlayCommand(GetSession(_sessionContext).Result.Id, request.Id, request, CancellationToken.None);
Task.WaitAll(task);
}
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index 1b185b073b..54e4657c11 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -9,6 +9,8 @@ using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Services;
+using MediaBrowser.Common.Net;
+using System.Threading;
namespace MediaBrowser.Api
{
@@ -50,14 +52,16 @@ namespace MediaBrowser.Api
private readonly IUserManager _userManager;
private readonly IConnectManager _connectManager;
private readonly IMediaEncoder _mediaEncoder;
+ private readonly IHttpClient _httpClient;
- public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, IMediaEncoder mediaEncoder)
+ public StartupWizardService(IServerConfigurationManager config, IHttpClient httpClient, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, IMediaEncoder mediaEncoder)
{
_config = config;
_appHost = appHost;
_userManager = userManager;
_connectManager = connectManager;
_mediaEncoder = mediaEncoder;
+ _httpClient = httpClient;
}
public void Post(ReportStartupWizardComplete request)
@@ -65,6 +69,35 @@ namespace MediaBrowser.Api
_config.Configuration.IsStartupWizardCompleted = true;
_config.SetOptimalValues();
_config.SaveConfiguration();
+
+ Task.Run(UpdateStats);
+ }
+
+ private async Task UpdateStats()
+ {
+ try
+ {
+ var url = string.Format("http://www.mb3admin.com/admin/service/package/installed?mac={0}&product=MBServer&operation=Install&version={1}",
+ _appHost.SystemId,
+ _appHost.ApplicationVersion.ToString());
+
+ using (var response = await _httpClient.SendAsync(new HttpRequestOptions
+ {
+
+ Url = url,
+ CancellationToken = CancellationToken.None,
+ LogErrors = false,
+ LogRequest = false
+
+ }, "GET").ConfigureAwait(false))
+ {
+
+ }
+ }
+ catch
+ {
+
+ }
}
public object Get(GetStartupInfo request)
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index 3f840dbfa3..3f4bb46f45 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -114,12 +114,14 @@ namespace MediaBrowser.Api
foreach (var link in video.GetLinkedAlternateVersions())
{
- link.PrimaryVersionId = null;
+ link.SetPrimaryVersionId(null);
+ link.LinkedAlternateVersions = Video.EmptyLinkedChildArray;
link.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
}
video.LinkedAlternateVersions = Video.EmptyLinkedChildArray;
+ video.SetPrimaryVersionId(null);
video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
}
@@ -174,7 +176,7 @@ namespace MediaBrowser.Api
foreach (var item in items.Where(i => i.Id != primaryVersion.Id))
{
- item.PrimaryVersionId = primaryVersion.Id.ToString("N");
+ item.SetPrimaryVersionId(primaryVersion.Id.ToString("N"));
item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs
index 0a279fa9cc..8f0b155f34 100644
--- a/MediaBrowser.Common/Net/HttpRequestOptions.cs
+++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs
@@ -93,6 +93,8 @@ namespace MediaBrowser.Common.Net
public bool LogRequest { get; set; }
public bool LogRequestAsDebug { get; set; }
public bool LogErrors { get; set; }
+ public bool LogResponse { get; set; }
+ public bool LogResponseHeaders { get; set; }
public bool LogErrorResponseBody { get; set; }
public bool EnableKeepAlive { get; set; }
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 5b4cd59001..f6a8f1d5a4 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1376,11 +1376,6 @@ namespace MediaBrowser.Controller.Entities
return list;
}
- internal virtual bool IsValidFromResolver(BaseItem newItem)
- {
- return true;
- }
-
internal virtual ItemUpdateType UpdateFromResolvedItem(BaseItem newItem)
{
var updateType = ItemUpdateType.None;
@@ -2045,7 +2040,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.IsLocalFile)
.Select(i => FileSystem.GetDirectoryName(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
- .SelectMany(i => FileSystem.GetFilePaths(i))
+ .SelectMany(i => directoryService.GetFilePaths(i))
.ToList();
var deletedImages = ImageInfos
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 5fb9e517c8..03fca60c89 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -265,21 +265,6 @@ namespace MediaBrowser.Controller.Entities
return changed;
}
- internal override bool IsValidFromResolver(BaseItem newItem)
- {
- var newCollectionFolder = newItem as CollectionFolder;
-
- if (newCollectionFolder != null)
- {
- if (!string.Equals(CollectionType, newCollectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- }
-
- return base.IsValidFromResolver(newItem);
- }
-
private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations)
{
var path = ContainingFolderPath;
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 12183aec2f..504d03a276 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -416,7 +416,7 @@ namespace MediaBrowser.Controller.Entities
{
BaseItem currentChild;
- if (currentChildren.TryGetValue(child.Id, out currentChild) && currentChild.IsValidFromResolver(child))
+ if (currentChildren.TryGetValue(child.Id, out currentChild))
{
validChildren.Add(currentChild);
@@ -1421,6 +1421,16 @@ namespace MediaBrowser.Controller.Entities
// Sweep through recursively and update status
foreach (var item in itemsResult)
{
+ if (item.IsVirtualItem)
+ {
+ // The querying doesn't support virtual unaired
+ var episode = item as Episode;
+ if (episode != null && episode.IsUnaired)
+ {
+ continue;
+ }
+ }
+
item.MarkPlayed(user, datePlayed, resetPosition);
}
}
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 52f1dd0514..dca1cfd01b 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -84,6 +84,20 @@ namespace MediaBrowser.Controller.Entities
}
}
+ public void SetPrimaryVersionId(string id)
+ {
+ if (string.IsNullOrWhiteSpace(id))
+ {
+ PrimaryVersionId = null;
+ }
+ else
+ {
+ PrimaryVersionId = id;
+ }
+
+ PresentationUniqueKey = CreatePresentationUniqueKey();
+ }
+
public override string CreatePresentationUniqueKey()
{
if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
@@ -667,8 +681,6 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("media");
}
- var mediaStreams = MediaSourceManager.GetMediaStreams(media.Id);
-
var locationType = media.LocationType;
var info = new MediaSourceInfo
@@ -676,8 +688,8 @@ namespace MediaBrowser.Controller.Entities
Id = media.Id.ToString("N"),
IsoType = media.IsoType,
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
- MediaStreams = mediaStreams,
- Name = GetMediaSourceName(media, mediaStreams),
+ MediaStreams = MediaSourceManager.GetMediaStreams(media.Id),
+ Name = GetMediaSourceName(media),
Path = enablePathSubstitution ? GetMappedPath(media, media.Path, locationType) : media.Path,
RunTimeTicks = media.RunTimeTicks,
Video3DFormat = media.Video3DFormat,
@@ -740,12 +752,20 @@ namespace MediaBrowser.Controller.Entities
return info;
}
- private static string GetMediaSourceName(Video video, List<MediaStream> mediaStreams)
+ private static string GetMediaSourceName(Video video)
{
var terms = new List<string>();
- var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
- var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
+ var locationType = video.LocationType;
+ var path = video.Path;
+ if ((locationType == LocationType.FileSystem || locationType == LocationType.Offline) && !string.IsNullOrWhiteSpace(path))
+ {
+ terms.Add(System.IO.Path.GetFileName(path));
+ }
+ else
+ {
+ terms.Add(video.Name);
+ }
if (video.Video3DFormat.HasValue)
{
@@ -779,50 +799,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- if (videoStream != null)
- {
- if (videoStream.Width.HasValue)
- {
- if (videoStream.Width.Value >= 3800)
- {
- terms.Add("4K");
- }
- else if (videoStream.Width.Value >= 1900)
- {
- terms.Add("1080P");
- }
- else if (videoStream.Width.Value >= 1270)
- {
- terms.Add("720P");
- }
- else if (videoStream.Width.Value >= 700)
- {
- terms.Add("480P");
- }
- else
- {
- terms.Add("SD");
- }
- }
- }
-
- if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec))
- {
- terms.Add(videoStream.Codec.ToUpper());
- }
-
- if (audioStream != null)
- {
- var audioCodec = string.Equals(audioStream.Codec, "dca", StringComparison.OrdinalIgnoreCase)
- ? audioStream.Profile
- : audioStream.Codec;
-
- if (!string.IsNullOrEmpty(audioCodec))
- {
- terms.Add(audioCodec.ToUpper());
- }
- }
-
return string.Join("/", terms.ToArray(terms.Count));
}
diff --git a/MediaBrowser.Controller/IO/StreamHelper.cs b/MediaBrowser.Controller/IO/StreamHelper.cs
index 106fec41fc..5aec9a1828 100644
--- a/MediaBrowser.Controller/IO/StreamHelper.cs
+++ b/MediaBrowser.Controller/IO/StreamHelper.cs
@@ -1,6 +1,7 @@
using System.IO;
using System.Threading;
using System;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.IO
{
@@ -23,5 +24,27 @@ namespace MediaBrowser.Controller.IO
}
}
}
+
+ public static async Task CopyToAsync(Stream source, Stream destination, int bufferSize, IProgress<double> progress, long contentLength, CancellationToken cancellationToken)
+ {
+ byte[] buffer = new byte[bufferSize];
+ int read;
+ long totalRead = 0;
+
+ while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ destination.Write(buffer, 0, read);
+
+ totalRead += read;
+
+ double pct = totalRead;
+ pct /= contentLength;
+ pct *= 100;
+
+ progress.Report(pct);
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index 523eec24ac..242011db06 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -63,8 +63,8 @@ namespace MediaBrowser.Controller.LiveTv
void Close();
int ConsumerCount { get; }
string OriginalStreamId { get; set; }
+ string TunerHostId { get; }
bool EnableStreamSharing { get; set; }
- ITunerHost TunerHost { get; set; }
MediaSourceInfo OpenedMediaSource { get; set; }
string UniqueId { get; }
List<string> SharedStreamIds { get; }
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index bddafe9a6a..8f8791922d 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -1325,6 +1325,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue)
{
videoSizeParam = string.Format("scale={0}:{1}", state.VideoStream.Width.Value.ToString(_usCulture), state.VideoStream.Height.Value.ToString(_usCulture));
+
+ videoSizeParam += ":force_original_aspect_ratio=decrease";
}
var mapPrefix = state.SubtitleStream.IsExternal ?
@@ -1335,7 +1337,7 @@ namespace MediaBrowser.Controller.MediaEncoding
? 0
: state.SubtitleStream.Index;
- return string.Format(" -filter_complex \"[{0}:{1}]{4}[sub] ; [0:{2}] [sub] overlay{3}\"",
+ return string.Format(" -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"",
mapPrefix.ToString(_usCulture),
subtitleStreamIndex.ToString(_usCulture),
state.VideoStream.Index.ToString(_usCulture),
@@ -2094,6 +2096,12 @@ namespace MediaBrowser.Controller.MediaEncoding
args += " -avoid_negative_ts disabled -start_at_zero";
}
+ // This is for internal graphical subs
+ if (hasGraphicalSubs)
+ {
+ args += GetGraphicalSubtitleParam(state, encodingOptions, videoCodec);
+ }
+
var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultH264Preset);
if (!string.IsNullOrEmpty(qualityParam))
@@ -2101,12 +2109,6 @@ namespace MediaBrowser.Controller.MediaEncoding
args += " " + qualityParam.Trim();
}
- // This is for internal graphical subs
- if (hasGraphicalSubs)
- {
- args += GetGraphicalSubtitleParam(state, encodingOptions, videoCodec);
- }
-
if (!state.RunTimeTicks.HasValue)
{
args += " -flags -global_header";
diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
index 81269fe3fa..7d50efd5ed 100644
--- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
@@ -3,6 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Controller.Providers;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -11,6 +12,6 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Refreshes the chapter images.
/// </summary>
- Task<bool> RefreshChapterImages(Video video, List<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken);
+ Task<bool> RefreshChapterImages(Video video, IDirectoryService directoryService, List<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 31cd96c9a6..2712380c70 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -118,9 +118,6 @@ namespace MediaBrowser.Controller.MediaEncoding
void UpdateEncoderPath(string path, string pathType);
bool SupportsEncoder(string encoder);
- void SetLogFilename(string name);
- void ClearLogFilename();
-
string[] GetPlayableStreamFileNames(string path, VideoType videoType);
IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber);
}
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index d957470d3b..d673198fdc 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -14,11 +14,11 @@ namespace MediaBrowser.Controller.Providers
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
- private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache =
- new ConcurrentDictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary<string, FileSystemMetadata[]> _cache = new Dictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
- private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache =
- new ConcurrentDictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary<string, FileSystemMetadata> _fileCache = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
+
+ private readonly Dictionary<string, List<string>> _filePathCache = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
public DirectoryService(ILogger logger, IFileSystem fileSystem)
{
@@ -33,11 +33,6 @@ namespace MediaBrowser.Controller.Providers
public FileSystemMetadata[] GetFileSystemEntries(string path)
{
- return GetFileSystemEntries(path, false);
- }
-
- private FileSystemMetadata[] GetFileSystemEntries(string path, bool clearCache)
- {
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentNullException("path");
@@ -45,13 +40,6 @@ namespace MediaBrowser.Controller.Providers
FileSystemMetadata[] entries;
- if (clearCache)
- {
- FileSystemMetadata[] removed;
-
- _cache.TryRemove(path, out removed);
- }
-
if (!_cache.TryGetValue(path, out entries))
{
//_logger.Debug("Getting files for " + path);
@@ -66,7 +54,8 @@ namespace MediaBrowser.Controller.Providers
entries = new FileSystemMetadata[] { };
}
- _cache.TryAdd(path, entries);
+ //_cache.TryAdd(path, entries);
+ _cache[path] = entries;
}
return entries;
@@ -74,13 +63,8 @@ namespace MediaBrowser.Controller.Providers
public List<FileSystemMetadata> GetFiles(string path)
{
- return GetFiles(path, false);
- }
-
- public List<FileSystemMetadata> GetFiles(string path, bool clearCache)
- {
var list = new List<FileSystemMetadata>();
- var items = GetFileSystemEntries(path, clearCache);
+ var items = GetFileSystemEntries(path);
foreach (var item in items)
{
if (!item.IsDirectory)
@@ -100,7 +84,8 @@ namespace MediaBrowser.Controller.Providers
if (file != null && file.Exists)
{
- _fileCache.TryAdd(path, file);
+ //_fileCache.TryAdd(path, file);
+ _fileCache[path] = file;
}
else
{
@@ -111,5 +96,24 @@ namespace MediaBrowser.Controller.Providers
return file;
//return _fileSystem.GetFileInfo(path);
}
+
+ public List<string> GetFilePaths(string path)
+ {
+ return GetFilePaths(path, false);
+ }
+
+ public List<string> GetFilePaths(string path, bool clearCache)
+ {
+ List<string> result;
+ if (clearCache || !_filePathCache.TryGetValue(path, out result))
+ {
+ result = _fileSystem.GetFilePaths(path).ToList();
+
+ _filePathCache[path] = result;
+ }
+
+ return result;
+ }
+
}
}
diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs
index 6f864f4be2..0b4574f6e5 100644
--- a/MediaBrowser.Controller/Providers/IDirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs
@@ -8,5 +8,8 @@ namespace MediaBrowser.Controller.Providers
FileSystemMetadata[] GetFileSystemEntries(string path);
List<FileSystemMetadata> GetFiles(string path);
FileSystemMetadata GetFile(string path);
+
+ List<string> GetFilePaths(string path);
+ List<string> GetFilePaths(string path, bool clearCache);
}
} \ No newline at end of file
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index 56a2c271f9..2901f51d58 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -9,6 +9,7 @@ using System.Globalization;
using System.Linq;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
+using MediaBrowser.Controller.Entities.Movies;
namespace MediaBrowser.LocalMetadata.Images
{
@@ -131,35 +132,91 @@ namespace MediaBrowser.LocalMetadata.Images
PopulatePrimaryImages(item, images, files, imagePrefix, isInMixedFolder);
- AddImage(files, images, "logo", imagePrefix, isInMixedFolder, ImageType.Logo);
- AddImage(files, images, "clearart", imagePrefix, isInMixedFolder, ImageType.Art);
+ var added = false;
+ var isEpisode = item is Episode;
+ var isSong = item.GetType() == typeof(Audio);
+ var isGame = item is Game;
+ var isPerson = item is Person;
+
+ // Logo
+ if (!isEpisode && !isSong && !isPerson)
+ {
+ added = AddImage(files, images, "logo", imagePrefix, isInMixedFolder, ImageType.Logo);
+ if (!added)
+ {
+ added = AddImage(files, images, "clearlogo", imagePrefix, isInMixedFolder, ImageType.Logo);
+ }
+ }
+
+ // Art
+ if (!isEpisode && !isSong && !isPerson)
+ {
+ AddImage(files, images, "clearart", imagePrefix, isInMixedFolder, ImageType.Art);
+ }
// For music albums, prefer cdart before disc
if (item is MusicAlbum)
{
- AddImage(files, images, "cdart", imagePrefix, isInMixedFolder, ImageType.Disc);
- AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc);
+ added = AddImage(files, images, "cdart", imagePrefix, isInMixedFolder, ImageType.Disc);
+
+ if (!added)
+ {
+ added = AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc);
+ }
}
- else
+ else if (isGame || item is Video || item is BoxSet)
{
- AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc);
- AddImage(files, images, "cdart", imagePrefix, isInMixedFolder, ImageType.Disc);
+ added = AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc);
+
+ if (!added)
+ {
+ added = AddImage(files, images, "cdart", imagePrefix, isInMixedFolder, ImageType.Disc);
+ }
+
+ if (!added)
+ {
+ added = AddImage(files, images, "discart", imagePrefix, isInMixedFolder, ImageType.Disc);
+ }
}
- AddImage(files, images, "box", imagePrefix, isInMixedFolder, ImageType.Box);
- AddImage(files, images, "back", imagePrefix, isInMixedFolder, ImageType.BoxRear);
- AddImage(files, images, "boxrear", imagePrefix, isInMixedFolder, ImageType.BoxRear);
- AddImage(files, images, "menu", imagePrefix, isInMixedFolder, ImageType.Menu);
+ if (isGame)
+ {
+ AddImage(files, images, "box", imagePrefix, isInMixedFolder, ImageType.Box);
+ AddImage(files, images, "menu", imagePrefix, isInMixedFolder, ImageType.Menu);
+
+ added = AddImage(files, images, "back", imagePrefix, isInMixedFolder, ImageType.BoxRear);
+
+ if (!added)
+ {
+ added = AddImage(files, images, "boxrear", imagePrefix, isInMixedFolder, ImageType.BoxRear);
+ }
+ }
// Banner
- AddImage(files, images, "banner", imagePrefix, isInMixedFolder, ImageType.Banner);
+ if (!isEpisode && !isSong && !isPerson)
+ {
+ AddImage(files, images, "banner", imagePrefix, isInMixedFolder, ImageType.Banner);
+ }
// Thumb
- AddImage(files, images, "landscape", imagePrefix, isInMixedFolder, ImageType.Thumb);
- AddImage(files, images, "thumb", imagePrefix, isInMixedFolder, ImageType.Thumb);
+ if (!isEpisode && !isSong && !isPerson)
+ {
+ added = AddImage(files, images, "landscape", imagePrefix, isInMixedFolder, ImageType.Thumb);
+ if (!added)
+ {
+ added = AddImage(files, images, "thumb", imagePrefix, isInMixedFolder, ImageType.Thumb);
+ }
+ }
+
+ if (!isEpisode && !isSong && !isPerson)
+ {
+ PopulateBackdrops(item, images, files, imagePrefix, isInMixedFolder, directoryService);
+ }
- PopulateBackdrops(item, images, files, imagePrefix, isInMixedFolder, directoryService);
- PopulateScreenshots(images, files, imagePrefix, isInMixedFolder);
+ if (item is IHasScreenshots)
+ {
+ PopulateScreenshots(images, files, imagePrefix, isInMixedFolder);
+ }
}
private static readonly string[] CommonImageFileNames = new[]
@@ -232,19 +289,28 @@ namespace MediaBrowser.LocalMetadata.Images
var fileNameWithoutExtension = item.FileNameWithoutExtension;
if (!string.IsNullOrEmpty(fileNameWithoutExtension))
{
- AddImage(files, images, fileNameWithoutExtension, ImageType.Primary);
+ if (AddImage(files, images, fileNameWithoutExtension, ImageType.Primary))
+ {
+ return;
+ }
}
foreach (var name in imageFileNames)
{
- AddImage(files, images, imagePrefix + name, ImageType.Primary);
+ if (AddImage(files, images, imagePrefix + name, ImageType.Primary))
+ {
+ return;
+ }
}
if (!isInMixedFolder)
{
foreach (var name in imageFileNames)
{
- AddImage(files, images, name, ImageType.Primary);
+ if (AddImage(files, images, name, ImageType.Primary))
+ {
+ return;
+ }
}
}
}
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index 259f423918..a3800e5c1c 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -226,7 +226,19 @@ namespace MediaBrowser.LocalMetadata.Savers
if (wasHidden || ConfigurationManager.Configuration.SaveMetadataHidden)
{
- FileSystem.SetHidden(path, true);
+ SetHidden(path, true);
+ }
+ }
+
+ private void SetHidden(string path, bool hidden)
+ {
+ try
+ {
+ FileSystem.SetHidden(path, hidden);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error("Error setting hidden attribute on {0} - {1}", path, ex.Message);
}
}
diff --git a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
index 86eb40b975..de8a59a3d9 100644
--- a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
+++ b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
@@ -18,7 +18,6 @@ namespace MediaBrowser.Model.Configuration
SaveImagePathsInNfo = true;
EnablePathSubstitution = true;
- EnableExtraThumbsDuplication = true;
}
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index cf4cd99258..37d266ac09 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -1335,21 +1335,15 @@ namespace MediaBrowser.Model.Dlna
return true;
}
- if (!maxBitrate.HasValue)
- {
- _logger.Info("Cannot " + playMethod + " due to unknown supported bitrate");
- return false;
- }
+ var requestedMaxBitrate = maxBitrate ?? 1000000;
- if (!item.Bitrate.HasValue)
- {
- _logger.Info("Cannot " + playMethod + " due to unknown content bitrate");
- return false;
- }
+ // If we don't know the bitrate, then force a transcode if requested max bitrate is under 40 mbps
+ var itemBitrate = item.Bitrate ??
+ 40000000;
- if (item.Bitrate.Value > maxBitrate.Value)
+ if (itemBitrate > requestedMaxBitrate)
{
- _logger.Info("Bitrate exceeds " + playMethod + " limit: media bitrate: {0}, max bitrate: {1}", item.Bitrate.Value.ToString(CultureInfo.InvariantCulture), maxBitrate.Value.ToString(CultureInfo.InvariantCulture));
+ _logger.Info("Bitrate exceeds " + playMethod + " limit: media bitrate: {0}, max bitrate: {1}", item.Bitrate.Value.ToString(CultureInfo.InvariantCulture), requestedMaxBitrate.ToString(CultureInfo.InvariantCulture));
return false;
}
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 8bad650b53..ba975db442 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -75,7 +75,7 @@ namespace MediaBrowser.Model.Dto
public bool? CanDownload { get; set; }
public bool? HasSubtitles { get; set; }
-
+
public string PreferredMetadataLanguage { get; set; }
public string PreferredMetadataCountryCode { get; set; }
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 747528cbfe..8a402e6f45 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -46,13 +46,13 @@ namespace MediaBrowser.Model.Entities
{
get
{
- if (!string.IsNullOrEmpty(Title))
- {
- return AddLanguageIfNeeded(Title);
- }
-
if (Type == MediaStreamType.Audio)
{
+ //if (!string.IsNullOrEmpty(Title))
+ //{
+ // return AddLanguageIfNeeded(Title);
+ //}
+
List<string> attributes = new List<string>();
if (!string.IsNullOrEmpty(Language))
@@ -84,8 +84,32 @@ namespace MediaBrowser.Model.Entities
return string.Join(" ", attributes.ToArray(attributes.Count));
}
+ if (Type == MediaStreamType.Video)
+ {
+ List<string> attributes = new List<string>();
+
+ var resolutionText = GetResolutionText();
+
+ if (!string.IsNullOrEmpty(resolutionText))
+ {
+ attributes.Add(resolutionText);
+ }
+
+ if (!string.IsNullOrEmpty(Codec))
+ {
+ attributes.Add(Codec.ToUpper());
+ }
+
+ return string.Join(" ", attributes.ToArray(attributes.Count));
+ }
+
if (Type == MediaStreamType.Subtitle)
{
+ //if (!string.IsNullOrEmpty(Title))
+ //{
+ // return AddLanguageIfNeeded(Title);
+ //}
+
List<string> attributes = new List<string>();
if (!string.IsNullOrEmpty(Language))
@@ -121,6 +145,54 @@ namespace MediaBrowser.Model.Entities
}
}
+ private string GetResolutionText()
+ {
+ var i = this;
+
+ if (i.Width.HasValue)
+ {
+ if (i.Width >= 3800)
+ {
+ return "4K";
+ }
+ if (i.Width >= 2500)
+ {
+ if (i.IsInterlaced)
+ {
+ return "1440I";
+ }
+ return "1440P";
+ }
+ if (i.Width >= 1900)
+ {
+ if (i.IsInterlaced)
+ {
+ return "1080I";
+ }
+ return "1080P";
+ }
+ if (i.Width >= 1260)
+ {
+ if (i.IsInterlaced)
+ {
+ return "720I";
+ }
+ return "720P";
+ }
+ if (i.Width >= 700)
+ {
+
+ if (i.IsInterlaced)
+ {
+ return "480I";
+ }
+ return "480P";
+ }
+
+ }
+ return null;
+ }
+
private string AddLanguageIfNeeded(string title)
{
if (!string.IsNullOrEmpty(Language) &&
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index f177233f9b..75edf05aa8 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -47,6 +47,7 @@ namespace MediaBrowser.Model.LiveTv
public bool EnableStreamLooping { get; set; }
public bool EnableNewHdhrChannelIds { get; set; }
public string Source { get; set; }
+ public int TunerCount { get; set; }
public TunerHostInfo()
{
diff --git a/MediaBrowser.Model/Session/GeneralCommandType.cs b/MediaBrowser.Model/Session/GeneralCommandType.cs
index 8dd0c29e43..616d5f9b41 100644
--- a/MediaBrowser.Model/Session/GeneralCommandType.cs
+++ b/MediaBrowser.Model/Session/GeneralCommandType.cs
@@ -39,6 +39,7 @@
ChannelDown = 31,
SetMaxStreamingBitrate = 31,
Guide = 32,
- ToggleStats = 33
+ ToggleStats = 33,
+ PlayMediaSource = 34
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Session/PlayRequest.cs b/MediaBrowser.Model/Session/PlayRequest.cs
index 5db5e90cb7..d50cb59533 100644
--- a/MediaBrowser.Model/Session/PlayRequest.cs
+++ b/MediaBrowser.Model/Session/PlayRequest.cs
@@ -1,4 +1,5 @@
-
+using MediaBrowser.Model.Services;
+
namespace MediaBrowser.Model.Session
{
/// <summary>
@@ -10,18 +11,21 @@ namespace MediaBrowser.Model.Session
/// Gets or sets the item ids.
/// </summary>
/// <value>The item ids.</value>
+ [ApiMember(Name = "ItemIds", Description = "The ids of the items to play, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
public string[] ItemIds { get; set; }
/// <summary>
/// Gets or sets the start position ticks that the first item should be played at
/// </summary>
/// <value>The start position ticks.</value>
+ [ApiMember(Name = "StartPositionTicks", Description = "The starting position of the first item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public long? StartPositionTicks { get; set; }
/// <summary>
/// Gets or sets the play command.
/// </summary>
/// <value>The play command.</value>
+ [ApiMember(Name = "PlayCommand", Description = "The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
public PlayCommand PlayCommand { get; set; }
/// <summary>
@@ -29,5 +33,9 @@ namespace MediaBrowser.Model.Session
/// </summary>
/// <value>The controlling user identifier.</value>
public string ControllingUserId { get; set; }
+
+ public int? SubtitleStreamIndex { get; set; }
+ public int? AudioStreamIndex { get; set; }
+ public string MediaSourceId { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 7fdbdbcc7a..4bf5e9208b 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -256,7 +256,7 @@ namespace MediaBrowser.Providers.Manager
if (_config.Configuration.SaveMetadataHidden)
{
- _fileSystem.SetHidden(path, true);
+ SetHidden(path, true);
}
}
finally
@@ -266,6 +266,18 @@ namespace MediaBrowser.Providers.Manager
}
}
+ private void SetHidden(string path, bool hidden)
+ {
+ try
+ {
+ _fileSystem.SetHidden(path, hidden);
+ }
+ catch (Exception ex)
+ {
+ _logger.Error("Error setting hidden attribute on {0} - {1}", path, ex.Message);
+ }
+ }
+
/// <summary>
/// Gets the save paths.
/// </summary>
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index af03e21b2d..4e72240f29 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -27,6 +27,7 @@ namespace MediaBrowser.Providers.Manager
protected readonly IFileSystem FileSystem;
protected readonly IUserDataManager UserDataManager;
protected readonly ILibraryManager LibraryManager;
+ private readonly SubtitleResolver _subtitleResolver;
protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager)
{
@@ -36,6 +37,8 @@ namespace MediaBrowser.Providers.Manager
FileSystem = fileSystem;
UserDataManager = userDataManager;
LibraryManager = libraryManager;
+
+ _subtitleResolver = new SubtitleResolver(BaseItem.LocalizationManager, fileSystem);
}
public async Task<ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
@@ -76,8 +79,7 @@ namespace MediaBrowser.Providers.Manager
if (video != null && !video.IsPlaceHolder)
{
requiresRefresh = !video.SubtitleFiles
- .SequenceEqual(SubtitleResolver.GetSubtitleFiles(video, refreshOptions.DirectoryService, FileSystem, false)
- .OrderBy(i => i), StringComparer.OrdinalIgnoreCase);
+ .SequenceEqual(_subtitleResolver.GetExternalSubtitleFiles(video, refreshOptions.DirectoryService, false), StringComparer.Ordinal);
}
}
}
@@ -124,7 +126,7 @@ namespace MediaBrowser.Providers.Manager
var providers = GetProviders(item, refreshOptions, isFirstRefresh, requiresRefresh)
.ToList();
- if (providers.Count > 0 || isFirstRefresh)
+ if (providers.Count > 0 || isFirstRefresh || requiresRefresh)
{
if (item.BeforeMetadataRefresh())
{
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index a6a363ffdf..1582385571 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -229,7 +229,7 @@ namespace MediaBrowser.Providers.MediaInfo
extractDuringScan = libraryOptions.ExtractChapterImagesDuringLibraryScan;
}
- await _encodingManager.RefreshChapterImages(video, chapters, extractDuringScan, false, cancellationToken).ConfigureAwait(false);
+ await _encodingManager.RefreshChapterImages(video, options.DirectoryService, chapters, extractDuringScan, false, cancellationToken).ConfigureAwait(false);
_chapterManager.SaveChapters(video.Id.ToString(), chapters);
}
@@ -472,7 +472,7 @@ namespace MediaBrowser.Providers.MediaInfo
var subtitleResolver = new SubtitleResolver(_localization, _fileSystem);
var startIndex = currentStreams.Count == 0 ? 0 : (currentStreams.Select(i => i.Index).Max() + 1);
- var externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, startIndex, options.DirectoryService, false).ToList();
+ var externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, startIndex, options.DirectoryService, false);
var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.Default ||
options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh;
@@ -497,7 +497,7 @@ namespace MediaBrowser.Providers.MediaInfo
// Rescan
if (downloadedLanguages.Count > 0)
{
- externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, startIndex, options.DirectoryService, true).ToList();
+ externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, startIndex, options.DirectoryService, true);
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
index a2c10d6a86..4e264bd223 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
@@ -16,29 +16,91 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly ILocalizationManager _localization;
private readonly IFileSystem _fileSystem;
+ private string[] SubtitleExtensions = new[]
+ {
+ ".srt",
+ ".ssa",
+ ".ass",
+ ".sub",
+ ".smi",
+ ".sami",
+ ".vtt"
+ };
+
public SubtitleResolver(ILocalizationManager localization, IFileSystem fileSystem)
{
_localization = localization;
_fileSystem = fileSystem;
}
- public IEnumerable<MediaStream> GetExternalSubtitleStreams(Video video,
+ public List<MediaStream> GetExternalSubtitleStreams(Video video,
int startIndex,
IDirectoryService directoryService,
bool clearCache)
{
- var files = GetSubtitleFiles(video, directoryService, _fileSystem, clearCache);
-
var streams = new List<MediaStream>();
- var videoFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(video.Path);
+ GetExternalSubtitleStreams(streams, video.ContainingFolderPath, video.Path, startIndex, directoryService, clearCache);
+
+ startIndex += streams.Count;
+
+ try
+ {
+ GetExternalSubtitleStreams(streams, video.GetInternalMetadataPath(), video.Path, startIndex, directoryService, clearCache);
+ }
+ catch (IOException)
+ {
+
+ }
+
+ return streams;
+ }
+
+ public List<string> GetExternalSubtitleFiles(Video video,
+ IDirectoryService directoryService,
+ bool clearCache)
+ {
+ var streams = GetExternalSubtitleStreams(video, 0, directoryService, clearCache);
+
+ var list = new List<string>();
+
+ foreach (var stream in streams)
+ {
+ list.Add(stream.Path);
+ }
+
+ return list;
+ }
+
+ private void GetExternalSubtitleStreams(List<MediaStream> streams, string folder,
+ string videoPath,
+ int startIndex,
+ IDirectoryService directoryService,
+ bool clearCache)
+ {
+ var videoFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(videoPath);
videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoFileNameWithoutExtension);
+ var files = directoryService.GetFilePaths(folder, clearCache);
+
foreach (var fullName in files)
{
+ var extension = Path.GetExtension(fullName);
+
+ if (!SubtitleExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
var fileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(fullName);
fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fileNameWithoutExtension);
+ if (!string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) &&
+ !fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
var codec = Path.GetExtension(fullName).ToLower().TrimStart('.');
if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase))
@@ -98,8 +160,6 @@ namespace MediaBrowser.Providers.MediaInfo
});
}
}
-
- return streams;
}
private string NormalizeFilenameForSubtitleComparison(string filename)
@@ -115,48 +175,5 @@ namespace MediaBrowser.Providers.MediaInfo
return filename;
}
-
- private static IEnumerable<string> SubtitleExtensions
- {
- get
- {
- return new[] { ".srt", ".ssa", ".ass", ".sub", ".smi", ".sami", ".vtt" };
- }
- }
-
- public static IEnumerable<string> GetSubtitleFiles(Video video, IDirectoryService directoryService, IFileSystem fileSystem, bool clearCache)
- {
- var containingPath = video.ContainingFolderPath;
-
- if (string.IsNullOrEmpty(containingPath))
- {
- throw new ArgumentException(string.Format("Cannot search for items that don't have a path: {0} {1}", video.Name, video.Id));
- }
-
- var files = fileSystem.GetFilePaths(containingPath, clearCache);
-
- var videoFileNameWithoutExtension = fileSystem.GetFileNameWithoutExtension(video.Path);
-
- return files.Where(i =>
- {
- var extension = Path.GetExtension(i);
-
- if (SubtitleExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
- {
- var fileNameWithoutExtension = fileSystem.GetFileNameWithoutExtension(i);
-
- if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
- });
- }
}
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
index 74bfa6e039..1ef420dddc 100644
--- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
@@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Omdb
list.Add(new RemoteImageInfo
{
ProviderName = Name,
- Url = string.Format("https://img.omdbapi.com/?i={0}&apikey=82e83907", imdbId)
+ Url = string.Format("https://img.omdbapi.com/?i={0}&apikey=fe53f97e", imdbId)
});
}
}
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index fe655759e1..6a9b7136c0 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -16,8 +16,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.IO;
namespace MediaBrowser.Providers.Subtitles
@@ -30,17 +30,19 @@ namespace MediaBrowser.Providers.Subtitles
private readonly ILibraryMonitor _monitor;
private readonly ILibraryManager _libraryManager;
private readonly IMediaSourceManager _mediaSourceManager;
+ private readonly IServerConfigurationManager _config;
public event EventHandler<SubtitleDownloadEventArgs> SubtitlesDownloaded;
public event EventHandler<SubtitleDownloadFailureEventArgs> SubtitleDownloadFailure;
- public SubtitleManager(ILogger logger, IFileSystem fileSystem, ILibraryMonitor monitor, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager)
+ public SubtitleManager(ILogger logger, IFileSystem fileSystem, ILibraryMonitor monitor, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager, IServerConfigurationManager config)
{
_logger = logger;
_fileSystem = fileSystem;
_monitor = monitor;
_libraryManager = libraryManager;
_mediaSourceManager = mediaSourceManager;
+ _config = config;
}
public void AddParts(IEnumerable<ISubtitleProvider> subtitleProviders)
@@ -102,6 +104,11 @@ namespace MediaBrowser.Providers.Subtitles
return results.SelectMany(i => i).ToArray();
}
+ private SubtitleOptions GetOptions()
+ {
+ return _config.GetConfiguration<SubtitleOptions>("subtitles");
+ }
+
public async Task DownloadSubtitles(Video video,
string subtitleId,
CancellationToken cancellationToken)
@@ -109,49 +116,37 @@ namespace MediaBrowser.Providers.Subtitles
var parts = subtitleId.Split(new[] { '_' }, 2);
var provider = GetProvider(parts.First());
+ var saveInMediaFolder = video.IsSaveLocalMetadataEnabled();
+
try
{
var response = await GetRemoteSubtitles(subtitleId, cancellationToken).ConfigureAwait(false);
using (var stream = response.Stream)
{
- var savePath = Path.Combine(_fileSystem.GetDirectoryName(video.Path),
- _fileSystem.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLower());
-
- if (response.IsForced)
+ using (var memoryStream = new MemoryStream())
{
- savePath += ".forced";
- }
-
- savePath += "." + response.Format.ToLower();
+ await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
+ memoryStream.Position = 0;
- _logger.Info("Saving subtitles to {0}", savePath);
+ var savePaths = new List<string>();
+ var saveFileName = _fileSystem.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLower();
- _monitor.ReportFileSystemChangeBeginning(savePath);
+ if (response.IsForced)
+ {
+ saveFileName += ".forced";
+ }
- try
- {
- //var isText = MediaStream.IsTextFormat(response.Format);
+ saveFileName += "." + response.Format.ToLower();
- using (var fs = _fileSystem.GetFileStream(savePath, FileOpenMode.Create, FileAccessMode.Write,
- FileShareMode.Read, true))
+ if (saveInMediaFolder)
{
- await stream.CopyToAsync(fs).ConfigureAwait(false);
+ savePaths.Add(Path.Combine(video.ContainingFolderPath, saveFileName));
}
- EventHelper.FireEventIfNotNull(SubtitlesDownloaded, this, new SubtitleDownloadEventArgs
- {
- Item = video,
- Format = response.Format,
- Language = response.Language,
- IsForced = response.IsForced,
- Provider = provider.Name
+ savePaths.Add(Path.Combine(video.GetInternalMetadataPath(), saveFileName));
- }, _logger);
- }
- finally
- {
- _monitor.ReportFileSystemChangeComplete(savePath, false);
+ await TrySaveToFiles(memoryStream, savePaths).ConfigureAwait(false);
}
}
}
@@ -173,6 +168,46 @@ namespace MediaBrowser.Providers.Subtitles
}
}
+ private async Task TrySaveToFiles(Stream stream, List<string> savePaths)
+ {
+ Exception exceptionToThrow = null;
+
+ foreach (var savePath in savePaths)
+ {
+ _logger.Info("Saving subtitles to {0}", savePath);
+
+ _monitor.ReportFileSystemChangeBeginning(savePath);
+
+ try
+ {
+ using (var fs = _fileSystem.GetFileStream(savePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
+ {
+ await stream.CopyToAsync(fs).ConfigureAwait(false);
+ }
+
+ return;
+ }
+ catch (Exception ex)
+ {
+ if (exceptionToThrow == null)
+ {
+ exceptionToThrow = ex;
+ }
+ }
+ finally
+ {
+ _monitor.ReportFileSystemChangeComplete(savePath, false);
+ }
+
+ stream.Position = 0;
+ }
+
+ if (exceptionToThrow != null)
+ {
+ throw exceptionToThrow;
+ }
+ }
+
public Task<RemoteSubtitleInfo[]> SearchSubtitles(Video video, string language, bool? isPerfectMatch, CancellationToken cancellationToken)
{
if (video.LocationType != LocationType.FileSystem ||
diff --git a/MediaBrowser.Server.Mono/ImageEncoderHelper.cs b/MediaBrowser.Server.Mono/ImageEncoderHelper.cs
index 4f8451c0d1..49955ad652 100644
--- a/MediaBrowser.Server.Mono/ImageEncoderHelper.cs
+++ b/MediaBrowser.Server.Mono/ImageEncoderHelper.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Server.Startup.Common
}
catch (Exception ex)
{
- logger.Error("Skia not available. Will try next image processor. {0}", ex.Message);
+ logger.Info("Skia not available. Will try next image processor. {0}", ex.Message);
}
try
@@ -41,7 +41,7 @@ namespace MediaBrowser.Server.Startup.Common
}
catch
{
- logger.Error("ImageMagick not available. Will try next image processor.");
+ logger.Info("ImageMagick not available. Will try next image processor.");
}
}
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index a9e5d3ca57..dfd0714471 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -61,8 +61,8 @@
<Reference Include="SimpleInjector, Version=4.0.12.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.4.0.12\lib\net45\SimpleInjector.dll</HintPath>
</Reference>
- <Reference Include="SkiaSharp, Version=1.59.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
- <HintPath>..\packages\SkiaSharp.1.59.2\lib\net45\SkiaSharp.dll</HintPath>
+ <Reference Include="SkiaSharp, Version=1.58.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
+ <HintPath>..\packages\SkiaSharp.1.58.1\lib\net45\SkiaSharp.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config
index 4f2324c21b..e7aec97b6c 100644
--- a/MediaBrowser.Server.Mono/packages.config
+++ b/MediaBrowser.Server.Mono/packages.config
@@ -4,7 +4,7 @@
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
<package id="SharpCompress" version="0.18.2" targetFramework="net46" />
<package id="SimpleInjector" version="4.0.12" targetFramework="net46" />
- <package id="SkiaSharp" version="1.59.2" targetFramework="net46" />
+ <package id="SkiaSharp" version="1.58.1" targetFramework="net46" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />
<package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.8" targetFramework="net46" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 33f858b004..f479db46fb 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -83,8 +83,8 @@
<Reference Include="SimpleInjector, Version=4.0.12.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleInjector.4.0.12\lib\net45\SimpleInjector.dll</HintPath>
</Reference>
- <Reference Include="SkiaSharp, Version=1.59.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
- <HintPath>..\packages\SkiaSharp.1.59.2\lib\net45\SkiaSharp.dll</HintPath>
+ <Reference Include="SkiaSharp, Version=1.58.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
+ <HintPath>..\packages\SkiaSharp.1.58.1\lib\net45\SkiaSharp.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
@@ -161,11 +161,11 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
- <Content Include="..\packages\SkiaSharp.1.59.2\runtimes\win7-x64\native\libSkiaSharp.dll">
+ <Content Include="..\packages\SkiaSharp.1.58.1\runtimes\win7-x64\native\libSkiaSharp.dll">
<Link>x64\libSkiaSharp.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="..\packages\SkiaSharp.1.59.2\runtimes\win7-x86\native\libSkiaSharp.dll">
+ <Content Include="..\packages\SkiaSharp.1.58.1\runtimes\win7-x86\native\libSkiaSharp.dll">
<Link>x86\libSkiaSharp.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 805c7af62e..e40a3ab15c 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -3,7 +3,7 @@
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
<package id="SharpCompress" version="0.18.2" targetFramework="net462" />
<package id="SimpleInjector" version="4.0.12" targetFramework="net462" />
- <package id="SkiaSharp" version="1.59.2" targetFramework="net462" />
+ <package id="SkiaSharp" version="1.58.1" targetFramework="net462" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net462" />
<package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.8" targetFramework="net462" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index c1c2e7d9dc..689f175f37 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -243,13 +243,13 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
// Support Tmdb
- // http://www.themoviedb.org/movie/36557
+ // https://www.themoviedb.org/movie/30287-fallo
var srch = MovieDbParserSearchString;
var index = xml.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
- var tmdbId = xml.Substring(index + srch.Length).TrimEnd('/');
+ var tmdbId = xml.Substring(index + srch.Length).TrimEnd('/').Split('-')[0];
int value;
if (!string.IsNullOrWhiteSpace(tmdbId) && int.TryParse(tmdbId, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 41c376ddf0..d32081458b 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -229,7 +229,19 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (wasHidden || ConfigurationManager.Configuration.SaveMetadataHidden)
{
- FileSystem.SetHidden(path, true);
+ SetHidden(path, true);
+ }
+ }
+
+ private void SetHidden(string path, bool hidden)
+ {
+ try
+ {
+ FileSystem.SetHidden(path, hidden);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error("Error setting hidden attribute on {0} - {1}", path, ex.Message);
}
}
diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs
index a4be24ebfe..6b4f67b0b5 100644
--- a/RSSDP/SsdpCommunicationsServer.cs
+++ b/RSSDP/SsdpCommunicationsServer.cs
@@ -366,6 +366,12 @@ namespace Rssdp.Infrastructure
{
foreach (var address in _networkManager.GetLocalIpAddresses())
{
+ if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
+ {
+ // Not supported ?
+ continue;
+ }
+
try
{
sockets.Add(_SocketFactory.CreateSsdpUdpSocket(address, _LocalPort));