commit
b8eba6cdb6
@ -1,93 +0,0 @@
|
||||
parameters:
|
||||
- name: Packages
|
||||
type: object
|
||||
default: {}
|
||||
- name: LinuxImage
|
||||
type: string
|
||||
default: "ubuntu-latest"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 8.0.x
|
||||
|
||||
jobs:
|
||||
- job: CompatibilityCheck
|
||||
displayName: Compatibility Check
|
||||
dependsOn: Build
|
||||
condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber'])
|
||||
|
||||
pool:
|
||||
vmImage: "${{ parameters.LinuxImage }}"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each Package in parameters.Packages }}:
|
||||
${{ Package.key }}:
|
||||
NugetPackageName: ${{ Package.value.NugetPackageName }}
|
||||
AssemblyFileName: ${{ Package.value.AssemblyFileName }}
|
||||
maxParallel: 2
|
||||
|
||||
steps:
|
||||
- checkout: none
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: "Update DotNet"
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: ${{ parameters.DotNetSdkVersion }}
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Install ABI CompatibilityChecker Tool'
|
||||
inputs:
|
||||
command: custom
|
||||
custom: tool
|
||||
arguments: 'update compatibilitychecker -g'
|
||||
|
||||
- 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'
|
||||
enabled: false
|
||||
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'
|
||||
enabled: false
|
||||
inputs:
|
||||
sourceFolder: $(System.ArtifactsDirectory)/current-artifacts
|
||||
contents: '**/*.dll'
|
||||
targetFolder: $(System.ArtifactsDirectory)/current-release
|
||||
cleanTargetFolder: true
|
||||
overWrite: true
|
||||
flattenFolders: true
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Execute ABI Compatibility Check Tool'
|
||||
enabled: false
|
||||
inputs:
|
||||
command: custom
|
||||
custom: compat
|
||||
arguments: 'current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only'
|
||||
workingDirectory: $(System.ArtifactsDirectory)
|
@ -1,71 +0,0 @@
|
||||
parameters:
|
||||
LinuxImage: 'ubuntu-latest'
|
||||
RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
||||
DotNetSdkVersion: 8.0.x
|
||||
|
||||
jobs:
|
||||
- job: Build
|
||||
displayName: Build
|
||||
strategy:
|
||||
matrix:
|
||||
Release:
|
||||
BuildConfiguration: Release
|
||||
Debug:
|
||||
BuildConfiguration: Debug
|
||||
pool:
|
||||
vmImage: '${{ parameters.LinuxImage }}'
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: true
|
||||
|
||||
- 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@1
|
||||
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@1
|
||||
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@1
|
||||
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@1
|
||||
displayName: 'Publish Artifact Common'
|
||||
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||
inputs:
|
||||
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/MediaBrowser.Common.dll'
|
||||
artifactName: 'Jellyfin.Common'
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish Artifact Extensions'
|
||||
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
|
||||
inputs:
|
||||
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/Jellyfin.Extensions.dll'
|
||||
artifactName: 'Jellyfin.Extensions'
|
@ -1,274 +0,0 @@
|
||||
jobs:
|
||||
- job: BuildPackage
|
||||
displayName: 'Build Packages'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
CentOS.amd64:
|
||||
BuildConfiguration: centos.amd64
|
||||
Fedora.amd64:
|
||||
BuildConfiguration: fedora.amd64
|
||||
Debian.amd64:
|
||||
BuildConfiguration: debian.amd64
|
||||
Debian.arm64:
|
||||
BuildConfiguration: debian.arm64
|
||||
Debian.armhf:
|
||||
BuildConfiguration: debian.armhf
|
||||
Ubuntu.amd64:
|
||||
BuildConfiguration: ubuntu.amd64
|
||||
Ubuntu.arm64:
|
||||
BuildConfiguration: ubuntu.arm64
|
||||
Ubuntu.armhf:
|
||||
BuildConfiguration: ubuntu.armhf
|
||||
Linux.amd64:
|
||||
BuildConfiguration: linux.amd64
|
||||
Linux.amd64-musl:
|
||||
BuildConfiguration: linux.amd64-musl
|
||||
Linux.arm64:
|
||||
BuildConfiguration: linux.arm64
|
||||
Linux.musl-linux-arm64:
|
||||
BuildConfiguration: linux.musl-linux-arm64
|
||||
Linux.armhf:
|
||||
BuildConfiguration: linux.armhf
|
||||
Windows.amd64:
|
||||
BuildConfiguration: windows.amd64
|
||||
MacOS.amd64:
|
||||
BuildConfiguration: macos.amd64
|
||||
MacOS.arm64:
|
||||
BuildConfiguration: macos.arm64
|
||||
Portable:
|
||||
BuildConfiguration: portable
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
|
||||
displayName: Set release version (stable)
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
|
||||
- script: 'docker build -f deployment/Dockerfile.$(BuildConfiguration) -t jellyfin-server-$(BuildConfiguration) --label "org.opencontainers.image.url=$(Build.Repository.Uri)" --label "org.opencontainers.image.revision=$(Build.SourceVersion)" deployment'
|
||||
displayName: 'Build Dockerfile'
|
||||
|
||||
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="yes" -e BUILD_ID=$(Build.BuildNumber) jellyfin-server-$(BuildConfiguration)'
|
||||
displayName: 'Run Dockerfile (unstable)'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
|
||||
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="no" -e BUILD_ID=$(Build.BuildNumber) jellyfin-server-$(BuildConfiguration)'
|
||||
displayName: 'Run Dockerfile (stable)'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish Release'
|
||||
inputs:
|
||||
targetPath: '$(Build.SourcesDirectory)/deployment/dist'
|
||||
artifactName: 'jellyfin-server-$(BuildConfiguration)'
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Create target directory on repository server'
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'inline'
|
||||
inline: 'mkdir -p /srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
|
||||
|
||||
- task: CopyFilesOverSSH@0
|
||||
displayName: 'Upload artifacts to repository server'
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
sourceFolder: '$(Build.SourcesDirectory)/deployment/dist'
|
||||
contents: '**'
|
||||
targetFolder: '/srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
|
||||
|
||||
- job: OpenAPISpec
|
||||
dependsOn: Test
|
||||
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/heads/master'),startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
displayName: 'Push OpenAPI Spec to repository'
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
|
||||
displayName: Set release version (stable)
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: 'Download OpenAPI Spec'
|
||||
inputs:
|
||||
source: 'current'
|
||||
artifact: "OpenAPI Spec"
|
||||
path: "$(System.ArtifactsDirectory)/openapispec"
|
||||
runVersion: "latest"
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Create target directory on repository server'
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'inline'
|
||||
inline: 'mkdir -p /srv/repository/incoming/azure/$(Build.BuildNumber)'
|
||||
|
||||
- task: CopyFilesOverSSH@0
|
||||
displayName: 'Upload artifacts to repository server'
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
sourceFolder: '$(System.ArtifactsDirectory)/openapispec'
|
||||
contents: 'openapi.json'
|
||||
targetFolder: '/srv/repository/incoming/azure/$(Build.BuildNumber)'
|
||||
|
||||
- job: BuildDocker
|
||||
displayName: 'Build Docker'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
amd64:
|
||||
BuildConfiguration: amd64
|
||||
arm64:
|
||||
BuildConfiguration: arm64
|
||||
armhf:
|
||||
BuildConfiguration: armhf
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
variables:
|
||||
- name: JellyfinVersion
|
||||
value: 0.0.0
|
||||
|
||||
steps:
|
||||
- script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
|
||||
displayName: Set release version (stable)
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
|
||||
- task: Docker@2
|
||||
displayName: 'Push Unstable Image'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
inputs:
|
||||
repository: 'jellyfin/jellyfin-server'
|
||||
command: buildAndPush
|
||||
buildContext: '.'
|
||||
Dockerfile: 'deployment/Dockerfile.docker.$(BuildConfiguration)'
|
||||
containerRegistry: Docker Hub
|
||||
tags: |
|
||||
unstable-$(Build.BuildNumber)-$(BuildConfiguration)
|
||||
unstable-$(BuildConfiguration)
|
||||
|
||||
- task: Docker@2
|
||||
displayName: 'Push Stable Image'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
inputs:
|
||||
repository: 'jellyfin/jellyfin-server'
|
||||
command: buildAndPush
|
||||
buildContext: '.'
|
||||
Dockerfile: 'deployment/Dockerfile.docker.$(BuildConfiguration)'
|
||||
containerRegistry: Docker Hub
|
||||
tags: |
|
||||
stable-$(Build.BuildNumber)-$(BuildConfiguration)
|
||||
$(JellyfinVersion)-$(BuildConfiguration)
|
||||
|
||||
- job: CollectArtifacts
|
||||
timeoutInMinutes: 20
|
||||
displayName: 'Collect Artifacts'
|
||||
condition: succeededOrFailed()
|
||||
continueOnError: true
|
||||
dependsOn:
|
||||
- BuildPackage
|
||||
- BuildDocker
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: SSH@0
|
||||
displayName: 'Update Unstable Repository'
|
||||
continueOnError: true
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'commands'
|
||||
commands: nohup sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) unstable &
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Update Stable Repository'
|
||||
continueOnError: true
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'commands'
|
||||
commands: nohup sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) $(Build.SourceBranch) &
|
||||
|
||||
- job: PublishNuget
|
||||
displayName: 'Publish NuGet packages'
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
variables:
|
||||
- name: JellyfinVersion
|
||||
value: $[replace(variables['Build.SourceBranch'],'refs/tags/v','')]
|
||||
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
displayName: 'Use .NET 8.0 sdk'
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: '8.0.x'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Build Stable Nuget packages'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
inputs:
|
||||
command: 'custom'
|
||||
projects: |
|
||||
Jellyfin.Data/Jellyfin.Data.csproj
|
||||
MediaBrowser.Common/MediaBrowser.Common.csproj
|
||||
MediaBrowser.Controller/MediaBrowser.Controller.csproj
|
||||
MediaBrowser.Model/MediaBrowser.Model.csproj
|
||||
Emby.Naming/Emby.Naming.csproj
|
||||
src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
|
||||
custom: 'pack'
|
||||
arguments: -o $(Build.ArtifactStagingDirectory) -p:Version=$(JellyfinVersion)
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Build Unstable Nuget packages'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
inputs:
|
||||
command: 'custom'
|
||||
projects: |
|
||||
Jellyfin.Data/Jellyfin.Data.csproj
|
||||
MediaBrowser.Common/MediaBrowser.Common.csproj
|
||||
MediaBrowser.Controller/MediaBrowser.Controller.csproj
|
||||
MediaBrowser.Model/MediaBrowser.Model.csproj
|
||||
Emby.Naming/Emby.Naming.csproj
|
||||
src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
|
||||
custom: 'pack'
|
||||
arguments: '--version-suffix $(Build.BuildNumber) -o $(Build.ArtifactStagingDirectory) -p:Stability=Unstable'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Nuget packages'
|
||||
inputs:
|
||||
pathToPublish: $(Build.ArtifactStagingDirectory)
|
||||
artifactName: Jellyfin Nuget Packages
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: 'Push Nuget packages to stable feed'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
|
||||
inputs:
|
||||
command: 'push'
|
||||
packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg'
|
||||
nuGetFeedType: 'external'
|
||||
publishFeedCredentials: 'NugetOrg'
|
||||
allowPackageConflicts: true # This ignores an error if the version already exists
|
||||
|
||||
- task: NuGetAuthenticate@1
|
||||
displayName: 'Authenticate to unstable Nuget feed'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: 'Push Nuget packages to unstable feed'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
inputs:
|
||||
command: 'push'
|
||||
packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' # No symbols since Azure Artifact does not support it
|
||||
nuGetFeedType: 'internal'
|
||||
publishVstsFeed: '7cce6c46-d610-45e3-9fb7-65a6bfd1b671/a5746b79-f369-42db-93ff-59cd066f9327'
|
||||
allowPackageConflicts: true # This ignores an error if the version already exists
|
@ -1,98 +0,0 @@
|
||||
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: 8.0.x
|
||||
|
||||
jobs:
|
||||
- job: Test
|
||||
displayName: Test
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each imageName in parameters.ImageNames }}:
|
||||
${{ imageName.key }}:
|
||||
ImageName: ${{ imageName.value }}
|
||||
pool:
|
||||
vmImage: "$(ImageName)"
|
||||
steps:
|
||||
- checkout: self
|
||||
clean: true
|
||||
submodules: true
|
||||
persistCredentials: false
|
||||
|
||||
# This is required for the SonarCloud analyzer
|
||||
- task: UseDotNet@2
|
||||
displayName: "Install .NET SDK 5.x"
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: '5.x'
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: "Update DotNet"
|
||||
inputs:
|
||||
packageType: sdk
|
||||
version: ${{ parameters.DotNetSdkVersion }}
|
||||
|
||||
- task: SonarCloudPrepare@1
|
||||
displayName: 'Prepare analysis on SonarCloud'
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
enabled: false
|
||||
inputs:
|
||||
SonarCloud: 'Sonarcloud for Jellyfin'
|
||||
organization: 'jellyfin'
|
||||
projectKey: 'jellyfin_jellyfin'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Run CLI Tests'
|
||||
inputs:
|
||||
command: "test"
|
||||
projects: ${{ parameters.TestProjects }}
|
||||
arguments: '--configuration Release --collect:"XPlat Code Coverage" --settings tests/coverletArgs.runsettings --verbosity minimal'
|
||||
publishTestResults: true
|
||||
testRunTitle: $(Agent.JobName)
|
||||
workingDirectory: "$(Build.SourcesDirectory)"
|
||||
|
||||
- task: SonarCloudAnalyze@1
|
||||
displayName: 'Run Code Analysis'
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
enabled: false
|
||||
|
||||
- task: SonarCloudPublish@1
|
||||
displayName: 'Publish Quality Gate Result'
|
||||
condition: eq(variables['ImageName'], 'ubuntu-latest')
|
||||
enabled: false
|
||||
|
||||
- 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: 'Run ReportGenerator'
|
||||
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
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish OpenAPI Artifact'
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
|
||||
inputs:
|
||||
targetPath: "tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json"
|
||||
artifactName: 'OpenAPI Spec'
|
@ -1,64 +0,0 @@
|
||||
name: $(Date:yyyyMMdd)$(Rev:.r)
|
||||
|
||||
variables:
|
||||
- name: TestProjects
|
||||
value: 'tests/**/*Tests.csproj'
|
||||
- name: RestoreBuildProjects
|
||||
value: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
tags:
|
||||
include:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
- ${{ if not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')) }}:
|
||||
- template: azure-pipelines-main.yml
|
||||
parameters:
|
||||
LinuxImage: 'ubuntu-latest'
|
||||
RestoreBuildProjects: $(RestoreBuildProjects)
|
||||
|
||||
- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}:
|
||||
- template: azure-pipelines-test.yml
|
||||
parameters:
|
||||
ImageNames:
|
||||
Linux: 'ubuntu-latest'
|
||||
Windows: 'windows-latest'
|
||||
macOS: 'macos-latest'
|
||||
|
||||
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
|
||||
- template: azure-pipelines-test.yml
|
||||
parameters:
|
||||
ImageNames:
|
||||
Linux: 'ubuntu-latest'
|
||||
|
||||
- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}:
|
||||
- template: azure-pipelines-abi.yml
|
||||
parameters:
|
||||
Packages:
|
||||
Naming:
|
||||
NugetPackageName: Jellyfin.Naming
|
||||
AssemblyFileName: Emby.Naming.dll
|
||||
Controller:
|
||||
NugetPackageName: Jellyfin.Controller
|
||||
AssemblyFileName: MediaBrowser.Controller.dll
|
||||
Model:
|
||||
NugetPackageName: Jellyfin.Model
|
||||
AssemblyFileName: MediaBrowser.Model.dll
|
||||
Common:
|
||||
NugetPackageName: Jellyfin.Common
|
||||
AssemblyFileName: MediaBrowser.Common.dll
|
||||
Extensions:
|
||||
NugetPackageName: Jellyfin.Extensions
|
||||
AssemblyFileName: Jellyfin.Extensions.dll
|
||||
LinuxImage: 'ubuntu-latest'
|
||||
|
||||
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
|
||||
- template: azure-pipelines-package.yml
|
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "Development Jellyfin Server - FFmpeg",
|
||||
"image":"mcr.microsoft.com/devcontainers/dotnet:8.0-jammy",
|
||||
// restores nuget packages, installs the dotnet workloads and installs the dev https certificate
|
||||
"postStartCommand": "dotnet restore; dotnet workload update; dotnet dev-certs https --trust; sudo bash \"./.devcontainer/Dev - Server Ffmpeg/install-ffmpeg.sh\"",
|
||||
// reads the extensions list and installs them
|
||||
"postAttachCommand": "cat .vscode/extensions.json | jq -r .recommendations[] | xargs -n 1 code --install-extension",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||
"version": "none",
|
||||
"dotnetRuntimeVersions": "8.0",
|
||||
"aspNetCoreRuntimeVersions": "8.0"
|
||||
},
|
||||
"ghcr.io/devcontainers-contrib/features/apt-packages:1": {
|
||||
"preserve_apt_list": false,
|
||||
"packages": ["libfontconfig1"]
|
||||
},
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {
|
||||
"dockerDashComposeVersion": "v2"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/github-cli:1": {},
|
||||
"ghcr.io/eitsupi/devcontainer-features/jq-likes:2": {}
|
||||
},
|
||||
"hostRequirements": {
|
||||
"memory": "8gb",
|
||||
"cpus": 4
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
## configure the following for a manuall install of a specific version from the repo
|
||||
|
||||
# wget https://repo.jellyfin.org/releases/server/ubuntu/versions/jellyfin-ffmpeg/6.0.1-1/jellyfin-ffmpeg6_6.0.1-1-jammy_amd64.deb -O ffmpeg.deb
|
||||
|
||||
# sudo apt update
|
||||
# sudo apt install -f ./ffmpeg.deb -y
|
||||
# rm ffmpeg.deb
|
||||
|
||||
|
||||
## Add the jellyfin repo
|
||||
sudo apt install curl gnupg -y
|
||||
sudo apt-get install software-properties-common -y
|
||||
sudo add-apt-repository universe -y
|
||||
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/jellyfin.gpg
|
||||
export VERSION_OS="$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release )"
|
||||
export VERSION_CODENAME="$( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release )"
|
||||
export DPKG_ARCHITECTURE="$( dpkg --print-architecture )"
|
||||
cat <<EOF | sudo tee /etc/apt/sources.list.d/jellyfin.sources
|
||||
Types: deb
|
||||
URIs: https://repo.jellyfin.org/${VERSION_OS}
|
||||
Suites: ${VERSION_CODENAME}
|
||||
Components: main
|
||||
Architectures: ${DPKG_ARCHITECTURE}
|
||||
Signed-By: /etc/apt/keyrings/jellyfin.gpg
|
||||
EOF
|
||||
|
||||
sudo apt update -y
|
||||
sudo apt install jellyfin-ffmpeg6 -y
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Media playback issue
|
||||
about: Create a media playback issue report
|
||||
title: ''
|
||||
labels: mediaplayback
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Media Info of the file**
|
||||
<!-- 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**
|
||||
<!-- 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**
|
||||
<!-- If available, add screenshots of the stats for nerds screen to help show the issue problem. -->
|
||||
|
||||
**Server System (please complete the following information):**
|
||||
- OS: [e.g. Docker on Linux, Docker on Windows, Debian, Windows]
|
||||
- Jellyfin Version: [e.g. 10.0.1]
|
||||
- Hardware settings & device: [e.g. NVENC on GTX1060, VAAPI on Intel i7 8700K]
|
||||
- Reverse proxy: [e.g. no, nginx, apache, etc.]
|
||||
- Other hardware notes: [e.g. Media mounted in CIFS/SMB share, Media mounted from Google Drive]
|
||||
|
||||
**Client System (please complete the following information):**
|
||||
- Device: [e.g. Apple iPhone XS, Xbox One S, LG OLED55C8, Samsung Galaxy Note9, Custom HTPC]
|
||||
- OS: [e.g. iOS, Android, Windows, macOS]
|
||||
- Client: [e.g. Web/Browser, webOS, Android, Android TV, Electron]
|
||||
- Browser (if Web client): [e.g. Firefox, Chrome, Safari]
|
||||
- Client and Browser Version: [e.g. 10.3.4 and 68.0]
|
@ -0,0 +1,29 @@
|
||||
name: Check Issue Template
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
jobs:
|
||||
check_issue:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: pull in script
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
repository: jellyfin/jellyfin-triage-script
|
||||
- name: install python
|
||||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: install python packages
|
||||
run: pip install -r main-repo-triage/requirements.txt
|
||||
- name: check and comment issue
|
||||
working-directory: ./main-repo-triage
|
||||
run: python3 single_issue_gha.py
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
ISSUE: ${{ github.event.issue.number }}
|
@ -1,87 +0,0 @@
|
||||
# DESIGNED FOR BUILDING ON AMD64 ONLY
|
||||
#####################################
|
||||
# Requires binfm_misc registration
|
||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||
ARG DOTNET_VERSION=8.0
|
||||
|
||||
FROM node:20-alpine as web-builder
|
||||
ARG JELLYFIN_WEB_VERSION=master
|
||||
RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python3 \
|
||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& apk del curl \
|
||||
&& cd jellyfin-web-* \
|
||||
&& npm ci --no-audit --unsafe-perm \
|
||||
&& npm run build:production \
|
||||
&& mv dist /dist
|
||||
|
||||
FROM debian:bookworm-slim as app
|
||||
|
||||
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
# http://stackoverflow.com/questions/48162574/ddg#49462622
|
||||
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
|
||||
# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
|
||||
ENV NVIDIA_VISIBLE_DEVICES="all"
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
|
||||
|
||||
ENV JELLYFIN_DATA_DIR=/config
|
||||
ENV JELLYFIN_CACHE_DIR=/cache
|
||||
|
||||
# https://github.com/intel/compute-runtime/releases
|
||||
ARG GMMLIB_VERSION=22.3.11.ci17757293
|
||||
ARG IGC_VERSION=1.0.15136.22
|
||||
ARG NEO_VERSION=23.39.27427.23
|
||||
ARG LEVEL_ZERO_VERSION=1.3.27427.23
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg curl \
|
||||
&& curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/debian-jellyfin.gpg \
|
||||
&& echo "deb [arch=$( dpkg --print-architecture )] https://repo.jellyfin.org/$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release ) $( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release ) main" | tee /etc/apt/sources.list.d/jellyfin.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y mesa-va-drivers jellyfin-ffmpeg6 openssl locales \
|
||||
# Intel VAAPI Tone mapping dependencies:
|
||||
# Prefer NEO to Beignet since the latter one doesn't support Comet Lake or newer for now.
|
||||
# Do not use the intel-opencl-icd package from repo since they will not build with RELEASE_WITH_REGKEYS enabled.
|
||||
&& mkdir intel-compute-runtime \
|
||||
&& cd intel-compute-runtime \
|
||||
&& curl -LO https://github.com/intel/intel-graphics-compiler/releases/download/igc-${IGC_VERSION}/intel-igc-core_${IGC_VERSION}_amd64.deb \
|
||||
-LO https://github.com/intel/intel-graphics-compiler/releases/download/igc-${IGC_VERSION}/intel-igc-opencl_${IGC_VERSION}_amd64.deb \
|
||||
-LO https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-level-zero-gpu_${LEVEL_ZERO_VERSION}_amd64.deb \
|
||||
-LO https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-opencl-icd_${NEO_VERSION}_amd64.deb \
|
||||
-LO https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/libigdgmm12_${GMMLIB_VERSION}_amd64.deb \
|
||||
&& dpkg -i *.deb \
|
||||
&& cd .. \
|
||||
&& rm -rf intel-compute-runtime \
|
||||
&& apt-get remove gnupg -y \
|
||||
&& apt-get clean autoclean -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR} \
|
||||
&& chmod 777 ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR} \
|
||||
&& sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
||||
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
ENV LANG=en_US.UTF-8
|
||||
ENV LANGUAGE=en_US:en
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 -p:DebugSymbols=false -p:DebugType=none
|
||||
|
||||
FROM app
|
||||
|
||||
ENV HEALTHCHECK_URL=http://localhost:8096/health
|
||||
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||
|
||||
EXPOSE 8096
|
||||
VOLUME ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR}
|
||||
ENTRYPOINT [ "./jellyfin/jellyfin", \
|
||||
"--ffmpeg", "/usr/lib/jellyfin-ffmpeg/ffmpeg" ]
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=10s --retries=3 \
|
||||
CMD curl -Lk -fsS "${HEALTHCHECK_URL}" || exit 1
|
@ -1,74 +0,0 @@
|
||||
# DESIGNED FOR BUILDING ON ARM ONLY
|
||||
#####################################
|
||||
# Requires binfm_misc registration
|
||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||
ARG DOTNET_VERSION=8.0
|
||||
|
||||
FROM node:20-alpine as web-builder
|
||||
ARG JELLYFIN_WEB_VERSION=master
|
||||
RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python3 \
|
||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& apk del curl \
|
||||
&& cd jellyfin-web-* \
|
||||
&& npm ci --no-audit --unsafe-perm \
|
||||
&& npm run build:production \
|
||||
&& mv dist /dist
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
||||
FROM arm32v7/debian:bookworm-slim as app
|
||||
|
||||
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
# http://stackoverflow.com/questions/48162574/ddg#49462622
|
||||
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
|
||||
# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
|
||||
ENV NVIDIA_VISIBLE_DEVICES="all"
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
|
||||
|
||||
ENV JELLYFIN_DATA_DIR=/config
|
||||
ENV JELLYFIN_CACHE_DIR=/cache
|
||||
|
||||
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg curl \
|
||||
&& curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/debian-jellyfin.gpg \
|
||||
&& curl -fsSL https://keyserver.ubuntu.com/pks/lookup?op=get\&search=0x6587ffd6536b8826e88a62547876ae518cbcf2f2 | gpg --dearmor -o /etc/apt/trusted.gpg.d/ubuntu-jellyfin.gpg \
|
||||
&& echo "deb [arch=$( dpkg --print-architecture )] https://repo.jellyfin.org/$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release ) $( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release ) main" | tee /etc/apt/sources.list.d/jellyfin.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
||||
jellyfin-ffmpeg6 libssl-dev libfontconfig1 \
|
||||
libfreetype6 vainfo libva2 locales \
|
||||
&& apt-get remove gnupg -y \
|
||||
&& apt-get clean autoclean -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR} \
|
||||
&& chmod 777 ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR} \
|
||||
&& sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
||||
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
ENV LANG=en_US.UTF-8
|
||||
ENV LANGUAGE=en_US:en
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm -p:DebugSymbols=false -p:DebugType=none
|
||||
|
||||
FROM app
|
||||
|
||||
ENV HEALTHCHECK_URL=http://localhost:8096/health
|
||||
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||
|
||||
EXPOSE 8096
|
||||
VOLUME ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR}
|
||||
ENTRYPOINT [ "/jellyfin/jellyfin", \
|
||||
"--ffmpeg", "/usr/lib/jellyfin-ffmpeg/ffmpeg" ]
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=10s --retries=3 \
|
||||
CMD curl -Lk -fsS "${HEALTHCHECK_URL}" || exit 1
|
@ -1,74 +0,0 @@
|
||||
# DESIGNED FOR BUILDING ON ARM64 ONLY
|
||||
#####################################
|
||||
# Requires binfm_misc registration
|
||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||
ARG DOTNET_VERSION=8.0
|
||||
|
||||
FROM node:20-alpine as web-builder
|
||||
ARG JELLYFIN_WEB_VERSION=master
|
||||
RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python3 \
|
||||
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& apk del curl \
|
||||
&& cd jellyfin-web-* \
|
||||
&& npm ci --no-audit --unsafe-perm \
|
||||
&& npm run build:production \
|
||||
&& mv dist /dist
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
||||
FROM arm64v8/debian:bookworm-slim as app
|
||||
|
||||
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
# http://stackoverflow.com/questions/48162574/ddg#49462622
|
||||
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
|
||||
# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
|
||||
ENV NVIDIA_VISIBLE_DEVICES="all"
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
|
||||
|
||||
ENV JELLYFIN_DATA_DIR=/config
|
||||
ENV JELLYFIN_CACHE_DIR=/cache
|
||||
|
||||
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg curl \
|
||||
&& curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/debian-jellyfin.gpg \
|
||||
&& curl -fsSL https://keyserver.ubuntu.com/pks/lookup?op=get\&search=0x6587ffd6536b8826e88a62547876ae518cbcf2f2 | gpg --dearmor -o /etc/apt/trusted.gpg.d/ubuntu-jellyfin.gpg \
|
||||
&& echo "deb [arch=$( dpkg --print-architecture )] https://repo.jellyfin.org/$( awk -F'=' '/^ID=/{ print $NF }' /etc/os-release ) $( awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release ) main" | tee /etc/apt/sources.list.d/jellyfin.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
||||
jellyfin-ffmpeg6 locales libssl-dev libfontconfig1 \
|
||||
libfreetype6 libomxil-bellagio0 libomxil-bellagio-bin \
|
||||
&& apt-get remove gnupg -y \
|
||||
&& apt-get clean autoclean -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR} \
|
||||
&& chmod 777 ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR} \
|
||||
&& sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
||||
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
ENV LANG=en_US.UTF-8
|
||||
ENV LANGUAGE=en_US:en
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
||||
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 -p:DebugSymbols=false -p:DebugType=none
|
||||
|
||||
FROM app
|
||||
|
||||
ENV HEALTHCHECK_URL=http://localhost:8096/health
|
||||
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
COPY --from=web-builder /dist /jellyfin/jellyfin-web
|
||||
|
||||
EXPOSE 8096
|
||||
VOLUME ${JELLYFIN_DATA_DIR} ${JELLYFIN_CACHE_DIR}
|
||||
ENTRYPOINT [ "/jellyfin/jellyfin", \
|
||||
"--ffmpeg", "/usr/lib/jellyfin-ffmpeg/ffmpeg" ]
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=10s --retries=3 \
|
||||
CMD curl -Lk -fsS "${HEALTHCHECK_URL}" || exit 1
|
@ -1,35 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
|
||||
namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IServerEntryPoint" /> which is responsible for starting the library monitor.
|
||||
/// </summary>
|
||||
public sealed class LibraryMonitorStartup : IServerEntryPoint
|
||||
{
|
||||
private readonly ILibraryMonitor _monitor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LibraryMonitorStartup"/> class.
|
||||
/// </summary>
|
||||
/// <param name="monitor">The library monitor.</param>
|
||||
public LibraryMonitorStartup(ILibraryMonitor monitor)
|
||||
{
|
||||
_monitor = monitor;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task RunAsync()
|
||||
{
|
||||
_monitor.Start();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"Albums": "Albaim"
|
||||
}
|
@ -0,0 +1 @@
|
||||
{}
|
@ -1,4 +1,12 @@
|
||||
{
|
||||
"External": "ବହିଃସ୍ଥ",
|
||||
"Genres": "ଧରଣ"
|
||||
"Genres": "ଧରଣ",
|
||||
"Albums": "ଆଲବମଗୁଡ଼ିକ",
|
||||
"Artists": "କଳାକାରଗୁଡ଼ିକ",
|
||||
"Application": "ଆପ୍ଲିକେସନ",
|
||||
"Books": "ବହିଗୁଡ଼ିକ",
|
||||
"Channels": "ଚ୍ୟାନେଲଗୁଡ଼ିକ",
|
||||
"ChapterNameValue": "ବିଭାଗ {0}",
|
||||
"Collections": "ସଂଗ୍ରହଗୁଡ଼ିକ",
|
||||
"Folders": "ଫୋଲ୍ଡରଗୁଡ଼ିକ"
|
||||
}
|
||||
|
@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using System.Net.Mime;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Attributes;
|
||||
using Jellyfin.Api.Extensions;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Api;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Lyrics;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Lyrics;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Jellyfin.Api.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Lyrics controller.
|
||||
/// </summary>
|
||||
[Route("")]
|
||||
public class LyricsController : BaseJellyfinApiController
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILyricManager _lyricManager;
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LyricsController"/> class.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||
/// <param name="lyricManager">Instance of the <see cref="ILyricManager"/> interface.</param>
|
||||
/// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
|
||||
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||
public LyricsController(
|
||||
ILibraryManager libraryManager,
|
||||
ILyricManager lyricManager,
|
||||
IProviderManager providerManager,
|
||||
IFileSystem fileSystem,
|
||||
IUserManager userManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_lyricManager = lyricManager;
|
||||
_providerManager = providerManager;
|
||||
_fileSystem = fileSystem;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an item's lyrics.
|
||||
/// </summary>
|
||||
/// <param name="itemId">Item id.</param>
|
||||
/// <response code="200">Lyrics returned.</response>
|
||||
/// <response code="404">Something went wrong. No Lyrics will be returned.</response>
|
||||
/// <returns>An <see cref="OkResult"/> containing the item's lyrics.</returns>
|
||||
[HttpGet("Audio/{itemId}/Lyrics")]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<LyricDto>> GetLyrics([FromRoute, Required] Guid itemId)
|
||||
{
|
||||
var isApiKey = User.GetIsApiKey();
|
||||
var userId = User.GetUserId();
|
||||
if (!isApiKey && userId.IsEmpty())
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var audio = _libraryManager.GetItemById<Audio>(itemId);
|
||||
if (audio is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!isApiKey)
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
if (user is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
// Check the item is visible for the user
|
||||
if (!audio.IsVisible(user))
|
||||
{
|
||||
return Unauthorized($"{user.Username} is not permitted to access item {audio.Name}.");
|
||||
}
|
||||
}
|
||||
|
||||
var result = await _lyricManager.GetLyricsAsync(audio, CancellationToken.None).ConfigureAwait(false);
|
||||
if (result is not null)
|
||||
{
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upload an external lyric file.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The item the lyric belongs to.</param>
|
||||
/// <param name="fileName">Name of the file being uploaded.</param>
|
||||
/// <response code="200">Lyrics uploaded.</response>
|
||||
/// <response code="400">Error processing upload.</response>
|
||||
/// <response code="404">Item not found.</response>
|
||||
/// <returns>The uploaded lyric.</returns>
|
||||
[HttpPost("Audio/{itemId}/Lyrics")]
|
||||
[Authorize(Policy = Policies.LyricManagement)]
|
||||
[AcceptsFile(MediaTypeNames.Text.Plain)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<LyricDto>> UploadLyrics(
|
||||
[FromRoute, Required] Guid itemId,
|
||||
[FromQuery, Required] string fileName)
|
||||
{
|
||||
var audio = _libraryManager.GetItemById<Audio>(itemId);
|
||||
if (audio is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (Request.ContentLength.GetValueOrDefault(0) == 0)
|
||||
{
|
||||
return BadRequest("No lyrics uploaded");
|
||||
}
|
||||
|
||||
// Utilize Path.GetExtension as it provides extra path validation.
|
||||
var format = Path.GetExtension(fileName.AsSpan()).RightPart('.').ToString();
|
||||
if (string.IsNullOrEmpty(format))
|
||||
{
|
||||
return BadRequest("Extension is required on filename");
|
||||
}
|
||||
|
||||
var stream = new MemoryStream();
|
||||
await using (stream.ConfigureAwait(false))
|
||||
{
|
||||
await Request.Body.CopyToAsync(stream).ConfigureAwait(false);
|
||||
var uploadedLyric = await _lyricManager.SaveLyricAsync(
|
||||
audio,
|
||||
format,
|
||||
stream)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (uploadedLyric is null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
_providerManager.QueueRefresh(audio.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
|
||||
return Ok(uploadedLyric);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an external lyric file.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <response code="204">Lyric deleted.</response>
|
||||
/// <response code="404">Item not found.</response>
|
||||
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
||||
[HttpDelete("Audio/{itemId}/Lyrics")]
|
||||
[Authorize(Policy = Policies.LyricManagement)]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> DeleteLyrics(
|
||||
[FromRoute, Required] Guid itemId)
|
||||
{
|
||||
var audio = _libraryManager.GetItemById<Audio>(itemId);
|
||||
if (audio is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
await _lyricManager.DeleteLyricsAsync(audio).ConfigureAwait(false);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search remote lyrics.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <response code="200">Lyrics retrieved.</response>
|
||||
/// <response code="404">Item not found.</response>
|
||||
/// <returns>An array of <see cref="RemoteLyricInfo"/>.</returns>
|
||||
[HttpGet("Audio/{itemId}/RemoteSearch/Lyrics")]
|
||||
[Authorize(Policy = Policies.LyricManagement)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<IReadOnlyList<RemoteLyricInfoDto>>> SearchRemoteLyrics([FromRoute, Required] Guid itemId)
|
||||
{
|
||||
var audio = _libraryManager.GetItemById<Audio>(itemId);
|
||||
if (audio is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var results = await _lyricManager.SearchLyricsAsync(audio, false, CancellationToken.None).ConfigureAwait(false);
|
||||
return Ok(results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a remote lyric.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="lyricId">The lyric id.</param>
|
||||
/// <response code="200">Lyric downloaded.</response>
|
||||
/// <response code="404">Item not found.</response>
|
||||
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
||||
[HttpPost("Audio/{itemId}/RemoteSearch/Lyrics/{lyricId}")]
|
||||
[Authorize(Policy = Policies.LyricManagement)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<LyricDto>> DownloadRemoteLyrics(
|
||||
[FromRoute, Required] Guid itemId,
|
||||
[FromRoute, Required] string lyricId)
|
||||
{
|
||||
var audio = _libraryManager.GetItemById<Audio>(itemId);
|
||||
if (audio is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var downloadedLyrics = await _lyricManager.DownloadLyricsAsync(audio, lyricId, CancellationToken.None).ConfigureAwait(false);
|
||||
if (downloadedLyrics is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_providerManager.QueueRefresh(audio.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
|
||||
return Ok(downloadedLyrics);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the remote lyrics.
|
||||
/// </summary>
|
||||
/// <param name="lyricId">The remote provider item id.</param>
|
||||
/// <response code="200">File returned.</response>
|
||||
/// <response code="404">Lyric not found.</response>
|
||||
/// <returns>A <see cref="FileStreamResult"/> with the lyric file.</returns>
|
||||
[HttpGet("Providers/Lyrics/{lyricId}")]
|
||||
[Authorize(Policy = Policies.LyricManagement)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<LyricDto>> GetRemoteLyrics([FromRoute, Required] string lyricId)
|
||||
{
|
||||
var result = await _lyricManager.GetRemoteLyricsAsync(lyricId, CancellationToken.None).ConfigureAwait(false);
|
||||
if (result is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
#pragma warning disable SA1300 // Lowercase required for backwards compat.
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Jellyfin.Data.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Media streaming protocol.
|
||||
/// Lowercase for backwards compatibility.
|
||||
/// </summary>
|
||||
[DefaultValue(http)]
|
||||
public enum MediaStreamProtocol
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP.
|
||||
/// </summary>
|
||||
http = 0,
|
||||
|
||||
/// <summary>
|
||||
/// HTTP Live Streaming.
|
||||
/// </summary>
|
||||
hls = 1
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue