Merge remote-tracking branch 'remotes/jellyfin/api-migration' into api-audio

# Conflicts:
#	Emby.Server.Implementations/ApplicationHost.cs
#	Jellyfin.Api/Helpers/TranscodingJobHelper.cs
This commit is contained in:
David 2020-07-22 11:02:44 +02:00
commit 90039e1ad3
724 changed files with 8326 additions and 5490 deletions

View File

@ -0,0 +1,163 @@
jobs:
- job: BuildPackage
displayName: 'Build Packages'
strategy:
matrix:
CentOS.amd64:
BuildConfiguration: centos.amd64
Fedora.amd64:
BuildConfiguration: fedora.amd64
Debian.amd64:
BuildConfiguration: debian.amd64
Debian.arm64:
BuildConfiguration: debian.arm64
Debian.armhf:
BuildConfiguration: debian.armhf
Ubuntu.amd64:
BuildConfiguration: ubuntu.amd64
Ubuntu.arm64:
BuildConfiguration: ubuntu.arm64
Ubuntu.armhf:
BuildConfiguration: ubuntu.armhf
Linux.amd64:
BuildConfiguration: linux.amd64
Windows.amd64:
BuildConfiguration: windows.amd64
MacOS:
BuildConfiguration: macos
Portable:
BuildConfiguration: portable
pool:
vmImage: 'ubuntu-latest'
steps:
- script: 'docker build -f deployment/Dockerfile.$(BuildConfiguration) -t jellyfin-server-$(BuildConfiguration) deployment'
displayName: 'Build Dockerfile'
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="yes" -e BUILD_ID=$(Build.BuildNumber) jellyfin-server-$(BuildConfiguration)'
displayName: 'Run Dockerfile (unstable)'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="no" -e BUILD_ID=$(Build.BuildNumber) jellyfin-server-$(BuildConfiguration)'
displayName: 'Run Dockerfile (stable)'
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
- task: PublishPipelineArtifact@1
displayName: 'Publish Release'
inputs:
targetPath: '$(Build.SourcesDirectory)/deployment/dist'
artifactName: 'jellyfin-server-$(BuildConfiguration)'
- task: SSH@0
displayName: 'Create target directory on repository server'
inputs:
sshEndpoint: repository
runOptions: 'inline'
inline: 'mkdir -p /srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
- task: CopyFilesOverSSH@0
displayName: 'Upload artifacts to repository server'
inputs:
sshEndpoint: repository
sourceFolder: '$(Build.SourcesDirectory)/deployment/dist'
contents: '**'
targetFolder: '/srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
- job: BuildDocker
displayName: 'Build Docker'
strategy:
matrix:
amd64:
BuildConfiguration: amd64
arm64:
BuildConfiguration: arm64
armhf:
BuildConfiguration: armhf
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
displayName: 'Push Unstable Image'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
inputs:
repository: 'jellyfin/jellyfin-server'
command: buildAndPush
buildContext: '.'
Dockerfile: 'deployment/Dockerfile.docker.$(BuildConfiguration)'
containerRegistry: Docker Hub
tags: |
unstable-$(Build.BuildNumber)-$(BuildConfiguration)
unstable-$(BuildConfiguration)
- task: Docker@2
displayName: 'Push Stable Image'
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
inputs:
repository: 'jellyfin/jellyfin-server'
command: buildAndPush
buildContext: '.'
Dockerfile: 'deployment/Dockerfile.docker.$(BuildConfiguration)'
containerRegistry: Docker Hub
tags: |
stable-$(Build.BuildNumber)-$(BuildConfiguration)
stable-$(BuildConfiguration)
- job: CollectArtifacts
displayName: 'Collect Artifacts'
dependsOn:
- BuildPackage
- BuildDocker
condition: and(succeeded('BuildPackage'), succeeded('BuildDocker'))
pool:
vmImage: 'ubuntu-latest'
steps:
- task: SSH@0
displayName: 'Update Unstable Repository'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
inputs:
sshEndpoint: repository
runOptions: 'inline'
inline: |
sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) unstable
rm $0
exit
- task: SSH@0
displayName: 'Update Stable Repository'
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
inputs:
sshEndpoint: repository
runOptions: 'inline'
inline: |
sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber)
rm $0
exit
- job: PublishNuget
displayName: 'Publish NuGet packages'
dependsOn:
- BuildPackage
condition: and(succeeded('BuildPackage'), startsWith(variables['Build.SourceBranch'], 'refs/tags'))
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NuGetCommand@2
inputs:
command: 'pack'
packagesToPack: Jellyfin.Data/Jellyfin.Data.csproj;MediaBrowser.Common/MediaBrowser.Common.csproj;MediaBrowser.Controller/MediaBrowser.Controller.csproj;MediaBrowser.Model/MediaBrowser.Model.csproj;Emby.Naming/Emby.Naming.csproj
packDestination: '$(Build.ArtifactStagingDirectory)'
- task: NuGetCommand@2
inputs:
command: 'push'
packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg'
includeNugetOrg: 'true'

View File

@ -15,11 +15,13 @@ trigger:
batch: true batch: true
jobs: jobs:
- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}:
- template: azure-pipelines-main.yml - template: azure-pipelines-main.yml
parameters: parameters:
LinuxImage: 'ubuntu-latest' LinuxImage: 'ubuntu-latest'
RestoreBuildProjects: $(RestoreBuildProjects) RestoreBuildProjects: $(RestoreBuildProjects)
- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}:
- template: azure-pipelines-test.yml - template: azure-pipelines-test.yml
parameters: parameters:
ImageNames: ImageNames:
@ -27,6 +29,7 @@ jobs:
Windows: 'windows-latest' Windows: 'windows-latest'
macOS: 'macos-latest' macOS: 'macos-latest'
- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}:
- template: azure-pipelines-abi.yml - template: azure-pipelines-abi.yml
parameters: parameters:
Packages: Packages:
@ -43,3 +46,6 @@ jobs:
NugetPackageName: Jellyfin.Common NugetPackageName: Jellyfin.Common
AssemblyFileName: MediaBrowser.Common.dll AssemblyFileName: MediaBrowser.Common.dll
LinuxImage: 'ubuntu-latest' LinuxImage: 'ubuntu-latest'
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
- template: azure-pipelines-package.yml

3
.gitignore vendored
View File

@ -39,7 +39,6 @@ ProgramData*/
CorePlugins*/ CorePlugins*/
ProgramData-Server*/ ProgramData-Server*/
ProgramData-UI*/ ProgramData-UI*/
MediaBrowser.WebDashboard/jellyfin-web/**
################# #################
## Visual Studio ## Visual Studio
@ -276,4 +275,4 @@ BenchmarkDotNet.Artifacts
# Ignore web artifacts from native builds # Ignore web artifacts from native builds
web/ web/
web-src.* web-src.*
MediaBrowser.WebDashboard/jellyfin-web/ MediaBrowser.WebDashboard/jellyfin-web

12
.vscode/launch.json vendored
View File

@ -1,9 +1,6 @@
{ {
// Use IntelliSense to find out which attributes exist for C# debugging "version": "0.2.0",
// Use hover for the description of the existing attributes "configurations": [
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{ {
"name": ".NET Core Launch (console)", "name": ".NET Core Launch (console)",
"type": "coreclr", "type": "coreclr",
@ -24,5 +21,8 @@
"request": "attach", "request": "attach",
"processId": "${command:pickProcess}" "processId": "${command:pickProcess}"
} }
,] ],
"env": {
"DOTNET_CLI_TELEMETRY_OPTOUT": "1"
}
} }

7
.vscode/tasks.json vendored
View File

@ -21,5 +21,10 @@
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
} }
] ],
"options": {
"env": {
"DOTNET_CLI_TELEMETRY_OPTOUT": "1"
}
}
} }

View File

@ -7,6 +7,7 @@ namespace DvdLib.Ifo
public class Cell public class Cell
{ {
public CellPlaybackInfo PlaybackInfo { get; private set; } public CellPlaybackInfo PlaybackInfo { get; private set; }
public CellPositionInfo PositionInfo { get; private set; } public CellPositionInfo PositionInfo { get; private set; }
internal void ParsePlayback(BinaryReader br) internal void ParsePlayback(BinaryReader br)

View File

@ -5,7 +5,9 @@ namespace DvdLib.Ifo
public class Chapter public class Chapter
{ {
public ushort ProgramChainNumber { get; private set; } public ushort ProgramChainNumber { get; private set; }
public ushort ProgramNumber { get; private set; } public ushort ProgramNumber { get; private set; }
public uint ChapterNumber { get; private set; } public uint ChapterNumber { get; private set; }
public Chapter(ushort pgcNum, ushort programNum, uint chapterNum) public Chapter(ushort pgcNum, ushort programNum, uint chapterNum)

View File

@ -117,12 +117,19 @@ namespace DvdLib.Ifo
uint chapNum = 1; uint chapNum = 1;
vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin); vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin);
var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1)); var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1));
if (t == null) continue; if (t == null)
{
continue;
}
do do
{ {
t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum)); t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum));
if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1])) break; if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1]))
{
break;
}
chapNum++; chapNum++;
} }
while (vtsFs.Position < (baseAddr + endaddr)); while (vtsFs.Position < (baseAddr + endaddr));
@ -147,7 +154,10 @@ namespace DvdLib.Ifo
uint vtsPgcOffset = vtsRead.ReadUInt32(); uint vtsPgcOffset = vtsRead.ReadUInt32();
var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum)); var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum));
if (t != null) t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum); if (t != null)
{
t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum);
}
} }
} }
} }

View File

@ -15,8 +15,14 @@ namespace DvdLib.Ifo
Second = GetBCDValue(data[2]); Second = GetBCDValue(data[2]);
Frames = GetBCDValue((byte)(data[3] & 0x3F)); Frames = GetBCDValue((byte)(data[3] & 0x3F));
if ((data[3] & 0x80) != 0) FrameRate = 30; if ((data[3] & 0x80) != 0)
else if ((data[3] & 0x40) != 0) FrameRate = 25; {
FrameRate = 30;
}
else if ((data[3] & 0x40) != 0)
{
FrameRate = 25;
}
} }
private static byte GetBCDValue(byte data) private static byte GetBCDValue(byte data)

View File

@ -22,7 +22,9 @@ namespace DvdLib.Ifo
public readonly List<Cell> Cells; public readonly List<Cell> Cells;
public DvdTime PlaybackTime { get; private set; } public DvdTime PlaybackTime { get; private set; }
public UserOperation ProhibitedUserOperations { get; private set; } public UserOperation ProhibitedUserOperations { get; private set; }
public byte[] AudioStreamControl { get; private set; } // 8*2 entries public byte[] AudioStreamControl { get; private set; } // 8*2 entries
public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries
@ -33,9 +35,11 @@ namespace DvdLib.Ifo
private ushort _goupProgramNumber; private ushort _goupProgramNumber;
public ProgramPlaybackMode PlaybackMode { get; private set; } public ProgramPlaybackMode PlaybackMode { get; private set; }
public uint ProgramCount { get; private set; } public uint ProgramCount { get; private set; }
public byte StillTime { get; private set; } public byte StillTime { get; private set; }
public byte[] Palette { get; private set; } // 16*4 entries public byte[] Palette { get; private set; } // 16*4 entries
private ushort _commandTableOffset; private ushort _commandTableOffset;
@ -71,8 +75,15 @@ namespace DvdLib.Ifo
StillTime = br.ReadByte(); StillTime = br.ReadByte();
byte pbMode = br.ReadByte(); byte pbMode = br.ReadByte();
if (pbMode == 0) PlaybackMode = ProgramPlaybackMode.Sequential; if (pbMode == 0)
else PlaybackMode = ((pbMode & 0x80) == 0) ? ProgramPlaybackMode.Random : ProgramPlaybackMode.Shuffle; {
PlaybackMode = ProgramPlaybackMode.Sequential;
}
else
{
PlaybackMode = ((pbMode & 0x80) == 0) ? ProgramPlaybackMode.Random : ProgramPlaybackMode.Shuffle;
}
ProgramCount = (uint)(pbMode & 0x7F); ProgramCount = (uint)(pbMode & 0x7F);
Palette = br.ReadBytes(64); Palette = br.ReadBytes(64);

View File

@ -8,8 +8,11 @@ namespace DvdLib.Ifo
public class Title public class Title
{ {
public uint TitleNumber { get; private set; } public uint TitleNumber { get; private set; }
public uint AngleCount { get; private set; } public uint AngleCount { get; private set; }
public ushort ChapterCount { get; private set; } public ushort ChapterCount { get; private set; }
public byte VideoTitleSetNumber { get; private set; } public byte VideoTitleSetNumber { get; private set; }
private ushort _parentalManagementMask; private ushort _parentalManagementMask;
@ -17,6 +20,7 @@ namespace DvdLib.Ifo
private uint _vtsStartSector; // relative to start of entire disk private uint _vtsStartSector; // relative to start of entire disk
public ProgramChain EntryProgramChain { get; private set; } public ProgramChain EntryProgramChain { get; private set; }
public readonly List<ProgramChain> ProgramChains; public readonly List<ProgramChain> ProgramChains;
public readonly List<Chapter> Chapters; public readonly List<Chapter> Chapters;
@ -55,7 +59,10 @@ namespace DvdLib.Ifo
var pgc = new ProgramChain(pgcNum); var pgc = new ProgramChain(pgcNum);
pgc.ParseHeader(br); pgc.ParseHeader(br);
ProgramChains.Add(pgc); ProgramChains.Add(pgc);
if (entryPgc) EntryProgramChain = pgc; if (entryPgc)
{
EntryProgramChain = pgc;
}
br.BaseStream.Seek(curPos, SeekOrigin.Begin); br.BaseStream.Seek(curPos, SeekOrigin.Begin);
} }

View File

@ -466,12 +466,12 @@ namespace Emby.Dlna.ContentDirectory
} }
else if (search.SearchType == SearchType.Playlist) else if (search.SearchType == SearchType.Playlist)
{ {
//items = items.OfType<Playlist>(); // items = items.OfType<Playlist>();
isFolder = true; isFolder = true;
} }
else if (search.SearchType == SearchType.MusicAlbum) else if (search.SearchType == SearchType.MusicAlbum)
{ {
//items = items.OfType<MusicAlbum>(); // items = items.OfType<MusicAlbum>();
isFolder = true; isFolder = true;
} }
@ -926,7 +926,7 @@ namespace Emby.Dlna.ContentDirectory
private QueryResult<ServerItem> GetMovieCollections(User user, InternalItemsQuery query) private QueryResult<ServerItem> GetMovieCollections(User user, InternalItemsQuery query)
{ {
query.Recursive = true; query.Recursive = true;
//query.Parent = parent; // query.Parent = parent;
query.SetUser(user); query.SetUser(user);
query.IncludeItemTypes = new[] { typeof(BoxSet).Name }; query.IncludeItemTypes = new[] { typeof(BoxSet).Name };
@ -1357,6 +1357,7 @@ namespace Emby.Dlna.ContentDirectory
internal class ServerItem internal class ServerItem
{ {
public BaseItem Item { get; set; } public BaseItem Item { get; set; }
public StubType? StubType { get; set; } public StubType? StubType { get; set; }
public ServerItem(BaseItem item) public ServerItem(BaseItem item)

View File

@ -98,21 +98,21 @@ namespace Emby.Dlna.Didl
{ {
using (var writer = XmlWriter.Create(builder, settings)) using (var writer = XmlWriter.Create(builder, settings))
{ {
//writer.WriteStartDocument(); // writer.WriteStartDocument();
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL); writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
writer.WriteAttributeString("xmlns", "dc", null, NS_DC); writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA); writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP); writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
//didl.SetAttribute("xmlns:sec", NS_SEC); // didl.SetAttribute("xmlns:sec", NS_SEC);
WriteXmlRootAttributes(_profile, writer); WriteXmlRootAttributes(_profile, writer);
WriteItemElement(writer, item, user, context, null, deviceId, filter, streamInfo); WriteItemElement(writer, item, user, context, null, deviceId, filter, streamInfo);
writer.WriteFullEndElement(); writer.WriteFullEndElement();
//writer.WriteEndDocument(); // writer.WriteEndDocument();
} }
return builder.ToString(); return builder.ToString();
@ -705,13 +705,13 @@ namespace Emby.Dlna.Didl
} }
/// <summary> /// <summary>
/// Adds fields used by both items and folders /// Adds fields used by both items and folders.
/// </summary> /// </summary>
private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter) private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
{ {
// Don't filter on dc:title because not all devices will include it in the filter // Don't filter on dc:title because not all devices will include it in the filter
// MediaMonkey for example won't display content without a title // MediaMonkey for example won't display content without a title
//if (filter.Contains("dc:title")) // if (filter.Contains("dc:title"))
{ {
AddValue(writer, "dc", "title", GetDisplayName(item, itemStubType, context), NS_DC); AddValue(writer, "dc", "title", GetDisplayName(item, itemStubType, context), NS_DC);
} }
@ -750,7 +750,7 @@ namespace Emby.Dlna.Didl
AddValue(writer, "dc", "description", desc, NS_DC); AddValue(writer, "dc", "description", desc, NS_DC);
} }
} }
//if (filter.Contains("upnp:longDescription")) // if (filter.Contains("upnp:longDescription"))
//{ //{
// if (!string.IsNullOrWhiteSpace(item.Overview)) // if (!string.IsNullOrWhiteSpace(item.Overview))
// { // {
@ -765,6 +765,7 @@ namespace Emby.Dlna.Didl
{ {
AddValue(writer, "dc", "rating", item.OfficialRating, NS_DC); AddValue(writer, "dc", "rating", item.OfficialRating, NS_DC);
} }
if (filter.Contains("upnp:rating")) if (filter.Contains("upnp:rating"))
{ {
AddValue(writer, "upnp", "rating", item.OfficialRating, NS_UPNP); AddValue(writer, "upnp", "rating", item.OfficialRating, NS_UPNP);
@ -1052,10 +1053,12 @@ namespace Emby.Dlna.Didl
{ {
return GetImageInfo(item, ImageType.Primary); return GetImageInfo(item, ImageType.Primary);
} }
if (item.HasImage(ImageType.Thumb)) if (item.HasImage(ImageType.Thumb))
{ {
return GetImageInfo(item, ImageType.Thumb); return GetImageInfo(item, ImageType.Thumb);
} }
if (item.HasImage(ImageType.Backdrop)) if (item.HasImage(ImageType.Backdrop))
{ {
if (item is Channel) if (item is Channel)
@ -1135,25 +1138,24 @@ namespace Emby.Dlna.Didl
if (width == 0 || height == 0) if (width == 0 || height == 0)
{ {
//_imageProcessor.GetImageSize(item, imageInfo); // _imageProcessor.GetImageSize(item, imageInfo);
width = null; width = null;
height = null; height = null;
} }
else if (width == -1 || height == -1) else if (width == -1 || height == -1)
{ {
width = null; width = null;
height = null; height = null;
} }
//try // try
//{ //{
// var size = _imageProcessor.GetImageSize(imageInfo); // var size = _imageProcessor.GetImageSize(imageInfo);
// width = size.Width; // width = size.Width;
// height = size.Height; // height = size.Height;
//} //}
//catch // catch
//{ //{
//} //}

View File

@ -12,7 +12,6 @@ namespace Emby.Dlna.Didl
public Filter() public Filter()
: this("*") : this("*")
{ {
} }
public Filter(string filter) public Filter(string filter)
@ -26,7 +25,7 @@ namespace Emby.Dlna.Didl
{ {
// Don't bother with this. Some clients (media monkey) use the filter and then don't display very well when very little data comes back. // Don't bother with this. Some clients (media monkey) use the filter and then don't display very well when very little data comes back.
return true; return true;
//return _all || ListHelper.ContainsIgnoreCase(_fields, field); // return _all || ListHelper.ContainsIgnoreCase(_fields, field);
} }
} }
} }

View File

@ -88,7 +88,6 @@ namespace Emby.Dlna
.Select(i => i.Item2) .Select(i => i.Item2)
.ToList(); .ToList();
} }
} }
public DeviceProfile GetDefaultProfile() public DeviceProfile GetDefaultProfile()
@ -141,55 +140,73 @@ namespace Emby.Dlna
if (!string.IsNullOrEmpty(profileInfo.DeviceDescription)) if (!string.IsNullOrEmpty(profileInfo.DeviceDescription))
{ {
if (deviceInfo.DeviceDescription == null || !IsRegexMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription)) if (deviceInfo.DeviceDescription == null || !IsRegexMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.FriendlyName)) if (!string.IsNullOrEmpty(profileInfo.FriendlyName))
{ {
if (deviceInfo.FriendlyName == null || !IsRegexMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName)) if (deviceInfo.FriendlyName == null || !IsRegexMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.Manufacturer)) if (!string.IsNullOrEmpty(profileInfo.Manufacturer))
{ {
if (deviceInfo.Manufacturer == null || !IsRegexMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer)) if (deviceInfo.Manufacturer == null || !IsRegexMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.ManufacturerUrl)) if (!string.IsNullOrEmpty(profileInfo.ManufacturerUrl))
{ {
if (deviceInfo.ManufacturerUrl == null || !IsRegexMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl)) if (deviceInfo.ManufacturerUrl == null || !IsRegexMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.ModelDescription)) if (!string.IsNullOrEmpty(profileInfo.ModelDescription))
{ {
if (deviceInfo.ModelDescription == null || !IsRegexMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription)) if (deviceInfo.ModelDescription == null || !IsRegexMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.ModelName)) if (!string.IsNullOrEmpty(profileInfo.ModelName))
{ {
if (deviceInfo.ModelName == null || !IsRegexMatch(deviceInfo.ModelName, profileInfo.ModelName)) if (deviceInfo.ModelName == null || !IsRegexMatch(deviceInfo.ModelName, profileInfo.ModelName))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.ModelNumber)) if (!string.IsNullOrEmpty(profileInfo.ModelNumber))
{ {
if (deviceInfo.ModelNumber == null || !IsRegexMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber)) if (deviceInfo.ModelNumber == null || !IsRegexMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.ModelUrl)) if (!string.IsNullOrEmpty(profileInfo.ModelUrl))
{ {
if (deviceInfo.ModelUrl == null || !IsRegexMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl)) if (deviceInfo.ModelUrl == null || !IsRegexMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
{
return false; return false;
}
} }
if (!string.IsNullOrEmpty(profileInfo.SerialNumber)) if (!string.IsNullOrEmpty(profileInfo.SerialNumber))
{ {
if (deviceInfo.SerialNumber == null || !IsRegexMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber)) if (deviceInfo.SerialNumber == null || !IsRegexMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
{
return false; return false;
}
} }
return true; return true;
@ -251,7 +268,7 @@ namespace Emby.Dlna
return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase); return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
case HeaderMatchType.Substring: case HeaderMatchType.Substring:
var isMatch = value.ToString().IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1; var isMatch = value.ToString().IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
//_logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch); // _logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
return isMatch; return isMatch;
case HeaderMatchType.Regex: case HeaderMatchType.Regex:
return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase); return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
@ -439,6 +456,7 @@ namespace Emby.Dlna
{ {
throw new ArgumentException("Profile is missing Id"); throw new ArgumentException("Profile is missing Id");
} }
if (string.IsNullOrEmpty(profile.Name)) if (string.IsNullOrEmpty(profile.Name))
{ {
throw new ArgumentException("Profile is missing Name"); throw new ArgumentException("Profile is missing Name");
@ -464,6 +482,7 @@ namespace Emby.Dlna
{ {
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile); _profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
} }
SerializeToXml(profile, path); SerializeToXml(profile, path);
} }
@ -474,7 +493,7 @@ namespace Emby.Dlna
/// <summary> /// <summary>
/// Recreates the object using serialization, to ensure it's not a subclass. /// Recreates the object using serialization, to ensure it's not a subclass.
/// If it's a subclass it may not serlialize properly to xml (different root element tag name) /// If it's a subclass it may not serlialize properly to xml (different root element tag name).
/// </summary> /// </summary>
/// <param name="profile"></param> /// <param name="profile"></param>
/// <returns></returns> /// <returns></returns>
@ -493,6 +512,7 @@ namespace Emby.Dlna
class InternalProfileInfo class InternalProfileInfo
{ {
internal DeviceProfileInfo Info { get; set; } internal DeviceProfileInfo Info { get; set; }
internal string Path { get; set; } internal string Path { get; set; }
} }
@ -566,9 +586,9 @@ namespace Emby.Dlna
new Foobar2000Profile(), new Foobar2000Profile(),
new SharpSmartTvProfile(), new SharpSmartTvProfile(),
new MediaMonkeyProfile(), new MediaMonkeyProfile(),
//new Windows81Profile(), // new Windows81Profile(),
//new WindowsMediaCenterProfile(), // new WindowsMediaCenterProfile(),
//new WindowsPhoneProfile(), // new WindowsPhoneProfile(),
new DirectTvProfile(), new DirectTvProfile(),
new DishHopperJoeyProfile(), new DishHopperJoeyProfile(),
new DefaultProfile(), new DefaultProfile(),

View File

@ -31,18 +31,26 @@ namespace Emby.Dlna.Eventing
public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl) public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl)
{ {
var subscription = GetSubscription(subscriptionId, false); var subscription = GetSubscription(subscriptionId, false);
if (subscription != null)
{
subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
int timeoutSeconds = subscription.TimeoutSeconds;
subscription.SubscriptionTime = DateTime.UtcNow;
subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300; _logger.LogDebug(
int timeoutSeconds = subscription.TimeoutSeconds; "Renewing event subscription for {0} with timeout of {1} to {2}",
subscription.SubscriptionTime = DateTime.UtcNow; subscription.NotificationType,
timeoutSeconds,
subscription.CallbackUrl);
_logger.LogDebug( return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds);
"Renewing event subscription for {0} with timeout of {1} to {2}", }
subscription.NotificationType,
timeoutSeconds,
subscription.CallbackUrl);
return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds); return new EventSubscriptionResponse
{
Content = string.Empty,
ContentType = "text/plain"
};
} }
public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl) public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl)
@ -150,6 +158,7 @@ namespace Emby.Dlna.Eventing
builder.Append("</" + key + ">"); builder.Append("</" + key + ">");
builder.Append("</e:property>"); builder.Append("</e:property>");
} }
builder.Append("</e:propertyset>"); builder.Append("</e:propertyset>");
var options = new HttpRequestOptions var options = new HttpRequestOptions
@ -169,7 +178,6 @@ namespace Emby.Dlna.Eventing
{ {
using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false)) using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
{ {
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)

View File

@ -7,10 +7,13 @@ namespace Emby.Dlna.Eventing
public class EventSubscription public class EventSubscription
{ {
public string Id { get; set; } public string Id { get; set; }
public string CallbackUrl { get; set; } public string CallbackUrl { get; set; }
public string NotificationType { get; set; } public string NotificationType { get; set; }
public DateTime SubscriptionTime { get; set; } public DateTime SubscriptionTime { get; set; }
public int TimeoutSeconds { get; set; } public int TimeoutSeconds { get; set; }
public long TriggerCount { get; set; } public long TriggerCount { get; set; }

View File

@ -35,8 +35,6 @@ namespace Emby.Dlna.Main
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly ILogger<DlnaEntryPoint> _logger; private readonly ILogger<DlnaEntryPoint> _logger;
private readonly IServerApplicationHost _appHost; private readonly IServerApplicationHost _appHost;
private PlayToManager _manager;
private readonly ISessionManager _sessionManager; private readonly ISessionManager _sessionManager;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
@ -47,14 +45,13 @@ namespace Emby.Dlna.Main
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder; private readonly IMediaEncoder _mediaEncoder;
private readonly IDeviceDiscovery _deviceDiscovery; private readonly IDeviceDiscovery _deviceDiscovery;
private SsdpDevicePublisher _Publisher;
private readonly ISocketFactory _socketFactory; private readonly ISocketFactory _socketFactory;
private readonly INetworkManager _networkManager; private readonly INetworkManager _networkManager;
private readonly object _syncLock = new object();
private PlayToManager _manager;
private SsdpDevicePublisher _publisher;
private ISsdpCommunicationsServer _communicationsServer; private ISsdpCommunicationsServer _communicationsServer;
internal IContentDirectory ContentDirectory { get; private set; } internal IContentDirectory ContentDirectory { get; private set; }
@ -181,7 +178,7 @@ namespace Emby.Dlna.Main
var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows || var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows ||
OperatingSystem.Id == OperatingSystemId.Linux; OperatingSystem.Id == OperatingSystemId.Linux;
_communicationsServer = new SsdpCommunicationsServer(_config, _socketFactory, _networkManager, _logger, enableMultiSocketBinding) _communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding)
{ {
IsShared = true IsShared = true
}; };
@ -232,20 +229,22 @@ namespace Emby.Dlna.Main
return; return;
} }
if (_Publisher != null) if (_publisher != null)
{ {
return; return;
} }
try try
{ {
_Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost); _publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost)
_Publisher.LogFunction = LogMessage; {
_Publisher.SupportPnpRootDevice = false; LogFunction = LogMessage,
SupportPnpRootDevice = false
};
await RegisterServerEndpoints().ConfigureAwait(false); await RegisterServerEndpoints().ConfigureAwait(false);
_Publisher.StartBroadcastingAliveMessages(TimeSpan.FromSeconds(options.BlastAliveMessageIntervalSeconds)); _publisher.StartBroadcastingAliveMessages(TimeSpan.FromSeconds(options.BlastAliveMessageIntervalSeconds));
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -267,6 +266,12 @@ namespace Emby.Dlna.Main
continue; continue;
} }
// Limit to LAN addresses only
if (!_networkManager.IsAddressInSubnets(address, true, true))
{
continue;
}
var fullService = "urn:schemas-upnp-org:device:MediaServer:1"; var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
_logger.LogInformation("Registering publisher for {0} on {1}", fullService, address); _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address);
@ -276,7 +281,7 @@ namespace Emby.Dlna.Main
var device = new SsdpRootDevice var device = new SsdpRootDevice
{ {
CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info. CacheLifetime = TimeSpan.FromSeconds(1800), // How long SSDP clients can cache this info.
Location = uri, // Must point to the URL that serves your devices UPnP description document. Location = uri, // Must point to the URL that serves your devices UPnP description document.
Address = address, Address = address,
SubnetMask = _networkManager.GetLocalIpSubnetMask(address), SubnetMask = _networkManager.GetLocalIpSubnetMask(address),
@ -288,13 +293,13 @@ namespace Emby.Dlna.Main
}; };
SetProperies(device, fullService); SetProperies(device, fullService);
_Publisher.AddDevice(device); _publisher.AddDevice(device);
var embeddedDevices = new[] var embeddedDevices = new[]
{ {
"urn:schemas-upnp-org:service:ContentDirectory:1", "urn:schemas-upnp-org:service:ContentDirectory:1",
"urn:schemas-upnp-org:service:ConnectionManager:1", "urn:schemas-upnp-org:service:ConnectionManager:1",
//"urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1" // "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
}; };
foreach (var subDevice in embeddedDevices) foreach (var subDevice in embeddedDevices)
@ -320,12 +325,13 @@ namespace Emby.Dlna.Main
{ {
guid = text.GetMD5(); guid = text.GetMD5();
} }
return guid.ToString("N", CultureInfo.InvariantCulture); return guid.ToString("N", CultureInfo.InvariantCulture);
} }
private void SetProperies(SsdpDevice device, string fullDeviceType) private void SetProperies(SsdpDevice device, string fullDeviceType)
{ {
var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty); var service = fullDeviceType.Replace("urn:", string.Empty, StringComparison.OrdinalIgnoreCase).Replace(":1", string.Empty, StringComparison.OrdinalIgnoreCase);
var serviceParts = service.Split(':'); var serviceParts = service.Split(':');
@ -336,7 +342,6 @@ namespace Emby.Dlna.Main
device.DeviceType = serviceParts[2]; device.DeviceType = serviceParts[2];
} }
private readonly object _syncLock = new object();
private void StartPlayToManager() private void StartPlayToManager()
{ {
lock (_syncLock) lock (_syncLock)
@ -388,6 +393,7 @@ namespace Emby.Dlna.Main
{ {
_logger.LogError(ex, "Error disposing PlayTo manager"); _logger.LogError(ex, "Error disposing PlayTo manager");
} }
_manager = null; _manager = null;
} }
} }
@ -414,11 +420,11 @@ namespace Emby.Dlna.Main
public void DisposeDevicePublisher() public void DisposeDevicePublisher()
{ {
if (_Publisher != null) if (_publisher != null)
{ {
_logger.LogInformation("Disposing SsdpDevicePublisher"); _logger.LogInformation("Disposing SsdpDevicePublisher");
_Publisher.Dispose(); _publisher.Dispose();
_Publisher = null; _publisher = null;
} }
} }
} }

View File

@ -19,8 +19,6 @@ namespace Emby.Dlna.PlayTo
{ {
public class Device : IDisposable public class Device : IDisposable
{ {
#region Fields & Properties
private Timer _timer; private Timer _timer;
public DeviceInfo Properties { get; set; } public DeviceInfo Properties { get; set; }
@ -37,6 +35,7 @@ namespace Emby.Dlna.PlayTo
RefreshVolumeIfNeeded().GetAwaiter().GetResult(); RefreshVolumeIfNeeded().GetAwaiter().GetResult();
return _volume; return _volume;
} }
set => _volume = value; set => _volume = value;
} }
@ -52,10 +51,10 @@ namespace Emby.Dlna.PlayTo
public bool IsStopped => TransportState == TRANSPORTSTATE.STOPPED; public bool IsStopped => TransportState == TRANSPORTSTATE.STOPPED;
#endregion
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
public Action OnDeviceUnavailable { get; set; } public Action OnDeviceUnavailable { get; set; }
@ -141,8 +140,6 @@ namespace Emby.Dlna.PlayTo
} }
} }
#region Commanding
public Task VolumeDown(CancellationToken cancellationToken) public Task VolumeDown(CancellationToken cancellationToken)
{ {
var sendVolume = Math.Max(Volume - 5, 0); var sendVolume = Math.Max(Volume - 5, 0);
@ -211,7 +208,9 @@ namespace Emby.Dlna.PlayTo
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetMute"); var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetMute");
if (command == null) if (command == null)
{
return false; return false;
}
var service = GetServiceRenderingControl(); var service = GetServiceRenderingControl();
@ -232,7 +231,7 @@ namespace Emby.Dlna.PlayTo
} }
/// <summary> /// <summary>
/// Sets volume on a scale of 0-100 /// Sets volume on a scale of 0-100.
/// </summary> /// </summary>
public async Task SetVolume(int value, CancellationToken cancellationToken) public async Task SetVolume(int value, CancellationToken cancellationToken)
{ {
@ -240,7 +239,9 @@ namespace Emby.Dlna.PlayTo
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume"); var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume");
if (command == null) if (command == null)
{
return; return;
}
var service = GetServiceRenderingControl(); var service = GetServiceRenderingControl();
@ -263,7 +264,9 @@ namespace Emby.Dlna.PlayTo
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek"); var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek");
if (command == null) if (command == null)
{
return; return;
}
var service = GetAvTransportService(); var service = GetAvTransportService();
@ -288,7 +291,9 @@ namespace Emby.Dlna.PlayTo
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI"); var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI");
if (command == null) if (command == null)
{
return; return;
}
var dictionary = new Dictionary<string, string> var dictionary = new Dictionary<string, string>
{ {
@ -401,11 +406,8 @@ namespace Emby.Dlna.PlayTo
RestartTimer(true); RestartTimer(true);
} }
#endregion
#region Get data
private int _connectFailureCount; private int _connectFailureCount;
private async void TimerCallback(object sender) private async void TimerCallback(object sender)
{ {
if (_disposed) if (_disposed)
@ -458,7 +460,9 @@ namespace Emby.Dlna.PlayTo
_connectFailureCount = 0; _connectFailureCount = 0;
if (_disposed) if (_disposed)
{
return; return;
}
// If we're not playing anything make sure we don't get data more often than neccessry to keep the Session alive // If we're not playing anything make sure we don't get data more often than neccessry to keep the Session alive
if (transportState.Value == TRANSPORTSTATE.STOPPED) if (transportState.Value == TRANSPORTSTATE.STOPPED)
@ -478,7 +482,9 @@ namespace Emby.Dlna.PlayTo
catch (Exception ex) catch (Exception ex)
{ {
if (_disposed) if (_disposed)
{
return; return;
}
_logger.LogError(ex, "Error updating device info for {DeviceName}", Properties.Name); _logger.LogError(ex, "Error updating device info for {DeviceName}", Properties.Name);
@ -494,6 +500,7 @@ namespace Emby.Dlna.PlayTo
return; return;
} }
} }
RestartTimerInactive(); RestartTimerInactive();
} }
} }
@ -578,7 +585,9 @@ namespace Emby.Dlna.PlayTo
cancellationToken: cancellationToken).ConfigureAwait(false); cancellationToken: cancellationToken).ConfigureAwait(false);
if (result == null || result.Document == null) if (result == null || result.Document == null)
{
return; return;
}
var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse") var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse")
.Select(i => i.Element("CurrentMute")) .Select(i => i.Element("CurrentMute"))
@ -750,7 +759,7 @@ namespace Emby.Dlna.PlayTo
if (track == null) if (track == null)
{ {
//If track is null, some vendors do this, use GetMediaInfo instead // If track is null, some vendors do this, use GetMediaInfo instead
return (true, null); return (true, null);
} }
@ -794,7 +803,6 @@ namespace Emby.Dlna.PlayTo
} }
catch (XmlException) catch (XmlException)
{ {
} }
// first try to add a root node with a dlna namesapce // first try to add a root node with a dlna namesapce
@ -806,7 +814,6 @@ namespace Emby.Dlna.PlayTo
} }
catch (XmlException) catch (XmlException)
{ {
} }
// some devices send back invalid xml // some devices send back invalid xml
@ -816,7 +823,6 @@ namespace Emby.Dlna.PlayTo
} }
catch (XmlException) catch (XmlException)
{ {
} }
return null; return null;
@ -871,10 +877,6 @@ namespace Emby.Dlna.PlayTo
return new string[4]; return new string[4];
} }
#endregion
#region From XML
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken) private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
{ {
if (AvCommands != null) if (AvCommands != null)
@ -1069,8 +1071,6 @@ namespace Emby.Dlna.PlayTo
return new Device(deviceProperties, httpClient, logger, config); return new Device(deviceProperties, httpClient, logger, config);
} }
#endregion
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
private static DeviceIcon CreateIcon(XElement element) private static DeviceIcon CreateIcon(XElement element)
{ {
@ -1194,8 +1194,6 @@ namespace Emby.Dlna.PlayTo
}); });
} }
#region IDisposable
bool _disposed; bool _disposed;
public void Dispose() public void Dispose()
@ -1222,8 +1220,6 @@ namespace Emby.Dlna.PlayTo
_disposed = true; _disposed = true;
} }
#endregion
public override string ToString() public override string ToString()
{ {
return string.Format("{0} - {1}", Properties.Name, Properties.BaseUrl); return string.Format("{0} - {1}", Properties.Name, Properties.BaseUrl);

View File

@ -425,6 +425,7 @@ namespace Emby.Dlna.PlayTo
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false); await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false);
return; return;
} }
await SeekAfterTransportChange(newPosition, CancellationToken.None).ConfigureAwait(false); await SeekAfterTransportChange(newPosition, CancellationToken.None).ConfigureAwait(false);
} }
} }
@ -713,6 +714,7 @@ namespace Emby.Dlna.PlayTo
throw new ArgumentException("Volume argument cannot be null"); throw new ArgumentException("Volume argument cannot be null");
} }
default: default:
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -798,12 +800,15 @@ namespace Emby.Dlna.PlayTo
public int? SubtitleStreamIndex { get; set; } public int? SubtitleStreamIndex { get; set; }
public string DeviceProfileId { get; set; } public string DeviceProfileId { get; set; }
public string DeviceId { get; set; } public string DeviceId { get; set; }
public string MediaSourceId { get; set; } public string MediaSourceId { get; set; }
public string LiveStreamId { get; set; } public string LiveStreamId { get; set; }
public BaseItem Item { get; set; } public BaseItem Item { get; set; }
private MediaSourceInfo MediaSource; private MediaSourceInfo MediaSource;
private IMediaSourceManager _mediaSourceManager; private IMediaSourceManager _mediaSourceManager;

View File

@ -78,9 +78,15 @@ namespace Emby.Dlna.PlayTo
var info = e.Argument; var info = e.Argument;
if (!info.Headers.TryGetValue("USN", out string usn)) usn = string.Empty; if (!info.Headers.TryGetValue("USN", out string usn))
{
usn = string.Empty;
}
if (!info.Headers.TryGetValue("NT", out string nt)) nt = string.Empty; if (!info.Headers.TryGetValue("NT", out string nt))
{
nt = string.Empty;
}
string location = info.Location.ToString(); string location = info.Location.ToString();
@ -88,7 +94,7 @@ namespace Emby.Dlna.PlayTo
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 && if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1) nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
{ {
//_logger.LogDebug("Upnp device {0} does not contain a MediaRenderer device (0).", location); // _logger.LogDebug("Upnp device {0} does not contain a MediaRenderer device (0).", location);
return; return;
} }
@ -112,7 +118,6 @@ namespace Emby.Dlna.PlayTo
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -133,6 +138,7 @@ namespace Emby.Dlna.PlayTo
usn = usn.Substring(index); usn = usn.Substring(index);
found = true; found = true;
} }
index = usn.IndexOf("::", StringComparison.OrdinalIgnoreCase); index = usn.IndexOf("::", StringComparison.OrdinalIgnoreCase);
if (index != -1) if (index != -1)
{ {
@ -243,7 +249,6 @@ namespace Emby.Dlna.PlayTo
} }
catch catch
{ {
} }
_sessionLock.Dispose(); _sessionLock.Dispose();

View File

@ -12,6 +12,7 @@ namespace Emby.Dlna.PlayTo
public class MediaChangedEventArgs : EventArgs public class MediaChangedEventArgs : EventArgs
{ {
public uBaseObject OldMediaInfo { get; set; } public uBaseObject OldMediaInfo { get; set; }
public uBaseObject NewMediaInfo { get; set; } public uBaseObject NewMediaInfo { get; set; }
} }
} }

View File

@ -91,7 +91,6 @@ namespace Emby.Dlna.PlayTo
using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false)) using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
{ {
} }
} }

View File

@ -44,10 +44,12 @@ namespace Emby.Dlna.PlayTo
{ {
return MediaBrowser.Model.Entities.MediaType.Audio; return MediaBrowser.Model.Entities.MediaType.Audio;
} }
if (classType.IndexOf(MediaBrowser.Model.Entities.MediaType.Video, StringComparison.Ordinal) != -1) if (classType.IndexOf(MediaBrowser.Model.Entities.MediaType.Video, StringComparison.Ordinal) != -1)
{ {
return MediaBrowser.Model.Entities.MediaType.Video; return MediaBrowser.Model.Entities.MediaType.Video;
} }
if (classType.IndexOf("image", StringComparison.Ordinal) != -1) if (classType.IndexOf("image", StringComparison.Ordinal) != -1)
{ {
return MediaBrowser.Model.Entities.MediaType.Photo; return MediaBrowser.Model.Entities.MediaType.Photo;

View File

@ -164,7 +164,7 @@ namespace Emby.Dlna.Profiles
public void AddXmlRootAttribute(string name, string value) public void AddXmlRootAttribute(string name, string value)
{ {
var atts = XmlRootAttributes ?? new XmlAttribute[] { }; var atts = XmlRootAttributes ?? System.Array.Empty<XmlAttribute>();
var list = atts.ToList(); var list = atts.ToList();
list.Add(new XmlAttribute list.Add(new XmlAttribute

View File

@ -28,7 +28,7 @@ namespace Emby.Dlna.Profiles
}, },
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = System.Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -123,7 +123,7 @@ namespace Emby.Dlna.Profiles
} }
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = System.Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -72,7 +72,7 @@ namespace Emby.Dlna.Profiles
} }
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = System.Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -37,7 +37,7 @@ namespace Emby.Dlna.Profiles
}, },
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = System.Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles namespace Emby.Dlna.Profiles
@ -37,7 +38,7 @@ namespace Emby.Dlna.Profiles
} }
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles namespace Emby.Dlna.Profiles
@ -223,7 +224,7 @@ namespace Emby.Dlna.Profiles
} }
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles namespace Emby.Dlna.Profiles
@ -223,7 +224,7 @@ namespace Emby.Dlna.Profiles
} }
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles namespace Emby.Dlna.Profiles
@ -211,7 +212,7 @@ namespace Emby.Dlna.Profiles
} }
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles namespace Emby.Dlna.Profiles
@ -211,7 +212,7 @@ namespace Emby.Dlna.Profiles
} }
}; };
ResponseProfiles = new ResponseProfile[] { }; ResponseProfiles = Array.Empty<ResponseProfile>();
} }
} }
} }

View File

@ -134,6 +134,7 @@ namespace Emby.Dlna.Server
return result; return result;
} }
} }
return c.ToString(CultureInfo.InvariantCulture); return c.ToString(CultureInfo.InvariantCulture);
} }
@ -157,18 +158,22 @@ namespace Emby.Dlna.Server
{ {
break; break;
} }
if (stringBuilder == null) if (stringBuilder == null)
{ {
stringBuilder = new StringBuilder(); stringBuilder = new StringBuilder();
} }
stringBuilder.Append(str, num, num2 - num); stringBuilder.Append(str, num, num2 - num);
stringBuilder.Append(GetEscapeSequence(str[num2])); stringBuilder.Append(GetEscapeSequence(str[num2]));
num = num2 + 1; num = num2 + 1;
} }
if (stringBuilder == null) if (stringBuilder == null)
{ {
return str; return str;
} }
stringBuilder.Append(str, num, length - num); stringBuilder.Append(str, num, length - num);
return stringBuilder.ToString(); return stringBuilder.ToString();
} }

View File

@ -18,6 +18,7 @@ namespace Emby.Dlna.Service
private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/"; private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
protected IServerConfigurationManager Config { get; } protected IServerConfigurationManager Config { get; }
protected ILogger Logger { get; } protected ILogger Logger { get; }
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger) protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
@ -135,6 +136,7 @@ namespace Emby.Dlna.Service
break; break;
} }
default: default:
{ {
await reader.SkipAsync().ConfigureAwait(false); await reader.SkipAsync().ConfigureAwait(false);
@ -211,7 +213,9 @@ namespace Emby.Dlna.Service
private class ControlRequestInfo private class ControlRequestInfo
{ {
public string LocalName { get; set; } public string LocalName { get; set; }
public string NamespaceURI { get; set; } public string NamespaceURI { get; set; }
public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
} }

View File

@ -80,6 +80,7 @@ namespace Emby.Dlna.Service
{ {
builder.Append("<allowedValue>" + DescriptionXmlBuilder.Escape(allowedValue) + "</allowedValue>"); builder.Append("<allowedValue>" + DescriptionXmlBuilder.Escape(allowedValue) + "</allowedValue>");
} }
builder.Append("</allowedValueList>"); builder.Append("</allowedValueList>");
} }

View File

@ -77,7 +77,7 @@ namespace Emby.Dlna.Ssdp
// (Optional) Set the filter so we only see notifications for devices we care about // (Optional) Set the filter so we only see notifications for devices we care about
// (can be any search target value i.e device type, uuid value etc - any value that appears in the // (can be any search target value i.e device type, uuid value etc - any value that appears in the
// DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method). // DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).
//_DeviceLocator.NotificationFilter = "upnp:rootdevice"; // _DeviceLocator.NotificationFilter = "upnp:rootdevice";
// Connect our event handler so we process devices as they are found // Connect our event handler so we process devices as they are found
_deviceLocator.DeviceAvailable += OnDeviceLocatorDeviceAvailable; _deviceLocator.DeviceAvailable += OnDeviceLocatorDeviceAvailable;

View File

@ -64,6 +64,7 @@ namespace Emby.Naming.AudioBook
{ {
result.ChapterNumber = int.Parse(matches[0].Groups[0].Value); result.ChapterNumber = int.Parse(matches[0].Groups[0].Value);
} }
if (matches.Count > 1) if (matches.Count > 1)
{ {
result.PartNumber = int.Parse(matches[matches.Count - 1].Groups[0].Value); result.PartNumber = int.Parse(matches[matches.Count - 1].Groups[0].Value);

View File

@ -5,17 +5,17 @@ namespace Emby.Naming.Common
public enum MediaType public enum MediaType
{ {
/// <summary> /// <summary>
/// The audio /// The audio.
/// </summary> /// </summary>
Audio = 0, Audio = 0,
/// <summary> /// <summary>
/// The photo /// The photo.
/// </summary> /// </summary>
Photo = 1, Photo = 1,
/// <summary> /// <summary>
/// The video /// The video.
/// </summary> /// </summary>
Video = 2 Video = 2
} }

View File

@ -43,6 +43,7 @@ using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Serialization; using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Services; using Emby.Server.Implementations.Services;
using Emby.Server.Implementations.Session; using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.SyncPlay;
using Emby.Server.Implementations.TV; using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates; using Emby.Server.Implementations.Updates;
using Emby.Server.Implementations.SyncPlay; using Emby.Server.Implementations.SyncPlay;
@ -79,8 +80,8 @@ using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles; using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.TV;
using MediaBrowser.Controller.SyncPlay; using MediaBrowser.Controller.SyncPlay;
using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers; using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.MediaEncoding.BdInfo; using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
@ -484,12 +485,10 @@ namespace Emby.Server.Implementations
foreach (var plugin in Plugins) foreach (var plugin in Plugins)
{ {
pluginBuilder.AppendLine( pluginBuilder.Append(plugin.Name)
string.Format( .Append(' ')
CultureInfo.InvariantCulture, .Append(plugin.Version)
"{0} {1}", .AppendLine();
plugin.Name,
plugin.Version));
} }
Logger.LogInformation("Plugins: {Plugins}", pluginBuilder.ToString()); Logger.LogInformation("Plugins: {Plugins}", pluginBuilder.ToString());
@ -566,10 +565,8 @@ namespace Emby.Server.Implementations
serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>)); serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
// TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation
serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>)); serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
serviceCollection.AddSingleton<IMediaEncoder>(provider => serviceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
ActivatorUtilities.CreateInstance<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(provider, _startupOptions.FFmpegPath ?? string.Empty));
// TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required // TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>)); serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
@ -875,6 +872,11 @@ namespace Emby.Server.Implementations
Logger.LogError(ex, "Error getting exported types from {Assembly}", ass.FullName); Logger.LogError(ex, "Error getting exported types from {Assembly}", ass.FullName);
continue; continue;
} }
catch (TypeLoadException ex)
{
Logger.LogError(ex, "Error loading types from {Assembly}.", ass.FullName);
continue;
}
foreach (Type type in exportedTypes) foreach (Type type in exportedTypes)
{ {
@ -958,7 +960,7 @@ namespace Emby.Server.Implementations
} }
/// <summary> /// <summary>
/// Notifies that the kernel that a change has been made that requires a restart /// Notifies that the kernel that a change has been made that requires a restart.
/// </summary> /// </summary>
public void NotifyPendingRestart() public void NotifyPendingRestart()
{ {
@ -1154,7 +1156,7 @@ namespace Emby.Server.Implementations
return null; return null;
} }
return GetLocalApiUrl(addresses.First()); return GetLocalApiUrl(addresses[0]);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1227,13 +1229,13 @@ namespace Emby.Server.Implementations
var addresses = ServerConfigurationManager var addresses = ServerConfigurationManager
.Configuration .Configuration
.LocalNetworkAddresses .LocalNetworkAddresses
.Select(NormalizeConfiguredLocalAddress) .Select(x => NormalizeConfiguredLocalAddress(x))
.Where(i => i != null) .Where(i => i != null)
.ToList(); .ToList();
if (addresses.Count == 0) if (addresses.Count == 0)
{ {
addresses.AddRange(_networkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces)); addresses.AddRange(_networkManager.GetLocalIpAddresses());
} }
var resultList = new List<IPAddress>(); var resultList = new List<IPAddress>();
@ -1248,8 +1250,7 @@ namespace Emby.Server.Implementations
} }
} }
var valid = await IsLocalIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false); if (await IsLocalIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false))
if (valid)
{ {
resultList.Add(address); resultList.Add(address);
@ -1263,13 +1264,12 @@ namespace Emby.Server.Implementations
return resultList; return resultList;
} }
public IPAddress NormalizeConfiguredLocalAddress(string address) public IPAddress NormalizeConfiguredLocalAddress(ReadOnlySpan<char> address)
{ {
var index = address.Trim('/').IndexOf('/'); var index = address.Trim('/').IndexOf('/');
if (index != -1) if (index != -1)
{ {
address = address.Substring(index + 1); address = address.Slice(index + 1);
} }
if (IPAddress.TryParse(address.Trim('/'), out IPAddress result)) if (IPAddress.TryParse(address.Trim('/'), out IPAddress result))

View File

@ -1072,7 +1072,7 @@ namespace Emby.Server.Implementations.Channels
} }
// was used for status // was used for status
//if (!string.Equals(item.ExternalEtag ?? string.Empty, info.Etag ?? string.Empty, StringComparison.Ordinal)) // if (!string.Equals(item.ExternalEtag ?? string.Empty, info.Etag ?? string.Empty, StringComparison.Ordinal))
//{ //{
// item.ExternalEtag = info.Etag; // item.ExternalEtag = info.Etag;
// forceUpdate = true; // forceUpdate = true;

View File

@ -363,60 +363,4 @@ namespace Emby.Server.Implementations.Collections
return results.Values; return results.Values;
} }
} }
/// <summary>
/// The collection manager entry point.
/// </summary>
public sealed class CollectionManagerEntryPoint : IServerEntryPoint
{
private readonly CollectionManager _collectionManager;
private readonly IServerConfigurationManager _config;
private readonly ILogger<CollectionManagerEntryPoint> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="CollectionManagerEntryPoint"/> class.
/// </summary>
/// <param name="collectionManager">The collection manager.</param>
/// <param name="config">The server configuration manager.</param>
/// <param name="logger">The logger.</param>
public CollectionManagerEntryPoint(
ICollectionManager collectionManager,
IServerConfigurationManager config,
ILogger<CollectionManagerEntryPoint> logger)
{
_collectionManager = (CollectionManager)collectionManager;
_config = config;
_logger = logger;
}
/// <inheritdoc />
public async Task RunAsync()
{
if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
{
var path = _collectionManager.GetCollectionsFolderPath();
if (Directory.Exists(path))
{
try
{
await _collectionManager.EnsureLibraryFolder(path, true).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating camera uploads library");
}
_config.Configuration.CollectionsUpgraded = true;
_config.SaveConfiguration();
}
}
}
/// <inheritdoc />
public void Dispose()
{
// Nothing to dispose
}
}
} }

View File

@ -109,7 +109,6 @@ namespace Emby.Server.Implementations.Configuration
if (!string.IsNullOrWhiteSpace(newPath) if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(Configuration.CertificatePath, newPath, StringComparison.Ordinal)) && !string.Equals(Configuration.CertificatePath, newPath, StringComparison.Ordinal))
{ {
// Validate
if (!File.Exists(newPath)) if (!File.Exists(newPath))
{ {
throw new FileNotFoundException( throw new FileNotFoundException(
@ -133,7 +132,6 @@ namespace Emby.Server.Implementations.Configuration
if (!string.IsNullOrWhiteSpace(newPath) if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(Configuration.MetadataPath, newPath, StringComparison.Ordinal)) && !string.Equals(Configuration.MetadataPath, newPath, StringComparison.Ordinal))
{ {
// Validate
if (!Directory.Exists(newPath)) if (!Directory.Exists(newPath))
{ {
throw new DirectoryNotFoundException( throw new DirectoryNotFoundException(
@ -146,60 +144,5 @@ namespace Emby.Server.Implementations.Configuration
EnsureWriteAccess(newPath); EnsureWriteAccess(newPath);
} }
} }
/// <summary>
/// Sets all configuration values to their optimal values.
/// </summary>
/// <returns>If the configuration changed.</returns>
public bool SetOptimalValues()
{
var config = Configuration;
var changed = false;
if (!config.EnableCaseSensitiveItemIds)
{
config.EnableCaseSensitiveItemIds = true;
changed = true;
}
if (!config.SkipDeserializationForBasicTypes)
{
config.SkipDeserializationForBasicTypes = true;
changed = true;
}
if (!config.EnableSimpleArtistDetection)
{
config.EnableSimpleArtistDetection = true;
changed = true;
}
if (!config.EnableNormalizedItemByNameIds)
{
config.EnableNormalizedItemByNameIds = true;
changed = true;
}
if (!config.DisableLiveTvChannelUserDataName)
{
config.DisableLiveTvChannelUserDataName = true;
changed = true;
}
if (!config.EnableNewOmdbSupport)
{
config.EnableNewOmdbSupport = true;
changed = true;
}
if (!config.CollectionsUpgraded)
{
config.CollectionsUpgraded = true;
changed = true;
}
return changed;
}
} }
} }

View File

@ -17,7 +17,6 @@ namespace Emby.Server.Implementations
{ {
{ HostWebClientKey, bool.TrueString }, { HostWebClientKey, bool.TrueString },
{ HttpListenerHost.DefaultRedirectKey, "web/index.html" }, { HttpListenerHost.DefaultRedirectKey, "web/index.html" },
{ InstallationManager.PluginManifestUrlKey, "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" },
{ FfmpegProbeSizeKey, "1G" }, { FfmpegProbeSizeKey, "1G" },
{ FfmpegAnalyzeDurationKey, "200M" }, { FfmpegAnalyzeDurationKey, "200M" },
{ PlaylistsAllowDuplicatesKey, bool.TrueString } { PlaylistsAllowDuplicatesKey, bool.TrueString }

View File

@ -162,7 +162,6 @@ namespace Emby.Server.Implementations.Data
} }
return false; return false;
}, ReadTransactionMode); }, ReadTransactionMode);
} }
@ -248,12 +247,12 @@ namespace Emby.Server.Implementations.Data
public enum SynchronousMode public enum SynchronousMode
{ {
/// <summary> /// <summary>
/// SQLite continues without syncing as soon as it has handed data off to the operating system /// SQLite continues without syncing as soon as it has handed data off to the operating system.
/// </summary> /// </summary>
Off = 0, Off = 0,
/// <summary> /// <summary>
/// SQLite database engine will still sync at the most critical moments /// SQLite database engine will still sync at the most critical moments.
/// </summary> /// </summary>
Normal = 1, Normal = 1,

View File

@ -51,7 +51,6 @@ namespace Emby.Server.Implementations.Data
_libraryManager.DeleteItem(item, new DeleteOptions _libraryManager.DeleteItem(item, new DeleteOptions
{ {
DeleteFileLocation = false DeleteFileLocation = false
}); });
} }

View File

@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Opens the connection to the database /// Opens the connection to the database.
/// </summary> /// </summary>
/// <returns>Task.</returns> /// <returns>Task.</returns>
private void InitializeInternal() private void InitializeInternal()
@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Save the display preferences associated with an item in the repo /// Save the display preferences associated with an item in the repo.
/// </summary> /// </summary>
/// <param name="displayPreferences">The display preferences.</param> /// <param name="displayPreferences">The display preferences.</param>
/// <param name="userId">The user id.</param> /// <param name="userId">The user id.</param>
@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Save all display preferences associated with a user in the repo /// Save all display preferences associated with a user in the repo.
/// </summary> /// </summary>
/// <param name="displayPreferences">The display preferences.</param> /// <param name="displayPreferences">The display preferences.</param>
/// <param name="userId">The user id.</param> /// <param name="userId">The user id.</param>

View File

@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Data
protected override TempStoreMode TempStore => TempStoreMode.Memory; protected override TempStoreMode TempStore => TempStoreMode.Memory;
/// <summary> /// <summary>
/// Opens the connection to the database /// Opens the connection to the database.
/// </summary> /// </summary>
public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager)
{ {
@ -321,7 +321,6 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "MediaStreams", "ColorPrimaries", "TEXT", existingColumnNames); AddColumn(db, "MediaStreams", "ColorPrimaries", "TEXT", existingColumnNames);
AddColumn(db, "MediaStreams", "ColorSpace", "TEXT", existingColumnNames); AddColumn(db, "MediaStreams", "ColorSpace", "TEXT", existingColumnNames);
AddColumn(db, "MediaStreams", "ColorTransfer", "TEXT", existingColumnNames); AddColumn(db, "MediaStreams", "ColorTransfer", "TEXT", existingColumnNames);
}, TransactionMode); }, TransactionMode);
connection.RunQueries(postQueries); connection.RunQueries(postQueries);
@ -549,7 +548,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Save a standard item in the repo /// Save a standard item in the repo.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
@ -794,6 +793,7 @@ namespace Emby.Server.Implementations.Data
{ {
saveItemStatement.TryBindNull("@Width"); saveItemStatement.TryBindNull("@Width");
} }
if (item.Height > 0) if (item.Height > 0)
{ {
saveItemStatement.TryBind("@Height", item.Height); saveItemStatement.TryBind("@Height", item.Height);
@ -933,6 +933,7 @@ namespace Emby.Server.Implementations.Data
{ {
saveItemStatement.TryBindNull("@SeriesName"); saveItemStatement.TryBindNull("@SeriesName");
} }
if (string.IsNullOrWhiteSpace(userDataKey)) if (string.IsNullOrWhiteSpace(userDataKey))
{ {
saveItemStatement.TryBindNull("@UserDataKey"); saveItemStatement.TryBindNull("@UserDataKey");
@ -1008,6 +1009,7 @@ namespace Emby.Server.Implementations.Data
{ {
artists = string.Join("|", hasArtists.Artists); artists = string.Join("|", hasArtists.Artists);
} }
saveItemStatement.TryBind("@Artists", artists); saveItemStatement.TryBind("@Artists", artists);
string albumArtists = null; string albumArtists = null;
@ -1107,6 +1109,7 @@ namespace Emby.Server.Implementations.Data
{ {
continue; continue;
} }
str.Append(ToValueString(i) + "|"); str.Append(ToValueString(i) + "|");
} }
@ -1205,7 +1208,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Internal retrieve from items or users table /// Internal retrieve from items or users table.
/// </summary> /// </summary>
/// <param name="id">The id.</param> /// <param name="id">The id.</param>
/// <returns>BaseItem.</returns> /// <returns>BaseItem.</returns>
@ -1367,6 +1370,7 @@ namespace Emby.Server.Implementations.Data
hasStartDate.StartDate = reader[index].ReadDateTime(); hasStartDate.StartDate = reader[index].ReadDateTime();
} }
} }
index++; index++;
} }
@ -1374,12 +1378,14 @@ namespace Emby.Server.Implementations.Data
{ {
item.EndDate = reader[index].TryReadDateTime(); item.EndDate = reader[index].TryReadDateTime();
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.ChannelId = new Guid(reader.GetString(index)); item.ChannelId = new Guid(reader.GetString(index));
} }
index++; index++;
if (enableProgramAttributes) if (enableProgramAttributes)
@ -1390,24 +1396,28 @@ namespace Emby.Server.Implementations.Data
{ {
hasProgramAttributes.IsMovie = reader.GetBoolean(index); hasProgramAttributes.IsMovie = reader.GetBoolean(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
hasProgramAttributes.IsSeries = reader.GetBoolean(index); hasProgramAttributes.IsSeries = reader.GetBoolean(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
hasProgramAttributes.EpisodeTitle = reader.GetString(index); hasProgramAttributes.EpisodeTitle = reader.GetString(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
hasProgramAttributes.IsRepeat = reader.GetBoolean(index); hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
} }
index++; index++;
} }
else else
@ -1420,6 +1430,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.CommunityRating = reader.GetFloat(index); item.CommunityRating = reader.GetFloat(index);
} }
index++; index++;
if (HasField(query, ItemFields.CustomRating)) if (HasField(query, ItemFields.CustomRating))
@ -1428,6 +1439,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.CustomRating = reader.GetString(index); item.CustomRating = reader.GetString(index);
} }
index++; index++;
} }
@ -1435,6 +1447,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.IndexNumber = reader.GetInt32(index); item.IndexNumber = reader.GetInt32(index);
} }
index++; index++;
if (HasField(query, ItemFields.Settings)) if (HasField(query, ItemFields.Settings))
@ -1443,18 +1456,21 @@ namespace Emby.Server.Implementations.Data
{ {
item.IsLocked = reader.GetBoolean(index); item.IsLocked = reader.GetBoolean(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.PreferredMetadataLanguage = reader.GetString(index); item.PreferredMetadataLanguage = reader.GetString(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.PreferredMetadataCountryCode = reader.GetString(index); item.PreferredMetadataCountryCode = reader.GetString(index);
} }
index++; index++;
} }
@ -1464,6 +1480,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.Width = reader.GetInt32(index); item.Width = reader.GetInt32(index);
} }
index++; index++;
} }
@ -1473,6 +1490,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.Height = reader.GetInt32(index); item.Height = reader.GetInt32(index);
} }
index++; index++;
} }
@ -1482,6 +1500,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.DateLastRefreshed = reader[index].ReadDateTime(); item.DateLastRefreshed = reader[index].ReadDateTime();
} }
index++; index++;
} }
@ -1489,18 +1508,21 @@ namespace Emby.Server.Implementations.Data
{ {
item.Name = reader.GetString(index); item.Name = reader.GetString(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.Path = RestorePath(reader.GetString(index)); item.Path = RestorePath(reader.GetString(index));
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.PremiereDate = reader[index].TryReadDateTime(); item.PremiereDate = reader[index].TryReadDateTime();
} }
index++; index++;
if (HasField(query, ItemFields.Overview)) if (HasField(query, ItemFields.Overview))
@ -1509,6 +1531,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.Overview = reader.GetString(index); item.Overview = reader.GetString(index);
} }
index++; index++;
} }
@ -1516,18 +1539,21 @@ namespace Emby.Server.Implementations.Data
{ {
item.ParentIndexNumber = reader.GetInt32(index); item.ParentIndexNumber = reader.GetInt32(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.ProductionYear = reader.GetInt32(index); item.ProductionYear = reader.GetInt32(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.OfficialRating = reader.GetString(index); item.OfficialRating = reader.GetString(index);
} }
index++; index++;
if (HasField(query, ItemFields.SortName)) if (HasField(query, ItemFields.SortName))
@ -1536,6 +1562,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.ForcedSortName = reader.GetString(index); item.ForcedSortName = reader.GetString(index);
} }
index++; index++;
} }
@ -1543,12 +1570,14 @@ namespace Emby.Server.Implementations.Data
{ {
item.RunTimeTicks = reader.GetInt64(index); item.RunTimeTicks = reader.GetInt64(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.Size = reader.GetInt64(index); item.Size = reader.GetInt64(index);
} }
index++; index++;
if (HasField(query, ItemFields.DateCreated)) if (HasField(query, ItemFields.DateCreated))
@ -1557,6 +1586,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.DateCreated = reader[index].ReadDateTime(); item.DateCreated = reader[index].ReadDateTime();
} }
index++; index++;
} }
@ -1564,6 +1594,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.DateModified = reader[index].ReadDateTime(); item.DateModified = reader[index].ReadDateTime();
} }
index++; index++;
item.Id = reader.GetGuid(index); item.Id = reader.GetGuid(index);
@ -1575,6 +1606,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.Genres = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); item.Genres = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
} }
index++; index++;
} }
@ -1582,6 +1614,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.ParentId = reader.GetGuid(index); item.ParentId = reader.GetGuid(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
@ -1591,6 +1624,7 @@ namespace Emby.Server.Implementations.Data
item.Audio = audio; item.Audio = audio;
} }
} }
index++; index++;
// TODO: Even if not needed by apps, the server needs it internally // TODO: Even if not needed by apps, the server needs it internally
@ -1604,6 +1638,7 @@ namespace Emby.Server.Implementations.Data
liveTvChannel.ServiceName = reader.GetString(index); liveTvChannel.ServiceName = reader.GetString(index);
} }
} }
index++; index++;
} }
@ -1611,6 +1646,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.IsInMixedFolder = reader.GetBoolean(index); item.IsInMixedFolder = reader.GetBoolean(index);
} }
index++; index++;
if (HasField(query, ItemFields.DateLastSaved)) if (HasField(query, ItemFields.DateLastSaved))
@ -1619,6 +1655,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.DateLastSaved = reader[index].ReadDateTime(); item.DateLastSaved = reader[index].ReadDateTime();
} }
index++; index++;
} }
@ -1636,8 +1673,10 @@ namespace Emby.Server.Implementations.Data
} }
} }
} }
item.LockedFields = GetLockedFields(reader.GetString(index)).ToArray(); item.LockedFields = GetLockedFields(reader.GetString(index)).ToArray();
} }
index++; index++;
} }
@ -1647,6 +1686,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.Studios = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); item.Studios = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
} }
index++; index++;
} }
@ -1656,6 +1696,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.Tags = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); item.Tags = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
} }
index++; index++;
} }
@ -1675,9 +1716,11 @@ namespace Emby.Server.Implementations.Data
} }
} }
} }
trailer.TrailerTypes = GetTrailerTypes(reader.GetString(index)).ToArray(); trailer.TrailerTypes = GetTrailerTypes(reader.GetString(index)).ToArray();
} }
} }
index++; index++;
} }
@ -1687,6 +1730,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.OriginalTitle = reader.GetString(index); item.OriginalTitle = reader.GetString(index);
} }
index++; index++;
} }
@ -1697,6 +1741,7 @@ namespace Emby.Server.Implementations.Data
video.PrimaryVersionId = reader.GetString(index); video.PrimaryVersionId = reader.GetString(index);
} }
} }
index++; index++;
if (HasField(query, ItemFields.DateLastMediaAdded)) if (HasField(query, ItemFields.DateLastMediaAdded))
@ -1705,6 +1750,7 @@ namespace Emby.Server.Implementations.Data
{ {
folder.DateLastMediaAdded = reader[index].TryReadDateTime(); folder.DateLastMediaAdded = reader[index].TryReadDateTime();
} }
index++; index++;
} }
@ -1712,18 +1758,21 @@ namespace Emby.Server.Implementations.Data
{ {
item.Album = reader.GetString(index); item.Album = reader.GetString(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.CriticRating = reader.GetFloat(index); item.CriticRating = reader.GetFloat(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.IsVirtualItem = reader.GetBoolean(index); item.IsVirtualItem = reader.GetBoolean(index);
} }
index++; index++;
if (item is IHasSeries hasSeriesName) if (item is IHasSeries hasSeriesName)
@ -1733,6 +1782,7 @@ namespace Emby.Server.Implementations.Data
hasSeriesName.SeriesName = reader.GetString(index); hasSeriesName.SeriesName = reader.GetString(index);
} }
} }
index++; index++;
if (hasEpisodeAttributes) if (hasEpisodeAttributes)
@ -1743,6 +1793,7 @@ namespace Emby.Server.Implementations.Data
{ {
episode.SeasonName = reader.GetString(index); episode.SeasonName = reader.GetString(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1753,6 +1804,7 @@ namespace Emby.Server.Implementations.Data
{ {
index++; index++;
} }
index++; index++;
} }
@ -1766,6 +1818,7 @@ namespace Emby.Server.Implementations.Data
hasSeries.SeriesId = reader.GetGuid(index); hasSeries.SeriesId = reader.GetGuid(index);
} }
} }
index++; index++;
} }
@ -1775,6 +1828,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.PresentationUniqueKey = reader.GetString(index); item.PresentationUniqueKey = reader.GetString(index);
} }
index++; index++;
} }
@ -1784,6 +1838,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.InheritedParentalRatingValue = reader.GetInt32(index); item.InheritedParentalRatingValue = reader.GetInt32(index);
} }
index++; index++;
} }
@ -1793,6 +1848,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.ExternalSeriesId = reader.GetString(index); item.ExternalSeriesId = reader.GetString(index);
} }
index++; index++;
} }
@ -1802,6 +1858,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.Tagline = reader.GetString(index); item.Tagline = reader.GetString(index);
} }
index++; index++;
} }
@ -1809,6 +1866,7 @@ namespace Emby.Server.Implementations.Data
{ {
DeserializeProviderIds(reader.GetString(index), item); DeserializeProviderIds(reader.GetString(index), item);
} }
index++; index++;
if (query.DtoOptions.EnableImages) if (query.DtoOptions.EnableImages)
@ -1817,6 +1875,7 @@ namespace Emby.Server.Implementations.Data
{ {
DeserializeImages(reader.GetString(index), item); DeserializeImages(reader.GetString(index), item);
} }
index++; index++;
} }
@ -1826,6 +1885,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.ProductionLocations = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries).ToArray(); item.ProductionLocations = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
} }
index++; index++;
} }
@ -1835,6 +1895,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.ExtraIds = SplitToGuids(reader.GetString(index)); item.ExtraIds = SplitToGuids(reader.GetString(index));
} }
index++; index++;
} }
@ -1842,6 +1903,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.TotalBitrate = reader.GetInt32(index); item.TotalBitrate = reader.GetInt32(index);
} }
index++; index++;
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
@ -1851,6 +1913,7 @@ namespace Emby.Server.Implementations.Data
item.ExtraType = extraType; item.ExtraType = extraType;
} }
} }
index++; index++;
if (hasArtistFields) if (hasArtistFields)
@ -1859,12 +1922,14 @@ namespace Emby.Server.Implementations.Data
{ {
hasArtists.Artists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); hasArtists.Artists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
} }
index++; index++;
if (item is IHasAlbumArtist hasAlbumArtists && !reader.IsDBNull(index)) if (item is IHasAlbumArtist hasAlbumArtists && !reader.IsDBNull(index))
{ {
hasAlbumArtists.AlbumArtists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); hasAlbumArtists.AlbumArtists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
} }
index++; index++;
} }
@ -1872,6 +1937,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.ExternalId = reader.GetString(index); item.ExternalId = reader.GetString(index);
} }
index++; index++;
if (HasField(query, ItemFields.SeriesPresentationUniqueKey)) if (HasField(query, ItemFields.SeriesPresentationUniqueKey))
@ -1883,6 +1949,7 @@ namespace Emby.Server.Implementations.Data
hasSeries.SeriesPresentationUniqueKey = reader.GetString(index); hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
} }
} }
index++; index++;
} }
@ -1892,6 +1959,7 @@ namespace Emby.Server.Implementations.Data
{ {
program.ShowId = reader.GetString(index); program.ShowId = reader.GetString(index);
} }
index++; index++;
} }
@ -1899,6 +1967,7 @@ namespace Emby.Server.Implementations.Data
{ {
item.OwnerId = reader.GetGuid(index); item.OwnerId = reader.GetGuid(index);
} }
index++; index++;
return item; return item;
@ -1919,7 +1988,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Gets chapters for an item /// Gets chapters for an item.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>IEnumerable{ChapterInfo}.</returns> /// <returns>IEnumerable{ChapterInfo}.</returns>
@ -1947,7 +2016,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Gets a single chapter for an item /// Gets a single chapter for an item.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
@ -2044,7 +2113,6 @@ namespace Emby.Server.Implementations.Data
db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob); db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob);
InsertChapters(idBlob, chapters, db); InsertChapters(idBlob, chapters, db);
}, TransactionMode); }, TransactionMode);
} }
} }
@ -2475,6 +2543,7 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind("@SearchTermStartsWith", searchTerm + "%"); statement.TryBind("@SearchTermStartsWith", searchTerm + "%");
} }
if (commandText.IndexOf("@SearchTermContains", StringComparison.OrdinalIgnoreCase) != -1) if (commandText.IndexOf("@SearchTermContains", StringComparison.OrdinalIgnoreCase) != -1)
{ {
statement.TryBind("@SearchTermContains", "%" + searchTerm + "%"); statement.TryBind("@SearchTermContains", "%" + searchTerm + "%");
@ -2706,22 +2775,85 @@ namespace Emby.Server.Implementations.Data
private string FixUnicodeChars(string buffer) private string FixUnicodeChars(string buffer)
{ {
if (buffer.IndexOf('\u2013') > -1) buffer = buffer.Replace('\u2013', '-'); // en dash if (buffer.IndexOf('\u2013') > -1)
if (buffer.IndexOf('\u2014') > -1) buffer = buffer.Replace('\u2014', '-'); // em dash {
if (buffer.IndexOf('\u2015') > -1) buffer = buffer.Replace('\u2015', '-'); // horizontal bar buffer = buffer.Replace('\u2013', '-'); // en dash
if (buffer.IndexOf('\u2017') > -1) buffer = buffer.Replace('\u2017', '_'); // double low line }
if (buffer.IndexOf('\u2018') > -1) buffer = buffer.Replace('\u2018', '\''); // left single quotation mark
if (buffer.IndexOf('\u2019') > -1) buffer = buffer.Replace('\u2019', '\''); // right single quotation mark if (buffer.IndexOf('\u2014') > -1)
if (buffer.IndexOf('\u201a') > -1) buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark {
if (buffer.IndexOf('\u201b') > -1) buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark buffer = buffer.Replace('\u2014', '-'); // em dash
if (buffer.IndexOf('\u201c') > -1) buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark }
if (buffer.IndexOf('\u201d') > -1) buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark
if (buffer.IndexOf('\u201e') > -1) buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark if (buffer.IndexOf('\u2015') > -1)
if (buffer.IndexOf('\u2026') > -1) buffer = buffer.Replace("\u2026", "..."); // horizontal ellipsis {
if (buffer.IndexOf('\u2032') > -1) buffer = buffer.Replace('\u2032', '\''); // prime buffer = buffer.Replace('\u2015', '-'); // horizontal bar
if (buffer.IndexOf('\u2033') > -1) buffer = buffer.Replace('\u2033', '\"'); // double prime }
if (buffer.IndexOf('\u0060') > -1) buffer = buffer.Replace('\u0060', '\''); // grave accent
if (buffer.IndexOf('\u00B4') > -1) buffer = buffer.Replace('\u00B4', '\''); // acute accent if (buffer.IndexOf('\u2017') > -1)
{
buffer = buffer.Replace('\u2017', '_'); // double low line
}
if (buffer.IndexOf('\u2018') > -1)
{
buffer = buffer.Replace('\u2018', '\''); // left single quotation mark
}
if (buffer.IndexOf('\u2019') > -1)
{
buffer = buffer.Replace('\u2019', '\''); // right single quotation mark
}
if (buffer.IndexOf('\u201a') > -1)
{
buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark
}
if (buffer.IndexOf('\u201b') > -1)
{
buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark
}
if (buffer.IndexOf('\u201c') > -1)
{
buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark
}
if (buffer.IndexOf('\u201d') > -1)
{
buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark
}
if (buffer.IndexOf('\u201e') > -1)
{
buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark
}
if (buffer.IndexOf('\u2026') > -1)
{
buffer = buffer.Replace("\u2026", "..."); // horizontal ellipsis
}
if (buffer.IndexOf('\u2032') > -1)
{
buffer = buffer.Replace('\u2032', '\''); // prime
}
if (buffer.IndexOf('\u2033') > -1)
{
buffer = buffer.Replace('\u2033', '\"'); // double prime
}
if (buffer.IndexOf('\u0060') > -1)
{
buffer = buffer.Replace('\u0060', '\''); // grave accent
}
if (buffer.IndexOf('\u00B4') > -1)
{
buffer = buffer.Replace('\u00B4', '\''); // acute accent
}
return buffer; return buffer;
} }
@ -2745,6 +2877,7 @@ namespace Emby.Server.Implementations.Data
{ {
items[i] = newItem; items[i] = newItem;
} }
return; return;
} }
} }
@ -2837,6 +2970,7 @@ namespace Emby.Server.Implementations.Data
{ {
statementTexts.Add(commandText); statementTexts.Add(commandText);
} }
if (query.EnableTotalRecordCount) if (query.EnableTotalRecordCount)
{ {
commandText = string.Empty; commandText = string.Empty;
@ -3241,6 +3375,7 @@ namespace Emby.Server.Implementations.Data
{ {
statementTexts.Add(commandText); statementTexts.Add(commandText);
} }
if (query.EnableTotalRecordCount) if (query.EnableTotalRecordCount)
{ {
commandText = string.Empty; commandText = string.Empty;
@ -3594,11 +3729,13 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("IndexNumber=@IndexNumber"); whereClauses.Add("IndexNumber=@IndexNumber");
statement?.TryBind("@IndexNumber", query.IndexNumber.Value); statement?.TryBind("@IndexNumber", query.IndexNumber.Value);
} }
if (query.ParentIndexNumber.HasValue) if (query.ParentIndexNumber.HasValue)
{ {
whereClauses.Add("ParentIndexNumber=@ParentIndexNumber"); whereClauses.Add("ParentIndexNumber=@ParentIndexNumber");
statement?.TryBind("@ParentIndexNumber", query.ParentIndexNumber.Value); statement?.TryBind("@ParentIndexNumber", query.ParentIndexNumber.Value);
} }
if (query.ParentIndexNumberNotEquals.HasValue) if (query.ParentIndexNumberNotEquals.HasValue)
{ {
whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)"); whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)");
@ -3884,6 +4021,7 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, artistId.ToByteArray()); statement.TryBind(paramName, artistId.ToByteArray());
} }
index++; index++;
} }
@ -3904,6 +4042,7 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, artistId.ToByteArray()); statement.TryBind(paramName, artistId.ToByteArray());
} }
index++; index++;
} }
@ -3924,8 +4063,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, artistId.ToByteArray()); statement.TryBind(paramName, artistId.ToByteArray());
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -3943,8 +4084,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, albumId.ToByteArray()); statement.TryBind(paramName, albumId.ToByteArray());
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -3962,8 +4105,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, artistId.ToByteArray()); statement.TryBind(paramName, artistId.ToByteArray());
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -3981,8 +4126,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, genreId.ToByteArray()); statement.TryBind(paramName, genreId.ToByteArray());
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -3998,8 +4145,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind("@Genre" + index, GetCleanValue(item)); statement.TryBind("@Genre" + index, GetCleanValue(item));
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -4015,8 +4164,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind("@Tag" + index, GetCleanValue(item)); statement.TryBind("@Tag" + index, GetCleanValue(item));
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -4032,8 +4183,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind("@ExcludeTag" + index, GetCleanValue(item)); statement.TryBind("@ExcludeTag" + index, GetCleanValue(item));
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -4052,8 +4205,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, studioId.ToByteArray()); statement.TryBind(paramName, studioId.ToByteArray());
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -4069,8 +4224,10 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind("@OfficialRating" + index, item); statement.TryBind("@OfficialRating" + index, item);
} }
index++; index++;
} }
var clause = "(" + string.Join(" OR ", clauses) + ")"; var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause); whereClauses.Add(clause);
} }
@ -4245,6 +4402,7 @@ namespace Emby.Server.Implementations.Data
statement.TryBind("@IsVirtualItem", isVirtualItem.Value); statement.TryBind("@IsVirtualItem", isVirtualItem.Value);
} }
} }
if (query.IsSpecialSeason.HasValue) if (query.IsSpecialSeason.HasValue)
{ {
if (query.IsSpecialSeason.Value) if (query.IsSpecialSeason.Value)
@ -4256,6 +4414,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("IndexNumber <> 0"); whereClauses.Add("IndexNumber <> 0");
} }
} }
if (query.IsUnaired.HasValue) if (query.IsUnaired.HasValue)
{ {
if (query.IsUnaired.Value) if (query.IsUnaired.Value)
@ -4267,6 +4426,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("PremiereDate < DATETIME('now')"); whereClauses.Add("PremiereDate < DATETIME('now')");
} }
} }
var queryMediaTypes = query.MediaTypes.Where(IsValidMediaType).ToArray(); var queryMediaTypes = query.MediaTypes.Where(IsValidMediaType).ToArray();
if (queryMediaTypes.Length == 1) if (queryMediaTypes.Length == 1)
{ {
@ -4282,6 +4442,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("MediaType in (" + val + ")"); whereClauses.Add("MediaType in (" + val + ")");
} }
if (query.ItemIds.Length > 0) if (query.ItemIds.Length > 0)
{ {
var includeIds = new List<string>(); var includeIds = new List<string>();
@ -4294,11 +4455,13 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind("@IncludeId" + index, id); statement.TryBind("@IncludeId" + index, id);
} }
index++; index++;
} }
whereClauses.Add("(" + string.Join(" OR ", includeIds) + ")"); whereClauses.Add("(" + string.Join(" OR ", includeIds) + ")");
} }
if (query.ExcludeItemIds.Length > 0) if (query.ExcludeItemIds.Length > 0)
{ {
var excludeIds = new List<string>(); var excludeIds = new List<string>();
@ -4311,6 +4474,7 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind("@ExcludeId" + index, id); statement.TryBind("@ExcludeId" + index, id);
} }
index++; index++;
} }
@ -4335,6 +4499,7 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%"); statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
} }
index++; index++;
break; break;
@ -4360,7 +4525,7 @@ namespace Emby.Server.Implementations.Data
// TODO this seems to be an idea for a better schema where ProviderIds are their own table // TODO this seems to be an idea for a better schema where ProviderIds are their own table
// buut this is not implemented // buut this is not implemented
//hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")"); // hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
// TODO this is a really BAD way to do it since the pair: // TODO this is a really BAD way to do it since the pair:
// Tmdb, 1234 matches Tmdb=1234 but also Tmdb=1234567 // Tmdb, 1234 matches Tmdb=1234 but also Tmdb=1234567
@ -4377,6 +4542,7 @@ namespace Emby.Server.Implementations.Data
{ {
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%"); statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
} }
index++; index++;
break; break;
@ -4427,6 +4593,7 @@ namespace Emby.Server.Implementations.Data
{ {
whereClauses.Add("(TopParentId=@TopParentId)"); whereClauses.Add("(TopParentId=@TopParentId)");
} }
if (statement != null) if (statement != null)
{ {
statement.TryBind("@TopParentId", queryTopParentIds[0].ToString("N", CultureInfo.InvariantCulture)); statement.TryBind("@TopParentId", queryTopParentIds[0].ToString("N", CultureInfo.InvariantCulture));
@ -4464,11 +4631,13 @@ namespace Emby.Server.Implementations.Data
statement.TryBind("@AncestorId", query.AncestorIds[0]); statement.TryBind("@AncestorId", query.AncestorIds[0]);
} }
} }
if (query.AncestorIds.Length > 1) if (query.AncestorIds.Length > 1)
{ {
var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'")); var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause)); whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause));
} }
if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)) if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey))
{ {
var inClause = "select guid from TypedBaseItems where PresentationUniqueKey=@AncestorWithPresentationUniqueKey"; var inClause = "select guid from TypedBaseItems where PresentationUniqueKey=@AncestorWithPresentationUniqueKey";
@ -4497,6 +4666,7 @@ namespace Emby.Server.Implementations.Data
statement.TryBind("@UnratedType", query.BlockUnratedItems[0].ToString()); statement.TryBind("@UnratedType", query.BlockUnratedItems[0].ToString());
} }
} }
if (query.BlockUnratedItems.Length > 1) if (query.BlockUnratedItems.Length > 1)
{ {
var inClause = string.Join(",", query.BlockUnratedItems.Select(i => "'" + i.ToString() + "'")); var inClause = string.Join(",", query.BlockUnratedItems.Select(i => "'" + i.ToString() + "'"));
@ -4789,7 +4959,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
connection.RunInTransaction(db => connection.RunInTransaction(db =>
{ {
connection.ExecuteAll(sql); connection.ExecuteAll(sql);
}, TransactionMode); }, TransactionMode);
} }
} }
@ -4972,6 +5141,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.TryBind("@ItemId", query.ItemId.ToByteArray()); statement.TryBind("@ItemId", query.ItemId.ToByteArray());
} }
} }
if (!query.AppearsInItemId.Equals(Guid.Empty)) if (!query.AppearsInItemId.Equals(Guid.Empty))
{ {
whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)"); whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
@ -4980,6 +5150,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray()); statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray());
} }
} }
var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList(); var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
if (queryPersonTypes.Count == 1) if (queryPersonTypes.Count == 1)
@ -4996,6 +5167,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
whereClauses.Add("PersonType in (" + val + ")"); whereClauses.Add("PersonType in (" + val + ")");
} }
var queryExcludePersonTypes = query.ExcludePersonTypes.Where(IsValidPersonType).ToList(); var queryExcludePersonTypes = query.ExcludePersonTypes.Where(IsValidPersonType).ToList();
if (queryExcludePersonTypes.Count == 1) if (queryExcludePersonTypes.Count == 1)
@ -5012,6 +5184,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
whereClauses.Add("PersonType not in (" + val + ")"); whereClauses.Add("PersonType not in (" + val + ")");
} }
if (query.MaxListOrder.HasValue) if (query.MaxListOrder.HasValue)
{ {
whereClauses.Add("ListOrder<=@MaxListOrder"); whereClauses.Add("ListOrder<=@MaxListOrder");
@ -5020,6 +5193,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.TryBind("@MaxListOrder", query.MaxListOrder.Value); statement.TryBind("@MaxListOrder", query.MaxListOrder.Value);
} }
} }
if (!string.IsNullOrWhiteSpace(query.NameContains)) if (!string.IsNullOrWhiteSpace(query.NameContains))
{ {
whereClauses.Add("Name like @NameContains"); whereClauses.Add("Name like @NameContains");
@ -5159,6 +5333,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
var typeString = string.Join(",", withItemTypes.Select(i => "'" + i + "'")); var typeString = string.Join(",", withItemTypes.Select(i => "'" + i + "'"));
commandText += " AND ItemId In (select guid from typedbaseitems where type in (" + typeString + "))"; commandText += " AND ItemId In (select guid from typedbaseitems where type in (" + typeString + "))";
} }
if (excludeItemTypes.Count > 0) if (excludeItemTypes.Count > 0)
{ {
var typeString = string.Join(",", excludeItemTypes.Select(i => "'" + i + "'")); var typeString = string.Join(",", excludeItemTypes.Select(i => "'" + i + "'"));
@ -5180,7 +5355,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
} }
} }
} }
} }
LogQueryTime("GetItemValueNames", commandText, now); LogQueryTime("GetItemValueNames", commandText, now);
@ -5631,7 +5805,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
db.Execute("delete from People where ItemId=@ItemId", itemIdBlob); db.Execute("delete from People where ItemId=@ItemId", itemIdBlob);
InsertPeople(itemIdBlob, people, db); InsertPeople(itemIdBlob, people, db);
}, TransactionMode); }, TransactionMode);
} }
} }
@ -5788,7 +5961,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob); db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);
InsertMediaStreams(itemIdBlob, streams, db); InsertMediaStreams(itemIdBlob, streams, db);
}, TransactionMode); }, TransactionMode);
} }
} }
@ -6134,7 +6306,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob);
InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken); InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken);
}, TransactionMode); }, TransactionMode);
} }
} }
@ -6200,7 +6371,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
/// Gets the attachment. /// Gets the attachment.
/// </summary> /// </summary>
/// <param name="reader">The reader.</param> /// <param name="reader">The reader.</param>
/// <returns>MediaAttachment</returns> /// <returns>MediaAttachment.</returns>
private MediaAttachment GetMediaAttachment(IReadOnlyList<IResultSetValue> reader) private MediaAttachment GetMediaAttachment(IReadOnlyList<IResultSetValue> reader)
{ {
var item = new MediaAttachment var item = new MediaAttachment

View File

@ -135,10 +135,12 @@ namespace Emby.Server.Implementations.Data
{ {
throw new ArgumentNullException(nameof(userData)); throw new ArgumentNullException(nameof(userData));
} }
if (internalUserId <= 0) if (internalUserId <= 0)
{ {
throw new ArgumentNullException(nameof(internalUserId)); throw new ArgumentNullException(nameof(internalUserId));
} }
if (string.IsNullOrEmpty(key)) if (string.IsNullOrEmpty(key))
{ {
throw new ArgumentNullException(nameof(key)); throw new ArgumentNullException(nameof(key));
@ -153,6 +155,7 @@ namespace Emby.Server.Implementations.Data
{ {
throw new ArgumentNullException(nameof(userData)); throw new ArgumentNullException(nameof(userData));
} }
if (internalUserId <= 0) if (internalUserId <= 0)
{ {
throw new ArgumentNullException(nameof(internalUserId)); throw new ArgumentNullException(nameof(internalUserId));
@ -235,7 +238,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Persist all user data for the specified user /// Persist all user data for the specified user.
/// </summary> /// </summary>
private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken) private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken)
{ {
@ -309,7 +312,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Return all user-data associated with the given user /// Return all user-data associated with the given user.
/// </summary> /// </summary>
/// <param name="internalUserId"></param> /// <param name="internalUserId"></param>
/// <returns></returns> /// <returns></returns>
@ -339,7 +342,7 @@ namespace Emby.Server.Implementations.Data
} }
/// <summary> /// <summary>
/// Read a row from the specified reader into the provided userData object /// Read a row from the specified reader into the provided userData object.
/// </summary> /// </summary>
/// <param name="reader"></param> /// <param name="reader"></param>
private UserItemData ReadRow(IReadOnlyList<IResultSetValue> reader) private UserItemData ReadRow(IReadOnlyList<IResultSetValue> reader)
@ -347,7 +350,7 @@ namespace Emby.Server.Implementations.Data
var userData = new UserItemData(); var userData = new UserItemData();
userData.Key = reader[0].ToString(); userData.Key = reader[0].ToString();
//userData.UserId = reader[1].ReadGuidFromBlob(); // userData.UserId = reader[1].ReadGuidFromBlob();
if (reader[2].SQLiteType != SQLiteType.Null) if (reader[2].SQLiteType != SQLiteType.Null)
{ {

View File

@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.Devices
{ {
IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery
{ {
//UserId = query.UserId // UserId = query.UserId
HasUser = true HasUser = true
}).Items; }).Items;
@ -169,6 +169,7 @@ namespace Emby.Server.Implementations.Devices
{ {
throw new ArgumentException("user not found"); throw new ArgumentException("user not found");
} }
if (string.IsNullOrEmpty(deviceId)) if (string.IsNullOrEmpty(deviceId))
{ {
throw new ArgumentNullException(nameof(deviceId)); throw new ArgumentNullException(nameof(deviceId));

View File

@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.Dto
} }
/// <summary> /// <summary>
/// Converts a BaseItem to a DTOBaseItem /// Converts a BaseItem to a DTOBaseItem.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="fields">The fields.</param> /// <param name="fields">The fields.</param>
@ -277,6 +277,7 @@ namespace Emby.Server.Implementations.Dto
dto.EpisodeTitle = dto.Name; dto.EpisodeTitle = dto.Name;
dto.Name = dto.SeriesName; dto.Name = dto.SeriesName;
} }
liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user); liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user);
} }
@ -292,6 +293,7 @@ namespace Emby.Server.Implementations.Dto
{ {
continue; continue;
} }
var containers = container.Split(new[] { ',' }); var containers = container.Split(new[] { ',' });
if (containers.Length < 2) if (containers.Length < 2)
{ {
@ -406,7 +408,6 @@ namespace Emby.Server.Implementations.Dto
dto.DateLastMediaAdded = folder.DateLastMediaAdded; dto.DateLastMediaAdded = folder.DateLastMediaAdded;
} }
} }
else else
{ {
if (options.EnableUserData) if (options.EnableUserData)
@ -443,7 +444,7 @@ namespace Emby.Server.Implementations.Dto
} }
/// <summary> /// <summary>
/// Gets client-side Id of a server-side BaseItem /// Gets client-side Id of a server-side BaseItem.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
@ -457,6 +458,7 @@ namespace Emby.Server.Implementations.Dto
{ {
dto.SeriesName = item.SeriesName; dto.SeriesName = item.SeriesName;
} }
private static void SetPhotoProperties(BaseItemDto dto, Photo item) private static void SetPhotoProperties(BaseItemDto dto, Photo item)
{ {
dto.CameraMake = item.CameraMake; dto.CameraMake = item.CameraMake;
@ -538,7 +540,7 @@ namespace Emby.Server.Implementations.Dto
} }
/// <summary> /// <summary>
/// Attaches People DTO's to a DTOBaseItem /// Attaches People DTO's to a DTOBaseItem.
/// </summary> /// </summary>
/// <param name="dto">The dto.</param> /// <param name="dto">The dto.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
@ -555,22 +557,27 @@ namespace Emby.Server.Implementations.Dto
{ {
return 0; return 0;
} }
if (i.IsType(PersonType.GuestStar)) if (i.IsType(PersonType.GuestStar))
{ {
return 1; return 1;
} }
if (i.IsType(PersonType.Director)) if (i.IsType(PersonType.Director))
{ {
return 2; return 2;
} }
if (i.IsType(PersonType.Writer)) if (i.IsType(PersonType.Writer))
{ {
return 3; return 3;
} }
if (i.IsType(PersonType.Producer)) if (i.IsType(PersonType.Producer))
{ {
return 4; return 4;
} }
if (i.IsType(PersonType.Composer)) if (i.IsType(PersonType.Composer))
{ {
return 4; return 4;
@ -594,7 +601,6 @@ namespace Emby.Server.Implementations.Dto
_logger.LogError(ex, "Error getting person {Name}", c); _logger.LogError(ex, "Error getting person {Name}", c);
return null; return null;
} }
}).Where(i => i != null) }).Where(i => i != null)
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First()) .Select(x => x.First())
@ -615,6 +621,7 @@ namespace Emby.Server.Implementations.Dto
{ {
baseItemPerson.PrimaryImageTag = GetTagAndFillBlurhash(dto, entity, ImageType.Primary); baseItemPerson.PrimaryImageTag = GetTagAndFillBlurhash(dto, entity, ImageType.Primary);
baseItemPerson.Id = entity.Id.ToString("N", CultureInfo.InvariantCulture); baseItemPerson.Id = entity.Id.ToString("N", CultureInfo.InvariantCulture);
baseItemPerson.ImageBlurHashes = dto.ImageBlurHashes;
list.Add(baseItemPerson); list.Add(baseItemPerson);
} }
} }
@ -727,7 +734,7 @@ namespace Emby.Server.Implementations.Dto
} }
/// <summary> /// <summary>
/// Sets simple property values on a DTOBaseItem /// Sets simple property values on a DTOBaseItem.
/// </summary> /// </summary>
/// <param name="dto">The dto.</param> /// <param name="dto">The dto.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
@ -947,7 +954,7 @@ namespace Emby.Server.Implementations.Dto
dto.AlbumPrimaryImageTag = GetTagAndFillBlurhash(dto, albumParent, ImageType.Primary); dto.AlbumPrimaryImageTag = GetTagAndFillBlurhash(dto, albumParent, ImageType.Primary);
} }
//if (options.ContainsField(ItemFields.MediaSourceCount)) // if (options.ContainsField(ItemFields.MediaSourceCount))
//{ //{
// Songs always have one // Songs always have one
//} //}
@ -957,13 +964,13 @@ namespace Emby.Server.Implementations.Dto
{ {
dto.Artists = hasArtist.Artists; dto.Artists = hasArtist.Artists;
//var artistItems = _libraryManager.GetArtists(new InternalItemsQuery // var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
//{ //{
// EnableTotalRecordCount = false, // EnableTotalRecordCount = false,
// ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) } // ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
//}); //});
//dto.ArtistItems = artistItems.Items // dto.ArtistItems = artistItems.Items
// .Select(i => // .Select(i =>
// { // {
// var artist = i.Item1; // var artist = i.Item1;
@ -976,7 +983,7 @@ namespace Emby.Server.Implementations.Dto
// .ToList(); // .ToList();
// Include artists that are not in the database yet, e.g., just added via metadata editor // Include artists that are not in the database yet, e.g., just added via metadata editor
//var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList(); // var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
dto.ArtistItems = hasArtist.Artists dto.ArtistItems = hasArtist.Artists
//.Except(foundArtists, new DistinctNameComparer()) //.Except(foundArtists, new DistinctNameComparer())
.Select(i => .Select(i =>
@ -1001,7 +1008,6 @@ namespace Emby.Server.Implementations.Dto
} }
return null; return null;
}).Where(i => i != null).ToArray(); }).Where(i => i != null).ToArray();
} }
@ -1010,13 +1016,13 @@ namespace Emby.Server.Implementations.Dto
{ {
dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault(); dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
//var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery // var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
//{ //{
// EnableTotalRecordCount = false, // EnableTotalRecordCount = false,
// ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) } // ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
//}); //});
//dto.AlbumArtists = artistItems.Items // dto.AlbumArtists = artistItems.Items
// .Select(i => // .Select(i =>
// { // {
// var artist = i.Item1; // var artist = i.Item1;
@ -1052,7 +1058,6 @@ namespace Emby.Server.Implementations.Dto
} }
return null; return null;
}).Where(i => i != null).ToArray(); }).Where(i => i != null).ToArray();
} }
@ -1166,7 +1171,7 @@ namespace Emby.Server.Implementations.Dto
// this block will add the series poster for episodes without a poster // this block will add the series poster for episodes without a poster
// TODO maybe remove the if statement entirely // TODO maybe remove the if statement entirely
//if (options.ContainsField(ItemFields.SeriesPrimaryImage)) // if (options.ContainsField(ItemFields.SeriesPrimaryImage))
{ {
episodeSeries = episodeSeries ?? episode.Series; episodeSeries = episodeSeries ?? episode.Series;
if (episodeSeries != null) if (episodeSeries != null)
@ -1212,7 +1217,7 @@ namespace Emby.Server.Implementations.Dto
// this block will add the series poster for seasons without a poster // this block will add the series poster for seasons without a poster
// TODO maybe remove the if statement entirely // TODO maybe remove the if statement entirely
//if (options.ContainsField(ItemFields.SeriesPrimaryImage)) // if (options.ContainsField(ItemFields.SeriesPrimaryImage))
{ {
series = series ?? season.Series; series = series ?? season.Series;
if (series != null) if (series != null)
@ -1350,6 +1355,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentLogoImageTag = GetTagAndFillBlurhash(dto, parent, image); dto.ParentLogoImageTag = GetTagAndFillBlurhash(dto, parent, image);
} }
} }
if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null) if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null)
{ {
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art); var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
@ -1360,6 +1366,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentArtImageTag = GetTagAndFillBlurhash(dto, parent, image); dto.ParentArtImageTag = GetTagAndFillBlurhash(dto, parent, image);
} }
} }
if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView)) if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
{ {
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb); var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
@ -1370,6 +1377,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentThumbImageTag = GetTagAndFillBlurhash(dto, parent, image); dto.ParentThumbImageTag = GetTagAndFillBlurhash(dto, parent, image);
} }
} }
if (backdropLimit > 0 && !((dto.BackdropImageTags != null && dto.BackdropImageTags.Length > 0) || (dto.ParentBackdropImageTags != null && dto.ParentBackdropImageTags.Length > 0))) if (backdropLimit > 0 && !((dto.BackdropImageTags != null && dto.BackdropImageTags.Length > 0) || (dto.ParentBackdropImageTags != null && dto.ParentBackdropImageTags.Length > 0)))
{ {
var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList(); var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList();

View File

@ -23,8 +23,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IPNetwork2" Version="2.4.0.126" /> <PackageReference Include="IPNetwork2" Version="2.5.211" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.4.3" /> <PackageReference Include="Jellyfin.XmlTv" Version="10.6.0-pre1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" /> <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
@ -33,14 +33,14 @@
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" /> <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.5" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.5" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.5" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.5" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" />
<PackageReference Include="Mono.Nat" Version="2.0.1" /> <PackageReference Include="Mono.Nat" Version="2.0.1" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" /> <PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" />
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.0" /> <PackageReference Include="ServiceStack.Text.Core" Version="5.9.0" />
<PackageReference Include="sharpcompress" Version="0.25.0" /> <PackageReference Include="sharpcompress" Version="0.25.1" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" /> <PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.0.9" /> <PackageReference Include="DotNet.Glob" Version="3.0.9" />
</ItemGroup> </ItemGroup>

View File

@ -132,7 +132,6 @@ namespace Emby.Server.Implementations.EntryPoints
} }
catch catch
{ {
} }
} }
} }

View File

@ -159,7 +159,6 @@ namespace Emby.Server.Implementations.EntryPoints
} }
catch (Exception) catch (Exception)
{ {
} }
} }
@ -175,7 +174,6 @@ namespace Emby.Server.Implementations.EntryPoints
} }
catch (Exception) catch (Exception)
{ {
} }
} }

View File

@ -1,3 +1,4 @@
using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Server.Implementations.Udp; using Emby.Server.Implementations.Udp;
@ -43,14 +44,21 @@ namespace Emby.Server.Implementations.EntryPoints
_logger = logger; _logger = logger;
_appHost = appHost; _appHost = appHost;
_config = configuration; _config = configuration;
} }
/// <inheritdoc /> /// <inheritdoc />
public Task RunAsync() public Task RunAsync()
{ {
_udpServer = new UdpServer(_logger, _appHost, _config); try
_udpServer.Start(PortNumber, _cancellationTokenSource.Token); {
_udpServer = new UdpServer(_logger, _appHost, _config);
_udpServer.Start(PortNumber, _cancellationTokenSource.Token);
}
catch (SocketException ex)
{
_logger.LogWarning(ex, "Unable to start AutoDiscovery listener on UDP port {PortNumber}", PortNumber);
}
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@ -140,7 +140,7 @@ namespace Emby.Server.Implementations.HttpClientManager
=> SendAsync(options, HttpMethod.Get); => SendAsync(options, HttpMethod.Get);
/// <summary> /// <summary>
/// Performs a GET request and returns the resulting stream /// Performs a GET request and returns the resulting stream.
/// </summary> /// </summary>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
/// <returns>Task{Stream}.</returns> /// <returns>Task{Stream}.</returns>

View File

@ -32,12 +32,12 @@ namespace Emby.Server.Implementations.HttpServer
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// The _options /// The _options.
/// </summary> /// </summary>
private readonly IDictionary<string, string> _options = new Dictionary<string, string>(); private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
/// <summary> /// <summary>
/// The _requested ranges /// The _requested ranges.
/// </summary> /// </summary>
private List<KeyValuePair<long, long?>> _requestedRanges; private List<KeyValuePair<long, long?>> _requestedRanges;

View File

@ -453,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer
{ {
httpRes.Headers.Add(key, value); httpRes.Headers.Add(key, value);
} }
httpRes.ContentType = "text/plain"; httpRes.ContentType = "text/plain";
await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false); await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false);
return; return;
@ -591,7 +592,7 @@ namespace Emby.Server.Implementations.HttpServer
} }
/// <summary> /// <summary>
/// Get the default CORS headers /// Get the default CORS headers.
/// </summary> /// </summary>
/// <param name="req"></param> /// <param name="req"></param>
/// <returns></returns> /// <returns></returns>

View File

@ -426,7 +426,7 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary> /// </summary>
private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options) private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options)
{ {
bool noCache = (requestContext.Headers[HeaderNames.CacheControl].ToString()).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; bool noCache = requestContext.Headers[HeaderNames.CacheControl].ToString().IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified); AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified);
if (!noCache) if (!noCache)
@ -580,13 +580,12 @@ namespace Emby.Server.Implementations.HttpServer
} }
catch (NotSupportedException) catch (NotSupportedException)
{ {
} }
} }
if (!string.IsNullOrWhiteSpace(rangeHeader) && totalContentLength.HasValue) if (!string.IsNullOrWhiteSpace(rangeHeader) && totalContentLength.HasValue)
{ {
var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest, _logger) var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest)
{ {
OnComplete = options.OnComplete OnComplete = options.OnComplete
}; };
@ -623,8 +622,11 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary> /// <summary>
/// Adds the caching responseHeaders. /// Adds the caching responseHeaders.
/// </summary> /// </summary>
private void AddCachingHeaders(IDictionary<string, string> responseHeaders, TimeSpan? cacheDuration, private void AddCachingHeaders(
bool noCache, DateTime? lastModifiedDate) IDictionary<string, string> responseHeaders,
TimeSpan? cacheDuration,
bool noCache,
DateTime? lastModifiedDate)
{ {
if (noCache) if (noCache)
{ {
@ -693,7 +695,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary> /// <summary>
/// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that.
/// </summary> /// </summary>
/// <param name="date">The date.</param> /// <param name="date">The date.</param>
/// <returns>DateTime.</returns> /// <returns>DateTime.</returns>

View File

@ -1,6 +1,7 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -8,13 +9,45 @@ using System.Net;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer namespace Emby.Server.Implementations.HttpServer
{ {
public class RangeRequestWriter : IAsyncStreamWriter, IHttpResult public class RangeRequestWriter : IAsyncStreamWriter, IHttpResult
{ {
private const int BufferSize = 81920;
private readonly Dictionary<string, string> _options = new Dictionary<string, string>();
private List<KeyValuePair<long, long?>> _requestedRanges;
/// <summary>
/// Initializes a new instance of the <see cref="RangeRequestWriter" /> class.
/// </summary>
/// <param name="rangeHeader">The range header.</param>
/// <param name="contentLength">The content length.</param>
/// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest)
{
if (string.IsNullOrEmpty(contentType))
{
throw new ArgumentNullException(nameof(contentType));
}
RangeHeader = rangeHeader;
SourceStream = source;
IsHeadRequest = isHeadRequest;
ContentType = contentType;
Headers[HeaderNames.ContentType] = contentType;
Headers[HeaderNames.AcceptRanges] = "bytes";
StatusCode = HttpStatusCode.PartialContent;
SetRangeValues(contentLength);
}
/// <summary> /// <summary>
/// Gets or sets the source stream. /// Gets or sets the source stream.
/// </summary> /// </summary>
@ -29,19 +62,6 @@ namespace Emby.Server.Implementations.HttpServer
private long TotalContentLength { get; set; } private long TotalContentLength { get; set; }
public Action OnComplete { get; set; } public Action OnComplete { get; set; }
private readonly ILogger _logger;
private const int BufferSize = 81920;
/// <summary>
/// The _options
/// </summary>
private readonly Dictionary<string, string> _options = new Dictionary<string, string>();
/// <summary>
/// The us culture
/// </summary>
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary> /// <summary>
/// Additional HTTP Headers /// Additional HTTP Headers
@ -50,32 +70,57 @@ namespace Emby.Server.Implementations.HttpServer
public IDictionary<string, string> Headers => _options; public IDictionary<string, string> Headers => _options;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RangeRequestWriter" /> class. /// Gets the requested ranges.
/// </summary> /// </summary>
/// <param name="rangeHeader">The range header.</param> /// <value>The requested ranges.</value>
/// <param name="contentLength">The content length.</param> protected List<KeyValuePair<long, long?>> RequestedRanges
/// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <param name="logger">The logger instance.</param>
public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest, ILogger logger)
{ {
if (string.IsNullOrEmpty(contentType)) get
{ {
throw new ArgumentNullException(nameof(contentType)); if (_requestedRanges == null)
{
_requestedRanges = new List<KeyValuePair<long, long?>>();
// Example: bytes=0-,32-63
var ranges = RangeHeader.Split('=')[1].Split(',');
foreach (var range in ranges)
{
var vals = range.Split('-');
long start = 0;
long? end = null;
if (!string.IsNullOrEmpty(vals[0]))
{
start = long.Parse(vals[0], CultureInfo.InvariantCulture);
}
if (!string.IsNullOrEmpty(vals[1]))
{
end = long.Parse(vals[1], CultureInfo.InvariantCulture);
}
_requestedRanges.Add(new KeyValuePair<long, long?>(start, end));
}
}
return _requestedRanges;
} }
}
RangeHeader = rangeHeader; public string ContentType { get; set; }
SourceStream = source;
IsHeadRequest = isHeadRequest;
this._logger = logger;
ContentType = contentType; public IRequest RequestContext { get; set; }
Headers[HeaderNames.ContentType] = contentType;
Headers[HeaderNames.AcceptRanges] = "bytes";
StatusCode = HttpStatusCode.PartialContent;
SetRangeValues(contentLength); public object Response { get; set; }
public int Status { get; set; }
public HttpStatusCode StatusCode
{
get => (HttpStatusCode)Status;
set => Status = (int)value;
} }
/// <summary> /// <summary>
@ -109,49 +154,6 @@ namespace Emby.Server.Implementations.HttpServer
} }
} }
/// <summary>
/// The _requested ranges
/// </summary>
private List<KeyValuePair<long, long?>> _requestedRanges;
/// <summary>
/// Gets the requested ranges.
/// </summary>
/// <value>The requested ranges.</value>
protected List<KeyValuePair<long, long?>> RequestedRanges
{
get
{
if (_requestedRanges == null)
{
_requestedRanges = new List<KeyValuePair<long, long?>>();
// Example: bytes=0-,32-63
var ranges = RangeHeader.Split('=')[1].Split(',');
foreach (var range in ranges)
{
var vals = range.Split('-');
long start = 0;
long? end = null;
if (!string.IsNullOrEmpty(vals[0]))
{
start = long.Parse(vals[0], UsCulture);
}
if (!string.IsNullOrEmpty(vals[1]))
{
end = long.Parse(vals[1], UsCulture);
}
_requestedRanges.Add(new KeyValuePair<long, long?>(start, end));
}
}
return _requestedRanges;
}
}
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
{ {
try try
@ -167,59 +169,44 @@ namespace Emby.Server.Implementations.HttpServer
// If the requested range is "0-", we can optimize by just doing a stream copy // If the requested range is "0-", we can optimize by just doing a stream copy
if (RangeEnd >= TotalContentLength - 1) if (RangeEnd >= TotalContentLength - 1)
{ {
await source.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); await source.CopyToAsync(responseStream, BufferSize, cancellationToken).ConfigureAwait(false);
} }
else else
{ {
await CopyToInternalAsync(source, responseStream, RangeLength).ConfigureAwait(false); await CopyToInternalAsync(source, responseStream, RangeLength, cancellationToken).ConfigureAwait(false);
} }
} }
} }
finally finally
{ {
if (OnComplete != null) OnComplete?.Invoke();
{
OnComplete();
}
} }
} }
private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength) private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
{ {
var array = new byte[BufferSize]; var array = ArrayPool<byte>.Shared.Rent(BufferSize);
int bytesRead; try
while ((bytesRead = await source.ReadAsync(array, 0, array.Length).ConfigureAwait(false)) != 0)
{ {
if (bytesRead == 0) int bytesRead;
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{ {
break; var bytesToCopy = Math.Min(bytesRead, copyLength);
}
var bytesToCopy = Math.Min(bytesRead, copyLength); await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy), cancellationToken).ConfigureAwait(false);
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy)).ConfigureAwait(false); copyLength -= bytesToCopy;
copyLength -= bytesToCopy; if (copyLength <= 0)
{
if (copyLength <= 0) break;
{ }
break;
} }
} }
} finally
{
public string ContentType { get; set; } ArrayPool<byte>.Shared.Return(array);
}
public IRequest RequestContext { get; set; }
public object Response { get; set; }
public int Status { get; set; }
public HttpStatusCode StatusCode
{
get => (HttpStatusCode)Status;
set => Status = (int)value;
} }
} }
} }

View File

@ -41,11 +41,11 @@ namespace Emby.Server.Implementations.HttpServer
res.Headers.Add(key, value); res.Headers.Add(key, value);
} }
// Try to prevent compatibility view // Try to prevent compatibility view
res.Headers["Access-Control-Allow-Headers"] = ("Accept, Accept-Language, Authorization, Cache-Control, " + res.Headers["Access-Control-Allow-Headers"] = "Accept, Accept-Language, Authorization, Cache-Control, " +
"Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, " + "Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, " +
"Content-Type, Cookie, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, " + "Content-Type, Cookie, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, " +
"Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, " + "Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, " +
"X-Emby-Authorization"); "X-Emby-Authorization";
if (dto is Exception exception) if (dto is Exception exception)
{ {

View File

@ -266,7 +266,6 @@ namespace Emby.Server.Implementations.IO
{ {
DisposeWatcher(newWatcher, false); DisposeWatcher(newWatcher, false);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -393,7 +392,6 @@ namespace Emby.Server.Implementations.IO
} }
return false; return false;
})) }))
{ {
monitorPath = false; monitorPath = false;

View File

@ -237,7 +237,7 @@ namespace Emby.Server.Implementations.IO
{ {
result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory; result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
//if (!result.IsDirectory) // if (!result.IsDirectory)
//{ //{
// result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; // result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
//} //}
@ -245,6 +245,16 @@ namespace Emby.Server.Implementations.IO
if (info is FileInfo fileInfo) if (info is FileInfo fileInfo)
{ {
result.Length = fileInfo.Length; result.Length = fileInfo.Length;
// Issue #2354 get the size of files behind symbolic links
if (fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint))
{
using (Stream thisFileStream = File.OpenRead(fileInfo.FullName))
{
result.Length = thisFileStream.Length;
}
}
result.DirectoryName = fileInfo.DirectoryName; result.DirectoryName = fileInfo.DirectoryName;
} }
@ -628,6 +638,7 @@ namespace Emby.Server.Implementations.IO
{ {
return false; return false;
} }
return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase); return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
}); });
} }
@ -682,6 +693,7 @@ namespace Emby.Server.Implementations.IO
{ {
return false; return false;
} }
return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase); return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
}); });
} }

View File

@ -36,11 +36,6 @@ namespace Emby.Server.Implementations
/// </summary> /// </summary>
string RestartArgs { get; } string RestartArgs { get; }
/// <summary>
/// Gets the value of the --plugin-manifest-url command line option.
/// </summary>
string PluginManifestUrl { get; }
/// <summary> /// <summary>
/// Gets the value of the --published-server-url command line option. /// Gets the value of the --published-server-url command line option.
/// </summary> /// </summary>

View File

@ -71,7 +71,6 @@ namespace Emby.Server.Implementations.Images
new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending)
}, },
IncludeItemTypes = includeItemTypes IncludeItemTypes = includeItemTypes
}); });
} }

View File

@ -78,7 +78,6 @@ namespace Emby.Server.Implementations.Images
} }
return i; return i;
}).GroupBy(x => x.Id) }).GroupBy(x => x.Id)
.Select(x => x.First()); .Select(x => x.First());

View File

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Resolvers;
@ -8,24 +9,33 @@ using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library namespace Emby.Server.Implementations.Library
{ {
/// <summary> /// <summary>
/// Provides the core resolver ignore rules /// Provides the core resolver ignore rules.
/// </summary> /// </summary>
public class CoreResolutionIgnoreRule : IResolverIgnoreRule public class CoreResolutionIgnoreRule : IResolverIgnoreRule
{ {
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IServerApplicationPaths _serverApplicationPaths;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CoreResolutionIgnoreRule"/> class. /// Initializes a new instance of the <see cref="CoreResolutionIgnoreRule"/> class.
/// </summary> /// </summary>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
public CoreResolutionIgnoreRule(ILibraryManager libraryManager) /// <param name="serverApplicationPaths">The server application paths.</param>
public CoreResolutionIgnoreRule(ILibraryManager libraryManager, IServerApplicationPaths serverApplicationPaths)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
_serverApplicationPaths = serverApplicationPaths;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent) public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent)
{ {
// Don't ignore application folders
if (fileInfo.FullName.Contains(_serverApplicationPaths.RootFolderPath, StringComparison.InvariantCulture))
{
return false;
}
// Don't ignore top level folders // Don't ignore top level folders
if (fileInfo.IsDirectory && parent is AggregateFolder) if (fileInfo.IsDirectory && parent is AggregateFolder)
{ {

View File

@ -12,11 +12,13 @@ namespace Emby.Server.Implementations.Library
public class ExclusiveLiveStream : ILiveStream public class ExclusiveLiveStream : ILiveStream
{ {
public int ConsumerCount { get; set; } public int ConsumerCount { get; set; }
public string OriginalStreamId { get; set; } public string OriginalStreamId { get; set; }
public string TunerHostId => null; public string TunerHostId => null;
public bool EnableStreamSharing { get; set; } public bool EnableStreamSharing { get; set; }
public MediaSourceInfo MediaSource { get; set; } public MediaSourceInfo MediaSource { get; set; }
public string UniqueId { get; private set; } public string UniqueId { get; private set; }

View File

@ -1,17 +1,20 @@
#nullable enable
using System;
using System.Linq; using System.Linq;
using DotNet.Globbing; using DotNet.Globbing;
namespace Emby.Server.Implementations.Library namespace Emby.Server.Implementations.Library
{ {
/// <summary> /// <summary>
/// Glob patterns for files to ignore /// Glob patterns for files to ignore.
/// </summary> /// </summary>
public static class IgnorePatterns public static class IgnorePatterns
{ {
/// <summary> /// <summary>
/// Files matching these glob patterns will be ignored /// Files matching these glob patterns will be ignored.
/// </summary> /// </summary>
public static readonly string[] Patterns = new string[] private static readonly string[] _patterns =
{ {
"**/small.jpg", "**/small.jpg",
"**/albumart.jpg", "**/albumart.jpg",
@ -19,32 +22,51 @@ namespace Emby.Server.Implementations.Library
// Directories // Directories
"**/metadata/**", "**/metadata/**",
"**/metadata",
"**/ps3_update/**", "**/ps3_update/**",
"**/ps3_update",
"**/ps3_vprm/**", "**/ps3_vprm/**",
"**/ps3_vprm",
"**/extrafanart/**", "**/extrafanart/**",
"**/extrafanart",
"**/extrathumbs/**", "**/extrathumbs/**",
"**/extrathumbs",
"**/.actors/**", "**/.actors/**",
"**/.actors",
"**/.wd_tv/**", "**/.wd_tv/**",
"**/.wd_tv",
"**/lost+found/**", "**/lost+found/**",
"**/lost+found",
// WMC temp recording directories that will constantly be written to // WMC temp recording directories that will constantly be written to
"**/TempRec/**", "**/TempRec/**",
"**/TempRec",
"**/TempSBE/**", "**/TempSBE/**",
"**/TempSBE",
// Synology // Synology
"**/eaDir/**", "**/eaDir/**",
"**/eaDir",
"**/@eaDir/**", "**/@eaDir/**",
"**/@eaDir",
"**/#recycle/**", "**/#recycle/**",
"**/#recycle",
// Qnap // Qnap
"**/@Recycle/**", "**/@Recycle/**",
"**/@Recycle",
"**/.@__thumb/**", "**/.@__thumb/**",
"**/.@__thumb",
"**/$RECYCLE.BIN/**", "**/$RECYCLE.BIN/**",
"**/$RECYCLE.BIN",
"**/System Volume Information/**", "**/System Volume Information/**",
"**/System Volume Information",
"**/.grab/**", "**/.grab/**",
"**/.grab",
// Unix hidden files and directories // Unix hidden files and directories
"**/.*/**", "**/.*/**",
"**/.*",
// thumbs.db // thumbs.db
"**/thumbs.db", "**/thumbs.db",
@ -56,19 +78,31 @@ namespace Emby.Server.Implementations.Library
private static readonly GlobOptions _globOptions = new GlobOptions private static readonly GlobOptions _globOptions = new GlobOptions
{ {
Evaluation = { Evaluation =
{
CaseInsensitive = true CaseInsensitive = true
} }
}; };
private static readonly Glob[] _globs = Patterns.Select(p => Glob.Parse(p, _globOptions)).ToArray(); private static readonly Glob[] _globs = _patterns.Select(p => Glob.Parse(p, _globOptions)).ToArray();
/// <summary> /// <summary>
/// Returns true if the supplied path should be ignored /// Returns true if the supplied path should be ignored.
/// </summary> /// </summary>
public static bool ShouldIgnore(string path) /// <param name="path">The path to test.</param>
/// <returns>Whether to ignore the path.</returns>
public static bool ShouldIgnore(ReadOnlySpan<char> path)
{ {
return _globs.Any(g => g.IsMatch(path)); int len = _globs.Length;
for (int i = 0; i < len; i++)
{
if (_globs[i].IsMatch(path))
{
return true;
}
}
return false;
} }
} }
} }

