Merge branch 'master' into nullable2
This commit is contained in:
commit
ba1ffbabd3
96
.ci/azure-pipelines-compat.yml
Normal file
96
.ci/azure-pipelines-compat.yml
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
parameters:
|
||||||
|
- name: Packages
|
||||||
|
type: object
|
||||||
|
default: {}
|
||||||
|
- name: LinuxImage
|
||||||
|
type: string
|
||||||
|
default: "ubuntu-latest"
|
||||||
|
- name: DotNetSdkVersion
|
||||||
|
type: string
|
||||||
|
default: 3.1.100
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
- job: CompatibilityCheck
|
||||||
|
displayName: Compatibility Check
|
||||||
|
pool:
|
||||||
|
vmImage: "${{ parameters.LinuxImage }}"
|
||||||
|
# only execute for pull requests
|
||||||
|
condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber'])
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
${{ each Package in parameters.Packages }}:
|
||||||
|
${{ Package.key }}:
|
||||||
|
NugetPackageName: ${{ Package.value.NugetPackageName }}
|
||||||
|
AssemblyFileName: ${{ Package.value.AssemblyFileName }}
|
||||||
|
maxParallel: 2
|
||||||
|
dependsOn: MainBuild
|
||||||
|
steps:
|
||||||
|
- checkout: none
|
||||||
|
|
||||||
|
- task: UseDotNet@2
|
||||||
|
displayName: "Update DotNet"
|
||||||
|
inputs:
|
||||||
|
packageType: sdk
|
||||||
|
version: ${{ parameters.DotNetSdkVersion }}
|
||||||
|
|
||||||
|
- task: DownloadPipelineArtifact@2
|
||||||
|
displayName: "Download New Assembly Build Artifact"
|
||||||
|
inputs:
|
||||||
|
source: "current"
|
||||||
|
artifact: "$(NugetPackageName)"
|
||||||
|
path: "$(System.ArtifactsDirectory)/new-artifacts"
|
||||||
|
runVersion: "latest"
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: "Copy New Assembly Build Artifact"
|
||||||
|
inputs:
|
||||||
|
sourceFolder: $(System.ArtifactsDirectory)/new-artifacts
|
||||||
|
contents: "**/*.dll"
|
||||||
|
targetFolder: $(System.ArtifactsDirectory)/new-release
|
||||||
|
cleanTargetFolder: true
|
||||||
|
overWrite: true
|
||||||
|
flattenFolders: true
|
||||||
|
|
||||||
|
- task: DownloadPipelineArtifact@2
|
||||||
|
displayName: "Download Reference Assembly Build Artifact"
|
||||||
|
inputs:
|
||||||
|
source: "specific"
|
||||||
|
artifact: "$(NugetPackageName)"
|
||||||
|
path: "$(System.ArtifactsDirectory)/current-artifacts"
|
||||||
|
project: "$(System.TeamProjectId)"
|
||||||
|
pipeline: "$(System.DefinitionId)"
|
||||||
|
runVersion: "latestFromBranch"
|
||||||
|
runBranch: "refs/heads/$(System.PullRequest.TargetBranch)"
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: "Copy Reference Assembly Build Artifact"
|
||||||
|
inputs:
|
||||||
|
sourceFolder: $(System.ArtifactsDirectory)/current-artifacts
|
||||||
|
contents: "**/*.dll"
|
||||||
|
targetFolder: $(System.ArtifactsDirectory)/current-release
|
||||||
|
cleanTargetFolder: true
|
||||||
|
overWrite: true
|
||||||
|
flattenFolders: true
|
||||||
|
|
||||||
|
- task: DownloadGitHubRelease@0
|
||||||
|
displayName: "Download ABI Compatibility Check Tool"
|
||||||
|
inputs:
|
||||||
|
connection: Jellyfin Release Download
|
||||||
|
userRepository: EraYaN/dotnet-compatibility
|
||||||
|
defaultVersionType: "latest"
|
||||||
|
itemPattern: "**-ci.zip"
|
||||||
|
downloadPath: "$(System.ArtifactsDirectory)"
|
||||||
|
|
||||||
|
- task: ExtractFiles@1
|
||||||
|
displayName: "Extract ABI Compatibility Check Tool"
|
||||||
|
inputs:
|
||||||
|
archiveFilePatterns: "$(System.ArtifactsDirectory)/*-ci.zip"
|
||||||
|
destinationFolder: $(System.ArtifactsDirectory)/tools
|
||||||
|
cleanDestinationFolder: true
|
||||||
|
|
||||||
|
# The `--warnings-only` switch will swallow the return code and not emit any errors.
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Execute ABI Compatibility Check Tool"
|
||||||
|
inputs:
|
||||||
|
script: "dotnet tools/CompatibilityCheckerCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only"
|
||||||
|
workingDirectory: $(System.ArtifactsDirectory)
|
101
.ci/azure-pipelines-main.yml
Normal file
101
.ci/azure-pipelines-main.yml
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
parameters:
|
||||||
|
LinuxImage: "ubuntu-latest"
|
||||||
|
RestoreBuildProjects: "Jellyfin.Server/Jellyfin.Server.csproj"
|
||||||
|
DotNetSdkVersion: 3.1.100
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
- job: MainBuild
|
||||||
|
displayName: Main Build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
Release:
|
||||||
|
BuildConfiguration: Release
|
||||||
|
Debug:
|
||||||
|
BuildConfiguration: Debug
|
||||||
|
maxParallel: 2
|
||||||
|
pool:
|
||||||
|
vmImage: "${{ parameters.LinuxImage }}"
|
||||||
|
steps:
|
||||||
|
- checkout: self
|
||||||
|
clean: true
|
||||||
|
submodules: true
|
||||||
|
persistCredentials: true
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Clone Web Client (Master, Release, or Tag)"
|
||||||
|
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
script: "git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Clone Web Client (PR)"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
|
||||||
|
inputs:
|
||||||
|
script: "git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||||
|
|
||||||
|
- task: NodeTool@0
|
||||||
|
displayName: "Install Node"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
versionSpec: "10.x"
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Build Web Client"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
script: yarn install
|
||||||
|
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: "Copy Web Client"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist
|
||||||
|
contents: "**"
|
||||||
|
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
||||||
|
cleanTargetFolder: true
|
||||||
|
overWrite: true
|
||||||
|
flattenFolders: false
|
||||||
|
|
||||||
|
- task: UseDotNet@2
|
||||||
|
displayName: "Update DotNet"
|
||||||
|
inputs:
|
||||||
|
packageType: sdk
|
||||||
|
version: ${{ parameters.DotNetSdkVersion }}
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: "Publish Server"
|
||||||
|
inputs:
|
||||||
|
command: publish
|
||||||
|
publishWebProjects: false
|
||||||
|
projects: "${{ parameters.RestoreBuildProjects }}"
|
||||||
|
arguments: "--configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory)"
|
||||||
|
zipAfterPublish: false
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@0
|
||||||
|
displayName: "Publish Artifact Naming"
|
||||||
|
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||||
|
inputs:
|
||||||
|
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/Emby.Naming.dll"
|
||||||
|
artifactName: "Jellyfin.Naming"
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@0
|
||||||
|
displayName: "Publish Artifact Controller"
|
||||||
|
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||||
|
inputs:
|
||||||
|
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Controller.dll"
|
||||||
|
artifactName: "Jellyfin.Controller"
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@0
|
||||||
|
displayName: "Publish Artifact Model"
|
||||||
|
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||||
|
inputs:
|
||||||
|
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Model.dll"
|
||||||
|
artifactName: "Jellyfin.Model"
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@0
|
||||||
|
displayName: "Publish Artifact Common"
|
||||||
|
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||||
|
inputs:
|
||||||
|
targetPath: "$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll"
|
||||||
|
artifactName: "Jellyfin.Common"
|
65
.ci/azure-pipelines-test.yml
Normal file
65
.ci/azure-pipelines-test.yml
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
parameters:
|
||||||
|
- name: ImageNames
|
||||||
|
type: object
|
||||||
|
default:
|
||||||
|
Linux: "ubuntu-latest"
|
||||||
|
Windows: "windows-latest"
|
||||||
|
macOS: "macos-latest"
|
||||||
|
- name: TestProjects
|
||||||
|
type: string
|
||||||
|
default: "tests/**/*Tests.csproj"
|
||||||
|
- name: DotNetSdkVersion
|
||||||
|
type: string
|
||||||
|
default: 3.1.100
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
- job: MainTest
|
||||||
|
displayName: Main Test
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
${{ each imageName in parameters.ImageNames }}:
|
||||||
|
${{ imageName.key }}:
|
||||||
|
ImageName: ${{ imageName.value }}
|
||||||
|
maxParallel: 3
|
||||||
|
pool:
|
||||||
|
vmImage: "$(ImageName)"
|
||||||
|
steps:
|
||||||
|
- checkout: self
|
||||||
|
clean: true
|
||||||
|
submodules: true
|
||||||
|
persistCredentials: false
|
||||||
|
|
||||||
|
- task: UseDotNet@2
|
||||||
|
displayName: "Update DotNet"
|
||||||
|
inputs:
|
||||||
|
packageType: sdk
|
||||||
|
version: ${{ parameters.DotNetSdkVersion }}
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: Run .NET Core CLI tests
|
||||||
|
inputs:
|
||||||
|
command: "test"
|
||||||
|
projects: ${{ parameters.TestProjects }}
|
||||||
|
arguments: '--configuration Release --collect:"XPlat Code Coverage" --settings tests/coverletArgs.runsettings --verbosity minimal "-p:GenerateDocumentationFile=False"'
|
||||||
|
publishTestResults: true
|
||||||
|
testRunTitle: $(Agent.JobName)
|
||||||
|
workingDirectory: "$(Build.SourcesDirectory)"
|
||||||
|
|
||||||
|
- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
|
||||||
|
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
|
||||||
|
displayName: ReportGenerator (merge)
|
||||||
|
inputs:
|
||||||
|
reports: "$(Agent.TempDirectory)/**/coverage.cobertura.xml"
|
||||||
|
targetdir: "$(Agent.TempDirectory)/merged/"
|
||||||
|
reporttypes: "Cobertura"
|
||||||
|
|
||||||
|
## V2 is already in the repository but it does not work "wrong number of segments" YAML error.
|
||||||
|
- task: PublishCodeCoverageResults@1
|
||||||
|
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
|
||||||
|
displayName: Publish Code Coverage
|
||||||
|
inputs:
|
||||||
|
codeCoverageTool: "cobertura"
|
||||||
|
#summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml' # !!THIS IS FOR V2
|
||||||
|
summaryFileLocation: "$(Agent.TempDirectory)/merged/**.xml"
|
||||||
|
pathToSources: $(Build.SourcesDirectory)
|
||||||
|
failIfCoverageEmpty: true
|
82
.ci/azure-pipelines-windows.yml
Normal file
82
.ci/azure-pipelines-windows.yml
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
parameters:
|
||||||
|
WindowsImage: "windows-latest"
|
||||||
|
TestProjects: "tests/**/*Tests.csproj"
|
||||||
|
DotNetSdkVersion: 3.1.100
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
- job: PublishWindows
|
||||||
|
displayName: Publish Windows
|
||||||
|
pool:
|
||||||
|
vmImage: ${{ parameters.WindowsImage }}
|
||||||
|
steps:
|
||||||
|
- checkout: self
|
||||||
|
clean: true
|
||||||
|
submodules: true
|
||||||
|
persistCredentials: true
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Clone Web Client (Master, Release, or Tag)"
|
||||||
|
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master'), contains(variables['Build.SourceBranch'], 'tag')), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
script: "git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Clone Web Client (PR)"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest'))
|
||||||
|
inputs:
|
||||||
|
script: "git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web"
|
||||||
|
|
||||||
|
- task: NodeTool@0
|
||||||
|
displayName: "Install Node"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
versionSpec: "10.x"
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Build Web Client"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
script: yarn install
|
||||||
|
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: "Copy Web Client"
|
||||||
|
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
||||||
|
inputs:
|
||||||
|
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist
|
||||||
|
contents: "**"
|
||||||
|
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
||||||
|
cleanTargetFolder: true
|
||||||
|
overWrite: true
|
||||||
|
flattenFolders: false
|
||||||
|
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: "Clone UX Repository"
|
||||||
|
inputs:
|
||||||
|
script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux
|
||||||
|
|
||||||
|
- task: PowerShell@2
|
||||||
|
displayName: "Build NSIS Installer"
|
||||||
|
inputs:
|
||||||
|
targetType: "filePath"
|
||||||
|
filePath: ./deployment/windows/build-jellyfin.ps1
|
||||||
|
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -InstallTrayApp -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
|
||||||
|
errorActionPreference: "stop"
|
||||||
|
workingDirectory: $(Build.SourcesDirectory)
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: "Copy NSIS Installer"
|
||||||
|
inputs:
|
||||||
|
sourceFolder: $(Build.SourcesDirectory)/deployment/windows/
|
||||||
|
contents: "jellyfin*.exe"
|
||||||
|
targetFolder: $(System.ArtifactsDirectory)/setup
|
||||||
|
cleanTargetFolder: true
|
||||||
|
overWrite: true
|
||||||
|
flattenFolders: true
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@0
|
||||||
|
displayName: "Publish Artifact Setup"
|
||||||
|
condition: succeeded()
|
||||||
|
inputs:
|
||||||
|
targetPath: "$(build.artifactstagingdirectory)/setup"
|
||||||
|
artifactName: "Jellyfin Server Setup"
|
|
@ -2,9 +2,11 @@ name: $(Date:yyyyMMdd)$(Rev:.r)
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- name: TestProjects
|
- name: TestProjects
|
||||||
value: 'tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj'
|
value: "tests/**/*Tests.csproj"
|
||||||
- name: RestoreBuildProjects
|
- name: RestoreBuildProjects
|
||||||
value: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
value: "Jellyfin.Server/Jellyfin.Server.csproj"
|
||||||
|
- name: DotNetSdkVersion
|
||||||
|
value: 3.1.100
|
||||||
|
|
||||||
pr:
|
pr:
|
||||||
autoCancel: true
|
autoCancel: true
|
||||||
|
@ -13,271 +15,26 @@ trigger:
|
||||||
batch: true
|
batch: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- job: main_build
|
- template: azure-pipelines-main.yml
|
||||||
displayName: Main Build
|
parameters:
|
||||||
pool:
|
LinuxImage: "ubuntu-latest"
|
||||||
vmImage: ubuntu-latest
|
RestoreBuildProjects: $(RestoreBuildProjects)
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
release:
|
|
||||||
BuildConfiguration: Release
|
|
||||||
debug:
|
|
||||||
BuildConfiguration: Debug
|
|
||||||
maxParallel: 2
|
|
||||||
steps:
|
|
||||||
- checkout: self
|
|
||||||
clean: true
|
|
||||||
submodules: true
|
|
||||||
persistCredentials: true
|
|
||||||
|
|
||||||
- task: CmdLine@2
|
- template: azure-pipelines-test.yml
|
||||||
displayName: "Check out web"
|
parameters:
|
||||||
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
ImageNames:
|
||||||
inputs:
|
Linux: "ubuntu-latest"
|
||||||
script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
Windows: "windows-latest"
|
||||||
|
macOS: "macos-latest"
|
||||||
|
|
||||||
- task: CmdLine@2
|
- template: azure-pipelines-windows.yml
|
||||||
displayName: "Check out web (PR)"
|
parameters:
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
|
WindowsImage: "windows-latest"
|
||||||
inputs:
|
TestProjects: $(TestProjects)
|
||||||
script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
|
||||||
|
|
||||||
- task: NodeTool@0
|
- template: azure-pipelines-compat.yml
|
||||||
displayName: 'Install Node.js'
|
parameters:
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
Packages:
|
||||||
inputs:
|
|
||||||
versionSpec: '10.x'
|
|
||||||
|
|
||||||
- task: CmdLine@2
|
|
||||||
displayName: "Build Web UI"
|
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
|
||||||
inputs:
|
|
||||||
script: yarn install
|
|
||||||
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
|
||||||
|
|
||||||
- task: CopyFiles@2
|
|
||||||
displayName: Copy the web UI
|
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
|
||||||
inputs:
|
|
||||||
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
|
|
||||||
contents: '**'
|
|
||||||
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
|
||||||
cleanTargetFolder: true # Optional
|
|
||||||
overWrite: true # Optional
|
|
||||||
flattenFolders: false # Optional
|
|
||||||
|
|
||||||
- task: DotNetCoreCLI@2
|
|
||||||
displayName: Publish
|
|
||||||
inputs:
|
|
||||||
command: publish
|
|
||||||
publishWebProjects: false
|
|
||||||
projects: '$(RestoreBuildProjects)'
|
|
||||||
arguments: '--configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory)'
|
|
||||||
zipAfterPublish: false
|
|
||||||
|
|
||||||
- task: PublishPipelineArtifact@0
|
|
||||||
displayName: 'Publish Artifact Naming'
|
|
||||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
|
||||||
inputs:
|
|
||||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/Emby.Naming.dll'
|
|
||||||
artifactName: 'Jellyfin.Naming'
|
|
||||||
|
|
||||||
- task: PublishPipelineArtifact@0
|
|
||||||
displayName: 'Publish Artifact Controller'
|
|
||||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
|
||||||
inputs:
|
|
||||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Controller.dll'
|
|
||||||
artifactName: 'Jellyfin.Controller'
|
|
||||||
|
|
||||||
- task: PublishPipelineArtifact@0
|
|
||||||
displayName: 'Publish Artifact Model'
|
|
||||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
|
||||||
inputs:
|
|
||||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Model.dll'
|
|
||||||
artifactName: 'Jellyfin.Model'
|
|
||||||
|
|
||||||
- task: PublishPipelineArtifact@0
|
|
||||||
displayName: 'Publish Artifact Common'
|
|
||||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
|
||||||
inputs:
|
|
||||||
targetPath: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll'
|
|
||||||
artifactName: 'Jellyfin.Common'
|
|
||||||
|
|
||||||
- job: main_test
|
|
||||||
displayName: Main Test
|
|
||||||
pool:
|
|
||||||
vmImage: windows-latest
|
|
||||||
steps:
|
|
||||||
- checkout: self
|
|
||||||
clean: true
|
|
||||||
submodules: true
|
|
||||||
persistCredentials: false
|
|
||||||
|
|
||||||
- task: DotNetCoreCLI@2
|
|
||||||
displayName: Build
|
|
||||||
inputs:
|
|
||||||
command: build
|
|
||||||
publishWebProjects: false
|
|
||||||
projects: '$(TestProjects)'
|
|
||||||
arguments: '--configuration $(BuildConfiguration)'
|
|
||||||
zipAfterPublish: false
|
|
||||||
|
|
||||||
- task: VisualStudioTestPlatformInstaller@1
|
|
||||||
inputs:
|
|
||||||
packageFeedSelector: 'nugetOrg' # Options: nugetOrg, customFeed, netShare
|
|
||||||
versionSelector: 'latestPreRelease' # Required when packageFeedSelector == NugetOrg || PackageFeedSelector == CustomFeed# Options: latestPreRelease, latestStable, specificVersion
|
|
||||||
|
|
||||||
- task: VSTest@2
|
|
||||||
inputs:
|
|
||||||
testSelector: 'testAssemblies' # Options: testAssemblies, testPlan, testRun
|
|
||||||
testAssemblyVer2: | # Required when testSelector == TestAssemblies
|
|
||||||
**\bin\$(BuildConfiguration)\**\*test*.dll
|
|
||||||
!**\obj\**
|
|
||||||
!**\xunit.runner.visualstudio.testadapter.dll
|
|
||||||
!**\xunit.runner.visualstudio.dotnetcore.testadapter.dll
|
|
||||||
#testPlan: # Required when testSelector == TestPlan
|
|
||||||
#testSuite: # Required when testSelector == TestPlan
|
|
||||||
#testConfiguration: # Required when testSelector == TestPlan
|
|
||||||
#tcmTestRun: '$(test.RunId)' # Optional
|
|
||||||
searchFolder: '$(System.DefaultWorkingDirectory)'
|
|
||||||
#testFiltercriteria: # Optional
|
|
||||||
#runOnlyImpactedTests: False # Optional
|
|
||||||
#runAllTestsAfterXBuilds: '50' # Optional
|
|
||||||
#uiTests: false # Optional
|
|
||||||
#vstestLocationMethod: 'version' # Optional. Options: version, location
|
|
||||||
#vsTestVersion: 'latest' # Optional. Options: latest, 16.0, 15.0, 14.0, toolsInstaller
|
|
||||||
#vstestLocation: # Optional
|
|
||||||
#runSettingsFile: # Optional
|
|
||||||
#overrideTestrunParameters: # Optional
|
|
||||||
#pathtoCustomTestAdapters: # Optional
|
|
||||||
runInParallel: True # Optional
|
|
||||||
runTestsInIsolation: True # Optional
|
|
||||||
codeCoverageEnabled: True # Optional
|
|
||||||
#otherConsoleOptions: # Optional
|
|
||||||
#distributionBatchType: 'basedOnTestCases' # Optional. Options: basedOnTestCases, basedOnExecutionTime, basedOnAssembly
|
|
||||||
#batchingBasedOnAgentsOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customBatchSize
|
|
||||||
#customBatchSizeValue: '10' # Required when distributionBatchType == BasedOnTestCases && BatchingBasedOnAgentsOption == CustomBatchSize
|
|
||||||
#batchingBasedOnExecutionTimeOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customTimeBatchSize
|
|
||||||
#customRunTimePerBatchValue: '60' # Required when distributionBatchType == BasedOnExecutionTime && BatchingBasedOnExecutionTimeOption == CustomTimeBatchSize
|
|
||||||
#dontDistribute: False # Optional
|
|
||||||
#testRunTitle: # Optional
|
|
||||||
#platform: # Optional
|
|
||||||
configuration: 'Debug' # Optional
|
|
||||||
publishRunAttachments: true # Optional
|
|
||||||
#diagnosticsEnabled: false # Optional
|
|
||||||
#collectDumpOn: 'onAbortOnly' # Optional. Options: onAbortOnly, always, never
|
|
||||||
#rerunFailedTests: False # Optional
|
|
||||||
#rerunType: 'basedOnTestFailurePercentage' # Optional. Options: basedOnTestFailurePercentage, basedOnTestFailureCount
|
|
||||||
#rerunFailedThreshold: '30' # Optional
|
|
||||||
#rerunFailedTestCasesMaxLimit: '5' # Optional
|
|
||||||
#rerunMaxAttempts: '3' # Optional
|
|
||||||
|
|
||||||
# - task: PublishTestResults@2
|
|
||||||
# inputs:
|
|
||||||
# testResultsFormat: 'VSTest' # Options: JUnit, NUnit, VSTest, xUnit, cTest
|
|
||||||
# testResultsFiles: '**/*.trx'
|
|
||||||
# #searchFolder: '$(System.DefaultWorkingDirectory)' # Optional
|
|
||||||
# mergeTestResults: true # Optional
|
|
||||||
# #failTaskOnFailedTests: false # Optional
|
|
||||||
# #testRunTitle: # Optional
|
|
||||||
# #buildPlatform: # Optional
|
|
||||||
# #buildConfiguration: # Optional
|
|
||||||
# #publishRunAttachments: true # Optional
|
|
||||||
|
|
||||||
- job: main_build_win
|
|
||||||
displayName: Main Build Windows
|
|
||||||
pool:
|
|
||||||
vmImage: windows-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
release:
|
|
||||||
BuildConfiguration: Release
|
|
||||||
maxParallel: 2
|
|
||||||
steps:
|
|
||||||
- checkout: self
|
|
||||||
clean: true
|
|
||||||
submodules: true
|
|
||||||
persistCredentials: true
|
|
||||||
|
|
||||||
- task: CmdLine@2
|
|
||||||
displayName: "Check out web (master, release or tag)"
|
|
||||||
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master'), contains(variables['Build.SourceBranch'], 'tag')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
|
||||||
inputs:
|
|
||||||
script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
|
||||||
|
|
||||||
- task: CmdLine@2
|
|
||||||
displayName: "Check out web (PR)"
|
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
|
|
||||||
inputs:
|
|
||||||
script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
|
|
||||||
|
|
||||||
- task: NodeTool@0
|
|
||||||
displayName: 'Install Node.js'
|
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
|
||||||
inputs:
|
|
||||||
versionSpec: '10.x'
|
|
||||||
|
|
||||||
- task: CmdLine@2
|
|
||||||
displayName: "Build Web UI"
|
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
|
||||||
inputs:
|
|
||||||
script: yarn install
|
|
||||||
workingDirectory: $(Agent.TempDirectory)/jellyfin-web
|
|
||||||
|
|
||||||
- task: CopyFiles@2
|
|
||||||
displayName: Copy the web UI
|
|
||||||
condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
|
|
||||||
inputs:
|
|
||||||
sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
|
|
||||||
contents: '**'
|
|
||||||
targetFolder: $(Build.SourcesDirectory)/MediaBrowser.WebDashboard/jellyfin-web
|
|
||||||
cleanTargetFolder: true # Optional
|
|
||||||
overWrite: true # Optional
|
|
||||||
flattenFolders: false # Optional
|
|
||||||
|
|
||||||
- task: CmdLine@2
|
|
||||||
displayName: Clone the UX repository
|
|
||||||
inputs:
|
|
||||||
script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux
|
|
||||||
|
|
||||||
- task: PowerShell@2
|
|
||||||
displayName: Build the NSIS Installer
|
|
||||||
inputs:
|
|
||||||
targetType: 'filePath' # Optional. Options: filePath, inline
|
|
||||||
filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath
|
|
||||||
arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -InstallTrayApp -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
|
|
||||||
#script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline
|
|
||||||
errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
|
|
||||||
#failOnStderr: false # Optional
|
|
||||||
#ignoreLASTEXITCODE: false # Optional
|
|
||||||
#pwsh: false # Optional
|
|
||||||
workingDirectory: $(Build.SourcesDirectory) # Optional
|
|
||||||
|
|
||||||
- task: CopyFiles@2
|
|
||||||
displayName: Copy the NSIS Installer to the artifact directory
|
|
||||||
inputs:
|
|
||||||
sourceFolder: $(Build.SourcesDirectory)/deployment/windows/ # Optional
|
|
||||||
contents: 'jellyfin*.exe'
|
|
||||||
targetFolder: $(System.ArtifactsDirectory)/setup
|
|
||||||
cleanTargetFolder: true # Optional
|
|
||||||
overWrite: true # Optional
|
|
||||||
flattenFolders: true # Optional
|
|
||||||
|
|
||||||
- task: PublishPipelineArtifact@0
|
|
||||||
displayName: 'Publish Setup Artifact'
|
|
||||||
condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
|
|
||||||
inputs:
|
|
||||||
targetPath: '$(build.artifactstagingdirectory)/setup'
|
|
||||||
artifactName: 'Jellyfin Server Setup'
|
|
||||||
|
|
||||||
- job: dotnet_compat
|
|
||||||
displayName: Compatibility Check
|
|
||||||
pool:
|
|
||||||
vmImage: ubuntu-latest
|
|
||||||
dependsOn: main_build
|
|
||||||
condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber']) # Only execute if the pullrequest numer is defined. (So not for normal CI builds)
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
Naming:
|
Naming:
|
||||||
NugetPackageName: Jellyfin.Naming
|
NugetPackageName: Jellyfin.Naming
|
||||||
AssemblyFileName: Emby.Naming.dll
|
AssemblyFileName: Emby.Naming.dll
|
||||||
|
@ -290,82 +47,4 @@ jobs:
|
||||||
Common:
|
Common:
|
||||||
NugetPackageName: Jellyfin.Common
|
NugetPackageName: Jellyfin.Common
|
||||||
AssemblyFileName: MediaBrowser.Common.dll
|
AssemblyFileName: MediaBrowser.Common.dll
|
||||||
maxParallel: 2
|
LinuxImage: "ubuntu-latest"
|
||||||
steps:
|
|
||||||
- checkout: none
|
|
||||||
|
|
||||||
- task: DownloadPipelineArtifact@2
|
|
||||||
displayName: Download the New Assembly Build Artifact
|
|
||||||
inputs:
|
|
||||||
source: 'current' # Options: current, specific
|
|
||||||
#preferTriggeringPipeline: false # Optional
|
|
||||||
#tags: # Optional
|
|
||||||
artifact: '$(NugetPackageName)' # Optional
|
|
||||||
#patterns: '**' # Optional
|
|
||||||
path: '$(System.ArtifactsDirectory)/new-artifacts'
|
|
||||||
#project: # Required when source == Specific
|
|
||||||
#pipeline: # Required when source == Specific
|
|
||||||
runVersion: 'latest' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
|
||||||
#runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch
|
|
||||||
#runId: # Required when source == Specific && runVersion == Specific
|
|
||||||
|
|
||||||
- task: CopyFiles@2
|
|
||||||
displayName: Copy New Assembly to new-release folder
|
|
||||||
inputs:
|
|
||||||
sourceFolder: $(System.ArtifactsDirectory)/new-artifacts # Optional
|
|
||||||
contents: '**/*.dll'
|
|
||||||
targetFolder: $(System.ArtifactsDirectory)/new-release
|
|
||||||
cleanTargetFolder: true # Optional
|
|
||||||
overWrite: true # Optional
|
|
||||||
flattenFolders: true # Optional
|
|
||||||
|
|
||||||
- task: DownloadPipelineArtifact@2
|
|
||||||
displayName: Download the Reference Assembly Build Artifact
|
|
||||||
inputs:
|
|
||||||
source: 'specific' # Options: current, specific
|
|
||||||
#preferTriggeringPipeline: false # Optional
|
|
||||||
#tags: # Optional
|
|
||||||
artifact: '$(NugetPackageName)' # Optional
|
|
||||||
#patterns: '**' # Optional
|
|
||||||
path: '$(System.ArtifactsDirectory)/current-artifacts'
|
|
||||||
project: '$(System.TeamProjectId)' # Required when source == Specific
|
|
||||||
pipeline: '$(System.DefinitionId)' # Required when source == Specific
|
|
||||||
runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
|
||||||
runBranch: 'refs/heads/$(System.PullRequest.TargetBranch)' # Required when source == Specific && runVersion == LatestFromBranch
|
|
||||||
#runId: # Required when source == Specific && runVersion == Specific
|
|
||||||
|
|
||||||
- task: CopyFiles@2
|
|
||||||
displayName: Copy Reference Assembly to current-release folder
|
|
||||||
inputs:
|
|
||||||
sourceFolder: $(System.ArtifactsDirectory)/current-artifacts # Optional
|
|
||||||
contents: '**/*.dll'
|
|
||||||
targetFolder: $(System.ArtifactsDirectory)/current-release
|
|
||||||
cleanTargetFolder: true # Optional
|
|
||||||
overWrite: true # Optional
|
|
||||||
flattenFolders: true # Optional
|
|
||||||
|
|
||||||
- task: DownloadGitHubRelease@0
|
|
||||||
displayName: Download ABI compatibility check tool from GitHub
|
|
||||||
inputs:
|
|
||||||
connection: Jellyfin Release Download
|
|
||||||
userRepository: EraYaN/dotnet-compatibility
|
|
||||||
defaultVersionType: 'latest' # Options: latest, specificVersion, specificTag
|
|
||||||
#version: # Required when defaultVersionType != Latest
|
|
||||||
itemPattern: '**-ci.zip' # Optional
|
|
||||||
downloadPath: '$(System.ArtifactsDirectory)'
|
|
||||||
|
|
||||||
- task: ExtractFiles@1
|
|
||||||
displayName: Extract ABI compatibility check tool
|
|
||||||
inputs:
|
|
||||||
archiveFilePatterns: '$(System.ArtifactsDirectory)/*-ci.zip'
|
|
||||||
destinationFolder: $(System.ArtifactsDirectory)/tools
|
|
||||||
cleanDestinationFolder: true
|
|
||||||
|
|
||||||
- task: CmdLine@2
|
|
||||||
displayName: Execute ABI compatibility check tool
|
|
||||||
inputs:
|
|
||||||
script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines'
|
|
||||||
workingDirectory: $(System.ArtifactsDirectory) # Optional
|
|
||||||
#failOnStderr: false # Optional
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
name: Nightly-$(date:yyyyMMdd).$(rev:r)
|
|
||||||
|
|
||||||
variables:
|
|
||||||
- name: Version
|
|
||||||
value: '1.0.0'
|
|
||||||
|
|
||||||
trigger: none
|
|
||||||
pr: none
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
- job: publish_artifacts_nightly
|
|
||||||
displayName: Publish Artifacts Nightly
|
|
||||||
pool:
|
|
||||||
vmImage: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- checkout: none
|
|
||||||
- task: DownloadPipelineArtifact@2
|
|
||||||
displayName: Download the Windows Setup Artifact
|
|
||||||
inputs:
|
|
||||||
source: 'specific' # Options: current, specific
|
|
||||||
artifact: 'Jellyfin Server Setup' # Optional
|
|
||||||
path: '$(System.ArtifactsDirectory)/win-installer'
|
|
||||||
project: '$(System.TeamProjectId)' # Required when source == Specific
|
|
||||||
pipelineId: 1 # Required when source == Specific
|
|
||||||
runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
|
||||||
runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch
|
|
||||||
|
|
||||||
- task: SSH@0
|
|
||||||
displayName: 'Create Drop directory'
|
|
||||||
inputs:
|
|
||||||
sshEndpoint: 'Jellyfin Build Server'
|
|
||||||
commands: 'mkdir -p /srv/incoming/jellyfin_$(Version)/win-installer && ln -s /srv/incoming/jellyfin_$(Version) /srv/incoming/jellyfin_nightly_azure_upload'
|
|
||||||
|
|
||||||
- task: CopyFilesOverSSH@0
|
|
||||||
displayName: 'Copy the Windows Setup to the Repo'
|
|
||||||
inputs:
|
|
||||||
sshEndpoint: 'Jellyfin Build Server'
|
|
||||||
sourceFolder: '$(System.ArtifactsDirectory)/win-installer'
|
|
||||||
contents: 'jellyfin_*.exe'
|
|
||||||
targetFolder: '/srv/incoming/jellyfin_nightly_azure_upload/win-installer'
|
|
||||||
|
|
||||||
- task: SSH@0
|
|
||||||
displayName: 'Clean up SCP symlink'
|
|
||||||
inputs:
|
|
||||||
sshEndpoint: 'Jellyfin Build Server'
|
|
||||||
commands: 'rm -f /srv/incoming/jellyfin_nightly_azure_upload'
|
|
|
@ -1,48 +0,0 @@
|
||||||
name: Release-$(Version)-$(date:yyyyMMdd).$(rev:r)
|
|
||||||
|
|
||||||
variables:
|
|
||||||
- name: Version
|
|
||||||
value: '1.0.0'
|
|
||||||
- name: UsedRunId
|
|
||||||
value: 0
|
|
||||||
|
|
||||||
trigger: none
|
|
||||||
pr: none
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
- job: publish_artifacts_release
|
|
||||||
displayName: Publish Artifacts Release
|
|
||||||
pool:
|
|
||||||
vmImage: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- checkout: none
|
|
||||||
- task: DownloadPipelineArtifact@2
|
|
||||||
displayName: Download the Windows Setup Artifact
|
|
||||||
inputs:
|
|
||||||
source: 'specific' # Options: current, specific
|
|
||||||
artifact: 'Jellyfin Server Setup' # Optional
|
|
||||||
path: '$(System.ArtifactsDirectory)/win-installer'
|
|
||||||
project: '$(System.TeamProjectId)' # Required when source == Specific
|
|
||||||
pipelineId: 1 # Required when source == Specific
|
|
||||||
runVersion: 'specific' # Required when source == Specific. Options: latest, latestFromBranch, specific
|
|
||||||
runId: $(UsedRunId)
|
|
||||||
|
|
||||||
- task: SSH@0
|
|
||||||
displayName: 'Create Drop directory'
|
|
||||||
inputs:
|
|
||||||
sshEndpoint: 'Jellyfin Build Server'
|
|
||||||
commands: 'mkdir -p /srv/incoming/jellyfin_$(Version)/win-installer && ln -s /srv/incoming/jellyfin_$(Version) /srv/incoming/jellyfin_release_azure_upload'
|
|
||||||
|
|
||||||
- task: CopyFilesOverSSH@0
|
|
||||||
displayName: 'Copy the Windows Setup to the Repo'
|
|
||||||
inputs:
|
|
||||||
sshEndpoint: 'Jellyfin Build Server'
|
|
||||||
sourceFolder: '$(System.ArtifactsDirectory)/win-installer'
|
|
||||||
contents: 'jellyfin_*.exe'
|
|
||||||
targetFolder: '/srv/incoming/jellyfin_release_azure_upload/win-installer'
|
|
||||||
|
|
||||||
- task: SSH@0
|
|
||||||
displayName: 'Clean up SCP symlink'
|
|
||||||
inputs:
|
|
||||||
sshEndpoint: 'Jellyfin Build Server'
|
|
||||||
commands: 'rm -f /srv/incoming/jellyfin_release_azure_upload'
|
|
6
.github/ISSUE_TEMPLATE/media_playback.md
vendored
6
.github/ISSUE_TEMPLATE/media_playback.md
vendored
|
@ -11,7 +11,10 @@ assignees: ''
|
||||||
<!-- Use the Media Info tool (set to text format, download here: https://mediaarea.net/en/MediaInfo) or copy the info from the web ui for the file with the playback issue. -->
|
<!-- Use the Media Info tool (set to text format, download here: https://mediaarea.net/en/MediaInfo) or copy the info from the web ui for the file with the playback issue. -->
|
||||||
|
|
||||||
**Logs**
|
**Logs**
|
||||||
<!-- Please paste any log message from during the playback issue, for example the ffmpeg command line can be very useful. -->
|
<!-- Please paste any log messages from during the playback issue. -->
|
||||||
|
|
||||||
|
**FFmpeg Logs**
|
||||||
|
<!-- Please paste any FFmpeg logs if remuxing or transcoding appears to be part of the issue. -->
|
||||||
|
|
||||||
**Stats for Nerds Screenshots**
|
**Stats for Nerds Screenshots**
|
||||||
<!-- If available, add screenshots of the stats for nerds screen to help show the issue problem. -->
|
<!-- If available, add screenshots of the stats for nerds screen to help show the issue problem. -->
|
||||||
|
@ -29,4 +32,3 @@ assignees: ''
|
||||||
- Client: [e.g. Web/Browser, webOS, Android, Android TV, Electron]
|
- Client: [e.g. Web/Browser, webOS, Android, Android TV, Electron]
|
||||||
- Browser (if Web client): [e.g. Firefox, Chrome, Safari]
|
- Browser (if Web client): [e.g. Firefox, Chrome, Safari]
|
||||||
- Client and Browser Version: [e.g. 10.3.4 and 68.0]
|
- Client and Browser Version: [e.g. 10.3.4 and 68.0]
|
||||||
|
|
||||||
|
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
@ -10,7 +10,7 @@
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
// If you have changed target frameworks, make sure to update the program path.
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.0/jellyfin.dll",
|
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.1/jellyfin.dll",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
||||||
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
|
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="..\SharedVersion.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
class BDInfoSettings
|
|
||||||
{
|
|
||||||
public static bool GenerateStreamDiagnostics => true;
|
|
||||||
|
|
||||||
public static bool EnableSSIF => true;
|
|
||||||
|
|
||||||
public static bool AutosaveReport => false;
|
|
||||||
|
|
||||||
public static bool GenerateFrameDataFile => false;
|
|
||||||
|
|
||||||
public static bool FilterLoopingPlaylists => true;
|
|
||||||
|
|
||||||
public static bool FilterShortPlaylists => false;
|
|
||||||
|
|
||||||
public static int FilterShortPlaylistsValue => 0;
|
|
||||||
|
|
||||||
public static bool UseImagePrefix => false;
|
|
||||||
|
|
||||||
public static string UseImagePrefixValue => null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Setting this to false throws an IComparer error on some discs.
|
|
||||||
/// </summary>
|
|
||||||
public static bool KeepStreamOrder => true;
|
|
||||||
|
|
||||||
public static bool GenerateTextSummary => false;
|
|
||||||
|
|
||||||
public static string LastPath => string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
449
BDInfo/BDROM.cs
449
BDInfo/BDROM.cs
|
@ -1,449 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public class BDROM
|
|
||||||
{
|
|
||||||
public FileSystemMetadata DirectoryRoot = null;
|
|
||||||
public FileSystemMetadata DirectoryBDMV = null;
|
|
||||||
public FileSystemMetadata DirectoryBDJO = null;
|
|
||||||
public FileSystemMetadata DirectoryCLIPINF = null;
|
|
||||||
public FileSystemMetadata DirectoryPLAYLIST = null;
|
|
||||||
public FileSystemMetadata DirectorySNP = null;
|
|
||||||
public FileSystemMetadata DirectorySSIF = null;
|
|
||||||
public FileSystemMetadata DirectorySTREAM = null;
|
|
||||||
|
|
||||||
public string VolumeLabel = null;
|
|
||||||
public ulong Size = 0;
|
|
||||||
public bool IsBDPlus = false;
|
|
||||||
public bool IsBDJava = false;
|
|
||||||
public bool IsDBOX = false;
|
|
||||||
public bool IsPSP = false;
|
|
||||||
public bool Is3D = false;
|
|
||||||
public bool Is50Hz = false;
|
|
||||||
|
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
|
|
||||||
public Dictionary<string, TSPlaylistFile> PlaylistFiles =
|
|
||||||
new Dictionary<string, TSPlaylistFile>();
|
|
||||||
public Dictionary<string, TSStreamClipFile> StreamClipFiles =
|
|
||||||
new Dictionary<string, TSStreamClipFile>();
|
|
||||||
public Dictionary<string, TSStreamFile> StreamFiles =
|
|
||||||
new Dictionary<string, TSStreamFile>();
|
|
||||||
public Dictionary<string, TSInterleavedFile> InterleavedFiles =
|
|
||||||
new Dictionary<string, TSInterleavedFile>();
|
|
||||||
|
|
||||||
public delegate bool OnStreamClipFileScanError(
|
|
||||||
TSStreamClipFile streamClipFile, Exception ex);
|
|
||||||
|
|
||||||
public event OnStreamClipFileScanError StreamClipFileScanError;
|
|
||||||
|
|
||||||
public delegate bool OnStreamFileScanError(
|
|
||||||
TSStreamFile streamClipFile, Exception ex);
|
|
||||||
|
|
||||||
public event OnStreamFileScanError StreamFileScanError;
|
|
||||||
|
|
||||||
public delegate bool OnPlaylistFileScanError(
|
|
||||||
TSPlaylistFile playlistFile, Exception ex);
|
|
||||||
|
|
||||||
public event OnPlaylistFileScanError PlaylistFileScanError;
|
|
||||||
|
|
||||||
public BDROM(string path, IFileSystem fileSystem)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
//
|
|
||||||
// Locate BDMV directories.
|
|
||||||
//
|
|
||||||
|
|
||||||
DirectoryBDMV =
|
|
||||||
GetDirectoryBDMV(path);
|
|
||||||
|
|
||||||
if (DirectoryBDMV == null)
|
|
||||||
{
|
|
||||||
throw new Exception("Unable to locate BD structure.");
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryRoot =
|
|
||||||
_fileSystem.GetDirectoryInfo(Path.GetDirectoryName(DirectoryBDMV.FullName));
|
|
||||||
DirectoryBDJO =
|
|
||||||
GetDirectory("BDJO", DirectoryBDMV, 0);
|
|
||||||
DirectoryCLIPINF =
|
|
||||||
GetDirectory("CLIPINF", DirectoryBDMV, 0);
|
|
||||||
DirectoryPLAYLIST =
|
|
||||||
GetDirectory("PLAYLIST", DirectoryBDMV, 0);
|
|
||||||
DirectorySNP =
|
|
||||||
GetDirectory("SNP", DirectoryRoot, 0);
|
|
||||||
DirectorySTREAM =
|
|
||||||
GetDirectory("STREAM", DirectoryBDMV, 0);
|
|
||||||
DirectorySSIF =
|
|
||||||
GetDirectory("SSIF", DirectorySTREAM, 0);
|
|
||||||
|
|
||||||
if (DirectoryCLIPINF == null
|
|
||||||
|| DirectoryPLAYLIST == null)
|
|
||||||
{
|
|
||||||
throw new Exception("Unable to locate BD structure.");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Initialize basic disc properties.
|
|
||||||
//
|
|
||||||
|
|
||||||
VolumeLabel = GetVolumeLabel(DirectoryRoot);
|
|
||||||
Size = (ulong)GetDirectorySize(DirectoryRoot);
|
|
||||||
|
|
||||||
if (null != GetDirectory("BDSVM", DirectoryRoot, 0))
|
|
||||||
{
|
|
||||||
IsBDPlus = true;
|
|
||||||
}
|
|
||||||
if (null != GetDirectory("SLYVM", DirectoryRoot, 0))
|
|
||||||
{
|
|
||||||
IsBDPlus = true;
|
|
||||||
}
|
|
||||||
if (null != GetDirectory("ANYVM", DirectoryRoot, 0))
|
|
||||||
{
|
|
||||||
IsBDPlus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectoryBDJO != null &&
|
|
||||||
_fileSystem.GetFilePaths(DirectoryBDJO.FullName).Any())
|
|
||||||
{
|
|
||||||
IsBDJava = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectorySNP != null &&
|
|
||||||
GetFilePaths(DirectorySNP.FullName, ".mnv").Any())
|
|
||||||
{
|
|
||||||
IsPSP = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectorySSIF != null &&
|
|
||||||
_fileSystem.GetFilePaths(DirectorySSIF.FullName).Any())
|
|
||||||
{
|
|
||||||
Is3D = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
|
|
||||||
{
|
|
||||||
IsDBOX = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Initialize file lists.
|
|
||||||
//
|
|
||||||
|
|
||||||
if (DirectoryPLAYLIST != null)
|
|
||||||
{
|
|
||||||
FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray();
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
PlaylistFiles.Add(
|
|
||||||
file.Name.ToUpper(), new TSPlaylistFile(this, file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectorySTREAM != null)
|
|
||||||
{
|
|
||||||
FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray();
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
StreamFiles.Add(
|
|
||||||
file.Name.ToUpper(), new TSStreamFile(file, _fileSystem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectoryCLIPINF != null)
|
|
||||||
{
|
|
||||||
FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray();
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
StreamClipFiles.Add(
|
|
||||||
file.Name.ToUpper(), new TSStreamClipFile(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectorySSIF != null)
|
|
||||||
{
|
|
||||||
FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray();
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
InterleavedFiles.Add(
|
|
||||||
file.Name.ToUpper(), new TSInterleavedFile(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<FileSystemMetadata> GetFiles(string path, string extension)
|
|
||||||
{
|
|
||||||
return _fileSystem.GetFiles(path, new[] { extension }, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<string> GetFilePaths(string path, string extension)
|
|
||||||
{
|
|
||||||
return _fileSystem.GetFilePaths(path, new[] { extension }, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Scan()
|
|
||||||
{
|
|
||||||
foreach (var streamClipFile in StreamClipFiles.Values)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
streamClipFile.Scan();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (StreamClipFileScanError != null)
|
|
||||||
{
|
|
||||||
if (StreamClipFileScanError(streamClipFile, ex))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var streamFile in StreamFiles.Values)
|
|
||||||
{
|
|
||||||
string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
|
|
||||||
if (InterleavedFiles.ContainsKey(ssifName))
|
|
||||||
{
|
|
||||||
streamFile.InterleavedFile = InterleavedFiles[ssifName];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TSStreamFile[] streamFiles = new TSStreamFile[StreamFiles.Count];
|
|
||||||
StreamFiles.Values.CopyTo(streamFiles, 0);
|
|
||||||
Array.Sort(streamFiles, CompareStreamFiles);
|
|
||||||
|
|
||||||
foreach (var playlistFile in PlaylistFiles.Values)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
playlistFile.Scan(StreamFiles, StreamClipFiles);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (PlaylistFileScanError != null)
|
|
||||||
{
|
|
||||||
if (PlaylistFileScanError(playlistFile, ex))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var streamFile in streamFiles)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var playlists = new List<TSPlaylistFile>();
|
|
||||||
foreach (var playlist in PlaylistFiles.Values)
|
|
||||||
{
|
|
||||||
foreach (var streamClip in playlist.StreamClips)
|
|
||||||
{
|
|
||||||
if (streamClip.Name == streamFile.Name)
|
|
||||||
{
|
|
||||||
playlists.Add(playlist);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
streamFile.Scan(playlists, false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (StreamFileScanError != null)
|
|
||||||
{
|
|
||||||
if (StreamFileScanError(streamFile, ex))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var playlistFile in PlaylistFiles.Values)
|
|
||||||
{
|
|
||||||
playlistFile.Initialize();
|
|
||||||
if (!Is50Hz)
|
|
||||||
{
|
|
||||||
foreach (var videoStream in playlistFile.VideoStreams)
|
|
||||||
{
|
|
||||||
if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
|
|
||||||
videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
|
|
||||||
{
|
|
||||||
Is50Hz = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileSystemMetadata GetDirectoryBDMV(
|
|
||||||
string path)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
|
|
||||||
|
|
||||||
while (dir != null)
|
|
||||||
{
|
|
||||||
if (string.Equals(dir.Name, "BDMV", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
var parentFolder = Path.GetDirectoryName(dir.FullName);
|
|
||||||
if (string.IsNullOrEmpty(parentFolder))
|
|
||||||
{
|
|
||||||
dir = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = _fileSystem.GetDirectoryInfo(parentFolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetDirectory("BDMV", _fileSystem.GetDirectoryInfo(path), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileSystemMetadata GetDirectory(
|
|
||||||
string name,
|
|
||||||
FileSystemMetadata dir,
|
|
||||||
int searchDepth)
|
|
||||||
{
|
|
||||||
if (dir != null)
|
|
||||||
{
|
|
||||||
FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
|
|
||||||
foreach (var child in children)
|
|
||||||
{
|
|
||||||
if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (searchDepth > 0)
|
|
||||||
{
|
|
||||||
foreach (var child in children)
|
|
||||||
{
|
|
||||||
GetDirectory(
|
|
||||||
name, child, searchDepth - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private long GetDirectorySize(FileSystemMetadata directoryInfo)
|
|
||||||
{
|
|
||||||
long size = 0;
|
|
||||||
|
|
||||||
//if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
|
|
||||||
{
|
|
||||||
FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
|
|
||||||
foreach (var pathFile in pathFiles)
|
|
||||||
{
|
|
||||||
if (pathFile.Extension.ToUpper() == ".SSIF")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
size += pathFile.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
|
|
||||||
foreach (var pathChild in pathChildren)
|
|
||||||
{
|
|
||||||
size += GetDirectorySize(pathChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetVolumeLabel(FileSystemMetadata dir)
|
|
||||||
{
|
|
||||||
return dir.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareStreamFiles(
|
|
||||||
TSStreamFile x,
|
|
||||||
TSStreamFile y)
|
|
||||||
{
|
|
||||||
// TODO: Use interleaved file sizes
|
|
||||||
|
|
||||||
if ((x == null || x.FileInfo == null) && (y == null || y.FileInfo == null))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if ((x == null || x.FileInfo == null) && (y != null && y.FileInfo != null))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if ((x != null && x.FileInfo != null) && (y == null || y.FileInfo == null))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (x.FileInfo.Length > y.FileInfo.Length)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if (y.FileInfo.Length > x.FileInfo.Length)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,493 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class LanguageCodes
|
|
||||||
{
|
|
||||||
public static string GetName(string code)
|
|
||||||
{
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case "abk": return "Abkhazian";
|
|
||||||
case "ace": return "Achinese";
|
|
||||||
case "ach": return "Acoli";
|
|
||||||
case "ada": return "Adangme";
|
|
||||||
case "aar": return "Afar";
|
|
||||||
case "afh": return "Afrihili";
|
|
||||||
case "afr": return "Afrikaans";
|
|
||||||
case "afa": return "Afro-Asiatic (Other)";
|
|
||||||
case "aka": return "Akan";
|
|
||||||
case "akk": return "Akkadian";
|
|
||||||
case "alb": return "Albanian";
|
|
||||||
case "sqi": return "Albanian";
|
|
||||||
case "ale": return "Aleut";
|
|
||||||
case "alg": return "Algonquian languages";
|
|
||||||
case "tut": return "Altaic (Other)";
|
|
||||||
case "amh": return "Amharic";
|
|
||||||
case "apa": return "Apache languages";
|
|
||||||
case "ara": return "Arabic";
|
|
||||||
case "arc": return "Aramaic";
|
|
||||||
case "arp": return "Arapaho";
|
|
||||||
case "arn": return "Araucanian";
|
|
||||||
case "arw": return "Arawak";
|
|
||||||
case "arm": return "Armenian";
|
|
||||||
case "hye": return "Armenian";
|
|
||||||
case "art": return "Artificial (Other)";
|
|
||||||
case "asm": return "Assamese";
|
|
||||||
case "ath": return "Athapascan languages";
|
|
||||||
case "aus": return "Australian languages";
|
|
||||||
case "map": return "Austronesian (Other)";
|
|
||||||
case "ava": return "Avaric";
|
|
||||||
case "ave": return "Avestan";
|
|
||||||
case "awa": return "Awadhi";
|
|
||||||
case "aym": return "Aymara";
|
|
||||||
case "aze": return "Azerbaijani";
|
|
||||||
case "ban": return "Balinese";
|
|
||||||
case "bat": return "Baltic (Other)";
|
|
||||||
case "bal": return "Baluchi";
|
|
||||||
case "bam": return "Bambara";
|
|
||||||
case "bai": return "Bamileke languages";
|
|
||||||
case "bad": return "Banda";
|
|
||||||
case "bnt": return "Bantu (Other)";
|
|
||||||
case "bas": return "Basa";
|
|
||||||
case "bak": return "Bashkir";
|
|
||||||
case "baq": return "Basque";
|
|
||||||
case "eus": return "Basque";
|
|
||||||
case "btk": return "Batak (Indonesia)";
|
|
||||||
case "bej": return "Beja";
|
|
||||||
case "bel": return "Belarusian";
|
|
||||||
case "bem": return "Bemba";
|
|
||||||
case "ben": return "Bengali";
|
|
||||||
case "ber": return "Berber (Other)";
|
|
||||||
case "bho": return "Bhojpuri";
|
|
||||||
case "bih": return "Bihari";
|
|
||||||
case "bik": return "Bikol";
|
|
||||||
case "bin": return "Bini";
|
|
||||||
case "bis": return "Bislama";
|
|
||||||
case "bos": return "Bosnian";
|
|
||||||
case "bra": return "Braj";
|
|
||||||
case "bre": return "Breton";
|
|
||||||
case "bug": return "Buginese";
|
|
||||||
case "bul": return "Bulgarian";
|
|
||||||
case "bua": return "Buriat";
|
|
||||||
case "bur": return "Burmese";
|
|
||||||
case "mya": return "Burmese";
|
|
||||||
case "cad": return "Caddo";
|
|
||||||
case "car": return "Carib";
|
|
||||||
case "cat": return "Catalan";
|
|
||||||
case "cau": return "Caucasian (Other)";
|
|
||||||
case "ceb": return "Cebuano";
|
|
||||||
case "cel": return "Celtic (Other)";
|
|
||||||
case "cai": return "Central American Indian (Other)";
|
|
||||||
case "chg": return "Chagatai";
|
|
||||||
case "cmc": return "Chamic languages";
|
|
||||||
case "cha": return "Chamorro";
|
|
||||||
case "che": return "Chechen";
|
|
||||||
case "chr": return "Cherokee";
|
|
||||||
case "chy": return "Cheyenne";
|
|
||||||
case "chb": return "Chibcha";
|
|
||||||
case "chi": return "Chinese";
|
|
||||||
case "zho": return "Chinese";
|
|
||||||
case "chn": return "Chinook jargon";
|
|
||||||
case "chp": return "Chipewyan";
|
|
||||||
case "cho": return "Choctaw";
|
|
||||||
case "chu": return "Church Slavic";
|
|
||||||
case "chk": return "Chuukese";
|
|
||||||
case "chv": return "Chuvash";
|
|
||||||
case "cop": return "Coptic";
|
|
||||||
case "cor": return "Cornish";
|
|
||||||
case "cos": return "Corsican";
|
|
||||||
case "cre": return "Cree";
|
|
||||||
case "mus": return "Creek";
|
|
||||||
case "crp": return "Creoles and pidgins (Other)";
|
|
||||||
case "cpe": return "Creoles and pidgins,";
|
|
||||||
case "cpf": return "Creoles and pidgins,";
|
|
||||||
case "cpp": return "Creoles and pidgins,";
|
|
||||||
case "scr": return "Croatian";
|
|
||||||
case "hrv": return "Croatian";
|
|
||||||
case "cus": return "Cushitic (Other)";
|
|
||||||
case "cze": return "Czech";
|
|
||||||
case "ces": return "Czech";
|
|
||||||
case "dak": return "Dakota";
|
|
||||||
case "dan": return "Danish";
|
|
||||||
case "day": return "Dayak";
|
|
||||||
case "del": return "Delaware";
|
|
||||||
case "din": return "Dinka";
|
|
||||||
case "div": return "Divehi";
|
|
||||||
case "doi": return "Dogri";
|
|
||||||
case "dgr": return "Dogrib";
|
|
||||||
case "dra": return "Dravidian (Other)";
|
|
||||||
case "dua": return "Duala";
|
|
||||||
case "dut": return "Dutch";
|
|
||||||
case "nld": return "Dutch";
|
|
||||||
case "dum": return "Dutch, Middle (ca. 1050-1350)";
|
|
||||||
case "dyu": return "Dyula";
|
|
||||||
case "dzo": return "Dzongkha";
|
|
||||||
case "efi": return "Efik";
|
|
||||||
case "egy": return "Egyptian (Ancient)";
|
|
||||||
case "eka": return "Ekajuk";
|
|
||||||
case "elx": return "Elamite";
|
|
||||||
case "eng": return "English";
|
|
||||||
case "enm": return "English, Middle (1100-1500)";
|
|
||||||
case "ang": return "English, Old (ca.450-1100)";
|
|
||||||
case "epo": return "Esperanto";
|
|
||||||
case "est": return "Estonian";
|
|
||||||
case "ewe": return "Ewe";
|
|
||||||
case "ewo": return "Ewondo";
|
|
||||||
case "fan": return "Fang";
|
|
||||||
case "fat": return "Fanti";
|
|
||||||
case "fao": return "Faroese";
|
|
||||||
case "fij": return "Fijian";
|
|
||||||
case "fin": return "Finnish";
|
|
||||||
case "fiu": return "Finno-Ugrian (Other)";
|
|
||||||
case "fon": return "Fon";
|
|
||||||
case "fre": return "French";
|
|
||||||
case "fra": return "French";
|
|
||||||
case "frm": return "French, Middle (ca.1400-1600)";
|
|
||||||
case "fro": return "French, Old (842-ca.1400)";
|
|
||||||
case "fry": return "Frisian";
|
|
||||||
case "fur": return "Friulian";
|
|
||||||
case "ful": return "Fulah";
|
|
||||||
case "gaa": return "Ga";
|
|
||||||
case "glg": return "Gallegan";
|
|
||||||
case "lug": return "Ganda";
|
|
||||||
case "gay": return "Gayo";
|
|
||||||
case "gba": return "Gbaya";
|
|
||||||
case "gez": return "Geez";
|
|
||||||
case "geo": return "Georgian";
|
|
||||||
case "kat": return "Georgian";
|
|
||||||
case "ger": return "German";
|
|
||||||
case "deu": return "German";
|
|
||||||
case "nds": return "Saxon";
|
|
||||||
case "gmh": return "German, Middle High (ca.1050-1500)";
|
|
||||||
case "goh": return "German, Old High (ca.750-1050)";
|
|
||||||
case "gem": return "Germanic (Other)";
|
|
||||||
case "gil": return "Gilbertese";
|
|
||||||
case "gon": return "Gondi";
|
|
||||||
case "gor": return "Gorontalo";
|
|
||||||
case "got": return "Gothic";
|
|
||||||
case "grb": return "Grebo";
|
|
||||||
case "grc": return "Greek, Ancient (to 1453)";
|
|
||||||
case "gre": return "Greek";
|
|
||||||
case "ell": return "Greek";
|
|
||||||
case "grn": return "Guarani";
|
|
||||||
case "guj": return "Gujarati";
|
|
||||||
case "gwi": return "Gwich´in";
|
|
||||||
case "hai": return "Haida";
|
|
||||||
case "hau": return "Hausa";
|
|
||||||
case "haw": return "Hawaiian";
|
|
||||||
case "heb": return "Hebrew";
|
|
||||||
case "her": return "Herero";
|
|
||||||
case "hil": return "Hiligaynon";
|
|
||||||
case "him": return "Himachali";
|
|
||||||
case "hin": return "Hindi";
|
|
||||||
case "hmo": return "Hiri Motu";
|
|
||||||
case "hit": return "Hittite";
|
|
||||||
case "hmn": return "Hmong";
|
|
||||||
case "hun": return "Hungarian";
|
|
||||||
case "hup": return "Hupa";
|
|
||||||
case "iba": return "Iban";
|
|
||||||
case "ice": return "Icelandic";
|
|
||||||
case "isl": return "Icelandic";
|
|
||||||
case "ibo": return "Igbo";
|
|
||||||
case "ijo": return "Ijo";
|
|
||||||
case "ilo": return "Iloko";
|
|
||||||
case "inc": return "Indic (Other)";
|
|
||||||
case "ine": return "Indo-European (Other)";
|
|
||||||
case "ind": return "Indonesian";
|
|
||||||
case "ina": return "Interlingua (International";
|
|
||||||
case "ile": return "Interlingue";
|
|
||||||
case "iku": return "Inuktitut";
|
|
||||||
case "ipk": return "Inupiaq";
|
|
||||||
case "ira": return "Iranian (Other)";
|
|
||||||
case "gle": return "Irish";
|
|
||||||
case "mga": return "Irish, Middle (900-1200)";
|
|
||||||
case "sga": return "Irish, Old (to 900)";
|
|
||||||
case "iro": return "Iroquoian languages";
|
|
||||||
case "ita": return "Italian";
|
|
||||||
case "jpn": return "Japanese";
|
|
||||||
case "jav": return "Javanese";
|
|
||||||
case "jrb": return "Judeo-Arabic";
|
|
||||||
case "jpr": return "Judeo-Persian";
|
|
||||||
case "kab": return "Kabyle";
|
|
||||||
case "kac": return "Kachin";
|
|
||||||
case "kal": return "Kalaallisut";
|
|
||||||
case "kam": return "Kamba";
|
|
||||||
case "kan": return "Kannada";
|
|
||||||
case "kau": return "Kanuri";
|
|
||||||
case "kaa": return "Kara-Kalpak";
|
|
||||||
case "kar": return "Karen";
|
|
||||||
case "kas": return "Kashmiri";
|
|
||||||
case "kaw": return "Kawi";
|
|
||||||
case "kaz": return "Kazakh";
|
|
||||||
case "kha": return "Khasi";
|
|
||||||
case "khm": return "Khmer";
|
|
||||||
case "khi": return "Khoisan (Other)";
|
|
||||||
case "kho": return "Khotanese";
|
|
||||||
case "kik": return "Kikuyu";
|
|
||||||
case "kmb": return "Kimbundu";
|
|
||||||
case "kin": return "Kinyarwanda";
|
|
||||||
case "kir": return "Kirghiz";
|
|
||||||
case "kom": return "Komi";
|
|
||||||
case "kon": return "Kongo";
|
|
||||||
case "kok": return "Konkani";
|
|
||||||
case "kor": return "Korean";
|
|
||||||
case "kos": return "Kosraean";
|
|
||||||
case "kpe": return "Kpelle";
|
|
||||||
case "kro": return "Kru";
|
|
||||||
case "kua": return "Kuanyama";
|
|
||||||
case "kum": return "Kumyk";
|
|
||||||
case "kur": return "Kurdish";
|
|
||||||
case "kru": return "Kurukh";
|
|
||||||
case "kut": return "Kutenai";
|
|
||||||
case "lad": return "Ladino";
|
|
||||||
case "lah": return "Lahnda";
|
|
||||||
case "lam": return "Lamba";
|
|
||||||
case "lao": return "Lao";
|
|
||||||
case "lat": return "Latin";
|
|
||||||
case "lav": return "Latvian";
|
|
||||||
case "ltz": return "Letzeburgesch";
|
|
||||||
case "lez": return "Lezghian";
|
|
||||||
case "lin": return "Lingala";
|
|
||||||
case "lit": return "Lithuanian";
|
|
||||||
case "loz": return "Lozi";
|
|
||||||
case "lub": return "Luba-Katanga";
|
|
||||||
case "lua": return "Luba-Lulua";
|
|
||||||
case "lui": return "Luiseno";
|
|
||||||
case "lun": return "Lunda";
|
|
||||||
case "luo": return "Luo (Kenya and Tanzania)";
|
|
||||||
case "lus": return "Lushai";
|
|
||||||
case "mac": return "Macedonian";
|
|
||||||
case "mkd": return "Macedonian";
|
|
||||||
case "mad": return "Madurese";
|
|
||||||
case "mag": return "Magahi";
|
|
||||||
case "mai": return "Maithili";
|
|
||||||
case "mak": return "Makasar";
|
|
||||||
case "mlg": return "Malagasy";
|
|
||||||
case "may": return "Malay";
|
|
||||||
case "msa": return "Malay";
|
|
||||||
case "mal": return "Malayalam";
|
|
||||||
case "mlt": return "Maltese";
|
|
||||||
case "mnc": return "Manchu";
|
|
||||||
case "mdr": return "Mandar";
|
|
||||||
case "man": return "Mandingo";
|
|
||||||
case "mni": return "Manipuri";
|
|
||||||
case "mno": return "Manobo languages";
|
|
||||||
case "glv": return "Manx";
|
|
||||||
case "mao": return "Maori";
|
|
||||||
case "mri": return "Maori";
|
|
||||||
case "mar": return "Marathi";
|
|
||||||
case "chm": return "Mari";
|
|
||||||
case "mah": return "Marshall";
|
|
||||||
case "mwr": return "Marwari";
|
|
||||||
case "mas": return "Masai";
|
|
||||||
case "myn": return "Mayan languages";
|
|
||||||
case "men": return "Mende";
|
|
||||||
case "mic": return "Micmac";
|
|
||||||
case "min": return "Minangkabau";
|
|
||||||
case "mis": return "Miscellaneous languages";
|
|
||||||
case "moh": return "Mohawk";
|
|
||||||
case "mol": return "Moldavian";
|
|
||||||
case "mkh": return "Mon-Khmer (Other)";
|
|
||||||
case "lol": return "Mongo";
|
|
||||||
case "mon": return "Mongolian";
|
|
||||||
case "mos": return "Mossi";
|
|
||||||
case "mul": return "Multiple languages";
|
|
||||||
case "mun": return "Munda languages";
|
|
||||||
case "nah": return "Nahuatl";
|
|
||||||
case "nau": return "Nauru";
|
|
||||||
case "nav": return "Navajo";
|
|
||||||
case "nde": return "Ndebele, North";
|
|
||||||
case "nbl": return "Ndebele, South";
|
|
||||||
case "ndo": return "Ndonga";
|
|
||||||
case "nep": return "Nepali";
|
|
||||||
case "new": return "Newari";
|
|
||||||
case "nia": return "Nias";
|
|
||||||
case "nic": return "Niger-Kordofanian (Other)";
|
|
||||||
case "ssa": return "Nilo-Saharan (Other)";
|
|
||||||
case "niu": return "Niuean";
|
|
||||||
case "non": return "Norse, Old";
|
|
||||||
case "nai": return "North American Indian (Other)";
|
|
||||||
case "sme": return "Northern Sami";
|
|
||||||
case "nor": return "Norwegian";
|
|
||||||
case "nob": return "Norwegian Bokmål";
|
|
||||||
case "nno": return "Norwegian Nynorsk";
|
|
||||||
case "nub": return "Nubian languages";
|
|
||||||
case "nym": return "Nyamwezi";
|
|
||||||
case "nya": return "Nyanja";
|
|
||||||
case "nyn": return "Nyankole";
|
|
||||||
case "nyo": return "Nyoro";
|
|
||||||
case "nzi": return "Nzima";
|
|
||||||
case "oci": return "Occitan";
|
|
||||||
case "oji": return "Ojibwa";
|
|
||||||
case "ori": return "Oriya";
|
|
||||||
case "orm": return "Oromo";
|
|
||||||
case "osa": return "Osage";
|
|
||||||
case "oss": return "Ossetian";
|
|
||||||
case "oto": return "Otomian languages";
|
|
||||||
case "pal": return "Pahlavi";
|
|
||||||
case "pau": return "Palauan";
|
|
||||||
case "pli": return "Pali";
|
|
||||||
case "pam": return "Pampanga";
|
|
||||||
case "pag": return "Pangasinan";
|
|
||||||
case "pan": return "Panjabi";
|
|
||||||
case "pap": return "Papiamento";
|
|
||||||
case "paa": return "Papuan (Other)";
|
|
||||||
case "per": return "Persian";
|
|
||||||
case "fas": return "Persian";
|
|
||||||
case "peo": return "Persian, Old (ca.600-400 B.C.)";
|
|
||||||
case "phi": return "Philippine (Other)";
|
|
||||||
case "phn": return "Phoenician";
|
|
||||||
case "pon": return "Pohnpeian";
|
|
||||||
case "pol": return "Polish";
|
|
||||||
case "por": return "Portuguese";
|
|
||||||
case "pra": return "Prakrit languages";
|
|
||||||
case "pro": return "Provençal";
|
|
||||||
case "pus": return "Pushto";
|
|
||||||
case "que": return "Quechua";
|
|
||||||
case "roh": return "Raeto-Romance";
|
|
||||||
case "raj": return "Rajasthani";
|
|
||||||
case "rap": return "Rapanui";
|
|
||||||
case "rar": return "Rarotongan";
|
|
||||||
case "roa": return "Romance (Other)";
|
|
||||||
case "rum": return "Romanian";
|
|
||||||
case "ron": return "Romanian";
|
|
||||||
case "rom": return "Romany";
|
|
||||||
case "run": return "Rundi";
|
|
||||||
case "rus": return "Russian";
|
|
||||||
case "sal": return "Salishan languages";
|
|
||||||
case "sam": return "Samaritan Aramaic";
|
|
||||||
case "smi": return "Sami languages (Other)";
|
|
||||||
case "smo": return "Samoan";
|
|
||||||
case "sad": return "Sandawe";
|
|
||||||
case "sag": return "Sango";
|
|
||||||
case "san": return "Sanskrit";
|
|
||||||
case "sat": return "Santali";
|
|
||||||
case "srd": return "Sardinian";
|
|
||||||
case "sas": return "Sasak";
|
|
||||||
case "sco": return "Scots";
|
|
||||||
case "gla": return "Gaelic";
|
|
||||||
case "sel": return "Selkup";
|
|
||||||
case "sem": return "Semitic (Other)";
|
|
||||||
case "scc": return "Serbian";
|
|
||||||
case "srp": return "Serbian";
|
|
||||||
case "srr": return "Serer";
|
|
||||||
case "shn": return "Shan";
|
|
||||||
case "sna": return "Shona";
|
|
||||||
case "sid": return "Sidamo";
|
|
||||||
case "sgn": return "Sign languages";
|
|
||||||
case "bla": return "Siksika";
|
|
||||||
case "snd": return "Sindhi";
|
|
||||||
case "sin": return "Sinhalese";
|
|
||||||
case "sit": return "Sino-Tibetan (Other)";
|
|
||||||
case "sio": return "Siouan languages";
|
|
||||||
case "den": return "Slave (Athapascan)";
|
|
||||||
case "sla": return "Slavic (Other)";
|
|
||||||
case "slo": return "Slovak";
|
|
||||||
case "slk": return "Slovak";
|
|
||||||
case "slv": return "Slovenian";
|
|
||||||
case "sog": return "Sogdian";
|
|
||||||
case "som": return "Somali";
|
|
||||||
case "son": return "Songhai";
|
|
||||||
case "snk": return "Soninke";
|
|
||||||
case "wen": return "Sorbian languages";
|
|
||||||
case "nso": return "Sotho, Northern";
|
|
||||||
case "sot": return "Sotho, Southern";
|
|
||||||
case "sai": return "South American Indian (Other)";
|
|
||||||
case "spa": return "Spanish";
|
|
||||||
case "suk": return "Sukuma";
|
|
||||||
case "sux": return "Sumerian";
|
|
||||||
case "sun": return "Sundanese";
|
|
||||||
case "sus": return "Susu";
|
|
||||||
case "swa": return "Swahili";
|
|
||||||
case "ssw": return "Swati";
|
|
||||||
case "swe": return "Swedish";
|
|
||||||
case "syr": return "Syriac";
|
|
||||||
case "tgl": return "Tagalog";
|
|
||||||
case "tah": return "Tahitian";
|
|
||||||
case "tai": return "Tai (Other)";
|
|
||||||
case "tgk": return "Tajik";
|
|
||||||
case "tmh": return "Tamashek";
|
|
||||||
case "tam": return "Tamil";
|
|
||||||
case "tat": return "Tatar";
|
|
||||||
case "tel": return "Telugu";
|
|
||||||
case "ter": return "Tereno";
|
|
||||||
case "tet": return "Tetum";
|
|
||||||
case "tha": return "Thai";
|
|
||||||
case "tib": return "Tibetan";
|
|
||||||
case "bod": return "Tibetan";
|
|
||||||
case "tig": return "Tigre";
|
|
||||||
case "tir": return "Tigrinya";
|
|
||||||
case "tem": return "Timne";
|
|
||||||
case "tiv": return "Tiv";
|
|
||||||
case "tli": return "Tlingit";
|
|
||||||
case "tpi": return "Tok Pisin";
|
|
||||||
case "tkl": return "Tokelau";
|
|
||||||
case "tog": return "Tonga (Nyasa)";
|
|
||||||
case "ton": return "Tonga (Tonga Islands)";
|
|
||||||
case "tsi": return "Tsimshian";
|
|
||||||
case "tso": return "Tsonga";
|
|
||||||
case "tsn": return "Tswana";
|
|
||||||
case "tum": return "Tumbuka";
|
|
||||||
case "tur": return "Turkish";
|
|
||||||
case "ota": return "Turkish, Ottoman (1500-1928)";
|
|
||||||
case "tuk": return "Turkmen";
|
|
||||||
case "tvl": return "Tuvalu";
|
|
||||||
case "tyv": return "Tuvinian";
|
|
||||||
case "twi": return "Twi";
|
|
||||||
case "uga": return "Ugaritic";
|
|
||||||
case "uig": return "Uighur";
|
|
||||||
case "ukr": return "Ukrainian";
|
|
||||||
case "umb": return "Umbundu";
|
|
||||||
case "und": return "Undetermined";
|
|
||||||
case "urd": return "Urdu";
|
|
||||||
case "uzb": return "Uzbek";
|
|
||||||
case "vai": return "Vai";
|
|
||||||
case "ven": return "Venda";
|
|
||||||
case "vie": return "Vietnamese";
|
|
||||||
case "vol": return "Volapük";
|
|
||||||
case "vot": return "Votic";
|
|
||||||
case "wak": return "Wakashan languages";
|
|
||||||
case "wal": return "Walamo";
|
|
||||||
case "war": return "Waray";
|
|
||||||
case "was": return "Washo";
|
|
||||||
case "wel": return "Welsh";
|
|
||||||
case "cym": return "Welsh";
|
|
||||||
case "wol": return "Wolof";
|
|
||||||
case "xho": return "Xhosa";
|
|
||||||
case "sah": return "Yakut";
|
|
||||||
case "yao": return "Yao";
|
|
||||||
case "yap": return "Yapese";
|
|
||||||
case "yid": return "Yiddish";
|
|
||||||
case "yor": return "Yoruba";
|
|
||||||
case "ypk": return "Yupik languages";
|
|
||||||
case "znd": return "Zande";
|
|
||||||
case "zap": return "Zapotec";
|
|
||||||
case "zen": return "Zenaga";
|
|
||||||
case "zha": return "Zhuang";
|
|
||||||
case "zul": return "Zulu";
|
|
||||||
case "zun": return "Zuni";
|
|
||||||
|
|
||||||
default: return code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using System.Resources;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("BDInfo")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("Jellyfin Project")]
|
|
||||||
[assembly: AssemblyProduct("Jellyfin Server")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2016 CinemaSquid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: NeutralResourcesLanguage("en")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
|
@ -1,5 +0,0 @@
|
||||||
The source is taken from the BDRom folder of this project:
|
|
||||||
|
|
||||||
http://www.cinemasquid.com/blu-ray/tools/bdinfo
|
|
||||||
|
|
||||||
BDInfoSettings was taken from the FormSettings class, and changed so that the settings all return defaults.
|
|
|
@ -1,309 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
#undef DEBUG
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecAC3
|
|
||||||
{
|
|
||||||
private static byte[] eac3_blocks = new byte[] { 1, 2, 3, 6 };
|
|
||||||
|
|
||||||
public static void Scan(
|
|
||||||
TSAudioStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
if (stream.IsInitialized) return;
|
|
||||||
|
|
||||||
byte[] sync = buffer.ReadBytes(2);
|
|
||||||
if (sync == null ||
|
|
||||||
sync[0] != 0x0B ||
|
|
||||||
sync[1] != 0x77)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sr_code = 0;
|
|
||||||
int frame_size = 0;
|
|
||||||
int frame_size_code = 0;
|
|
||||||
int channel_mode = 0;
|
|
||||||
int lfe_on = 0;
|
|
||||||
int dial_norm = 0;
|
|
||||||
int num_blocks = 0;
|
|
||||||
|
|
||||||
byte[] hdr = buffer.ReadBytes(4);
|
|
||||||
int bsid = (hdr[3] & 0xF8) >> 3;
|
|
||||||
buffer.Seek(-4, SeekOrigin.Current);
|
|
||||||
if (bsid <= 10)
|
|
||||||
{
|
|
||||||
byte[] crc = buffer.ReadBytes(2);
|
|
||||||
sr_code = buffer.ReadBits(2);
|
|
||||||
frame_size_code = buffer.ReadBits(6);
|
|
||||||
bsid = buffer.ReadBits(5);
|
|
||||||
int bsmod = buffer.ReadBits(3);
|
|
||||||
|
|
||||||
channel_mode = buffer.ReadBits(3);
|
|
||||||
int cmixlev = 0;
|
|
||||||
if (((channel_mode & 0x1) > 0) && (channel_mode != 0x1))
|
|
||||||
{
|
|
||||||
cmixlev = buffer.ReadBits(2);
|
|
||||||
}
|
|
||||||
int surmixlev = 0;
|
|
||||||
if ((channel_mode & 0x4) > 0)
|
|
||||||
{
|
|
||||||
surmixlev = buffer.ReadBits(2);
|
|
||||||
}
|
|
||||||
int dsurmod = 0;
|
|
||||||
if (channel_mode == 0x2)
|
|
||||||
{
|
|
||||||
dsurmod = buffer.ReadBits(2);
|
|
||||||
if (dsurmod == 0x2)
|
|
||||||
{
|
|
||||||
stream.AudioMode = TSAudioMode.Surround;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lfe_on = buffer.ReadBits(1);
|
|
||||||
dial_norm = buffer.ReadBits(5);
|
|
||||||
int compr = 0;
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
compr = buffer.ReadBits(8);
|
|
||||||
}
|
|
||||||
int langcod = 0;
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
langcod = buffer.ReadBits(8);
|
|
||||||
}
|
|
||||||
int mixlevel = 0;
|
|
||||||
int roomtyp = 0;
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
mixlevel = buffer.ReadBits(5);
|
|
||||||
roomtyp = buffer.ReadBits(2);
|
|
||||||
}
|
|
||||||
if (channel_mode == 0)
|
|
||||||
{
|
|
||||||
int dialnorm2 = buffer.ReadBits(5);
|
|
||||||
int compr2 = 0;
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
compr2 = buffer.ReadBits(8);
|
|
||||||
}
|
|
||||||
int langcod2 = 0;
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
langcod2 = buffer.ReadBits(8);
|
|
||||||
}
|
|
||||||
int mixlevel2 = 0;
|
|
||||||
int roomtyp2 = 0;
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
mixlevel2 = buffer.ReadBits(5);
|
|
||||||
roomtyp2 = buffer.ReadBits(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int copyrightb = buffer.ReadBits(1);
|
|
||||||
int origbs = buffer.ReadBits(1);
|
|
||||||
if (bsid == 6)
|
|
||||||
{
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
int dmixmod = buffer.ReadBits(2);
|
|
||||||
int ltrtcmixlev = buffer.ReadBits(3);
|
|
||||||
int ltrtsurmixlev = buffer.ReadBits(3);
|
|
||||||
int lorocmixlev = buffer.ReadBits(3);
|
|
||||||
int lorosurmixlev = buffer.ReadBits(3);
|
|
||||||
}
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
int dsurexmod = buffer.ReadBits(2);
|
|
||||||
int dheadphonmod = buffer.ReadBits(2);
|
|
||||||
if (dheadphonmod == 0x2)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
int adconvtyp = buffer.ReadBits(1);
|
|
||||||
int xbsi2 = buffer.ReadBits(8);
|
|
||||||
int encinfo = buffer.ReadBits(1);
|
|
||||||
if (dsurexmod == 2)
|
|
||||||
{
|
|
||||||
stream.AudioMode = TSAudioMode.Extended;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int frame_type = buffer.ReadBits(2);
|
|
||||||
int substreamid = buffer.ReadBits(3);
|
|
||||||
frame_size = (buffer.ReadBits(11) + 1) << 1;
|
|
||||||
|
|
||||||
sr_code = buffer.ReadBits(2);
|
|
||||||
if (sr_code == 3)
|
|
||||||
{
|
|
||||||
sr_code = buffer.ReadBits(2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
num_blocks = buffer.ReadBits(2);
|
|
||||||
}
|
|
||||||
channel_mode = buffer.ReadBits(3);
|
|
||||||
lfe_on = buffer.ReadBits(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (channel_mode)
|
|
||||||
{
|
|
||||||
case 0: // 1+1
|
|
||||||
stream.ChannelCount = 2;
|
|
||||||
if (stream.AudioMode == TSAudioMode.Unknown)
|
|
||||||
{
|
|
||||||
stream.AudioMode = TSAudioMode.DualMono;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1: // 1/0
|
|
||||||
stream.ChannelCount = 1;
|
|
||||||
break;
|
|
||||||
case 2: // 2/0
|
|
||||||
stream.ChannelCount = 2;
|
|
||||||
if (stream.AudioMode == TSAudioMode.Unknown)
|
|
||||||
{
|
|
||||||
stream.AudioMode = TSAudioMode.Stereo;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3: // 3/0
|
|
||||||
stream.ChannelCount = 3;
|
|
||||||
break;
|
|
||||||
case 4: // 2/1
|
|
||||||
stream.ChannelCount = 3;
|
|
||||||
break;
|
|
||||||
case 5: // 3/1
|
|
||||||
stream.ChannelCount = 4;
|
|
||||||
break;
|
|
||||||
case 6: // 2/2
|
|
||||||
stream.ChannelCount = 4;
|
|
||||||
break;
|
|
||||||
case 7: // 3/2
|
|
||||||
stream.ChannelCount = 5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream.ChannelCount = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (sr_code)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
stream.SampleRate = 48000;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
stream.SampleRate = 44100;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
stream.SampleRate = 32000;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream.SampleRate = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bsid <= 10)
|
|
||||||
{
|
|
||||||
switch (frame_size_code >> 1)
|
|
||||||
{
|
|
||||||
case 18:
|
|
||||||
stream.BitRate = 640000;
|
|
||||||
break;
|
|
||||||
case 17:
|
|
||||||
stream.BitRate = 576000;
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
stream.BitRate = 512000;
|
|
||||||
break;
|
|
||||||
case 15:
|
|
||||||
stream.BitRate = 448000;
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
stream.BitRate = 384000;
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
stream.BitRate = 320000;
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
stream.BitRate = 256000;
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
stream.BitRate = 224000;
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
stream.BitRate = 192000;
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
stream.BitRate = 160000;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
stream.BitRate = 128000;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
stream.BitRate = 112000;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
stream.BitRate = 96000;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
stream.BitRate = 80000;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
stream.BitRate = 64000;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
stream.BitRate = 56000;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
stream.BitRate = 48000;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
stream.BitRate = 40000;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
stream.BitRate = 32000;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream.BitRate = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stream.BitRate = (long)
|
|
||||||
(4.0 * frame_size * stream.SampleRate / (num_blocks * 256));
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.LFE = lfe_on;
|
|
||||||
if (stream.StreamType != TSStreamType.AC3_PLUS_AUDIO &&
|
|
||||||
stream.StreamType != TSStreamType.AC3_PLUS_SECONDARY_AUDIO)
|
|
||||||
{
|
|
||||||
stream.DialNorm = dial_norm - 31;
|
|
||||||
}
|
|
||||||
stream.IsVBR = false;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecAVC
|
|
||||||
{
|
|
||||||
public static void Scan(
|
|
||||||
TSVideoStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
uint parse = 0;
|
|
||||||
byte accessUnitDelimiterParse = 0;
|
|
||||||
byte sequenceParameterSetParse = 0;
|
|
||||||
string profile = null;
|
|
||||||
string level = null;
|
|
||||||
byte constraintSet0Flag = 0;
|
|
||||||
byte constraintSet1Flag = 0;
|
|
||||||
byte constraintSet2Flag = 0;
|
|
||||||
byte constraintSet3Flag = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
parse = (parse << 8) + buffer.ReadByte();
|
|
||||||
|
|
||||||
if (parse == 0x00000109)
|
|
||||||
{
|
|
||||||
accessUnitDelimiterParse = 1;
|
|
||||||
}
|
|
||||||
else if (accessUnitDelimiterParse > 0)
|
|
||||||
{
|
|
||||||
--accessUnitDelimiterParse;
|
|
||||||
if (accessUnitDelimiterParse == 0)
|
|
||||||
{
|
|
||||||
switch ((parse & 0xFF) >> 5)
|
|
||||||
{
|
|
||||||
case 0: // I
|
|
||||||
case 3: // SI
|
|
||||||
case 5: // I, SI
|
|
||||||
tag = "I";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: // I, P
|
|
||||||
case 4: // SI, SP
|
|
||||||
case 6: // I, SI, P, SP
|
|
||||||
tag = "P";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // I, P, B
|
|
||||||
case 7: // I, SI, P, SP, B
|
|
||||||
tag = "B";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (stream.IsInitialized) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parse == 0x00000127 || parse == 0x00000167)
|
|
||||||
{
|
|
||||||
sequenceParameterSetParse = 3;
|
|
||||||
}
|
|
||||||
else if (sequenceParameterSetParse > 0)
|
|
||||||
{
|
|
||||||
--sequenceParameterSetParse;
|
|
||||||
switch (sequenceParameterSetParse)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
switch (parse & 0xFF)
|
|
||||||
{
|
|
||||||
case 66:
|
|
||||||
profile = "Baseline Profile";
|
|
||||||
break;
|
|
||||||
case 77:
|
|
||||||
profile = "Main Profile";
|
|
||||||
break;
|
|
||||||
case 88:
|
|
||||||
profile = "Extended Profile";
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
profile = "High Profile";
|
|
||||||
break;
|
|
||||||
case 110:
|
|
||||||
profile = "High 10 Profile";
|
|
||||||
break;
|
|
||||||
case 122:
|
|
||||||
profile = "High 4:2:2 Profile";
|
|
||||||
break;
|
|
||||||
case 144:
|
|
||||||
profile = "High 4:4:4 Profile";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
profile = "Unknown Profile";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
constraintSet0Flag = (byte)
|
|
||||||
((parse & 0x80) >> 7);
|
|
||||||
constraintSet1Flag = (byte)
|
|
||||||
((parse & 0x40) >> 6);
|
|
||||||
constraintSet2Flag = (byte)
|
|
||||||
((parse & 0x20) >> 5);
|
|
||||||
constraintSet3Flag = (byte)
|
|
||||||
((parse & 0x10) >> 4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
byte b = (byte)(parse & 0xFF);
|
|
||||||
if (b == 11 && constraintSet3Flag == 1)
|
|
||||||
{
|
|
||||||
level = "1b";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
level = string.Format(
|
|
||||||
"{0:D}.{1:D}",
|
|
||||||
b / 10, (b - ((b / 10) * 10)));
|
|
||||||
}
|
|
||||||
stream.EncodingProfile = string.Format(
|
|
||||||
"{0} {1}", profile, level);
|
|
||||||
stream.IsVBR = true;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecDTS
|
|
||||||
{
|
|
||||||
private static int[] dca_sample_rates =
|
|
||||||
{
|
|
||||||
0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
|
|
||||||
12000, 24000, 48000, 96000, 192000
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int[] dca_bit_rates =
|
|
||||||
{
|
|
||||||
32000, 56000, 64000, 96000, 112000, 128000,
|
|
||||||
192000, 224000, 256000, 320000, 384000,
|
|
||||||
448000, 512000, 576000, 640000, 768000,
|
|
||||||
896000, 1024000, 1152000, 1280000, 1344000,
|
|
||||||
1408000, 1411200, 1472000, 1509000, 1920000,
|
|
||||||
2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int[] dca_channels =
|
|
||||||
{
|
|
||||||
1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int[] dca_bits_per_sample =
|
|
||||||
{
|
|
||||||
16, 16, 20, 20, 0, 24, 24
|
|
||||||
};
|
|
||||||
|
|
||||||
public static void Scan(
|
|
||||||
TSAudioStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
long bitrate,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
if (stream.IsInitialized) return;
|
|
||||||
|
|
||||||
bool syncFound = false;
|
|
||||||
uint sync = 0;
|
|
||||||
for (int i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
sync = (sync << 8) + buffer.ReadByte();
|
|
||||||
if (sync == 0x7FFE8001)
|
|
||||||
{
|
|
||||||
syncFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!syncFound) return;
|
|
||||||
|
|
||||||
int frame_type = buffer.ReadBits(1);
|
|
||||||
int samples_deficit = buffer.ReadBits(5);
|
|
||||||
int crc_present = buffer.ReadBits(1);
|
|
||||||
int sample_blocks = buffer.ReadBits(7);
|
|
||||||
int frame_size = buffer.ReadBits(14);
|
|
||||||
if (frame_size < 95)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int amode = buffer.ReadBits(6);
|
|
||||||
int sample_rate = buffer.ReadBits(4);
|
|
||||||
if (sample_rate < 0 || sample_rate >= dca_sample_rates.Length)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int bit_rate = buffer.ReadBits(5);
|
|
||||||
if (bit_rate < 0 || bit_rate >= dca_bit_rates.Length)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int downmix = buffer.ReadBits(1);
|
|
||||||
int dynrange = buffer.ReadBits(1);
|
|
||||||
int timestamp = buffer.ReadBits(1);
|
|
||||||
int aux_data = buffer.ReadBits(1);
|
|
||||||
int hdcd = buffer.ReadBits(1);
|
|
||||||
int ext_descr = buffer.ReadBits(3);
|
|
||||||
int ext_coding = buffer.ReadBits(1);
|
|
||||||
int aspf = buffer.ReadBits(1);
|
|
||||||
int lfe = buffer.ReadBits(2);
|
|
||||||
int predictor_history = buffer.ReadBits(1);
|
|
||||||
if (crc_present == 1)
|
|
||||||
{
|
|
||||||
int crc = buffer.ReadBits(16);
|
|
||||||
}
|
|
||||||
int multirate_inter = buffer.ReadBits(1);
|
|
||||||
int version = buffer.ReadBits(4);
|
|
||||||
int copy_history = buffer.ReadBits(2);
|
|
||||||
int source_pcm_res = buffer.ReadBits(3);
|
|
||||||
int front_sum = buffer.ReadBits(1);
|
|
||||||
int surround_sum = buffer.ReadBits(1);
|
|
||||||
int dialog_norm = buffer.ReadBits(4);
|
|
||||||
if (source_pcm_res < 0 || source_pcm_res >= dca_bits_per_sample.Length)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int subframes = buffer.ReadBits(4);
|
|
||||||
int total_channels = buffer.ReadBits(3) + 1 + ext_coding;
|
|
||||||
|
|
||||||
stream.SampleRate = dca_sample_rates[sample_rate];
|
|
||||||
stream.ChannelCount = total_channels;
|
|
||||||
stream.LFE = (lfe > 0 ? 1 : 0);
|
|
||||||
stream.BitDepth = dca_bits_per_sample[source_pcm_res];
|
|
||||||
stream.DialNorm = -dialog_norm;
|
|
||||||
if ((source_pcm_res & 0x1) == 0x1)
|
|
||||||
{
|
|
||||||
stream.AudioMode = TSAudioMode.Extended;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.BitRate = (uint)dca_bit_rates[bit_rate];
|
|
||||||
switch (stream.BitRate)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
if (bitrate > 0)
|
|
||||||
{
|
|
||||||
stream.BitRate = bitrate;
|
|
||||||
stream.IsVBR = false;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stream.BitRate = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
stream.IsVBR = true;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
stream.IsVBR = false;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,246 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecDTSHD
|
|
||||||
{
|
|
||||||
private static int[] SampleRates = new int[]
|
|
||||||
{ 0x1F40, 0x3E80, 0x7D00, 0x0FA00, 0x1F400, 0x5622, 0x0AC44, 0x15888, 0x2B110, 0x56220, 0x2EE0, 0x5DC0, 0x0BB80, 0x17700, 0x2EE00, 0x5DC00 };
|
|
||||||
|
|
||||||
public static void Scan(
|
|
||||||
TSAudioStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
long bitrate,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
if (stream.IsInitialized &&
|
|
||||||
(stream.StreamType == TSStreamType.DTS_HD_SECONDARY_AUDIO ||
|
|
||||||
(stream.CoreStream != null &&
|
|
||||||
stream.CoreStream.IsInitialized))) return;
|
|
||||||
|
|
||||||
bool syncFound = false;
|
|
||||||
uint sync = 0;
|
|
||||||
for (int i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
sync = (sync << 8) + buffer.ReadByte();
|
|
||||||
if (sync == 0x64582025)
|
|
||||||
{
|
|
||||||
syncFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!syncFound)
|
|
||||||
{
|
|
||||||
tag = "CORE";
|
|
||||||
if (stream.CoreStream == null)
|
|
||||||
{
|
|
||||||
stream.CoreStream = new TSAudioStream();
|
|
||||||
stream.CoreStream.StreamType = TSStreamType.DTS_AUDIO;
|
|
||||||
}
|
|
||||||
if (!stream.CoreStream.IsInitialized)
|
|
||||||
{
|
|
||||||
buffer.BeginRead();
|
|
||||||
TSCodecDTS.Scan(stream.CoreStream, buffer, bitrate, ref tag);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = "HD";
|
|
||||||
int temp1 = buffer.ReadBits(8);
|
|
||||||
int nuSubStreamIndex = buffer.ReadBits(2);
|
|
||||||
int nuExtSSHeaderSize = 0;
|
|
||||||
int nuExtSSFSize = 0;
|
|
||||||
int bBlownUpHeader = buffer.ReadBits(1);
|
|
||||||
if (1 == bBlownUpHeader)
|
|
||||||
{
|
|
||||||
nuExtSSHeaderSize = buffer.ReadBits(12) + 1;
|
|
||||||
nuExtSSFSize = buffer.ReadBits(20) + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nuExtSSHeaderSize = buffer.ReadBits(8) + 1;
|
|
||||||
nuExtSSFSize = buffer.ReadBits(16) + 1;
|
|
||||||
}
|
|
||||||
int nuNumAudioPresent = 1;
|
|
||||||
int nuNumAssets = 1;
|
|
||||||
int bStaticFieldsPresent = buffer.ReadBits(1);
|
|
||||||
if (1 == bStaticFieldsPresent)
|
|
||||||
{
|
|
||||||
int nuRefClockCode = buffer.ReadBits(2);
|
|
||||||
int nuExSSFrameDurationCode = buffer.ReadBits(3) + 1;
|
|
||||||
long nuTimeStamp = 0;
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
nuTimeStamp = (buffer.ReadBits(18) << 18) + buffer.ReadBits(18);
|
|
||||||
}
|
|
||||||
nuNumAudioPresent = buffer.ReadBits(3) + 1;
|
|
||||||
nuNumAssets = buffer.ReadBits(3) + 1;
|
|
||||||
int[] nuActiveExSSMask = new int[nuNumAudioPresent];
|
|
||||||
for (int i = 0; i < nuNumAudioPresent; i++)
|
|
||||||
{
|
|
||||||
nuActiveExSSMask[i] = buffer.ReadBits(nuSubStreamIndex + 1); //?
|
|
||||||
}
|
|
||||||
for (int i = 0; i < nuNumAudioPresent; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < nuSubStreamIndex + 1; j++)
|
|
||||||
{
|
|
||||||
if (((j + 1) % 2) == 1)
|
|
||||||
{
|
|
||||||
int mask = buffer.ReadBits(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (1 == buffer.ReadBits(1))
|
|
||||||
{
|
|
||||||
int nuMixMetadataAdjLevel = buffer.ReadBits(2);
|
|
||||||
int nuBits4MixOutMask = buffer.ReadBits(2) * 4 + 4;
|
|
||||||
int nuNumMixOutConfigs = buffer.ReadBits(2) + 1;
|
|
||||||
int[] nuMixOutChMask = new int[nuNumMixOutConfigs];
|
|
||||||
for (int i = 0; i < nuNumMixOutConfigs; i++)
|
|
||||||
{
|
|
||||||
nuMixOutChMask[i] = buffer.ReadBits(nuBits4MixOutMask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int[] AssetSizes = new int[nuNumAssets];
|
|
||||||
for (int i = 0; i < nuNumAssets; i++)
|
|
||||||
{
|
|
||||||
if (1 == bBlownUpHeader)
|
|
||||||
{
|
|
||||||
AssetSizes[i] = buffer.ReadBits(20) + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AssetSizes[i] = buffer.ReadBits(16) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < nuNumAssets; i++)
|
|
||||||
{
|
|
||||||
long bufferPosition = buffer.Position;
|
|
||||||
int nuAssetDescriptorFSIZE = buffer.ReadBits(9) + 1;
|
|
||||||
int DescriptorDataForAssetIndex = buffer.ReadBits(3);
|
|
||||||
if (1 == bStaticFieldsPresent)
|
|
||||||
{
|
|
||||||
int AssetTypeDescrPresent = buffer.ReadBits(1);
|
|
||||||
if (1 == AssetTypeDescrPresent)
|
|
||||||
{
|
|
||||||
int AssetTypeDescriptor = buffer.ReadBits(4);
|
|
||||||
}
|
|
||||||
int LanguageDescrPresent = buffer.ReadBits(1);
|
|
||||||
if (1 == LanguageDescrPresent)
|
|
||||||
{
|
|
||||||
int LanguageDescriptor = buffer.ReadBits(24);
|
|
||||||
}
|
|
||||||
int bInfoTextPresent = buffer.ReadBits(1);
|
|
||||||
if (1 == bInfoTextPresent)
|
|
||||||
{
|
|
||||||
int nuInfoTextByteSize = buffer.ReadBits(10) + 1;
|
|
||||||
int[] InfoText = new int[nuInfoTextByteSize];
|
|
||||||
for (int j = 0; j < nuInfoTextByteSize; j++)
|
|
||||||
{
|
|
||||||
InfoText[j] = buffer.ReadBits(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int nuBitResolution = buffer.ReadBits(5) + 1;
|
|
||||||
int nuMaxSampleRate = buffer.ReadBits(4);
|
|
||||||
int nuTotalNumChs = buffer.ReadBits(8) + 1;
|
|
||||||
int bOne2OneMapChannels2Speakers = buffer.ReadBits(1);
|
|
||||||
int nuSpkrActivityMask = 0;
|
|
||||||
if (1 == bOne2OneMapChannels2Speakers)
|
|
||||||
{
|
|
||||||
int bEmbeddedStereoFlag = 0;
|
|
||||||
if (nuTotalNumChs > 2)
|
|
||||||
{
|
|
||||||
bEmbeddedStereoFlag = buffer.ReadBits(1);
|
|
||||||
}
|
|
||||||
int bEmbeddedSixChFlag = 0;
|
|
||||||
if (nuTotalNumChs > 6)
|
|
||||||
{
|
|
||||||
bEmbeddedSixChFlag = buffer.ReadBits(1);
|
|
||||||
}
|
|
||||||
int bSpkrMaskEnabled = buffer.ReadBits(1);
|
|
||||||
int nuNumBits4SAMask = 0;
|
|
||||||
if (1 == bSpkrMaskEnabled)
|
|
||||||
{
|
|
||||||
nuNumBits4SAMask = buffer.ReadBits(2);
|
|
||||||
nuNumBits4SAMask = nuNumBits4SAMask * 4 + 4;
|
|
||||||
nuSpkrActivityMask = buffer.ReadBits(nuNumBits4SAMask);
|
|
||||||
}
|
|
||||||
// TODO...
|
|
||||||
}
|
|
||||||
stream.SampleRate = SampleRates[nuMaxSampleRate];
|
|
||||||
stream.BitDepth = nuBitResolution;
|
|
||||||
|
|
||||||
stream.LFE = 0;
|
|
||||||
if ((nuSpkrActivityMask & 0x8) == 0x8)
|
|
||||||
{
|
|
||||||
++stream.LFE;
|
|
||||||
}
|
|
||||||
if ((nuSpkrActivityMask & 0x1000) == 0x1000)
|
|
||||||
{
|
|
||||||
++stream.LFE;
|
|
||||||
}
|
|
||||||
stream.ChannelCount = nuTotalNumChs - stream.LFE;
|
|
||||||
}
|
|
||||||
if (nuNumAssets > 1)
|
|
||||||
{
|
|
||||||
// TODO...
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
if (stream.CoreStream != null)
|
|
||||||
{
|
|
||||||
var coreStream = (TSAudioStream)stream.CoreStream;
|
|
||||||
if (coreStream.AudioMode == TSAudioMode.Extended &&
|
|
||||||
stream.ChannelCount == 5)
|
|
||||||
{
|
|
||||||
stream.AudioMode = TSAudioMode.Extended;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (coreStream.DialNorm != 0)
|
|
||||||
{
|
|
||||||
stream.DialNorm = coreStream.DialNorm;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream.StreamType == TSStreamType.DTS_HD_MASTER_AUDIO)
|
|
||||||
{
|
|
||||||
stream.IsVBR = true;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
else if (bitrate > 0)
|
|
||||||
{
|
|
||||||
stream.IsVBR = false;
|
|
||||||
stream.BitRate = bitrate;
|
|
||||||
if (stream.CoreStream != null)
|
|
||||||
{
|
|
||||||
stream.BitRate += stream.CoreStream.BitRate;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
stream.IsInitialized = (stream.BitRate > 0 ? true : false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecLPCM
|
|
||||||
{
|
|
||||||
public static void Scan(
|
|
||||||
TSAudioStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
if (stream.IsInitialized) return;
|
|
||||||
|
|
||||||
byte[] header = buffer.ReadBytes(4);
|
|
||||||
int flags = (header[2] << 8) + header[3];
|
|
||||||
|
|
||||||
switch ((flags & 0xF000) >> 12)
|
|
||||||
{
|
|
||||||
case 1: // 1/0/0
|
|
||||||
stream.ChannelCount = 1;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 3: // 2/0/0
|
|
||||||
stream.ChannelCount = 2;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 4: // 3/0/0
|
|
||||||
stream.ChannelCount = 3;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 5: // 2/1/0
|
|
||||||
stream.ChannelCount = 3;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 6: // 3/1/0
|
|
||||||
stream.ChannelCount = 4;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 7: // 2/2/0
|
|
||||||
stream.ChannelCount = 4;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 8: // 3/2/0
|
|
||||||
stream.ChannelCount = 5;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 9: // 3/2/1
|
|
||||||
stream.ChannelCount = 5;
|
|
||||||
stream.LFE = 1;
|
|
||||||
break;
|
|
||||||
case 10: // 3/4/0
|
|
||||||
stream.ChannelCount = 7;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
case 11: // 3/4/1
|
|
||||||
stream.ChannelCount = 7;
|
|
||||||
stream.LFE = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream.ChannelCount = 0;
|
|
||||||
stream.LFE = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ((flags & 0xC0) >> 6)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
stream.BitDepth = 16;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
stream.BitDepth = 20;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
stream.BitDepth = 24;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream.BitDepth = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ((flags & 0xF00) >> 8)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
stream.SampleRate = 48000;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
stream.SampleRate = 96000;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
stream.SampleRate = 192000;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream.SampleRate = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.BitRate = (uint)
|
|
||||||
(stream.SampleRate * stream.BitDepth *
|
|
||||||
(stream.ChannelCount + stream.LFE));
|
|
||||||
|
|
||||||
stream.IsVBR = false;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,208 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
#undef DEBUG
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecMPEG2
|
|
||||||
{
|
|
||||||
public static void Scan(
|
|
||||||
TSVideoStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
int parse = 0;
|
|
||||||
int pictureParse = 0;
|
|
||||||
int sequenceHeaderParse = 0;
|
|
||||||
int extensionParse = 0;
|
|
||||||
int sequenceExtensionParse = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
parse = (parse << 8) + buffer.ReadByte();
|
|
||||||
|
|
||||||
if (parse == 0x00000100)
|
|
||||||
{
|
|
||||||
pictureParse = 2;
|
|
||||||
}
|
|
||||||
else if (parse == 0x000001B3)
|
|
||||||
{
|
|
||||||
sequenceHeaderParse = 7;
|
|
||||||
}
|
|
||||||
else if (sequenceHeaderParse > 0)
|
|
||||||
{
|
|
||||||
--sequenceHeaderParse;
|
|
||||||
switch (sequenceHeaderParse)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
case 6:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
stream.Width =
|
|
||||||
(int)((parse & 0xFFF000) >> 12);
|
|
||||||
stream.Height =
|
|
||||||
(int)(parse & 0xFFF);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
stream.AspectRatio =
|
|
||||||
(TSAspectRatio)((parse & 0xF0) >> 4);
|
|
||||||
|
|
||||||
switch ((parse & 0xF0) >> 4)
|
|
||||||
{
|
|
||||||
case 0: // Forbidden
|
|
||||||
break;
|
|
||||||
case 1: // Square
|
|
||||||
break;
|
|
||||||
case 2: // 4:3
|
|
||||||
break;
|
|
||||||
case 3: // 16:9
|
|
||||||
break;
|
|
||||||
case 4: // 2.21:1
|
|
||||||
break;
|
|
||||||
default: // Reserved
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (parse & 0xF)
|
|
||||||
{
|
|
||||||
case 0: // Forbidden
|
|
||||||
break;
|
|
||||||
case 1: // 23.976
|
|
||||||
stream.FrameRateEnumerator = 24000;
|
|
||||||
stream.FrameRateDenominator = 1001;
|
|
||||||
break;
|
|
||||||
case 2: // 24
|
|
||||||
stream.FrameRateEnumerator = 24000;
|
|
||||||
stream.FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
case 3: // 25
|
|
||||||
stream.FrameRateEnumerator = 25000;
|
|
||||||
stream.FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
case 4: // 29.97
|
|
||||||
stream.FrameRateEnumerator = 30000;
|
|
||||||
stream.FrameRateDenominator = 1001;
|
|
||||||
break;
|
|
||||||
case 5: // 30
|
|
||||||
stream.FrameRateEnumerator = 30000;
|
|
||||||
stream.FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
case 6: // 50
|
|
||||||
stream.FrameRateEnumerator = 50000;
|
|
||||||
stream.FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
case 7: // 59.94
|
|
||||||
stream.FrameRateEnumerator = 60000;
|
|
||||||
stream.FrameRateDenominator = 1001;
|
|
||||||
break;
|
|
||||||
case 8: // 60
|
|
||||||
stream.FrameRateEnumerator = 60000;
|
|
||||||
stream.FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
default: // Reserved
|
|
||||||
stream.FrameRateEnumerator = 0;
|
|
||||||
stream.FrameRateDenominator = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
#if DEBUG
|
|
||||||
stream.BitRate =
|
|
||||||
(((parse & 0xFFFFC0) >> 6) * 200);
|
|
||||||
#endif
|
|
||||||
stream.IsVBR = true;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pictureParse > 0)
|
|
||||||
{
|
|
||||||
--pictureParse;
|
|
||||||
if (pictureParse == 0)
|
|
||||||
{
|
|
||||||
switch ((parse & 0x38) >> 3)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
tag = "I";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
tag = "P";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
tag = "B";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (stream.IsInitialized) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parse == 0x000001B5)
|
|
||||||
{
|
|
||||||
extensionParse = 1;
|
|
||||||
}
|
|
||||||
else if (extensionParse > 0)
|
|
||||||
{
|
|
||||||
--extensionParse;
|
|
||||||
if (extensionParse == 0)
|
|
||||||
{
|
|
||||||
if ((parse & 0xF0) == 0x10)
|
|
||||||
{
|
|
||||||
sequenceExtensionParse = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (sequenceExtensionParse > 0)
|
|
||||||
{
|
|
||||||
--sequenceExtensionParse;
|
|
||||||
#if DEBUG
|
|
||||||
if (sequenceExtensionParse == 0)
|
|
||||||
{
|
|
||||||
uint sequenceExtension =
|
|
||||||
((parse & 0x8) >> 3);
|
|
||||||
if (sequenceExtension == 0)
|
|
||||||
{
|
|
||||||
stream.IsInterlaced = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stream.IsInterlaced = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
// TODO: Do something more interesting here...
|
|
||||||
|
|
||||||
public abstract class TSCodecMVC
|
|
||||||
{
|
|
||||||
public static void Scan(
|
|
||||||
TSVideoStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
stream.IsVBR = true;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecTrueHD
|
|
||||||
{
|
|
||||||
public static void Scan(
|
|
||||||
TSAudioStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
if (stream.IsInitialized &&
|
|
||||||
stream.CoreStream != null &&
|
|
||||||
stream.CoreStream.IsInitialized) return;
|
|
||||||
|
|
||||||
bool syncFound = false;
|
|
||||||
uint sync = 0;
|
|
||||||
for (int i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
sync = (sync << 8) + buffer.ReadByte();
|
|
||||||
if (sync == 0xF8726FBA)
|
|
||||||
{
|
|
||||||
syncFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!syncFound)
|
|
||||||
{
|
|
||||||
tag = "CORE";
|
|
||||||
if (stream.CoreStream == null)
|
|
||||||
{
|
|
||||||
stream.CoreStream = new TSAudioStream();
|
|
||||||
stream.CoreStream.StreamType = TSStreamType.AC3_AUDIO;
|
|
||||||
}
|
|
||||||
if (!stream.CoreStream.IsInitialized)
|
|
||||||
{
|
|
||||||
buffer.BeginRead();
|
|
||||||
TSCodecAC3.Scan(stream.CoreStream, buffer, ref tag);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = "HD";
|
|
||||||
int ratebits = buffer.ReadBits(4);
|
|
||||||
if (ratebits != 0xF)
|
|
||||||
{
|
|
||||||
stream.SampleRate =
|
|
||||||
(((ratebits & 8) > 0 ? 44100 : 48000) << (ratebits & 7));
|
|
||||||
}
|
|
||||||
int temp1 = buffer.ReadBits(8);
|
|
||||||
int channels_thd_stream1 = buffer.ReadBits(5);
|
|
||||||
int temp2 = buffer.ReadBits(2);
|
|
||||||
|
|
||||||
stream.ChannelCount = 0;
|
|
||||||
stream.LFE = 0;
|
|
||||||
int c_LFE2 = buffer.ReadBits(1);
|
|
||||||
if (c_LFE2 == 1)
|
|
||||||
{
|
|
||||||
stream.LFE += 1;
|
|
||||||
}
|
|
||||||
int c_Cvh = buffer.ReadBits(1);
|
|
||||||
if (c_Cvh == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 1;
|
|
||||||
}
|
|
||||||
int c_LRw = buffer.ReadBits(1);
|
|
||||||
if (c_LRw == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 2;
|
|
||||||
}
|
|
||||||
int c_LRsd = buffer.ReadBits(1);
|
|
||||||
if (c_LRsd == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 2;
|
|
||||||
}
|
|
||||||
int c_Ts = buffer.ReadBits(1);
|
|
||||||
if (c_Ts == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 1;
|
|
||||||
}
|
|
||||||
int c_Cs = buffer.ReadBits(1);
|
|
||||||
if (c_Cs == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 1;
|
|
||||||
}
|
|
||||||
int c_LRrs = buffer.ReadBits(1);
|
|
||||||
if (c_LRrs == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 2;
|
|
||||||
}
|
|
||||||
int c_LRc = buffer.ReadBits(1);
|
|
||||||
if (c_LRc == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 2;
|
|
||||||
}
|
|
||||||
int c_LRvh = buffer.ReadBits(1);
|
|
||||||
if (c_LRvh == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 2;
|
|
||||||
}
|
|
||||||
int c_LRs = buffer.ReadBits(1);
|
|
||||||
if (c_LRs == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 2;
|
|
||||||
}
|
|
||||||
int c_LFE = buffer.ReadBits(1);
|
|
||||||
if (c_LFE == 1)
|
|
||||||
{
|
|
||||||
stream.LFE += 1;
|
|
||||||
}
|
|
||||||
int c_C = buffer.ReadBits(1);
|
|
||||||
if (c_C == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 1;
|
|
||||||
}
|
|
||||||
int c_LR = buffer.ReadBits(1);
|
|
||||||
if (c_LR == 1)
|
|
||||||
{
|
|
||||||
stream.ChannelCount += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int access_unit_size = 40 << (ratebits & 7);
|
|
||||||
int access_unit_size_pow2 = 64 << (ratebits & 7);
|
|
||||||
|
|
||||||
int a1 = buffer.ReadBits(16);
|
|
||||||
int a2 = buffer.ReadBits(16);
|
|
||||||
int a3 = buffer.ReadBits(16);
|
|
||||||
|
|
||||||
int is_vbr = buffer.ReadBits(1);
|
|
||||||
int peak_bitrate = buffer.ReadBits(15);
|
|
||||||
peak_bitrate = (peak_bitrate * stream.SampleRate) >> 4;
|
|
||||||
|
|
||||||
double peak_bitdepth =
|
|
||||||
(double)peak_bitrate /
|
|
||||||
(stream.ChannelCount + stream.LFE) /
|
|
||||||
stream.SampleRate;
|
|
||||||
if (peak_bitdepth > 14)
|
|
||||||
{
|
|
||||||
stream.BitDepth = 24;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stream.BitDepth = 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format(
|
|
||||||
"{0}\t{1}\t{2:F2}",
|
|
||||||
stream.PID, peak_bitrate, peak_bitdepth));
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
// TODO: Get THD dialnorm from metadata
|
|
||||||
if (stream.CoreStream != null)
|
|
||||||
{
|
|
||||||
TSAudioStream coreStream = (TSAudioStream)stream.CoreStream;
|
|
||||||
if (coreStream.DialNorm != 0)
|
|
||||||
{
|
|
||||||
stream.DialNorm = coreStream.DialNorm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
stream.IsVBR = true;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public abstract class TSCodecVC1
|
|
||||||
{
|
|
||||||
public static void Scan(
|
|
||||||
TSVideoStream stream,
|
|
||||||
TSStreamBuffer buffer,
|
|
||||||
ref string tag)
|
|
||||||
{
|
|
||||||
int parse = 0;
|
|
||||||
byte frameHeaderParse = 0;
|
|
||||||
byte sequenceHeaderParse = 0;
|
|
||||||
bool isInterlaced = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
parse = (parse << 8) + buffer.ReadByte();
|
|
||||||
|
|
||||||
if (parse == 0x0000010D)
|
|
||||||
{
|
|
||||||
frameHeaderParse = 4;
|
|
||||||
}
|
|
||||||
else if (frameHeaderParse > 0)
|
|
||||||
{
|
|
||||||
--frameHeaderParse;
|
|
||||||
if (frameHeaderParse == 0)
|
|
||||||
{
|
|
||||||
uint pictureType = 0;
|
|
||||||
if (isInterlaced)
|
|
||||||
{
|
|
||||||
if ((parse & 0x80000000) == 0)
|
|
||||||
{
|
|
||||||
pictureType =
|
|
||||||
(uint)((parse & 0x78000000) >> 13);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pictureType =
|
|
||||||
(uint)((parse & 0x3c000000) >> 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pictureType =
|
|
||||||
(uint)((parse & 0xf0000000) >> 14);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((pictureType & 0x20000) == 0)
|
|
||||||
{
|
|
||||||
tag = "P";
|
|
||||||
}
|
|
||||||
else if ((pictureType & 0x10000) == 0)
|
|
||||||
{
|
|
||||||
tag = "B";
|
|
||||||
}
|
|
||||||
else if ((pictureType & 0x8000) == 0)
|
|
||||||
{
|
|
||||||
tag = "I";
|
|
||||||
}
|
|
||||||
else if ((pictureType & 0x4000) == 0)
|
|
||||||
{
|
|
||||||
tag = "BI";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tag = null;
|
|
||||||
}
|
|
||||||
if (stream.IsInitialized) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parse == 0x0000010F)
|
|
||||||
{
|
|
||||||
sequenceHeaderParse = 6;
|
|
||||||
}
|
|
||||||
else if (sequenceHeaderParse > 0)
|
|
||||||
{
|
|
||||||
--sequenceHeaderParse;
|
|
||||||
switch (sequenceHeaderParse)
|
|
||||||
{
|
|
||||||
case 5:
|
|
||||||
int profileLevel = ((parse & 0x38) >> 3);
|
|
||||||
if (((parse & 0xC0) >> 6) == 3)
|
|
||||||
{
|
|
||||||
stream.EncodingProfile = string.Format(
|
|
||||||
"Advanced Profile {0}", profileLevel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stream.EncodingProfile = string.Format(
|
|
||||||
"Main Profile {0}", profileLevel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
if (((parse & 0x40) >> 6) > 0)
|
|
||||||
{
|
|
||||||
isInterlaced = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
isInterlaced = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
stream.IsVBR = true;
|
|
||||||
stream.IsInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
|
|
||||||
// TODO: Do more interesting things here...
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public class TSInterleavedFile
|
|
||||||
{
|
|
||||||
public FileSystemMetadata FileInfo = null;
|
|
||||||
public string Name = null;
|
|
||||||
|
|
||||||
public TSInterleavedFile(FileSystemMetadata fileInfo)
|
|
||||||
{
|
|
||||||
FileInfo = fileInfo;
|
|
||||||
Name = fileInfo.Name.ToUpper();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,780 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public enum TSStreamType : byte
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
MPEG1_VIDEO = 0x01,
|
|
||||||
MPEG2_VIDEO = 0x02,
|
|
||||||
AVC_VIDEO = 0x1b,
|
|
||||||
MVC_VIDEO = 0x20,
|
|
||||||
VC1_VIDEO = 0xea,
|
|
||||||
MPEG1_AUDIO = 0x03,
|
|
||||||
MPEG2_AUDIO = 0x04,
|
|
||||||
LPCM_AUDIO = 0x80,
|
|
||||||
AC3_AUDIO = 0x81,
|
|
||||||
AC3_PLUS_AUDIO = 0x84,
|
|
||||||
AC3_PLUS_SECONDARY_AUDIO = 0xA1,
|
|
||||||
AC3_TRUE_HD_AUDIO = 0x83,
|
|
||||||
DTS_AUDIO = 0x82,
|
|
||||||
DTS_HD_AUDIO = 0x85,
|
|
||||||
DTS_HD_SECONDARY_AUDIO = 0xA2,
|
|
||||||
DTS_HD_MASTER_AUDIO = 0x86,
|
|
||||||
PRESENTATION_GRAPHICS = 0x90,
|
|
||||||
INTERACTIVE_GRAPHICS = 0x91,
|
|
||||||
SUBTITLE = 0x92
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TSVideoFormat : byte
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
VIDEOFORMAT_480i = 1,
|
|
||||||
VIDEOFORMAT_576i = 2,
|
|
||||||
VIDEOFORMAT_480p = 3,
|
|
||||||
VIDEOFORMAT_1080i = 4,
|
|
||||||
VIDEOFORMAT_720p = 5,
|
|
||||||
VIDEOFORMAT_1080p = 6,
|
|
||||||
VIDEOFORMAT_576p = 7,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TSFrameRate : byte
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
FRAMERATE_23_976 = 1,
|
|
||||||
FRAMERATE_24 = 2,
|
|
||||||
FRAMERATE_25 = 3,
|
|
||||||
FRAMERATE_29_97 = 4,
|
|
||||||
FRAMERATE_50 = 6,
|
|
||||||
FRAMERATE_59_94 = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TSChannelLayout : byte
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
CHANNELLAYOUT_MONO = 1,
|
|
||||||
CHANNELLAYOUT_STEREO = 3,
|
|
||||||
CHANNELLAYOUT_MULTI = 6,
|
|
||||||
CHANNELLAYOUT_COMBO = 12
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TSSampleRate : byte
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
SAMPLERATE_48 = 1,
|
|
||||||
SAMPLERATE_96 = 4,
|
|
||||||
SAMPLERATE_192 = 5,
|
|
||||||
SAMPLERATE_48_192 = 12,
|
|
||||||
SAMPLERATE_48_96 = 14
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TSAspectRatio
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
ASPECT_4_3 = 2,
|
|
||||||
ASPECT_16_9 = 3,
|
|
||||||
ASPECT_2_21 = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TSDescriptor
|
|
||||||
{
|
|
||||||
public byte Name;
|
|
||||||
public byte[] Value;
|
|
||||||
|
|
||||||
public TSDescriptor(byte name, byte length)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Value = new byte[length];
|
|
||||||
}
|
|
||||||
|
|
||||||
public TSDescriptor Clone()
|
|
||||||
{
|
|
||||||
var descriptor =
|
|
||||||
new TSDescriptor(Name, (byte)Value.Length);
|
|
||||||
Value.CopyTo(descriptor.Value, 0);
|
|
||||||
return descriptor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class TSStream
|
|
||||||
{
|
|
||||||
public TSStream()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format("{0} ({1})", CodecShortName, PID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ushort PID;
|
|
||||||
public TSStreamType StreamType;
|
|
||||||
public List<TSDescriptor> Descriptors = null;
|
|
||||||
public long BitRate = 0;
|
|
||||||
public long ActiveBitRate = 0;
|
|
||||||
public bool IsVBR = false;
|
|
||||||
public bool IsInitialized = false;
|
|
||||||
public string LanguageName;
|
|
||||||
public bool IsHidden = false;
|
|
||||||
|
|
||||||
public ulong PayloadBytes = 0;
|
|
||||||
public ulong PacketCount = 0;
|
|
||||||
public double PacketSeconds = 0;
|
|
||||||
public int AngleIndex = 0;
|
|
||||||
|
|
||||||
public ulong PacketSize => PacketCount * 192;
|
|
||||||
|
|
||||||
private string _LanguageCode;
|
|
||||||
public string LanguageCode
|
|
||||||
{
|
|
||||||
get => _LanguageCode;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_LanguageCode = value;
|
|
||||||
LanguageName = LanguageCodes.GetName(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsVideoStream
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.MPEG1_VIDEO:
|
|
||||||
case TSStreamType.MPEG2_VIDEO:
|
|
||||||
case TSStreamType.AVC_VIDEO:
|
|
||||||
case TSStreamType.MVC_VIDEO:
|
|
||||||
case TSStreamType.VC1_VIDEO:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAudioStream
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.MPEG1_AUDIO:
|
|
||||||
case TSStreamType.MPEG2_AUDIO:
|
|
||||||
case TSStreamType.LPCM_AUDIO:
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
|
||||||
case TSStreamType.AC3_PLUS_AUDIO:
|
|
||||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
|
||||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
|
||||||
case TSStreamType.DTS_AUDIO:
|
|
||||||
case TSStreamType.DTS_HD_AUDIO:
|
|
||||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
|
||||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsGraphicsStream
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
|
||||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsTextStream
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.SUBTITLE:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CodecName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.MPEG1_VIDEO:
|
|
||||||
return "MPEG-1 Video";
|
|
||||||
case TSStreamType.MPEG2_VIDEO:
|
|
||||||
return "MPEG-2 Video";
|
|
||||||
case TSStreamType.AVC_VIDEO:
|
|
||||||
return "MPEG-4 AVC Video";
|
|
||||||
case TSStreamType.MVC_VIDEO:
|
|
||||||
return "MPEG-4 MVC Video";
|
|
||||||
case TSStreamType.VC1_VIDEO:
|
|
||||||
return "VC-1 Video";
|
|
||||||
case TSStreamType.MPEG1_AUDIO:
|
|
||||||
return "MP1 Audio";
|
|
||||||
case TSStreamType.MPEG2_AUDIO:
|
|
||||||
return "MP2 Audio";
|
|
||||||
case TSStreamType.LPCM_AUDIO:
|
|
||||||
return "LPCM Audio";
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
|
||||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
|
||||||
return "Dolby Digital EX Audio";
|
|
||||||
else
|
|
||||||
return "Dolby Digital Audio";
|
|
||||||
case TSStreamType.AC3_PLUS_AUDIO:
|
|
||||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
|
||||||
return "Dolby Digital Plus Audio";
|
|
||||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
|
||||||
return "Dolby TrueHD Audio";
|
|
||||||
case TSStreamType.DTS_AUDIO:
|
|
||||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
|
||||||
return "DTS-ES Audio";
|
|
||||||
else
|
|
||||||
return "DTS Audio";
|
|
||||||
case TSStreamType.DTS_HD_AUDIO:
|
|
||||||
return "DTS-HD High-Res Audio";
|
|
||||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
|
||||||
return "DTS Express";
|
|
||||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
|
||||||
return "DTS-HD Master Audio";
|
|
||||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
|
||||||
return "Presentation Graphics";
|
|
||||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
|
||||||
return "Interactive Graphics";
|
|
||||||
case TSStreamType.SUBTITLE:
|
|
||||||
return "Subtitle";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CodecAltName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.MPEG1_VIDEO:
|
|
||||||
return "MPEG-1";
|
|
||||||
case TSStreamType.MPEG2_VIDEO:
|
|
||||||
return "MPEG-2";
|
|
||||||
case TSStreamType.AVC_VIDEO:
|
|
||||||
return "AVC";
|
|
||||||
case TSStreamType.MVC_VIDEO:
|
|
||||||
return "MVC";
|
|
||||||
case TSStreamType.VC1_VIDEO:
|
|
||||||
return "VC-1";
|
|
||||||
case TSStreamType.MPEG1_AUDIO:
|
|
||||||
return "MP1";
|
|
||||||
case TSStreamType.MPEG2_AUDIO:
|
|
||||||
return "MP2";
|
|
||||||
case TSStreamType.LPCM_AUDIO:
|
|
||||||
return "LPCM";
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
|
||||||
return "DD AC3";
|
|
||||||
case TSStreamType.AC3_PLUS_AUDIO:
|
|
||||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
|
||||||
return "DD AC3+";
|
|
||||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
|
||||||
return "Dolby TrueHD";
|
|
||||||
case TSStreamType.DTS_AUDIO:
|
|
||||||
return "DTS";
|
|
||||||
case TSStreamType.DTS_HD_AUDIO:
|
|
||||||
return "DTS-HD Hi-Res";
|
|
||||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
|
||||||
return "DTS Express";
|
|
||||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
|
||||||
return "DTS-HD Master";
|
|
||||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
|
||||||
return "PGS";
|
|
||||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
|
||||||
return "IGS";
|
|
||||||
case TSStreamType.SUBTITLE:
|
|
||||||
return "SUB";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CodecShortName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.MPEG1_VIDEO:
|
|
||||||
return "MPEG-1";
|
|
||||||
case TSStreamType.MPEG2_VIDEO:
|
|
||||||
return "MPEG-2";
|
|
||||||
case TSStreamType.AVC_VIDEO:
|
|
||||||
return "AVC";
|
|
||||||
case TSStreamType.MVC_VIDEO:
|
|
||||||
return "MVC";
|
|
||||||
case TSStreamType.VC1_VIDEO:
|
|
||||||
return "VC-1";
|
|
||||||
case TSStreamType.MPEG1_AUDIO:
|
|
||||||
return "MP1";
|
|
||||||
case TSStreamType.MPEG2_AUDIO:
|
|
||||||
return "MP2";
|
|
||||||
case TSStreamType.LPCM_AUDIO:
|
|
||||||
return "LPCM";
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
|
||||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
|
||||||
return "AC3-EX";
|
|
||||||
else
|
|
||||||
return "AC3";
|
|
||||||
case TSStreamType.AC3_PLUS_AUDIO:
|
|
||||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
|
||||||
return "AC3+";
|
|
||||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
|
||||||
return "TrueHD";
|
|
||||||
case TSStreamType.DTS_AUDIO:
|
|
||||||
if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
|
|
||||||
return "DTS-ES";
|
|
||||||
else
|
|
||||||
return "DTS";
|
|
||||||
case TSStreamType.DTS_HD_AUDIO:
|
|
||||||
return "DTS-HD HR";
|
|
||||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
|
||||||
return "DTS Express";
|
|
||||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
|
||||||
return "DTS-HD MA";
|
|
||||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
|
||||||
return "PGS";
|
|
||||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
|
||||||
return "IGS";
|
|
||||||
case TSStreamType.SUBTITLE:
|
|
||||||
return "SUB";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual string Description => "";
|
|
||||||
|
|
||||||
public abstract TSStream Clone();
|
|
||||||
|
|
||||||
protected void CopyTo(TSStream stream)
|
|
||||||
{
|
|
||||||
stream.PID = PID;
|
|
||||||
stream.StreamType = StreamType;
|
|
||||||
stream.IsVBR = IsVBR;
|
|
||||||
stream.BitRate = BitRate;
|
|
||||||
stream.IsInitialized = IsInitialized;
|
|
||||||
stream.LanguageCode = _LanguageCode;
|
|
||||||
if (Descriptors != null)
|
|
||||||
{
|
|
||||||
stream.Descriptors = new List<TSDescriptor>();
|
|
||||||
foreach (var descriptor in Descriptors)
|
|
||||||
{
|
|
||||||
stream.Descriptors.Add(descriptor.Clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TSVideoStream : TSStream
|
|
||||||
{
|
|
||||||
public TSVideoStream()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Width;
|
|
||||||
public int Height;
|
|
||||||
public bool IsInterlaced;
|
|
||||||
public int FrameRateEnumerator;
|
|
||||||
public int FrameRateDenominator;
|
|
||||||
public TSAspectRatio AspectRatio;
|
|
||||||
public string EncodingProfile;
|
|
||||||
|
|
||||||
private TSVideoFormat _VideoFormat;
|
|
||||||
public TSVideoFormat VideoFormat
|
|
||||||
{
|
|
||||||
get => _VideoFormat;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_VideoFormat = value;
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case TSVideoFormat.VIDEOFORMAT_480i:
|
|
||||||
Height = 480;
|
|
||||||
IsInterlaced = true;
|
|
||||||
break;
|
|
||||||
case TSVideoFormat.VIDEOFORMAT_480p:
|
|
||||||
Height = 480;
|
|
||||||
IsInterlaced = false;
|
|
||||||
break;
|
|
||||||
case TSVideoFormat.VIDEOFORMAT_576i:
|
|
||||||
Height = 576;
|
|
||||||
IsInterlaced = true;
|
|
||||||
break;
|
|
||||||
case TSVideoFormat.VIDEOFORMAT_576p:
|
|
||||||
Height = 576;
|
|
||||||
IsInterlaced = false;
|
|
||||||
break;
|
|
||||||
case TSVideoFormat.VIDEOFORMAT_720p:
|
|
||||||
Height = 720;
|
|
||||||
IsInterlaced = false;
|
|
||||||
break;
|
|
||||||
case TSVideoFormat.VIDEOFORMAT_1080i:
|
|
||||||
Height = 1080;
|
|
||||||
IsInterlaced = true;
|
|
||||||
break;
|
|
||||||
case TSVideoFormat.VIDEOFORMAT_1080p:
|
|
||||||
Height = 1080;
|
|
||||||
IsInterlaced = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TSFrameRate _FrameRate;
|
|
||||||
public TSFrameRate FrameRate
|
|
||||||
{
|
|
||||||
get => _FrameRate;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_FrameRate = value;
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case TSFrameRate.FRAMERATE_23_976:
|
|
||||||
FrameRateEnumerator = 24000;
|
|
||||||
FrameRateDenominator = 1001;
|
|
||||||
break;
|
|
||||||
case TSFrameRate.FRAMERATE_24:
|
|
||||||
FrameRateEnumerator = 24000;
|
|
||||||
FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
case TSFrameRate.FRAMERATE_25:
|
|
||||||
FrameRateEnumerator = 25000;
|
|
||||||
FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
case TSFrameRate.FRAMERATE_29_97:
|
|
||||||
FrameRateEnumerator = 30000;
|
|
||||||
FrameRateDenominator = 1001;
|
|
||||||
break;
|
|
||||||
case TSFrameRate.FRAMERATE_50:
|
|
||||||
FrameRateEnumerator = 50000;
|
|
||||||
FrameRateDenominator = 1000;
|
|
||||||
break;
|
|
||||||
case TSFrameRate.FRAMERATE_59_94:
|
|
||||||
FrameRateEnumerator = 60000;
|
|
||||||
FrameRateDenominator = 1001;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Description
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
string description = "";
|
|
||||||
|
|
||||||
if (Height > 0)
|
|
||||||
{
|
|
||||||
description += string.Format("{0:D}{1} / ",
|
|
||||||
Height,
|
|
||||||
IsInterlaced ? "i" : "p");
|
|
||||||
}
|
|
||||||
if (FrameRateEnumerator > 0 &&
|
|
||||||
FrameRateDenominator > 0)
|
|
||||||
{
|
|
||||||
if (FrameRateEnumerator % FrameRateDenominator == 0)
|
|
||||||
{
|
|
||||||
description += string.Format("{0:D} fps / ",
|
|
||||||
FrameRateEnumerator / FrameRateDenominator);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
description += string.Format("{0:F3} fps / ",
|
|
||||||
(double)FrameRateEnumerator / FrameRateDenominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (AspectRatio == TSAspectRatio.ASPECT_4_3)
|
|
||||||
{
|
|
||||||
description += "4:3 / ";
|
|
||||||
}
|
|
||||||
else if (AspectRatio == TSAspectRatio.ASPECT_16_9)
|
|
||||||
{
|
|
||||||
description += "16:9 / ";
|
|
||||||
}
|
|
||||||
if (EncodingProfile != null)
|
|
||||||
{
|
|
||||||
description += EncodingProfile + " / ";
|
|
||||||
}
|
|
||||||
if (description.EndsWith(" / "))
|
|
||||||
{
|
|
||||||
description = description.Substring(0, description.Length - 3);
|
|
||||||
}
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override TSStream Clone()
|
|
||||||
{
|
|
||||||
var stream = new TSVideoStream();
|
|
||||||
CopyTo(stream);
|
|
||||||
|
|
||||||
stream.VideoFormat = _VideoFormat;
|
|
||||||
stream.FrameRate = _FrameRate;
|
|
||||||
stream.Width = Width;
|
|
||||||
stream.Height = Height;
|
|
||||||
stream.IsInterlaced = IsInterlaced;
|
|
||||||
stream.FrameRateEnumerator = FrameRateEnumerator;
|
|
||||||
stream.FrameRateDenominator = FrameRateDenominator;
|
|
||||||
stream.AspectRatio = AspectRatio;
|
|
||||||
stream.EncodingProfile = EncodingProfile;
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TSAudioMode
|
|
||||||
{
|
|
||||||
Unknown,
|
|
||||||
DualMono,
|
|
||||||
Stereo,
|
|
||||||
Surround,
|
|
||||||
Extended
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TSAudioStream : TSStream
|
|
||||||
{
|
|
||||||
public TSAudioStream()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SampleRate;
|
|
||||||
public int ChannelCount;
|
|
||||||
public int BitDepth;
|
|
||||||
public int LFE;
|
|
||||||
public int DialNorm;
|
|
||||||
public TSAudioMode AudioMode;
|
|
||||||
public TSAudioStream CoreStream;
|
|
||||||
public TSChannelLayout ChannelLayout;
|
|
||||||
|
|
||||||
public static int ConvertSampleRate(
|
|
||||||
TSSampleRate sampleRate)
|
|
||||||
{
|
|
||||||
switch (sampleRate)
|
|
||||||
{
|
|
||||||
case TSSampleRate.SAMPLERATE_48:
|
|
||||||
return 48000;
|
|
||||||
|
|
||||||
case TSSampleRate.SAMPLERATE_96:
|
|
||||||
case TSSampleRate.SAMPLERATE_48_96:
|
|
||||||
return 96000;
|
|
||||||
|
|
||||||
case TSSampleRate.SAMPLERATE_192:
|
|
||||||
case TSSampleRate.SAMPLERATE_48_192:
|
|
||||||
return 192000;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ChannelDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (ChannelLayout == TSChannelLayout.CHANNELLAYOUT_MONO &&
|
|
||||||
ChannelCount == 2)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
string description = "";
|
|
||||||
if (ChannelCount > 0)
|
|
||||||
{
|
|
||||||
description += string.Format(
|
|
||||||
"{0:D}.{1:D}",
|
|
||||||
ChannelCount, LFE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (ChannelLayout)
|
|
||||||
{
|
|
||||||
case TSChannelLayout.CHANNELLAYOUT_MONO:
|
|
||||||
description += "1.0";
|
|
||||||
break;
|
|
||||||
case TSChannelLayout.CHANNELLAYOUT_STEREO:
|
|
||||||
description += "2.0";
|
|
||||||
break;
|
|
||||||
case TSChannelLayout.CHANNELLAYOUT_MULTI:
|
|
||||||
description += "5.1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (AudioMode == TSAudioMode.Extended)
|
|
||||||
{
|
|
||||||
if (StreamType == TSStreamType.AC3_AUDIO)
|
|
||||||
{
|
|
||||||
description += "-EX";
|
|
||||||
}
|
|
||||||
if (StreamType == TSStreamType.DTS_AUDIO ||
|
|
||||||
StreamType == TSStreamType.DTS_HD_AUDIO ||
|
|
||||||
StreamType == TSStreamType.DTS_HD_MASTER_AUDIO)
|
|
||||||
{
|
|
||||||
description += "-ES";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Description
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
string description = ChannelDescription;
|
|
||||||
|
|
||||||
if (SampleRate > 0)
|
|
||||||
{
|
|
||||||
description += string.Format(
|
|
||||||
" / {0:D} kHz", SampleRate / 1000);
|
|
||||||
}
|
|
||||||
if (BitRate > 0)
|
|
||||||
{
|
|
||||||
description += string.Format(
|
|
||||||
" / {0:D} kbps", (uint)Math.Round((double)BitRate / 1000));
|
|
||||||
}
|
|
||||||
if (BitDepth > 0)
|
|
||||||
{
|
|
||||||
description += string.Format(
|
|
||||||
" / {0:D}-bit", BitDepth);
|
|
||||||
}
|
|
||||||
if (DialNorm != 0)
|
|
||||||
{
|
|
||||||
description += string.Format(
|
|
||||||
" / DN {0}dB", DialNorm);
|
|
||||||
}
|
|
||||||
if (ChannelCount == 2)
|
|
||||||
{
|
|
||||||
switch (AudioMode)
|
|
||||||
{
|
|
||||||
case TSAudioMode.DualMono:
|
|
||||||
description += " / Dual Mono";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TSAudioMode.Surround:
|
|
||||||
description += " / Dolby Surround";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (description.EndsWith(" / "))
|
|
||||||
{
|
|
||||||
description = description.Substring(0, description.Length - 3);
|
|
||||||
}
|
|
||||||
if (CoreStream != null)
|
|
||||||
{
|
|
||||||
string codec = "";
|
|
||||||
switch (CoreStream.StreamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
|
||||||
codec = "AC3 Embedded";
|
|
||||||
break;
|
|
||||||
case TSStreamType.DTS_AUDIO:
|
|
||||||
codec = "DTS Core";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
description += string.Format(
|
|
||||||
" ({0}: {1})",
|
|
||||||
codec,
|
|
||||||
CoreStream.Description);
|
|
||||||
}
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override TSStream Clone()
|
|
||||||
{
|
|
||||||
var stream = new TSAudioStream();
|
|
||||||
CopyTo(stream);
|
|
||||||
|
|
||||||
stream.SampleRate = SampleRate;
|
|
||||||
stream.ChannelLayout = ChannelLayout;
|
|
||||||
stream.ChannelCount = ChannelCount;
|
|
||||||
stream.BitDepth = BitDepth;
|
|
||||||
stream.LFE = LFE;
|
|
||||||
stream.DialNorm = DialNorm;
|
|
||||||
stream.AudioMode = AudioMode;
|
|
||||||
if (CoreStream != null)
|
|
||||||
{
|
|
||||||
stream.CoreStream = (TSAudioStream)CoreStream.Clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TSGraphicsStream : TSStream
|
|
||||||
{
|
|
||||||
public TSGraphicsStream()
|
|
||||||
{
|
|
||||||
IsVBR = true;
|
|
||||||
IsInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override TSStream Clone()
|
|
||||||
{
|
|
||||||
var stream = new TSGraphicsStream();
|
|
||||||
CopyTo(stream);
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TSTextStream : TSStream
|
|
||||||
{
|
|
||||||
public TSTextStream()
|
|
||||||
{
|
|
||||||
IsVBR = true;
|
|
||||||
IsInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override TSStream Clone()
|
|
||||||
{
|
|
||||||
var stream = new TSTextStream();
|
|
||||||
CopyTo(stream);
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public class TSStreamBuffer
|
|
||||||
{
|
|
||||||
private MemoryStream Stream = new MemoryStream();
|
|
||||||
private int SkipBits = 0;
|
|
||||||
private byte[] Buffer;
|
|
||||||
private int BufferLength = 0;
|
|
||||||
public int TransferLength = 0;
|
|
||||||
|
|
||||||
public TSStreamBuffer()
|
|
||||||
{
|
|
||||||
Buffer = new byte[4096];
|
|
||||||
Stream = new MemoryStream(Buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long Length => (long)BufferLength;
|
|
||||||
|
|
||||||
public long Position => Stream.Position;
|
|
||||||
|
|
||||||
public void Add(
|
|
||||||
byte[] buffer,
|
|
||||||
int offset,
|
|
||||||
int length)
|
|
||||||
{
|
|
||||||
TransferLength += length;
|
|
||||||
|
|
||||||
if (BufferLength + length >= Buffer.Length)
|
|
||||||
{
|
|
||||||
length = Buffer.Length - BufferLength;
|
|
||||||
}
|
|
||||||
if (length > 0)
|
|
||||||
{
|
|
||||||
Array.Copy(buffer, offset, Buffer, BufferLength, length);
|
|
||||||
BufferLength += length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Seek(
|
|
||||||
long offset,
|
|
||||||
SeekOrigin loc)
|
|
||||||
{
|
|
||||||
Stream.Seek(offset, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
BufferLength = 0;
|
|
||||||
TransferLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BeginRead()
|
|
||||||
{
|
|
||||||
SkipBits = 0;
|
|
||||||
Stream.Seek(0, SeekOrigin.Begin);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndRead()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] ReadBytes(int bytes)
|
|
||||||
{
|
|
||||||
if (Stream.Position + bytes >= BufferLength)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] value = new byte[bytes];
|
|
||||||
Stream.Read(value, 0, bytes);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte ReadByte()
|
|
||||||
{
|
|
||||||
return (byte)Stream.ReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ReadBits(int bits)
|
|
||||||
{
|
|
||||||
long pos = Stream.Position;
|
|
||||||
|
|
||||||
int shift = 24;
|
|
||||||
int data = 0;
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
if (pos + i >= BufferLength) break;
|
|
||||||
data += (Stream.ReadByte() << shift);
|
|
||||||
shift -= 8;
|
|
||||||
}
|
|
||||||
var vector = new BitVector32(data);
|
|
||||||
|
|
||||||
int value = 0;
|
|
||||||
for (int i = SkipBits; i < SkipBits + bits; i++)
|
|
||||||
{
|
|
||||||
value <<= 1;
|
|
||||||
value += (vector[1 << (32 - i - 1)] ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkipBits += bits;
|
|
||||||
Stream.Seek(pos + (SkipBits >> 3), SeekOrigin.Begin);
|
|
||||||
SkipBits = SkipBits % 8;
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public class TSStreamClip
|
|
||||||
{
|
|
||||||
public int AngleIndex = 0;
|
|
||||||
public string Name;
|
|
||||||
public double TimeIn;
|
|
||||||
public double TimeOut;
|
|
||||||
public double RelativeTimeIn;
|
|
||||||
public double RelativeTimeOut;
|
|
||||||
public double Length;
|
|
||||||
|
|
||||||
public ulong FileSize = 0;
|
|
||||||
public ulong InterleavedFileSize = 0;
|
|
||||||
public ulong PayloadBytes = 0;
|
|
||||||
public ulong PacketCount = 0;
|
|
||||||
public double PacketSeconds = 0;
|
|
||||||
|
|
||||||
public List<double> Chapters = new List<double>();
|
|
||||||
|
|
||||||
public TSStreamFile StreamFile = null;
|
|
||||||
public TSStreamClipFile StreamClipFile = null;
|
|
||||||
|
|
||||||
public TSStreamClip(
|
|
||||||
TSStreamFile streamFile,
|
|
||||||
TSStreamClipFile streamClipFile)
|
|
||||||
{
|
|
||||||
if (streamFile != null)
|
|
||||||
{
|
|
||||||
Name = streamFile.Name;
|
|
||||||
StreamFile = streamFile;
|
|
||||||
FileSize = (ulong)StreamFile.FileInfo.Length;
|
|
||||||
if (StreamFile.InterleavedFile != null)
|
|
||||||
{
|
|
||||||
InterleavedFileSize = (ulong)StreamFile.InterleavedFile.FileInfo.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StreamClipFile = streamClipFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DisplayName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (StreamFile != null &&
|
|
||||||
StreamFile.InterleavedFile != null &&
|
|
||||||
BDInfoSettings.EnableSSIF)
|
|
||||||
{
|
|
||||||
return StreamFile.InterleavedFile.Name;
|
|
||||||
}
|
|
||||||
return Name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong PacketSize => PacketCount * 192;
|
|
||||||
|
|
||||||
public ulong PacketBitRate
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (PacketSeconds > 0)
|
|
||||||
{
|
|
||||||
return (ulong)Math.Round(((PacketSize * 8.0) / PacketSeconds));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCompatible(TSStreamClip clip)
|
|
||||||
{
|
|
||||||
foreach (var stream1 in StreamFile.Streams.Values)
|
|
||||||
{
|
|
||||||
if (clip.StreamFile.Streams.ContainsKey(stream1.PID))
|
|
||||||
{
|
|
||||||
var stream2 = clip.StreamFile.Streams[stream1.PID];
|
|
||||||
if (stream1.StreamType != stream2.StreamType)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,244 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
// BDInfo - Blu-ray Video and Audio Analysis Tool
|
|
||||||
// Copyright © 2010 Cinema Squid
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
#undef DEBUG
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
|
|
||||||
namespace BDInfo
|
|
||||||
{
|
|
||||||
public class TSStreamClipFile
|
|
||||||
{
|
|
||||||
public FileSystemMetadata FileInfo = null;
|
|
||||||
public string FileType = null;
|
|
||||||
public bool IsValid = false;
|
|
||||||
public string Name = null;
|
|
||||||
|
|
||||||
public Dictionary<ushort, TSStream> Streams =
|
|
||||||
new Dictionary<ushort, TSStream>();
|
|
||||||
|
|
||||||
public TSStreamClipFile(FileSystemMetadata fileInfo)
|
|
||||||
{
|
|
||||||
FileInfo = fileInfo;
|
|
||||||
Name = fileInfo.Name.ToUpper();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Scan()
|
|
||||||
{
|
|
||||||
Stream fileStream = null;
|
|
||||||
BinaryReader fileReader = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
Debug.WriteLine(string.Format(
|
|
||||||
"Scanning {0}...", Name));
|
|
||||||
#endif
|
|
||||||
Streams.Clear();
|
|
||||||
|
|
||||||
fileStream = File.OpenRead(FileInfo.FullName);
|
|
||||||
fileReader = new BinaryReader(fileStream);
|
|
||||||
|
|
||||||
byte[] data = new byte[fileStream.Length];
|
|
||||||
fileReader.Read(data, 0, data.Length);
|
|
||||||
|
|
||||||
byte[] fileType = new byte[8];
|
|
||||||
Array.Copy(data, 0, fileType, 0, fileType.Length);
|
|
||||||
|
|
||||||
FileType = Encoding.ASCII.GetString(fileType, 0, fileType.Length);
|
|
||||||
if (FileType != "HDMV0100" &&
|
|
||||||
FileType != "HDMV0200")
|
|
||||||
{
|
|
||||||
throw new Exception(string.Format(
|
|
||||||
"Clip info file {0} has an unknown file type {1}.",
|
|
||||||
FileInfo.Name, FileType));
|
|
||||||
}
|
|
||||||
#if DEBUG
|
|
||||||
Debug.WriteLine(string.Format(
|
|
||||||
"\tFileType: {0}", FileType));
|
|
||||||
#endif
|
|
||||||
int clipIndex =
|
|
||||||
((int)data[12] << 24) +
|
|
||||||
((int)data[13] << 16) +
|
|
||||||
((int)data[14] << 8) +
|
|
||||||
((int)data[15]);
|
|
||||||
|
|
||||||
int clipLength =
|
|
||||||
((int)data[clipIndex] << 24) +
|
|
||||||
((int)data[clipIndex + 1] << 16) +
|
|
||||||
((int)data[clipIndex + 2] << 8) +
|
|
||||||
((int)data[clipIndex + 3]);
|
|
||||||
|
|
||||||
byte[] clipData = new byte[clipLength];
|
|
||||||
Array.Copy(data, clipIndex + 4, clipData, 0, clipData.Length);
|
|
||||||
|
|
||||||
int streamCount = clipData[8];
|
|
||||||
#if DEBUG
|
|
||||||
Debug.WriteLine(string.Format(
|
|
||||||
"\tStreamCount: {0}", streamCount));
|
|
||||||
#endif
|
|
||||||
int streamOffset = 10;
|
|
||||||
for (int streamIndex = 0;
|
|
||||||
streamIndex < streamCount;
|
|
||||||
streamIndex++)
|
|
||||||
{
|
|
||||||
TSStream stream = null;
|
|
||||||
|
|
||||||
ushort PID = (ushort)
|
|
||||||
((clipData[streamOffset] << 8) +
|
|
||||||
clipData[streamOffset + 1]);
|
|
||||||
|
|
||||||
streamOffset += 2;
|
|
||||||
|
|
||||||
var streamType = (TSStreamType)
|
|
||||||
clipData[streamOffset + 1];
|
|
||||||
switch (streamType)
|
|
||||||
{
|
|
||||||
case TSStreamType.MVC_VIDEO:
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TSStreamType.AVC_VIDEO:
|
|
||||||
case TSStreamType.MPEG1_VIDEO:
|
|
||||||
case TSStreamType.MPEG2_VIDEO:
|
|
||||||
case TSStreamType.VC1_VIDEO:
|
|
||||||
{
|
|
||||||
var videoFormat = (TSVideoFormat)
|
|
||||||
(clipData[streamOffset + 2] >> 4);
|
|
||||||
var frameRate = (TSFrameRate)
|
|
||||||
(clipData[streamOffset + 2] & 0xF);
|
|
||||||
var aspectRatio = (TSAspectRatio)
|
|
||||||
(clipData[streamOffset + 3] >> 4);
|
|
||||||
|
|
||||||
stream = new TSVideoStream();
|
|
||||||
((TSVideoStream)stream).VideoFormat = videoFormat;
|
|
||||||
((TSVideoStream)stream).AspectRatio = aspectRatio;
|
|
||||||
((TSVideoStream)stream).FrameRate = frameRate;
|
|
||||||
#if DEBUG
|
|
||||||
Debug.WriteLine(string.Format(
|
|
||||||
"\t{0} {1} {2} {3} {4}",
|
|
||||||
PID,
|
|
||||||
streamType,
|
|
||||||
videoFormat,
|
|
||||||
frameRate,
|
|
||||||
aspectRatio));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TSStreamType.AC3_AUDIO:
|
|
||||||
case TSStreamType.AC3_PLUS_AUDIO:
|
|
||||||
case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
|
|
||||||
case TSStreamType.AC3_TRUE_HD_AUDIO:
|
|
||||||
case TSStreamType.DTS_AUDIO:
|
|
||||||
case TSStreamType.DTS_HD_AUDIO:
|
|
||||||
case TSStreamType.DTS_HD_MASTER_AUDIO:
|
|
||||||
case TSStreamType.DTS_HD_SECONDARY_AUDIO:
|
|
||||||
case TSStreamType.LPCM_AUDIO:
|
|
||||||
case TSStreamType.MPEG1_AUDIO:
|
|
||||||
case TSStreamType.MPEG2_AUDIO:
|
|
||||||
{
|
|
||||||
byte[] languageBytes = new byte[3];
|
|
||||||
Array.Copy(clipData, streamOffset + 3,
|
|
||||||
languageBytes, 0, languageBytes.Length);
|
|
||||||
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
|
||||||
|
|
||||||
var channelLayout = (TSChannelLayout)
|
|
||||||
(clipData[streamOffset + 2] >> 4);
|
|
||||||
var sampleRate = (TSSampleRate)
|
|
||||||
(clipData[streamOffset + 2] & 0xF);
|
|
||||||
|
|
||||||
stream = new TSAudioStream();
|
|
||||||
((TSAudioStream)stream).LanguageCode = languageCode;
|
|
||||||
((TSAudioStream)stream).ChannelLayout = channelLayout;
|
|
||||||
((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate);
|
|
||||||
((TSAudioStream)stream).LanguageCode = languageCode;
|
|
||||||
#if DEBUG
|
|
||||||
Debug.WriteLine(string.Format(
|
|
||||||
"\t{0} {1} {2} {3} {4}",
|
|
||||||
PID,
|
|
||||||
streamType,
|
|
||||||
languageCode,
|
|
||||||
channelLayout,
|
|
||||||
sampleRate));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TSStreamType.INTERACTIVE_GRAPHICS:
|
|
||||||
case TSStreamType.PRESENTATION_GRAPHICS:
|
|
||||||
{
|
|
||||||
byte[] languageBytes = new byte[3];
|
|
||||||
Array.Copy(clipData, streamOffset + 2,
|
|
||||||
languageBytes, 0, languageBytes.Length);
|
|
||||||
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
|
||||||
|
|
||||||
stream = new TSGraphicsStream();
|
|
||||||
stream.LanguageCode = languageCode;
|
|
||||||
#if DEBUG
|
|
||||||
Debug.WriteLine(string.Format(
|
|
||||||
"\t{0} {1} {2}",
|
|
||||||
PID,
|
|
||||||
streamType,
|
|
||||||
languageCode));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TSStreamType.SUBTITLE:
|
|
||||||
{
|
|
||||||
byte[] languageBytes = new byte[3];
|
|
||||||
Array.Copy(clipData, streamOffset + 3,
|
|
||||||
languageBytes, 0, languageBytes.Length);
|
|
||||||
string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
|
|
||||||
#if DEBUG
|
|
||||||
Debug.WriteLine(string.Format(
|
|
||||||
"\t{0} {1} {2}",
|
|
||||||
PID,
|
|
||||||
streamType,
|
|
||||||
languageCode));
|
|
||||||
#endif
|
|
||||||
stream = new TSTextStream();
|
|
||||||
stream.LanguageCode = languageCode;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream != null)
|
|
||||||
{
|
|
||||||
stream.PID = PID;
|
|
||||||
stream.StreamType = streamType;
|
|
||||||
Streams.Add(PID, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
streamOffset += clipData[streamOffset] + 1;
|
|
||||||
}
|
|
||||||
IsValid = true;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (fileReader != null) fileReader.Dispose();
|
|
||||||
if (fileStream != null) fileStream.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,8 @@
|
||||||
- [fhriley](https://github.com/fhriley)
|
- [fhriley](https://github.com/fhriley)
|
||||||
- [nevado](https://github.com/nevado)
|
- [nevado](https://github.com/nevado)
|
||||||
- [mark-monteiro](https://github.com/mark-monteiro)
|
- [mark-monteiro](https://github.com/mark-monteiro)
|
||||||
|
- [ullmie02](https://github.com/ullmie02)
|
||||||
|
- [pR0Ps](https://github.com/pR0Ps)
|
||||||
|
|
||||||
# Emby Contributors
|
# Emby Contributors
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
ARG DOTNET_VERSION=3.0
|
ARG DOTNET_VERSION=3.1
|
||||||
ARG FFMPEG_VERSION=latest
|
ARG FFMPEG_VERSION=latest
|
||||||
|
|
||||||
FROM node:alpine as web-builder
|
FROM node:alpine as web-builder
|
||||||
|
@ -14,7 +14,9 @@ FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION}-buster as builder
|
||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
# because of changes in docker and systemd we need to not build in parallel at the moment
|
||||||
|
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
|
||||||
|
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
||||||
|
|
||||||
FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
|
FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
|
||||||
FROM debian:buster-slim
|
FROM debian:buster-slim
|
||||||
|
@ -29,7 +31,7 @@ COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||||
# mesa-va-drivers: needed for VAAPI
|
# mesa-va-drivers: needed for VAAPI
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
||||||
libfontconfig1 libgomp1 libva-drm2 mesa-va-drivers openssl \
|
libfontconfig1 libgomp1 libva-drm2 mesa-va-drivers openssl ca-certificates \
|
||||||
&& apt-get clean autoclean \
|
&& apt-get clean autoclean \
|
||||||
&& apt-get autoremove \
|
&& apt-get autoremove \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# Requires binfm_misc registration
|
ARG DOTNET_VERSION=3.1
|
||||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
|
||||||
ARG DOTNET_VERSION=3.0
|
|
||||||
|
|
||||||
|
|
||||||
FROM node:alpine as web-builder
|
FROM node:alpine as web-builder
|
||||||
|
@ -23,11 +21,10 @@ RUN find . -type d -name obj | xargs -r rm -r
|
||||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
||||||
|
|
||||||
|
|
||||||
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
FROM debian:buster-slim
|
||||||
FROM debian:stretch-slim-arm32v7
|
|
||||||
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||||
|
libssl-dev ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& mkdir -p /cache /config /media \
|
&& mkdir -p /cache /config /media \
|
||||||
&& chmod 777 /cache /config /media
|
&& chmod 777 /cache /config /media
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# Requires binfm_misc registration
|
ARG DOTNET_VERSION=3.1
|
||||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
|
||||||
ARG DOTNET_VERSION=3.0
|
|
||||||
|
|
||||||
|
|
||||||
FROM node:alpine as web-builder
|
FROM node:alpine as web-builder
|
||||||
|
@ -23,11 +21,10 @@ RUN find . -type d -name obj | xargs -r rm -r
|
||||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
|
||||||
|
|
||||||
|
|
||||||
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
FROM debian:buster-slim
|
||||||
FROM debian:stretch-slim-arm64v8
|
|
||||||
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||||
|
libssl-dev ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& mkdir -p /cache /config /media \
|
&& mkdir -p /cache /config /media \
|
||||||
&& chmod 777 /cache /config /media
|
&& chmod 777 /cache /config /media
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace DvdLib.Ifo
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (var vmgFs = _fileSystem.GetFileStream(vmgPath.FullName, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
using (var vmgFs = new FileStream(vmgPath.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||||
{
|
{
|
||||||
using (var vmgRead = new BigEndianBinaryReader(vmgFs))
|
using (var vmgRead = new BigEndianBinaryReader(vmgFs))
|
||||||
{
|
{
|
||||||
|
@ -95,7 +95,7 @@ namespace DvdLib.Ifo
|
||||||
{
|
{
|
||||||
VTSPaths[vtsNum] = vtsPath;
|
VTSPaths[vtsNum] = vtsPath;
|
||||||
|
|
||||||
using (var vtsFs = _fileSystem.GetFileStream(vtsPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
using (var vtsFs = new FileStream(vtsPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||||
{
|
{
|
||||||
using (var vtsRead = new BigEndianBinaryReader(vtsFs))
|
using (var vtsRead = new BigEndianBinaryReader(vtsFs))
|
||||||
{
|
{
|
||||||
|
|
|
@ -170,32 +170,32 @@ namespace Emby.Dlna.Api
|
||||||
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
return _resultFactory.GetResult(Request, xml, XMLContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Post(ProcessMediaReceiverRegistrarControlRequest request)
|
public async Task<object> Post(ProcessMediaReceiverRegistrarControlRequest request)
|
||||||
{
|
{
|
||||||
var response = PostAsync(request.RequestStream, MediaReceiverRegistrar);
|
var response = await PostAsync(request.RequestStream, MediaReceiverRegistrar).ConfigureAwait(false);
|
||||||
|
|
||||||
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Post(ProcessContentDirectoryControlRequest request)
|
public async Task<object> Post(ProcessContentDirectoryControlRequest request)
|
||||||
{
|
{
|
||||||
var response = PostAsync(request.RequestStream, ContentDirectory);
|
var response = await PostAsync(request.RequestStream, ContentDirectory).ConfigureAwait(false);
|
||||||
|
|
||||||
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Post(ProcessConnectionManagerControlRequest request)
|
public async Task<object> Post(ProcessConnectionManagerControlRequest request)
|
||||||
{
|
{
|
||||||
var response = PostAsync(request.RequestStream, ConnectionManager);
|
var response = await PostAsync(request.RequestStream, ConnectionManager).ConfigureAwait(false);
|
||||||
|
|
||||||
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ControlResponse PostAsync(Stream requestStream, IUpnpService service)
|
private Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
|
||||||
{
|
{
|
||||||
var id = GetPathValue(2).ToString();
|
var id = GetPathValue(2).ToString();
|
||||||
|
|
||||||
return service.ProcessControlRequest(new ControlRequest
|
return service.ProcessControlRequestAsync(new ControlRequest
|
||||||
{
|
{
|
||||||
Headers = Request.Headers,
|
Headers = Request.Headers,
|
||||||
InputXml = requestStream,
|
InputXml = requestStream,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna.Service;
|
using Emby.Dlna.Service;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
@ -20,17 +21,19 @@ namespace Emby.Dlna.ConnectionManager
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string GetServiceXml()
|
public string GetServiceXml()
|
||||||
{
|
{
|
||||||
return new ConnectionManagerXmlBuilder().GetXml();
|
return new ConnectionManagerXmlBuilder().GetXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
/// <inheritdoc />
|
||||||
|
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
|
||||||
{
|
{
|
||||||
var profile = _dlna.GetProfile(request.Headers) ??
|
var profile = _dlna.GetProfile(request.Headers) ??
|
||||||
_dlna.GetDefaultProfile();
|
_dlna.GetDefaultProfile();
|
||||||
|
|
||||||
return new ControlHandler(_config, _logger, profile).ProcessControlRequest(request);
|
return new ControlHandler(_config, _logger, profile).ProcessControlRequestAsync(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna.Service;
|
using Emby.Dlna.Service;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
@ -66,12 +67,14 @@ namespace Emby.Dlna.ContentDirectory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string GetServiceXml()
|
public string GetServiceXml()
|
||||||
{
|
{
|
||||||
return new ContentDirectoryXmlBuilder().GetXml();
|
return new ContentDirectoryXmlBuilder().GetXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
/// <inheritdoc />
|
||||||
|
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
|
||||||
{
|
{
|
||||||
var profile = _dlna.GetProfile(request.Headers) ??
|
var profile = _dlna.GetProfile(request.Headers) ??
|
||||||
_dlna.GetDefaultProfile();
|
_dlna.GetDefaultProfile();
|
||||||
|
@ -96,7 +99,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||||
_userViewManager,
|
_userViewManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
_tvSeriesManager)
|
_tvSeriesManager)
|
||||||
.ProcessControlRequest(request);
|
.ProcessControlRequestAsync(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
private User GetUser(DeviceProfile profile)
|
private User GetUser(DeviceProfile profile)
|
||||||
|
|
|
@ -76,7 +76,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, mediaEncoder);
|
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, mediaEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
|
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
|
||||||
|
@ -771,11 +771,11 @@ namespace Emby.Dlna.ContentDirectory
|
||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return new QueryResult<ServerItem>
|
return ApplyPaging(new QueryResult<ServerItem>
|
||||||
{
|
{
|
||||||
Items = folders,
|
Items = folders,
|
||||||
TotalRecordCount = folders.Length
|
TotalRecordCount = folders.Length
|
||||||
};
|
}, startIndex, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
|
private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
|
||||||
|
@ -1336,7 +1336,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
|
Logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
|
||||||
|
|
||||||
return new ServerItem(_libraryManager.GetUserRootFolder());
|
return new ServerItem(_libraryManager.GetUserRootFolder());
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Emby.Dlna.Didl
|
||||||
|
|
||||||
public Filter(string filter)
|
public Filter(string filter)
|
||||||
{
|
{
|
||||||
_all = StringHelper.EqualsIgnoreCase(filter, "*");
|
_all = string.Equals(filter, "*", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
_fields = (filter ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
_fields = (filter ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
}
|
}
|
||||||
|
|
|
@ -385,7 +385,7 @@ namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(systemProfilesPath);
|
Directory.CreateDirectory(systemProfilesPath);
|
||||||
|
|
||||||
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||||
{
|
{
|
||||||
await stream.CopyToAsync(fileStream);
|
await stream.CopyToAsync(fileStream);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,25 +29,15 @@ namespace Emby.Dlna.Eventing
|
||||||
{
|
{
|
||||||
var subscription = GetSubscription(subscriptionId, false);
|
var subscription = GetSubscription(subscriptionId, false);
|
||||||
|
|
||||||
int timeoutSeconds;
|
subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
|
||||||
|
int timeoutSeconds = subscription.TimeoutSeconds;
|
||||||
|
subscription.SubscriptionTime = DateTime.UtcNow;
|
||||||
|
|
||||||
// Remove logging for now because some devices are sending this very frequently
|
_logger.LogDebug(
|
||||||
// TODO re-enable with dlna debug logging setting
|
"Renewing event subscription for {0} with timeout of {1} to {2}",
|
||||||
//_logger.LogDebug("Renewing event subscription for {0} with timeout of {1} to {2}",
|
subscription.NotificationType,
|
||||||
// subscription.NotificationType,
|
timeoutSeconds,
|
||||||
// timeout,
|
subscription.CallbackUrl);
|
||||||
// subscription.CallbackUrl);
|
|
||||||
|
|
||||||
if (subscription != null)
|
|
||||||
{
|
|
||||||
subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
|
|
||||||
timeoutSeconds = subscription.TimeoutSeconds;
|
|
||||||
subscription.SubscriptionTime = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timeoutSeconds = 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds);
|
return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds);
|
||||||
}
|
}
|
||||||
|
@ -57,12 +47,10 @@ namespace Emby.Dlna.Eventing
|
||||||
var timeout = ParseTimeout(requestedTimeoutString) ?? 300;
|
var timeout = ParseTimeout(requestedTimeoutString) ?? 300;
|
||||||
var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
// Remove logging for now because some devices are sending this very frequently
|
_logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}",
|
||||||
// TODO re-enable with dlna debug logging setting
|
notificationType,
|
||||||
//_logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}",
|
timeout,
|
||||||
// notificationType,
|
callbackUrl);
|
||||||
// timeout,
|
|
||||||
// callbackUrl);
|
|
||||||
|
|
||||||
_subscriptions.TryAdd(id, new EventSubscription
|
_subscriptions.TryAdd(id, new EventSubscription
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Emby.Dlna
|
namespace Emby.Dlna
|
||||||
{
|
{
|
||||||
public interface IUpnpService
|
public interface IUpnpService
|
||||||
|
@ -13,6 +15,6 @@ namespace Emby.Dlna
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <returns>ControlResponse.</returns>
|
/// <returns>ControlResponse.</returns>
|
||||||
ControlResponse ProcessControlRequest(ControlRequest request);
|
Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna.Service;
|
using Emby.Dlna.Service;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
@ -15,17 +16,19 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string GetServiceXml()
|
public string GetServiceXml()
|
||||||
{
|
{
|
||||||
return new MediaReceiverRegistrarXmlBuilder().GetXml();
|
return new MediaReceiverRegistrarXmlBuilder().GetXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
/// <inheritdoc />
|
||||||
|
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
|
||||||
{
|
{
|
||||||
return new ControlHandler(
|
return new ControlHandler(
|
||||||
_config,
|
_config,
|
||||||
Logger)
|
Logger)
|
||||||
.ProcessControlRequest(request);
|
.ProcessControlRequestAsync(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna.Didl;
|
using Emby.Dlna.Didl;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
|
|
@ -5,7 +5,6 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Emby.Dlna.Common;
|
using Emby.Dlna.Common;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
|
|
||||||
namespace Emby.Dlna.Server
|
namespace Emby.Dlna.Server
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Emby.Dlna.Didl;
|
using Emby.Dlna.Didl;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
@ -15,44 +15,34 @@ 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 readonly IServerConfigurationManager Config;
|
protected IServerConfigurationManager Config { get; }
|
||||||
protected readonly ILogger _logger;
|
protected ILogger Logger { get; }
|
||||||
|
|
||||||
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
|
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
|
||||||
{
|
{
|
||||||
Config = config;
|
Config = config;
|
||||||
_logger = logger;
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
public async Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLog;
|
LogRequest(request);
|
||||||
|
|
||||||
if (enableDebugLogging)
|
|
||||||
{
|
|
||||||
LogRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = ProcessControlRequestInternal(request);
|
|
||||||
|
|
||||||
if (enableDebugLogging)
|
|
||||||
{
|
|
||||||
LogResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var response = await ProcessControlRequestInternalAsync(request).ConfigureAwait(false);
|
||||||
|
LogResponse(response);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error processing control request");
|
Logger.LogError(ex, "Error processing control request");
|
||||||
|
|
||||||
return new ControlErrorHandler().GetResponse(ex);
|
return ControlErrorHandler.GetResponse(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ControlResponse ProcessControlRequestInternal(ControlRequest request)
|
private async Task<ControlResponse> ProcessControlRequestInternalAsync(ControlRequest request)
|
||||||
{
|
{
|
||||||
ControlRequestInfo requestInfo = null;
|
ControlRequestInfo requestInfo = null;
|
||||||
|
|
||||||
|
@ -63,16 +53,17 @@ namespace Emby.Dlna.Service
|
||||||
ValidationType = ValidationType.None,
|
ValidationType = ValidationType.None,
|
||||||
CheckCharacters = false,
|
CheckCharacters = false,
|
||||||
IgnoreProcessingInstructions = true,
|
IgnoreProcessingInstructions = true,
|
||||||
IgnoreComments = true
|
IgnoreComments = true,
|
||||||
|
Async = true
|
||||||
};
|
};
|
||||||
|
|
||||||
using (var reader = XmlReader.Create(streamReader, readerSettings))
|
using (var reader = XmlReader.Create(streamReader, readerSettings))
|
||||||
{
|
{
|
||||||
requestInfo = ParseRequest(reader);
|
requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug("Received control request {0}", requestInfo.LocalName);
|
Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
|
||||||
|
|
||||||
var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
|
var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
|
||||||
|
|
||||||
|
@ -114,17 +105,15 @@ namespace Emby.Dlna.Service
|
||||||
IsSuccessful = true
|
IsSuccessful = true
|
||||||
};
|
};
|
||||||
|
|
||||||
//logger.LogDebug(xml);
|
|
||||||
|
|
||||||
controlResponse.Headers.Add("EXT", string.Empty);
|
controlResponse.Headers.Add("EXT", string.Empty);
|
||||||
|
|
||||||
return controlResponse;
|
return controlResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ControlRequestInfo ParseRequest(XmlReader reader)
|
private async Task<ControlRequestInfo> ParseRequestAsync(XmlReader reader)
|
||||||
{
|
{
|
||||||
reader.MoveToContent();
|
await reader.MoveToContentAsync().ConfigureAwait(false);
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
// Loop through each element
|
// Loop through each element
|
||||||
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
||||||
|
@ -139,37 +128,38 @@ namespace Emby.Dlna.Service
|
||||||
{
|
{
|
||||||
using (var subReader = reader.ReadSubtree())
|
using (var subReader = reader.ReadSubtree())
|
||||||
{
|
{
|
||||||
return ParseBodyTag(subReader);
|
return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
reader.Skip();
|
await reader.SkipAsync().ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ControlRequestInfo();
|
return new ControlRequestInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ControlRequestInfo ParseBodyTag(XmlReader reader)
|
private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader)
|
||||||
{
|
{
|
||||||
var result = new ControlRequestInfo();
|
var result = new ControlRequestInfo();
|
||||||
|
|
||||||
reader.MoveToContent();
|
await reader.MoveToContentAsync().ConfigureAwait(false);
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
// Loop through each element
|
// Loop through each element
|
||||||
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
||||||
|
@ -183,28 +173,28 @@ namespace Emby.Dlna.Service
|
||||||
{
|
{
|
||||||
using (var subReader = reader.ReadSubtree())
|
using (var subReader = reader.ReadSubtree())
|
||||||
{
|
{
|
||||||
ParseFirstBodyChild(subReader, result.Headers);
|
await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseFirstBodyChild(XmlReader reader, IDictionary<string, string> headers)
|
private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary<string, string> headers)
|
||||||
{
|
{
|
||||||
reader.MoveToContent();
|
await reader.MoveToContentAsync().ConfigureAwait(false);
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
// Loop through each element
|
// Loop through each element
|
||||||
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
||||||
|
@ -212,20 +202,20 @@ namespace Emby.Dlna.Service
|
||||||
if (reader.NodeType == XmlNodeType.Element)
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
{
|
{
|
||||||
// TODO: Should we be doing this here, or should it be handled earlier when decoding the request?
|
// TODO: Should we be doing this here, or should it be handled earlier when decoding the request?
|
||||||
headers[reader.LocalName.RemoveDiacritics()] = reader.ReadElementContentAsString();
|
headers[reader.LocalName.RemoveDiacritics()] = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reader.Read();
|
await reader.ReadAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ControlRequestInfo
|
private class ControlRequestInfo
|
||||||
{
|
{
|
||||||
public string LocalName;
|
public string LocalName { get; set; }
|
||||||
public string NamespaceURI;
|
public string NamespaceURI { get; set; }
|
||||||
public IDictionary<string, string> Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
|
protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
|
||||||
|
@ -237,10 +227,7 @@ namespace Emby.Dlna.Service
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var originalHeaders = request.Headers;
|
Logger.LogDebug("Control request. Headers: {@Headers}", request.Headers);
|
||||||
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
|
|
||||||
|
|
||||||
_logger.LogDebug("Control request. Headers: {0}", headers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogResponse(ControlResponse response)
|
private void LogResponse(ControlResponse response)
|
||||||
|
@ -250,11 +237,7 @@ namespace Emby.Dlna.Service
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var originalHeaders = response.Headers;
|
Logger.LogDebug("Control response. Headers: {@Headers}\n{Xml}", response.Headers, response.Xml);
|
||||||
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
|
|
||||||
//builder.Append(response.Xml);
|
|
||||||
|
|
||||||
_logger.LogDebug("Control response. Headers: {0}", headers);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ using Emby.Dlna.Didl;
|
||||||
|
|
||||||
namespace Emby.Dlna.Service
|
namespace Emby.Dlna.Service
|
||||||
{
|
{
|
||||||
public class ControlErrorHandler
|
public static class ControlErrorHandler
|
||||||
{
|
{
|
||||||
private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
|
private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
|
||||||
|
|
||||||
public ControlResponse GetResponse(Exception ex)
|
public static ControlResponse GetResponse(Exception ex)
|
||||||
{
|
{
|
||||||
var settings = new XmlWriterSettings
|
var settings = new XmlWriterSettings
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,6 @@ using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -129,7 +128,7 @@ namespace Emby.Drawing
|
||||||
{
|
{
|
||||||
var file = await ProcessImage(options).ConfigureAwait(false);
|
var file = await ProcessImage(options).ConfigureAwait(false);
|
||||||
|
|
||||||
using (var fileStream = _fileSystem.GetFileStream(file.Item1, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true))
|
using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, true))
|
||||||
{
|
{
|
||||||
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
|
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.Audio
|
namespace Emby.Naming.Audio
|
||||||
{
|
{
|
||||||
public class MultiPartResult
|
public class MultiPartResult
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.AudioBook
|
namespace Emby.Naming.AudioBook
|
||||||
{
|
{
|
||||||
public class AudioBookFilePathParserResult
|
public class AudioBookFilePathParserResult
|
||||||
|
|
|
@ -7,6 +7,9 @@ namespace Emby.Naming.AudioBook
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioBookInfo
|
public class AudioBookInfo
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AudioBookInfo" /> class.
|
||||||
|
/// </summary>
|
||||||
public AudioBookInfo()
|
public AudioBookInfo()
|
||||||
{
|
{
|
||||||
Files = new List<AudioBookFileInfo>();
|
Files = new List<AudioBookFileInfo>();
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.Common
|
namespace Emby.Naming.Common
|
||||||
{
|
{
|
||||||
public enum MediaType
|
public enum MediaType
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Emby.Naming.Video;
|
using Emby.Naming.Video;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
namespace Emby.Naming.Common
|
namespace Emby.Naming.Common
|
||||||
{
|
{
|
||||||
|
@ -173,13 +177,12 @@ namespace Emby.Naming.Common
|
||||||
|
|
||||||
CleanDateTimes = new[]
|
CleanDateTimes = new[]
|
||||||
{
|
{
|
||||||
@"(.+[^ _\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9][0-9]|20[0-1][0-9])([ _\,\.\(\)\[\]\-][^0-9]|$)"
|
@"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19\d{2}|20\d{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19\d{2}|20\d{2})*"
|
||||||
};
|
};
|
||||||
|
|
||||||
CleanStrings = new[]
|
CleanStrings = new[]
|
||||||
{
|
{
|
||||||
@"[ _\,\.\(\)\[\]\-](ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
|
@"[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
|
||||||
@"[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
|
|
||||||
@"(\[.*\])"
|
@"(\[.*\])"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -336,7 +339,7 @@ namespace Emby.Naming.Common
|
||||||
|
|
||||||
// *** End Kodi Standard Naming
|
// *** End Kodi Standard Naming
|
||||||
|
|
||||||
// [bar] Foo - 1 [baz]
|
// [bar] Foo - 1 [baz]
|
||||||
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[-\s_]+(?<epnumber>\d+).*$")
|
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[-\s_]+(?<epnumber>\d+).*$")
|
||||||
{
|
{
|
||||||
IsNamed = true
|
IsNamed = true
|
||||||
|
@ -420,126 +423,126 @@ namespace Emby.Naming.Common
|
||||||
{
|
{
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "trailer",
|
ExtraType = ExtraType.Trailer,
|
||||||
RuleType = ExtraRuleType.Filename,
|
RuleType = ExtraRuleType.Filename,
|
||||||
Token = "trailer",
|
Token = "trailer",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "trailer",
|
ExtraType = ExtraType.Trailer,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-trailer",
|
Token = "-trailer",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "trailer",
|
ExtraType = ExtraType.Trailer,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = ".trailer",
|
Token = ".trailer",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "trailer",
|
ExtraType = ExtraType.Trailer,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "_trailer",
|
Token = "_trailer",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "trailer",
|
ExtraType = ExtraType.Trailer,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = " trailer",
|
Token = " trailer",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "sample",
|
ExtraType = ExtraType.Sample,
|
||||||
RuleType = ExtraRuleType.Filename,
|
RuleType = ExtraRuleType.Filename,
|
||||||
Token = "sample",
|
Token = "sample",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "sample",
|
ExtraType = ExtraType.Sample,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-sample",
|
Token = "-sample",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "sample",
|
ExtraType = ExtraType.Sample,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = ".sample",
|
Token = ".sample",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "sample",
|
ExtraType = ExtraType.Sample,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "_sample",
|
Token = "_sample",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "sample",
|
ExtraType = ExtraType.Sample,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = " sample",
|
Token = " sample",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "themesong",
|
ExtraType = ExtraType.ThemeSong,
|
||||||
RuleType = ExtraRuleType.Filename,
|
RuleType = ExtraRuleType.Filename,
|
||||||
Token = "theme",
|
Token = "theme",
|
||||||
MediaType = MediaType.Audio
|
MediaType = MediaType.Audio
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "scene",
|
ExtraType = ExtraType.Scene,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-scene",
|
Token = "-scene",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "clip",
|
ExtraType = ExtraType.Clip,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-clip",
|
Token = "-clip",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "interview",
|
ExtraType = ExtraType.Interview,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-interview",
|
Token = "-interview",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "behindthescenes",
|
ExtraType = ExtraType.BehindTheScenes,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-behindthescenes",
|
Token = "-behindthescenes",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "deletedscene",
|
ExtraType = ExtraType.DeletedScene,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-deleted",
|
Token = "-deleted",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "featurette",
|
ExtraType = ExtraType.Clip,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-featurette",
|
Token = "-featurette",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
},
|
},
|
||||||
new ExtraRule
|
new ExtraRule
|
||||||
{
|
{
|
||||||
ExtraType = "short",
|
ExtraType = ExtraType.Clip,
|
||||||
RuleType = ExtraRuleType.Suffix,
|
RuleType = ExtraRuleType.Suffix,
|
||||||
Token = "-short",
|
Token = "-short",
|
||||||
MediaType = MediaType.Video
|
MediaType = MediaType.Video
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' " >true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -21,9 +22,9 @@
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Code analysers-->
|
<!-- Code Analyzers-->
|
||||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
|
||||||
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.Subtitles
|
namespace Emby.Naming.Subtitles
|
||||||
{
|
{
|
||||||
public class SubtitleInfo
|
public class SubtitleInfo
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -28,7 +31,6 @@ namespace Emby.Naming.Subtitles
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags = GetFlags(path);
|
var flags = GetFlags(path);
|
||||||
|
|
||||||
var info = new SubtitleInfo
|
var info = new SubtitleInfo
|
||||||
{
|
{
|
||||||
Path = path,
|
Path = path,
|
||||||
|
@ -42,7 +44,7 @@ namespace Emby.Naming.Subtitles
|
||||||
// Should have a name, language and file extension
|
// Should have a name, language and file extension
|
||||||
if (parts.Count >= 3)
|
if (parts.Count >= 3)
|
||||||
{
|
{
|
||||||
info.Language = parts[parts.Count - 2];
|
info.Language = parts[^2];
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.TV
|
namespace Emby.Naming.TV
|
||||||
{
|
{
|
||||||
public class EpisodeInfo
|
public class EpisodeInfo
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
@ -128,7 +131,7 @@ namespace Emby.Naming.TV
|
||||||
var endingNumberGroup = match.Groups["endingepnumber"];
|
var endingNumberGroup = match.Groups["endingepnumber"];
|
||||||
if (endingNumberGroup.Success)
|
if (endingNumberGroup.Success)
|
||||||
{
|
{
|
||||||
// Will only set EndingEpsiodeNumber if the captured number is not followed by additional numbers
|
// Will only set EndingEpisodeNumber if the captured number is not followed by additional numbers
|
||||||
// or a 'p' or 'i' as what you would get with a pixel resolution specification.
|
// or a 'p' or 'i' as what you would get with a pixel resolution specification.
|
||||||
// It avoids erroneous parsing of something like "series-s09e14-1080p.mkv" as a multi-episode from E14 to E108
|
// It avoids erroneous parsing of something like "series-s09e14-1080p.mkv" as a multi-episode from E14 to E108
|
||||||
int nextIndex = endingNumberGroup.Index + endingNumberGroup.Length;
|
int nextIndex = endingNumberGroup.Index + endingNumberGroup.Length;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.TV
|
namespace Emby.Naming.TV
|
||||||
{
|
{
|
||||||
public class EpisodePathParserResult
|
public class EpisodePathParserResult
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.TV
|
namespace Emby.Naming.TV
|
||||||
{
|
{
|
||||||
public class SeasonPathParserResult
|
public class SeasonPathParserResult
|
||||||
|
|
|
@ -1,86 +1,48 @@
|
||||||
using System;
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Emby.Naming.Common;
|
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see href="http://kodi.wiki/view/Advancedsettings.xml#video" />.
|
/// <see href="http://kodi.wiki/view/Advancedsettings.xml#video" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CleanDateTimeParser
|
public static class CleanDateTimeParser
|
||||||
{
|
{
|
||||||
private readonly NamingOptions _options;
|
public static CleanDateTimeResult Clean(string name, IReadOnlyList<Regex> cleanDateTimeRegexes)
|
||||||
|
|
||||||
public CleanDateTimeParser(NamingOptions options)
|
|
||||||
{
|
{
|
||||||
_options = options;
|
CleanDateTimeResult result = new CleanDateTimeResult(name);
|
||||||
}
|
var len = cleanDateTimeRegexes.Count;
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
public CleanDateTimeResult Clean(string name)
|
|
||||||
{
|
|
||||||
var originalName = name;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var extension = Path.GetExtension(name) ?? string.Empty;
|
if (TryClean(name, cleanDateTimeRegexes[i], ref result))
|
||||||
// Check supported extensions
|
|
||||||
if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)
|
|
||||||
&& !_options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
// Dummy up a file extension because the expressions will fail without one
|
return result;
|
||||||
// This is tricky because we can't just check Path.GetExtension for empty
|
|
||||||
// If the input is "St. Vincent (2014)", it will produce ". Vincent (2014)" as the extension
|
|
||||||
name += ".mkv";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ArgumentException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = _options.CleanDateTimeRegexes.Select(i => Clean(name, i))
|
return result;
|
||||||
.FirstOrDefault(i => i.HasChanged) ??
|
|
||||||
new CleanDateTimeResult { Name = originalName };
|
|
||||||
|
|
||||||
if (result.HasChanged)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a second pass, running clean string first
|
|
||||||
var cleanStringResult = new CleanStringParser().Clean(name, _options.CleanStringRegexes);
|
|
||||||
|
|
||||||
if (!cleanStringResult.HasChanged)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _options.CleanDateTimeRegexes.Select(i => Clean(cleanStringResult.Name, i))
|
|
||||||
.FirstOrDefault(i => i.HasChanged) ??
|
|
||||||
result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CleanDateTimeResult Clean(string name, Regex expression)
|
private static bool TryClean(string name, Regex expression, ref CleanDateTimeResult result)
|
||||||
{
|
{
|
||||||
var result = new CleanDateTimeResult();
|
|
||||||
|
|
||||||
var match = expression.Match(name);
|
var match = expression.Match(name);
|
||||||
|
|
||||||
if (match.Success
|
if (match.Success
|
||||||
&& match.Groups.Count == 4
|
&& match.Groups.Count == 5
|
||||||
&& match.Groups[1].Success
|
&& match.Groups[1].Success
|
||||||
&& match.Groups[2].Success
|
&& match.Groups[2].Success
|
||||||
&& int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
|
&& int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
|
||||||
{
|
{
|
||||||
name = match.Groups[1].Value;
|
result = new CleanDateTimeResult(match.Groups[1].Value.TrimEnd(), year);
|
||||||
result.Year = year;
|
return true;
|
||||||
result.HasChanged = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Name = name;
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,33 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
public class CleanDateTimeResult
|
public readonly struct CleanDateTimeResult
|
||||||
{
|
{
|
||||||
|
public CleanDateTimeResult(string name, int? year)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Year = year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleanDateTimeResult(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Year = null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the name.
|
/// Gets the name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The name.</value>
|
/// <value>The name.</value>
|
||||||
public string Name { get; set; }
|
public string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the year.
|
/// Gets the year.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The year.</value>
|
/// <value>The year.</value>
|
||||||
public int? Year { get; set; }
|
public int? Year { get; }
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether this instance has changed.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if this instance has changed; otherwise, <c>false</c>.</value>
|
|
||||||
public bool HasChanged { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,45 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// http://kodi.wiki/view/Advancedsettings.xml#video
|
/// <see href="http://kodi.wiki/view/Advancedsettings.xml#video" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CleanStringParser
|
public static class CleanStringParser
|
||||||
{
|
{
|
||||||
public CleanStringResult Clean(string name, IEnumerable<Regex> expressions)
|
public static bool TryClean(string name, IReadOnlyList<Regex> expressions, out ReadOnlySpan<char> newName)
|
||||||
{
|
{
|
||||||
var hasChanged = false;
|
var len = expressions.Count;
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
foreach (var exp in expressions)
|
|
||||||
{
|
{
|
||||||
var result = Clean(name, exp);
|
if (TryClean(name, expressions[i], out newName))
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(result.Name))
|
|
||||||
{
|
{
|
||||||
name = result.Name;
|
return true;
|
||||||
hasChanged = hasChanged || result.HasChanged;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CleanStringResult
|
newName = ReadOnlySpan<char>.Empty;
|
||||||
{
|
return false;
|
||||||
Name = name,
|
|
||||||
HasChanged = hasChanged
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CleanStringResult Clean(string name, Regex expression)
|
private static bool TryClean(string name, Regex expression, out ReadOnlySpan<char> newName)
|
||||||
{
|
{
|
||||||
var result = new CleanStringResult();
|
|
||||||
|
|
||||||
var match = expression.Match(name);
|
var match = expression.Match(name);
|
||||||
|
int index = match.Index;
|
||||||
if (match.Success)
|
if (match.Success && index != 0)
|
||||||
{
|
{
|
||||||
result.HasChanged = true;
|
newName = name.AsSpan().Slice(0, match.Index);
|
||||||
name = name.Substring(0, match.Index);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Name = name;
|
newName = string.Empty;
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
namespace Emby.Naming.Video
|
|
||||||
{
|
|
||||||
public class CleanStringResult
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the name.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The name.</value>
|
|
||||||
public string Name { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether this instance has changed.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if this instance has changed; otherwise, <c>false</c>.</value>
|
|
||||||
public bool HasChanged { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -20,7 +23,7 @@ namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
return _options.VideoExtraRules
|
return _options.VideoExtraRules
|
||||||
.Select(i => GetExtraInfo(path, i))
|
.Select(i => GetExtraInfo(path, i))
|
||||||
.FirstOrDefault(i => !string.IsNullOrEmpty(i.ExtraType)) ?? new ExtraResult();
|
.FirstOrDefault(i => i.ExtraType != null) ?? new ExtraResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExtraResult GetExtraInfo(string path, ExtraRule rule)
|
private ExtraResult GetExtraInfo(string path, ExtraRule rule)
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
public class ExtraResult
|
public class ExtraResult
|
||||||
|
@ -6,7 +11,8 @@ namespace Emby.Naming.Video
|
||||||
/// Gets or sets the type of the extra.
|
/// Gets or sets the type of the extra.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The type of the extra.</value>
|
/// <value>The type of the extra.</value>
|
||||||
public string ExtraType { get; set; }
|
public ExtraType? ExtraType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the rule.
|
/// Gets or sets the rule.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
using Emby.Naming.Common;
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaType = Emby.Naming.Common.MediaType;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
|
@ -9,16 +13,19 @@ namespace Emby.Naming.Video
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The token.</value>
|
/// <value>The token.</value>
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type of the extra.
|
/// Gets or sets the type of the extra.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The type of the extra.</value>
|
/// <value>The type of the extra.</value>
|
||||||
public string ExtraType { get; set; }
|
public ExtraType ExtraType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type of the rule.
|
/// Gets or sets the type of the rule.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The type of the rule.</value>
|
/// <value>The type of the rule.</value>
|
||||||
public ExtraRuleType RuleType { get; set; }
|
public ExtraRuleType RuleType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type of the media.
|
/// Gets or sets the type of the media.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
public enum ExtraRuleType
|
public enum ExtraRuleType
|
||||||
|
@ -6,10 +9,12 @@ namespace Emby.Naming.Video
|
||||||
/// The suffix
|
/// The suffix
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Suffix = 0,
|
Suffix = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The filename
|
/// The filename
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Filename = 1,
|
Filename = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The regex
|
/// The regex
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -6,15 +9,17 @@ namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
public class FileStack
|
public class FileStack
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
|
||||||
public List<string> Files { get; set; }
|
|
||||||
public bool IsDirectoryStack { get; set; }
|
|
||||||
|
|
||||||
public FileStack()
|
public FileStack()
|
||||||
{
|
{
|
||||||
Files = new List<string>();
|
Files = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public List<string> Files { get; set; }
|
||||||
|
|
||||||
|
public bool IsDirectoryStack { get; set; }
|
||||||
|
|
||||||
public bool ContainsFile(string file, bool isDirectory)
|
public bool ContainsFile(string file, bool isDirectory)
|
||||||
{
|
{
|
||||||
if (IsDirectoryStack == isDirectory)
|
if (IsDirectoryStack == isDirectory)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
public class Format3DRule
|
public class Format3DRule
|
||||||
|
@ -7,6 +10,7 @@ namespace Emby.Naming.Video
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The token.</value>
|
/// <value>The token.</value>
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the preceeding token.
|
/// Gets or sets the preceeding token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -11,14 +14,14 @@ namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null)
|
||||||
{
|
{
|
||||||
return default(StubResult);
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
var extension = Path.GetExtension(path);
|
var extension = Path.GetExtension(path);
|
||||||
|
|
||||||
if (!options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
if (!options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return default(StubResult);
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new StubResult()
|
var result = new StubResult()
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
public struct StubResult
|
public struct StubResult
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
public class StubTypeRule
|
public class StubTypeRule
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -30,10 +32,10 @@ namespace Emby.Naming.Video
|
||||||
public int? Year { get; set; }
|
public int? Year { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type of the extra, e.g. trailer, theme song, behing the scenes, etc.
|
/// Gets or sets the type of the extra, e.g. trailer, theme song, behind the scenes, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The type of the extra.</value>
|
/// <value>The type of the extra.</value>
|
||||||
public string ExtraType { get; set; }
|
public ExtraType? ExtraType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the extra rule.
|
/// Gets or sets the extra rule.
|
||||||
|
@ -77,6 +79,7 @@ namespace Emby.Naming.Video
|
||||||
/// <value>The file name without extension.</value>
|
/// <value>The file name without extension.</value>
|
||||||
public string FileNameWithoutExtension => !IsDirectory ? System.IO.Path.GetFileNameWithoutExtension(Path) : System.IO.Path.GetFileName(Path);
|
public string FileNameWithoutExtension => !IsDirectory ? System.IO.Path.GetFileNameWithoutExtension(Path) : System.IO.Path.GetFileName(Path);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
// Makes debugging easier
|
// Makes debugging easier
|
||||||
|
|
|
@ -7,6 +7,16 @@ namespace Emby.Naming.Video
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoInfo
|
public class VideoInfo
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VideoInfo" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public VideoInfo()
|
||||||
|
{
|
||||||
|
Files = new List<VideoFileInfo>();
|
||||||
|
Extras = new List<VideoFileInfo>();
|
||||||
|
AlternateVersions = new List<VideoFileInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the name.
|
/// Gets or sets the name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -36,12 +46,5 @@ namespace Emby.Naming.Video
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The alternate versions.</value>
|
/// <value>The alternate versions.</value>
|
||||||
public List<VideoFileInfo> AlternateVersions { get; set; }
|
public List<VideoFileInfo> AlternateVersions { get; set; }
|
||||||
|
|
||||||
public VideoInfo()
|
|
||||||
{
|
|
||||||
Files = new List<VideoFileInfo>();
|
|
||||||
Extras = new List<VideoFileInfo>();
|
|
||||||
AlternateVersions = new List<VideoFileInfo>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
|
@ -29,7 +33,7 @@ namespace Emby.Naming.Video
|
||||||
// Filter out all extras, otherwise they could cause stacks to not be resolved
|
// Filter out all extras, otherwise they could cause stacks to not be resolved
|
||||||
// See the unit test TestStackedWithTrailer
|
// See the unit test TestStackedWithTrailer
|
||||||
var nonExtras = videoInfos
|
var nonExtras = videoInfos
|
||||||
.Where(i => string.IsNullOrEmpty(i.ExtraType))
|
.Where(i => i.ExtraType == null)
|
||||||
.Select(i => new FileSystemMetadata
|
.Select(i => new FileSystemMetadata
|
||||||
{
|
{
|
||||||
FullName = i.Path,
|
FullName = i.Path,
|
||||||
|
@ -76,7 +80,7 @@ namespace Emby.Naming.Video
|
||||||
}
|
}
|
||||||
|
|
||||||
var standaloneMedia = remainingFiles
|
var standaloneMedia = remainingFiles
|
||||||
.Where(i => string.IsNullOrEmpty(i.ExtraType))
|
.Where(i => i.ExtraType == null)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach (var media in standaloneMedia)
|
foreach (var media in standaloneMedia)
|
||||||
|
@ -145,7 +149,7 @@ namespace Emby.Naming.Video
|
||||||
if (list.Count == 1)
|
if (list.Count == 1)
|
||||||
{
|
{
|
||||||
var trailers = remainingFiles
|
var trailers = remainingFiles
|
||||||
.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase))
|
.Where(i => i.ExtraType == ExtraType.Trailer)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
list[0].Extras.AddRange(trailers);
|
list[0].Extras.AddRange(trailers);
|
||||||
|
@ -226,7 +230,7 @@ namespace Emby.Naming.Video
|
||||||
}
|
}
|
||||||
|
|
||||||
return remainingFiles
|
return remainingFiles
|
||||||
.Where(i => !string.IsNullOrEmpty(i.ExtraType))
|
.Where(i => i.ExtraType == null)
|
||||||
.Where(i => baseNames.Any(b => i.FileNameWithoutExtension.StartsWith(b, StringComparison.OrdinalIgnoreCase)))
|
.Where(i => baseNames.Any(b => i.FileNameWithoutExtension.StartsWith(b, StringComparison.OrdinalIgnoreCase)))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -91,9 +94,10 @@ namespace Emby.Naming.Video
|
||||||
{
|
{
|
||||||
var cleanDateTimeResult = CleanDateTime(name);
|
var cleanDateTimeResult = CleanDateTime(name);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(extraResult.ExtraType))
|
if (extraResult.ExtraType == null
|
||||||
|
&& TryCleanString(cleanDateTimeResult.Name, out ReadOnlySpan<char> newName))
|
||||||
{
|
{
|
||||||
name = CleanString(cleanDateTimeResult.Name).Name;
|
name = newName.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
year = cleanDateTimeResult.Year;
|
year = cleanDateTimeResult.Year;
|
||||||
|
@ -127,14 +131,14 @@ namespace Emby.Naming.Video
|
||||||
return _options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
|
return _options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CleanStringResult CleanString(string name)
|
public bool TryCleanString(string name, out ReadOnlySpan<char> newName)
|
||||||
{
|
{
|
||||||
return new CleanStringParser().Clean(name, _options.CleanStringRegexes);
|
return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CleanDateTimeResult CleanDateTime(string name)
|
public CleanDateTimeResult CleanDateTime(string name)
|
||||||
{
|
{
|
||||||
return new CleanDateTimeParser(_options).Clean(name);
|
return CleanDateTimeParser.Clean(name, _options.CleanDateTimeRegexes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||||
|
@ -21,11 +20,12 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Code analysers-->
|
<!-- Code Analyzers-->
|
||||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" />
|
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
|
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||||
|
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Activity;
|
using MediaBrowser.Model.Activity;
|
||||||
using MediaBrowser.Model.Events;
|
using MediaBrowser.Model.Events;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1600
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
@ -103,14 +104,11 @@ using MediaBrowser.Providers.Subtitles;
|
||||||
using MediaBrowser.Providers.TV.TheTVDB;
|
using MediaBrowser.Providers.TV.TheTVDB;
|
||||||
using MediaBrowser.WebDashboard.Api;
|
using MediaBrowser.WebDashboard.Api;
|
||||||
using MediaBrowser.XbmcMetadata.Providers;
|
using MediaBrowser.XbmcMetadata.Providers;
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Extensions;
|
using Microsoft.AspNetCore.Http.Extensions;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
|
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations
|
namespace Emby.Server.Implementations
|
||||||
|
@ -180,11 +178,7 @@ namespace Emby.Server.Implementations
|
||||||
/// Gets the plugins.
|
/// Gets the plugins.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The plugins.</value>
|
/// <value>The plugins.</value>
|
||||||
public IPlugin[] Plugins
|
public IReadOnlyList<IPlugin> Plugins => _plugins;
|
||||||
{
|
|
||||||
get => _plugins;
|
|
||||||
protected set => _plugins = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the logger factory.
|
/// Gets or sets the logger factory.
|
||||||
|
@ -605,7 +599,7 @@ namespace Emby.Server.Implementations
|
||||||
HttpsPort = ServerConfiguration.DefaultHttpsPort;
|
HttpsPort = ServerConfiguration.DefaultHttpsPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonSerializer = new JsonSerializer(FileSystemManager);
|
JsonSerializer = new JsonSerializer();
|
||||||
|
|
||||||
if (Plugins != null)
|
if (Plugins != null)
|
||||||
{
|
{
|
||||||
|
@ -764,9 +758,8 @@ namespace Emby.Server.Implementations
|
||||||
LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
|
LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
|
||||||
serviceCollection.AddSingleton(LibraryManager);
|
serviceCollection.AddSingleton(LibraryManager);
|
||||||
|
|
||||||
// TODO wtaylor: investigate use of second music manager
|
|
||||||
var musicManager = new MusicManager(LibraryManager);
|
var musicManager = new MusicManager(LibraryManager);
|
||||||
serviceCollection.AddSingleton<IMusicManager>(new MusicManager(LibraryManager));
|
serviceCollection.AddSingleton<IMusicManager>(musicManager);
|
||||||
|
|
||||||
LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager);
|
LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager);
|
||||||
serviceCollection.AddSingleton(LibraryMonitor);
|
serviceCollection.AddSingleton(LibraryMonitor);
|
||||||
|
@ -879,6 +872,8 @@ namespace Emby.Server.Implementations
|
||||||
serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
|
serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
|
||||||
serviceCollection.AddSingleton<EncodingHelper>();
|
serviceCollection.AddSingleton<EncodingHelper>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton(typeof(IAttachmentExtractor), typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor));
|
||||||
|
|
||||||
_displayPreferencesRepository.Initialize();
|
_displayPreferencesRepository.Initialize();
|
||||||
|
|
||||||
var userDataRepo = new SqliteUserDataRepository(LoggerFactory.CreateLogger<SqliteUserDataRepository>(), ApplicationPaths);
|
var userDataRepo = new SqliteUserDataRepository(LoggerFactory.CreateLogger<SqliteUserDataRepository>(), ApplicationPaths);
|
||||||
|
@ -1012,7 +1007,7 @@ namespace Emby.Server.Implementations
|
||||||
{
|
{
|
||||||
string dir = Path.Combine(ApplicationPaths.PluginsPath, args.Argument.name);
|
string dir = Path.Combine(ApplicationPaths.PluginsPath, args.Argument.name);
|
||||||
var types = Directory.EnumerateFiles(dir, "*.dll", SearchOption.AllDirectories)
|
var types = Directory.EnumerateFiles(dir, "*.dll", SearchOption.AllDirectories)
|
||||||
.Select(x => Assembly.LoadFrom(x))
|
.Select(Assembly.LoadFrom)
|
||||||
.SelectMany(x => x.ExportedTypes)
|
.SelectMany(x => x.ExportedTypes)
|
||||||
.Where(x => x.IsClass && !x.IsAbstract && !x.IsInterface && !x.IsGenericType)
|
.Where(x => x.IsClass && !x.IsAbstract && !x.IsInterface && !x.IsGenericType)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
@ -1058,7 +1053,7 @@ namespace Emby.Server.Implementations
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
|
ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
|
||||||
Plugins = GetExports<IPlugin>()
|
_plugins = GetExports<IPlugin>()
|
||||||
.Select(LoadPlugin)
|
.Select(LoadPlugin)
|
||||||
.Where(i => i != null)
|
.Where(i => i != null)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
@ -1479,7 +1474,7 @@ namespace Emby.Server.Implementations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="address">The IPv6 address.</param>
|
/// <param name="address">The IPv6 address.</param>
|
||||||
/// <returns>The IPv6 address without the scope id.</returns>
|
/// <returns>The IPv6 address without the scope id.</returns>
|
||||||
private string RemoveScopeId(string address)
|
private ReadOnlySpan<char> RemoveScopeId(ReadOnlySpan<char> address)
|
||||||
{
|
{
|
||||||
var index = address.IndexOf('%');
|
var index = address.IndexOf('%');
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
|
@ -1487,33 +1482,50 @@ namespace Emby.Server.Implementations
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
return address.Substring(0, index);
|
return address.Slice(0, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string GetLocalApiUrl(IPAddress ipAddress)
|
public string GetLocalApiUrl(IPAddress ipAddress)
|
||||||
{
|
{
|
||||||
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||||
{
|
{
|
||||||
var str = RemoveScopeId(ipAddress.ToString());
|
var str = RemoveScopeId(ipAddress.ToString());
|
||||||
|
Span<char> span = new char[str.Length + 2];
|
||||||
|
span[0] = '[';
|
||||||
|
str.CopyTo(span.Slice(1));
|
||||||
|
span[^1] = ']';
|
||||||
|
|
||||||
return GetLocalApiUrl("[" + str + "]");
|
return GetLocalApiUrl(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetLocalApiUrl(ipAddress.ToString());
|
return GetLocalApiUrl(ipAddress.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetLocalApiUrl(string host)
|
/// <inheritdoc />
|
||||||
|
public string GetLocalApiUrl(ReadOnlySpan<char> host)
|
||||||
{
|
{
|
||||||
|
var url = new StringBuilder(64);
|
||||||
if (EnableHttps)
|
if (EnableHttps)
|
||||||
{
|
{
|
||||||
return string.Format("https://{0}:{1}",
|
url.Append("https://");
|
||||||
host,
|
}
|
||||||
HttpsPort.ToString(CultureInfo.InvariantCulture));
|
else
|
||||||
|
{
|
||||||
|
url.Append("http://");
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Format("http://{0}:{1}",
|
url.Append(host)
|
||||||
host,
|
.Append(':')
|
||||||
HttpPort.ToString(CultureInfo.InvariantCulture));
|
.Append(HttpPort);
|
||||||
|
|
||||||
|
string baseUrl = ServerConfigurationManager.Configuration.BaseUrl;
|
||||||
|
if (baseUrl.Length != 0)
|
||||||
|
{
|
||||||
|
url.Append('/').Append(baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken)
|
public Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken)
|
||||||
|
@ -1690,32 +1702,9 @@ namespace Emby.Server.Implementations
|
||||||
/// <param name="plugin">The plugin.</param>
|
/// <param name="plugin">The plugin.</param>
|
||||||
public void RemovePlugin(IPlugin plugin)
|
public void RemovePlugin(IPlugin plugin)
|
||||||
{
|
{
|
||||||
var list = Plugins.ToList();
|
var list = _plugins.ToList();
|
||||||
list.Remove(plugin);
|
list.Remove(plugin);
|
||||||
Plugins = list.ToArray();
|
_plugins = list.ToArray();
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This returns localhost in the case of no external dns, and the hostname if the
|
|
||||||
/// dns is prefixed with a valid Uri prefix.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="externalDns">The external dns prefix to get the hostname of.</param>
|
|
||||||
/// <returns>The hostname in <paramref name="externalDns"/>.</returns>
|
|
||||||
private static string GetHostnameFromExternalDns(string externalDns)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(externalDns))
|
|
||||||
{
|
|
||||||
return "localhost";
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new Uri(externalDns).Host;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return externalDns;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void LaunchUrl(string url)
|
public virtual void LaunchUrl(string url)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user