diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs
index 3ed4f650f7..7d14e521f3 100644
--- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Common.Implementations/IO/ManagedFileSystem.cs
@@ -392,10 +392,27 @@ namespace Emby.Common.Implementations.IO
if (_supportsAsyncFileStreams && isAsync)
{
- return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144, true);
+ return GetFileStream(path, mode, access, share, FileOpenOptions.Asynchronous);
}
- return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144);
+ return GetFileStream(path, mode, access, share, FileOpenOptions.None);
+ }
+
+ public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ return _sharpCifsFileSystem.GetFileStream(path, mode, access, share);
+ }
+
+ var defaultBufferSize = 4096;
+ return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), defaultBufferSize, GetFileOptions(fileOpenOptions));
+ }
+
+ private FileOptions GetFileOptions(FileOpenOptions mode)
+ {
+ var val = (int)mode;
+ return (FileOptions)val;
}
private FileMode GetFileMode(FileOpenMode mode)
@@ -501,6 +518,49 @@ namespace Emby.Common.Implementations.IO
}
}
+ public void SetAttributes(string path, bool isHidden, bool isReadOnly)
+ {
+ if (_sharpCifsFileSystem.IsEnabledForPath(path))
+ {
+ _sharpCifsFileSystem.SetAttributes(path, isHidden, isReadOnly);
+ return;
+ }
+
+ var info = GetFileInfo(path);
+
+ if (!info.Exists)
+ {
+ return;
+ }
+
+ if (info.IsReadOnly == isReadOnly && info.IsHidden == isHidden)
+ {
+ return;
+ }
+
+ var attributes = File.GetAttributes(path);
+
+ if (isReadOnly)
+ {
+ attributes = attributes | FileAttributes.ReadOnly;
+ }
+ else
+ {
+ attributes = RemoveAttribute(attributes, FileAttributes.ReadOnly);
+ }
+
+ if (isHidden)
+ {
+ attributes = attributes | FileAttributes.Hidden;
+ }
+ else
+ {
+ attributes = RemoveAttribute(attributes, FileAttributes.Hidden);
+ }
+
+ File.SetAttributes(path, attributes);
+ }
+
private static FileAttributes RemoveAttribute(FileAttributes attributes, FileAttributes attributesToRemove)
{
return attributes & ~attributesToRemove;
@@ -673,20 +733,7 @@ namespace Emby.Common.Implementations.IO
return;
}
- var fileInfo = GetFileInfo(path);
-
- if (fileInfo.Exists)
- {
- if (fileInfo.IsHidden)
- {
- SetHidden(path, false);
- }
- if (fileInfo.IsReadOnly)
- {
- SetReadOnly(path, false);
- }
- }
-
+ SetAttributes(path, false, false);
File.Delete(path);
}
diff --git a/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs b/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs
index 0a407d64f5..64cac76230 100644
--- a/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs
+++ b/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs
@@ -53,6 +53,11 @@ namespace Emby.Common.Implementations.IO
if (separator == '/')
{
result = result.Replace('\\', '/');
+
+ if (result.StartsWith("smb:/", StringComparison.OrdinalIgnoreCase) && !result.StartsWith("smb://", StringComparison.OrdinalIgnoreCase))
+ {
+ result = result.Replace("smb:/", "smb://");
+ }
}
return result;
@@ -161,23 +166,38 @@ namespace Emby.Common.Implementations.IO
public void SetHidden(string path, bool isHidden)
{
var file = CreateSmbFile(path);
-
- var isCurrentlyHidden = file.IsHidden();
-
- if (isCurrentlyHidden && !isHidden)
- {
- file.SetAttributes(file.GetAttributes() & ~SmbFile.AttrReadonly);
- }
- else if (!isCurrentlyHidden && isHidden)
- {
- file.SetAttributes(file.GetAttributes() | SmbFile.AttrReadonly);
- }
+ SetHidden(file, isHidden);
}
public void SetReadOnly(string path, bool isReadOnly)
{
var file = CreateSmbFile(path);
+ SetReadOnly(file, isReadOnly);
+ }
+ public void SetAttributes(string path, bool isHidden, bool isReadOnly)
+ {
+ var file = CreateSmbFile(path);
+ SetHidden(file, isHidden);
+ SetReadOnly(file, isReadOnly);
+ }
+
+ private void SetHidden(SmbFile file, bool isHidden)
+ {
+ var isCurrentlyHidden = file.IsHidden();
+
+ if (isCurrentlyHidden && !isHidden)
+ {
+ file.SetAttributes(file.GetAttributes() & ~SmbFile.AttrHidden);
+ }
+ else if (!isCurrentlyHidden && isHidden)
+ {
+ file.SetAttributes(file.GetAttributes() | SmbFile.AttrHidden);
+ }
+ }
+
+ private void SetReadOnly(SmbFile file, bool isReadOnly)
+ {
var isCurrentlyReadOnly = !file.CanWrite();
if (isCurrentlyReadOnly && !isReadOnly)
diff --git a/Emby.Common.Implementations/project.json b/Emby.Common.Implementations/project.json
index 674101e8a7..ff60c740e8 100644
--- a/Emby.Common.Implementations/project.json
+++ b/Emby.Common.Implementations/project.json
@@ -45,7 +45,7 @@
"System.Net.Requests": "4.3.0",
"System.Xml.ReaderWriter": "4.3.0",
"System.Xml.XmlSerializer": "4.3.0",
- "System.Net.Http": "4.3.0",
+ "System.Net.Http": "4.3.2",
"System.Net.Primitives": "4.3.0",
"System.Net.Sockets": "4.3.0",
"System.Net.NetworkInformation": "4.3.0",
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index 8f62e6d27a..b09dba70c3 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -587,10 +587,7 @@ namespace Emby.Dlna
new DirectTvProfile(),
new DishHopperJoeyProfile(),
new DefaultProfile(),
- new PopcornHourProfile(),
- new VlcProfile(),
- new BubbleUpnpProfile(),
- new KodiProfile(),
+ new PopcornHourProfile()
};
foreach (var item in list)
diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj
index a8c05a5272..cae5a96362 100644
--- a/Emby.Dlna/Emby.Dlna.csproj
+++ b/Emby.Dlna/Emby.Dlna.csproj
@@ -79,13 +79,11 @@
-
-
@@ -105,7 +103,6 @@
-
@@ -153,13 +150,11 @@
-
-
@@ -178,7 +173,6 @@
-
diff --git a/Emby.Dlna/Profiles/BubbleUpnpProfile.cs b/Emby.Dlna/Profiles/BubbleUpnpProfile.cs
deleted file mode 100644
index b551bff2ae..0000000000
--- a/Emby.Dlna/Profiles/BubbleUpnpProfile.cs
+++ /dev/null
@@ -1,146 +0,0 @@
-using MediaBrowser.Model.Dlna;
-using System.Xml.Serialization;
-
-namespace Emby.Dlna.Profiles
-{
- [XmlRoot("Profile")]
- public class BubbleUpnpProfile : DefaultProfile
- {
- public BubbleUpnpProfile()
- {
- Name = "BubbleUPnp";
-
- Identification = new DeviceIdentification
- {
- ModelName = "BubbleUPnp",
-
- Headers = new[]
- {
- new HttpHeaderInfo {Name = "User-Agent", Value = "BubbleUPnp", Match = HeaderMatchType.Substring}
- }
- };
-
- TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
-
- new TranscodingProfile
- {
- Container = "ts",
- Type = DlnaProfileType.Video,
- AudioCodec = "aac",
- VideoCodec = "h264"
- },
-
- new TranscodingProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
-
- DirectPlayProfiles = new[]
- {
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Audio
- },
-
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Photo,
- }
- };
-
- ResponseProfiles = new ResponseProfile[] { };
-
- ContainerProfiles = new ContainerProfile[] { };
-
- CodecProfiles = new CodecProfile[] { };
-
- SubtitleProfiles = new[]
- {
- new SubtitleProfile
- {
- Format = "srt",
- Method = SubtitleDeliveryMethod.External,
- },
-
- new SubtitleProfile
- {
- Format = "sub",
- Method = SubtitleDeliveryMethod.External,
- },
-
- new SubtitleProfile
- {
- Format = "srt",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "ass",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "ssa",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "smi",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "dvdsub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "pgs",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "pgssub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "sub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- }
- };
- }
- }
-}
diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs
index e99b22f2d0..1413e89d2a 100644
--- a/Emby.Dlna/Profiles/DefaultProfile.cs
+++ b/Emby.Dlna/Profiles/DefaultProfile.cs
@@ -30,8 +30,8 @@ namespace Emby.Dlna.Profiles
MaxIconWidth = 48;
MaxIconHeight = 48;
- MaxStreamingBitrate = 30000000;
- MaxStaticBitrate = 30000000;
+ MaxStreamingBitrate = 40000000;
+ MaxStaticBitrate = 40000000;
MusicStreamingTranscodingBitrate = 192000;
EnableAlbumArtInDidl = false;
@@ -64,15 +64,13 @@ namespace Emby.Dlna.Profiles
{
new DirectPlayProfile
{
- Container = "m4v,ts,mpegts,mkv,avi,mpg,mpeg,mp4,mov",
- VideoCodec = "h264",
- AudioCodec = "aac,mp3,ac3",
+ Container = "m4v,mpegts,ts,3gp,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm,wtv,m2ts,dvr-ms",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
- Container = "mp3,wma,aac,wav,flac",
+ Container = "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac",
Type = DlnaProfileType.Audio
}
};
@@ -82,13 +80,61 @@ namespace Emby.Dlna.Profiles
new SubtitleProfile
{
Format = "srt",
- Method = SubtitleDeliveryMethod.Embed
+ Method = SubtitleDeliveryMethod.External,
+ },
+
+ new SubtitleProfile
+ {
+ Format = "sub",
+ Method = SubtitleDeliveryMethod.External,
},
new SubtitleProfile
{
Format = "srt",
- Method = SubtitleDeliveryMethod.External,
+ Method = SubtitleDeliveryMethod.Embed
+ },
+
+ new SubtitleProfile
+ {
+ Format = "ass",
+ Method = SubtitleDeliveryMethod.Embed
+ },
+
+ new SubtitleProfile
+ {
+ Format = "ssa",
+ Method = SubtitleDeliveryMethod.Embed
+ },
+
+ new SubtitleProfile
+ {
+ Format = "smi",
+ Method = SubtitleDeliveryMethod.Embed
+ },
+
+ new SubtitleProfile
+ {
+ Format = "dvdsub",
+ Method = SubtitleDeliveryMethod.Embed
+ },
+
+ new SubtitleProfile
+ {
+ Format = "pgs",
+ Method = SubtitleDeliveryMethod.Embed
+ },
+
+ new SubtitleProfile
+ {
+ Format = "pgssub",
+ Method = SubtitleDeliveryMethod.Embed
+ },
+
+ new SubtitleProfile
+ {
+ Format = "sub",
+ Method = SubtitleDeliveryMethod.Embed
}
};
diff --git a/Emby.Dlna/Profiles/KodiProfile.cs b/Emby.Dlna/Profiles/KodiProfile.cs
deleted file mode 100644
index dbcac6652c..0000000000
--- a/Emby.Dlna/Profiles/KodiProfile.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using MediaBrowser.Model.Dlna;
-using System.Xml.Serialization;
-
-namespace Emby.Dlna.Profiles
-{
- [XmlRoot("Profile")]
- public class KodiProfile : DefaultProfile
- {
- public KodiProfile()
- {
- Name = "Kodi";
-
- MaxStreamingBitrate = 100000000;
- MusicStreamingTranscodingBitrate = 1280000;
-
- TimelineOffsetSeconds = 5;
-
- Identification = new DeviceIdentification
- {
- ModelName = "Kodi",
-
- Headers = new[]
- {
- new HttpHeaderInfo {Name = "User-Agent", Value = "Kodi", Match = HeaderMatchType.Substring}
- }
- };
-
- TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
-
- new TranscodingProfile
- {
- Container = "ts",
- Type = DlnaProfileType.Video,
- AudioCodec = "aac",
- VideoCodec = "h264"
- },
-
- new TranscodingProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
-
- DirectPlayProfiles = new[]
- {
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Audio
- },
-
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Photo,
- }
- };
-
- ResponseProfiles = new ResponseProfile[] { };
-
- ContainerProfiles = new ContainerProfile[] { };
-
- CodecProfiles = new CodecProfile[] { };
-
- SubtitleProfiles = new[]
- {
- new SubtitleProfile
- {
- Format = "srt",
- Method = SubtitleDeliveryMethod.External,
- },
-
- new SubtitleProfile
- {
- Format = "sub",
- Method = SubtitleDeliveryMethod.External,
- },
-
- new SubtitleProfile
- {
- Format = "srt",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "ass",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "ssa",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "smi",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "dvdsub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "pgs",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "pgssub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "sub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- }
- };
- }
- }
-}
diff --git a/Emby.Dlna/Profiles/VlcProfile.cs b/Emby.Dlna/Profiles/VlcProfile.cs
deleted file mode 100644
index 2cd0e5cae7..0000000000
--- a/Emby.Dlna/Profiles/VlcProfile.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using MediaBrowser.Model.Dlna;
-using System.Xml.Serialization;
-
-namespace Emby.Dlna.Profiles
-{
- [XmlRoot("Profile")]
- public class VlcProfile : DefaultProfile
- {
- public VlcProfile()
- {
- Name = "Vlc";
-
-
- TimelineOffsetSeconds = 5;
-
- Identification = new DeviceIdentification
- {
- ModelName = "Vlc",
-
- Headers = new[]
- {
- new HttpHeaderInfo {Name = "User-Agent", Value = "vlc", Match = HeaderMatchType.Substring}
- }
- };
-
- TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
-
- new TranscodingProfile
- {
- Container = "ts",
- Type = DlnaProfileType.Video,
- AudioCodec = "aac",
- VideoCodec = "h264"
- },
-
- new TranscodingProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
-
- DirectPlayProfiles = new[]
- {
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Audio
- },
-
- new DirectPlayProfile
- {
- Container = "",
- Type = DlnaProfileType.Photo,
- }
- };
-
- ResponseProfiles = new ResponseProfile[] { };
-
- ContainerProfiles = new ContainerProfile[] { };
-
- CodecProfiles = new CodecProfile[] { };
-
- SubtitleProfiles = new[]
- {
- new SubtitleProfile
- {
- Format = "srt",
- Method = SubtitleDeliveryMethod.External,
- },
-
- new SubtitleProfile
- {
- Format = "sub",
- Method = SubtitleDeliveryMethod.External,
- },
-
- new SubtitleProfile
- {
- Format = "srt",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "ass",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "ssa",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "smi",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "dvdsub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "pgs",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "pgssub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- },
-
- new SubtitleProfile
- {
- Format = "sub",
- Method = SubtitleDeliveryMethod.Embed,
- DidlMode = "",
- }
- };
- }
- }
-}
diff --git a/Emby.Dlna/Profiles/Xml/BubbleUPnp.xml b/Emby.Dlna/Profiles/Xml/BubbleUPnp.xml
deleted file mode 100644
index 84bfa336a0..0000000000
--- a/Emby.Dlna/Profiles/Xml/BubbleUPnp.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
- BubbleUPnp
-
- BubbleUPnp
-
-
-
-
- Emby
- http://emby.media/
- Emby Server
- Emby
- Emby
- http://emby.media/
- false
- false
- false
- Audio,Photo,Video
- JPEG_SM
- 480
- 480
- 48
- 48
- 30000000
- 30000000
- 192000
-
- DMS-1.50
- 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
- 0
- false
- false
- false
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Emby.Dlna/Profiles/Xml/Default.xml b/Emby.Dlna/Profiles/Xml/Default.xml
index 6d39ac1da1..9c4e68d965 100644
--- a/Emby.Dlna/Profiles/Xml/Default.xml
+++ b/Emby.Dlna/Profiles/Xml/Default.xml
@@ -16,8 +16,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
@@ -29,8 +29,8 @@
false
-
-
+
+
@@ -45,7 +45,15 @@
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Emby.Dlna/Profiles/Xml/Denon AVR.xml b/Emby.Dlna/Profiles/Xml/Denon AVR.xml
index 9c6af71ed9..772e9a41c0 100644
--- a/Emby.Dlna/Profiles/Xml/Denon AVR.xml
+++ b/Emby.Dlna/Profiles/Xml/Denon AVR.xml
@@ -21,8 +21,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
@@ -45,7 +45,15 @@
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Emby.Dlna/Profiles/Xml/DirecTV HD-DVR.xml b/Emby.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
index bb0fd0bb23..381a9f6411 100644
--- a/Emby.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
+++ b/Emby.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
@@ -22,8 +22,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
index fc84965105..4eb67ae81b 100644
--- a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
+++ b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Kodi.xml b/Emby.Dlna/Profiles/Xml/Kodi.xml
deleted file mode 100644
index 286417d968..0000000000
--- a/Emby.Dlna/Profiles/Xml/Kodi.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
- Kodi
-
- Kodi
-
-
-
-
- Emby
- http://emby.media/
- Emby Server
- Emby
- Emby
- http://emby.media/
- false
- false
- false
- Audio,Photo,Video
- JPEG_SM
- 480
- 480
- 48
- 48
- 100000000
- 30000000
- 1280000
-
- DMS-1.50
- 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
- 5
- false
- false
- false
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml
index e48af3842c..a61fefcc8b 100644
--- a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml
+++ b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml
@@ -22,8 +22,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml b/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml
index 7f15181544..bd20112a8a 100644
--- a/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml
+++ b/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml
@@ -20,8 +20,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/MediaMonkey.xml b/Emby.Dlna/Profiles/Xml/MediaMonkey.xml
index 3d5b398969..325c2e8368 100644
--- a/Emby.Dlna/Profiles/Xml/MediaMonkey.xml
+++ b/Emby.Dlna/Profiles/Xml/MediaMonkey.xml
@@ -22,8 +22,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
@@ -51,7 +51,15 @@
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml b/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml
index 689f2813c9..1c58ab0c96 100644
--- a/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml
+++ b/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml b/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml
index 4da6fa3fa5..69bf74a987 100644
--- a/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml
+++ b/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml
@@ -16,8 +16,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml b/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml
index fbdc7bc4fc..6fbed05900 100644
--- a/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml
+++ b/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml
@@ -22,8 +22,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml b/Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml
index 2ca6ff605a..ae2e686b85 100644
--- a/Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml
+++ b/Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml
@@ -22,8 +22,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
index d3735a9ed4..576f5ca500 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
@@ -26,8 +26,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2014.xml b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2014.xml
index c5c62cb737..5a04afb3e4 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2014.xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2014.xml
@@ -26,8 +26,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2015.xml b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2015.xml
index fd0ff91a02..97f0e37907 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2015.xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2015.xml
@@ -24,8 +24,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2016.xml b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2016.xml
index 66c942bfe3..052bc80d86 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2016.xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2016.xml
@@ -24,8 +24,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
index 7113a45830..084fa9df01 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
@@ -24,8 +24,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml
index e5fe83f0f3..046282ba39 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml
index 8bbaefed9a..e30afa2af0 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml
index 4e51116a02..cff07f04c4 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml
index 002b31a27e..2d5794087d 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml
index 2067a1d45b..d61b986c2b 100644
--- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml
+++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony PlayStation 3.xml b/Emby.Dlna/Profiles/Xml/Sony PlayStation 3.xml
index bea72c4104..966ecc2c8f 100644
--- a/Emby.Dlna/Profiles/Xml/Sony PlayStation 3.xml
+++ b/Emby.Dlna/Profiles/Xml/Sony PlayStation 3.xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml b/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml
index 128e0cf1fc..6a818193b8 100644
--- a/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml
+++ b/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Vlc.xml b/Emby.Dlna/Profiles/Xml/Vlc.xml
deleted file mode 100644
index cd35f3f91a..0000000000
--- a/Emby.Dlna/Profiles/Xml/Vlc.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
- Vlc
-
- Vlc
-
-
-
-
- Emby
- http://emby.media/
- Emby Server
- Emby
- Emby
- http://emby.media/
- false
- false
- false
- Audio,Photo,Video
- JPEG_SM
- 480
- 480
- 48
- 48
- 30000000
- 30000000
- 192000
-
- DMS-1.50
- 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
- 5
- false
- false
- false
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Emby.Dlna/Profiles/Xml/WDTV Live.xml b/Emby.Dlna/Profiles/Xml/WDTV Live.xml
index acb9727034..71b3463187 100644
--- a/Emby.Dlna/Profiles/Xml/WDTV Live.xml
+++ b/Emby.Dlna/Profiles/Xml/WDTV Live.xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Xbox 360.xml b/Emby.Dlna/Profiles/Xml/Xbox 360.xml
index e46c52f4c8..3b7d2963f2 100644
--- a/Emby.Dlna/Profiles/Xml/Xbox 360.xml
+++ b/Emby.Dlna/Profiles/Xml/Xbox 360.xml
@@ -24,8 +24,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/Xbox One.xml b/Emby.Dlna/Profiles/Xml/Xbox One.xml
index cffc386b1c..423327a389 100644
--- a/Emby.Dlna/Profiles/Xml/Xbox One.xml
+++ b/Emby.Dlna/Profiles/Xml/Xbox One.xml
@@ -23,8 +23,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
diff --git a/Emby.Dlna/Profiles/Xml/foobar2000.xml b/Emby.Dlna/Profiles/Xml/foobar2000.xml
index 192ba5a300..febc12a8fa 100644
--- a/Emby.Dlna/Profiles/Xml/foobar2000.xml
+++ b/Emby.Dlna/Profiles/Xml/foobar2000.xml
@@ -22,8 +22,8 @@
480
48
48
- 30000000
- 30000000
+ 40000000
+ 40000000
192000
DMS-1.50
@@ -51,7 +51,15 @@
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
index 500f57aade..f603c49509 100644
--- a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
+++ b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
@@ -105,17 +105,6 @@ namespace Emby.Drawing.ImageMagick
}
}
- public void CropWhiteSpace(string inputPath, string outputPath)
- {
- CheckDisposed();
-
- using (var wand = new MagickWand(inputPath))
- {
- wand.CurrentImage.TrimImage(10);
- wand.SaveImage(outputPath);
- }
- }
-
public ImageSize GetImageSize(string path)
{
CheckDisposed();
@@ -150,6 +139,11 @@ namespace Emby.Drawing.ImageMagick
{
using (var originalImage = new MagickWand(inputPath))
{
+ if (options.CropWhiteSpace)
+ {
+ originalImage.CurrentImage.TrimImage(10);
+ }
+
ScaleImage(originalImage, width, height, options.Blur ?? 0);
if (autoOrient)
diff --git a/Emby.Drawing.Net/GDIImageEncoder.cs b/Emby.Drawing.Net/GDIImageEncoder.cs
index 638415afdc..e710baaa77 100644
--- a/Emby.Drawing.Net/GDIImageEncoder.cs
+++ b/Emby.Drawing.Net/GDIImageEncoder.cs
@@ -75,27 +75,24 @@ namespace Emby.Drawing.Net
}
}
- public void CropWhiteSpace(string inputPath, string outputPath)
+ private Image GetImage(string path, bool cropWhitespace)
{
- using (var image = (Bitmap)Image.FromFile(inputPath))
+ if (cropWhitespace)
{
- using (var croppedImage = image.CropWhitespace())
+ using (var originalImage = (Bitmap)Image.FromFile(path))
{
- _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
-
- using (var outputStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, false))
- {
- croppedImage.Save(System.Drawing.Imaging.ImageFormat.Png, outputStream, 100);
- }
+ return originalImage.CropWhitespace();
}
}
+
+ return Image.FromFile(path);
}
public void EncodeImage(string inputPath, string cacheFilePath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
{
var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
- using (var originalImage = Image.FromFile(inputPath))
+ using (var originalImage = GetImage(inputPath, options.CropWhiteSpace))
{
var newWidth = Convert.ToInt32(width);
var newHeight = Convert.ToInt32(height);
diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
new file mode 100644
index 0000000000..d7b33b9507
--- /dev/null
+++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
@@ -0,0 +1,80 @@
+
+
+
+
+ 11.0
+ Debug
+ AnyCPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}
+ Library
+ Properties
+ Emby.Drawing.Skia
+ Emby.Drawing.Skia
+ en-US
+ 512
+ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Profile7
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ {9142eefa-7570-41e1-bfcc-468bb571af2f}
+ MediaBrowser.Common
+
+
+ {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}
+ MediaBrowser.Controller
+
+
+ {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}
+ MediaBrowser.Model
+
+
+
+
+ Properties\SharedVersion.cs
+
+
+
+
+
+
+
+
+
+
+ ..\packages\SkiaSharp.1.57.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll
+ True
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Emby.Drawing.Skia/PercentPlayedDrawer.cs b/Emby.Drawing.Skia/PercentPlayedDrawer.cs
new file mode 100644
index 0000000000..e291a462b9
--- /dev/null
+++ b/Emby.Drawing.Skia/PercentPlayedDrawer.cs
@@ -0,0 +1,31 @@
+using SkiaSharp;
+using MediaBrowser.Model.Drawing;
+using System;
+
+namespace Emby.Drawing.Skia
+{
+ public class PercentPlayedDrawer
+ {
+ private const int IndicatorHeight = 8;
+
+ public void Process(SKCanvas canvas, ImageSize imageSize, double percent)
+ {
+ using (var paint = new SKPaint())
+ {
+ var endX = imageSize.Width - 1;
+ var endY = imageSize.Height - 1;
+
+ paint.Color = SKColor.Parse("#99000000");
+ paint.Style = SKPaintStyle.Fill;
+ canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, (float)endX, (float)endY), paint);
+
+ double foregroundWidth = endX;
+ foregroundWidth *= percent;
+ foregroundWidth /= 100;
+
+ paint.Color = SKColor.Parse("#FF52B54B");
+ canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, Convert.ToInt32(Math.Round(foregroundWidth)), (float)endY), paint);
+ }
+ }
+ }
+}
diff --git a/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs b/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs
new file mode 100644
index 0000000000..9f3a74eb7f
--- /dev/null
+++ b/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs
@@ -0,0 +1,120 @@
+using SkiaSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Drawing;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.IO;
+using System.Reflection;
+
+namespace Emby.Drawing.Skia
+{
+ public class PlayedIndicatorDrawer
+ {
+ private const int FontSize = 42;
+ private const int OffsetFromTopRightCorner = 38;
+
+ private readonly IApplicationPaths _appPaths;
+ private readonly IHttpClient _iHttpClient;
+ private readonly IFileSystem _fileSystem;
+
+ public PlayedIndicatorDrawer(IApplicationPaths appPaths, IHttpClient iHttpClient, IFileSystem fileSystem)
+ {
+ _appPaths = appPaths;
+ _iHttpClient = iHttpClient;
+ _fileSystem = fileSystem;
+ }
+
+ public async Task DrawPlayedIndicator(SKCanvas canvas, ImageSize imageSize)
+ {
+ var x = imageSize.Width - OffsetFromTopRightCorner;
+
+ using (var paint = new SKPaint())
+ {
+ paint.Color = SKColor.Parse("#CC52B54B");
+ paint.Style = SKPaintStyle.Fill;
+ canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
+ }
+
+ using (var paint = new SKPaint())
+ {
+ paint.Color = new SKColor(255, 255, 255, 255);
+ paint.Style = SKPaintStyle.Fill;
+ paint.Typeface = SKTypeface.FromFile(await DownloadFont("webdings.ttf", "https://github.com/MediaBrowser/Emby.Resources/raw/master/fonts/webdings.ttf",
+ _appPaths, _iHttpClient, _fileSystem).ConfigureAwait(false));
+ paint.TextSize = FontSize;
+ paint.IsAntialias = true;
+
+ canvas.DrawText("a", (float)x-20, OffsetFromTopRightCorner + 12, paint);
+ }
+ }
+
+ internal static string ExtractFont(string name, IApplicationPaths paths, IFileSystem fileSystem)
+ {
+ var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
+
+ if (fileSystem.FileExists(filePath))
+ {
+ return filePath;
+ }
+
+ var namespacePath = typeof(PlayedIndicatorDrawer).Namespace + ".fonts." + name;
+ var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".ttf");
+ fileSystem.CreateDirectory(fileSystem.GetDirectoryName(tempPath));
+
+ using (var stream = typeof(PlayedIndicatorDrawer).GetTypeInfo().Assembly.GetManifestResourceStream(namespacePath))
+ {
+ using (var fileStream = fileSystem.GetFileStream(tempPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
+ {
+ stream.CopyTo(fileStream);
+ }
+ }
+
+ fileSystem.CreateDirectory(fileSystem.GetDirectoryName(filePath));
+
+ try
+ {
+ fileSystem.CopyFile(tempPath, filePath, false);
+ }
+ catch (IOException)
+ {
+
+ }
+
+ return tempPath;
+ }
+
+ internal static async Task DownloadFont(string name, string url, IApplicationPaths paths, IHttpClient httpClient, IFileSystem fileSystem)
+ {
+ var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
+
+ if (fileSystem.FileExists(filePath))
+ {
+ return filePath;
+ }
+
+ var tempPath = await httpClient.GetTempFile(new HttpRequestOptions
+ {
+ Url = url,
+ Progress = new Progress()
+
+ }).ConfigureAwait(false);
+
+ fileSystem.CreateDirectory(fileSystem.GetDirectoryName(filePath));
+
+ try
+ {
+ fileSystem.CopyFile(tempPath, filePath, false);
+ }
+ catch (IOException)
+ {
+
+ }
+
+ return tempPath;
+ }
+ }
+}
diff --git a/Emby.Drawing.Skia/Properties/AssemblyInfo.cs b/Emby.Drawing.Skia/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..c0dc7c5b4b
--- /dev/null
+++ b/Emby.Drawing.Skia/Properties/AssemblyInfo.cs
@@ -0,0 +1,25 @@
+using System.Resources;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Emby.Drawing.Skia")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Emby.Drawing.Skia")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: NeutralResourcesLanguage("en")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
\ No newline at end of file
diff --git a/Emby.Drawing.Skia/SkiaEncoder.cs b/Emby.Drawing.Skia/SkiaEncoder.cs
new file mode 100644
index 0000000000..74ceb75910
--- /dev/null
+++ b/Emby.Drawing.Skia/SkiaEncoder.cs
@@ -0,0 +1,387 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using SkiaSharp;
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace Emby.Drawing.Skia
+{
+ public class SkiaEncoder : IImageEncoder
+ {
+ private readonly ILogger _logger;
+ private readonly IApplicationPaths _appPaths;
+ private readonly Func _httpClientFactory;
+ private readonly IFileSystem _fileSystem;
+
+ public SkiaEncoder(ILogger logger, IApplicationPaths appPaths, Func httpClientFactory, IFileSystem fileSystem)
+ {
+ _logger = logger;
+ _appPaths = appPaths;
+ _httpClientFactory = httpClientFactory;
+ _fileSystem = fileSystem;
+
+ LogVersion();
+ }
+
+ public string[] SupportedInputFormats
+ {
+ get
+ {
+ // Some common file name extensions for RAW picture files include: .cr2, .crw, .dng, .nef, .orf, .rw2, .pef, .arw, .sr2, .srf, and .tif.
+ return new[]
+ {
+ "jpeg",
+ "jpg",
+ "png",
+ "dng",
+ "webp",
+ "gif",
+ "bmp",
+ "ico",
+ "astc",
+ "ktx",
+ "pkm",
+ "wbmp"
+ };
+ }
+ }
+
+ public ImageFormat[] SupportedOutputFormats
+ {
+ get
+ {
+ return new[] { ImageFormat.Webp, ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png, ImageFormat.Bmp };
+ }
+ }
+
+ private void LogVersion()
+ {
+ _logger.Info("SkiaSharp version: " + GetVersion());
+ }
+
+ public static string GetVersion()
+ {
+ using (var bitmap = new SKBitmap())
+ {
+ return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString();
+ }
+ }
+
+ private static bool IsWhiteSpace(SKColor color)
+ {
+ return (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0;
+ }
+
+ public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat)
+ {
+ switch (selectedFormat)
+ {
+ case ImageFormat.Bmp:
+ return SKEncodedImageFormat.Bmp;
+ case ImageFormat.Jpg:
+ return SKEncodedImageFormat.Jpeg;
+ case ImageFormat.Gif:
+ return SKEncodedImageFormat.Gif;
+ case ImageFormat.Webp:
+ return SKEncodedImageFormat.Webp;
+ default:
+ return SKEncodedImageFormat.Png;
+ }
+ }
+
+ private static bool IsAllWhiteRow(SKBitmap bmp, int row)
+ {
+ for (var i = 0; i < bmp.Width; ++i)
+ {
+ if (!IsWhiteSpace(bmp.GetPixel(i, row)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool IsAllWhiteColumn(SKBitmap bmp, int col)
+ {
+ for (var i = 0; i < bmp.Height; ++i)
+ {
+ if (!IsWhiteSpace(bmp.GetPixel(col, i)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private SKBitmap CropWhiteSpace(SKBitmap bitmap)
+ {
+ var topmost = 0;
+ for (int row = 0; row < bitmap.Height; ++row)
+ {
+ if (IsAllWhiteRow(bitmap, row))
+ topmost = row;
+ else break;
+ }
+
+ int bottommost = 0;
+ for (int row = bitmap.Height - 1; row >= 0; --row)
+ {
+ if (IsAllWhiteRow(bitmap, row))
+ bottommost = row;
+ else break;
+ }
+
+ int leftmost = 0, rightmost = 0;
+ for (int col = 0; col < bitmap.Width; ++col)
+ {
+ if (IsAllWhiteColumn(bitmap, col))
+ leftmost = col;
+ else
+ break;
+ }
+
+ for (int col = bitmap.Width - 1; col >= 0; --col)
+ {
+ if (IsAllWhiteColumn(bitmap, col))
+ rightmost = col;
+ else
+ break;
+ }
+
+ var newRect = SKRectI.Create(leftmost, topmost, rightmost - leftmost, bottommost - topmost);
+
+ using (var image = SKImage.FromBitmap(bitmap))
+ {
+ using (var subset = image.Subset(newRect))
+ {
+ return SKBitmap.FromImage(subset);
+ //using (var data = subset.Encode(StripCollageBuilder.GetEncodedFormat(outputPath), 90))
+ //{
+ // using (var fileStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
+ // {
+ // data.AsStream().CopyTo(fileStream);
+ // }
+ //}
+ }
+ }
+ }
+
+ public ImageSize GetImageSize(string path)
+ {
+ using (var s = new SKFileStream(path))
+ {
+ using (var codec = SKCodec.Create(s))
+ {
+ var info = codec.Info;
+
+ return new ImageSize
+ {
+ Width = info.Width,
+ Height = info.Height
+ };
+ }
+ }
+ }
+
+ private string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
+ private SKBitmap Decode(string path)
+ {
+ var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
+
+ if (requiresTransparencyHack)
+ {
+ using (var stream = new SKFileStream(path))
+ {
+ var codec = SKCodec.Create(stream);
+
+ // create the bitmap
+ var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height);
+ // decode
+ codec.GetPixels(bitmap.Info, bitmap.GetPixels());
+
+ return bitmap;
+ }
+ }
+
+ return SKBitmap.Decode(path);
+ }
+
+ private SKBitmap GetBitmap(string path, bool cropWhitespace)
+ {
+ if (cropWhitespace)
+ {
+ using (var bitmap = Decode(path))
+ {
+ return CropWhiteSpace(bitmap);
+ }
+ }
+
+ return Decode(path);
+ }
+
+ public void EncodeImage(string inputPath, string outputPath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
+ {
+ if (string.IsNullOrWhiteSpace(inputPath))
+ {
+ throw new ArgumentNullException("inputPath");
+ }
+ if (string.IsNullOrWhiteSpace(inputPath))
+ {
+ throw new ArgumentNullException("outputPath");
+ }
+
+ var skiaOutputFormat = GetImageFormat(selectedOutputFormat);
+
+ var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor);
+ var hasForegroundColor = !string.IsNullOrWhiteSpace(options.ForegroundLayer);
+ var blur = options.Blur ?? 0;
+ var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0);
+
+ using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace))
+ {
+ using (var resizedBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType))
+ {
+ // scale image
+ var resizeMethod = SKBitmapResizeMethod.Lanczos3;
+
+ bitmap.Resize(resizedBitmap, resizeMethod);
+
+ // If all we're doing is resizing then we can stop now
+ if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
+ {
+ using (var outputStream = new SKFileWStream(outputPath))
+ {
+ resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
+ return;
+ }
+ }
+
+ // create bitmap to use for canvas drawing
+ using (var saveBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType))
+ {
+ // create canvas used to draw into bitmap
+ using (var canvas = new SKCanvas(saveBitmap))
+ {
+ // set background color if present
+ if (hasBackgroundColor)
+ {
+ canvas.Clear(SKColor.Parse(options.BackgroundColor));
+ }
+
+ // Add blur if option is present
+ if (blur > 0)
+ {
+ using (var paint = new SKPaint())
+ {
+ // create image from resized bitmap to apply blur
+ using (var filter = SKImageFilter.CreateBlur(blur, blur))
+ {
+ paint.ImageFilter = filter;
+ canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), paint);
+ }
+ }
+ }
+ else
+ {
+ // draw resized bitmap onto canvas
+ canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height));
+ }
+
+ // If foreground layer present then draw
+ if (hasForegroundColor)
+ {
+ Double opacity;
+ if (!Double.TryParse(options.ForegroundLayer, out opacity)) opacity = .4;
+
+ canvas.DrawColor(new SKColor(0, 0, 0, (Byte)((1 - opacity) * 0xFF)), SKBlendMode.SrcOver);
+ }
+
+ if (hasIndicator)
+ {
+ DrawIndicator(canvas, width, height, options);
+ }
+
+ using (var outputStream = new SKFileWStream(outputPath))
+ {
+ saveBitmap.Encode(outputStream, skiaOutputFormat, quality);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void CreateImageCollage(ImageCollageOptions options)
+ {
+ double ratio = options.Width;
+ ratio /= options.Height;
+
+ if (ratio >= 1.4)
+ {
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
+ }
+ else if (ratio >= .9)
+ {
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
+ }
+ else
+ {
+ // @todo create Poster collage capability
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
+ }
+ }
+
+ private void DrawIndicator(SKCanvas canvas, int imageWidth, int imageHeight, ImageProcessingOptions options)
+ {
+ try
+ {
+ var currentImageSize = new ImageSize(imageWidth, imageHeight);
+
+ if (options.AddPlayedIndicator)
+ {
+ var task = new PlayedIndicatorDrawer(_appPaths, _httpClientFactory(), _fileSystem).DrawPlayedIndicator(canvas, currentImageSize);
+ Task.WaitAll(task);
+ }
+ else if (options.UnplayedCount.HasValue)
+ {
+ new UnplayedCountIndicator(_appPaths, _httpClientFactory(), _fileSystem).DrawUnplayedCountIndicator(canvas, currentImageSize, options.UnplayedCount.Value);
+ }
+
+ if (options.PercentPlayed > 0)
+ {
+ new PercentPlayedDrawer().Process(canvas, currentImageSize, options.PercentPlayed);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error drawing indicator overlay", ex);
+ }
+ }
+
+ public string Name
+ {
+ get { return "Skia"; }
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public bool SupportsImageCollageCreation
+ {
+ get { return true; }
+ }
+
+ public bool SupportsImageEncoding
+ {
+ get { return true; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Emby.Drawing.Skia/StripCollageBuilder.cs b/Emby.Drawing.Skia/StripCollageBuilder.cs
new file mode 100644
index 0000000000..605677aaba
--- /dev/null
+++ b/Emby.Drawing.Skia/StripCollageBuilder.cs
@@ -0,0 +1,190 @@
+using SkiaSharp;
+using MediaBrowser.Common.Configuration;
+using System;
+using System.IO;
+using MediaBrowser.Model.IO;
+
+namespace Emby.Drawing.Skia
+{
+ public class StripCollageBuilder
+ {
+ private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
+
+ public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem)
+ {
+ _appPaths = appPaths;
+ _fileSystem = fileSystem;
+ }
+
+ public static SKEncodedImageFormat GetEncodedFormat(string outputPath)
+ {
+ var ext = Path.GetExtension(outputPath).ToLower();
+
+ if (ext == ".jpg" || ext == ".jpeg")
+ return SKEncodedImageFormat.Jpeg;
+
+ if (ext == ".webp")
+ return SKEncodedImageFormat.Webp;
+
+ if (ext == ".gif")
+ return SKEncodedImageFormat.Gif;
+
+ if (ext == ".bmp")
+ return SKEncodedImageFormat.Bmp;
+
+ // default to png
+ return SKEncodedImageFormat.Png;
+ }
+
+ public void BuildPosterCollage(string[] paths, string outputPath, int width, int height)
+ {
+ // @todo
+ }
+
+ public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
+ {
+ using (var bitmap = BuildSquareCollageBitmap(paths, width, height))
+ {
+ using (var outputStream = new SKFileWStream(outputPath))
+ {
+ bitmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
+ }
+ }
+ }
+
+ public void BuildThumbCollage(string[] paths, string outputPath, int width, int height)
+ {
+ using (var bitmap = BuildThumbCollageBitmap(paths, width, height))
+ {
+ using (var outputStream = new SKFileWStream(outputPath))
+ {
+ bitmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
+ }
+ }
+ }
+
+ private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height)
+ {
+ var bitmap = new SKBitmap(width, height);
+
+ using (var canvas = new SKCanvas(bitmap))
+ {
+ canvas.Clear(SKColors.Black);
+
+ // determine sizes for each image that will composited into the final image
+ var iSlice = Convert.ToInt32(width * 0.23475);
+ int iTrans = Convert.ToInt32(height * .25);
+ int iHeight = Convert.ToInt32(height * .70);
+ var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
+ var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+ int imageIndex = 0;
+
+ for (int i = 0; i < 4; i++)
+ {
+ using (var currentBitmap = SKBitmap.Decode(paths[imageIndex]))
+ {
+ // resize to the same aspect as the original
+ int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
+ using (var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
+ {
+ currentBitmap.Resize(resizeBitmap, SKBitmapResizeMethod.Lanczos3);
+ // determine how much to crop
+ int ix = (int)Math.Abs((iWidth - iSlice) / 2);
+ using (var image = SKImage.FromBitmap(resizeBitmap))
+ {
+ // crop image
+ using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight)))
+ {
+ // draw image onto canvas
+ canvas.DrawImage(subset, (horizontalImagePadding * (i + 1)) + (iSlice * i), verticalSpacing);
+
+ using (var croppedBitmap = SKBitmap.FromImage(subset))
+ {
+ // create reflection of image below the drawn image
+ using (var reflectionBitmap = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType))
+ {
+ // resize to half height
+ croppedBitmap.Resize(reflectionBitmap, SKBitmapResizeMethod.Lanczos3);
+
+ using (var flippedBitmap = new SKBitmap(reflectionBitmap.Width, reflectionBitmap.Height, reflectionBitmap.ColorType, reflectionBitmap.AlphaType))
+ {
+ using (var flippedCanvas = new SKCanvas(flippedBitmap))
+ {
+ // flip image vertically
+ var matrix = SKMatrix.MakeScale(1, -1);
+ matrix.SetScaleTranslate(1, -1, 0, flippedBitmap.Height);
+ flippedCanvas.SetMatrix(matrix);
+ flippedCanvas.DrawBitmap(reflectionBitmap, 0, 0);
+ flippedCanvas.ResetMatrix();
+
+ // create gradient to make image appear as a reflection
+ var remainingHeight = height - (iHeight + (2 * verticalSpacing));
+ flippedCanvas.ClipRect(SKRect.Create(reflectionBitmap.Width, remainingHeight));
+ using (var gradient = new SKPaint())
+ {
+ gradient.IsAntialias = true;
+ gradient.BlendMode = SKBlendMode.SrcOver;
+ gradient.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(0, remainingHeight), new[] { new SKColor(0, 0, 0, 128), new SKColor(0, 0, 0, 208), new SKColor(0, 0, 0, 240), new SKColor(0, 0, 0, 255) }, null, SKShaderTileMode.Clamp);
+ flippedCanvas.DrawPaint(gradient);
+ }
+
+ // finally draw reflection onto canvas
+ canvas.DrawBitmap(flippedBitmap, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + (2 * verticalSpacing));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ imageIndex++;
+
+ if (imageIndex >= paths.Length)
+ imageIndex = 0;
+ }
+ }
+
+ return bitmap;
+ }
+
+ private SKBitmap BuildSquareCollageBitmap(string[] paths, int width, int height)
+ {
+ var bitmap = new SKBitmap(width, height);
+ var imageIndex = 0;
+ var cellWidth = width / 2;
+ var cellHeight = height / 2;
+
+ using (var canvas = new SKCanvas(bitmap))
+ {
+ for (var x = 0; x < 2; x++)
+ {
+ for (var y = 0; y < 2; y++)
+ {
+ using (var currentBitmap = SKBitmap.Decode(paths[imageIndex]))
+ {
+ using (var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
+ {
+ // scale image
+ currentBitmap.Resize(resizedBitmap, SKBitmapResizeMethod.Lanczos3);
+
+ // draw this image into the strip at the next position
+ var xPos = x * cellWidth;
+ var yPos = y * cellHeight;
+ canvas.DrawBitmap(resizedBitmap, xPos, yPos);
+ }
+ }
+ imageIndex++;
+
+ if (imageIndex >= paths.Length)
+ imageIndex = 0;
+ }
+ }
+ }
+
+ return bitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Emby.Drawing.Skia/UnplayedCountIndicator.cs b/Emby.Drawing.Skia/UnplayedCountIndicator.cs
new file mode 100644
index 0000000000..f0283ad23e
--- /dev/null
+++ b/Emby.Drawing.Skia/UnplayedCountIndicator.cs
@@ -0,0 +1,68 @@
+using SkiaSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Drawing;
+using System.Globalization;
+using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.IO;
+
+namespace Emby.Drawing.Skia
+{
+ public class UnplayedCountIndicator
+ {
+ private const int OffsetFromTopRightCorner = 38;
+
+ private readonly IApplicationPaths _appPaths;
+ private readonly IHttpClient _iHttpClient;
+ private readonly IFileSystem _fileSystem;
+
+ public UnplayedCountIndicator(IApplicationPaths appPaths, IHttpClient iHttpClient, IFileSystem fileSystem)
+ {
+ _appPaths = appPaths;
+ _iHttpClient = iHttpClient;
+ _fileSystem = fileSystem;
+ }
+
+ public void DrawUnplayedCountIndicator(SKCanvas canvas, ImageSize imageSize, int count)
+ {
+ var x = imageSize.Width - OffsetFromTopRightCorner;
+ var text = count.ToString(CultureInfo.InvariantCulture);
+
+ using (var paint = new SKPaint())
+ {
+ paint.Color = SKColor.Parse("#CC52B54B");
+ paint.Style = SKPaintStyle.Fill;
+ canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
+ }
+ using (var paint = new SKPaint())
+ {
+ paint.Color = new SKColor(255, 255, 255, 255);
+ paint.Style = SKPaintStyle.Fill;
+ paint.Typeface = SKTypeface.FromFile(PlayedIndicatorDrawer.ExtractFont("robotoregular.ttf", _appPaths, _fileSystem));
+ paint.TextSize = 24;
+ paint.IsAntialias = true;
+
+ var y = OffsetFromTopRightCorner + 9;
+
+ if (text.Length == 1)
+ {
+ x -= 7;
+ }
+ if (text.Length == 2)
+ {
+ x -= 13;
+ }
+ else if (text.Length >= 3)
+ {
+ x -= 15;
+ y -= 2;
+ paint.TextSize = 18;
+ }
+
+ canvas.DrawText(text, (float)x, y, paint);
+ }
+ }
+ }
+}
diff --git a/Emby.Drawing.Skia/packages.config b/Emby.Drawing.Skia/packages.config
new file mode 100644
index 0000000000..0743c38094
--- /dev/null
+++ b/Emby.Drawing.Skia/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index bee0e9b69b..82181238bb 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -56,7 +56,7 @@ namespace Emby.Drawing
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
private readonly IServerApplicationPaths _appPaths;
- private readonly IImageEncoder _imageEncoder;
+ private IImageEncoder _imageEncoder;
private readonly Func _libraryManager;
public ImageProcessor(ILogger logger,
@@ -64,7 +64,7 @@ namespace Emby.Drawing
IFileSystem fileSystem,
IJsonSerializer jsonSerializer,
IImageEncoder imageEncoder,
- int maxConcurrentImageProcesses, Func libraryManager, ITimerFactory timerFactory)
+ Func libraryManager, ITimerFactory timerFactory)
{
_logger = logger;
_fileSystem = fileSystem;
@@ -103,6 +103,20 @@ namespace Emby.Drawing
_cachedImagedSizes = new ConcurrentDictionary(sizeDictionary);
}
+ public IImageEncoder ImageEncoder
+ {
+ get { return _imageEncoder; }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ _imageEncoder = value;
+ }
+ }
+
public string[] SupportedInputFormats
{
get
@@ -136,14 +150,6 @@ namespace Emby.Drawing
}
}
- private string CroppedWhitespaceImageCachePath
- {
- get
- {
- return Path.Combine(_appPaths.ImageCachePath, "cropped-images");
- }
- }
-
public void AddParts(IEnumerable enhancers)
{
ImageEnhancers = enhancers.ToArray();
@@ -186,14 +192,6 @@ namespace Emby.Drawing
return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
- if (options.CropWhiteSpace && _imageEncoder.SupportsImageEncoding)
- {
- var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
-
- originalImagePath = tuple.Item1;
- dateModified = tuple.Item2;
- }
-
if (options.Enhancers.Count > 0)
{
var tuple = await GetEnhancedImage(new ItemImageInfo
@@ -214,7 +212,7 @@ namespace Emby.Drawing
return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
- ImageSize? originalImageSize;
+ ImageSize? originalImageSize = null;
try
{
originalImageSize = GetImageSize(originalImagePath, dateModified, true);
@@ -241,8 +239,8 @@ namespace Emby.Drawing
if (!_fileSystem.FileExists(cacheFilePath))
{
- var newWidth = Convert.ToInt32(newSize.Width);
- var newHeight = Convert.ToInt32(newSize.Height);
+ var newWidth = Convert.ToInt32(Math.Round(newSize.Width));
+ var newHeight = Convert.ToInt32(Math.Round(newSize.Height));
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath));
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
@@ -349,22 +347,22 @@ namespace Emby.Drawing
return new ImageSize(options.Width.Value, options.Height.Value);
}
- var aspect = GetEstimatedAspectRatio(options.Image.Type);
+ var aspect = GetEstimatedAspectRatio(options.Image.Type, options.Item);
var width = options.Width ?? options.MaxWidth;
if (width.HasValue)
{
- var heightValue = aspect / width.Value;
- return new ImageSize(width.Value, Convert.ToInt32(heightValue));
+ var heightValue = width.Value / aspect;
+ return new ImageSize(width.Value, heightValue);
}
var height = options.Height ?? options.MaxHeight ?? 200;
var widthValue = aspect * height;
- return new ImageSize(Convert.ToInt32(widthValue), height);
+ return new ImageSize(widthValue, height);
}
- private double GetEstimatedAspectRatio(ImageType type)
+ private double GetEstimatedAspectRatio(ImageType type, IHasImages item)
{
switch (type)
{
@@ -384,7 +382,7 @@ namespace Emby.Drawing
case ImageType.Logo:
return 2.58;
case ImageType.Primary:
- return .667;
+ return item.GetDefaultPrimaryImageAspectRatio() ?? .667;
default:
return 1;
}
@@ -400,46 +398,6 @@ namespace Emby.Drawing
return requestedFormat;
}
- ///
- /// Crops whitespace from an image, caches the result, and returns the cached path
- ///
- private async Task> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified)
- {
- var name = originalImagePath;
- name += "datemodified=" + dateModified.Ticks;
-
- var croppedImagePath = GetCachePath(CroppedWhitespaceImageCachePath, name, Path.GetExtension(originalImagePath));
-
- // Check again in case of contention
- if (_fileSystem.FileExists(croppedImagePath))
- {
- return GetResult(croppedImagePath);
- }
-
- try
- {
- _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(croppedImagePath));
- var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(croppedImagePath));
- _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
-
- _imageEncoder.CropWhiteSpace(originalImagePath, tmpPath);
- CopyFile(tmpPath, croppedImagePath);
- return GetResult(tmpPath);
- }
- catch (NotImplementedException)
- {
- // No need to spam the log with an error message
- return new Tuple(originalImagePath, dateModified);
- }
- catch (Exception ex)
- {
- // We have to have a catch-all here because some of the .net image methods throw a plain old Exception
- _logger.ErrorException("Error cropping image {0}", ex, originalImagePath);
-
- return new Tuple(originalImagePath, dateModified);
- }
- }
-
private Tuple GetResult(string path)
{
return new Tuple(path, _fileSystem.GetLastWriteTimeUtc(path));
@@ -555,26 +513,39 @@ namespace Emby.Drawing
/// ImageSize.
private ImageSize GetImageSizeInternal(string path, bool allowSlowMethod)
{
+ // Can't use taglib because it keeps a lock on the file
+ //try
+ //{
+ // using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(path), _fileSystem.OpenRead(path), null)))
+ // {
+ // var image = file as TagLib.Image.File;
+
+ // var properties = image.Properties;
+
+ // return new ImageSize
+ // {
+ // Height = properties.PhotoHeight,
+ // Width = properties.PhotoWidth
+ // };
+ // }
+ //}
+ //catch
+ //{
+ //}
+
try
{
- using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(path), _fileSystem.OpenRead(path), null)))
- {
- var image = file as TagLib.Image.File;
-
- var properties = image.Properties;
-
- return new ImageSize
- {
- Height = properties.PhotoHeight,
- Width = properties.PhotoWidth
- };
- }
+ return ImageHeader.GetDimensions(path, _logger, _fileSystem);
}
catch
{
- }
+ if (allowSlowMethod)
+ {
+ return _imageEncoder.GetImageSize(path);
+ }
- return ImageHeader.GetDimensions(path, _logger, _fileSystem);
+ throw;
+ }
}
private readonly ITimer _saveImageSizeTimer;
diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs
index 4fa18ce553..c7d365fb2c 100644
--- a/Emby.Drawing/NullImageEncoder.cs
+++ b/Emby.Drawing/NullImageEncoder.cs
@@ -57,6 +57,11 @@ namespace Emby.Drawing
get { return false; }
}
+ public ImageSize GetImageSize(string path)
+ {
+ throw new NotImplementedException();
+ }
+
public void Dispose()
{
}
diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs
index 78bdc11898..0fe30eb80c 100644
--- a/Emby.Server.Core/ApplicationHost.cs
+++ b/Emby.Server.Core/ApplicationHost.cs
@@ -187,7 +187,7 @@ namespace Emby.Server.Core
/// The HTTP server.
private IHttpServer HttpServer { get; set; }
private IDtoService DtoService { get; set; }
- private IImageProcessor ImageProcessor { get; set; }
+ public IImageProcessor ImageProcessor { get; set; }
///
/// Gets or sets the media encoder.
@@ -761,7 +761,10 @@ namespace Emby.Server.Core
return null;
}
- X509Certificate2 localCert = new X509Certificate2(certificateLocation, info.Password);
+ // Don't use an empty string password
+ var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password;
+
+ X509Certificate2 localCert = new X509Certificate2(certificateLocation, password);
//localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
if (!localCert.HasPrivateKey)
{
@@ -780,14 +783,7 @@ namespace Emby.Server.Core
private IImageProcessor GetImageProcessor()
{
- var maxConcurrentImageProcesses = Math.Max(Environment.ProcessorCount, 4);
-
- if (StartupOptions.ContainsOption("-imagethreads"))
- {
- int.TryParse(StartupOptions.GetOption("-imagethreads"), NumberStyles.Any, CultureInfo.InvariantCulture, out maxConcurrentImageProcesses);
- }
-
- return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, maxConcurrentImageProcesses, () => LibraryManager, TimerFactory);
+ return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory);
}
protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
@@ -1132,7 +1128,8 @@ namespace Emby.Server.Core
// Custom cert
return new CertificateInfo
{
- Path = ServerConfigurationManager.Configuration.CertificatePath
+ Path = ServerConfigurationManager.Configuration.CertificatePath,
+ Password = ServerConfigurationManager.Configuration.CertificatePassword
};
}
diff --git a/Emby.Server.Core/IO/LibraryMonitor.cs b/Emby.Server.Core/IO/LibraryMonitor.cs
index 8af826c881..0f0640a383 100644
--- a/Emby.Server.Core/IO/LibraryMonitor.cs
+++ b/Emby.Server.Core/IO/LibraryMonitor.cs
@@ -537,7 +537,7 @@ namespace Emby.Server.Core.IO
}
}
- var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _timerFactory, _environmentInfo);
+ var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _timerFactory, _environmentInfo, LibraryManager);
newRefresher.Completed += NewRefresher_Completed;
_activeRefreshers.Add(newRefresher);
}
diff --git a/Emby.Server.Core/project.json b/Emby.Server.Core/project.json
index 70543d7df1..fd4f9d6cf7 100644
--- a/Emby.Server.Core/project.json
+++ b/Emby.Server.Core/project.json
@@ -68,7 +68,7 @@
"System.AppDomain": "2.0.11",
"System.Globalization.Extensions": "4.3.0",
"System.IO.FileSystem.Watcher": "4.3.0",
- "System.Net.Security": "4.3.0",
+ "System.Net.Security": "4.3.1",
"System.Security.Cryptography.X509Certificates": "4.3.0",
"System.Runtime.Extensions": "4.3.0",
"MediaBrowser.Model": {
diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs
index bf88358465..e9b6f7a404 100644
--- a/Emby.Server.Implementations/Activity/ActivityRepository.cs
+++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs
@@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.Activity
{
using (var statement = db.PrepareStatement("replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)"))
{
- statement.TryBind("@Id", entry.Id.ToGuidParamValue());
+ statement.TryBind("@Id", entry.Id.ToGuidBlob());
statement.TryBind("@Name", entry.Name);
statement.TryBind("@Overview", entry.Overview);
@@ -168,7 +168,7 @@ namespace Emby.Server.Implementations.Activity
var info = new ActivityLogEntry
{
- Id = reader[index].ReadGuid().ToString("N")
+ Id = reader[index].ReadGuidFromBlob().ToString("N")
};
index++;
diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
index 13874223cc..385b4bd518 100644
--- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
+++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
@@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.AppBase
Logger.Info("Saving system configuration");
var path = CommonApplicationPaths.SystemConfigurationFilePath;
- FileSystem.CreateDirectory(Path.GetDirectoryName(path));
+ FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path));
lock (_configurationSyncLock)
{
@@ -293,7 +293,7 @@ namespace Emby.Server.Implementations.AppBase
_configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
var path = GetConfigurationFile(key);
- FileSystem.CreateDirectory(Path.GetDirectoryName(path));
+ FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path));
lock (_configurationSyncLock)
{
diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
index ad2f459459..d6a41dd67b 100644
--- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
+++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
@@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.AppBase
// If the file didn't exist before, or if something has changed, re-save
if (buffer == null || !buffer.SequenceEqual(newBytes))
{
- fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+ fileSystem.CreateDirectory(fileSystem.GetDirectoryName(path));
// Save it after load in case we got new items
fileSystem.WriteAllBytes(path, newBytes);
diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
index f3d84315e9..4118bd1b21 100644
--- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
@@ -106,8 +106,8 @@ namespace Emby.Server.Implementations.Data
using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)"))
{
- statement.TryBind("@id", displayPreferences.Id.ToGuidParamValue());
- statement.TryBind("@userId", userId.ToGuidParamValue());
+ statement.TryBind("@id", displayPreferences.Id.ToGuidBlob());
+ statement.TryBind("@userId", userId.ToGuidBlob());
statement.TryBind("@client", client);
statement.TryBind("@data", serialized);
@@ -170,8 +170,8 @@ namespace Emby.Server.Implementations.Data
{
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"))
{
- statement.TryBind("@id", guidId.ToGuidParamValue());
- statement.TryBind("@userId", userId.ToGuidParamValue());
+ statement.TryBind("@id", guidId.ToGuidBlob());
+ statement.TryBind("@userId", userId.ToGuidBlob());
statement.TryBind("@client", client);
foreach (var row in statement.ExecuteQuery())
@@ -204,7 +204,7 @@ namespace Emby.Server.Implementations.Data
{
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId"))
{
- statement.TryBind("@userId", userId.ToGuidParamValue());
+ statement.TryBind("@userId", userId.ToGuidBlob());
foreach (var row in statement.ExecuteQuery())
{
diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs
index 783258a138..d2c851b3c6 100644
--- a/Emby.Server.Implementations/Data/SqliteExtensions.cs
+++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs
@@ -26,17 +26,17 @@ namespace Emby.Server.Implementations.Data
});
}
- public static byte[] ToGuidParamValue(this string str)
+ public static byte[] ToGuidBlob(this string str)
{
- return ToGuidParamValue(new Guid(str));
+ return ToGuidBlob(new Guid(str));
}
- public static byte[] ToGuidParamValue(this Guid guid)
+ public static byte[] ToGuidBlob(this Guid guid)
{
return guid.ToByteArray();
}
- public static Guid ReadGuid(this IResultSetValue result)
+ public static Guid ReadGuidFromBlob(this IResultSetValue result)
{
return new Guid(result.ToBlob());
}
@@ -172,7 +172,7 @@ namespace Emby.Server.Implementations.Data
public static Guid GetGuid(this IReadOnlyList result, int index)
{
- return result[index].ReadGuid();
+ return result[index].ReadGuidFromBlob();
}
private static void CheckName(string name)
@@ -262,7 +262,7 @@ namespace Emby.Server.Implementations.Data
IBindParameter bindParam;
if (statement.BindParameters.TryGetValue(name, out bindParam))
{
- bindParam.Bind(value.ToGuidParamValue());
+ bindParam.Bind(value.ToGuidBlob());
}
else
{
diff --git a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs
index 9fbe8669d1..a254962c94 100644
--- a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs
@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Data
using (var statement = db.PrepareStatement(commandText))
{
- statement.TryBind("@ResultId", result.Id.ToGuidParamValue());
+ statement.TryBind("@ResultId", result.Id.ToGuidBlob());
statement.TryBind("@OriginalPath", result.OriginalPath);
statement.TryBind("@TargetPath", result.TargetPath);
@@ -100,7 +100,7 @@ namespace Emby.Server.Implementations.Data
{
using (var statement = db.PrepareStatement("delete from FileOrganizerResults where ResultId = @ResultId"))
{
- statement.TryBind("@ResultId", id.ToGuidParamValue());
+ statement.TryBind("@ResultId", id.ToGuidBlob());
statement.MoveNext();
}
}, TransactionMode);
@@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.Data
{
using (var statement = connection.PrepareStatement("select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@ResultId"))
{
- statement.TryBind("@ResultId", id.ToGuidParamValue());
+ statement.TryBind("@ResultId", id.ToGuidBlob());
foreach (var row in statement.ExecuteQuery())
{
@@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Data
var result = new FileOrganizationResult
{
- Id = reader[0].ReadGuid().ToString("N")
+ Id = reader[0].ReadGuidFromBlob().ToString("N")
};
index++;
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 61dce9bba3..28be49dc2f 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -2128,7 +2128,7 @@ namespace Emby.Server.Implementations.Data
connection.RunInTransaction(db =>
{
// First delete chapters
- db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", id.ToGuidParamValue());
+ db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", id.ToGuidBlob());
using (var saveChapterStatement = PrepareStatement(db, "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath, ImageDateModified) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath, @ImageDateModified)"))
{
@@ -2139,7 +2139,7 @@ namespace Emby.Server.Implementations.Data
saveChapterStatement.Reset();
}
- saveChapterStatement.TryBind("@ItemId", id.ToGuidParamValue());
+ saveChapterStatement.TryBind("@ItemId", id.ToGuidBlob());
saveChapterStatement.TryBind("@ChapterIndex", index);
saveChapterStatement.TryBind("@StartPositionTicks", chapter.StartPositionTicks);
saveChapterStatement.TryBind("@Name", chapter.Name);
@@ -2919,7 +2919,7 @@ namespace Emby.Server.Implementations.Data
foreach (var row in statement.ExecuteQuery())
{
- list.Add(row[0].ReadGuid());
+ list.Add(row[0].ReadGuidFromBlob());
}
}
@@ -3113,7 +3113,7 @@ namespace Emby.Server.Implementations.Data
foreach (var row in statement.ExecuteQuery())
{
- list.Add(row[0].ReadGuid());
+ list.Add(row[0].ReadGuidFromBlob());
}
}
}
@@ -3643,7 +3643,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(select Name from TypedBaseItems where guid=" + paramName + ") in (select Name from People where ItemId=Guid)");
if (statement != null)
{
- statement.TryBind(paramName, personId.ToGuidParamValue());
+ statement.TryBind(paramName, personId.ToGuidBlob());
}
index++;
}
@@ -3843,7 +3843,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)");
if (statement != null)
{
- statement.TryBind(paramName, artistId.ToGuidParamValue());
+ statement.TryBind(paramName, artistId.ToGuidBlob());
}
index++;
}
@@ -3862,7 +3862,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
if (statement != null)
{
- statement.TryBind(paramName, albumId.ToGuidParamValue());
+ statement.TryBind(paramName, albumId.ToGuidBlob());
}
index++;
}
@@ -3881,7 +3881,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)");
if (statement != null)
{
- statement.TryBind(paramName, artistId.ToGuidParamValue());
+ statement.TryBind(paramName, artistId.ToGuidBlob());
}
index++;
}
@@ -3900,7 +3900,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=2)");
if (statement != null)
{
- statement.TryBind(paramName, genreId.ToGuidParamValue());
+ statement.TryBind(paramName, genreId.ToGuidBlob());
}
index++;
}
@@ -3953,7 +3953,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=3)");
if (statement != null)
{
- statement.TryBind(paramName, studioId.ToGuidParamValue());
+ statement.TryBind(paramName, studioId.ToGuidBlob());
}
index++;
}
@@ -4521,22 +4521,22 @@ namespace Emby.Server.Implementations.Data
connection.RunInTransaction(db =>
{
// Delete people
- ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", id.ToGuidParamValue());
+ ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", id.ToGuidBlob());
// Delete chapters
- ExecuteWithSingleParam(db, "delete from " + ChaptersTableName + " where ItemId=@Id", id.ToGuidParamValue());
+ ExecuteWithSingleParam(db, "delete from " + ChaptersTableName + " where ItemId=@Id", id.ToGuidBlob());
// Delete media streams
- ExecuteWithSingleParam(db, "delete from mediastreams where ItemId=@Id", id.ToGuidParamValue());
+ ExecuteWithSingleParam(db, "delete from mediastreams where ItemId=@Id", id.ToGuidBlob());
// Delete ancestors
- ExecuteWithSingleParam(db, "delete from AncestorIds where ItemId=@Id", id.ToGuidParamValue());
+ ExecuteWithSingleParam(db, "delete from AncestorIds where ItemId=@Id", id.ToGuidBlob());
// Delete item values
- ExecuteWithSingleParam(db, "delete from ItemValues where ItemId=@Id", id.ToGuidParamValue());
+ ExecuteWithSingleParam(db, "delete from ItemValues where ItemId=@Id", id.ToGuidBlob());
// Delete the item
- ExecuteWithSingleParam(db, "delete from TypedBaseItems where guid=@Id", id.ToGuidParamValue());
+ ExecuteWithSingleParam(db, "delete from TypedBaseItems where guid=@Id", id.ToGuidBlob());
}, TransactionMode);
}
}
@@ -4643,7 +4643,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("ItemId=@ItemId");
if (statement != null)
{
- statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
+ statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
}
}
if (query.AppearsInItemId != Guid.Empty)
@@ -4651,7 +4651,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
if (statement != null)
{
- statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidParamValue());
+ statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidBlob());
}
}
var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
@@ -4730,14 +4730,14 @@ namespace Emby.Server.Implementations.Data
// First delete
deleteAncestorsStatement.Reset();
- deleteAncestorsStatement.TryBind("@ItemId", itemId.ToGuidParamValue());
+ deleteAncestorsStatement.TryBind("@ItemId", itemId.ToGuidBlob());
deleteAncestorsStatement.MoveNext();
foreach (var ancestorId in ancestorIds)
{
updateAncestorsStatement.Reset();
- updateAncestorsStatement.TryBind("@ItemId", itemId.ToGuidParamValue());
- updateAncestorsStatement.TryBind("@AncestorId", ancestorId.ToGuidParamValue());
+ updateAncestorsStatement.TryBind("@ItemId", itemId.ToGuidBlob());
+ updateAncestorsStatement.TryBind("@AncestorId", ancestorId.ToGuidBlob());
updateAncestorsStatement.TryBind("@AncestorIdText", ancestorId.ToString("N"));
updateAncestorsStatement.MoveNext();
}
@@ -5198,7 +5198,7 @@ namespace Emby.Server.Implementations.Data
CheckDisposed();
// First delete
- db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidParamValue());
+ db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidBlob());
using (var statement = PrepareStatement(db, "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)"))
{
@@ -5214,7 +5214,7 @@ namespace Emby.Server.Implementations.Data
statement.Reset();
- statement.TryBind("@ItemId", itemId.ToGuidParamValue());
+ statement.TryBind("@ItemId", itemId.ToGuidBlob());
statement.TryBind("@Type", pair.Item1);
statement.TryBind("@Value", itemValue);
@@ -5252,7 +5252,7 @@ namespace Emby.Server.Implementations.Data
{
// First delete
// "delete from People where ItemId=?"
- connection.Execute("delete from People where ItemId=?", itemId.ToGuidParamValue());
+ connection.Execute("delete from People where ItemId=?", itemId.ToGuidBlob());
var listIndex = 0;
@@ -5266,7 +5266,7 @@ namespace Emby.Server.Implementations.Data
statement.Reset();
}
- statement.TryBind("@ItemId", itemId.ToGuidParamValue());
+ statement.TryBind("@ItemId", itemId.ToGuidBlob());
statement.TryBind("@Name", person.Name);
statement.TryBind("@Role", person.Role);
statement.TryBind("@PersonType", person.Type);
@@ -5339,7 +5339,7 @@ namespace Emby.Server.Implementations.Data
using (var statement = PrepareStatementSafe(connection, cmdText))
{
- statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
+ statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
if (query.Type.HasValue)
{
@@ -5383,7 +5383,7 @@ namespace Emby.Server.Implementations.Data
using (var connection = CreateConnection())
{
// First delete chapters
- connection.Execute("delete from mediastreams where ItemId=@ItemId", id.ToGuidParamValue());
+ connection.Execute("delete from mediastreams where ItemId=@ItemId", id.ToGuidBlob());
using (var statement = PrepareStatement(connection, string.Format("replace into mediastreams ({0}) values ({1})",
string.Join(",", _mediaStreamSaveColumns),
@@ -5393,7 +5393,7 @@ namespace Emby.Server.Implementations.Data
{
var paramList = new List
diff --git a/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs b/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs
index 2becebb3d3..3c8ad55fe4 100644
--- a/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs
+++ b/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs
@@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.FFMpeg
else
{
info = existingVersion;
- versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath);
+ versionedDirectoryPath = _fileSystem.GetDirectoryName(info.EncoderPath);
excludeFromDeletions.Add(versionedDirectoryPath);
}
}
@@ -135,7 +135,7 @@ namespace Emby.Server.Implementations.FFMpeg
{
EncoderPath = encoder,
ProbePath = probe,
- Version = Path.GetFileName(Path.GetDirectoryName(probe))
+ Version = Path.GetFileName(_fileSystem.GetDirectoryName(probe))
};
}
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index ee5245a69a..5e96eda94a 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -228,7 +228,8 @@ namespace Emby.Server.Implementations.HttpServer
_streamFactory,
_enableDualModeSockets,
GetRequest,
- _fileSystem);
+ _fileSystem,
+ _environment);
}
private IHttpRequest GetRequest(HttpListenerContext httpContext)
@@ -452,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer
var date = DateTime.Now;
var httpRes = httpReq.Response;
bool enableLog = false;
+ bool logHeaders = false;
string urlToLog = null;
string remoteIp = null;
@@ -490,13 +492,14 @@ namespace Emby.Server.Implementations.HttpServer
var urlString = url.OriginalString;
enableLog = EnableLogging(urlString, localPath);
urlToLog = urlString;
+ logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
if (enableLog)
{
urlToLog = GetUrlToLog(urlString);
remoteIp = httpReq.RemoteIp;
- LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent);
+ LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent, logHeaders ? httpReq.Headers : null);
}
if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
@@ -611,7 +614,7 @@ namespace Emby.Server.Implementations.HttpServer
var duration = DateTime.Now - date;
- LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration);
+ LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration, logHeaders ? httpRes.Headers : null);
}
}
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index 687bd62b06..0af88595f9 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -353,31 +353,28 @@ namespace Emby.Server.Implementations.HttpServer
///
/// Pres the process optimized result.
///
- /// The request context.
- /// The responseHeaders.
- /// The cache key.
- /// The cache key string.
- /// The last date modified.
- /// Duration of the cache.
- /// Type of the content.
- /// System.Object.
private object GetCachedResult(IRequest requestContext, IDictionary responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType)
{
responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString);
- if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
+ var noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
+
+ if (!noCache)
{
- AddAgeHeader(responseHeaders, lastDateModified);
- AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration);
+ if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
+ {
+ AddAgeHeader(responseHeaders, lastDateModified);
+ AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration, noCache);
- var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
+ var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
- AddResponseHeaders(result, responseHeaders);
+ AddResponseHeaders(result, responseHeaders);
- return result;
+ return result;
+ }
}
- AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration);
+ AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration, noCache);
return null;
}
@@ -673,11 +670,7 @@ namespace Emby.Server.Implementations.HttpServer
///
/// Adds the caching responseHeaders.
///
- /// The responseHeaders.
- /// The cache key.
- /// The last date modified.
- /// Duration of the cache.
- private void AddCachingHeaders(IDictionary responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration)
+ private void AddCachingHeaders(IDictionary responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache)
{
// Don't specify both last modified and Etag, unless caching unconditionally. They are redundant
// https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching
@@ -687,11 +680,11 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r");
}
- if (cacheDuration.HasValue)
+ if (!noCache && cacheDuration.HasValue)
{
responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds);
}
- else if (!string.IsNullOrEmpty(cacheKey))
+ else if (!noCache && !string.IsNullOrEmpty(cacheKey))
{
responseHeaders["Cache-Control"] = "public";
}
@@ -701,18 +694,15 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
}
- AddExpiresHeader(responseHeaders, cacheKey, cacheDuration);
+ AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache);
}
///
/// Adds the expires header.
///
- /// The responseHeaders.
- /// The cache key.
- /// Duration of the cache.
- private void AddExpiresHeader(IDictionary responseHeaders, string cacheKey, TimeSpan? cacheDuration)
+ private void AddExpiresHeader(IDictionary responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache)
{
- if (cacheDuration.HasValue)
+ if (!noCache && cacheDuration.HasValue)
{
responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
}
diff --git a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs
index 8fc92a09a7..f0e75eea48 100644
--- a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs
+++ b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs
@@ -1,6 +1,8 @@
using MediaBrowser.Model.Logging;
using System;
using System.Globalization;
+using System.Linq;
+using MediaBrowser.Model.Services;
using SocketHttpListener.Net;
namespace Emby.Server.Implementations.HttpServer
@@ -19,9 +21,18 @@ namespace Emby.Server.Implementations.HttpServer
logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty);
}
- public static void LogRequest(ILogger logger, string url, string method, string userAgent)
+ public static void LogRequest(ILogger logger, string url, string method, string userAgent, QueryParamCollection headers)
{
- logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty);
+ if (headers == null)
+ {
+ logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty);
+ }
+ else
+ {
+ var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray());
+
+ logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
+ }
}
///
@@ -32,12 +43,13 @@ namespace Emby.Server.Implementations.HttpServer
/// The URL.
/// The end point.
/// The duration.
- public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration)
+ public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration, QueryParamCollection headers)
{
var durationMs = duration.TotalMilliseconds;
var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
- logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url);
+ var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
+ logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText);
}
}
}
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index b11b2fe88f..682fa7a0b8 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
@@ -30,8 +31,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private readonly IFileSystem _fileSystem;
private readonly Func _httpRequestFactory;
private readonly bool _enableDualMode;
+ private readonly IEnvironmentInfo _environment;
- public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func httpRequestFactory, IFileSystem fileSystem)
+ public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
{
_logger = logger;
_certificate = certificate;
@@ -44,6 +46,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_enableDualMode = enableDualMode;
_httpRequestFactory = httpRequestFactory;
_fileSystem = fileSystem;
+ _environment = environment;
}
public Action ErrorHandler { get; set; }
@@ -56,7 +59,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
public void Start(IEnumerable urlPrefixes)
{
if (_listener == null)
- _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem);
+ _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
_listener.EnableDualMode = _enableDualMode;
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
index fd30b227f0..9e58ee57cd 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Services;
using SocketHttpListener.Net;
using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
@@ -66,6 +67,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_response.AddHeader(name, value);
}
+ public QueryParamCollection Headers
+ {
+ get
+ {
+ return _response.Headers;
+ }
+ }
+
public string GetHeader(string name)
{
return _response.Headers[name];
diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs
index 033cbd8b01..edff251563 100644
--- a/Emby.Server.Implementations/IO/FileRefresher.cs
+++ b/Emby.Server.Implementations/IO/FileRefresher.cs
@@ -34,8 +34,9 @@ namespace Emby.Server.Implementations.IO
public event EventHandler Completed;
private readonly IEnvironmentInfo _environmentInfo;
+ private readonly ILibraryManager _libraryManager;
- public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo)
+ public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo, ILibraryManager libraryManager1)
{
logger.Debug("New file refresher created for {0}", path);
Path = path;
@@ -47,6 +48,7 @@ namespace Emby.Server.Implementations.IO
Logger = logger;
_timerFactory = timerFactory;
_environmentInfo = environmentInfo;
+ _libraryManager = libraryManager1;
AddPath(path);
}
@@ -235,6 +237,12 @@ namespace Emby.Server.Implementations.IO
return false;
}
+ // Only try to open video files
+ if (!_libraryManager.IsVideoFile(path))
+ {
+ return false;
+ }
+
try
{
var data = _fileSystem.GetFileSystemInfo(path);
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index 2677f7b2ad..b2ec84a82a 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -258,7 +258,7 @@ namespace Emby.Server.Implementations.Images
{
return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
}
- if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre)
+ if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum)
{
return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 685c794b76..3c94f97842 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1197,6 +1197,7 @@ namespace Emby.Server.Implementations.Library
catch (OperationCanceledException)
{
_logger.Info("Post-scan task cancelled: {0}", task.GetType().Name);
+ throw;
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
index 643c5970e1..d4be2dabed 100644
--- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
@@ -63,7 +63,7 @@ namespace Emby.Server.Implementations.Library.Validators
catch (OperationCanceledException)
{
// Don't clutter the log
- break;
+ throw;
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs
index b1820bb917..f7fbb93318 100644
--- a/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs
@@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Library.Validators
catch (OperationCanceledException)
{
// Don't clutter the log
- break;
+ throw;
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs
index d8956f78a1..d71e77a9a7 100644
--- a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs
@@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.Library.Validators
catch (OperationCanceledException)
{
// Don't clutter the log
- break;
+ throw;
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs
index 983c881b75..98d53c1250 100644
--- a/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs
@@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.Library.Validators
catch (OperationCanceledException)
{
// Don't clutter the log
- break;
+ throw;
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
index 6faab7bb9d..97b8ff0ac4 100644
--- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
@@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Library.Validators
catch (OperationCanceledException)
{
// Don't clutter the log
- break;
+ throw;
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs
index ae43c77f0a..4afb4c04a7 100644
--- a/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs
+++ b/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs
@@ -26,6 +26,8 @@ namespace Emby.Server.Implementations.Library.Validators
while (yearNumber < maxYear)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
try
{
var year = _libraryManager.GetYear(yearNumber);
@@ -35,7 +37,7 @@ namespace Emby.Server.Implementations.Library.Validators
catch (OperationCanceledException)
{
// Don't clutter the log
- break;
+ throw;
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
index 76c7a7d77c..40752db800 100644
--- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
+++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
@@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.Notifications
}
clauses.Add("UserId=?");
- paramList.Add(query.UserId.ToGuidParamValue());
+ paramList.Add(query.UserId.ToGuidBlob());
var whereClause = " where " + string.Join(" And ", clauses.ToArray());
@@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Notifications
using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead"))
{
statement.TryBind("@IsRead", false);
- statement.TryBind("@UserId", userId.ToGuidParamValue());
+ statement.TryBind("@UserId", userId.ToGuidBlob());
var levels = new List();
@@ -159,8 +159,8 @@ namespace Emby.Server.Implementations.Notifications
{
var notification = new Notification
{
- Id = reader[0].ReadGuid().ToString("N"),
- UserId = reader[1].ReadGuid().ToString("N"),
+ Id = reader[0].ReadGuidFromBlob().ToString("N"),
+ UserId = reader[1].ReadGuidFromBlob().ToString("N"),
Date = reader[2].ReadDateTime(),
Name = reader[3].ToString()
};
@@ -251,8 +251,8 @@ namespace Emby.Server.Implementations.Notifications
{
using (var statement = conn.PrepareStatement("replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)"))
{
- statement.TryBind("@Id", notification.Id.ToGuidParamValue());
- statement.TryBind("@UserId", notification.UserId.ToGuidParamValue());
+ statement.TryBind("@Id", notification.Id.ToGuidBlob());
+ statement.TryBind("@UserId", notification.UserId.ToGuidBlob());
statement.TryBind("@Date", notification.Date.ToDateTimeParamValue());
statement.TryBind("@Name", notification.Name);
statement.TryBind("@Description", notification.Description);
@@ -315,7 +315,7 @@ namespace Emby.Server.Implementations.Notifications
using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId"))
{
statement.TryBind("@IsRead", isRead);
- statement.TryBind("@UserId", userId.ToGuidParamValue());
+ statement.TryBind("@UserId", userId.ToGuidBlob());
statement.MoveNext();
}
@@ -337,13 +337,13 @@ namespace Emby.Server.Implementations.Notifications
using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId and Id=@Id"))
{
statement.TryBind("@IsRead", isRead);
- statement.TryBind("@UserId", userId.ToGuidParamValue());
+ statement.TryBind("@UserId", userId.ToGuidBlob());
foreach (var id in notificationIdList)
{
statement.Reset();
- statement.TryBind("@Id", id.ToGuidParamValue());
+ statement.TryBind("@Id", id.ToGuidBlob());
statement.MoveNext();
}
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
index a2d61873b8..9ec0af6bb5 100644
--- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
@@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.Security
{
using (var statement = db.PrepareStatement("replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"))
{
- statement.TryBind("@Id", info.Id.ToGuidParamValue());
+ statement.TryBind("@Id", info.Id.ToGuidBlob());
statement.TryBind("@AccessToken", info.AccessToken);
statement.TryBind("@DeviceId", info.DeviceId);
@@ -259,7 +259,7 @@ namespace Emby.Server.Implementations.Security
using (var statement = connection.PrepareStatement(commandText))
{
- statement.BindParameters["@Id"].Bind(id.ToGuidParamValue());
+ statement.BindParameters["@Id"].Bind(id.ToGuidBlob());
foreach (var row in statement.ExecuteQuery())
{
@@ -275,7 +275,7 @@ namespace Emby.Server.Implementations.Security
{
var info = new AuthenticationInfo
{
- Id = reader[0].ReadGuid().ToString("N"),
+ Id = reader[0].ReadGuidFromBlob().ToString("N"),
AccessToken = reader[1].ToString()
};
diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs
index e8230947ec..46e9205bb2 100644
--- a/Emby.Server.Implementations/Social/SharingRepository.cs
+++ b/Emby.Server.Implementations/Social/SharingRepository.cs
@@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.Social
var commandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (?, ?, ?, ?)";
db.Execute(commandText,
- info.Id.ToGuidParamValue(),
+ info.Id.ToGuidBlob(),
info.ItemId,
info.UserId,
info.ExpirationDate.ToDateTimeParamValue());
@@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Social
var commandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = ?";
var paramList = new List
/// true if [supports image encoding]; otherwise, false.
bool SupportsImageEncoding { get; }
+
+ ImageSize GetImageSize(string path);
}
}
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 19f391b4a6..a107c12328 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -112,5 +112,7 @@ namespace MediaBrowser.Controller.Drawing
///
/// true if [supports image collage creation]; otherwise, false.
bool SupportsImageCollageCreation { get; }
+
+ IImageEncoder ImageEncoder { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index f4b3d94554..70ac083430 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -86,6 +86,7 @@ namespace MediaBrowser.Controller.Drawing
PercentPlayed.Equals(0) &&
!UnplayedCount.HasValue &&
!Blur.HasValue &&
+ !CropWhiteSpace &&
string.IsNullOrEmpty(BackgroundColor) &&
string.IsNullOrEmpty(ForegroundLayer);
}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index ca0b97a9f6..11311905c2 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -1306,7 +1306,8 @@ namespace MediaBrowser.Controller.MediaEncoding
filters.Add("format=nv12|vaapi");
filters.Add("hwupload");
}
- else if (state.DeInterlace && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+
+ if (state.DeInterlace && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
filters.Add("yadif=0:-1:0");
}
@@ -1533,14 +1534,26 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var flags = new List();
- if (state.IgnoreDts)
+ if (state.IgnoreInputDts)
{
flags.Add("+igndts");
}
- if (state.IgnoreIndex)
+ if (state.IgnoreInputIndex)
{
flags.Add("+ignidx");
}
+ if (state.GenPtsInput)
+ {
+ flags.Add("+genpts");
+ }
+ if (state.DiscardCorruptFramesInput)
+ {
+ flags.Add("+discardcorrupt");
+ }
+ if (state.EnableFastSeekInput)
+ {
+ flags.Add("+fastseek");
+ }
if (flags.Count > 0)
{
@@ -1864,6 +1877,22 @@ namespace MediaBrowser.Controller.MediaEncoding
).Trim();
}
+ public string GetOutputFFlags(EncodingJobInfo state)
+ {
+ var flags = new List();
+ if (state.GenPtsOutput)
+ {
+ flags.Add("+genpts");
+ }
+
+ if (flags.Count > 0)
+ {
+ return " -fflags " + string.Join("", flags.ToArray());
+ }
+
+ return string.Empty;
+ }
+
public string GetProgressiveVideoArguments(EncodingJobInfo state, EncodingOptions encodingOptions, string videoCodec, string defaultH264Preset)
{
var args = "-codec:v:0 " + videoCodec;
@@ -1943,6 +1972,8 @@ namespace MediaBrowser.Controller.MediaEncoding
args += " -vsync " + state.OutputVideoSync;
}
+ args += GetOutputFFlags(state);
+
return args;
}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index 28ada9daeb..409dec482c 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -39,14 +39,52 @@ namespace MediaBrowser.Controller.MediaEncoding
public bool ReadInputAtNativeFramerate { get; set; }
- public bool IgnoreDts
+ public bool IgnoreInputDts
{
- get { return MediaSource.IgnoreDts; }
+ get
+ {
+ return MediaSource.IgnoreDts;
+ }
}
- public bool IgnoreIndex
+ public bool IgnoreInputIndex
{
- get { return MediaSource.IgnoreIndex; }
+ get
+ {
+ return MediaSource.IgnoreIndex;
+ }
+ }
+
+ public bool GenPtsInput
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool DiscardCorruptFramesInput
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool EnableFastSeekInput
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public bool GenPtsOutput
+ {
+ get
+ {
+ return false;
+ }
}
public string OutputContainer { get; set; }
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index a3a55176cd..57e2ec450d 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -218,13 +218,9 @@ namespace MediaBrowser.LocalMetadata.Savers
{
if (file.IsHidden)
{
- FileSystem.SetHidden(path, false);
wasHidden = true;
}
- if (file.IsReadOnly)
- {
- FileSystem.SetReadOnly(path, false);
- }
+ FileSystem.SetAttributes(path, false, false);
}
using (var filestream = FileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index 15221c2acd..27f66835f5 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -50,10 +50,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return false;
}
- if (logOutput)
- {
- _logger.Info("ffmpeg info: {0}", output);
- }
+ _logger.Info("ffmpeg info: {0}", output);
if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1)
{
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 8b20dca1b5..6270b87c65 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -176,6 +176,14 @@ namespace MediaBrowser.MediaEncoding.Probing
info.Video3DFormat = Video3DFormat.FullSideBySide;
}
+ foreach (var mediaStream in info.MediaStreams)
+ {
+ if (mediaStream.Type == MediaStreamType.Audio && !mediaStream.BitRate.HasValue)
+ {
+ mediaStream.BitRate = GetEstimatedAudioBitrate(mediaStream.Codec, mediaStream.Channels);
+ }
+ }
+
var videoStreamsBitrate = info.MediaStreams.Where(i => i.Type == MediaStreamType.Video).Select(i => i.BitRate ?? 0).Sum();
// If ffprobe reported the container bitrate as being the same as the video stream bitrate, then it's wrong
if (videoStreamsBitrate == (info.Bitrate ?? 0))
@@ -187,6 +195,32 @@ namespace MediaBrowser.MediaEncoding.Probing
return info;
}
+ private int? GetEstimatedAudioBitrate(string codec, int? channels)
+ {
+ if (!channels.HasValue)
+ {
+ return null;
+ }
+
+ var channelsValue = channels.Value;
+
+ if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
+ {
+ if (channelsValue <= 2)
+ {
+ return 192000;
+ }
+
+ if (channelsValue >= 5)
+ {
+ return 320000;
+ }
+ }
+
+ return null;
+ }
+
private void FetchFromItunesInfo(string xml, MediaInfo info)
{
// Make things simpler and strip out the dtd
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 838111a383..60bbf62404 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -55,6 +55,7 @@ namespace MediaBrowser.Model.Configuration
///
/// The value pointing to the file system where the ssl certiifcate is located..
public string CertificatePath { get; set; }
+ public string CertificatePassword { get; set; }
///
/// Gets or sets a value indicating whether this instance is port authorized.
diff --git a/MediaBrowser.Model/Drawing/ImageSize.cs b/MediaBrowser.Model/Drawing/ImageSize.cs
index 8cf09da185..c2b0291bdb 100644
--- a/MediaBrowser.Model/Drawing/ImageSize.cs
+++ b/MediaBrowser.Model/Drawing/ImageSize.cs
@@ -61,6 +61,12 @@ namespace MediaBrowser.Model.Drawing
_height = height;
}
+ public ImageSize(double width, double height)
+ {
+ _width = width;
+ _height = height;
+ }
+
private void ParseValue(string value)
{
if (!string.IsNullOrEmpty(value))
diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs
index 26de9332e3..ea6b048248 100644
--- a/MediaBrowser.Model/IO/IFileSystem.cs
+++ b/MediaBrowser.Model/IO/IFileSystem.cs
@@ -108,6 +108,8 @@ namespace MediaBrowser.Model.IO
/// FileStream.
Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false);
+ Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions);
+
///
/// Opens the read.
///
@@ -311,7 +313,8 @@ namespace MediaBrowser.Model.IO
IEnumerable GetFileSystemEntryPaths(string path, bool recursive = false);
void SetHidden(string path, bool isHidden);
- void SetReadOnly(string path, bool isHidden);
+ void SetReadOnly(string path, bool readOnly);
+ void SetAttributes(string path, bool isHidden, bool readOnly);
char DirectorySeparatorChar { get; }
@@ -402,4 +405,46 @@ namespace MediaBrowser.Model.IO
ReadWrite = 3
}
+ //
+ // Summary:
+ // Represents advanced options for creating a System.IO.FileStream object.
+ [Flags]
+ public enum FileOpenOptions
+ {
+ //
+ // Summary:
+ // Indicates that the system should write through any intermediate cache and go
+ // directly to disk.
+ WriteThrough = int.MinValue,
+ //
+ // Summary:
+ // Indicates that no additional options should be used when creating a System.IO.FileStream
+ // object.
+ None = 0,
+ //
+ // Summary:
+ // Indicates that a file is encrypted and can be decrypted only by using the same
+ // user account used for encryption.
+ Encrypted = 16384,
+ //
+ // Summary:
+ // Indicates that a file is automatically deleted when it is no longer in use.
+ DeleteOnClose = 67108864,
+ //
+ // Summary:
+ // Indicates that the file is to be accessed sequentially from beginning to end.
+ // The system can use this as a hint to optimize file caching. If an application
+ // moves the file pointer for random access, optimum caching may not occur; however,
+ // correct operation is still guaranteed.
+ SequentialScan = 134217728,
+ //
+ // Summary:
+ // Indicates that the file is accessed randomly. The system can use this as a hint
+ // to optimize file caching.
+ RandomAccess = 268435456,
+ //
+ // Summary:
+ // Indicates that a file can be used for asynchronous reading and writing.
+ Asynchronous = 1073741824
+ }
}
diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs
index 115ba25ce0..f056c7410a 100644
--- a/MediaBrowser.Model/Services/IRequest.cs
+++ b/MediaBrowser.Model/Services/IRequest.cs
@@ -155,6 +155,8 @@ namespace MediaBrowser.Model.Services
//Add Metadata to Response
Dictionary Items { get; }
+ QueryParamCollection Headers { get; }
+
Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 1d8275c26f..4bd5044094 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -166,7 +166,7 @@ namespace MediaBrowser.Providers.Manager
{
var currentPath = currentImagePath;
- _logger.Debug("Deleting previous image {0}", currentPath);
+ _logger.Info("Deleting previous image {0}", currentPath);
_libraryMonitor.ReportFileSystemChangeBeginning(currentPath);
@@ -236,7 +236,7 @@ namespace MediaBrowser.Providers.Manager
/// Task.
private async Task SaveImageToLocation(Stream source, string path, CancellationToken cancellationToken)
{
- _logger.Debug("Saving image to {0}", path);
+ _logger.Info("Saving image to {0}", path);
var parentFolder = _fileSystem.GetDirectoryName(path);
@@ -249,31 +249,16 @@ namespace MediaBrowser.Providers.Manager
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
- // If the file is currently hidden we'll have to remove that or the save will fail
- var file = _fileSystem.GetFileInfo(path);
+ _fileSystem.SetAttributes(path, false, false);
- // This will fail if the file is hidden
- if (file.Exists)
+ using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.Asynchronous))
{
- if (file.IsHidden)
- {
- _fileSystem.SetHidden(file.FullName, false);
- }
- if (file.IsReadOnly)
- {
- _fileSystem.SetReadOnly(path, false);
- }
- }
-
- using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
- {
- await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken)
- .ConfigureAwait(false);
+ await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
}
if (_config.Configuration.SaveMetadataHidden)
{
- _fileSystem.SetHidden(file.FullName, true);
+ _fileSystem.SetHidden(path, true);
}
}
finally
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index f544c09dc1..d5494c21fd 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -200,6 +200,7 @@ namespace MediaBrowser.Providers.Manager
MergeCriticRating(source, target, lockedFields, replaceData);
MergeAwards(source, target, lockedFields, replaceData);
MergeTrailers(source, target, lockedFields, replaceData);
+ MergeVideoInfo(source, target, lockedFields, replaceData);
if (mergeMetadataSettings)
{
@@ -307,5 +308,19 @@ namespace MediaBrowser.Providers.Manager
}
}
}
+
+ private static void MergeVideoInfo(BaseItem source, BaseItem target, List lockedFields, bool replaceData)
+ {
+ var sourceCast = source as Video;
+ var targetCast = target as Video;
+
+ if (sourceCast != null && targetCast != null)
+ {
+ if (replaceData || targetCast.Video3DFormat == null)
+ {
+ targetCast.Video3DFormat = sourceCast.Video3DFormat;
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
index 477543d5e2..f9d19b6be5 100644
--- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
@@ -72,8 +72,7 @@ namespace MediaBrowser.Providers.Omdb
var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);
- var baseUrl = await OmdbProvider.GetOmdbBaseUrl(cancellationToken).ConfigureAwait(false);
- var url = baseUrl + "/?plot=full&r=json";
+ var urlQuery = "plot=full&r=json";
if (type == "episode" && episodeSearchInfo != null)
{
episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out imdbId);
@@ -94,23 +93,23 @@ namespace MediaBrowser.Providers.Omdb
{
if (year.HasValue)
{
- url += "&y=" + year.Value.ToString(CultureInfo.InvariantCulture);
+ urlQuery += "&y=" + year.Value.ToString(CultureInfo.InvariantCulture);
}
// &s means search and returns a list of results as opposed to t
if (isSearch)
{
- url += "&s=" + WebUtility.UrlEncode(name);
+ urlQuery += "&s=" + WebUtility.UrlEncode(name);
}
else
{
- url += "&t=" + WebUtility.UrlEncode(name);
+ urlQuery += "&t=" + WebUtility.UrlEncode(name);
}
- url += "&type=" + type;
+ urlQuery += "&type=" + type;
}
else
{
- url += "&i=" + imdbId;
+ urlQuery += "&i=" + imdbId;
isSearch = false;
}
@@ -118,14 +117,16 @@ namespace MediaBrowser.Providers.Omdb
{
if (searchInfo.IndexNumber.HasValue)
{
- url += string.Format(CultureInfo.InvariantCulture, "&Episode={0}", searchInfo.IndexNumber);
+ urlQuery += string.Format(CultureInfo.InvariantCulture, "&Episode={0}", searchInfo.IndexNumber);
}
if (searchInfo.ParentIndexNumber.HasValue)
{
- url += string.Format(CultureInfo.InvariantCulture, "&Season={0}", searchInfo.ParentIndexNumber);
+ urlQuery += string.Format(CultureInfo.InvariantCulture, "&Season={0}", searchInfo.ParentIndexNumber);
}
}
+ var url = await OmdbProvider.GetOmdbUrl(urlQuery, cancellationToken).ConfigureAwait(false);
+
using (var stream = await OmdbProvider.GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false))
{
var resultList = new List();
diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
index d1c3b22142..b89105376a 100644
--- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
@@ -265,9 +265,16 @@ namespace MediaBrowser.Providers.Omdb
return false;
}
- public static async Task GetOmdbBaseUrl(CancellationToken cancellationToken)
+ public static async Task GetOmdbUrl(string query, CancellationToken cancellationToken)
{
- return "https://www.omdbapi.com";
+ var url = "https://www.omdbapi.com?apikey=fe53f97e";
+
+ if (!string.IsNullOrWhiteSpace(query))
+ {
+ url += "&" + query;
+ }
+
+ return url;
}
private async Task EnsureItemInfo(string imdbId, CancellationToken cancellationToken)
@@ -292,8 +299,7 @@ namespace MediaBrowser.Providers.Omdb
}
}
- var baseUrl = await GetOmdbBaseUrl(cancellationToken).ConfigureAwait(false);
- var url = string.Format(baseUrl + "/?i={0}&plot=full&tomatoes=true&r=json", imdbParam);
+ var url = await GetOmdbUrl(string.Format("i={0}&plot=full&tomatoes=true&r=json", imdbParam), cancellationToken).ConfigureAwait(false);
using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false))
{
@@ -327,8 +333,7 @@ namespace MediaBrowser.Providers.Omdb
}
}
- var baseUrl = await GetOmdbBaseUrl(cancellationToken).ConfigureAwait(false);
- var url = string.Format(baseUrl + "/?i={0}&season={1}&detail=full", imdbParam, seasonId);
+ var url = await GetOmdbUrl(string.Format("i={0}&season={1}&detail=full", imdbParam, seasonId), cancellationToken).ConfigureAwait(false);
using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false))
{
diff --git a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
index 8133efafb8..73626328a2 100644
--- a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
+++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
@@ -122,10 +122,10 @@
..\ThirdParty\taglib\TagLib.Portable.dll
- ..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll
+ ..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll
- ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
+ ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
..\ThirdParty\emby\Emby.Server.Connect.dll
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index bcdfa858ff..e4bde07c7d 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -94,11 +94,11 @@
True
- ..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll
+ ..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll
True
- ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
+ ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
True
diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config
index 81da308f52..de26c7666e 100644
--- a/MediaBrowser.Server.Mono/packages.config
+++ b/MediaBrowser.Server.Mono/packages.config
@@ -5,6 +5,6 @@
-
-
+
+
\ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
index ddbde2f666..b8fa097d64 100644
--- a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
+++ b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
@@ -2,6 +2,7 @@
using Emby.Drawing;
using Emby.Drawing.Net;
using Emby.Drawing.ImageMagick;
+using Emby.Drawing.Skia;
using Emby.Server.Core;
using Emby.Server.Implementations;
using MediaBrowser.Common.Configuration;
@@ -23,6 +24,15 @@ namespace MediaBrowser.Server.Startup.Common
{
if (!startupOptions.ContainsOption("-enablegdi"))
{
+ try
+ {
+ return new SkiaEncoder(logManager.GetLogger("Skia"), appPaths, httpClient, fileSystem);
+ }
+ catch
+ {
+ logger.Error("Error loading Skia. Will revert to ImageMagick.");
+ }
+
try
{
return new ImageMagickEncoder(logManager.GetLogger("ImageMagick"), appPaths, httpClient, fileSystem);
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index 8e38c9a987..272054609f 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -22,6 +22,7 @@ using Emby.Common.Implementations.IO;
using Emby.Common.Implementations.Logging;
using Emby.Common.Implementations.Networking;
using Emby.Common.Implementations.Security;
+using Emby.Drawing;
using Emby.Server.Core;
using Emby.Server.Core.Logging;
using Emby.Server.Implementations;
@@ -335,8 +336,6 @@ namespace MediaBrowser.ServerApplication
var fileSystem = new ManagedFileSystem(logManager.GetLogger("FileSystem"), environmentInfo, appPaths.TempDirectory);
- var imageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => _appHost.HttpClient, appPaths);
-
FileSystem = fileSystem;
_appHost = new WindowsAppHost(appPaths,
@@ -346,7 +345,7 @@ namespace MediaBrowser.ServerApplication
new PowerManagement(),
"emby.windows.zip",
environmentInfo,
- imageEncoder,
+ new NullImageEncoder(),
new Server.Startup.Common.SystemEvents(logManager.GetLogger("SystemEvents")),
new RecyclableMemoryStreamProvider(),
new Networking.NetworkManager(logManager.GetLogger("NetworkManager")),
@@ -367,6 +366,19 @@ namespace MediaBrowser.ServerApplication
var task = _appHost.Init(initProgress);
Task.WaitAll(task);
+ if (!runService)
+ {
+ task = InstallVcredist2013IfNeeded(_appHost, _logger);
+ Task.WaitAll(task);
+
+ // needed by skia
+ task = InstallVcredist2015IfNeeded(_appHost, _logger);
+ Task.WaitAll(task);
+ }
+
+ // set image encoder here
+ _appHost.ImageProcessor.ImageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => _appHost.HttpClient, appPaths);
+
task = task.ContinueWith(new Action(a => _appHost.RunStartupTasks()), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent);
if (runService)
@@ -377,9 +389,6 @@ namespace MediaBrowser.ServerApplication
{
Task.WaitAll(task);
- task = InstallVcredist2013IfNeeded(_appHost, _logger);
- Task.WaitAll(task);
-
Microsoft.Win32.SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
HideSplashScreen();
@@ -736,31 +745,6 @@ namespace MediaBrowser.ServerApplication
Process.Start(startInfo);
}
- private static bool CanRestartWindowsService()
- {
- var startInfo = new ProcessStartInfo
- {
- FileName = "cmd.exe",
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- Verb = "runas",
- ErrorDialog = false,
- Arguments = String.Format("/c sc query {0}", BackgroundService.GetExistingServiceName())
- };
- using (var process = Process.Start(startInfo))
- {
- process.WaitForExit();
- if (process.ExitCode == 0)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- }
-
private static async Task InstallVcredist2013IfNeeded(ApplicationHost appHost, ILogger logger)
{
// Reference
@@ -791,9 +775,11 @@ namespace MediaBrowser.ServerApplication
return;
}
+ MessageBox.Show("The Visual C++ 2013 Runtime will now be installed.", "Install Visual C++ Runtime", MessageBoxButtons.OK, MessageBoxIcon.Information);
+
try
{
- await InstallVcredist2013().ConfigureAwait(false);
+ await InstallVcredist(GetVcredist2013Url()).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -801,13 +787,79 @@ namespace MediaBrowser.ServerApplication
}
}
- private async static Task InstallVcredist2013()
+ private static string GetVcredist2013Url()
+ {
+ if (Environment.Is64BitProcess)
+ {
+ return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_x64.exe";
+ }
+
+ // TODO: ARM url - https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_arm.exe
+
+ return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_x86.exe";
+ }
+
+ private static async Task InstallVcredist2015IfNeeded(ApplicationHost appHost, ILogger logger)
+ {
+ // Reference
+ // http://stackoverflow.com/questions/12206314/detect-if-visual-c-redistributable-for-visual-studio-2012-is-installed
+
+ try
+ {
+ var subkey = Environment.Is64BitProcess
+ ? "SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64"
+ : "SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x86";
+
+ using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default)
+ .OpenSubKey(subkey))
+ {
+ if (ndpKey != null && ndpKey.GetValue("Version") != null)
+ {
+ var installedVersion = ((string)ndpKey.GetValue("Version")).TrimStart('v');
+ if (installedVersion.StartsWith("14", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.ErrorException("Error getting .NET Framework version", ex);
+ return;
+ }
+
+ MessageBox.Show("The Visual C++ 2015 Runtime will now be installed.", "Install Visual C++ Runtime", MessageBoxButtons.OK, MessageBoxIcon.Information);
+
+ try
+ {
+ await InstallVcredist(GetVcredist2015Url()).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ logger.ErrorException("Error installing Visual Studio C++ runtime", ex);
+ }
+ }
+
+ private static string GetVcredist2015Url()
+ {
+ if (Environment.Is64BitProcess)
+ {
+ return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2015/vc_redist.x64.exe";
+ }
+
+ // TODO: ARM url - https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2015/vcredist_arm.exe
+
+ return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2015/vc_redist.x86.exe";
+ }
+
+ private async static Task InstallVcredist(string url)
{
var httpClient = _appHost.HttpClient;
var tmp = await httpClient.GetTempFile(new HttpRequestOptions
{
- Url = GetVcredist2013Url(),
+ Url = url,
Progress = new Progress()
}).ConfigureAwait(false);
@@ -833,18 +885,6 @@ namespace MediaBrowser.ServerApplication
}
}
- private static string GetVcredist2013Url()
- {
- if (Environment.Is64BitProcess)
- {
- return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_x64.exe";
- }
-
- // TODO: ARM url - https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_arm.exe
-
- return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_x86.exe";
- }
-
///
/// Sets the error mode.
///
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 749468fe2b..d632007d20 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -99,12 +99,16 @@
..\packages\SimpleInjector.3.3.2\lib\net45\SimpleInjector.dll
True
+
+ ..\packages\SkiaSharp.1.57.1\lib\net45\SkiaSharp.dll
+ True
+
- ..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll
+ ..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll
True
- ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
+ ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
True
@@ -185,6 +189,14 @@
+
+ x64\libSkiaSharp.dll
+ PreserveNewest
+
+
+ x86\libSkiaSharp.dll
+ PreserveNewest
+
MediaBrowser.InstallUtil.dll
PreserveNewest
@@ -1100,6 +1112,10 @@
{c97a239e-a96c-4d64-a844-ccf8cc30aecb}
Emby.Drawing.Net
+
+ {2312da6d-ff86-4597-9777-bceec32d96dd}
+ Emby.Drawing.Skia
+
{08fff49b-f175-4807-a2b5-73b0ebd9f716}
Emby.Drawing
diff --git a/MediaBrowser.ServerApplication/Native/LoopUtil.cs b/MediaBrowser.ServerApplication/Native/LoopUtil.cs
index 9a96f5518e..7c74712312 100644
--- a/MediaBrowser.ServerApplication/Native/LoopUtil.cs
+++ b/MediaBrowser.ServerApplication/Native/LoopUtil.cs
@@ -57,10 +57,6 @@ namespace MediaBrowser.ServerApplication.Native
}
- // Call this API to free the memory returned by the Enumeration API
- [DllImport("FirewallAPI.dll")]
- internal static extern void NetworkIsolationFreeAppContainers(IntPtr pACs);
-
// Call this API to load the current list of LoopUtil-enabled AppContainers
[DllImport("FirewallAPI.dll")]
internal static extern uint NetworkIsolationGetAppContainerConfig(out uint pdwCntACs, out IntPtr appContainerSids);
@@ -69,23 +65,13 @@ namespace MediaBrowser.ServerApplication.Native
[DllImport("FirewallAPI.dll")]
private static extern uint NetworkIsolationSetAppContainerConfig(uint pdwCntACs, SID_AND_ATTRIBUTES[] appContainerSids);
-
// Use this API to convert a string SID into an actual SID
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool ConvertStringSidToSid(string strSid, out IntPtr pSid);
- [DllImport("advapi32", /*CharSet = CharSet.Auto,*/ SetLastError = true)]
- static extern bool ConvertSidToStringSid(
- [MarshalAs(UnmanagedType.LPArray)] byte[] pSID,
- out IntPtr ptrSid);
-
[DllImport("advapi32", /*CharSet = CharSet.Auto,*/ SetLastError = true)]
static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid);
- // Use this API to convert a string reference (e.g. "@{blah.pri?ms-resource://whatever}") into a plain string
- [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
- internal static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf);
-
// Call this API to enumerate all of the AppContainers on the system
[DllImport("FirewallAPI.dll")]
internal static extern uint NetworkIsolationEnumAppContainers(uint Flags, out uint pdwCntPublicACs, out IntPtr ppACs);
@@ -196,7 +182,6 @@ namespace MediaBrowser.ServerApplication.Native
{
util.SaveLoopbackState();
}
- util.SaveLoopbackState();
}
private static List PI_NetworkIsolationGetAppContainerConfig()
@@ -305,11 +290,5 @@ namespace MediaBrowser.ServerApplication.Native
}
return count;
}
-
- public void FreeResources()
- {
- NetworkIsolationFreeAppContainers(_pACs);
- }
-
}
}
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 68d0a7fdad..2d4ba61707 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -5,6 +5,7 @@
-
-
+
+
+
\ No newline at end of file
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index dfd4694c36..d8f7cb57f4 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -15,6 +15,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Xml;
@@ -227,6 +228,11 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
}
+ protected virtual string MovieDbParserSearchString
+ {
+ get { return "themoviedb.org/movie/"; }
+ }
+
private void ParseProviderLinks(T item, string xml)
{
//Look for a match for the Regex pattern "tt" followed by 7 digits
@@ -238,7 +244,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
// Support Tmdb
// http://www.themoviedb.org/movie/36557
- var srch = "themoviedb.org/movie/";
+ var srch = MovieDbParserSearchString;
var index = xml.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
if (index != -1)
@@ -250,6 +256,23 @@ namespace MediaBrowser.XbmcMetadata.Parsers
item.SetProviderId(MetadataProviders.Tmdb, tmdbId);
}
}
+
+ if (item is Series)
+ {
+ srch = "thetvdb.com/?tab=series&id=";
+
+ index = xml.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
+
+ if (index != -1)
+ {
+ var tvdbId = xml.Substring(index + srch.Length).TrimEnd('/');
+ int value;
+ if (!string.IsNullOrWhiteSpace(tvdbId) && int.TryParse(tvdbId, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
+ {
+ item.SetProviderId(MetadataProviders.Tvdb, tvdbId);
+ }
+ }
+ }
}
protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult itemResult)
diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
index 98016f4f70..b0db4e6f38 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
@@ -13,6 +13,19 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
public class SeriesNfoParser : BaseNfoParser
{
+ protected override bool SupportsUrlAfterClosingXmlTag
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ protected override string MovieDbParserSearchString
+ {
+ get { return "themoviedb.org/tv/"; }
+ }
+
///
/// Fetches the data from XML node.
///
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 623b109f76..ae24928028 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -220,14 +220,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
if (file.IsHidden)
{
- FileSystem.SetHidden(path, false);
-
wasHidden = true;
}
- if (file.IsReadOnly)
- {
- FileSystem.SetReadOnly(path, false);
- }
+ FileSystem.SetAttributes(path, false, false);
}
using (var filestream = FileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index b9933969f5..219beeab16 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -80,6 +80,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Net", "Emby.Dr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener.Portable", "SocketHttpListener.Portable\SocketHttpListener.Portable.csproj", "{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Skia", "Emby.Drawing.Skia\Emby.Drawing.Skia.csproj", "{2312DA6D-FF86-4597-9777-BCEEC32D96DD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1099,6 +1101,46 @@ Global
{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x64.Build.0 = Release|Any CPU
{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.ActiveCfg = Release|Any CPU
{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Win32.Build.0 = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x64.Build.0 = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x86.Build.0 = Debug|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Any CPU.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Win32.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Win32.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x64.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x64.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x86.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x86.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Win32.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Win32.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x64.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x64.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x86.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x86.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Any CPU.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Any CPU.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Mixed Platforms.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Win32.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Win32.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.Build.0 = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.ActiveCfg = Release|Any CPU
+ {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index c86e9a71cd..64e4d14181 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Common
- 3.0.699
+ 3.0.700
Emby.Common
Emby Team
ebr,Luke,scottisafool
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index f68cf4e410..917288cb1e 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Server.Core
- 3.0.699
+ 3.0.700
Emby.Server.Core
Emby Team
ebr,Luke,scottisafool
@@ -12,7 +12,7 @@
Contains core components required to build plugins for Emby Server.
Copyright © Emby 2013
-
+
diff --git a/SocketHttpListener.Portable/Net/EndPointListener.cs b/SocketHttpListener.Portable/Net/EndPointListener.cs
index 4f1a17fc0d..2106bbec56 100644
--- a/SocketHttpListener.Portable/Net/EndPointListener.cs
+++ b/SocketHttpListener.Portable/Net/EndPointListener.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.System;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
@@ -33,8 +34,9 @@ namespace SocketHttpListener.Net
private readonly ITextEncoding _textEncoding;
private readonly IMemoryStreamFactory _memoryStreamFactory;
private readonly IFileSystem _fileSystem;
+ private readonly IEnvironmentInfo _environment;
- public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem)
+ public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{
this.listener = listener;
_logger = logger;
@@ -44,6 +46,7 @@ namespace SocketHttpListener.Net
_memoryStreamFactory = memoryStreamFactory;
_textEncoding = textEncoding;
_fileSystem = fileSystem;
+ _environment = environment;
this.secure = secure;
this.cert = cert;
@@ -109,7 +112,7 @@ namespace SocketHttpListener.Net
return;
}
- HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem).ConfigureAwait(false);
+ HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
//_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
lock (listener.unregistered)
diff --git a/SocketHttpListener.Portable/Net/EndPointManager.cs b/SocketHttpListener.Portable/Net/EndPointManager.cs
index 11f7749153..6a00ed360a 100644
--- a/SocketHttpListener.Portable/Net/EndPointManager.cs
+++ b/SocketHttpListener.Portable/Net/EndPointManager.cs
@@ -106,7 +106,7 @@ namespace SocketHttpListener.Net
}
else
{
- epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem);
+ epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
p[port] = epl;
}
diff --git a/SocketHttpListener.Portable/Net/HttpConnection.cs b/SocketHttpListener.Portable/Net/HttpConnection.cs
index ac8ada4862..65e7470f7e 100644
--- a/SocketHttpListener.Portable/Net/HttpConnection.cs
+++ b/SocketHttpListener.Portable/Net/HttpConnection.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.System;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
@@ -41,8 +42,9 @@ namespace SocketHttpListener.Net
private readonly ITextEncoding _textEncoding;
private readonly IStreamFactory _streamFactory;
private readonly IFileSystem _fileSystem;
+ private readonly IEnvironmentInfo _environment;
- private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem)
+ private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{
_logger = logger;
this.sock = sock;
@@ -53,6 +55,7 @@ namespace SocketHttpListener.Net
_memoryStreamFactory = memoryStreamFactory;
_textEncoding = textEncoding;
_fileSystem = fileSystem;
+ _environment = environment;
_streamFactory = streamFactory;
}
@@ -84,9 +87,9 @@ namespace SocketHttpListener.Net
Init();
}
- public static async Task Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem)
+ public static async Task Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{
- var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem);
+ var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment);
await connection.InitStream().ConfigureAwait(false);
@@ -217,7 +220,7 @@ namespace SocketHttpListener.Net
{
var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure;
- o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger);
+ o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment);
}
else
{
diff --git a/SocketHttpListener.Portable/Net/HttpListener.cs b/SocketHttpListener.Portable/Net/HttpListener.cs
index c2e7acd8e7..b3e01425ca 100644
--- a/SocketHttpListener.Portable/Net/HttpListener.cs
+++ b/SocketHttpListener.Portable/Net/HttpListener.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.System;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
@@ -22,6 +23,7 @@ namespace SocketHttpListener.Net
internal ITextEncoding TextEncoding { get; private set; }
internal IMemoryStreamFactory MemoryStreamFactory { get; private set; }
internal INetworkManager NetworkManager { get; private set; }
+ internal IEnvironmentInfo EnvironmentInfo { get; private set; }
public bool EnableDualMode { get; set; }
@@ -40,7 +42,7 @@ namespace SocketHttpListener.Net
public Action OnContext { get; set; }
- public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem)
+ public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
{
_logger = logger;
CryptoProvider = cryptoProvider;
@@ -50,19 +52,20 @@ namespace SocketHttpListener.Net
TextEncoding = textEncoding;
MemoryStreamFactory = memoryStreamFactory;
FileSystem = fileSystem;
+ EnvironmentInfo = environmentInfo;
prefixes = new HttpListenerPrefixCollection(logger, this);
registry = new Dictionary();
connections = new Dictionary();
auth_schemes = AuthenticationSchemes.Anonymous;
}
- public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem)
- :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem)
+ public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+ :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
{
}
- public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem)
- : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem)
+ public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+ : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
{
_certificate = certificate;
}
diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs
index dea4049d56..9552fe8ca0 100644
--- a/SocketHttpListener.Portable/Net/ResponseStream.cs
+++ b/SocketHttpListener.Portable/Net/ResponseStream.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.System;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
@@ -28,8 +29,9 @@ namespace SocketHttpListener.Net
private readonly IAcceptSocket _socket;
private readonly bool _supportsDirectSocketAccess;
private readonly ILogger _logger;
+ private readonly IEnvironmentInfo _environment;
- internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger)
+ internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger, IEnvironmentInfo environment)
{
this.response = response;
_memoryStreamFactory = memoryStreamFactory;
@@ -38,6 +40,7 @@ namespace SocketHttpListener.Net
_socket = socket;
_supportsDirectSocketAccess = supportsDirectSocketAccess;
_logger = logger;
+ _environment = environment;
this.stream = stream;
}
@@ -344,7 +347,20 @@ namespace SocketHttpListener.Net
private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
{
- using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, true))
+ var allowAsync = _environment.OperatingSystem != OperatingSystem.Windows;
+
+ var fileOpenOptions = offset > 0
+ ? FileOpenOptions.RandomAccess
+ : FileOpenOptions.SequentialScan;
+
+ if (allowAsync)
+ {
+ fileOpenOptions |= FileOpenOptions.Asynchronous;
+ }
+
+ // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+
+ using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
{
if (offset > 0)
{
@@ -355,11 +371,53 @@ namespace SocketHttpListener.Net
if (count > 0)
{
- await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
+ if (allowAsync)
+ {
+ await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await CopyToInternalAsyncWithSyncRead(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
+ }
}
else
{
- await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false);
+ if (allowAsync)
+ {
+ await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ fs.CopyTo(targetStream, 81920);
+ }
+ }
+ }
+ }
+
+ private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
+ {
+ var array = new byte[81920];
+ int bytesRead;
+
+ while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
+ {
+ if (bytesRead == 0)
+ {
+ break;
+ }
+
+ var bytesToWrite = Math.Min(bytesRead, copyLength);
+
+ if (bytesToWrite > 0)
+ {
+ await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
+ }
+
+ copyLength -= bytesToWrite;
+
+ if (copyLength <= 0)
+ {
+ break;
}
}
}
@@ -368,7 +426,7 @@ namespace SocketHttpListener.Net
{
var array = new byte[81920];
int bytesRead;
-
+
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
if (bytesRead == 0)