View File

@ -97,13 +97,13 @@ namespace Emby.Server.Implementations.Library
private IIntroProvider[] IntroProviders { get; set; } private IIntroProvider[] IntroProviders { get; set; }
/// <summary> /// <summary>
/// Gets or sets the list of entity resolution ignore rules /// Gets or sets the list of entity resolution ignore rules.
/// </summary> /// </summary>
/// <value>The entity resolution ignore rules.</value> /// <value>The entity resolution ignore rules.</value>
private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; }
/// <summary> /// <summary>
/// Gets or sets the list of currently registered entity resolvers /// Gets or sets the list of currently registered entity resolvers.
/// </summary> /// </summary>
/// <value>The entity resolvers enumerable.</value> /// <value>The entity resolvers enumerable.</value>
private IItemResolver[] EntityResolvers { get; set; } private IItemResolver[] EntityResolvers { get; set; }
@ -136,7 +136,7 @@ namespace Emby.Server.Implementations.Library
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LibraryManager" /> class. /// Initializes a new instance of the <see cref="LibraryManager" /> class.
/// </summary> /// </summary>
/// <param name="appHost">The application host</param> /// <param name="appHost">The application host.</param>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
/// <param name="taskManager">The task manager.</param> /// <param name="taskManager">The task manager.</param>
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
@ -209,12 +209,12 @@ namespace Emby.Server.Implementations.Library
} }
/// <summary> /// <summary>
/// The _root folder /// The _root folder.
/// </summary> /// </summary>
private volatile AggregateFolder _rootFolder; private volatile AggregateFolder _rootFolder;
/// <summary> /// <summary>
/// The _root folder sync lock /// The _root folder sync lock.
/// </summary> /// </summary>
private readonly object _rootFolderSyncLock = new object(); private readonly object _rootFolderSyncLock = new object();
@ -341,7 +341,7 @@ namespace Emby.Server.Implementations.Library
if (item is LiveTvProgram) if (item is LiveTvProgram)
{ {
_logger.LogDebug( _logger.LogDebug(
"Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", "Removing item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
item.GetType().Name, item.GetType().Name,
item.Name ?? "Unknown name", item.Name ?? "Unknown name",
item.Path ?? string.Empty, item.Path ?? string.Empty,
@ -350,7 +350,7 @@ namespace Emby.Server.Implementations.Library
else else
{ {
_logger.LogInformation( _logger.LogInformation(
"Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", "Removing item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
item.GetType().Name, item.GetType().Name,
item.Name ?? "Unknown name", item.Name ?? "Unknown name",
item.Path ?? string.Empty, item.Path ?? string.Empty,
@ -368,7 +368,12 @@ namespace Emby.Server.Implementations.Library
continue; continue;
} }
_logger.LogDebug("Deleting path {MetadataPath}", metadataPath); _logger.LogDebug(
"Deleting metadata path, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
item.GetType().Name,
item.Name ?? "Unknown name",
metadataPath,
item.Id);
try try
{ {
@ -392,7 +397,13 @@ namespace Emby.Server.Implementations.Library
{ {
try try
{ {
_logger.LogDebug("Deleting path {path}", fileSystemInfo.FullName); _logger.LogInformation(
"Deleting item path, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
item.GetType().Name,
item.Name ?? "Unknown name",
fileSystemInfo.FullName,
item.Id);
if (fileSystemInfo.IsDirectory) if (fileSystemInfo.IsDirectory)
{ {
Directory.Delete(fileSystemInfo.FullName, true); Directory.Delete(fileSystemInfo.FullName, true);
@ -514,8 +525,8 @@ namespace Emby.Server.Implementations.Library
return key.GetMD5(); return key.GetMD5();
} }
public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, bool allowIgnorePath = true) public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null)
=> ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent, allowIgnorePath: allowIgnorePath); => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent);
private BaseItem ResolvePath( private BaseItem ResolvePath(
FileSystemMetadata fileInfo, FileSystemMetadata fileInfo,
@ -523,8 +534,7 @@ namespace Emby.Server.Implementations.Library
IItemResolver[] resolvers, IItemResolver[] resolvers,
Folder parent = null, Folder parent = null,
string collectionType = null, string collectionType = null,
LibraryOptions libraryOptions = null, LibraryOptions libraryOptions = null)
bool allowIgnorePath = true)
{ {
if (fileInfo == null) if (fileInfo == null)
{ {
@ -548,7 +558,7 @@ namespace Emby.Server.Implementations.Library
}; };
// Return null if ignore rules deem that we should do so // Return null if ignore rules deem that we should do so
if (allowIgnorePath && IgnoreFile(args.FileInfo, args.Parent)) if (IgnoreFile(args.FileInfo, args.Parent))
{ {
return null; return null;
} }
@ -627,7 +637,7 @@ namespace Emby.Server.Implementations.Library
} }
/// <summary> /// <summary>
/// Determines whether a path should be ignored based on its contents - called after the contents have been read /// Determines whether a path should be ignored based on its contents - called after the contents have been read.
/// </summary> /// </summary>
/// <param name="args">The args.</param> /// <param name="args">The args.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
@ -713,7 +723,7 @@ namespace Emby.Server.Implementations.Library
Directory.CreateDirectory(rootFolderPath); Directory.CreateDirectory(rootFolderPath);
var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ??
((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath), allowIgnorePath: false)) ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath)))
.DeepCopy<Folder, AggregateFolder>(); .DeepCopy<Folder, AggregateFolder>();
// In case program data folder was moved // In case program data folder was moved
@ -795,7 +805,7 @@ namespace Emby.Server.Implementations.Library
if (tmpItem == null) if (tmpItem == null)
{ {
_logger.LogDebug("Creating new userRootFolder with DeepCopy"); _logger.LogDebug("Creating new userRootFolder with DeepCopy");
tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath), allowIgnorePath: false)).DeepCopy<Folder, UserRootFolder>(); tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy<Folder, UserRootFolder>();
} }
// In case program data folder was moved // In case program data folder was moved
@ -909,7 +919,7 @@ namespace Emby.Server.Implementations.Library
} }
/// <summary> /// <summary>
/// Gets a Genre /// Gets a Genre.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <returns>Task{Genre}.</returns> /// <returns>Task{Genre}.</returns>
@ -990,7 +1000,7 @@ namespace Emby.Server.Implementations.Library
} }
/// <summary> /// <summary>
/// Reloads the root media folder /// Reloads the root media folder.
/// </summary> /// </summary>
/// <param name="progress">The progress.</param> /// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
@ -1793,7 +1803,7 @@ namespace Emby.Server.Implementations.Library
/// Creates the items. /// Creates the items.
/// </summary> /// </summary>
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
/// <param name="parent">The parent item</param> /// <param name="parent">The parent item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken) public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
{ {
@ -1894,9 +1904,19 @@ namespace Emby.Server.Implementations.Library
} }
} }
ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); try
image.Width = size.Width; {
image.Height = size.Height; ImageDimensions size = _imageProcessor.GetImageDimensions(item, image);
image.Width = size.Width;
image.Height = size.Height;
}
catch (Exception ex)
{
_logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path);
image.Width = 0;
image.Height = 0;
continue;
}
try try
{ {
@ -2595,7 +2615,7 @@ namespace Emby.Server.Implementations.Library
Anime series don't generally have a season in their file name, however, Anime series don't generally have a season in their file name, however,
tvdb needs a season to correctly get the metadata. tvdb needs a season to correctly get the metadata.
Hence, a null season needs to be filled with something. */ Hence, a null season needs to be filled with something. */
//FIXME perhaps this would be better for tvdb parser to ask for season 1 if no season is specified // FIXME perhaps this would be better for tvdb parser to ask for season 1 if no season is specified
episode.ParentIndexNumber = 1; episode.ParentIndexNumber = 1;
} }
@ -2784,10 +2804,12 @@ namespace Emby.Server.Implementations.Library
{ {
throw new ArgumentNullException(nameof(path)); throw new ArgumentNullException(nameof(path));
} }
if (string.IsNullOrWhiteSpace(from)) if (string.IsNullOrWhiteSpace(from))
{ {
throw new ArgumentNullException(nameof(from)); throw new ArgumentNullException(nameof(from));
} }
if (string.IsNullOrWhiteSpace(to)) if (string.IsNullOrWhiteSpace(to))
{ {
throw new ArgumentNullException(nameof(to)); throw new ArgumentNullException(nameof(to));
@ -2861,7 +2883,6 @@ namespace Emby.Server.Implementations.Library
_logger.LogError(ex, "Error getting person"); _logger.LogError(ex, "Error getting person");
return null; return null;
} }
}).Where(i => i != null).ToList(); }).Where(i => i != null).ToList();
} }
@ -2896,7 +2917,8 @@ namespace Emby.Server.Implementations.Library
} }
catch (HttpException ex) catch (HttpException ex)
{ {
if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) if (ex.StatusCode.HasValue
&& (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden))
{ {
continue; continue;
} }
@ -2989,21 +3011,6 @@ namespace Emby.Server.Implementations.Library
}); });
} }
private static bool ValidateNetworkPath(string path)
{
//if (Environment.OSVersion.Platform == PlatformID.Win32NT)
//{
// // We can't validate protocol-based paths, so just allow them
// if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
// {
// return Directory.Exists(path);
// }
//}
// Without native support for unc, we cannot validate this when running under mono
return true;
}
private const string ShortcutFileExtension = ".mblink"; private const string ShortcutFileExtension = ".mblink";
public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo) public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
@ -3030,11 +3037,6 @@ namespace Emby.Server.Implementations.Library
throw new FileNotFoundException("The path does not exist."); throw new FileNotFoundException("The path does not exist.");
} }
if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
{
throw new FileNotFoundException("The network path does not exist.");
}
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
@ -3073,11 +3075,6 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(pathInfo)); throw new ArgumentNullException(nameof(pathInfo));
} }
if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
{
throw new FileNotFoundException("The network path does not exist.");
}
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);

