aboutsummaryrefslogtreecommitdiff
path: root/deployment
diff options
context:
space:
mode:
authorAndrew Rabert <6550543+nvllsvm@users.noreply.github.com>2019-01-22 18:13:47 -0500
committerGitHub <noreply@github.com>2019-01-22 18:13:47 -0500
commit28483bdb54be96ae83e0fded097f534d7e26ba1e (patch)
treee7f4b92326417ebf55eecdf68a01d2c3b9e660d7 /deployment
parent920c39454c05e979eabe81877269cd4517a03ccf (diff)
parent8106c8393b711a7e1d40487e3caf2b014decbe28 (diff)
Merge pull request #651 from jellyfin/release-10.1.0
Release 10.1.0
Diffstat (limited to 'deployment')
-rw-r--r--deployment/README.md111
-rwxr-xr-xdeployment/common.build.sh112
-rw-r--r--deployment/debian-package-x64/Dockerfile23
-rwxr-xr-xdeployment/debian-package-x64/clean.sh7
-rw-r--r--deployment/debian-package-x64/dependencies.txt1
-rwxr-xr-xdeployment/debian-package-x64/package.sh31
-rw-r--r--deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers37
-rw-r--r--deployment/debian-package-x64/pkg-src/bin/restart.sh18
-rw-r--r--deployment/debian-package-x64/pkg-src/changelog152
-rw-r--r--deployment/debian-package-x64/pkg-src/compat1
-rw-r--r--deployment/debian-package-x64/pkg-src/conf/jellyfin34
-rw-r--r--deployment/debian-package-x64/pkg-src/conf/jellyfin.service.conf7
-rw-r--r--deployment/debian-package-x64/pkg-src/conf/logging.json30
-rw-r--r--deployment/debian-package-x64/pkg-src/control23
-rw-r--r--deployment/debian-package-x64/pkg-src/copyright29
-rw-r--r--deployment/debian-package-x64/pkg-src/gbp.conf6
-rw-r--r--deployment/debian-package-x64/pkg-src/install6
-rw-r--r--deployment/debian-package-x64/pkg-src/jellyfin.init49
-rw-r--r--deployment/debian-package-x64/pkg-src/jellyfin.service14
-rw-r--r--deployment/debian-package-x64/pkg-src/jellyfin.upstart20
-rw-r--r--deployment/debian-package-x64/pkg-src/po/POTFILES.in1
-rw-r--r--deployment/debian-package-x64/pkg-src/po/templates.pot57
-rw-r--r--deployment/debian-package-x64/pkg-src/postinst87
-rw-r--r--deployment/debian-package-x64/pkg-src/postrm75
-rw-r--r--deployment/debian-package-x64/pkg-src/preinst74
-rw-r--r--deployment/debian-package-x64/pkg-src/prerm60
-rw-r--r--deployment/debian-package-x64/pkg-src/rules23
-rw-r--r--deployment/debian-package-x64/pkg-src/source.lintian-overrides3
-rw-r--r--deployment/debian-package-x64/pkg-src/source/format1
-rw-r--r--deployment/debian-package-x64/pkg-src/source/options11
-rwxr-xr-xdeployment/debian-x64/build.sh7
-rwxr-xr-xdeployment/debian-x64/clean.sh7
-rw-r--r--deployment/debian-x64/dependencies.txt1
-rwxr-xr-xdeployment/debian-x64/package.sh7
-rwxr-xr-xdeployment/docker/build.sh12
-rw-r--r--deployment/docker/dependencies.txt1
-rwxr-xr-xdeployment/docker/package.sh12
-rw-r--r--deployment/fedora-package-x64/Dockerfile15
-rwxr-xr-xdeployment/fedora-package-x64/clean.sh7
-rw-r--r--deployment/fedora-package-x64/dependencies.txt1
-rwxr-xr-xdeployment/fedora-package-x64/package.sh83
-rw-r--r--deployment/fedora-package-x64/pkg-src/.gitignore3
-rw-r--r--deployment/fedora-package-x64/pkg-src/README.md43
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin-firewalld.xml9
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.env27
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.override.conf7
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.service15
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.spec218
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.sudoers19
-rw-r--r--deployment/fedora-package-x64/pkg-src/restart.sh6
-rwxr-xr-xdeployment/framework/build.sh8
-rwxr-xr-xdeployment/framework/clean.sh7
-rwxr-xr-xdeployment/framework/package.sh7
-rwxr-xr-xdeployment/linux-x64/build.sh7
-rwxr-xr-xdeployment/linux-x64/clean.sh7
-rw-r--r--deployment/linux-x64/dependencies.txt1
-rwxr-xr-xdeployment/linux-x64/package.sh7
-rwxr-xr-xdeployment/osx-x64/build.sh7
-rwxr-xr-xdeployment/osx-x64/clean.sh7
-rw-r--r--deployment/osx-x64/dependencies.txt1
-rwxr-xr-xdeployment/osx-x64/package.sh7
-rwxr-xr-xdeployment/ubuntu-x64/build.sh7
-rwxr-xr-xdeployment/ubuntu-x64/clean.sh7
-rw-r--r--deployment/ubuntu-x64/dependencies.txt1
-rwxr-xr-xdeployment/ubuntu-x64/package.sh7
-rw-r--r--deployment/unraid/docker-templates/README.md15
-rw-r--r--deployment/unraid/docker-templates/jellyfin.xml51
-rw-r--r--deployment/win-generic/build-jellyfin.ps1110
-rw-r--r--deployment/win-generic/dependencies.txt1
-rw-r--r--deployment/win-generic/install-jellyfin.ps1460
-rw-r--r--deployment/win-generic/install.bat1
-rwxr-xr-xdeployment/win-x64/build.sh7
-rwxr-xr-xdeployment/win-x64/clean.sh7
-rw-r--r--deployment/win-x64/dependencies.txt1
-rwxr-xr-xdeployment/win-x64/package.sh9
-rwxr-xr-xdeployment/win-x86/build.sh7
-rwxr-xr-xdeployment/win-x86/clean.sh7
-rw-r--r--deployment/win-x86/dependencies.txt1
-rwxr-xr-xdeployment/win-x86/package.sh9
79 files changed, 2377 insertions, 0 deletions
diff --git a/deployment/README.md b/deployment/README.md
new file mode 100644
index 000000000..05b4ed51e
--- /dev/null
+++ b/deployment/README.md
@@ -0,0 +1,111 @@
+# Jellyfin Packaging
+
+This directory contains the packaging configuration of Jellyfin for multiple platforms. The specification is below; all package platforms must follow the specification to be compatable with the central `build` script.
+
+## Package List
+
+### Operating System Packages
+
+* `debian-package-x64`: Package for Debian and Ubuntu amd64 systems.
+* `fedora-package-x64`: Package for Fedora, CentOS, and Red Hat Enterprise Linux amd64 systems.
+
+### Portable Builds (archives)
+
+* `debian-x64`: Portable binary archive for Debian amd64 systems.
+* `ubuntu-x64`: Portable binary archive for Ubuntu amd64 systems.
+* `linux-x64`: Portable binary archive for generic Linux amd64 systems.
+* `osx-x64`: Portable binary archive for MacOS amd64 systems.
+* `win-x64`: Portable binary archive for Windows amd64 systems.
+* `win-x86`: Portable binary archive for Windows i386 systems.
+
+### Other Builds
+
+These builds are not necessarily run from the `build` script, but are present for other platforms.
+
+* `framework`: Compiled `.dll` for use with .NET Core runtime on any system.
+* `docker`: Docker manifests for auto-publishing.
+* `unraid`: unRaid Docker template; not built by `build` but imported into unRaid directly.
+* `win-generic`: Portable binary for generic Windows systems.
+
+## Package Specification
+
+### Dependencies
+
+* If a platform requires additional build dependencies, the required binary names, i.e. to validate `which <binary>`, should be specified in a `dependencies.txt` file inside the platform directory.
+
+* Each dependency should be present on its own line.
+
+### Action Scripts
+
+* Actions are defined in BASH scripts with the name `<action>.sh` within the platform directory.
+
+* The list of valid actions are:
+
+ 1. `build`: Builds a set of binaries.
+ 2. `package`: Assembles the compiled binaries into a package.
+ 3. `sign`: Performs signing actions on a package.
+ 4. `publish`: Performs a publishing action for a package.
+ 5. `clean`: Cleans up any artifacts from the previous actions.
+
+* All package actions are optional, however at least one should generate output files, and any that do should contain a `clean` action.
+
+* Actions are executed in the order specified above, and later actions may depend on former actions.
+
+* Actions except for `clean` should `set -o errexit` to terminate on failed actions.
+
+* The `clean` action should always `exit 0` even if no work is done or it fails.
+
+### Output Files
+
+* Upon completion of the defined actions, at least one output file must be created in the `<platform>/pkg-dist` directory.
+
+* Output files will be moved to the directory `jellyfin-build/<platform>` one directory above the repository root upon completion.
+
+### Common Functions
+
+* A number of common functions are defined in `deployment/common.build.sh` for use by platform scripts.
+
+* Each action script should import the common functions to define a number of standard variables.
+
+* The common variables are:
+
+ * `ROOT`: The Jellyfin repostiory root, usually `../..`.
+ * `CONFIG`: The .NET config, usually `Release`.
+ * `DOTNETRUNTIME`: The .NET `--runtime` value, platform-dependent.
+ * `OUTPUT_DIR`: The intermediate output dir, usually `./dist/jellyfin_${VERSION}`.
+ * `BUILD_CONTEXT`: The Docker build context, usually `../..`.
+ * `DOCKERFILE`: The Dockerfile, usually `Dockerfile` in the platform directory.
+ * `IMAGE_TAG`: A tag for the built Docker image.
+ * `PKG_DIR`: The final binary output directory for collection, invariably `pkg-dist`.
+ * `ARCHIVE_CMD`: The compression/archive command for release archives, usually `tar -xvzf` or `zip`.
+
+#### `get_version`
+
+Reads the version information from `SharedVersion.cs`.
+
+**Arguments:** `ROOT`
+
+#### `build_jellyfin`
+
+Build a standard self-contained binary in the current OS context.
+
+**Arguments:** `ROOT` `CONFIG` `DOTNETRUNTIME` `OUTPUT_DIR`
+
+#### `build_jellyfin_docker`
+
+Build a standard self-contained binary in a Docker image.
+
+**Arguments:** `BUILD_CONTEXT` `DOCKERFILE` `IMAGE_TAG`
+
+#### `clean_jellyfin`
+
+Clean up a build for housekeeping.
+
+**Arguments:** `ROOT` `CONFIG` `OUTPUT_DIR` `PKG_DIR`
+
+#### `package_portable`
+
+Produce a compressed archive.
+
+**Arguments:** `ROOT` `OUTPUT_DIR` `PKG_DIR` `ARCHIVE_CMD`
+
diff --git a/deployment/common.build.sh b/deployment/common.build.sh
new file mode 100755
index 000000000..7392fd401
--- /dev/null
+++ b/deployment/common.build.sh
@@ -0,0 +1,112 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o nounset
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+CYAN='\033[0;36m'
+NC='\033[0m' # No Color
+
+DEFAULT_BUILD_CONTEXT="../.."
+DEFAULT_ROOT="."
+DEFAULT_DOTNETRUNTIME="framework"
+DEFAULT_CONFIG="Release"
+DEFAULT_OUTPUT_DIR="dist/jellyfin-git"
+DEFAULT_PKG_DIR="pkg-dist"
+DEFAULT_DOCKERFILE="Dockerfile"
+DEFAULT_IMAGE_TAG="jellyfin:"`git rev-parse --abbrev-ref HEAD`
+DEFAULT_ARCHIVE_CMD="tar -xvzf"
+
+# Parse the version from the AssemblyVersion
+get_version()
+(
+ local ROOT=${1-$DEFAULT_ROOT}
+ grep "AssemblyVersion" ${ROOT}/SharedVersion.cs \
+ | sed -E 's/\[assembly: ?AssemblyVersion\("([0-9\.]+)"\)\]/\1/' \
+ | sed -E 's/.0$//'
+)
+
+# Run a build
+build_jellyfin()
+(
+ ROOT=${1-$DEFAULT_ROOT}
+ CONFIG=${2-$DEFAULT_CONFIG}
+ DOTNETRUNTIME=${3-$DEFAULT_DOTNETRUNTIME}
+ OUTPUT_DIR=${4-$DEFAULT_OUTPUT_DIR}
+
+ echo -e "${CYAN}Building jellyfin in '${ROOT}' for ${DOTNETRUNTIME} with configuration ${CONFIG} and output directory '${OUTPUT_DIR}'.${NC}"
+ if [[ $DOTNETRUNTIME == 'framework' ]]; then
+ dotnet publish "${ROOT}" --configuration "${CONFIG}" --output="${OUTPUT_DIR}"
+ else
+ dotnet publish "${ROOT}" --configuration "${CONFIG}" --output="${OUTPUT_DIR}" --self-contained --runtime ${DOTNETRUNTIME}
+ fi
+ EXIT_CODE=$?
+ if [ $EXIT_CODE -eq 0 ]; then
+ echo -e "${GREEN}[DONE] Build jellyfin in '${ROOT}' for ${DOTNETRUNTIME} with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' complete.${NC}"
+ else
+ echo -e "${RED}[FAIL] Build jellyfin in '${ROOT}' for ${DOTNETRUNTIME} with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' FAILED.${NC}"
+ fi
+)
+
+# Run a docker
+build_jellyfin_docker()
+(
+ BUILD_CONTEXT=${1-$DEFAULT_BUILD_CONTEXT}
+ DOCKERFILE=${2-$DEFAULT_DOCKERFILE}
+ IMAGE_TAG=${3-$DEFAULT_IMAGE_TAG}
+
+ echo -e "${CYAN}Building jellyfin docker image in '${BUILD_CONTEXT}' with Dockerfile '${DOCKERFILE}' and tag '${IMAGE_TAG}'.${NC}"
+ docker build -t ${IMAGE_TAG} -f ${DOCKERFILE} ${BUILD_CONTEXT}
+ EXIT_CODE=$?
+ if [ $EXIT_CODE -eq 0 ]; then
+ echo -e "${GREEN}[DONE] Building jellyfin docker image in '${BUILD_CONTEXT}' with Dockerfile '${DOCKERFILE}' and tag '${IMAGE_TAG}' complete.${NC}"
+ else
+ echo -e "${RED}[FAIL] Building jellyfin docker image in '${BUILD_CONTEXT}' with Dockerfile '${DOCKERFILE}' and tag '${IMAGE_TAG}' FAILED.${NC}"
+ fi
+)
+
+# Clean a build
+clean_jellyfin()
+(
+ local ROOT=${1-$DEFAULT_ROOT}
+ local CONFIG=${2-$DEFAULT_CONFIG}
+ local OUTPUT_DIR=${3-$DEFAULT_OUTPUT_DIR}
+ local PKG_DIR=${4-$DEFAULT_PKG_DIR}
+ echo -e "${CYAN}Cleaning jellyfin in '${ROOT}'' with configuration ${CONFIG} and output directory '${OUTPUT_DIR}'.${NC}"
+ echo -e "${CYAN}Deleting '${OUTPUT_DIR}'${NC}"
+ rm -rf "$OUTPUT_DIR"
+ echo -e "${CYAN}Deleting '${PKG_DIR}'${NC}"
+ rm -rf "$PKG_DIR"
+ dotnet clean "${ROOT}" -maxcpucount:1 --configuration ${CONFIG}
+ local EXIT_CODE=$?
+ if [ $EXIT_CODE -eq 0 ]; then
+ echo -e "${GREEN}[DONE] Clean jellyfin in '${ROOT}' with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' complete.${NC}"
+ else
+ echo -e "${RED}[FAIL] Clean jellyfin in '${ROOT}' with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' failed.${NC}"
+ fi
+)
+
+# Packages the output folder into an archive.
+package_portable()
+(
+ local ROOT=${1-$DEFAULT_ROOT}
+ local OUTPUT_DIR=${2-$DEFAULT_OUTPUT_DIR}
+ local PKG_DIR=${3-$DEFAULT_PKG_DIR}
+ local ARCHIVE_CMD=${4-$DEFAULT_ARCHIVE_CMD}
+ # Package portable build result
+ if [ -d ${OUTPUT_DIR} ]; then
+ echo -e "${CYAN}Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}'.${NC}"
+ mkdir -p ${PKG_DIR}
+ tar -zcvf "${PKG_DIR}/`basename "${OUTPUT_DIR}"`.portable.tar.gz" -C "`dirname "${OUTPUT_DIR}"`" "`basename "${OUTPUT_DIR}"`"
+ local EXIT_CODE=$?
+ if [ $EXIT_CODE -eq 0 ]; then
+ echo -e "${GREEN}[DONE] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' complete.${NC}"
+ else
+ echo -e "${RED}[FAIL] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' FAILED.${NC}"
+ fi
+ else
+ echo -e "${RED}[FAIL] Build artifacts do not exist for ${OUTPUT_DIR}. Run build.sh first.${NC}"
+ fi
+)
+
diff --git a/deployment/debian-package-x64/Dockerfile b/deployment/debian-package-x64/Dockerfile
new file mode 100644
index 000000000..2afe6c1d3
--- /dev/null
+++ b/deployment/debian-package-x64/Dockerfile
@@ -0,0 +1,23 @@
+FROM debian:9
+ARG SOURCEDIR=/repo
+ENV DEB_BUILD_OPTIONS=noddebs
+
+# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+RUN apt-get update \
+ && apt-get install -y apt-transport-https debhelper gnupg wget devscripts \
+ && wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg \
+ && mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/ \
+ && wget -q https://packages.microsoft.com/config/debian/9/prod.list \
+ && mv prod.list /etc/apt/sources.list.d/microsoft-prod.list \
+ && chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg \
+ && chown root:root /etc/apt/sources.list.d/microsoft-prod.list \
+ && apt-get update
+
+WORKDIR ${SOURCEDIR}
+COPY . .
+COPY ./deployment/debian-package-x64/pkg-src ./debian
+
+RUN yes | mk-build-deps -i debian/control \
+ && dpkg-buildpackage -us -uc
+
+WORKDIR /
diff --git a/deployment/debian-package-x64/clean.sh b/deployment/debian-package-x64/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/debian-package-x64/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/debian-package-x64/dependencies.txt b/deployment/debian-package-x64/dependencies.txt
new file mode 100644
index 000000000..bdb967096
--- /dev/null
+++ b/deployment/debian-package-x64/dependencies.txt
@@ -0,0 +1 @@
+docker
diff --git a/deployment/debian-package-x64/package.sh b/deployment/debian-package-x64/package.sh
new file mode 100755
index 000000000..dec953961
--- /dev/null
+++ b/deployment/debian-package-x64/package.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+# TODO get the version in the package automatically. And using the changelog to decide the debian package suffix version.
+
+# Build a Jellyfin .deb file with Docker on Linux
+# Places the output .deb file in the parent directory
+
+package_temporary_dir="`pwd`/pkg-dist-tmp"
+output_dir="`pwd`/pkg-dist"
+current_user="`whoami`"
+image_name="jellyfin-debuild"
+
+cleanup() {
+ set +o errexit
+ docker image rm $image_name --force
+ rm -rf "$package_temporary_dir"
+}
+trap cleanup EXIT INT
+
+docker build ../.. -t "$image_name" -f ./Dockerfile --build-arg SOURCEDIR="/jellyfin-${VERSION}"
+mkdir -p "$package_temporary_dir"
+mkdir -p "$output_dir"
+docker run --rm -v "$package_temporary_dir:/temp" "$image_name" sh -c 'find / -maxdepth 1 -type f -name "jellyfin*" -exec mv {} /temp \;'
+chown -R "$current_user" "$package_temporary_dir" \
+|| sudo chown -R "$current_user" "$package_temporary_dir"
+
+mv "$package_temporary_dir"/* "$output_dir"
diff --git a/deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers b/deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers
new file mode 100644
index 000000000..4eb91366b
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers
@@ -0,0 +1,37 @@
+#Allow jellyfin group to start, stop and restart itself
+Cmnd_Alias RESTARTSERVER_SYSV = /sbin/service jellyfin restart, /usr/sbin/service jellyfin restart
+Cmnd_Alias STARTSERVER_SYSV = /sbin/service jellyfin start, /usr/sbin/service jellyfin start
+Cmnd_Alias STOPSERVER_SYSV = /sbin/service jellyfin stop, /usr/sbin/service jellyfin stop
+Cmnd_Alias RESTARTSERVER_SYSTEMD = /usr/bin/systemctl restart jellyfin, /bin/systemctl restart jellyfin
+Cmnd_Alias STARTSERVER_SYSTEMD = /usr/bin/systemctl start jellyfin, /bin/systemctl start jellyfin
+Cmnd_Alias STOPSERVER_SYSTEMD = /usr/bin/systemctl stop jellyfin, /bin/systemctl stop jellyfin
+Cmnd_Alias RESTARTSERVER_INITD = /etc/init.d/jellyfin restart
+Cmnd_Alias STARTSERVER_INITD = /etc/init.d/jellyfin start
+Cmnd_Alias STOPSERVER_INITD = /etc/init.d/jellyfin stop
+
+
+%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSV
+%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSV
+%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSV
+%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSTEMD
+%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSTEMD
+%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSTEMD
+%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_INITD
+%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_INITD
+%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_INITD
+
+Defaults!RESTARTSERVER_SYSV !requiretty
+Defaults!STARTSERVER_SYSV !requiretty
+Defaults!STOPSERVER_SYSV !requiretty
+Defaults!RESTARTSERVER_SYSTEMD !requiretty
+Defaults!STARTSERVER_SYSTEMD !requiretty
+Defaults!STOPSERVER_SYSTEMD !requiretty
+Defaults!RESTARTSERVER_INITD !requiretty
+Defaults!STARTSERVER_INITD !requiretty
+Defaults!STOPSERVER_INITD !requiretty
+
+#Allow the server to mount iso images
+%jellyfin ALL=(ALL) NOPASSWD: /bin/mount
+%jellyfin ALL=(ALL) NOPASSWD: /bin/umount
+
+Defaults:%jellyfin !requiretty
diff --git a/deployment/debian-package-x64/pkg-src/bin/restart.sh b/deployment/debian-package-x64/pkg-src/bin/restart.sh
new file mode 100644
index 000000000..a6f4632ba
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/bin/restart.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+NAME=jellyfin
+
+restart_cmds=("s6-svc -t /var/run/s6/services/${NAME}" \
+ "systemctl restart ${NAME}" \
+ "service ${NAME} restart" \
+ "/etc/init.d/${NAME} restart")
+
+for restart_cmd in "${restart_cmds[@]}"; do
+ cmd=$(echo "$restart_cmd" | awk '{print $1}')
+ cmd_loc=$(command -v ${cmd})
+ if [[ -n "$cmd_loc" ]]; then
+ restart_cmd=$(echo "$restart_cmd" | sed -e "s%${cmd}%${cmd_loc}%")
+ echo "sleep 2; sudo $restart_cmd > /dev/null 2>&1" | at now > /dev/null 2>&1
+ exit 0
+ fi
+done
diff --git a/deployment/debian-package-x64/pkg-src/changelog b/deployment/debian-package-x64/pkg-src/changelog
new file mode 100644
index 000000000..7f3f12b00
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/changelog
@@ -0,0 +1,152 @@
+jellyfin (10.1.0-1) unstable; urgency=medium
+
+ * jellyfin:
+ * PR335 Build scripts and build system consolidation.
+ * PR424 add jellyfin-web as submodule
+ * PR455 Cleanup some small things
+ * PR458 Clean up several minor issues and add TODOs
+ * PR506 Removing tabs and trailing whitespace
+ * PR508 Update internal versioning and user agents.
+ * PR516 Remove useless properties from IEnvironmentInfo
+ * PR520 Fix potential bug where aspect ratio would be incorrectly calculated
+ * PR534 Add linux-arm and linux-arm64 native NuGet dependency.
+ * PR540 Update Emby API keys to our own
+ * PR541 Change ItemId to Guid in ProviderManager
+ * PR556 Fix "Password Reset by PIN" page
+ * PR562 Fix error with uppercase photo extension and fix typo in a log line
+ * PR563 Update dev from master
+ * PR566 Avoid printing stacktrace when bind to port 1900 fails
+ * PR567 Shutdown gracefully when recieving a termination signal
+ * PR571 Add more NuGet metadata properties
+ * PR575 Reformat all C# server code to conform with code standards
+ * PR576 Add code analysers for debug builds
+ * PR580 Fix Docker build
+ * PR582 Replace custom image parser with Skia
+ * PR587 Add nuget info to Emby.Naming
+ * PR589 Ensure config and log folders exist
+ * PR596 Fix indentation for xml files
+ * PR598 Remove MediaBrowser.Text for license violations and hackiness
+ * PR606 Slim down docker image
+ * PR613 Update MediaEncoding
+ * PR616 Add Swagger documentation
+ * PR619 Really slim down Docker container
+ * PR621 Minor improvements to library scan code
+ * PR622 Add unified build script and bump_version script
+ * PR623 Replaced injections of ILogger with ILoggerFactory
+ * PR625 Update taglib-sharp
+ * PR626 Fix extra type name in parameter, add out keyword
+ * PR627 Use string for ApplicationVersion
+ * PR628 Update Product Name (User-Agent)
+ * PR629 Fix subtitle converter misinterpreting 0 valued endTimeTicks
+ * PR631 Cleanup ImageProcessor and SkiaEncoder
+ * PR634 Replace our TVDB key with @drakus72's which is V1
+ * PR636 Allow subtitle extraction and conversion in direct streaming
+ * PR637 Remove unused font
+ * PR638 Removed XmlTv testfiles and nuget install
+ * PR646: Fix infinite loop bug on subtitle.m3u8 request
+ * PR655: Support trying local branches in submodule
+ * PR661: Fix NullRef from progress report
+ * PR666: Add cross-platform build for arm64
+ * jellyfin-web:
+ * PR1: Change webcomponents to non-minified version
+ * PR4: Fix user profile regression
+ * PR6: Make icon into proper ico and large PNG
+ * PR7: Fix firefox failing to set password for users with no password set
+ * PR8: Remove premiere stuff and fix crashes caused by earlier removals
+ * PR12: Fix return from PIN reset to index.html
+ * PR13: Send android clients to select server before login
+ * PR14: Reimplement page to add server
+ * PR16: Fix spinning circle at the end of config wizard
+ * PR17: Fix directorybrower not resetting scroll
+ * PR19: Set union merge for CONTRIBUTORS.md
+ * PR20: Show album thumbnail and artist image in page itemdetail
+ * PR26: Make the card titles clickable
+ * PR27: Stop pagination and adding a library from being able to trigger multiple times
+ * PR28: Add transparent nav bar to BlueRadiance theme CSS
+ * PR29: Clean up imageuploader
+ * PR30: Remove iap and simplify registrationservices
+ * PR36: Open videos in fullscreen on android devices
+ * PR37: Remove broken features from web interface
+ * PR38: Fix inconsistent UI coloring around settings drawer
+ * PR39: Remove back button from dashboard and metadata manager
+ * PR42: Fix Home backdrop not loading
+ * PR43: Filter videos by audio stream language
+ * PR44: Remove filter from library collection type options
+ * PR45: Fix data-backbutton logic
+ * PR46: Minor changes to navbar elements
+ * PR48: Remove Sync code
+ * PR52: Fix progress color
+ * PR53: Fix user tabs color
+ * PR54: Add back button to server dashboard
+
+ -- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 20 Jan 2019 23:19:46 -0500
+
+jellyfin (10.0.2-1) unstable; urgency=medium
+
+ * Hotfix release
+ * jellyfin/jellyfin-web#23: Update Chromecast app ID [via direct commit]
+ * #540: Update Emby API keys to our own
+ * #541: Change ItemId to Guid in ProviderManager
+ * #566: Avoid printing stacktrace when bind to port 1900 fails
+
+ -- Joshua Boniface <joshua@boniface.me> Sat, 19 Jan 2019 01:19:59 -0500
+
+jellyfin (10.0.1-1) unstable; urgency=medium
+
+ * Hotfix release, corrects several small bugs from 10.0.0
+ * #512: Fix CONTRIBUTORS.md formatting
+ * #501: Fix regression in integer divisions in latest movies category
+ * #498: Change contributing link in settings to readthedocs.io
+ * #493: Remove unused values.txt resource
+ * #491: Fix userprofile.js crash
+ * #519: Fix the DecodeJfif function to get proper image sizes
+ * #486: Add NuGet package info to plugin projects
+
+ -- Joshua Boniface <joshua@boniface.me> Tue, 08 Jan 2019 20:06:01 -0500
+
+jellyfin (10.0.0-1) unstable; urgency=medium
+
+ * The first Jellyfin release under our new versioning scheme
+ * Numerous bugfixes and code readability improvements
+ * Updated logging configuration, including flag for it and configdir
+ * Updated theming including logo
+ * Dozens of other improvements as documented in GitHub pull request #419
+
+ -- Joshua Boniface <joshua@boniface.me> Sat, 05 Jan 2019 15:39:25 -0500
+
+jellyfin (3.5.2-5) unstable; urgency=medium
+
+ * Fully GPL'd release - remove tainted code from MediaBrowser.Common
+ * Several code cleanups and tweaks
+
+ -- Joshua Boniface <joshua@boniface.me> Fri, 28 Dec 2018 10:26:30 -0500
+
+jellyfin (3.5.2-4) unstable; urgency=medium
+
+ * Correct manifest.json bug and vdpau
+
+ -- Joshua Boniface <joshua@boniface.me> Thu, 20 Dec 2018 18:31:43 -0500
+
+jellyfin (3.5.2-3) unstable; urgency=medium
+
+ * Correct several bugs in 3.5.2-2 packaging
+
+ -- Joshua Boniface <joshua@boniface.me> Sat, 15 Dec 2018 18:17:32 -0500
+
+jellyfin (3.5.2-2) unstable; urgency=medium
+
+ * Major code updates related to rebranding and cleanup
+
+ -- Joshua Boniface <joshua@boniface.me> Fri, 14 Dec 2018 00:07:46 -0500
+
+jellyfin (3.5.2-1) unstable; urgency=medium
+
+ * Add ffmpeg dependency and cleanup work
+
+ -- Joshua Boniface <joshua@boniface.me> Tue, 11 Dec 2018 20:55:32 -0500
+
+jellyfin (3.5.2) unstable; urgency=medium
+
+ * Rename from emby-server on version 3.5.2
+
+ -- Joshua Boniface <joshua@boniface.me> Sun, 9 Dec 2018 15:20:58 -0400
diff --git a/deployment/debian-package-x64/pkg-src/compat b/deployment/debian-package-x64/pkg-src/compat
new file mode 100644
index 000000000..45a4fb75d
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/compat
@@ -0,0 +1 @@
+8
diff --git a/deployment/debian-package-x64/pkg-src/conf/jellyfin b/deployment/debian-package-x64/pkg-src/conf/jellyfin
new file mode 100644
index 000000000..861865aae
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin
@@ -0,0 +1,34 @@
+# Jellyfin default configuration options
+
+# Use this file to override the default configurations; add additional
+# options with JELLYFIN_ADD_OPTS.
+
+# Under systemd, use
+# /etc/systemd/system/jellyfin.service.d/jellyfin.service.conf
+# to override the user or this config file's location.
+
+#
+# This is a POSIX shell fragment
+#
+
+#
+# General options
+#
+
+# Program directories
+JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin"
+JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin"
+JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin"
+# Restart script for in-app server control
+JELLYFIN_RESTART_SCRIPT="/usr/lib/jellyfin/restart.sh"
+# Additional options for the binary
+JELLYFIN_ADD_OPTS=""
+
+#
+# SysV init/Upstart options
+#
+
+# Application username
+JELLYFIN_USER="jellyfin"
+# Full application command
+JELLYFIN_ARGS="-programdata $JELLYFIN_DATA_DIRECTORY -configdir $JELLYFIN_CONFIG_DIRECTORY -logdir $JELLYFIN_LOG_DIRECTORY -restartpath $JELLYFIN_RESTART_SCRIPT $JELLYFIN_ADD_OPTS"
diff --git a/deployment/debian-package-x64/pkg-src/conf/jellyfin.service.conf b/deployment/debian-package-x64/pkg-src/conf/jellyfin.service.conf
new file mode 100644
index 000000000..1b69dd74e
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin.service.conf
@@ -0,0 +1,7 @@
+# Jellyfin systemd configuration options
+
+# Use this file to override the user or environment file location.
+
+[Service]
+#User = jellyfin
+#EnvironmentFile = /etc/default/jellyfin
diff --git a/deployment/debian-package-x64/pkg-src/conf/logging.json b/deployment/debian-package-x64/pkg-src/conf/logging.json
new file mode 100644
index 000000000..f32b2089e
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/conf/logging.json
@@ -0,0 +1,30 @@
+{
+ "Serilog": {
+ "MinimumLevel": "Information",
+ "WriteTo": [
+ {
+ "Name": "Console",
+ "Args": {
+ "outputTemplate": "[{Timestamp:HH:mm:ss}] [{Level:u3}] {Message:lj}{NewLine}{Exception}"
+ }
+ },
+ {
+ "Name": "Async",
+ "Args": {
+ "configure": [
+ {
+ "Name": "File",
+ "Args": {
+ "path": "%JELLYFIN_LOG_DIR%//jellyfin.log",
+ "fileSizeLimitBytes": 10485700,
+ "rollOnFileSizeLimit": true,
+ "retainedFileCountLimit": 10,
+ "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] {Message}{NewLine}{Exception}"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
diff --git a/deployment/debian-package-x64/pkg-src/control b/deployment/debian-package-x64/pkg-src/control
new file mode 100644
index 000000000..74bebeaf1
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/control
@@ -0,0 +1,23 @@
+Source: jellyfin
+Section: misc
+Priority: optional
+Maintainer: Jellyfin Team <team@jellyfin.org>
+Build-Depends: debhelper (>= 9),
+ dotnet-sdk-2.2,
+ libc6-dev,
+ libcurl4-openssl-dev,
+ libfontconfig1-dev,
+ libfreetype6-dev
+Standards-Version: 3.9.4
+Homepage: https://jellyfin.media/
+Vcs-Git: https://github.org/jellyfin/jellyfin.git
+Vcs-Browser: https://github.org/jellyfin/jellyfin
+
+Package: jellyfin
+Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
+Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
+Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
+Architecture: any
+Depends: at, libsqlite3-0, ffmpeg, libfontconfig1, libfreetype6, libssl1.0.0 | libssl1.0.2
+Description: Jellyfin is a home media server.
+ It is built on top of other popular open source technologies such as Service Stack, jQuery, jQuery mobile, and Mono. It features a REST-based api with built-in documentation to facilitate client development. We also have client libraries for our api to enable rapid development.
diff --git a/deployment/debian-package-x64/pkg-src/copyright b/deployment/debian-package-x64/pkg-src/copyright
new file mode 100644
index 000000000..0d7a2a600
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/copyright
@@ -0,0 +1,29 @@
+Format: http://dep.debian.net/deps/dep5
+Upstream-Name: jellyfin
+Source: https://github.com/jellyfin/jellyfin
+
+Files: *
+Copyright: 2018 Jellyfin Team
+License: GPL-2.0+
+
+Files: debian/*
+Copyright: 2018 Joshua Boniface <joshua@boniface.me>
+Copyright: 2014 Carlos Hernandez <carlos@techbyte.ca>
+License: GPL-2.0+
+
+License: GPL-2.0+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ This package 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 General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
diff --git a/deployment/debian-package-x64/pkg-src/gbp.conf b/deployment/debian-package-x64/pkg-src/gbp.conf
new file mode 100644
index 000000000..60b3d2872
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/gbp.conf
@@ -0,0 +1,6 @@
+[DEFAULT]
+pristine-tar = False
+cleaner = fakeroot debian/rules clean
+
+[import-orig]
+filter = [ ".git*", ".hg*", ".vs*", ".vscode*" ]
diff --git a/deployment/debian-package-x64/pkg-src/install b/deployment/debian-package-x64/pkg-src/install
new file mode 100644
index 000000000..adaff7b26
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/install
@@ -0,0 +1,6 @@
+usr/lib/jellyfin usr/lib/
+debian/conf/jellyfin etc/default/
+debian/conf/logging.json etc/jellyfin/
+debian/conf/jellyfin.service.conf etc/systemd/system/jellyfin.service.d/
+debian/bin/jellyfin-sudoers etc/sudoers.d/
+debian/bin/restart.sh usr/lib/jellyfin/
diff --git a/deployment/debian-package-x64/pkg-src/jellyfin.init b/deployment/debian-package-x64/pkg-src/jellyfin.init
new file mode 100644
index 000000000..d103fb0f1
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/jellyfin.init
@@ -0,0 +1,49 @@
+### BEGIN INIT INFO
+# Provides: Jellyfin Media Server
+# Required-Start: $local_fs $network
+# Required-Stop: $local_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Jellyfin Media Server
+# Description: Runs Jellyfin Server
+### END INIT INFO
+
+# Carry out specific functions when asked to by the system
+
+pidfile="/var/run/jellyfin.pid"
+pid=`cat $pidfile`
+
+case "$1" in
+ start)
+ if [ "$pid" == "" ]; then
+ echo "Starting Jellyfin..."
+ . /etc/default/jellyfin
+ nohup su -u $JELLYFIN_USER -c /usr/bin/jellyfin $JELLYFIN_ARGS
+ echo ?? > $pidfile
+ else
+ echo "Jellyfin already running"
+ fi
+ ;;
+ stop)
+ if [ "$pid" != "" ]; then
+ echo "Stopping Jellyfin..."
+ kill $pid
+ sleep 2
+ rm -f $pidfile
+ else
+ echo "Jellyfin not running"
+ fi
+ ;;
+ status)
+ if [ "$pid" != "" ]; then
+ echo "Jellyfin running as $pid"
+ ps -f $pid
+ else
+ echo "Jellyfin is not running"
+ fi
+ ;;
+ *)
+ echo "Usage: $0 {start|stop}"
+ exit 1
+ ;;
+esac
diff --git a/deployment/debian-package-x64/pkg-src/jellyfin.service b/deployment/debian-package-x64/pkg-src/jellyfin.service
new file mode 100644
index 000000000..c17422029
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/jellyfin.service
@@ -0,0 +1,14 @@
+[Unit]
+Description = Jellyfin Media Server
+After = network.target
+
+[Service]
+Type = simple
+EnvironmentFile = /etc/default/jellyfin
+User = jellyfin
+ExecStart = /usr/bin/jellyfin -programdata ${JELLYFIN_DATA_DIRECTORY} -configdir ${JELLYFIN_CONFIG_DIRECTORY} -logdir ${JELLYFIN_LOG_DIRECTORY} -restartpath ${JELLYFIN_RESTART_SCRIPT} ${JELLYFIN_ADD_OPTS}
+Restart = on-failure
+TimeoutSec = 15
+
+[Install]
+WantedBy = multi-user.target
diff --git a/deployment/debian-package-x64/pkg-src/jellyfin.upstart b/deployment/debian-package-x64/pkg-src/jellyfin.upstart
new file mode 100644
index 000000000..ef5bc9bca
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/jellyfin.upstart
@@ -0,0 +1,20 @@
+description "jellyfin daemon"
+
+start on (local-filesystems and net-device-up IFACE!=lo)
+stop on runlevel [!2345]
+
+console log
+respawn
+respawn limit 10 5
+
+kill timeout 20
+
+script
+ set -x
+ echo "Starting $UPSTART_JOB"
+
+ # Log file
+ logger -t "$0" "DEBUG: `set`"
+ . /etc/default/jellyfin
+ exec su -u $JELLYFIN_USER -c /usr/bin/jellyfin $JELLYFIN_ARGS
+end script
diff --git a/deployment/debian-package-x64/pkg-src/po/POTFILES.in b/deployment/debian-package-x64/pkg-src/po/POTFILES.in
new file mode 100644
index 000000000..cef83a340
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/po/POTFILES.in
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] templates
diff --git a/deployment/debian-package-x64/pkg-src/po/templates.pot b/deployment/debian-package-x64/pkg-src/po/templates.pot
new file mode 100644
index 000000000..2cdcae417
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/po/templates.pot
@@ -0,0 +1,57 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: jellyfin-server\n"
+"Report-Msgid-Bugs-To: jellyfin-server@packages.debian.org\n"
+"POT-Creation-Date: 2015-06-12 20:51-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: note
+#. Description
+#: ../templates:1001
+msgid "Jellyfin permission info:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../templates:1001
+msgid ""
+"Jellyfin by default runs under a user named \"jellyfin\". Please ensure that the "
+"user jellyfin has read and write access to any folders you wish to add to your "
+"library. Otherwise please run jellyfin under a different user."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../templates:2001
+msgid "Username to run Jellyfin as:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../templates:2001
+msgid "The user that jellyfin will run as."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../templates:3001
+msgid "Jellyfin still running"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../templates:3001
+msgid "Jellyfin is currently running. Please close it and try again."
+msgstr ""
diff --git a/deployment/debian-package-x64/pkg-src/postinst b/deployment/debian-package-x64/pkg-src/postinst
new file mode 100644
index 000000000..3690d20ba
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/postinst
@@ -0,0 +1,87 @@
+#!/bin/bash
+set -e
+
+NAME=jellyfin
+DEFAULT_FILE=/etc/default/${NAME}
+
+# Source Jellyfin default configuration
+if [[ -f $DEFAULT_FILE ]]; then
+ . $DEFAULT_FILE
+fi
+
+# Data directories for program data (cache, db), configs, and logs
+PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
+CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
+LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME}
+
+case "$1" in
+ configure)
+ # create jellyfin group if it does not exist
+ if [[ -z "$(getent group jellyfin)" ]]; then
+ addgroup --quiet --system jellyfin > /dev/null 2>&1
+ fi
+ # create jellyfin user if it does not exist
+ if [[ -z "$(getent passwd jellyfin)" ]]; then
+ adduser --system --ingroup jellyfin --shell /bin/false jellyfin --no-create-home --home ${PROGRAMDATA} \
+ --gecos "Jellyfin default user" > /dev/null 2>&1
+ fi
+ # ensure $PROGRAMDATA exists
+ if [[ ! -d $PROGRAMDATA ]]; then
+ mkdir $PROGRAMDATA
+ fi
+ # ensure $CONFIGDATA exists
+ if [[ ! -d $CONFIGDATA ]]; then
+ mkdir $CONFIGDATA
+ fi
+ # ensure $LOGDATA exists
+ if [[ ! -d $LOGDATA ]]; then
+ mkdir $LOGDATA
+ fi
+ # Ensure permissions are correct on all config directories
+ chown -R jellyfin:jellyfin $PROGRAMDATA
+ chown -R jellyfin:jellyfin $CONFIGDATA
+ chown -R jellyfin:jellyfin $LOGDATA
+
+ chmod +x /usr/lib/jellyfin/restart.sh > /dev/null 2>&1 || true
+
+ # Install jellyfin symlink into /usr/bin
+ ln -sf /usr/lib/jellyfin/bin/jellyfin /usr/bin/jellyfin
+
+ ;;
+ abort-upgrade|abort-remove|abort-deconfigure)
+ ;;
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+#DEBHELPER
+
+if [[ -x "/usr/bin/deb-systemd-helper" ]]; then
+ # Manual init script handling
+ deb-systemd-helper unmask jellyfin.service >/dev/null || true
+ # was-enabled defaults to true, so new installations run enable.
+ if deb-systemd-helper --quiet was-enabled jellyfin.service; then
+ # Enables the unit on first installation, creates new
+ # symlinks on upgrades if the unit file has changed.
+ deb-systemd-helper enable jellyfin.service >/dev/null || true
+ else
+ # Update the statefile to add new symlinks (if any), which need to be
+ # cleaned up on purge. Also remove old symlinks.
+ deb-systemd-helper update-state jellyfin.service >/dev/null || true
+ fi
+fi
+
+# End automatically added section
+# Automatically added by dh_installinit
+if [[ "$1" == "configure" ]] || [[ "$1" == "abort-upgrade" ]]; then
+ if [[ -d "/run/systemd/systemd" ]]; then
+ systemctl --system daemon-reload >/dev/null || true
+ deb-systemd-invoke start jellyfin >/dev/null || true
+ elif [[ -x "/etc/init.d/jellyfin" ]] || [[ -e "/etc/init/jellyfin.conf" ]]; then
+ update-rc.d jellyfin defaults >/dev/null
+ invoke-rc.d jellyfin start || exit $?
+ fi
+fi
+exit 0
diff --git a/deployment/debian-package-x64/pkg-src/postrm b/deployment/debian-package-x64/pkg-src/postrm
new file mode 100644
index 000000000..690f5d587
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/postrm
@@ -0,0 +1,75 @@
+#!/bin/bash
+set -e
+
+NAME=jellyfin
+DEFAULT_FILE=/etc/default/${NAME}
+
+# Source Jellyfin default configuration
+if [[ -f $DEFAULT_FILE ]]; then
+ . $DEFAULT_FILE
+fi
+
+# Data directories for program data (cache, db), configs, and logs
+PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
+CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
+LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME}
+
+# In case this system is running systemd, we make systemd reload the unit files
+# to pick up changes.
+if [[ -d /run/systemd/system ]] ; then
+ systemctl --system daemon-reload >/dev/null || true
+fi
+
+case "$1" in
+ purge)
+ echo PURGE | debconf-communicate $NAME > /dev/null 2>&1 || true
+
+ if [[ -x "/etc/init.d/jellyfin" ]] || [[ -e "/etc/init/jellyfin.connf" ]]; then
+ update-rc.d jellyfin remove >/dev/null 2>&1 || true
+ fi
+
+ if [[ -x "/usr/bin/deb-systemd-helper" ]]; then
+ deb-systemd-helper purge jellyfin.service >/dev/null
+ deb-systemd-helper unmask jellyfin.service >/dev/null
+ fi
+
+ # Remove user and group
+ userdel jellyfin > /dev/null 2>&1 || true
+ delgroup --quiet jellyfin > /dev/null 2>&1 || true
+ # Remove config dir
+ if [[ -d $CONFIGDATA ]]; then
+ rm -rf $CONFIGDATA
+ fi
+ # Remove log dir
+ if [[ -d $LOGDATA ]]; then
+ rm -rf $LOGDATA
+ fi
+ # Remove program data dir
+ if [[ -d $PROGRAMDATA ]]; then
+ rm -rf $PROGRAMDATA
+ fi
+ # Remove binary symlink
+ [[ -f /usr/bin/jellyfin ]] && rm /usr/bin/jellyfin
+ # Remove sudoers config
+ [[ -f /etc/sudoers.d/jellyfin-sudoers ]] && rm /etc/sudoers.d/jellyfin-sudoers
+ # Remove anything at the default locations; catches situations where the user moved the defaults
+ [[ -e /etc/jellyfin ]] && rm -rf /etc/jellyfin
+ [[ -e /var/log/jellyfin ]] && rm -rf /var/log/jellyfin
+ [[ -e /var/lib/jellyfin ]] && rm -rf /var/lib/jellyfin
+ ;;
+ remove)
+ if [[ -x "/usr/bin/deb-systemd-helper" ]]; then
+ deb-systemd-helper mask jellyfin.service >/dev/null
+ fi
+ ;;
+ upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ ;;
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+#DEBHELPER#
+
+exit 0
diff --git a/deployment/debian-package-x64/pkg-src/preinst b/deployment/debian-package-x64/pkg-src/preinst
new file mode 100644
index 000000000..0063e0e63
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/preinst
@@ -0,0 +1,74 @@
+#!/bin/bash
+set -e
+
+NAME=jellyfin
+DEFAULT_FILE=/etc/default/${NAME}
+
+# Source Jellyfin default configuration
+if [[ -f $DEFAULT_FILE ]]; then
+ . $DEFAULT_FILE
+fi
+
+# Data directories for program data (cache, db), configs, and logs
+PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
+CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
+LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME}
+
+# In case this system is running systemd, we make systemd reload the unit files
+# to pick up changes.
+if [[ -d /run/systemd/system ]] ; then
+ systemctl --system daemon-reload >/dev/null || true
+fi
+
+case "$1" in
+ install|upgrade)
+ # try graceful termination;
+ if [[ -d /run/systemd/system ]]; then
+ deb-systemd-invoke stop ${NAME}.service > /dev/null 2>&1 || true
+ elif [ -x "/etc/init.d/${NAME}" ] || [ -e "/etc/init/${NAME}.conf" ]; then
+ invoke-rc.d ${NAME} stop > /dev/null 2>&1 || true
+ fi
+ # try and figure out if jellyfin is running
+ PIDFILE=$(find /var/run/ -maxdepth 1 -mindepth 1 -name "jellyfin*.pid" -print -quit)
+ [[ -n "$PIDFILE" ]] && [[ -s "$PIDFILE" ]] && JELLYFIN_PID=$(cat ${PIDFILE})
+ # if its running, let's stop it
+ if [[ -n "$JELLYFIN_PID" ]]; then
+ echo "Stopping Jellyfin!"
+ # if jellyfin is still running, kill it
+ if [[ -n "$(ps -p $JELLYFIN_PID -o pid=)" ]]; then
+ CPIDS=$(pgrep -P $JELLYFIN_PID)
+ sleep 2 && kill -KILL $CPIDS
+ kill -TERM $CPIDS > /dev/null 2>&1
+ fi
+ sleep 1
+ # if it's still running, show error
+ if [[ -n "$(ps -p $JELLYFIN_PID -o pid=)" ]]; then
+ echo "Could not successfully stop JellyfinServer, please do so before uninstalling."
+ exit 1
+ else
+ [[ -f $PIDFILE ]] && rm $PIDFILE
+ fi
+ fi
+
+ # Clean up old Emby cruft that can break the user's system
+ [[ -f /etc/sudoers.d/emby ]] && rm -f /etc/sudoers.d/emby
+
+ # If we have existing config or log dirs in /var/lib/jellyfin, move them into the right place
+ if [[ -d $PROGRAMDATA/config ]]; then
+ mv $PROGRAMDATA/config $CONFIGDATA
+ fi
+ if [[ -d $PROGRAMDATA/logs ]]; then
+ mv $PROGRAMDATA/logs $LOGDATA
+ fi
+
+ ;;
+ abort-upgrade)
+ ;;
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+#DEBHELPER#
+
+exit 0
diff --git a/deployment/debian-package-x64/pkg-src/prerm b/deployment/debian-package-x64/pkg-src/prerm
new file mode 100644
index 000000000..4770c03c4
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/prerm
@@ -0,0 +1,60 @@
+#!/bin/bash
+set -e
+
+NAME=jellyfin
+DEFAULT_FILE=/etc/default/${NAME}
+
+# Source Jellyfin default configuration
+if [[ -f $DEFAULT_FILE ]]; then
+ . $DEFAULT_FILE
+fi
+
+# Data directories for program data (cache, db), configs, and logs
+PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
+CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
+LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME}
+
+case "$1" in
+ remove|upgrade|deconfigure)
+ echo "Stopping Jellyfin!"
+ # try graceful termination;
+ if [[ -d /run/systemd/system ]]; then
+ deb-systemd-invoke stop ${NAME}.service > /dev/null 2>&1 || true
+ elif [ -x "/etc/init.d/${NAME}" ] || [ -e "/etc/init/${NAME}.conf" ]; then
+ invoke-rc.d ${NAME} stop > /dev/null 2>&1 || true
+ fi
+ # Ensure that it is shutdown
+ PIDFILE=$(find /var/run/ -maxdepth 1 -mindepth 1 -name "jellyfin*.pid" -print -quit)
+ [[ -n "$PIDFILE" ]] && [[ -s "$PIDFILE" ]] && JELLYFIN_PID=$(cat ${PIDFILE})
+ # if its running, let's stop it
+ if [[ -n "$JELLYFIN_PID" ]]; then
+ # if jellyfin is still running, kill it
+ if [[ -n "$(ps -p $JELLYFIN_PID -o pid=)" ]]; then
+ CPIDS=$(pgrep -P $JELLYFIN_PID)
+ sleep 2 && kill -KILL $CPIDS
+ kill -TERM $CPIDS > /dev/null 2>&1
+ fi
+ sleep 1
+ # if it's still running, show error
+ if [[ -n "$(ps -p $JELLYFIN_PID -o pid=)" ]]; then
+ echo "Could not successfully stop Jellyfin, please do so before uninstalling."
+ exit 1
+ else
+ [[ -f $PIDFILE ]] && rm $PIDFILE
+ fi
+ fi
+ if [[ -f /usr/lib/jellyfin/bin/MediaBrowser.Server.Mono.exe.so ]]; then
+ rm /usr/lib/jellyfin/bin/MediaBrowser.Server.Mono.exe.so
+ fi
+ ;;
+ failed-upgrade)
+ ;;
+ *)
+ echo "prerm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+#DEBHELPER#
+
+exit 0
diff --git a/deployment/debian-package-x64/pkg-src/rules b/deployment/debian-package-x64/pkg-src/rules
new file mode 100644
index 000000000..ce98cb8f8
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/rules
@@ -0,0 +1,23 @@
+#! /usr/bin/make -f
+CONFIG := Release
+TERM := xterm
+SHELL := /bin/bash
+DOTNETRUNTIME := debian-x64
+export DH_VERBOSE=1
+export DOTNET_CLI_TELEMETRY_OPTOUT=1
+
+%:
+ dh $@
+
+# disable "make check"
+override_dh_auto_test:
+
+# disable stripping debugging symbols
+override_dh_clistrip:
+
+override_dh_auto_build:
+ dotnet publish --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime $(DOTNETRUNTIME) Jellyfin.Server
+
+override_dh_auto_clean:
+ dotnet clean -maxcpucount:1 --configuration $(CONFIG) Jellyfin.Server || true
+ rm -rf '$(CURDIR)/usr'
diff --git a/deployment/debian-package-x64/pkg-src/source.lintian-overrides b/deployment/debian-package-x64/pkg-src/source.lintian-overrides
new file mode 100644
index 000000000..aeb332f13
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/source.lintian-overrides
@@ -0,0 +1,3 @@
+# This is an override for the following lintian errors:
+jellyfin source: license-problem-md5sum-non-free-file Emby.Drawing/ImageMagick/fonts/webdings.ttf*
+jellyfin source: source-is-missing
diff --git a/deployment/debian-package-x64/pkg-src/source/format b/deployment/debian-package-x64/pkg-src/source/format
new file mode 100644
index 000000000..d3827e75a
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/source/format
@@ -0,0 +1 @@
+1.0
diff --git a/deployment/debian-package-x64/pkg-src/source/options b/deployment/debian-package-x64/pkg-src/source/options
new file mode 100644
index 000000000..17b5373d5
--- /dev/null
+++ b/deployment/debian-package-x64/pkg-src/source/options
@@ -0,0 +1,11 @@
+tar-ignore='.git*'
+tar-ignore='**/.git'
+tar-ignore='**/.hg'
+tar-ignore='**/.vs'
+tar-ignore='**/.vscode'
+tar-ignore='deployment'
+tar-ignore='**/bin'
+tar-ignore='**/obj'
+tar-ignore='**/.nuget'
+tar-ignore='*.deb'
+tar-ignore='ThirdParty'
diff --git a/deployment/debian-x64/build.sh b/deployment/debian-x64/build.sh
new file mode 100755
index 000000000..47cfb5327
--- /dev/null
+++ b/deployment/debian-x64/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+build_jellyfin ../../Jellyfin.Server Release debian-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/debian-x64/clean.sh b/deployment/debian-x64/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/debian-x64/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/debian-x64/dependencies.txt b/deployment/debian-x64/dependencies.txt
new file mode 100644
index 000000000..3d25d1bdf
--- /dev/null
+++ b/deployment/debian-x64/dependencies.txt
@@ -0,0 +1 @@
+dotnet
diff --git a/deployment/debian-x64/package.sh b/deployment/debian-x64/package.sh
new file mode 100755
index 000000000..13b943ea8
--- /dev/null
+++ b/deployment/debian-x64/package.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/docker/build.sh b/deployment/docker/build.sh
new file mode 100755
index 000000000..444208c85
--- /dev/null
+++ b/deployment/docker/build.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+build_jellyfin_docker ../.. ../../Dockerfile jellyfin:amd64-${VERSION}
+
+build_jellyfin_docker ../.. ../../Dockerfile.arm jellyfin:arm-${VERSION}
+
+#build_jellyfin_docker ../.. ../../Dockerfile.arm64v8 jellyfin:arm64v8-${VERSION}
+#build_jellyfin_docker ../.. ../../Dockerfile.arm32v7 jellyfin:arm32v7-${VERSION}
diff --git a/deployment/docker/dependencies.txt b/deployment/docker/dependencies.txt
new file mode 100644
index 000000000..bdb967096
--- /dev/null
+++ b/deployment/docker/dependencies.txt
@@ -0,0 +1 @@
+docker
diff --git a/deployment/docker/package.sh b/deployment/docker/package.sh
new file mode 100755
index 000000000..d74426e2f
--- /dev/null
+++ b/deployment/docker/package.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+docker manifest create jellyfin:${VERSION} jellyfin:amd64-${VERSION} jellyfin:arm32v7-${VERSION} jellyfin:arm64v8-${VERSION}
+docker manifest annotate jellyfin:amd64-${VERSION} --os linux --arch amd64
+#docker manifest annotate jellyfin:arm32v7-${VERSION} --os linux --arch arm --variant armv7
+#docker manifest annotate jellyfin:arm64v8-${VERSION} --os linux --arch arm64 --variant armv8
+
+#TODO publish.sh - docker manifest push jellyfin:${VERSION}
diff --git a/deployment/fedora-package-x64/Dockerfile b/deployment/fedora-package-x64/Dockerfile
new file mode 100644
index 000000000..e5deac29f
--- /dev/null
+++ b/deployment/fedora-package-x64/Dockerfile
@@ -0,0 +1,15 @@
+FROM fedora:29
+ARG HOME=/build
+RUN mkdir /build && \
+ dnf install -y @buildsys-build rpmdevtools dnf-plugins-core && \
+ dnf copr enable -y @dotnet-sig/dotnet && \
+ rpmdev-setuptree
+
+WORKDIR /build/rpmbuild
+COPY ./deployment/fedora-package-x64/pkg-src/jellyfin.spec SPECS
+COPY ./deployment/fedora-package-x64/pkg-src/ SOURCES
+
+RUN spectool -g -R SPECS/jellyfin.spec && \
+ rpmbuild -bs SPECS/jellyfin.spec && \
+ dnf build-dep -y SRPMS/jellyfin-*.src.rpm && \
+ rpmbuild -bb SPECS/jellyfin.spec; \ No newline at end of file
diff --git a/deployment/fedora-package-x64/clean.sh b/deployment/fedora-package-x64/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/fedora-package-x64/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/fedora-package-x64/dependencies.txt b/deployment/fedora-package-x64/dependencies.txt
new file mode 100644
index 000000000..bdb967096
--- /dev/null
+++ b/deployment/fedora-package-x64/dependencies.txt
@@ -0,0 +1 @@
+docker
diff --git a/deployment/fedora-package-x64/package.sh b/deployment/fedora-package-x64/package.sh
new file mode 100755
index 000000000..416c8213b
--- /dev/null
+++ b/deployment/fedora-package-x64/package.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env sh
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+# TODO get the version in the package automatically. And using the changelog to decide the debian package suffix version.
+
+# Build a Jellyfin .rpm file with Docker on Linux
+# Places the output .rpm file in the parent directory
+
+set -o errexit
+set -o xtrace
+set -o nounset
+
+package_temporary_dir="`pwd`/pkg-dist-tmp"
+output_dir="`pwd`/pkg-dist"
+pkg_src_dir="`pwd`/pkg-src"
+current_user="`whoami`"
+image_name="jellyfin-rpmbuild"
+
+cleanup() {
+ set +o errexit
+ docker image rm $image_name --force
+ rm -rf "$package_temporary_dir"
+ rm -rf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz"
+}
+trap cleanup EXIT INT
+GNU_TAR=1
+mkdir -p "$package_temporary_dir"
+echo "Bundling all sources for RPM build."
+tar \
+--transform "s,^\.,jellyfin-${VERSION}" \
+--exclude='.git*' \
+--exclude='**/.git' \
+--exclude='**/.hg' \
+--exclude='**/.vs' \
+--exclude='**/.vscode' \
+--exclude='deployment' \
+--exclude='**/bin' \
+--exclude='**/obj' \
+--exclude='**/.nuget' \
+--exclude='*.deb' \
+--exclude='*.rpm' \
+-Jcvf \
+"$package_temporary_dir/jellyfin-${VERSION}.tar.xz" \
+-C "../.." \
+./ || true && GNU_TAR=0
+
+if [ $GNU_TAR -eq 0 ]; then
+ echo "The installed tar binary did not support --transform. Using workaround."
+ mkdir -p "$package_temporary_dir/jellyfin-${VERSION}"
+ # Not GNU tar
+ tar \
+ --exclude='.git*' \
+ --exclude='**/.git' \
+ --exclude='**/.hg' \
+ --exclude='**/.vs' \
+ --exclude='**/.vscode' \
+ --exclude='deployment' \
+ --exclude='**/bin' \
+ --exclude='**/obj' \
+ --exclude='**/.nuget' \
+ --exclude='*.deb' \
+ --exclude='*.rpm' \
+ -zcf \
+ "$package_temporary_dir/jellyfin-${VERSION}/jellyfin.tar.gz" \
+ -C "../.." \
+ ./
+ echo "Extracting filtered package."
+ tar -xzf "$package_temporary_dir/jellyfin-${VERSION}/jellyfin.tar.gz" -C "$package_temporary_dir/jellyfin-${VERSION}"
+ echo "Removing filtered package."
+ rm "$package_temporary_dir/jellyfin-${VERSION}/jellyfin.tar.gz"
+ echo "Repackaging package into final tarball."
+ tar -zcf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz" -C "$package_temporary_dir" "jellyfin-${VERSION}"
+fi
+
+docker build ../.. -t "$image_name" -f ./Dockerfile
+mkdir -p "$output_dir"
+docker run --rm -v "$package_temporary_dir:/temp" "$image_name" sh -c 'find /build/rpmbuild -maxdepth 3 -type f -name "jellyfin*.rpm" -exec mv {} /temp \;'
+chown -R "$current_user" "$package_temporary_dir" \
+|| sudo chown -R "$current_user" "$package_temporary_dir"
+mv "$package_temporary_dir"/*.rpm "$output_dir"
diff --git a/deployment/fedora-package-x64/pkg-src/.gitignore b/deployment/fedora-package-x64/pkg-src/.gitignore
new file mode 100644
index 000000000..6019b98c2
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/.gitignore
@@ -0,0 +1,3 @@
+*.rpm
+*.zip
+*.tar.gz \ No newline at end of file
diff --git a/deployment/fedora-package-x64/pkg-src/README.md b/deployment/fedora-package-x64/pkg-src/README.md
new file mode 100644
index 000000000..7ed6f7efc
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/README.md
@@ -0,0 +1,43 @@
+# Jellyfin RPM
+
+## Build Fedora Package with docker
+
+Change into this directory `cd rpm-package`
+Run the build script `./build-fedora-rpm.sh`.
+Resulting RPM and src.rpm will be in `../../jellyfin-*.rpm`
+
+## ffmpeg
+
+The RPM package for Fedora/CentOS requires some additional repositories as ffmpeg is not in the main repositories.
+
+```shell
+# ffmpeg from RPMfusion free
+# Fedora
+$ sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
+# CentOS 7
+$ sudo yum localinstall --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm
+```
+
+## ISO mounting
+
+To allow Jellyfin to mount/umount ISO files uncomment these two lines in `/etc/sudoers.d/jellyfin-sudoers`
+```
+# %jellyfin ALL=(ALL) NOPASSWD: /bin/mount
+# %jellyfin ALL=(ALL) NOPASSWD: /bin/umount
+```
+
+## Building with dotnet
+
+Jellyfin is build with `--self-contained` so no dotnet required for runtime.
+
+```shell
+# dotnet required for building the RPM
+# Fedora
+$ sudo dnf copr enable @dotnet-sig/dotnet
+# CentOS
+$ sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
+```
+
+## TODO
+
+- [ ] OpenSUSE \ No newline at end of file
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin-firewalld.xml b/deployment/fedora-package-x64/pkg-src/jellyfin-firewalld.xml
new file mode 100644
index 000000000..538c5d65f
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin-firewalld.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<service>
+ <short>Jellyfin</short>
+ <description>The Free Software Media System.</description>
+ <port protocol="tcp" port="8096"/>
+ <port protocol="tcp" port="8920"/>
+ <port protocol="udp" port="1900"/>
+ <port protocol="udp" port="7359"/>
+</service>
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.env b/deployment/fedora-package-x64/pkg-src/jellyfin.env
new file mode 100644
index 000000000..827a33f46
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.env
@@ -0,0 +1,27 @@
+# Jellyfin default configuration options
+
+# Use this file to override the default configurations; add additional
+# options with JELLYFIN_ADD_OPTS.
+
+# To override the user or this config file's location, use
+# /etc/systemd/system/jellyfin.service.d/override.conf
+
+#
+# This is a POSIX shell fragment
+#
+
+#
+# General options
+#
+
+# Tell jellyfin wich ffmpeg/ffprobe to use
+# JELLYFIN_FFMPEG="-ffmpeg /usr/bin/ffmpeg -ffprobe /usr/bin/ffprobe"
+
+# Program directories
+JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin"
+JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin"
+JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin"
+# In-App service control
+JELLYFIN_RESTART_OPT="-restartpath /usr/libexec/jellyfin/restart.sh"
+# Additional options for the binary
+JELLYFIN_ADD_OPTS="" \ No newline at end of file
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.override.conf b/deployment/fedora-package-x64/pkg-src/jellyfin.override.conf
new file mode 100644
index 000000000..8652450bb
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.override.conf
@@ -0,0 +1,7 @@
+# Jellyfin systemd configuration options
+
+# Use this file to override the user or environment file location.
+
+[Service]
+#User = jellyfin
+#EnvironmentFile = /etc/sysconfig/jellyfin
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.service b/deployment/fedora-package-x64/pkg-src/jellyfin.service
new file mode 100644
index 000000000..0ece5b57f
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.service
@@ -0,0 +1,15 @@
+[Unit]
+After=network.target
+Description=Jellyfin is a free software media system that puts you in control of managing and streaming your media.
+
+[Service]
+EnvironmentFile=/etc/sysconfig/jellyfin
+WorkingDirectory=/var/lib/jellyfin
+ExecStart=/usr/bin/jellyfin -programdata ${JELLYFIN_DATA_DIRECTORY} -configdir ${JELLYFIN_CONFIG_DIRECTORY} -logdir ${JELLYFIN_LOG_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_ADD_OPTS} ${JELLYFIN_FFMPEG}
+TimeoutSec=15
+Restart=on-failure
+User=jellyfin
+Group=jellyfin
+
+[Install]
+WantedBy=multi-user.target
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.spec b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
new file mode 100644
index 000000000..6a4a5870b
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
@@ -0,0 +1,218 @@
+%global debug_package %{nil}
+# jellyfin tag to package
+%global gittag v10.1.0
+# Taglib-sharp commit of the submodule since github archive doesn't include submodules
+%global taglib_commit ee5ab21742b71fd1b87ee24895582327e9e04776
+%global taglib_shortcommit %(c=%{taglib_commit}; echo ${c:0:7})
+
+AutoReq: no
+Name: jellyfin
+Version: 10.1.0
+Release: 1%{?dist}
+Summary: The Free Software Media Browser
+License: GPLv2
+URL: https://jellyfin.media
+Source0: %{name}-%{version}.tar.gz
+Source1: jellyfin.service
+Source2: jellyfin.env
+Source3: jellyfin.sudoers
+Source4: restart.sh
+Source5: jellyfin.override.conf
+Source6: jellyfin-firewalld.xml
+
+%{?systemd_requires}
+BuildRequires: systemd
+Requires(pre): shadow-utils
+BuildRequires: libcurl-devel, fontconfig-devel, freetype-devel, openssl-devel, glibc-devel, libicu-devel
+Requires: libcurl, fontconfig, freetype, openssl, glibc libicu
+# Requirements not packaged in main repos
+# COPR @dotnet-sig/dotnet
+BuildRequires: dotnet-sdk-2.2
+# RPMfusion free
+Requires: ffmpeg
+
+# For the update-db-paths.sh script to fix emby paths to jellyfin
+%{?fedora:Recommends: sqlite}
+
+# Fedora has openssl1.1 which is incompatible with dotnet
+%{?fedora:Requires: compat-openssl10}
+# Disable Automatic Dependency Processing for Centos
+%{?el7:AutoReqProv: no}
+
+%description
+Jellyfin is a free software media system that puts you in control of managing and streaming your media.
+
+
+%prep
+%autosetup -n %{name}-%{version}
+
+%build
+
+%install
+export DOTNET_CLI_TELEMETRY_OPTOUT=1
+export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+dotnet publish --configuration Release --output='%{buildroot}%{_libdir}/jellyfin' --self-contained --runtime fedora-x64 Jellyfin.Server
+%{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/%{name}/LICENSE
+%{__install} -D -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/systemd/system/%{name}.service.d/override.conf
+%{__install} -D -m 0644 Jellyfin.Server/Resources/Configuration/logging.json %{buildroot}%{_sysconfdir}/%{name}/logging.json
+%{__mkdir} -p %{buildroot}%{_bindir}
+tee %{buildroot}%{_bindir}/jellyfin << EOF
+#!/bin/sh
+exec %{_libdir}/%{name}/%{name} \${@}
+EOF
+%{__mkdir} -p %{buildroot}%{_sharedstatedir}/jellyfin
+%{__mkdir} -p %{buildroot}%{_sysconfdir}/%{name}
+%{__mkdir} -p %{buildroot}%{_var}/log/jellyfin
+
+%{__install} -D -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/%{name}.service
+%{__install} -D -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/sysconfig/%{name}
+%{__install} -D -m 0600 %{SOURCE3} %{buildroot}%{_sysconfdir}/sudoers.d/%{name}-sudoers
+%{__install} -D -m 0755 %{SOURCE4} %{buildroot}%{_libexecdir}/%{name}/restart.sh
+%{__install} -D -m 0644 %{SOURCE6} %{buildroot}%{_prefix}/lib/firewalld/service/%{name}.xml
+
+%files
+%{_libdir}/%{name}/jellyfin-web/*
+%attr(755,root,root) %{_bindir}/%{name}
+%{_libdir}/%{name}/*.json
+%{_libdir}/%{name}/*.pdb
+%{_libdir}/%{name}/*.dll
+%{_libdir}/%{name}/*.so
+%{_libdir}/%{name}/*.a
+%{_libdir}/%{name}/createdump
+# Needs 755 else only root can run it since binary build by dotnet is 722
+%attr(755,root,root) %{_libdir}/%{name}/jellyfin
+%{_libdir}/%{name}/sosdocsunix.txt
+%{_unitdir}/%{name}.service
+%{_libexecdir}/%{name}/restart.sh
+%{_prefix}/lib/firewalld/service/%{name}.xml
+%attr(755,jellyfin,jellyfin) %dir %{_sysconfdir}/%{name}
+%config %{_sysconfdir}/sysconfig/%{name}
+%config(noreplace) %attr(600,root,root) %{_sysconfdir}/sudoers.d/%{name}-sudoers
+%config(noreplace) %{_sysconfdir}/systemd/system/%{name}.service.d/override.conf
+%config(noreplace) %attr(644,jellyfin,jellyfin) %{_sysconfdir}/%{name}/logging.json
+%attr(-,jellyfin,jellyfin) %dir %{_sharedstatedir}/jellyfin
+%attr(-,jellyfin,jellyfin) %dir %{_var}/log/jellyfin
+%if 0%{?fedora}
+%license LICENSE
+%else
+%{_datadir}/licenses/%{name}/LICENSE
+%endif
+
+%pre
+getent group jellyfin >/dev/null || groupadd -r jellyfin
+getent passwd jellyfin >/dev/null || \
+ useradd -r -g jellyfin -d %{_sharedstatedir}/jellyfin -s /sbin/nologin \
+ -c "Jellyfin default user" jellyfin
+exit 0
+
+%post
+# Move existing configuration to /etc/jellyfin and symlink config to /etc/jellyfin
+if [ $1 -gt 1 ] ; then
+ service_state=$(systemctl is-active jellyfin.service)
+ if [ "${service_state}" = "active" ]; then
+ systemctl stop jellyfin.service
+ fi
+ if [ ! -L %{_sharedstatedir}/%{name}/config ]; then
+ mv %{_sharedstatedir}/%{name}/config/* %{_sysconfdir}/%{name}/
+ rmdir %{_sharedstatedir}/%{name}/config
+ ln -sf %{_sysconfdir}/%{name} %{_sharedstatedir}/%{name}/config
+ fi
+ if [ ! -L %{_sharedstatedir}/%{name}/logs ]; then
+ mv %{_sharedstatedir}/%{name}/logs/* %{_var}/log/jellyfin
+ rmdir %{_sharedstatedir}/%{name}/logs
+ ln -sf %{_var}/log/jellyfin %{_sharedstatedir}/%{name}/logs
+ fi
+ if [ "${service_state}" = "active" ]; then
+ systemctl start jellyfin.service
+ fi
+fi
+%systemd_post jellyfin.service
+
+%preun
+%systemd_preun jellyfin.service
+
+%postun
+%systemd_postun_with_restart jellyfin.service
+
+%changelog
+* Sun Jan 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
+- jellyfin:
+- PR335 Build scripts and build system consolidation.
+- PR424 add jellyfin-web as submodule
+- PR455 Cleanup some small things
+- PR458 Clean up several minor issues and add TODOs
+- PR506 Removing tabs and trailing whitespace
+- PR508 Update internal versioning and user agents.
+- PR516 Remove useless properties from IEnvironmentInfo
+- PR520 Fix potential bug where aspect ratio would be incorrectly calculated
+- PR534 Add linux-arm and linux-arm64 native NuGet dependency.
+- PR540 Update Emby API keys to our own
+- PR541 Change ItemId to Guid in ProviderManager
+- PR556 Fix "Password Reset by PIN" page
+- PR562 Fix error with uppercase photo extension and fix typo in a log line
+- PR563 Update dev from master
+- PR566 Avoid printing stacktrace when bind to port 1900 fails
+- PR567 Shutdown gracefully when recieving a termination signal
+- PR571 Add more NuGet metadata properties
+- PR575 Reformat all C# server code to conform with code standards
+- PR576 Add code analysers for debug builds
+- PR580 Fix Docker build
+- PR582 Replace custom image parser with Skia
+- PR587 Add nuget info to Emby.Naming
+- PR589 Ensure config and log folders exist
+- PR596 Fix indentation for xml files
+- PR598 Remove MediaBrowser.Text for license violations and hackiness
+- PR606 Slim down docker image
+- PR613 Update MediaEncoding
+- PR616 Add Swagger documentation
+- PR619 Really slim down Docker container
+- PR621 Minor improvements to library scan code
+- PR622 Add unified build script and bump_version script
+- PR623 Replaced injections of ILogger with ILoggerFactory
+- PR625 Update taglib-sharp
+- PR626 Fix extra type name in parameter, add out keyword
+- PR627 Use string for ApplicationVersion
+- PR628 Update Product Name (User-Agent)
+- PR629 Fix subtitle converter misinterpreting 0 valued endTimeTicks
+- PR631 Cleanup ImageProcessor and SkiaEncoder
+- PR634 Replace our TVDB key with @drakus72's which is V1
+- PR636 Allow subtitle extraction and conversion in direct streaming
+- PR637 Remove unused font
+- PR638 Removed XmlTv testfiles and nuget install
+- PR646: Fix infinite loop bug on subtitle.m3u8 request
+- PR655: Support trying local branches in submodule
+- PR661: Fix NullRef from progress report
+- PR666: Add cross-platform build for arm64
+- jellyfin-web:
+- PR1: Change webcomponents to non-minified version
+- PR4: Fix user profile regression
+- PR6: Make icon into proper ico and large PNG
+- PR7: Fix firefox failing to set password for users with no password set
+- PR8: Remove premiere stuff and fix crashes caused by earlier removals
+- PR12: Fix return from PIN reset to index.html
+- PR13: Send android clients to select server before login
+- PR14: Reimplement page to add server
+- PR16: Fix spinning circle at the end of config wizard
+- PR17: Fix directorybrower not resetting scroll
+- PR19: Set union merge for CONTRIBUTORS.md
+- PR20: Show album thumbnail and artist image in page itemdetail
+- PR26: Make the card titles clickable
+- PR27: Stop pagination and adding a library from being able to trigger multiple times
+- PR28: Add transparent nav bar to BlueRadiance theme CSS
+- PR29: Clean up imageuploader
+- PR30: Remove iap and simplify registrationservices
+- PR36: Open videos in fullscreen on android devices
+- PR37: Remove broken features from web interface
+- PR38: Fix inconsistent UI coloring around settings drawer
+- PR39: Remove back button from dashboard and metadata manager
+- PR42: Fix Home backdrop not loading
+- PR43: Filter videos by audio stream language
+- PR44: Remove filter from library collection type options
+- PR45: Fix data-backbutton logic
+- PR46: Minor changes to navbar elements
+- PR48: Remove Sync code
+- PR52: Fix progress color
+- PR53: Fix user tabs color
+- PR54: Add back button to server dashboard
+* Fri Jan 11 2019 Thomas Büttner <thomas@vergesslicher.tech> - 10.0.2-1
+- TODO Changelog for 10.0.2
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.sudoers b/deployment/fedora-package-x64/pkg-src/jellyfin.sudoers
new file mode 100644
index 000000000..b31d52f7e
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.sudoers
@@ -0,0 +1,19 @@
+# Allow jellyfin group to start, stop and restart itself
+Cmnd_Alias RESTARTSERVER_SYSTEMD = /usr/bin/systemctl restart jellyfin, /bin/systemctl restart jellyfin
+Cmnd_Alias STARTSERVER_SYSTEMD = /usr/bin/systemctl start jellyfin, /bin/systemctl start jellyfin
+Cmnd_Alias STOPSERVER_SYSTEMD = /usr/bin/systemctl stop jellyfin, /bin/systemctl stop jellyfin
+
+
+%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSTEMD
+%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSTEMD
+%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSTEMD
+
+Defaults!RESTARTSERVER_SYSTEMD !requiretty
+Defaults!STARTSERVER_SYSTEMD !requiretty
+Defaults!STOPSERVER_SYSTEMD !requiretty
+
+# Uncomment to allow the server to mount iso images
+# %jellyfin ALL=(ALL) NOPASSWD: /bin/mount
+# %jellyfin ALL=(ALL) NOPASSWD: /bin/umount
+
+Defaults:%jellyfin !requiretty
diff --git a/deployment/fedora-package-x64/pkg-src/restart.sh b/deployment/fedora-package-x64/pkg-src/restart.sh
new file mode 100644
index 000000000..e84dca587
--- /dev/null
+++ b/deployment/fedora-package-x64/pkg-src/restart.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+NAME=jellyfin
+restart_cmd="/usr/bin/systemctl restart ${NAME}"
+echo "sleep 2; sudo $restart_cmd > /dev/null 2>&1" | at now > /dev/null 2>&1
+exit 0 \ No newline at end of file
diff --git a/deployment/framework/build.sh b/deployment/framework/build.sh
new file mode 100755
index 000000000..4f2e6363e
--- /dev/null
+++ b/deployment/framework/build.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+#Magic word framework will create a non self contained build
+build_jellyfin ../../Jellyfin.Server Release framework `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/framework/clean.sh b/deployment/framework/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/framework/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/framework/package.sh b/deployment/framework/package.sh
new file mode 100755
index 000000000..13b943ea8
--- /dev/null
+++ b/deployment/framework/package.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/linux-x64/build.sh b/deployment/linux-x64/build.sh
new file mode 100755
index 000000000..1f0fb62d3
--- /dev/null
+++ b/deployment/linux-x64/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+build_jellyfin ../../Jellyfin.Server Release linux-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/linux-x64/clean.sh b/deployment/linux-x64/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/linux-x64/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/linux-x64/dependencies.txt b/deployment/linux-x64/dependencies.txt
new file mode 100644
index 000000000..3d25d1bdf
--- /dev/null
+++ b/deployment/linux-x64/dependencies.txt
@@ -0,0 +1 @@
+dotnet
diff --git a/deployment/linux-x64/package.sh b/deployment/linux-x64/package.sh
new file mode 100755
index 000000000..13b943ea8
--- /dev/null
+++ b/deployment/linux-x64/package.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/osx-x64/build.sh b/deployment/osx-x64/build.sh
new file mode 100755
index 000000000..d6bfb9f5e
--- /dev/null
+++ b/deployment/osx-x64/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+build_jellyfin ../../Jellyfin.Server Release osx-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/osx-x64/clean.sh b/deployment/osx-x64/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/osx-x64/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/osx-x64/dependencies.txt b/deployment/osx-x64/dependencies.txt
new file mode 100644
index 000000000..3d25d1bdf
--- /dev/null
+++ b/deployment/osx-x64/dependencies.txt
@@ -0,0 +1 @@
+dotnet
diff --git a/deployment/osx-x64/package.sh b/deployment/osx-x64/package.sh
new file mode 100755
index 000000000..13b943ea8
--- /dev/null
+++ b/deployment/osx-x64/package.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/ubuntu-x64/build.sh b/deployment/ubuntu-x64/build.sh
new file mode 100755
index 000000000..870bac780
--- /dev/null
+++ b/deployment/ubuntu-x64/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+build_jellyfin ../../Jellyfin.Server Release ubuntu-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/ubuntu-x64/clean.sh b/deployment/ubuntu-x64/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/ubuntu-x64/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/ubuntu-x64/dependencies.txt b/deployment/ubuntu-x64/dependencies.txt
new file mode 100644
index 000000000..3d25d1bdf
--- /dev/null
+++ b/deployment/ubuntu-x64/dependencies.txt
@@ -0,0 +1 @@
+dotnet
diff --git a/deployment/ubuntu-x64/package.sh b/deployment/ubuntu-x64/package.sh
new file mode 100755
index 000000000..13b943ea8
--- /dev/null
+++ b/deployment/ubuntu-x64/package.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/unraid/docker-templates/README.md b/deployment/unraid/docker-templates/README.md
new file mode 100644
index 000000000..2c268e8b3
--- /dev/null
+++ b/deployment/unraid/docker-templates/README.md
@@ -0,0 +1,15 @@
+# docker-templates
+
+### Installation:
+
+Open unRaid GUI (at least unRaid 6.5)
+
+Click on the Docker tab
+
+Add the following line under "Template Repositories"
+
+https://github.com/jellyfin/jellyfin/blob/master/deployment/unraid/docker-templates
+
+Click save than click on Add Container and select jellyfin.
+
+Adjust to your paths to your liking and off you go!
diff --git a/deployment/unraid/docker-templates/jellyfin.xml b/deployment/unraid/docker-templates/jellyfin.xml
new file mode 100644
index 000000000..1d97a9f00
--- /dev/null
+++ b/deployment/unraid/docker-templates/jellyfin.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Containers>
+ <TemplateURL>https://raw.githubusercontent.com/jellyfin/jellyfin/deployment/unraid/docker-templates/jellyfin.xml</TemplateURL>
+ <Beta>False</Beta>
+ <Category>MediaApp:Video MediaApp:Music MediaApp:Photos MediaServer:Video MediaServer:Music MediaServer:Photos</Category>
+ <Name>JellyFin</Name>
+ <Description>
+ JellyFin is The Free Software Media Browser Converted By Community Applications Always verify this template (and values) against the dockerhub support page for the container!![br][br]
+ You can add as many mount points as needed for recordings, movies ,etc. [br][br]
+ [b][span style='color: #E80000;']Directions:[/span][/b][br]
+ [b]/config[/b] : this is where Jellyfin will store it's databases and configuration.[br][br]
+ [b]Port[/b] : This is the default port for Jellyfin. (Will add ssl port later)[br][br]
+ [b]Media[/b] : This is the mounting point of your media. When you access it in Jellyfin it will be /media or whatever you chose for a mount point
+ [b]Tip:[/b] You can add more volume mappings if you wish Jellyfin has access to it.
+ </Description>
+ <Overview>
+ Jellyfin Server is a home media server built on top of other popular open source technologies such as Service Stack, jQuery, jQuery mobile, and Mono and will remain completely free!
+ </Overview>
+ <Support>https://www.reddit.com/r/jellyfin/</Support>
+ <Registry>https://hub.docker.com/r/jellyfin/jellyfin/</Registry>
+ <GitHub>https://github.com/jellyfin/jellyfin/></GitHub>
+ <Repository>jellyfin/jellyfin</Repository>
+ <Project>https://jellyfin.media/</Project>
+ <BindTime>true</BindTime>
+ <Privileged>false</Privileged>
+ <Networking>
+ <Mode>host</Mode>
+ <Publish>
+ <Port>
+ <HostPort>8096</HostPort>
+ <ContainerPort>8096</ContainerPort>
+ <Protocol>tcp</Protocol>
+ </Port>
+ </Publish>
+ </Networking>
+ <Data>
+ <Volume>
+ <HostDir>/mnt/cache/appdata/config</HostDir>
+ <ContainerDir>/config</ContainerDir>
+ <Mode>rw</Mode>
+ </Volume>
+ <Volume>
+ <HostDir>/mnt/user</HostDir>
+ <ContainerDir>/media</ContainerDir>
+ <Mode>rw</Mode>
+ </Volume>
+ </Data>
+ <WebUI>http://[IP]:[PORT:8096]/</WebUI>
+ <Icon>https://raw.githubusercontent.com/binhex/docker-templates/master/binhex/images/emby-icon.png</Icon>
+ <ExtraParams></ExtraParams>
+</Containers>
diff --git a/deployment/win-generic/build-jellyfin.ps1 b/deployment/win-generic/build-jellyfin.ps1
new file mode 100644
index 000000000..7807a46c3
--- /dev/null
+++ b/deployment/win-generic/build-jellyfin.ps1
@@ -0,0 +1,110 @@
+[CmdletBinding()]
+param(
+ [switch]$InstallFFMPEG,
+ [switch]$InstallNSSM,
+ [switch]$GenerateZip,
+ [string]$InstallLocation = "$Env:AppData/Jellyfin-Server/",
+ [ValidateSet('Debug','Release')][string]$BuildType = 'Release',
+ [ValidateSet('Quiet','Minimal', 'Normal')][string]$DotNetVerbosity = 'Minimal',
+ [ValidateSet('win','win7', 'win8','win81','win10')][string]$WindowsVersion = 'win',
+ [ValidateSet('x64','x86', 'arm', 'arm64')][string]$Architecture = 'x64'
+)
+
+#PowershellCore and *nix check to make determine which temp dir to use.
+if(($PSVersionTable.PSEdition -eq 'Core') -and (-not $IsWindows)){
+ $TempDir = mktemp -d
+}else{
+ $TempDir = $env:Temp
+}
+
+function Build-JellyFin {
+ if(($Architecture -eq 'arm64') -and ($WindowsVersion -ne 'win10')){
+ Write-Error "arm64 only supported with Windows10 Version"
+ exit
+ }
+ if(($Architecture -eq 'arm') -and ($WindowsVersion -notin @('win10','win81','win8'))){
+ Write-Error "arm only supported with Windows 8 or higher"
+ exit
+ }
+ dotnet publish -c $BuildType -r "$windowsversion-$Architecture" MediaBrowser.sln -o $InstallLocation -v $DotNetVerbosity
+}
+
+function Install-FFMPEG {
+ param(
+ [string]$InstallLocation,
+ [string]$Architecture
+ )
+ Write-Verbose "Checking Architecture"
+ if($Architecture -notin @('x86','x64')){
+ Write-Warning "No builds available for your selected architecture of $Architecture"
+ Write-Warning "FFMPEG will not be installed"
+ }elseif($Architecture -eq 'x64'){
+ Write-Verbose "Downloading 64 bit FFMPEG"
+ Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-4.1-win64-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose
+ }else{
+ Write-Verbose "Downloading 32 bit FFMPEG"
+ Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-4.1-win32-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose
+ }
+
+ Expand-Archive "$tempdir/fmmpeg.zip" -DestinationPath "$tempdir/ffmpeg/" | Write-Verbose
+ if($Architecture -eq 'x64'){
+ Write-Verbose "Copying Binaries to Jellyfin location"
+ Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.1-win64-static/bin" | ForEach-Object {
+ Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+ }
+ }else{
+ Write-Verbose "Copying Binaries to Jellyfin location"
+ Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.1-win32-static/bin" | ForEach-Object {
+ Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+ }
+ }
+ Remove-Item "$tempdir/ffmpeg/" -Recurse -Force -ErrorAction Continue | Write-Verbose
+ Remove-Item "$tempdir/fmmpeg.zip" -Force -ErrorAction Continue | Write-Verbose
+}
+
+function Install-NSSM {
+ param(
+ [string]$InstallLocation,
+ [string]$Architecture
+ )
+ Write-Verbose "Checking Architecture"
+ if($Architecture -notin @('x86','x64')){
+ Write-Warning "No builds available for your selected architecture of $Architecture"
+ Write-Warning "NSSM will not be installed"
+ }else{
+ Write-Verbose "Downloading NSSM"
+ Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -UseBasicParsing -OutFile "$tempdir/nssm.zip" | Write-Verbose
+ }
+
+ Expand-Archive "$tempdir/nssm.zip" -DestinationPath "$tempdir/nssm/" | Write-Verbose
+ if($Architecture -eq 'x64'){
+ Write-Verbose "Copying Binaries to Jellyfin location"
+ Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win64" | ForEach-Object {
+ Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+ }
+ }else{
+ Write-Verbose "Copying Binaries to Jellyfin location"
+ Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win32" | ForEach-Object {
+ Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+ }
+ }
+ Remove-Item "$tempdir/nssm/" -Recurse -Force -ErrorAction Continue | Write-Verbose
+ Remove-Item "$tempdir/nssm.zip" -Force -ErrorAction Continue | Write-Verbose
+}
+
+Write-Verbose "Starting Build Process: Selected Environment is $WindowsVersion-$Architecture"
+Build-JellyFin
+if($InstallFFMPEG.IsPresent -or ($InstallFFMPEG -eq $true)){
+ Write-Verbose "Starting FFMPEG Install"
+ Install-FFMPEG $InstallLocation $Architecture
+}
+if($InstallNSSM.IsPresent -or ($InstallNSSM -eq $true)){
+ Write-Verbose "Starting NSSM Install"
+ Install-NSSM $InstallLocation $Architecture
+}
+Copy-Item .\install-jellyfin.ps1 $InstallLocation\install-jellyfin.ps1
+Copy-Item .\install.bat $InstallLocation\install.bat
+if($GenerateZip.IsPresent -or ($GenerateZip -eq $true)){
+ Compress-Archive -Path $InstallLocation -DestinationPath "$InstallLocation/jellyfin.zip" -Force
+}
+Write-Verbose "Finished"
diff --git a/deployment/win-generic/dependencies.txt b/deployment/win-generic/dependencies.txt
new file mode 100644
index 000000000..3d25d1bdf
--- /dev/null
+++ b/deployment/win-generic/dependencies.txt
@@ -0,0 +1 @@
+dotnet
diff --git a/deployment/win-generic/install-jellyfin.ps1 b/deployment/win-generic/install-jellyfin.ps1
new file mode 100644
index 000000000..56c098462
--- /dev/null
+++ b/deployment/win-generic/install-jellyfin.ps1
@@ -0,0 +1,460 @@
+[CmdletBinding()]
+
+param(
+ [Switch]$Quiet,
+ [Switch]$InstallAsService,
+ [pscredential]$ServiceUser,
+ [switch]$CreateDesktopShorcut,
+ [switch]$LaunchJellyfin,
+ [switch]$MigrateEmbyLibrary,
+ [string]$InstallLocation,
+ [string]$EmbyLibraryLocation,
+ [string]$JellyfinLibraryLocation
+)
+<# This form was created using POSHGUI.com a free online gui designer for PowerShell
+.NAME
+ Install-Jellyfin
+#>
+
+#This doesn't need to be used by default anymore, but I am keeping it in as a function for future use.
+function Elevate-Window {
+ # Get the ID and security principal of the current user account
+ $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
+ $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
+
+ # Get the security principal for the Administrator role
+ $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
+
+ # Check to see if we are currently running "as Administrator"
+ if ($myWindowsPrincipal.IsInRole($adminRole))
+ {
+ # We are running "as Administrator" - so change the title and background color to indicate this
+ $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
+ $Host.UI.RawUI.BackgroundColor = "DarkBlue"
+ clear-host
+ }
+ else
+ {
+ # We are not running "as Administrator" - so relaunch as administrator
+
+ # Create a new process object that starts PowerShell
+ $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
+
+ # Specify the current script path and name as a parameter
+ $newProcess.Arguments = $myInvocation.MyCommand.Definition;
+
+ # Indicate that the process should be elevated
+ $newProcess.Verb = "runas";
+
+ # Start the new process
+ [System.Diagnostics.Process]::Start($newProcess);
+
+ # Exit from the current, unelevated, process
+ exit
+ }
+}
+
+#FIXME The install methods should be a function that takes all the params, the quiet flag should be a paramset
+
+if($Quiet.IsPresent -or $Quiet -eq $true){
+ if([string]::IsNullOrEmpty($JellyfinLibraryLocation)){
+ $Script:JellyfinDataDir = "$env:AppData\jellyfin\"
+ }else{
+ $Script:JellyfinDataDir = $JellyfinLibraryLocation
+ }
+ if([string]::IsNullOrEmpty($InstallLocation)){
+ $Script:DefaultJellyfinInstallDirectory = "$env:Appdata\jellyfin\"
+ }else{
+ $Script:DefaultJellyfinInstallDirectory = $InstallLocation
+ }
+
+ if([string]::IsNullOrEmpty($EmbyLibraryLocation)){
+ $Script:defaultEmbyDataDir = "$env:Appdata\Emby-Server\data\"
+ }else{
+ $Script:defaultEmbyDataDir = $EmbyLibraryLocation
+ }
+
+ if($InstallAsService.IsPresent -or $InstallAsService -eq $true){
+ $Script:InstallAsService = $true
+ }else{$Script:InstallAsService = $false}
+ if($null -eq $ServiceUser){
+ $Script:InstallServiceAsUser = $false
+ }else{
+ $Script:InstallServiceAsUser = $true
+ $Script:UserCredentials = $ServiceUser
+ $Script:JellyfinDataDir = "C:\Users\$($Script:UserCredentials.UserName)\Appdata\Roaming\jellyfin\"}
+ if($CreateDesktopShorcut.IsPresent -or $CreateDesktopShorcut -eq $true) {$Script:CreateShortcut = $true}else{$Script:CreateShortcut = $false}
+ if($MigrateEmbyLibrary.IsPresent -or $MigrateEmbyLibrary -eq $true){$Script:MigrateLibrary = $true}else{$Script:MigrateLibrary = $false}
+ if($LaunchJellyfin.IsPresent -or $LaunchJellyfin -eq $true){$Script:StartJellyfin = $true}else{$Script:StartJellyfin = $false}
+
+ if(-not (Test-Path $Script:DefaultJellyfinInstallDirectory)){
+ mkdir $Script:DefaultJellyfinInstallDirectory
+ }
+ Copy-Item -Path $PSScriptRoot/* -DestinationPath "$Script:DefaultJellyfinInstallDirectory/" -Force -Recurse
+ if($Script:InstallAsService){
+ if($Script:InstallServiceAsUser){
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ Start-Sleep -Milliseconds 500
+ &sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
+ }else{
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ Start-Sleep -Milliseconds 500
+ #&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin ObjectName $Script:UserCredentials.UserName $Script:UserCredentials.GetNetworkCredential().Password
+ #Set-Service -Name Jellyfin -Credential $Script:UserCredentials
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
+ }
+ }
+ if($Script:MigrateLibrary){
+ Copy-Item -Path $Script:defaultEmbyDataDir/config -Destination $Script:JellyfinDataDir -force -Recurse
+ Copy-Item -Path $Script:defaultEmbyDataDir/cache -Destination $Script:JellyfinDataDir -force -Recurse
+ Copy-Item -Path $Script:defaultEmbyDataDir/data -Destination $Script:JellyfinDataDir -force -Recurse
+ Copy-Item -Path $Script:defaultEmbyDataDir/metadata -Destination $Script:JellyfinDataDir -force -Recurse
+ Copy-Item -Path $Script:defaultEmbyDataDir/root -Destination $Script:JellyfinDataDir -force -Recurse
+ }
+ if($Script:CreateShortcut){
+ $WshShell = New-Object -comObject WScript.Shell
+ $Shortcut = $WshShell.CreateShortcut("$Home\Desktop\Jellyfin.lnk")
+ $Shortcut.TargetPath = "$Script:DefaultJellyfinInstallDirectory\jellyfin.exe"
+ $Shortcut.Save()
+ }
+ if($Script:StartJellyfin){
+ if($Script:InstallAsService){
+ Get-Service Jellyfin | Start-Service
+ }else{
+ Start-Process -FilePath $Script:DefaultJellyfinInstallDirectory\jellyfin.exe -PassThru
+ }
+ }
+}else{
+
+}
+Add-Type -AssemblyName System.Windows.Forms
+[System.Windows.Forms.Application]::EnableVisualStyles()
+
+$Script:JellyFinDataDir = "$env:AppData\jellyfin\"
+$Script:DefaultJellyfinInstallDirectory = "$env:Appdata\jellyfin\"
+$Script:defaultEmbyDataDir = "$env:Appdata\Emby-Server\"
+$Script:InstallAsService = $False
+$Script:InstallServiceAsUser = $false
+$Script:CreateShortcut = $false
+$Script:MigrateLibrary = $false
+$Script:StartJellyfin = $false
+
+function InstallJellyfin {
+ Write-Host "Install as service: $Script:InstallAsService"
+ Write-Host "Install as serviceuser: $Script:InstallServiceAsUser"
+ Write-Host "Create Shortcut: $Script:CreateShortcut"
+ Write-Host "MigrateLibrary: $Script:MigrateLibrary"
+ $GUIElementsCollection | ForEach-Object {
+ $_.Enabled = $false
+ }
+ Write-Host "Making Jellyfin directory"
+ $ProgressBar.Minimum = 1
+ $ProgressBar.Maximum = 100
+ $ProgressBar.Value = 1
+ if($Script:DefaultJellyfinInstallDirectory -ne $InstallLocationBox.Text){
+ Write-Host "Custom Install Location Chosen: $($InstallLocationBox.Text)"
+ $Script:DefaultJellyfinInstallDirectory = $InstallLocationBox.Text
+ }
+ if($Script:JellyfinDataDir -ne $CustomLibraryBox.Text){
+ Write-Host "Custom Library Location Chosen: $($CustomLibraryBox.Text)"
+ $Script:JellyfinDataDir = $CustomLibraryBox.Text
+ }
+ if(-not (Test-Path $Script:DefaultJellyfinInstallDirectory)){
+ mkdir $Script:DefaultJellyfinInstallDirectory
+ }
+ Write-Host "Copying Jellyfin Data"
+ $progressbar.Value = 10
+ Copy-Item -Path $PSScriptRoot/* -Destination $Script:DefaultJellyfinInstallDirectory/ -Force -Recurse
+ Write-Host "Finished Copying"
+ $ProgressBar.Value = 50
+ if($Script:InstallAsService){
+ if($Script:InstallServiceAsUser){
+ Write-Host "Installing Service as user $($Script:UserCredentials.UserName)"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ Start-Sleep -Milliseconds 2000
+ &sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
+ }else{
+ Write-Host "Installing Service as LocalSystem"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ Start-Sleep -Milliseconds 2000
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
+ }
+ }
+ $progressbar.Value = 60
+ if($Script:MigrateLibrary){
+ if($Script:defaultEmbyDataDir -ne $LibraryLocationBox.Text){
+ Write-Host "Custom location defined for emby library: $($LibraryLocationBox.Text)"
+ $Script:defaultEmbyDataDir = $LibraryLocationBox.Text
+ }
+ Write-Host "Copying emby library from $Script:defaultEmbyDataDir to $Script:JellyFinDataDir"
+ Write-Host "This could take a while depending on the size of your library. Please be patient"
+ Write-Host "Copying config"
+ Copy-Item -Path $Script:defaultEmbyDataDir/config -Destination $Script:JellyfinDataDir -force -Recurse
+ Write-Host "Copying cache"
+ Copy-Item -Path $Script:defaultEmbyDataDir/cache -Destination $Script:JellyfinDataDir -force -Recurse
+ Write-Host "Copying data"
+ Copy-Item -Path $Script:defaultEmbyDataDir/data -Destination $Script:JellyfinDataDir -force -Recurse
+ Write-Host "Copying metadata"
+ Copy-Item -Path $Script:defaultEmbyDataDir/metadata -Destination $Script:JellyfinDataDir -force -Recurse
+ Write-Host "Copying root dir"
+ Copy-Item -Path $Script:defaultEmbyDataDir/root -Destination $Script:JellyfinDataDir -force -Recurse
+ }
+ $progressbar.Value = 80
+ if($Script:CreateShortcut){
+ Write-Host "Creating Shortcut"
+ $WshShell = New-Object -comObject WScript.Shell
+ $Shortcut = $WshShell.CreateShortcut("$Home\Desktop\Jellyfin.lnk")
+ $Shortcut.TargetPath = "$Script:DefaultJellyfinInstallDirectory\jellyfin.exe"
+ $Shortcut.Save()
+ }
+ $ProgressBar.Value = 90
+ if($Script:StartJellyfin){
+ if($Script:InstallAsService){
+ Write-Host "Starting Jellyfin Service"
+ Get-Service Jellyfin | Start-Service
+ }else{
+ Write-Host "Starting Jellyfin"
+ Start-Process -FilePath $Script:DefaultJellyfinInstallDirectory\jellyfin.exe -PassThru
+ }
+ }
+ $progressbar.Value = 100
+ Write-Host Finished
+ $wshell = New-Object -ComObject Wscript.Shell
+ $wshell.Popup("Operation Completed",0,"Done",0x1)
+ $InstallForm.Close()
+}
+function ServiceBoxCheckChanged {
+ if($InstallAsServiceCheck.Checked){
+ $Script:InstallAsService = $true
+ $ServiceUserLabel.Visible = $true
+ $ServiceUserLabel.Enabled = $true
+ $ServiceUserBox.Visible = $true
+ $ServiceUserBox.Enabled = $true
+ }else{
+ $Script:InstallAsService = $false
+ $ServiceUserLabel.Visible = $false
+ $ServiceUserLabel.Enabled = $false
+ $ServiceUserBox.Visible = $false
+ $ServiceUserBox.Enabled = $false
+ }
+}
+function UserSelect {
+ if($ServiceUserBox.Text -eq 'Local System')
+ {
+ $Script:InstallServiceAsUser = $false
+ $Script:UserCredentials = $null
+ $ServiceUserBox.Items.RemoveAt(1)
+ $ServiceUserBox.Items.Add("Custom User")
+ }elseif($ServiceUserBox.Text -eq 'Custom User'){
+ $Script:InstallServiceAsUser = $true
+ $Script:UserCredentials = Get-Credential -Message "Please enter the credentials of the user you with to run Jellyfin Service as" -UserName $env:USERNAME
+ $ServiceUserBox.Items[1] = "$($Script:UserCredentials.UserName)"
+ }
+}
+function CreateShortcutBoxCheckChanged {
+ if($CreateShortcutCheck.Checked){
+ $Script:CreateShortcut = $true
+ }else{
+ $Script:CreateShortcut = $False
+ }
+}
+function StartJellyFinBoxCheckChanged {
+ if($StartProgramCheck.Checked){
+ $Script:StartJellyfin = $true
+ }else{
+ $Script:StartJellyfin = $false
+ }
+}
+
+function CustomLibraryCheckChanged {
+ if($CustomLibraryCheck.Checked){
+ $Script:UseCustomLibrary = $true
+ $CustomLibraryBox.Enabled = $true
+ }else{
+ $Script:UseCustomLibrary = $false
+ $CustomLibraryBox.Enabled = $false
+ }
+}
+
+function MigrateLibraryCheckboxChanged {
+
+ if($MigrateLibraryCheck.Checked){
+ $Script:MigrateLibrary = $true
+ $LibraryMigrationLabel.Visible = $true
+ $LibraryMigrationLabel.Enabled = $true
+ $LibraryLocationBox.Visible = $true
+ $LibraryLocationBox.Enabled = $true
+ }else{
+ $Script:MigrateLibrary = $false
+ $LibraryMigrationLabel.Visible = $false
+ $LibraryMigrationLabel.Enabled = $false
+ $LibraryLocationBox.Visible = $false
+ $LibraryLocationBox.Enabled = $false
+ }
+
+}
+
+
+#region begin GUI{
+
+$InstallForm = New-Object system.Windows.Forms.Form
+$InstallForm.ClientSize = '320,240'
+$InstallForm.text = "Terrible Jellyfin Installer"
+$InstallForm.TopMost = $false
+
+$GUIElementsCollection = @()
+
+$InstallButton = New-Object system.Windows.Forms.Button
+$InstallButton.text = "Install"
+$InstallButton.width = 60
+$InstallButton.height = 30
+$InstallButton.location = New-Object System.Drawing.Point(5,5)
+$InstallButton.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallButton
+
+$ProgressBar = New-Object system.Windows.Forms.ProgressBar
+$ProgressBar.width = 245
+$ProgressBar.height = 30
+$ProgressBar.location = New-Object System.Drawing.Point(70,5)
+
+$InstallLocationLabel = New-Object system.Windows.Forms.Label
+$InstallLocationLabel.text = "Install Location"
+$InstallLocationLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
+$InstallLocationLabel.AutoSize = $true
+$InstallLocationLabel.width = 100
+$InstallLocationLabel.height = 20
+$InstallLocationLabel.location = New-Object System.Drawing.Point(5,50)
+$InstallLocationLabel.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallLocationLabel
+
+$InstallLocationBox = New-Object system.Windows.Forms.TextBox
+$InstallLocationBox.multiline = $false
+$InstallLocationBox.width = 205
+$InstallLocationBox.height = 20
+$InstallLocationBox.location = New-Object System.Drawing.Point(110,50)
+$InstallLocationBox.Text = $Script:DefaultJellyfinInstallDirectory
+$InstallLocationBox.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallLocationBox
+
+$CustomLibraryCheck = New-Object system.Windows.Forms.CheckBox
+$CustomLibraryCheck.text = "Custom Library Location:"
+$CustomLibraryCheck.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
+$CustomLibraryCheck.AutoSize = $false
+$CustomLibraryCheck.width = 180
+$CustomLibraryCheck.height = 20
+$CustomLibraryCheck.location = New-Object System.Drawing.Point(5,75)
+$CustomLibraryCheck.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $CustomLibraryCheck
+
+$CustomLibraryBox = New-Object system.Windows.Forms.TextBox
+$CustomLibraryBox.multiline = $false
+$CustomLibraryBox.width = 130
+$CustomLibraryBox.height = 20
+$CustomLibraryBox.location = New-Object System.Drawing.Point(185,75)
+$CustomLibraryBox.Text = $Script:JellyFinDataDir
+$CustomLibraryBox.Font = 'Microsoft Sans Serif,10'
+$CustomLibraryBox.Enabled = $false
+$GUIElementsCollection += $CustomLibraryBox
+
+$InstallAsServiceCheck = New-Object system.Windows.Forms.CheckBox
+$InstallAsServiceCheck.text = "Install as Service"
+$InstallAsServiceCheck.AutoSize = $false
+$InstallAsServiceCheck.width = 140
+$InstallAsServiceCheck.height = 20
+$InstallAsServiceCheck.location = New-Object System.Drawing.Point(5,125)
+$InstallAsServiceCheck.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallAsServiceCheck
+
+$ServiceUserLabel = New-Object system.Windows.Forms.Label
+$ServiceUserLabel.text = "Run Service As:"
+$ServiceUserLabel.AutoSize = $true
+$ServiceUserLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
+$ServiceUserLabel.width = 100
+$ServiceUserLabel.height = 20
+$ServiceUserLabel.location = New-Object System.Drawing.Point(15,145)
+$ServiceUserLabel.Font = 'Microsoft Sans Serif,10'
+$ServiceUserLabel.Visible = $false
+$ServiceUserLabel.Enabled = $false
+$GUIElementsCollection += $ServiceUserLabel
+
+$ServiceUserBox = New-Object system.Windows.Forms.ComboBox
+$ServiceUserBox.text = "Run Service As"
+$ServiceUserBox.width = 195
+$ServiceUserBox.height = 20
+@('Local System','Custom User') | ForEach-Object {[void] $ServiceUserBox.Items.Add($_)}
+$ServiceUserBox.location = New-Object System.Drawing.Point(120,145)
+$ServiceUserBox.Font = 'Microsoft Sans Serif,10'
+$ServiceUserBox.Visible = $false
+$ServiceUserBox.Enabled = $false
+$ServiceUserBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList
+$GUIElementsCollection += $ServiceUserBox
+
+$MigrateLibraryCheck = New-Object system.Windows.Forms.CheckBox
+$MigrateLibraryCheck.text = "Import Emby Library"
+$MigrateLibraryCheck.AutoSize = $false
+$MigrateLibraryCheck.width = 160
+$MigrateLibraryCheck.height = 20
+$MigrateLibraryCheck.location = New-Object System.Drawing.Point(5,170)
+$MigrateLibraryCheck.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $MigrateLibraryCheck
+
+$LibraryMigrationLabel = New-Object system.Windows.Forms.Label
+$LibraryMigrationLabel.text = "Emby Library Path"
+$LibraryMigrationLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
+$LibraryMigrationLabel.AutoSize = $false
+$LibraryMigrationLabel.width = 120
+$LibraryMigrationLabel.height = 20
+$LibraryMigrationLabel.location = New-Object System.Drawing.Point(15,190)
+$LibraryMigrationLabel.Font = 'Microsoft Sans Serif,10'
+$LibraryMigrationLabel.Visible = $false
+$LibraryMigrationLabel.Enabled = $false
+$GUIElementsCollection += $LibraryMigrationLabel
+
+$LibraryLocationBox = New-Object system.Windows.Forms.TextBox
+$LibraryLocationBox.multiline = $false
+$LibraryLocationBox.width = 175
+$LibraryLocationBox.height = 20
+$LibraryLocationBox.location = New-Object System.Drawing.Point(140,190)
+$LibraryLocationBox.Text = $Script:defaultEmbyDataDir
+$LibraryLocationBox.Font = 'Microsoft Sans Serif,10'
+$LibraryLocationBox.Visible = $false
+$LibraryLocationBox.Enabled = $false
+$GUIElementsCollection += $LibraryLocationBox
+
+$CreateShortcutCheck = New-Object system.Windows.Forms.CheckBox
+$CreateShortcutCheck.text = "Desktop Shortcut"
+$CreateShortcutCheck.AutoSize = $false
+$CreateShortcutCheck.width = 150
+$CreateShortcutCheck.height = 20
+$CreateShortcutCheck.location = New-Object System.Drawing.Point(5,215)
+$CreateShortcutCheck.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $CreateShortcutCheck
+
+$StartProgramCheck = New-Object system.Windows.Forms.CheckBox
+$StartProgramCheck.text = "Start Jellyfin"
+$StartProgramCheck.AutoSize = $false
+$StartProgramCheck.width = 160
+$StartProgramCheck.height = 20
+$StartProgramCheck.location = New-Object System.Drawing.Point(160,215)
+$StartProgramCheck.Font = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $StartProgramCheck
+
+$InstallForm.controls.AddRange($GUIElementsCollection)
+$InstallForm.Controls.Add($ProgressBar)
+
+#region gui events {
+$InstallButton.Add_Click({ InstallJellyfin })
+$CustomLibraryCheck.Add_CheckedChanged({CustomLibraryCheckChanged})
+$InstallAsServiceCheck.Add_CheckedChanged({ServiceBoxCheckChanged})
+$ServiceUserBox.Add_SelectedValueChanged({ UserSelect })
+$MigrateLibraryCheck.Add_CheckedChanged({MigrateLibraryCheckboxChanged})
+$CreateShortcutCheck.Add_CheckedChanged({CreateShortcutBoxCheckChanged})
+$StartProgramCheck.Add_CheckedChanged({StartJellyFinBoxCheckChanged})
+#endregion events }
+
+#endregion GUI }
+
+
+[void]$InstallForm.ShowDialog() \ No newline at end of file
diff --git a/deployment/win-generic/install.bat b/deployment/win-generic/install.bat
new file mode 100644
index 000000000..e21479a79
--- /dev/null
+++ b/deployment/win-generic/install.bat
@@ -0,0 +1 @@
+powershell.exe -executionpolicy Bypass -file install-jellyfin.ps1
diff --git a/deployment/win-x64/build.sh b/deployment/win-x64/build.sh
new file mode 100755
index 000000000..0b3046203
--- /dev/null
+++ b/deployment/win-x64/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+build_jellyfin ../../Jellyfin.Server Release win-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/win-x64/clean.sh b/deployment/win-x64/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/win-x64/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/win-x64/dependencies.txt b/deployment/win-x64/dependencies.txt
new file mode 100644
index 000000000..3d25d1bdf
--- /dev/null
+++ b/deployment/win-x64/dependencies.txt
@@ -0,0 +1 @@
+dotnet
diff --git a/deployment/win-x64/package.sh b/deployment/win-x64/package.sh
new file mode 100755
index 000000000..e8410e8c2
--- /dev/null
+++ b/deployment/win-x64/package.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
+
+#TODO setup and maybe change above code to produce the Windows native zip format.
diff --git a/deployment/win-x86/build.sh b/deployment/win-x86/build.sh
new file mode 100755
index 000000000..610db356a
--- /dev/null
+++ b/deployment/win-x86/build.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+build_jellyfin ../../Jellyfin.Server Release win-x86 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/win-x86/clean.sh b/deployment/win-x86/clean.sh
new file mode 100755
index 000000000..3df2d7796
--- /dev/null
+++ b/deployment/win-x86/clean.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/win-x86/dependencies.txt b/deployment/win-x86/dependencies.txt
new file mode 100644
index 000000000..3d25d1bdf
--- /dev/null
+++ b/deployment/win-x86/dependencies.txt
@@ -0,0 +1 @@
+dotnet
diff --git a/deployment/win-x86/package.sh b/deployment/win-x86/package.sh
new file mode 100755
index 000000000..e8410e8c2
--- /dev/null
+++ b/deployment/win-x86/package.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+VERSION=`get_version ../..`
+
+package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
+
+#TODO setup and maybe change above code to produce the Windows native zip format.