View File

@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.Library
{ {
mediaInfo = _json.DeserializeFromFile<MediaInfo>(cacheFilePath); mediaInfo = _json.DeserializeFromFile<MediaInfo>(cacheFilePath);
//_logger.LogDebug("Found cached media info"); // _logger.LogDebug("Found cached media info");
} }
catch catch
{ {
@ -85,7 +85,7 @@ namespace Emby.Server.Implementations.Library
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
_json.SerializeToFile(mediaInfo, cacheFilePath); _json.SerializeToFile(mediaInfo, cacheFilePath);
//_logger.LogDebug("Saved media info to {0}", cacheFilePath); // _logger.LogDebug("Saved media info to {0}", cacheFilePath);
} }
} }
@ -148,17 +148,14 @@ namespace Emby.Server.Implementations.Library
{ {
videoStream.BitRate = 30000000; videoStream.BitRate = 30000000;
} }
else if (width >= 1900) else if (width >= 1900)
{ {
videoStream.BitRate = 20000000; videoStream.BitRate = 20000000;
} }
else if (width >= 1200) else if (width >= 1200)
{ {
videoStream.BitRate = 8000000; videoStream.BitRate = 8000000;
} }
else if (width >= 700) else if (width >= 700)
{ {
videoStream.BitRate = 2000000; videoStream.BitRate = 2000000;

View File

@ -205,22 +205,27 @@ namespace Emby.Server.Implementations.Library
{ {
return MediaProtocol.Rtsp; return MediaProtocol.Rtsp;
} }
if (path.StartsWith("Rtmp", StringComparison.OrdinalIgnoreCase)) if (path.StartsWith("Rtmp", StringComparison.OrdinalIgnoreCase))
{ {
return MediaProtocol.Rtmp; return MediaProtocol.Rtmp;
} }
if (path.StartsWith("Http", StringComparison.OrdinalIgnoreCase)) if (path.StartsWith("Http", StringComparison.OrdinalIgnoreCase))
{ {
return MediaProtocol.Http; return MediaProtocol.Http;
} }
if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase)) if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase))
{ {
return MediaProtocol.Rtp; return MediaProtocol.Rtp;
} }
if (path.StartsWith("ftp", StringComparison.OrdinalIgnoreCase)) if (path.StartsWith("ftp", StringComparison.OrdinalIgnoreCase))
{ {
return MediaProtocol.Ftp; return MediaProtocol.Ftp;
} }
if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase)) if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
{ {
return MediaProtocol.Udp; return MediaProtocol.Udp;
@ -436,7 +441,6 @@ namespace Emby.Server.Implementations.Library
} }
return 1; return 1;
}).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0) }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
.ThenByDescending(i => .ThenByDescending(i =>
{ {
@ -620,7 +624,6 @@ namespace Emby.Server.Implementations.Library
MediaSource = mediaSource, MediaSource = mediaSource,
ExtractChapters = false, ExtractChapters = false,
MediaType = DlnaProfileType.Video MediaType = DlnaProfileType.Video
}, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);
mediaSource.MediaStreams = info.MediaStreams; mediaSource.MediaStreams = info.MediaStreams;
@ -646,7 +649,7 @@ namespace Emby.Server.Implementations.Library
{ {
mediaInfo = _jsonSerializer.DeserializeFromFile<MediaInfo>(cacheFilePath); mediaInfo = _jsonSerializer.DeserializeFromFile<MediaInfo>(cacheFilePath);
//_logger.LogDebug("Found cached media info"); // _logger.LogDebug("Found cached media info");
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -682,7 +685,7 @@ namespace Emby.Server.Implementations.Library
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
_jsonSerializer.SerializeToFile(mediaInfo, cacheFilePath); _jsonSerializer.SerializeToFile(mediaInfo, cacheFilePath);
//_logger.LogDebug("Saved media info to {0}", cacheFilePath); // _logger.LogDebug("Saved media info to {0}", cacheFilePath);
} }
} }
@ -748,17 +751,14 @@ namespace Emby.Server.Implementations.Library
{ {
videoStream.BitRate = 30000000; videoStream.BitRate = 30000000;
} }
else if (width >= 1900) else if (width >= 1900)
{ {
videoStream.BitRate = 20000000; videoStream.BitRate = 20000000;
} }
else if (width >= 1200) else if (width >= 1200)
{ {
videoStream.BitRate = 8000000; videoStream.BitRate = 8000000;
} }
else if (width >= 700) else if (width >= 700)
{ {
videoStream.BitRate = 2000000; videoStream.BitRate = 2000000;

View File

@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Library
} }
/// <summary> /// <summary>
/// Ensures DateCreated and DateModified have values /// Ensures DateCreated and DateModified have values.
/// </summary> /// </summary>
/// <param name="fileSystem">The file system.</param> /// <param name="fileSystem">The file system.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>

View File

@ -209,8 +209,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
Name = parseName ? Name = parseName ?
resolvedItem.Name : resolvedItem.Name :
Path.GetFileNameWithoutExtension(firstMedia.Path), Path.GetFileNameWithoutExtension(firstMedia.Path),
//AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(), // AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(),
//LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray() // LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray()
}; };
result.Items.Add(libraryItem); result.Items.Add(libraryItem);

View File

@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
// Args points to an album if parent is an Artist folder or it directly contains music // Args points to an album if parent is an Artist folder or it directly contains music
if (args.IsDirectory) if (args.IsDirectory)
{ {
// if (args.Parent is MusicArtist) return true; //saves us from testing children twice // if (args.Parent is MusicArtist) return true; // saves us from testing children twice
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, _libraryManager)) if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, _libraryManager))
{ {
return true; return true;

View File

@ -292,7 +292,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
} }
return true; return true;
//var blurayExtensions = new[] // var blurayExtensions = new[]
//{ //{
// ".mts", // ".mts",
// ".m2ts", // ".m2ts",
@ -300,7 +300,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
// ".mpls" // ".mpls"
//}; //};
//return directoryService.GetFiles(fullPath).Any(i => blurayExtensions.Contains(i.Extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)); // return directoryService.GetFiles(fullPath).Any(i => blurayExtensions.Contains(i.Extension ?? string.Empty, StringComparer.OrdinalIgnoreCase));
} }
} }
} }

View File

@ -19,7 +19,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
// Only process items that are in a collection folder containing books // Only process items that are in a collection folder containing books
if (!string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase)) if (!string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
{
return null; return null;
}
if (args.IsDirectory) if (args.IsDirectory)
{ {
@ -55,7 +57,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
// Don't return a Book if there is more (or less) than one document in the directory // Don't return a Book if there is more (or less) than one document in the directory
if (bookFiles.Count != 1) if (bookFiles.Count != 1)
{
return null; return null;
}
return new Book return new Book
{ {

View File

@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
public virtual ResolverPriority Priority => ResolverPriority.First; public virtual ResolverPriority Priority => ResolverPriority.First;
/// <summary> /// <summary>
/// Sets initial values on the newly resolved item /// Sets initial values on the newly resolved item.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="args">The args.</param> /// <param name="args">The args.</param>

View File

@ -41,10 +41,12 @@ namespace Emby.Server.Implementations.Library.Resolvers
{ {
return new AggregateFolder(); return new AggregateFolder();
} }
if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase)) if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase))
{ {
return new UserRootFolder(); //if we got here and still a root - must be user root return new UserRootFolder(); // if we got here and still a root - must be user root
} }
if (args.IsVf) if (args.IsVf)
{ {
return new CollectionFolder return new CollectionFolder
@ -73,7 +75,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
{ {
return false; return false;
} }
}) })
.Select(i => _fileSystem.GetFileNameWithoutExtension(i)) .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
.FirstOrDefault(); .FirstOrDefault();

View File

@ -55,6 +55,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
episode.SeriesId = series.Id; episode.SeriesId = series.Id;
episode.SeriesName = series.Name; episode.SeriesName = series.Name;
} }
if (season != null) if (season != null)
{ {
episode.SeasonId = season.Id; episode.SeasonId = season.Id;

View File

@ -23,8 +23,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// </summary> /// </summary>
/// <param name="config">The config.</param> /// <param name="config">The config.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="localization">The localization</param> /// <param name="localization">The localization.</param>
/// <param name="logger">The logger</param> /// <param name="logger">The logger.</param>
public SeasonResolver( public SeasonResolver(
IServerConfigurationManager config, IServerConfigurationManager config,
ILibraryManager libraryManager, ILibraryManager libraryManager,
@ -94,7 +94,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
_localization.GetLocalizedString("NameSeasonNumber"), _localization.GetLocalizedString("NameSeasonNumber"),
seasonNumber, seasonNumber,
args.GetLibraryOptions().PreferredMetadataLanguage); args.GetLibraryOptions().PreferredMetadataLanguage);
} }
return season; return season;

View File

@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
var collectionType = args.GetCollectionType(); var collectionType = args.GetCollectionType();
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{ {
//if (args.ContainsFileSystemEntryByName("tvshow.nfo")) // if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
//{ //{
// return new Series // return new Series
// { // {

View File

@ -194,6 +194,7 @@ namespace Emby.Server.Implementations.Library
{ {
searchQuery.AncestorIds = new[] { searchQuery.ParentId }; searchQuery.AncestorIds = new[] { searchQuery.ParentId };
} }
searchQuery.ParentId = Guid.Empty; searchQuery.ParentId = Guid.Empty;
searchQuery.IncludeItemsByName = true; searchQuery.IncludeItemsByName = true;
searchQuery.IncludeItemTypes = Array.Empty<string>(); searchQuery.IncludeItemTypes = Array.Empty<string>();
@ -207,7 +208,6 @@ namespace Emby.Server.Implementations.Library
return mediaItems.Select(i => new SearchHintInfo return mediaItems.Select(i => new SearchHintInfo
{ {
Item = i Item = i
}).ToList(); }).ToList();
} }
} }

View File

@ -103,7 +103,7 @@ namespace Emby.Server.Implementations.Library
} }
/// <summary> /// <summary>
/// Retrieve all user data for the given user /// Retrieve all user data for the given user.
/// </summary> /// </summary>
/// <param name="userId"></param> /// <param name="userId"></param>
/// <returns></returns> /// <returns></returns>
@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.Library
} }
/// <summary> /// <summary>
/// Converts a UserItemData to a DTOUserItemData /// Converts a UserItemData to a DTOUserItemData.
/// </summary> /// </summary>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
/// <returns>DtoUserItemData.</returns> /// <returns>DtoUserItemData.</returns>

View File

@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Library.Validators
_libraryManager.DeleteItem(item, new DeleteOptions _libraryManager.DeleteItem(item, new DeleteOptions
{ {
DeleteFileLocation = false DeleteFileLocation = false
}, false); }, false);
} }

View File

@ -92,7 +92,6 @@ namespace Emby.Server.Implementations.Library.Validators
_libraryManager.DeleteItem(item, new DeleteOptions _libraryManager.DeleteItem(item, new DeleteOptions
{ {
DeleteFileLocation = false DeleteFileLocation = false
}, false); }, false);
} }

View File

@ -1547,7 +1547,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
IsFolder = false, IsFolder = false,
Recursive = true, Recursive = true,
DtoOptions = new DtoOptions(true) DtoOptions = new DtoOptions(true)
}) })
.Where(i => i.IsFileProtocol && File.Exists(i.Path)) .Where(i => i.IsFileProtocol && File.Exists(i.Path))
.Skip(seriesTimer.KeepUpTo - 1) .Skip(seriesTimer.KeepUpTo - 1)

View File

@ -183,7 +183,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn"; var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn";
//var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ? // var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ?
// " -f mp4 -movflags frag_keyframe+empty_moov" : // " -f mp4 -movflags frag_keyframe+empty_moov" :
// string.Empty; // string.Empty;
@ -206,13 +206,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
return "-codec:a:0 copy"; return "-codec:a:0 copy";
//var audioChannels = 2; // var audioChannels = 2;
//var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); // var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
//if (audioStream != null) // if (audioStream != null)
//{ //{
// audioChannels = audioStream.Channels ?? audioChannels; // audioChannels = audioStream.Channels ?? audioChannels;
//} //}
//return "-codec:a:0 aac -strict experimental -ab 320000"; // return "-codec:a:0 aac -strict experimental -ab 320000";
} }
private static bool EncodeVideo(MediaSourceInfo mediaSource) private static bool EncodeVideo(MediaSourceInfo mediaSource)

View File

@ -56,7 +56,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
name += " " + info.EpisodeTitle; name += " " + info.EpisodeTitle;
} }
} }
else if (info.IsMovie && info.ProductionYear != null) else if (info.IsMovie && info.ProductionYear != null)
{ {
name += " (" + info.ProductionYear + ")"; name += " (" + info.ProductionYear + ")";

View File

@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var programsInfo = new List<ProgramInfo>(); var programsInfo = new List<ProgramInfo>();
foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs)) foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
{ {
//_logger.LogDebug("Proccesing Schedule for statio ID " + stationID + // _logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
// " which corresponds to channel " + channelNumber + " and program id " + // " which corresponds to channel " + channelNumber + " and program id " +
// schedule.programID + " which says it has images? " + // schedule.programID + " which says it has images? " +
// programDict[schedule.programID].hasImageArtwork); // programDict[schedule.programID].hasImageArtwork);
@ -178,7 +178,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect); programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
//programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ?? // programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ?? // GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
// GetProgramImage(ApiUrl, data, "Banner-LO", false) ?? // GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
// GetProgramImage(ApiUrl, data, "Banner-LOT", false); // GetProgramImage(ApiUrl, data, "Banner-LOT", false);
@ -212,6 +212,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
channelNumber = map.channel; channelNumber = map.channel;
} }
if (string.IsNullOrWhiteSpace(channelNumber)) if (string.IsNullOrWhiteSpace(channelNumber))
{ {
channelNumber = map.atscMajor + "." + map.atscMinor; channelNumber = map.atscMajor + "." + map.atscMinor;
@ -276,7 +277,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
CommunityRating = null, CommunityRating = null,
EpisodeTitle = episodeTitle, EpisodeTitle = episodeTitle,
Audio = audioType, Audio = audioType,
//IsNew = programInfo.@new ?? false, // IsNew = programInfo.@new ?? false,
IsRepeat = programInfo.@new == null, IsRepeat = programInfo.@new == null,
IsSeries = string.Equals(details.entityType, "episode", StringComparison.OrdinalIgnoreCase), IsSeries = string.Equals(details.entityType, "episode", StringComparison.OrdinalIgnoreCase),
ImageUrl = details.primaryImage, ImageUrl = details.primaryImage,
@ -400,6 +401,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
date = DateTime.SpecifyKind(date, DateTimeKind.Utc); date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
} }
return date; return date;
} }
@ -622,6 +624,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_lastErrorResponse = DateTime.UtcNow; _lastErrorResponse = DateTime.UtcNow;
} }
} }
throw; throw;
} }
finally finally
@ -701,7 +704,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
LogErrorResponseBody = true LogErrorResponseBody = true
}; };
//_logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " + // _logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent); // httpOptions.RequestContent);
using (var response = await Post(httpOptions, false, null).ConfigureAwait(false)) using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
@ -805,11 +808,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
throw new ArgumentException("Username is required"); throw new ArgumentException("Username is required");
} }
if (string.IsNullOrEmpty(info.Password)) if (string.IsNullOrEmpty(info.Password))
{ {
throw new ArgumentException("Password is required"); throw new ArgumentException("Password is required");
} }
} }
if (validateListings) if (validateListings)
{ {
if (string.IsNullOrEmpty(info.ListingsId)) if (string.IsNullOrEmpty(info.ListingsId))
@ -932,24 +937,35 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Token public class Token
{ {
public int code { get; set; } public int code { get; set; }
public string message { get; set; } public string message { get; set; }
public string serverID { get; set; } public string serverID { get; set; }
public string token { get; set; } public string token { get; set; }
} }
public class Lineup public class Lineup
{ {
public string lineup { get; set; } public string lineup { get; set; }
public string name { get; set; } public string name { get; set; }
public string transport { get; set; } public string transport { get; set; }
public string location { get; set; } public string location { get; set; }
public string uri { get; set; } public string uri { get; set; }
} }
public class Lineups public class Lineups
{ {
public int code { get; set; } public int code { get; set; }
public string serverID { get; set; } public string serverID { get; set; }
public string datetime { get; set; } public string datetime { get; set; }
public List<Lineup> lineups { get; set; } public List<Lineup> lineups { get; set; }
} }
@ -957,8 +973,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Headends public class Headends
{ {
public string headend { get; set; } public string headend { get; set; }
public string transport { get; set; } public string transport { get; set; }
public string location { get; set; } public string location { get; set; }
public List<Lineup> lineups { get; set; } public List<Lineup> lineups { get; set; }
} }
@ -967,59 +986,83 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Map public class Map
{ {
public string stationID { get; set; } public string stationID { get; set; }
public string channel { get; set; } public string channel { get; set; }
public string logicalChannelNumber { get; set; } public string logicalChannelNumber { get; set; }
public int uhfVhf { get; set; } public int uhfVhf { get; set; }
public int atscMajor { get; set; } public int atscMajor { get; set; }
public int atscMinor { get; set; } public int atscMinor { get; set; }
} }
public class Broadcaster public class Broadcaster
{ {
public string city { get; set; } public string city { get; set; }
public string state { get; set; } public string state { get; set; }
public string postalcode { get; set; } public string postalcode { get; set; }
public string country { get; set; } public string country { get; set; }
} }
public class Logo public class Logo
{ {
public string URL { get; set; } public string URL { get; set; }
public int height { get; set; } public int height { get; set; }
public int width { get; set; } public int width { get; set; }
public string md5 { get; set; } public string md5 { get; set; }
} }
public class Station public class Station
{ {
public string stationID { get; set; } public string stationID { get; set; }
public string name { get; set; } public string name { get; set; }
public string callsign { get; set; } public string callsign { get; set; }
public List<string> broadcastLanguage { get; set; } public List<string> broadcastLanguage { get; set; }
public List<string> descriptionLanguage { get; set; } public List<string> descriptionLanguage { get; set; }
public Broadcaster broadcaster { get; set; } public Broadcaster broadcaster { get; set; }
public string affiliate { get; set; } public string affiliate { get; set; }
public Logo logo { get; set; } public Logo logo { get; set; }
public bool? isCommercialFree { get; set; } public bool? isCommercialFree { get; set; }
} }
public class Metadata public class Metadata
{ {
public string lineup { get; set; } public string lineup { get; set; }
public string modified { get; set; } public string modified { get; set; }
public string transport { get; set; } public string transport { get; set; }
} }
public class Channel public class Channel
{ {
public List<Map> map { get; set; } public List<Map> map { get; set; }
public List<Station> stations { get; set; } public List<Station> stations { get; set; }
public Metadata metadata { get; set; } public Metadata metadata { get; set; }
} }
public class RequestScheduleForChannel public class RequestScheduleForChannel
{ {
public string stationID { get; set; } public string stationID { get; set; }
public List<string> date { get; set; } public List<string> date { get; set; }
} }
@ -1029,29 +1072,43 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Rating public class Rating
{ {
public string body { get; set; } public string body { get; set; }
public string code { get; set; } public string code { get; set; }
} }
public class Multipart public class Multipart
{ {
public int partNumber { get; set; } public int partNumber { get; set; }
public int totalParts { get; set; } public int totalParts { get; set; }
} }
public class Program public class Program
{ {
public string programID { get; set; } public string programID { get; set; }
public string airDateTime { get; set; } public string airDateTime { get; set; }
public int duration { get; set; } public int duration { get; set; }
public string md5 { get; set; } public string md5 { get; set; }
public List<string> audioProperties { get; set; } public List<string> audioProperties { get; set; }
public List<string> videoProperties { get; set; } public List<string> videoProperties { get; set; }
public List<Rating> ratings { get; set; } public List<Rating> ratings { get; set; }
public bool? @new { get; set; } public bool? @new { get; set; }
public Multipart multipart { get; set; } public Multipart multipart { get; set; }
public string liveTapeDelay { get; set; } public string liveTapeDelay { get; set; }
public bool premiere { get; set; } public bool premiere { get; set; }
public bool repeat { get; set; } public bool repeat { get; set; }
public string isPremiereOrFinale { get; set; } public string isPremiereOrFinale { get; set; }
} }
@ -1060,16 +1117,22 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class MetadataSchedule public class MetadataSchedule
{ {
public string modified { get; set; } public string modified { get; set; }
public string md5 { get; set; } public string md5 { get; set; }
public string startDate { get; set; } public string startDate { get; set; }
public string endDate { get; set; } public string endDate { get; set; }
public int days { get; set; } public int days { get; set; }
} }
public class Day public class Day
{ {
public string stationID { get; set; } public string stationID { get; set; }
public List<Program> programs { get; set; } public List<Program> programs { get; set; }
public MetadataSchedule metadata { get; set; } public MetadataSchedule metadata { get; set; }
public Day() public Day()
@ -1092,24 +1155,28 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Description100 public class Description100
{ {
public string descriptionLanguage { get; set; } public string descriptionLanguage { get; set; }
public string description { get; set; } public string description { get; set; }
} }
public class Description1000 public class Description1000
{ {
public string descriptionLanguage { get; set; } public string descriptionLanguage { get; set; }
public string description { get; set; } public string description { get; set; }
} }
public class DescriptionsProgram public class DescriptionsProgram
{ {
public List<Description100> description100 { get; set; } public List<Description100> description100 { get; set; }
public List<Description1000> description1000 { get; set; } public List<Description1000> description1000 { get; set; }
} }
public class Gracenote public class Gracenote
{ {
public int season { get; set; } public int season { get; set; }
public int episode { get; set; } public int episode { get; set; }
} }
@ -1121,104 +1188,154 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class ContentRating public class ContentRating
{ {
public string body { get; set; } public string body { get; set; }
public string code { get; set; } public string code { get; set; }
} }
public class Cast public class Cast
{ {
public string billingOrder { get; set; } public string billingOrder { get; set; }
public string role { get; set; } public string role { get; set; }
public string nameId { get; set; } public string nameId { get; set; }
public string personId { get; set; } public string personId { get; set; }
public string name { get; set; } public string name { get; set; }
public string characterName { get; set; } public string characterName { get; set; }
} }
public class Crew public class Crew
{ {
public string billingOrder { get; set; } public string billingOrder { get; set; }
public string role { get; set; } public string role { get; set; }
public string nameId { get; set; } public string nameId { get; set; }
public string personId { get; set; } public string personId { get; set; }
public string name { get; set; } public string name { get; set; }
} }
public class QualityRating public class QualityRating
{ {
public string ratingsBody { get; set; } public string ratingsBody { get; set; }
public string rating { get; set; } public string rating { get; set; }
public string minRating { get; set; } public string minRating { get; set; }
public string maxRating { get; set; } public string maxRating { get; set; }
public string increment { get; set; } public string increment { get; set; }
} }
public class Movie public class Movie
{ {
public string year { get; set; } public string year { get; set; }
public int duration { get; set; } public int duration { get; set; }
public List<QualityRating> qualityRating { get; set; } public List<QualityRating> qualityRating { get; set; }
} }
public class Recommendation public class Recommendation
{ {
public string programID { get; set; } public string programID { get; set; }
public string title120 { get; set; } public string title120 { get; set; }
} }
public class ProgramDetails public class ProgramDetails
{ {
public string audience { get; set; } public string audience { get; set; }
public string programID { get; set; } public string programID { get; set; }
public List<Title> titles { get; set; } public List<Title> titles { get; set; }
public EventDetails eventDetails { get; set; } public EventDetails eventDetails { get; set; }
public DescriptionsProgram descriptions { get; set; } public DescriptionsProgram descriptions { get; set; }
public string originalAirDate { get; set; } public string originalAirDate { get; set; }
public List<string> genres { get; set; } public List<string> genres { get; set; }
public string episodeTitle150 { get; set; } public string episodeTitle150 { get; set; }
public List<MetadataPrograms> metadata { get; set; } public List<MetadataPrograms> metadata { get; set; }
public List<ContentRating> contentRating { get; set; } public List<ContentRating> contentRating { get; set; }
public List<Cast> cast { get; set; } public List<Cast> cast { get; set; }
public List<Crew> crew { get; set; } public List<Crew> crew { get; set; }
public string entityType { get; set; } public string entityType { get; set; }
public string showType { get; set; } public string showType { get; set; }
public bool hasImageArtwork { get; set; } public bool hasImageArtwork { get; set; }
public string primaryImage { get; set; } public string primaryImage { get; set; }
public string thumbImage { get; set; } public string thumbImage { get; set; }
public string backdropImage { get; set; } public string backdropImage { get; set; }
public string bannerImage { get; set; } public string bannerImage { get; set; }
public string imageID { get; set; } public string imageID { get; set; }
public string md5 { get; set; } public string md5 { get; set; }
public List<string> contentAdvisory { get; set; } public List<string> contentAdvisory { get; set; }
public Movie movie { get; set; } public Movie movie { get; set; }
public List<Recommendation> recommendations { get; set; } public List<Recommendation> recommendations { get; set; }
} }
public class Caption public class Caption
{ {
public string content { get; set; } public string content { get; set; }
public string lang { get; set; } public string lang { get; set; }
} }
public class ImageData public class ImageData
{ {
public string width { get; set; } public string width { get; set; }
public string height { get; set; } public string height { get; set; }
public string uri { get; set; } public string uri { get; set; }
public string size { get; set; } public string size { get; set; }
public string aspect { get; set; } public string aspect { get; set; }
public string category { get; set; } public string category { get; set; }
public string text { get; set; } public string text { get; set; }
public string primary { get; set; } public string primary { get; set; }
public string tier { get; set; } public string tier { get; set; }
public Caption caption { get; set; } public Caption caption { get; set; }
} }
public class ShowImages public class ShowImages
{ {
public string programID { get; set; } public string programID { get; set; }
public List<ImageData> data { get; set; } public List<ImageData> data { get; set; }
} }
} }
} }
} }

View File

@ -224,6 +224,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
uniqueString = "-" + programInfo.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture); uniqueString = "-" + programInfo.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture);
} }
if (programInfo.EpisodeNumber.HasValue) if (programInfo.EpisodeNumber.HasValue)
{ {
uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture); uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture);

View File

@ -406,8 +406,8 @@ namespace Emby.Server.Implementations.LiveTv
if (!(service is EmbyTV.EmbyTV)) if (!(service is EmbyTV.EmbyTV))
{ {
// We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says // We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says
//mediaSource.SupportsDirectPlay = false; // mediaSource.SupportsDirectPlay = false;
//mediaSource.SupportsDirectStream = false; // mediaSource.SupportsDirectStream = false;
mediaSource.SupportsTranscoding = true; mediaSource.SupportsTranscoding = true;
foreach (var stream in mediaSource.MediaStreams) foreach (var stream in mediaSource.MediaStreams)
{ {
@ -556,9 +556,10 @@ namespace Emby.Server.Implementations.LiveTv
{ {
forceUpdate = true; forceUpdate = true;
} }
item.ParentId = channel.Id; item.ParentId = channel.Id;
//item.ChannelType = channelType; // item.ChannelType = channelType;
item.Audio = info.Audio; item.Audio = info.Audio;
item.ChannelId = channel.Id; item.ChannelId = channel.Id;
@ -575,6 +576,7 @@ namespace Emby.Server.Implementations.LiveTv
{ {
forceUpdate = true; forceUpdate = true;
} }
item.ExternalSeriesId = seriesId; item.ExternalSeriesId = seriesId;
var isSeries = info.IsSeries || !string.IsNullOrEmpty(info.EpisodeTitle); var isSeries = info.IsSeries || !string.IsNullOrEmpty(info.EpisodeTitle);
@ -589,30 +591,37 @@ namespace Emby.Server.Implementations.LiveTv
{ {
tags.Add("Live"); tags.Add("Live");
} }
if (info.IsPremiere) if (info.IsPremiere)
{ {
tags.Add("Premiere"); tags.Add("Premiere");
} }
if (info.IsNews) if (info.IsNews)
{ {
tags.Add("News"); tags.Add("News");
} }
if (info.IsSports) if (info.IsSports)
{ {
tags.Add("Sports"); tags.Add("Sports");
} }
if (info.IsKids) if (info.IsKids)
{ {
tags.Add("Kids"); tags.Add("Kids");
} }
if (info.IsRepeat) if (info.IsRepeat)
{ {
tags.Add("Repeat"); tags.Add("Repeat");
} }
if (info.IsMovie) if (info.IsMovie)
{ {
tags.Add("Movie"); tags.Add("Movie");
} }
if (isSeries) if (isSeries)
{ {
tags.Add("Series"); tags.Add("Series");
@ -635,6 +644,7 @@ namespace Emby.Server.Implementations.LiveTv
{ {
forceUpdate = true; forceUpdate = true;
} }
item.IsSeries = isSeries; item.IsSeries = isSeries;
item.Name = info.Name; item.Name = info.Name;
@ -652,12 +662,14 @@ namespace Emby.Server.Implementations.LiveTv
{ {
forceUpdate = true; forceUpdate = true;
} }
item.StartDate = info.StartDate; item.StartDate = info.StartDate;
if (item.EndDate != info.EndDate) if (item.EndDate != info.EndDate)
{ {
forceUpdate = true; forceUpdate = true;
} }
item.EndDate = info.EndDate; item.EndDate = info.EndDate;
item.ProductionYear = info.ProductionYear; item.ProductionYear = info.ProductionYear;
@ -1168,7 +1180,6 @@ namespace Emby.Server.Implementations.LiveTv
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name }, IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
ChannelIds = new Guid[] { currentChannel.Id }, ChannelIds = new Guid[] { currentChannel.Id },
DtoOptions = new DtoOptions(true) DtoOptions = new DtoOptions(true)
}).Cast<LiveTvProgram>().ToDictionary(i => i.Id); }).Cast<LiveTvProgram>().ToDictionary(i => i.Id);
var newPrograms = new List<LiveTvProgram>(); var newPrograms = new List<LiveTvProgram>();
@ -1368,10 +1379,10 @@ namespace Emby.Server.Implementations.LiveTv
// limit = (query.Limit ?? 10) * 2; // limit = (query.Limit ?? 10) * 2;
limit = null; limit = null;
//var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray(); // var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
//var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray(); // var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
//return new QueryResult<BaseItem> // return new QueryResult<BaseItem>
//{ //{
// Items = items, // Items = items,
// TotalRecordCount = items.Length // TotalRecordCount = items.Length
@ -1738,7 +1749,6 @@ namespace Emby.Server.Implementations.LiveTv
var results = await GetTimers(new TimerQuery var results = await GetTimers(new TimerQuery
{ {
Id = id Id = id
}, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);
return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)); return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
@ -1790,7 +1800,6 @@ namespace Emby.Server.Implementations.LiveTv
.Select(i => .Select(i =>
{ {
return i.Item1; return i.Item1;
}) })
.ToArray(); .ToArray();
@ -1845,7 +1854,6 @@ namespace Emby.Server.Implementations.LiveTv
} }
return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName); return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName);
}) })
.ToArray(); .ToArray();
@ -1878,7 +1886,6 @@ namespace Emby.Server.Implementations.LiveTv
OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) }, OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) },
TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id }, TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id },
DtoOptions = options DtoOptions = options
}) : new List<BaseItem>(); }) : new List<BaseItem>();
RemoveFields(options); RemoveFields(options);
@ -1956,7 +1963,7 @@ namespace Emby.Server.Implementations.LiveTv
OriginalAirDate = program.PremiereDate, OriginalAirDate = program.PremiereDate,
Overview = program.Overview, Overview = program.Overview,
StartDate = program.StartDate, StartDate = program.StartDate,
//ImagePath = program.ExternalImagePath, // ImagePath = program.ExternalImagePath,
Name = program.Name, Name = program.Name,
OfficialRating = program.OfficialRating OfficialRating = program.OfficialRating
}; };
@ -2456,7 +2463,6 @@ namespace Emby.Server.Implementations.LiveTv
UserId = user.Id, UserId = user.Id,
IsRecordingsFolder = true, IsRecordingsFolder = true,
RefreshLatestChannelItems = refreshChannels RefreshLatestChannelItems = refreshChannels
}).Items); }).Items);
return folders.Cast<BaseItem>().ToList(); return folders.Cast<BaseItem>().ToList();

View File

@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv
} }
/// <summary> /// <summary>
/// Creates the triggers that define when the task will run /// Creates the triggers that define when the task will run.
/// </summary> /// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns> /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()

View File

@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false); var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
var list = result.ToList(); var list = result.ToList();
//logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list)); // logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
if (!string.IsNullOrEmpty(key) && list.Count > 0) if (!string.IsNullOrEmpty(key) && list.Count > 0)
{ {
@ -99,7 +99,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
catch (IOException) catch (IOException)
{ {
} }
} }
} }
@ -116,7 +115,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
catch (IOException) catch (IOException)
{ {
} }
} }
} }

View File

@ -111,7 +111,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
ChannelType = ChannelType.TV, ChannelType = ChannelType.TV,
IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase), IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase),
Path = i.URL Path = i.URL
}).Cast<ChannelInfo>().ToList(); }).Cast<ChannelInfo>().ToList();
} }
@ -171,6 +170,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_modelCache[cacheKey] = response; _modelCache[cacheKey] = response;
} }
} }
return response; return response;
} }
@ -201,7 +201,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase); var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
var name = line.Substring(0, index - 1); var name = line.Substring(0, index - 1);
var currentChannel = line.Substring(index + 7); var currentChannel = line.Substring(index + 7);
if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; } if (currentChannel != "none")
{
status = LiveTvTunerStatus.LiveTv;
}
else
{
status = LiveTvTunerStatus.Available;
}
tuners.Add(new LiveTvTunerInfo tuners.Add(new LiveTvTunerInfo
{ {
Name = name, Name = name,
@ -230,11 +238,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
inside = true; inside = true;
continue; continue;
} }
if (let == '>') if (let == '>')
{ {
inside = false; inside = false;
continue; continue;
} }
if (!inside) if (!inside)
{ {
buffer[bufferIndex] = let; buffer[bufferIndex] = let;
@ -332,12 +342,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private class Channels private class Channels
{ {
public string GuideNumber { get; set; } public string GuideNumber { get; set; }
public string GuideName { get; set; } public string GuideName { get; set; }
public string VideoCodec { get; set; } public string VideoCodec { get; set; }
public string AudioCodec { get; set; } public string AudioCodec { get; set; }
public string URL { get; set; } public string URL { get; set; }
public bool Favorite { get; set; } public bool Favorite { get; set; }
public bool DRM { get; set; } public bool DRM { get; set; }
public int HD { get; set; } public int HD { get; set; }
} }
@ -481,7 +498,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
Height = height, Height = height,
BitRate = videoBitrate, BitRate = videoBitrate,
NalLengthSize = nal NalLengthSize = nal
}, },
new MediaStream new MediaStream
{ {
@ -502,8 +518,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
SupportsTranscoding = true, SupportsTranscoding = true,
IsInfiniteStream = true, IsInfiniteStream = true,
IgnoreDts = true, IgnoreDts = true,
//IgnoreIndex = true, // IgnoreIndex = true,
//ReadAtNativeFramerate = true // ReadAtNativeFramerate = true
}; };
mediaSource.InferTotalBitrate(); mediaSource.InferTotalBitrate();
@ -659,13 +675,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public class DiscoverResponse public class DiscoverResponse
{ {
public string FriendlyName { get; set; } public string FriendlyName { get; set; }
public string ModelNumber { get; set; } public string ModelNumber { get; set; }
public string FirmwareName { get; set; } public string FirmwareName { get; set; }
public string FirmwareVersion { get; set; } public string FirmwareVersion { get; set; }
public string DeviceID { get; set; } public string DeviceID { get; set; }
public string DeviceAuth { get; set; } public string DeviceAuth { get; set; }
public string BaseURL { get; set; } public string BaseURL { get; set; }
public string LineupURL { get; set; } public string LineupURL { get; set; }
public int TunerCount { get; set; } public int TunerCount { get; set; }
public bool SupportsTranscoding public bool SupportsTranscoding
@ -674,7 +698,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
var model = ModelNumber ?? string.Empty; var model = ModelNumber ?? string.Empty;
if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)) if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)
{ {
return true; return true;
} }
@ -722,7 +746,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
} }
} }
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {

View File

@ -117,17 +117,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
taskCompletionSource, taskCompletionSource,
LiveStreamCancellationTokenSource.Token).ConfigureAwait(false); LiveStreamCancellationTokenSource.Token).ConfigureAwait(false);
//OpenedMediaSource.Protocol = MediaProtocol.File; // OpenedMediaSource.Protocol = MediaProtocol.File;
//OpenedMediaSource.Path = tempFile; // OpenedMediaSource.Path = tempFile;
//OpenedMediaSource.ReadAtNativeFramerate = true; // OpenedMediaSource.ReadAtNativeFramerate = true;
MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
MediaSource.Protocol = MediaProtocol.Http; MediaSource.Protocol = MediaProtocol.Http;
//OpenedMediaSource.SupportsDirectPlay = false; // OpenedMediaSource.SupportsDirectPlay = false;
//OpenedMediaSource.SupportsDirectStream = true; // OpenedMediaSource.SupportsDirectStream = true;
//OpenedMediaSource.SupportsTranscoding = true; // OpenedMediaSource.SupportsTranscoding = true;
//await Task.Delay(5000).ConfigureAwait(false); // await Task.Delay(5000).ConfigureAwait(false);
await taskCompletionSource.Task.ConfigureAwait(false); await taskCompletionSource.Task.ConfigureAwait(false);
} }

View File

@ -58,12 +58,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
protected virtual int EmptyReadLimit => 1000; protected virtual int EmptyReadLimit => 1000;
public MediaSourceInfo OriginalMediaSource { get; set; } public MediaSourceInfo OriginalMediaSource { get; set; }
public MediaSourceInfo MediaSource { get; set; } public MediaSourceInfo MediaSource { get; set; }
public int ConsumerCount { get; set; } public int ConsumerCount { get; set; }
public string OriginalStreamId { get; set; } public string OriginalStreamId { get; set; }
public bool EnableStreamSharing { get; set; } public bool EnableStreamSharing { get; set; }
public string UniqueId { get; } public string UniqueId { get; }
public string TunerHostId { get; } public string TunerHostId { get; }
@ -220,11 +223,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
catch (IOException) catch (IOException)
{ {
} }
catch (ArgumentException) catch (ArgumentException)
{ {
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -127,7 +127,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{ {
using (var stream = await new M3uParser(Logger, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false)) using (var stream = await new M3uParser(Logger, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
{ {
} }
} }

View File

@ -210,7 +210,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
} }
} }
} }
if (!IsValidChannelNumber(numberString)) if (!IsValidChannelNumber(numberString))
@ -284,7 +283,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number)) if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
{ {
//channel.Number = number.ToString(); // channel.Number = number.ToString();
nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' }); nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' });
} }
} }

Some files were not shown because too many files have changed in this diff Show More