summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:25 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:25 +0000
commitd2c5a3255ca77b59775a54ecb70fabc86335296a (patch)
tree348ae3ff176c7c9c9ebe9624e45a7e12bae61155
parentAdding upstream version 2:20.4+dfsg. (diff)
downloadkodi-d2c5a3255ca77b59775a54ecb70fabc86335296a.tar.xz
kodi-d2c5a3255ca77b59775a54ecb70fabc86335296a.zip
Adding debian version 2:20.4+dfsg-1.debian/2%20.4+dfsg-1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--debian/README.Debian24
-rw-r--r--debian/README.source32
-rw-r--r--debian/changelog1241
-rw-r--r--debian/control543
-rw-r--r--debian/copyright1693
-rwxr-xr-xdebian/dh-addon/dh_kodiaddon_depends148
-rw-r--r--debian/dh-addon/kodiaddon.pm7
-rw-r--r--debian/extra/arial.ttfbin0 -> 5924104 bytes
-rw-r--r--debian/from-debian-logo.svg189
-rw-r--r--debian/gbp.conf7
-rw-r--r--debian/gitlab-ci.yml3
-rw-r--r--debian/headers-check.c126
-rw-r--r--debian/kodi-addons-dev-common.README.Debian2
-rw-r--r--debian/kodi-addons-dev-common.install3
-rw-r--r--debian/kodi-addons-dev.install2
-rw-r--r--debian/kodi-addons-dev.manpages1
-rw-r--r--debian/kodi-bin.install3
-rw-r--r--debian/kodi-bin.lintian-overrides20
-rw-r--r--debian/kodi-bin.manpages1
-rw-r--r--debian/kodi-data.install11
-rw-r--r--debian/kodi-data.links7
-rw-r--r--debian/kodi-data.lintian-overrides14
-rw-r--r--debian/kodi-eventclients-common.install1
-rw-r--r--debian/kodi-eventclients-dev-common.examples1
-rw-r--r--debian/kodi-eventclients-dev-common.install1
-rw-r--r--debian/kodi-eventclients-dev.install1
-rw-r--r--debian/kodi-eventclients-kodi-send.install1
-rw-r--r--debian/kodi-eventclients-kodi-send.lintian-overrides2
-rw-r--r--debian/kodi-eventclients-kodi-send.manpages1
-rw-r--r--debian/kodi-eventclients-ps3.install2
-rw-r--r--debian/kodi-eventclients-ps3.lintian-overrides6
-rw-r--r--debian/kodi-eventclients-ps3.manpages1
-rw-r--r--debian/kodi-eventclients-python.install1
-rw-r--r--debian/kodi-eventclients-python.lintian-overrides2
-rw-r--r--debian/kodi-eventclients-wiiremote.install1
-rw-r--r--debian/kodi-eventclients-wiiremote.lintian-overrides2
-rw-r--r--debian/kodi-eventclients-wiiremote.manpages1
-rw-r--r--debian/kodi-eventclients-zeroconf.install1
-rw-r--r--debian/kodi-eventclients-zeroconf.lintian-overrides5
-rw-r--r--debian/kodi-tools-texturepacker.install1
-rw-r--r--debian/kodi-tools-texturepacker.lintian-overrides2
-rw-r--r--debian/kodi-tools-texturepacker.manpages1
-rw-r--r--debian/kodi.install4
-rw-r--r--debian/kodi.lintian-overrides5
-rw-r--r--debian/kodi.manpages2
-rw-r--r--debian/kodi.mime19
-rwxr-xr-xdebian/mergefonts.ff6
-rw-r--r--debian/not-installed7
-rw-r--r--debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch7004
-rw-r--r--debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch145
-rw-r--r--debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch58
-rw-r--r--debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch90
-rw-r--r--debian/patches/kodi/0004-use-system-groovy.patch128
-rw-r--r--debian/patches/kodi/0005-fix-tests.patch28
-rw-r--r--debian/patches/kodi/0006-dont-use-openssl.patch29
-rw-r--r--debian/patches/kodi/0007-support-omitting-addons-service.patch27
-rw-r--r--debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch22
-rw-r--r--debian/patches/kodi/0009-Skip-long-time-broken-test.patch23
-rw-r--r--debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch31
-rw-r--r--debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch22
-rw-r--r--debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch96
-rw-r--r--debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch22
-rw-r--r--debian/patches/kodi/0014-Fix-C++-example-includes.patch52
-rw-r--r--debian/patches/kodi/0015-debian-cross-compile.patch33
-rw-r--r--debian/patches/kodi/0016-ports-architectures.patch132
-rw-r--r--debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch184
-rw-r--r--debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch1694
-rw-r--r--debian/patches/libdvdread/debian-0001-libdvdcss.patch25
-rw-r--r--debian/patches/libdvdread/debian-0002-descriptor.patch104
-rw-r--r--debian/patches/series28
-rw-r--r--debian/patches/workarounds/0001-Workaround-989814.patch71
-rw-r--r--debian/patches/workarounds/0002-ffmpeg5.patch2429
-rw-r--r--debian/patches/workarounds/0003-xbmc-libdvd_vfs-enen92.patch5056
-rw-r--r--debian/patches/workarounds/0004-ffmpeg6.patch662
-rw-r--r--debian/patches/workarounds/0005-pcre2.patch1219
-rw-r--r--debian/patches/workarounds/0006-loongarch.patch40
-rw-r--r--debian/patches/workarounds/0007-swig.patch10
-rwxr-xr-xdebian/rules294
-rw-r--r--debian/source/format1
-rw-r--r--debian/source/include-binaries8
-rw-r--r--debian/source/options2
-rw-r--r--debian/tests/control3
-rwxr-xr-xdebian/tests/gui23
-rw-r--r--debian/upstream/metadata7
-rw-r--r--debian/upstream/signing-key.asc25
-rw-r--r--debian/watch75
-rw-r--r--debian/webinterface-default/addon.xml145
-rw-r--r--debian/webinterface-default/css/core.css794
-rw-r--r--debian/webinterface-default/css/ipad.css9
-rw-r--r--debian/webinterface-default/favicon.icobin0 -> 370070 bytes
-rw-r--r--debian/webinterface-default/icon.pngbin0 -> 6129 bytes
-rw-r--r--debian/webinterface-default/images/DefaultAlbumCover.pngbin0 -> 46672 bytes
-rw-r--r--debian/webinterface-default/images/DefaultVideo.pngbin0 -> 44464 bytes
-rw-r--r--debian/webinterface-default/images/ajax-loader.gifbin0 -> 4782 bytes
-rw-r--r--debian/webinterface-default/images/close-button.pngbin0 -> 1649 bytes
-rwxr-xr-xdebian/webinterface-default/images/remote.jpgbin0 -> 44656 bytes
-rwxr-xr-xdebian/webinterface-default/index.html73
-rwxr-xr-xdebian/webinterface-default/js/MediaLibrary.js1420
-rwxr-xr-xdebian/webinterface-default/js/NowPlayingManager.js661
-rw-r--r--debian/webinterface-default/js/json2.js492
-rw-r--r--debian/webinterface-default/js/xbmc.core.js90
-rw-r--r--debian/webinterface-default/js/xbmc.init.js27
-rw-r--r--debian/webinterface-default/js/xbmc.launcher.js46
-rw-r--r--debian/webinterface-default/js/xbmc.rpc.js49
104 files changed, 27862 insertions, 0 deletions
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 0000000..d5dda4c
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,24 @@
+Kodi from Debian
+----------------
+
+This package is different from the package you can build from the Kodi source
+you can download from https://kodi.tv (vanilla Kodi, from now on).
+
+This package uses external libraries such as libav distributed in Debian, while
+the XBMC project suggests using the libraries embedded in vanilla Kodi's source.
+
+This difference may cause problems not experienced with vanilla Kodi thus you
+are kindly asked not to report bugs directly to https://kodi.tv, but to
+Debian's Bug Tracking System (BTS):
+
+ https://bugs.debian.org/src:kodi
+
+You can get an overview of the package at Debian Tracker:
+
+ https://tracker.debian.org/kodi
+
+or ask your queestions in Debian Multimedia mailing list by e-mail:
+
+ debian-multimedia@lists.debian.org
+
+ -- Vasyl Gello <vasek.gello@gmail.com>, Fri, 13 Nov 2020 10:00:00 +0300
diff --git a/debian/README.source b/debian/README.source
new file mode 100644
index 0000000..70b0b61
--- /dev/null
+++ b/debian/README.source
@@ -0,0 +1,32 @@
+Kodi used to embed dvdread and dvdnav in its source but the developers switched to
+downloading it which is not an option for Debian source packages. The embedded
+copy of both libraries is retrieved from VideoLAN upstream by watchfile and the
+required Debian patches are applied (debian/patches/libdvd{read,nav}-*.patch).
+
+Kodi replaced the default webinterface in 17.0 beta6 but the new interface contains
+many generated files without providing the source for them. The web interface
+is temporarily reverted to the one included in beta5 to restore GPL compliance.
+
+The web interface is placed in debian patch folder (debian/webinterface-default)
+and is copied in autoconf override because quilt patches can not handle git binary
+diffs.
+
+The cdatetime-std-chrono patch set, available as upstream PR:
+
+ https://github.com/xbmc/xbmc/pull/18727
+
+is a refactored date and time conversion logic in Kodi, that fixes the totally
+broken current implementation for 32-bit architectures (i386, mipsel).
+It should have been added to 19.0 but upstream authors decided to postpond it
+until 20.0 development cycle starts. I decided to include it in Debian release
+nonetheless along with embedded date library (embedded-libdate-tz) from Howard
+Hinnant:
+
+ https://github.com/Howardhinnant/date
+
+It does not make sense to package libdate-tz separately because it is partially
+accepted as upcoming C++20 standard and eventually kodi will move to C++20 in
+20.0 or 21.0. Upstream author also expects the library to be embedded in project,
+reasoning of "poor CMake support" (see upstream issues).
+
+ -- Vasyl Gello <vasek.gello@gmail.com>, Tue, 3 Jun 2020 10:30:00 +0300
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..168cc81
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,1241 @@
+kodi (2:20.4+dfsg-1) unstable; urgency=medium
+
+ * New upstream version 20.4+dfsg
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sun, 11 Feb 2024 07:12:03 +0000
+
+kodi (2:20.3+dfsg-1) unstable; urgency=medium
+
+ * New upstream version 20.3+dfsg (Closes: #1061600)
+ * Build with APP_RENDER_SYSTEM=gles for arm platforms (Closes: #1056563)
+ * Add pcre2 patch (Closes: #1000113)
+ * Add workaround for LoongArch (Closes: #1054463)
+ * Drop obsolete font metapackages from deps (Closes: #1050052)
+ * Drop patches merged upstream
+ * Update cdatetime-std-chrono patchset
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sat, 03 Feb 2024 13:51:04 +0000
+
+kodi (2:20.2+dfsg-4) unstable; urgency=medium
+
+ * Add patch to fix crash with ffmpeg6
+ * Fix FTBFS on s390x (Closes: #1043128)
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sun, 06 Aug 2023 08:31:29 +0000
+
+kodi (2:20.2+dfsg-3) unstable; urgency=medium
+
+ * Revert language pack patches for now to land
+ in unstable
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Fri, 04 Aug 2023 23:26:08 +0000
+
+kodi (2:20.2+dfsg-2) unstable; urgency=medium
+
+ * d/gbp.conf: Drop unnecessary upstream-branch
+ * debian: switch to DEP-14 git branch naming scheme
+ * Prepare for language pack separation
+ * Separate language packs (Closes: #1042996)
+ * Fix build against FFmpeg 6.0 (Closes: #1041400)
+ * Add patch for CD/DVD playback without mount support
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Fri, 04 Aug 2023 19:25:39 +0000
+
+kodi (2:20.2+dfsg-1) unstable; urgency=medium
+
+ * New upstream version 20.2+dfsg
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 03 Jul 2023 08:50:21 +0000
+
+kodi (2:20.1+dfsg-1) unstable; urgency=medium
+
+ * New upstream version 20.1+dfsg
+ * Refresh cdatetime-std-chrono patchset
+ * Drop patches merged upstream
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sun, 12 Mar 2023 09:31:18 +0000
+
+kodi (2:20.0+dfsg-2) unstable; urgency=high
+
+ * s/gbp.conf: Switch to versioned upstream branches
+ * Fix CVE-2023-23082 (Closes: #1031048)
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 13 Feb 2023 10:43:13 +0000
+
+kodi (2:20.0+dfsg-1) unstable; urgency=medium
+
+ * New upstream version 20.0+dfsg
+ * d/rules: Add alpha and arm64 overrides
+ * Refresh ports patch
+ * Refresh libdvd patch
+ * Refresh cdatetime-std-chrono patchset
+ * Drop patches merged upstream
+ * Refresh ffmpeg5 patch
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sat, 21 Jan 2023 18:03:44 +0000
+
+kodi (2:20.0~rc2+dfsg-2) unstable; urgency=medium
+
+ * d/rules: Declare ports architectures
+ * Add patch to build on ports architectures
+ * Refresh ffmpeg5 patch
+ * Patch DoS vulnerability awaiting for CVE
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Thu, 05 Jan 2023 07:24:56 +0000
+
+kodi (2:20.0~rc2+dfsg-1) unstable; urgency=medium
+
+ * New upstream version 20.0~rc2+dfsg
+ * d/control: Add B+R on kodi-addons-dev
+ * d/control: Bump standards version (no changes required)
+ * d/copyright: Bump copyright years
+ * Drop patches merged upstream
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 19 Dec 2022 19:06:13 +0000
+
+kodi (2:20.0~rc1+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 20.0~rc1+dfsg1
+ * Drop obsolete build dependency libgl1-mesa-dev
+ * Add Breaks/Replaces to kodi-addons-dev fixing piuparts failure
+ in stable2sid
+ * Add copyright entries for embedded libdvd*
+ * Drop copyright entry for libdate-tz-embedded and several
+ other extinct paths
+ * Fix the missing manpage after move of /usr/bin/dh_kodiaddon_depends
+ * Add patches for bashisms in kodi.sh
+ * Add descriptions to workaround patches
+ * Use +dfsg instead of +dfsg1 in watchfile
+ * Add workaround patches addressing removal of EGL Chromium headerfile
+ in Mesa 22.3.0 anda regression of playlist detection in Kodi 20 RC1
+ * Refresh cdatetime patchset fixing broken test spotted during
+ reproducibility test
+ * Fix placement of zeroconf wrapper
+ * Drop old NEWS entry about systemd integration
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Tue, 13 Dec 2022 15:04:25 +0000
+
+kodi (2:20.0~beta1+dfsg1-2) unstable; urgency=medium
+
+ * d/rules: Add installable dummy file to kodi/system
+ * Add workaround to fix crossbuilds
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Wed, 09 Nov 2022 21:16:07 +0000
+
+kodi (2:20.0~beta1+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 20.0~beta1+dfsg1
+ * Refresh cdatetime patchset
+ * Refresh kodi and libdvdread patchsets
+ * Refresh ffmpeg5 patchset
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Tue, 08 Nov 2022 19:44:52 +0000
+
+kodi (2:20.0~alpha3+git20221015.976c5c8+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 20.0~alpha3+git20221015.976c5c8+dfsg1
+ * Ship firewalld files (Closes: #1015956)
+ * Bump standards version
+ * Fix lintian warnings
+ * Use system howardhinnant-date
+ * d/watch: Switch to git tags instead of webpage scraping
+ * d/watch: Temporary switch libdvd* to master branch
+ * Refresh kodi patchset
+ * Drop libdvdnav patchset
+ * Drop workaround patches merged upstream
+ * Refresh cdatetime-std-chrono patchset
+ * workarounds: Add libdvd* callback support (Closes: #1020452)
+ * workarounds: refresh ffmpeg5 patch (Closes: #1016925)
+ * d/rules: Follow on upstream buildsystem changes
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sat, 15 Oct 2022 16:54:13 +0000
+
+kodi (2:20.0~alpha2+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 20.0~alpha2+dfsg1
+ * d/copyright fixes:
+ + Keep COMPONENT-VERSION files in tools/depends/target
+ + Remove useless versioncheck addon (Closes: #1015163)
+ + Bump copyright years
+ * Remove obsoleted patches and update the rest:
+ + Add patch fixing color conversion test (merged)
+ + Add patch for overriding local tarball checksum (merged)
+ + Add patch for ffmpeg 5 support (not merged) (Closes: #1004612)
+ + Add patch for proper fix of EDL rounding (merged)
+ + Add patch for building against libfmt 9.0.0 (merged) (Closes: #1014542)
+ * d/rules fixes:
+ + Don't rely on versionfile parsing
+ * + Supply SHA256 hashes for libdvd*
+ * Upload to unstable.
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Wed, 03 Aug 2022 14:24:22 +0000
+
+kodi (2:20.0~alpha1+dfsg1-2) experimental; urgency=medium
+
+ * Fix failing tests and restore timezone picker (Closes:‌ #1011241)
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Thu, 19 May 2022 15:08:49 +0000
+
+kodi (2:20.0~alpha1+dfsg1-1) experimental; urgency=medium
+
+ * New upstream version 20.0~alpha1+dfsg1
+ * Leave only language packs in repo-resources-embedded
+ * Branch out experimental
+ * Restrict watchfile to next Debian stable codename
+ * Add pipewire to build-dependencies
+ * Refresh Kodi patches
+ * Add workaround patches
+ * Refresh cdatetime-std-chrono patches
+ * Refresh headers-check.c
+ * Use system RapidJSON
+ * Bump libdate-tz C++ standard to 17 and enable StringView back
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 16 May 2022 06:45:07 +0000
+
+kodi (2:19.4+dfsg2-1) unstable; urgency=medium
+
+ * New upstream version 19.4+dfsg2
+ + Ship language packs for offline use (Closes: #1009278)
+ + Add copyright entry for language pack tarball
+ * Build libdate-tz as external build-dependency of Kodi.
+ * d/rules: Annotate actions and replace direct source patching
+ within rulefile with proper compiler definition
+ * d/rules:‌ Fix improper cleanup of generated embedded tarballs
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Fri, 29 Apr 2022 07:10:17 +0000
+
+kodi (2:19.4+dfsg1-2) unstable; urgency=medium
+
+ * Upload to unstable
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 09 Apr 2022 12:51:13 +0000
+
+kodi (2:19.4+dfsg1-1) experimental; urgency=medium
+
+ * New upstream version 19.4+dfsg1
+ * Drop system/certs and .github from tarball
+ * Refresh patches
+ * Reorder package structure to allow installation on
+ foreign architectures (Closes: #996627)
+ * Move TexturePacker to a separate binary package
+ * Fix Lintian warnings.
+ * Build native prerequisites before configure if cross-building
+ * Version the build-dependency on gtest to >= 1.10.0~
+ * d/watch: Switch libdate-tz to tags
+ * Put KodiConfig.cmake in arch-dep place (Closes: #999482)
+ * Add patches for cross build support
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 21 Mar 2022 17:48:21 +0000
+
+kodi (2:19.3+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 19.3+dfsg1
+ * Refresh patches
+ * Add proper WITH_ARCH for amd64, i386 and riscv64
+ * Disable DebugFission by CMake configuration option instead of patch
+ * Use the system kissft
+ * kodi-bin: Remove unused lintian override
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sun, 24 Oct 2021 14:45:29 +0000
+
+kodi (2:19.2+dfsg1-2) unstable; urgency=medium
+
+ * Fix AppStream warning with metainfo file
+ * Make build reproducible
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Wed, 13 Oct 2021 22:12:35 +0000
+
+kodi (2:19.2+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 19.2+dfsg1
+ * Restrict watchfile to current Debian stable codename
+ * Bump standard version
+ * Refresh patches
+ * Install package metainfo
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Wed, 06 Oct 2021 10:59:56 +0000
+
+kodi (2:19.1+dfsg2-2) unstable; urgency=medium
+
+ * Add runtime locale test and fallback (Closes: #989814)
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Thu, 24 Jun 2021 20:44:30 +0000
+
+kodi (2:19.1+dfsg2-1) unstable; urgency=medium
+
+ * New upstream version 19.1+dfsg2
+ * Merge 'bullseye' branch into master and revert patches
+ related to newer libdvdread and branch isolation.
+ * Drop the patch downgrading ffmpeg to fit buster-backports.
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 07 Jun 2021 16:42:08 +0200
+
+kodi (2:19.0+dfsg1-2) unstable; urgency=medium
+
+ * Add missing font dependency (Closes: #985497)
+ * Fix github ref
+ * Branch out bullseye
+ * Refresh cdatetime-std-chrono patch (Closes: #984682)
+ * libdate-tz: Fix crash for early local times and USE_OS_TZDB
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sun, 30 May 2021 04:57:39 +0000
+
+kodi (2:19.1+dfsg1-1~exp0) experimental; urgency=medium
+
+ * New upstream version 19.1+dfsg1
+ * Add missing font dependency (Closes: #985497)
+ * Fix links to Github releases in watchfile
+ * Refresh patches
+ * Prepare for official backport
+ * Refresh cdatetime-std-chrono patch (Closes: #984682)
+ * libdate-tz: Fix crash for early local times and USE_OS_TZDB
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sat, 15 May 2021 21:15:26 +0000
+
+kodi (2:19.0+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 19.0+dfsg1
+ * Declare proper Debian release splitting kodi-addons-dev (Closes: #980846)
+ * Detect and honor big-endian architectures
+ * Refresh cdatetime-std-chrono patch
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Fri, 19 Feb 2021 00:02:45 +0000
+
+kodi (2:19.0~rc1+git20210119.8c761c4+dfsg1-2) experimental; urgency=medium
+
+ * Team upload.
+ * Re-instate the kodi-addons-dev-common package split.
+
+ -- Mattia Rizzolo <mattia@debian.org> Wed, 20 Jan 2021 01:56:06 +0100
+
+kodi (2:19.0~rc1+git20210119.8c761c4+dfsg1-1) unstable; urgency=medium
+
+ [ Vasyl Gello ]
+ * New upstream version 19.0~rc1+dfsg1 and 19.0~rc1+git20210119.8c761c4+dfsg1.
+ + Fix possible crash on shutdown. (Closes: #979367)
+ + New upstream snapshot fixes non-DFSG free JPEG image
+ which led to FTP master rejection
+ * d/watch: mangle capital letter abbrevs too
+ * Delete patches merged upstream
+ * Refresh cdatateime-std-chrono patch
+ * copyright: Reflect skin.estuary picture replacement
+
+ [ Mattia Rizzolo ]
+ * Temporary revert the kodi-addons-dev-common split to avoid NEW fo
+ this upload (the previous version was rejected from NEW).
+ * Upload to unstable.
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Tue, 19 Jan 2021 20:02:25 +0000
+
+kodi (2:19.0~beta2+dfsg1-6) experimental; urgency=medium
+
+ [ Mattia Rizzolo ]
+ * d/control: define dh-sequence-kodiaddon as a versioned Provides
+
+ [ Vasyl Gello ]
+ * Check the existence of kodi include dir's full path
+ in dh_kodiaddon_depends.
+ * Refresh cdatetime-std-chrono patch. (Closes: #980038)
+ * Introduce a kodi-addons-dev-common package to hold all the arch-indep
+ files.
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Tue, 12 Jan 2021 02:57:10 +0000
+
+kodi (2:19.0~beta2+dfsg1-5) unstable; urgency=medium
+
+ * Team upload.
+ * Fix arch:all build after turning kodi-addons-dev arch:any.
+
+ -- Mattia Rizzolo <mattia@debian.org> Sun, 10 Jan 2021 20:46:04 +0100
+
+kodi (2:19.0~beta2+dfsg1-4) unstable; urgency=medium
+
+ * Team upload.
+
+ [ Vasyl Gello ]
+ * d/watch: Declare bare git snapshot naming scheme since v20.
+
+ [ Mattia Rizzolo ]
+ * Mark kodi-addons-dev as Arch:any.
+ This is to prevent addons from building in architectures where Kodi
+ is not available.
+
+ -- Mattia Rizzolo <mattia@debian.org> Sun, 10 Jan 2021 15:57:30 +0100
+
+kodi (2:19.0~beta2+dfsg1-3) unstable; urgency=medium
+
+ * d/upstream/metadata: Add Bug-Submit URL
+ * Drop libenca-dev build dependency
+ * dh_kodiaddon_depends: Provide a sliding window
+ for ABI bumps to avoid unnecessary addon rebuild
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sun, 03 Jan 2021 08:45:17 +0000
+
+kodi (2:19.0~beta2+dfsg1-2) unstable; urgency=medium
+
+ [ Vasyl Gello ]
+ * Upload to unstable (Closes: #926922)
+ * d/watch: Simplify dversionmangle
+ * Update Vcs-Git/Vcs-Browser for the move to 'kodi-media-center' subgroup
+ * Restore libfreetype6-dev alternative build-dep for buster.
+
+ [ Tobias Frost ]
+ * Add CVE-ids to past changelog entries when they have been fixed,
+ as per security team policy.
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Tue, 22 Dec 2020 10:01:37 +0000
+
+kodi (2:19.0~beta2+dfsg1-1) experimental; urgency=medium
+
+ * New upstream version 19.0~beta2+dfsg1
+ + Fix kodi-ps3remote crash. (Closes: #962929)
+ * Build a new kodi-eventclients-zeroconf package with the zeroconf scripts
+ * Add breaks and replaces to kodi-eventclients-ps3
+ * Backport a patch from Kodi 20 to replace CDateTime with cdate-std-chrono.
+ Fixes test failures on multiple architectures.
+ + Add libdate-tz as component tarball
+ * Update d/copyright
+ * Use the system-wide tzdata.
+ * Drop clang-format from build-deps, not actually needed during the build
+ * Mark kodi-addons-dev as indep
+ * Fix arch-indepedent-only build (Closes: #976303)
+ * Bump Standards-Version to 4.5.1 (no changes required)
+ * Fix lintian warnings
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Sat, 19 Dec 2020 04:55:34 +0000
+
+kodi (2:19.0~alpha3+dfsg1-1) experimental; urgency=medium
+
+ [ Vasyl Gello ]
+ * New upstream version 19.0~alpha3+dfsg1
+ + This version fully builds with Python 3. (Closes: 936805)
+ * Refresh patches
+ * Revert "temporary disable tests parallelism", in 19.0 tests run fine
+ * Bump the required ffmepg version
+ * Don't use clang-format on x32
+ * Drop the build-dep on lib-p8-platform
+ * Update the watchfile
+ * Don't run dwz during the build as it fails on us
+ * Add several Multi-Arch fields, from the M-A hinter
+ * Fix several lintian warnings
+ * Add default webinterface as debian include (this is temporary until the
+ packaging of the new interface is completed)
+ * Retrieve embedded libdvdnav and libdvdread from upstream
+ * debian/header-check.c: Add new and delete removed headers
+ * Refresh copyright information
+ * Provide 'dh-sequence-kodiaddon' virtual package
+ * Drop kodi-x11, kodi-wayland and kodi-gbm packages, now the same binary
+ can handle all window systems
+
+ [ Adrian Bunk ]
+ * Rename SSE patch file (Closes: #961856)
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Tue, 17 Nov 2020 13:04:40 +0100
+
+kodi (2:18.8+dfsg1-2) unstable; urgency=medium
+
+ * temporary disable tests parallelism (Closes: #968339)
+ * add myself to Uploaders
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Thu, 03 Sep 2020 01:48:09 +0300
+
+kodi (2:18.8+dfsg1-1) unstable; urgency=medium
+
+ [ Vasyl Gello ]
+ * Team upload
+ * fix circular dependency hell (Closes: #963865)
+ * Depend on libudfread & shairplay
+ * remove unnecessary dlopen-ed shlibdeps from kodi-bin
+ * remove dummy remnant
+
+ [ Jonas Smedegaard ]
+ * Remove myself from Uploaders
+
+ [ Vasyl Gello ]
+ * drop unnecessary cpluff component
+ * New upstream version 18.8+dfsg1 (Closes: #964591)
+ * Refresh patches
+
+ [ Adrian Bunk ]
+ * Don't enable SSE in i386 builds (Closes: #961856)
+
+ [ Balint Reczey ]
+ * debian/README.source: Clarify that dvdread and dvdnav are patched for Kodi
+ * debian/gbp.conf: Set components
+ * debian/README.source: Gbp now exports components properly
+ * New upstream version 18.7.1+dfsg1
+
+ -- Vasyl Gello <vasek.gello@gmail.com> Mon, 03 Aug 2020 02:20:44 +0000
+
+kodi (2:18.7+dfsg1-1) unstable; urgency=medium
+
+ * Team upload
+ * New upstream version 18.7
+ * Refresh patches
+ * Update additional tarballs to libdvdnav 6.1.0 and libdvdread 6.1.1
+
+ -- Balint Reczey <rbalint@ubuntu.com> Tue, 26 May 2020 16:14:53 +0200
+
+kodi (2:18.6+dfsg1-2) unstable; urgency=medium
+
+ * Team upload
+ * Drop pycryptodome support with Python 2
+ * debian/control: Revert kodi-data to depend on python-pil instead of python3-pil.
+ Kodi runs addons with Python 2 and many addons would break without PIL.
+ * Run kodi-ps3remote with Python 3
+ * Apply suggestion to debian/rules
+ * debian/rules: Ship debug symbols for all kodi binaries and drop -dbg migration
+ (Closes: #955134)
+
+ -- Balint Reczey <rbalint@ubuntu.com> Fri, 03 Apr 2020 13:48:30 +0200
+
+kodi (2:18.6+dfsg1-1) unstable; urgency=medium
+
+ * Upload to unstable
+
+ -- Balint Reczey <rbalint@ubuntu.com> Sat, 21 Mar 2020 16:39:01 +0100
+
+kodi (2:18.6+dfsg1-1~exp1) experimental; urgency=medium
+
+ * test: Disable flaky TestMassEvent.General test, too
+
+ -- Balint Reczey <rbalint@ubuntu.com> Thu, 19 Mar 2020 21:41:10 +0100
+
+kodi (2:18.6+dfsg1-1~exp0) experimental; urgency=medium
+
+ * debian/rules: Set -DWITH_ARCH=... and -DNEON=False explicitly for armel,
+ armhf, ppc64el and s390x. Those Debian architectures are not detected
+ properly by upstream CMake scripts.
+ * Build-depend on python2-dev
+ * Reposition "from debian" on the main screen to adjust to the changed new
+ skin
+ * Don't strip service.xbmc.versioncheck addon from upstream tarball
+ * New upstream version 18.6
+ * Ship versioncheck addon disabled
+ * Disable long-time failing test and fix others instead of ignoring all test
+ results
+ * Drop obsolete patches
+ * Drop 03-privacy.patch and add TODO item about resurrecting it properly
+ * Refresh patches
+ * Run kodi-send with Python 3
+ * test: Disable flaky TestMassEvent.Polling test
+ * Fix ppc64el build
+ * Fix arch detection
+ * test: Skip checking errno against ENOEN to not FTBFS on armhf
+
+ -- Balint Reczey <rbalint@ubuntu.com> Wed, 18 Mar 2020 12:09:23 +0100
+
+kodi (2:18.5+dfsg1-1~exp0) experimental; urgency=medium
+
+ [ Balint Reczey ]
+ * Team upload
+ * debian/tests/gui: Wait for kodi to start, not just a fixed 5 seconds
+ * Refresh patches
+ * Update extra libdvdnav and libdvdread original tarballs
+ * debian/copyright_hints: Update hints with new files
+ * debian/control: Tidy up using cme fix
+ * debian/gitlab-ci.yml: Add Salsa CI configuration
+ * Refresh build dependencies based on upstream's packaging
+ * Ship separate packages for X11, Wayland and GBM
+ * debian/rules:
+ - Rewrite to use cmake and build separate binaries.
+ Thanks to Wolfgang Schupp
+ - Extend override_dh_clean
+ - Pass -lphtread to linker by default
+ - Refactor building Debianized artifacts
+ - Run tests for each build dir
+ - Clean up separate build directories
+ - clean media/Fonts/arial.ttf, too
+ - Call dh with python2
+ - Drop obsolete --parallel dh argument
+ - Adjust to new component names
+ * debian/copyright: Fix open issues and Lintian complaints
+ * Let upstream's build system build the embedded libdvdnav and libread
+ libraries
+ * Install TexturePacker to /usr/bin/
+ * Ignore failing tests for now
+ * Update which files are shipped by which package
+ * Switch hashing implementation from OpenSSL to Libgcrypt
+ * Build without OpenSSL
+ * Depend on unhinted Roboto font (Closes: #922950)
+ * Fix FTBFS of kodi-test by not #include-ing excluded Windows-only header
+ * Fix dh_kodiaddon_depends to get API versions the new way
+ * Refresh file list shipped by kodi-addons-dev
+ * Remove myself from Uploaders
+ * Work around FTBFS caused by fontforge SEGFAULT
+ * New upstream version 18.5+dfsg1 (CVE-2017-5982)
+ * debian/gbp.conf: Drop postexport hook.
+ It is obsoleted by storing all components in git.
+ * Stop marking kodi-bin Multiarch: same since it now ships TexturePacker
+ * Stop marking kodi-gbm, kodi-x11 and kodi-wayland Multiarch: same.
+ They depend on kodi-bin which is not Multiarch: same either.
+ * Build kodi-wayland, too
+
+ [ Rechi ]
+ * debian/copyright: update Files-Excluded
+ - libUPnP was updated
+ - UnrarXLib was split into an addon
+ - Visual Studio files were removed
+ - windows platform specific code location changed
+ * drop unused Build-depends
+ * add new Build-depends
+ * debian/rules: remove unused DEB vars
+ * debian/rules: remove non existent cmake options
+ - egl is a required dependency on linux so there is no ENABLE_EGL switch
+ - x11 isn't an optional dependency for gbm so there is no ENABLE_X11 switch
+ - vdpau is only an optional dependency for x11, so ENABLE_VDPAU switch
+ exists only for x11
+ * debian/rules: update dlopened libs
+ libass, libbluray, libcec, libcurl and libnfs are no longer dlopend
+ * fix libmicrohttpd linking
+ * debian/rules: install kodi-x11 as last package
+ last installed package defines the fallback windowing in bin/kodi
+ * fix depends syntax
+ * fix test target build system dependency
+
+ -- Balint Reczey <rbalint@ubuntu.com> Fri, 24 Jan 2020 08:20:58 +0100
+
+kodi (2:17.6+dfsg1-4) unstable; urgency=medium
+
+ * debian/tests/gui: Print xvfb-run error to stdout
+ * debian/tests/gui: Fix test by starting 24bit screen and waiting for
+ kodi's start
+ * Drop transitional packages
+ * Fix FTBFS when _G_va_list is not defined, like on Ubuntu 19.04
+
+ -- Balint Reczey <rbalint@ubuntu.com> Tue, 20 Nov 2018 12:21:00 +0100
+
+kodi (2:17.6+dfsg1-3) unstable; urgency=medium
+
+ [ Balint Reczey ]
+ * debian/NEWS: Fix language to keep lintian happy
+ * Add simple autopkgtest
+
+ [ Gianfranco Costamagna ]
+ * Upstream fixes for new ffmpeg:
+ debian/patches/19f28e88a5dfed82e9844f69210f7c045f18ca8e.patch
+ debian/patches/c7e2acc1b2ee781af6e14d80da0edd0aa23bdf03.patch
+ (Closes: #888383, #912994)
+
+ -- Balint Reczey <rbalint@ubuntu.com> Fri, 16 Nov 2018 01:42:36 +0100
+
+kodi (2:17.6+dfsg1-2) unstable; urgency=medium
+
+ [ Ondřej Nový ]
+ * d/copyright: Use https protocol in Format field
+ * d/control: Set Vcs-* to salsa.debian.org
+
+ [ Rechi ]
+ * Drop build dependencies on libboost-*
+ Boost isn't required since v17.
+
+ [ Felipe Sateler ]
+ * Change maintainer address to debian-multimedia@lists.debian.org
+
+ [ Balint Reczey ]
+ * Ship only Kodi desktop session without the xbmc.desktop duplicate link
+ * Stop build-depending on versioned GCC, this workaround is not needed
+ anymore (Closes: #892399)
+ Thanks to Adrian Bunk who also proposed a patch and a delayed NMU.
+ * Stop shipping kodi.service
+ Please use a lightweight display manager set up to autologin instead.
+ * Add d/source.lintian-overrides to d/source/lintian-overrides
+ to keep lintian happy
+
+ [ Rolf Leggewie ]
+ * demote hard font dependencies from Depends to Recommends (LP: #1685918)
+
+ -- Balint Reczey <rbalint@ubuntu.com> Sat, 28 Apr 2018 20:50:46 +0200
+
+kodi (2:17.6+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 17.6 (with accumulated changes from 17.4 and 17.5):
+ - https://kodi.tv/article/kodi-v174-final-just-bunch-fixes
+ - https://kodi.tv/article/kodi-v175-final-another-bunch-fixes
+ - https://kodi.tv/article/kodi-v176-final-very-last
+ * Refresh patches
+ * Depend and build-depend on python-pil instead of python-imaging
+ (Closes: #866437)
+ * Apply workaround for scratchy sound with FFmpeg 3.4.
+ Thanks to James Cowgill for triaging and Stefan Hachmann for the patch
+ (Closes: #881536)
+ * Fix starting kodi on arm64 (Closes: #876876)
+ * Change URLs to use HTTPS in README.Debian and drop feed URL from
+ description (Closes: #860484)
+
+ -- Balint Reczey <rbalint@ubuntu.com> Tue, 26 Dec 2017 01:06:49 +0100
+
+kodi (2:17.3+dfsg1-5) unstable; urgency=medium
+
+ * Build-depend on fontforge-nox (not fontforge.
+ * Use rsvg-convert to generate branding logo.
+ Build-depend on (not inkscape).
+ * Fix remove repository feed from kodi-data.
+ Tighten kodi-repository-kodi breaks+replaces on kodi-data.
+
+ -- Jonas Smedegaard <dr@jones.dk> Wed, 11 Oct 2017 02:37:25 +0200
+
+kodi (2:17.3+dfsg1-4) unstable; urgency=medium
+
+ * Update package relations:
+ + Fix have kodi-repository-kodi conflict against and replace older
+ kodi/kodi-data/xbmc.
+ Fixes bug#877960. Thanks to Andreas Beckmann.
+ + Fix have kodi-repository-kodi conflict against (not break) virtual
+ kodi-repository.
+ + Fix have package kodi-repository-kodi depend on ${misc:Depends}.
+ + Stop build-depend on dh-autoreconf autotools-dev: Handled by
+ debhelper.
+ * Rewrite copyright info, with major coverage improvements.
+ * Add maintainer script copyright-check to source.
+ * Update git-buildpackage config:
+ + Add usage comment.
+ + Filter any .git* file.
+ * Override lintian regarding license in License-Reference field.
+ See bug#786450.
+ * Override lintian regarding obsolete-url-in-packaging: License grant
+ must be included verbatim.
+
+ -- Jonas Smedegaard <dr@jones.dk> Tue, 10 Oct 2017 22:46:23 +0200
+
+kodi (2:17.3+dfsg1-3) unstable; urgency=medium
+
+ * Fix set core configure options to all instances.
+ * Set configure options --disable-maintainer-mode
+ --disable-silent-rules (unused now but might be added in future).
+ * Fix avoid custom build rule silencing.
+ * Fix FTBFS: Build-depend on and build with gcc-6 and g++-6 (until
+ bug#841556 is fixed).
+ Closes: Bug#853476. Thanks to Matthias Klose and Bálint Réczey.
+ * Modernize Vcs-* fields:
+ + Use https (not git or http) protocol.
+ + Use git (not gitweb) in path.
+ * Use https in Homepage URL.
+ * Add myself as uploader.
+ * Add patch 18 to support omitting addon repository feed.
+ * Ship repository feed in separate package kodi-repository-kodi.
+ Closes: Bug#877656 (or arguably only lowers severity of it, but
+ since we cannot track that versioned better to close and track the
+ lowered severity separately).
+
+ -- Jonas Smedegaard <dr@jones.dk> Wed, 04 Oct 2017 03:53:10 +0200
+
+kodi (2:17.3+dfsg1-2) unstable; urgency=medium
+
+ * Upload to unstable
+ * Stop shipping kodi.service as an example since it is now shipped
+ as a regular .service file
+
+ -- Balint Reczey <rbalint@ubuntu.com> Thu, 29 Jun 2017 05:15:29 +0200
+
+kodi (2:17.3+dfsg1-1) experimental; urgency=medium
+
+ * New upstream version 17.3
+ See: https://kodi.tv/article/kodi-v173-minor-bug-fix-and-security-release
+ * Refresh patches
+
+ -- Balint Reczey <rbalint@ubuntu.com> Fri, 26 May 2017 18:44:04 +0200
+
+kodi (2:17.1+dfsg1-3) unstable; urgency=medium
+
+ * Fix zip file directory traversal vulnerability (CVE-2017-8314)
+ (Closes: #863230)
+
+ -- Balint Reczey <rbalint@ubuntu.com> Sat, 27 May 2017 00:50:34 +0200
+
+kodi (2:17.1+dfsg1-2) unstable; urgency=medium
+
+ * Upload to unstable
+
+ -- Balint Reczey <rbalint@ubuntu.com> Thu, 13 Apr 2017 23:49:12 +0200
+
+kodi (2:17.1+dfsg1-1) experimental; urgency=medium
+
+ * Depend on fonts-noto-mono package which contains NotoMono-Regular.ttf
+ (Closes: #856668)
+ * Fix FTBFS on alpha by not using Intel assempler code (Closes: #856815)
+ * Imported Upstream version 17.1+dfsg1
+ See: https://kodi.tv/kodi-v17-1-krypton
+ * Update my Uploader email address to my Ubuntu one
+ * Fix extract-components target in d/rules
+
+ -- Balint Reczey <rbalint@ubuntu.com> Sun, 02 Apr 2017 11:01:21 +0200
+
+kodi (2:17.1~rc1+dfsg1-1) experimental; urgency=medium
+
+ * Imported Upstream version 17.1~rc1+dfsg1
+ * Refresh patches
+
+ -- Balint Reczey <balint@balintreczey.hu> Tue, 28 Feb 2017 02:21:54 +0100
+
+kodi (2:17.0+dfsg1-3) unstable; urgency=medium
+
+ * Ship disabled systemd service file (Closes: #854985, #801886)
+ * Use systemd service file recommended on upstream wiki
+
+ -- Balint Reczey <balint@balintreczey.hu> Wed, 22 Feb 2017 01:28:43 +0100
+
+kodi (2:17.0+dfsg1-2) unstable; urgency=medium
+
+ * Apply patches to additional tarballs using quilt series file
+ (Closes: #854463)
+
+ -- Balint Reczey <balint@balintreczey.hu> Thu, 09 Feb 2017 10:25:18 +0100
+
+kodi (2:17.0+dfsg1-1) experimental; urgency=medium
+
+ * Imported Upstream version 17.0+dfsg1
+ See: https://kodi.tv/kodi17/
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 06 Feb 2017 19:33:08 +0100
+
+kodi (2:17.0~rc4+dfsg1-1) experimental; urgency=medium
+
+ * Imported Upstream version 17.0~rc4+dfsg1
+ See: https://kodi.tv/kodi-v17-0-krypton-release-candidate-4/
+ * Refresh patches
+ * Remove spaces around '=' in service file.
+ Also convert service file to use Unix line ending
+
+ -- Balint Reczey <balint@balintreczey.hu> Sun, 05 Feb 2017 01:27:27 +0100
+
+kodi (2:17.0~rc3+dfsg1-2) unstable; urgency=medium
+
+ * Bump debhelper compat level to 10.
+ Remove --parallel and --with autoreconf since those are now defaults
+ * Build-depend on libcec-dev >= 4~ (Closes: #852216)
+ * Fix make clean in debian/rules
+ * Use real dlopen() for opening libdvdcss (Closes: #784578)
+
+ -- Balint Reczey <balint@balintreczey.hu> Wed, 25 Jan 2017 21:23:22 +0100
+
+kodi (2:17.0~rc3+dfsg1-1) unstable; urgency=medium
+
+ * Make default lirc device match lirc package's default (Closes: #850467)
+ * Stop passing ./configure flags which are not supported anymore
+ * Update fonts and font dependencies
+ * Imported Upstream version 17.0~rc3+dfsg1
+ See: https://kodi.tv/kodi-v17-0-krypton-release-candidate-3/
+ * Refresh patches
+ * Fix FTBFS due to missing AEDefines_override.h
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 16 Jan 2017 21:41:03 +0100
+
+kodi (2:17.0~rc2+dfsg1-1) unstable; urgency=medium
+
+ * Imported Upstream version 17.0~beta7+dfsg1
+ See: https://kodi.tv/kodi-v17-krypton-the-last-beta-7/
+ * Refresh patches
+ * Use NotoSans-Regular font from fonts-noto-hinted package
+ * Imported Upstream version 17.0~rc2+dfsg1
+ See: https://kodi.tv/kodi-v17-krypton-release-candidate-1/
+ * Fix positioning of the "from debian" text next to KODI logo
+
+ -- Balint Reczey <balint@balintreczey.hu> Fri, 06 Jan 2017 18:39:14 +0100
+
+kodi (2:17.0~beta6+dfsg1-1) unstable; urgency=medium
+
+ * Drop new built-in webinterface addon from beta 6.
+ The addon contains many generated files without source. It will
+ be packaged separately.
+ * Imported Upstream version 17.0~beta6+dfsg1
+ * Refresh patches
+ * Revert the webinterface.default addon to old web interface from beta5
+ * Update lintian override about MediaLibrary.js to match new packaging
+ * Revert to using libcec 3.1 until libcec4 becomes available in Debian
+
+ -- Balint Reczey <balint@balintreczey.hu> Thu, 22 Dec 2016 02:00:46 +0100
+
+kodi (2:17.0~beta5+dfsg1-4) unstable; urgency=medium
+
+ * Stop using different epoch for transitional xbmc packages
+ * Use 2: epoch for kodi packages (Closes: #844541)
+ * Handle original tarballs properly when epoch is present in the package version
+
+ -- Balint Reczey <balint@balintreczey.hu> Thu, 17 Nov 2016 15:42:51 +0100
+
+kodi (17.0~beta5+dfsg1-3) unstable; urgency=medium
+
+ * Generate addon API versions for architecture-specific builds only
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 14 Nov 2016 16:37:40 +0100
+
+kodi (17.0~beta5+dfsg1-2) unstable; urgency=medium
+
+ [ Balint Reczey ]
+ * Stop providing xbmc-eventclients-j2me.
+ This was a transitional package originally, but Kodi stopped shipping
+ J2ME client. (Closes: #843169)
+ * Transition to depending on fonts-anonymous-pro.
+ Also accept ttf-anonymous-pro instead to support older releases
+ * Generate additional original source tarball names from current version
+ * Use more absolute paths in d/rules
+
+ [ Tobias Grimm ]
+ * Updated tarball versions in `debian/rules extract-components`
+ * Provide virtual packages for addon APIs and install a debhelper addon
+ to enable KODI addon packages to depend on these virtual packages.
+ * Standards-Version: 3.9.8
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 14 Nov 2016 11:32:17 +0100
+
+kodi (17.0~beta5+dfsg1-1) unstable; urgency=medium
+
+ [ Lukas Rechberger ]
+ * Make kodi depend on kodi-data of same version (Closes: #841937)
+
+ [ Balint Reczey ]
+ * Fix Kodi's FFmpeg API usage for allocating and freeing AVFrame
+ (Closes: #831591)
+ * New upstream beta release 17.0 Beta 5
+ See: https://kodi.tv/kodi-v17-krypton-beta-5/
+ * Refresh patches
+ * Run tests only for architecture dependent package builds
+ * Use Anonymous Pro font from ttf-anonymous-pro instead of from texlive-fonts-extra
+ (Closes: #842717)
+
+ -- Balint Reczey <balint@balintreczey.hu> Wed, 02 Nov 2016 21:53:39 +0100
+
+kodi (17.0~beta4+dfsg1-2) experimental; urgency=medium
+
+ * Generate version of xbmc transitional packages dynamically
+ (Closes: #842141)
+ * Check installed headers only during architecture-specific builds
+
+ -- Balint Reczey <balint@balintreczey.hu> Wed, 26 Oct 2016 13:37:42 +0200
+
+kodi (17.0~beta4+dfsg1-1) experimental; urgency=medium
+
+ * Ship additional headers referenced from already shipped ones
+ * Ensure all needed development headers are installed
+ * Use patches from libdvdread package
+ * Build-depend on libssh-gcrypt-dev instead of libssh-dev to avoid
+ transitive linking to libssl
+ * Build-depend on libgcrypt-dev instead of libssl-dev
+ * New upstream beta release 17.0 Beta 4
+ See: https://kodi.tv/kodi-v17-krypton-beta-4/
+ * Refresh patches
+ * Stop building with OpenSSL
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 10 Oct 2016 23:00:38 +0200
+
+kodi (17.0~beta3+dfsg1-1) experimental; urgency=medium
+
+ * New upstream beta release 17.0 Beta 3
+ See: https://kodi.tv/kodi-v17-krypton-beta-3/
+ * Refresh patches
+ * Use OpenGL ES and no VAAPI/VDAPU on arm64.
+ This fixes FTBFS on arm64
+ * Enable Google Tests on armel and mips, too.
+ The test results don't make the build fail anyway
+ * Build-depend on valgrind on amd64 and i386.
+ This makes tests use Valgrind on those popular and fast architectures
+ * Fix FTBFS on armel/armhf
+ * Properly set hardening options
+ * Re-enable TestSortUtils test
+ * Fix building tests
+ * Build-depend on default-libmysqlclient-dev to keep Lintian happy
+ * Adjust "from debian" logo placement
+
+ -- Balint Reczey <balint@balintreczey.hu> Fri, 07 Oct 2016 10:27:11 +0200
+
+kodi (17.0~beta2+dfsg1-1) experimental; urgency=medium
+
+ * New upstream beta release 17.0 Beta 2
+ See: https://kodi.tv/kodi-v17-krypton-beta-2/
+ * Drop build-depenency on libjasper-dev (Closes: 818201)
+ * Adjust packaging to new skin's font requirements.
+ Add dependency on fonts-lato and texlive-fonts-extra, drop
+ dependency on fonts-roboto-hinted, make symlinks to new
+ fonts instead of shipping them.
+ * Add transitional dummy packages from xbmc
+ * Drop obsoleted dependencies and patches
+ * Silence Lintian complaining for missing misc:Depends of transitional
+ packages
+ * Ignore failed clean of components without Lintian noticing
+ * Build-depend on liblcms2-dev for Little CMS support
+
+ -- Balint Reczey <balint@balintreczey.hu> Sat, 24 Sep 2016 14:57:31 +0200
+
+kodi (17.0~alpha3+dfsg1-1) experimental; urgency=medium
+
+ [ Lukas Rechberger ]
+ * Skip timestamps to make build reproducible (Closes: #825285)
+
+ [ Balint Reczey ]
+ * Build depend on groovy instead of groovy2 (Closes: #824187)
+ * Recommend kodi-visualization-spectrum
+ * New upstream alpha release 17.0 Alpha 2
+ See: https://kodi.tv/kodi-v17-krypton-alpha-2/
+ * Stop excluding paths from orig tarball which are already removed
+ * Refresh patches and changed paths in d/rules
+ * Fix FTBFS due to format string warnings
+ * Disable building DVDCSS
+ * Build-depend on libbluray-dev (>= 0.7.0) to match version required by ./configure
+ * Derive embedded libdvdnav and libdvdread from additional original tarballs
+ * Fix building with Google Test
+ * Ignore failing tests but run them with Valgrind when it is available
+ * Update d/copyright
+ * Add information about multiple orig tarballs
+ * New upstream alpha release 17.0 Alpha 3
+ See: https://kodi.tv/kodi-v17-krypton-alpha-3/
+ * Refresh patches
+ * Really revert patches to embedded dvdnav and dvdread copies in clean target
+ * Drop J2ME client support in sync with upstream
+ * Don't crash on missing version checker addon
+ * Position "from Debian" image better on new skin
+ * Drop symlinks to fonts used in the replaced skin
+
+ -- Balint Reczey <balint@balintreczey.hu> Fri, 05 Aug 2016 01:23:53 +0200
+
+kodi (16.1+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 16.1
+ See https://kodi.tv/kodi-16-1-jarvis-mark-xvi
+
+ -- Balint Reczey <balint@balintreczey.hu> Sun, 24 Apr 2016 15:51:42 +0200
+
+kodi (16.1~rc2+dfsg1-1) unstable; urgency=medium
+
+ * New upstream release candidate 16.1 RC2
+ See: https://kodi.tv/kodi-16-1-jarvis-release-candidate-2/
+ * Fix GetKernelBitness() on s390x to fix FTBFS on that arch
+ * Skip tests on armel and mips to prevent FTBFS
+ * Stop excluding files from upstream tarball which are already removed
+ upstream
+ * Don't modify GetVersionShort(), return package version in GetVersion()
+ instead
+
+ -- Balint Reczey <balint@balintreczey.hu> Tue, 29 Mar 2016 10:52:16 +0200
+
+kodi (16.0+dfsg1-3) unstable; urgency=medium
+
+ * Fix system info for s390x and arm64 architectures
+ * Skip tests failing on buildds to fix FTBFS on most ports
+ * Skip sorting test failing in the test code on armhf and armel
+
+ -- Balint Reczey <balint@balintreczey.hu> Fri, 25 Mar 2016 10:49:06 +0100
+
+kodi (16.0+dfsg1-2) unstable; urgency=medium
+
+ * Enable Google Tests at build-time
+ * Fix user agent string and related test
+ * Disable bindnow hardening option because it breaks playing DVDs
+
+ -- Balint Reczey <balint@balintreczey.hu> Tue, 15 Mar 2016 15:08:54 +0100
+
+kodi (16.0+dfsg1-1) unstable; urgency=medium
+
+ * New upstream version 16.0
+ See https://kodi.tv/kodi-16-0-jarvis-mark-xvi/
+ * Refresh patches
+ * Change build-dependency on libcec-platform-dev to libp8-platform-dev.
+ The library has been renamed
+ * Build-depend on libcec-dev (>= 3.1) which is built with p8-platform
+ * Stop shipping menu file
+ * Override false positive lintian warning about missing JavaScript source
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 22 Feb 2016 23:08:18 +0100
+
+kodi (16.0~rc3+dfsg2-1) experimental; urgency=medium
+
+ * New upstream release candidate 16.0 RC3
+ (Closes: #792299) (CVE-2015-3885)
+ See http://kodi.tv/kodi-16-0-jarvis-release-candidate-3/
+ * Refresh patches
+ * Don't use libcadec, wait for the codec to be included in FFmpeg instead
+ * Drop libhdhomerun-dev build dependency
+ * Add libcrossguid-dev and uuid-dev as build-dependencies
+ * Drop workarounds for screensavers dropped by upstream
+ * Use hinted Roboto fonts adapting to their new location in filesystem
+ * Enable PIE
+ * Make C-Pluff build with PIC only enabling PIE-enabled build to succeed
+ * Update debian/copyright for 16.0 RC3 changes
+
+ -- Balint Reczey <balint@balintreczey.hu> Sat, 13 Feb 2016 22:53:08 +0100
+
+kodi (15.2+dfsg1-3) unstable; urgency=medium
+
+ * Disable PIE due to build failure on amd64
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 25 Jan 2016 10:35:02 +0100
+
+kodi (15.2+dfsg1-2) unstable; urgency=medium
+
+ * Fix 03-privacy.patch to disable rss feed
+ * Disable debugging by default (Closes: #777041)
+ * Build-depend on fonts-droid-fallback instead of obsoleted fonts-droid
+ (Closes: #804695)
+ * Enable all hardening options during build
+ * Migrate to libpng-dev build-dependency (Closes: #810186)
+
+ -- Balint Reczey <balint@balintreczey.hu> Sun, 24 Jan 2016 10:55:08 +0100
+
+kodi (15.2+dfsg1-1) unstable; urgency=medium
+
+ [ Balint Reczey ]
+ * Skip handling migration to automatic debug packages when it is not supported by debhelper
+ * Update debian/watch to not skip part of oddly named versions
+ * New upstream release 15.2
+ See http://kodi.tv/kodi-15-2-isengard-final-release/
+
+ [ Andreas Cadhalpun ]
+ * Fix FTBFS with upcoming FFmpeg 2.9 release (Closes: #803831)
+
+ -- Balint Reczey <balint@balintreczey.hu> Fri, 06 Nov 2015 18:42:22 +0400
+
+kodi (15.2~rc3+dfsg1-1) unstable; urgency=medium
+
+ * New upstream release candidate 15.2 RC3
+ See http://kodi.tv/kodi-15-2-isengard-release-candidate-3
+
+ -- Balint Reczey <balint@balintreczey.hu> Tue, 06 Oct 2015 12:06:19 +0200
+
+kodi (15.2~rc1+dfsg1-2) unstable; urgency=medium
+
+ * Make Breaks/Replaces relation to xbmc packages versioned.
+ This lets dummy transition-only xbmc packages coexist with kodi.
+ Also remove Provides/Replaces relations remaining from xbmc packaging.
+ (Closes: #799823)
+ * Split architecture-indepedent data to kodi-data.
+ Only the kodi and kodi-standalone binaries are kept in kodi package which is
+ now Architecture:any since it contains the architecture-specific path to
+ kodi.bin. (Closes: #799979)
+
+ -- Balint Reczey <balint@balintreczey.hu> Sat, 26 Sep 2015 15:13:36 +0200
+
+kodi (15.2~rc1+dfsg1-1) unstable; urgency=medium
+
+ [ Balint Reczey ]
+ * Really fix s390x build
+ * Call ./configure through dh_auto_configure
+ * Convert to package to use multiarch library dirs
+ * Stop shipping kodi-dbg and disable debugging during build.
+ This is a preparation for the automatically generated debug packages
+ and switching to FFmpeg resulted less reported crashes to BTS.
+ Kodi-dbg packages used quite a big space on mirrors and weren't used
+ frequently.
+ * Make kodi-addons-dev Replaces/Breaks: kodi-bin (<= 15.1+dfsg1-3)
+ This is needed to manage moving .cmake files to to kodi-addons-dev.
+ * Migrate from kodi-dbg to ddebs properly.
+ Thanks to Mattia Rizzolo
+ * Make kodi-addons-dev Architecture: any
+ * Simplify debian/rules using exporting DH_OPTIONS
+ * New upstream release candidate 15.2 RC1
+ See http://kodi.tv/kodi-15-2-isengard-release-candidate-2/
+ * Refresh patches
+
+ [ Tobias Grimm ]
+ * Fixed file name of patches/09-use-correct-ftgl.h
+ * Install *.cmake files in kodi-addons-dev
+
+ [ Mattia Rizzolo ]
+ * debian/rules: correct use of `echo`
+
+ -- Balint Reczey <balint@balintreczey.hu> Mon, 21 Sep 2015 10:38:00 +0200
+
+kodi (15.1+dfsg1-3) unstable; urgency=medium
+
+ * Make configure more verbose when building on architecture not supported
+ by upstream
+ * Fix FTBFS on aarch64 (Closes: #796532)
+ * Don't use NEON on arm/armhf. (Closes: #797204)
+ * Fix build on s390x
+
+ -- Balint Reczey <balint@balintreczey.hu> Sun, 30 Aug 2015 10:20:07 +0200
+
+kodi (15.1+dfsg1-2) unstable; urgency=medium
+
+ * Don't stop configuration for unknown architectures
+ * Drop unknown ./configure options
+ * Continue configuration for unknown arches even further (Closes: #790635)
+ * Link with libatomic to fix FTBFS on powerpc and some other architectures
+ * Fix broken symlinks to DejaVuSans font files
+
+ -- Balint Reczey <balint@balintreczey.hu> Tue, 18 Aug 2015 23:51:14 +0200
+
+kodi (15.1+dfsg1-1) unstable; urgency=medium
+
+ * New upstream release 15.0
+ See http://www.kodi.tv/kodi-15-0-isengard-one-release-to-rule-them-all/
+ * Depend on libav.*-dev provided by src:ffmpeg
+ * Recommend udisks2 instead of udisks.
+ Udisks has been removed from unstable but support for udisks2 is not
+ implemented yet.
+ * Ship patch helping Jessie backports
+ * Refresh patches
+ * Eliminate __DATE__ macros from source to make build more reproducible
+ * Build-depend on libsdl2.*-dev instead of libsdl.*-dev
+ * Build-depend on libgif-dev
+ * Drop obsoleted fix of installed header's include paths
+ * Refresh include file list included by kodi-addons-dev
+ * Build depend on libcec (>= 3)
+ * Build-depend on groovy2 instead of groovy
+ * Sort build dependencies
+ * Fix packaging repository URL
+ * Remove removed files from debian/copyright
+ * Fix filenames with spaces in debian/copyright
+ * Ship TexturePacker in kodi-addons-dev in /usr/lib/kodi
+ * Build depend on libcec-platform-dev
+ * Stop using embedded gnulib modules in rsxs screensaver (Closes: #795813)
+ * Add missing copyright paragraphs to d/copyright
+ * Stop marking files as excluded which are removed from upstream tarball
+ already
+ * Bump standards version to 3.9.6
+ * New upstream release 15.1
+ See http://kodi.tv/kodi-15-1-isengard-maintenance-release/
+ * Move TexturePacker to kodi-bin
+ * Stop building TexturePacker statically
+
+ -- Balint Reczey <balint@balintreczey.hu> Tue, 18 Aug 2015 14:16:59 +0200
+
+kodi (14.2+dfsg1-2) unstable; urgency=medium
+
+ * Recommend udisks (Closes: #787293)
+
+ -- Balint Reczey <balint@balintreczey.hu> Thu, 04 Jun 2015 09:39:30 +0200
+
+kodi (14.2+dfsg1-1) experimental; urgency=medium
+
+ * Fix addon shared library naming on MIPS
+ * Drop non-machine-readable parts of debian/copyright
+ * Generate machine-readable debian/copyright for all files
+ * Clean up generated debian/copyright
+ * Remove non-free files in d/copyright
+ * Fix debian/watch file
+ * Update debian/copyright with new removals
+ * Drop get-orig-source target from d/rules.
+ Use uscan for generating repacked original tarball.
+ * Imported Upstream version 14.1+dfsg1
+ http://kodi.tv/kodi-14-1-helix-bugfix-release
+ * Copyright updates
+ * Use avformat_flush(), it is now exported by FFmpeg
+ * Stop using files omitted from DFSG-free tarballs
+ * Sort filenames omitted from original tarball
+ * Omit embedded Boost header from original tarball
+ * Download original tarball from GitHub
+ * Imported Upstream version 14.2+dfsg1
+ http://kodi.tv/kodi-14-2-helix-the-final-translation
+
+ -- Balint Reczey <balint@balintreczey.hu> Sat, 17 Jan 2015 00:30:36 +0100
+
+kodi (14.0+dfsg1-1) experimental; urgency=medium
+
+ * New upstream release 14.0 (CVE-2013-1438)
+ See http://kodi.tv/kodi-14-0-helix-unwinds
+ * Refresh patches
+ * Generate "from Debian" logo from SVG
+
+ -- Balint Reczey <balint@balintreczey.hu> Fri, 02 Jan 2015 13:19:52 +0100
+
+kodi (14.0~beta1+dfsg1-1) experimental; urgency=medium
+
+ * First packaged Kodi version based on xbmc 2:13.2+dfsg1-4
+ See http://kodi.tv/introducing-kodi-14 for the rationale behind the
+ name change (Closes: #767180)
+ * Use packaged FFmpeg
+ * Stop using internal ffmpeg functions
+ * Build-depend on libcec-dev >= 2.2
+ * Add upstream patches for fixing suspend and adding MIPS support
+
+ -- Balint Reczey <balint@balintreczey.hu> Sat, 08 Nov 2014 11:14:40 +0100
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..e6327fe
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,543 @@
+Source: kodi
+Priority: optional
+Section: video
+Maintainer: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org>
+Uploaders: Vasyl Gello <vasek.gello@gmail.com>
+Build-Depends: autoconf,
+ automake,
+ autopoint,
+ cmake,
+ curl,
+ debhelper-compat (= 13),
+ default-jre:native,
+ default-libmysqlclient-dev,
+ dh-python,
+ doxygen,
+ fontforge-nox,
+ fonts-dejavu-core,
+ fonts-droid-fallback,
+ gawk,
+ gettext,
+ gperf,
+ groovy:native,
+ libhowardhinnant-date-dev,
+ libasound2-dev | libasound-dev,
+ libass-dev,
+ libavahi-client-dev,
+ libavahi-common-dev,
+ libavcodec-dev (>= 7:4.2.2),
+ libavfilter-dev (>= 7:4.2.2),
+ libavformat-dev (>= 7:4.2.2),
+ libavutil-dev (>= 7:4.2.2),
+ libbluetooth-dev,
+ libbluray-dev (>= 1:0.7.0),
+ libcap-dev,
+ libcdio-dev,
+ libcec-dev (>= 4~),
+ libcommons-lang-java:native,
+ libcrossguid-dev,
+ libcurl4-gnutls-dev | libcurl-dev,
+ libcwiid-dev [linux-any],
+ libdav1d-dev (>= 0.7.0),
+ libdbus-1-dev,
+ libdrm-dev,
+# libdvdnav-dev, use patched embedded version
+# libdvdread-dev, use patched embedded version
+ libegl1-mesa-dev,
+ libflatbuffers-dev,
+ libfmt-dev (>= 6.1.2),
+ libfontconfig-dev,
+ libfreetype-dev | libfreetype6-dev,
+ libfribidi-dev,
+ libfstrcmp-dev,
+ libgbm-dev,
+ libgcrypt-dev,
+ libgif-dev,
+ libgif-dev:native,
+ libgl-dev,
+ libglew-dev,
+ libglu1-mesa-dev | libglu-dev,
+ libgnutls28-dev,
+ libgpg-error-dev,
+ libgtest-dev (>= 1.10.0~),
+ libinput-dev,
+ libiso9660-dev,
+ libiso9660++-dev,
+ libjpeg-dev,
+ libjpeg-dev:native,
+ libkissfft-dev (>= 131.1.0~),
+ liblcms2-dev,
+ liblirc-dev | liblircclient-dev,
+ libltdl-dev,
+ liblzo2-dev,
+ liblzo2-dev:native,
+ libmicrohttpd-dev,
+ libnfs-dev,
+ libomxil-bellagio-dev [armel],
+ libpcre2-dev,
+ libpipewire-0.3-dev,
+ libplist-dev,
+ libpng-dev,
+ libpng-dev:native,
+ libpostproc-dev (>= 7:4.2.2),
+ libpulse-dev,
+ libpython3-dev,
+ librsvg2-bin,
+ libshairplay-dev (>= 0.9.0~),
+ libsmbclient-dev,
+ libsndio-dev,
+ libspdlog-dev (>= 1:1.5.0),
+ libsqlite3-dev,
+ libswresample-dev (>= 7:4.2.2),
+ libswscale-dev (>= 7:4.2.2),
+ libtag1-dev (>= 1.8),
+ libtinyxml-dev,
+ libtool,
+ libudev-dev,
+ libudfread-dev (>= 1.0.0),
+ libva-dev,
+ libvdpau-dev,
+ libxkbcommon-dev,
+ libxrandr-dev,
+ libxslt1-dev,
+ libxt-dev,
+ nasm [i386],
+ python3-dev:any,
+ rapidjson-dev,
+ swig,
+ unzip,
+ uuid-dev,
+ valgrind [amd64 i386],
+ wayland-protocols,
+ waylandpp-dev,
+ zip,
+ zlib1g-dev
+Standards-Version: 4.6.2
+Rules-Requires-Root: no
+Vcs-Browser: https://salsa.debian.org/multimedia-team/kodi-media-center/kodi
+Vcs-Git: https://salsa.debian.org/multimedia-team/kodi-media-center/kodi.git -b debian/sid
+Homepage: https://kodi.tv/
+
+Package: kodi
+Architecture: any
+Depends: kodi-bin (>= ${source:Version}),
+ kodi-bin (<< ${source:Version}.1~),
+ kodi-data (>= ${source:Version}),
+ ${misc:Depends}
+Recommends: kodi-repository-kodi | kodi-repository,
+ kodi-visualization-spectrum
+Breaks: xbmc (<< 2:13.2+dfsg1-5~), ${kodi:APIBREAKS}
+Provides: ${kodi:APIPROVIDES}
+Replaces: xbmc (<< 2:13.2+dfsg1-5~)
+Description: Open Source Home Theatre (executable binaries)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package contains the kodi binaries.
+
+Package: kodi-data
+Architecture: all
+Multi-Arch: foreign
+Depends: mesa-utils,
+ x11-utils,
+ libjs-jquery,
+ libjs-iscroll,
+ ${misc:Depends}
+Recommends: fonts-noto-core,
+ fonts-noto-mono,
+ fonts-roboto-unhinted,
+Suggests: fonts-noto-ui-core,
+Breaks: xbmc (<< 2:13.2+dfsg1-5~)
+Replaces: xbmc (<< 2:13.2+dfsg1-5~)
+Description: Open Source Home Theatre (arch-independent data package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package contains all the architecture independent data needed to have a
+ working Kodi.
+
+Package: kodi-bin
+Architecture: any
+Depends: python3-pil,
+ python3-pycryptodome,
+ ${python3:Depends},
+ ${dlopenlibs:Depends},
+ ${shlibs:Depends},
+ ${misc:Depends},
+Recommends: ${shlibs:Recommends},
+ udisks2
+Pre-Depends: ${misc:Pre-Depends}
+Breaks: xbmc-bin (<< 2:13.2+dfsg1-5~)
+Conflicts: libgl1-mesa-swx11
+Replaces: xbmc-bin (<< 2:13.2+dfsg1-5~)
+Description: Open Source Home Theatre (architecture-dependent files)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package contains the binaries needed to have a working Kodi.
+
+Package: kodi-eventclients-common
+Architecture: all
+Multi-Arch: foreign
+Depends: ${misc:Depends}
+Description: Open Source Home Theatre (Event Client Common package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package is the common package for Kodi Event Client.
+
+Package: kodi-eventclients-python
+Architecture: any
+Depends: kodi-eventclients-common (= ${source:Version}),
+ python3-bluez,
+ ${python3:Depends},
+ ${misc:Depends}
+Breaks: kodi-eventclients-common (<< 2:19.4+dfsg1-1~)
+Replaces: kodi-eventclients-common (<< 2:19.4+dfsg1-1~)
+Description: Open Source Home Theatre (Event Client Python package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package is the virtual Python package for Kodi Event Client.
+
+Package: kodi-eventclients-dev-common
+Architecture: all
+Multi-Arch: foreign
+Section: libdevel
+Depends: ${misc:Depends}
+Breaks: kodi-eventclients-dev (<< 2:19.4+dfsg1-1~)
+Replaces: kodi-eventclients-dev (<< 2:19.4+dfsg1-1~)
+Description: Open Source Home Theatre (Event Client common dev package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This is the common development package for Kodi Event Client.
+
+Package: kodi-eventclients-dev
+Architecture: any
+Section: libdevel
+Depends: kodi-eventclients-dev-common (= ${source:Version}),
+ kodi-eventclients-python (= ${binary:Version}),
+ ${misc:Depends}
+Description: Open Source Home Theatre (Event Client virtual dev package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This is the virtual development package for Kodi Event Client.
+
+Package: kodi-eventclients-wiiremote
+Architecture: any
+Depends: kodi-eventclients-python (= ${binary:Version}),
+ ${python3:Depends},
+ ${shlibs:Depends},
+ ${misc:Depends}
+Description: Open Source Home Theatre (Event Client WII Remote support package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package is the Wii Remote client package for Kodi.
+
+Package: kodi-eventclients-ps3
+Architecture: any
+Depends: kodi-eventclients-python (= ${binary:Version}),
+ python3-pyudev,
+ python3-usb,
+ ${python3:Depends},
+ ${misc:Depends}
+Breaks: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~)
+Replaces: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~)
+Description: Open Source Home Theatre (Event Client PS3 package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package is the PS3 package for Kodi Event Client.
+
+Package: kodi-eventclients-kodi-send
+Architecture: any
+Depends: kodi-eventclients-python (= ${binary:Version}),
+ ${python3:Depends},
+ ${misc:Depends}
+Description: Open Source Home Theatre (Event Client Kodi-SEND package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package is the Kodi-SEND package for Kodi Event Client.
+
+Package: kodi-eventclients-zeroconf
+Architecture: any
+Depends: kodi-eventclients-python (= ${binary:Version}),
+ python3-avahi,
+ python3-dbus,
+ python3-gi,
+ ${python3:Depends},
+ ${misc:Depends}
+Breaks: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~)
+Replaces: kodi-eventclients-common (<< 2:19.0~alpha3+dfsg1-1~)
+Description: Open Source Home Theatre (Event Client ZeroConf script package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package is the ZeroConf script for Kodi Event Client.
+
+Package: kodi-addons-dev-common
+Architecture: all
+Multi-Arch: foreign
+Section: libdevel
+Depends: ${misc:Depends}
+Breaks: kodi-addons-dev (<< 2:19.4+dfsg1-1~)
+Replaces: kodi-addons-dev (<< 2:19.4+dfsg1-1~)
+Description: Open Source Home Theatre (architecture-independent addon development package)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This is the development package for Kodi Addons.
+ .
+ This package contains independent headers for building addons without the need
+ to keep a whole Kodi source tree.
+
+Package: kodi-addons-dev
+Section: libdevel
+Architecture: any
+Multi-Arch: same
+Provides: dh-sequence-kodiaddon (= ${binary:Version})
+Depends: kodi-addons-dev-common (= ${source:Version}),
+ ${misc:Depends}
+Breaks: kodi-addons-dev-common (<< 2:20.0~rc1+dfsg1-1~)
+Replaces: kodi-addons-dev-common (<< 2:20.0~rc1+dfsg1-1~)
+Description: Open Source Home Theatre (addon development package)
+ This package is a dummy package used in conjunction with kodi-addons-dev
+ to detect if a binary addon should be built for given Debian architecture.
+ .
+ The alternative to introducing this package is marking kodi-addons-dev back
+ as arch:any, but this makes Lintian and multi-arch hinter noisy.
+ .
+ If Kodi upstream starts shipping architecture-specific development libraries
+ again, they will land in this package.
+
+Package: kodi-repository-kodi
+Architecture: all
+Multi-Arch: foreign
+Depends: ${misc:Depends}
+Enhances: kodi
+Breaks: kodi-data (<< 2:17.3+dfsg1-5~),
+ xbmc (<< 2:13.2+dfsg1-5~)
+Conflicts: kodi-repository
+Provides: kodi-repository
+Replaces: kodi-repository,
+ kodi-data (<< 2:17.3+dfsg1-5~),
+ xbmc (<< 2:13.2+dfsg1-5~)
+Description: Open Source Home Theatre (official addons repository feed)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package enables download of addons via the official Kodi
+ repository feed.
+
+Package: kodi-tools-texturepacker
+Architecture: any
+Depends: ${shlibs:Depends},
+ ${misc:Depends}
+Breaks: kodi-bin (<< 2:19.4+dfsg1-1~)
+Replaces: kodi-bin (<< 2:19.4+dfsg1-1~)
+Description: Open Source Home Theatre (TexturePacker skin development tool)
+ Kodi, formerly known as XBMC is an award winning free and
+ open source software media-player and entertainment hub for all your digital
+ media. Kodi is available for Linux, Mac OS X (Leopard, Tiger and Apple TV)
+ and Microsoft Windows, as well as the original Xbox game console. Created in
+ 2003 by a group of like minded programmers, Kodi is a non-profit project run
+ and developed by volunteers located around the world. More than 50 software
+ developers have contributed to Kodi, and 100-plus translators have worked to
+ expand its reach, making it available in more than 30 languages.
+ .
+ While Kodi functions very well as a standard media player application for
+ your computer, it has been designed to be the perfect companion for your
+ HTPC. Supporting an almost endless range of remote controls, and combined
+ with its beautiful interface and powerful skinning engine, Kodi feels very
+ natural to use from the couch and is the ideal solution for your home
+ theater. Once installed, your computer will become a fully functional
+ multimedia jukebox.
+ .
+ This package contains TexturePacker, the tool for Kodi skin developers.
+ End users don't need this package to run Kodi.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..adf4c04
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,1693 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: Kodi
+Source: http://kodi.tv/
+Files-Excluded: .github
+ addons/service.xbmc.versioncheck
+ addons/skin.estuary/fonts/*.ttf
+ addons/skin.estouchy/fonts/*.ttf
+ addons/webinterface.default
+ lib/libUPnP/Neptune/ThirdParty/zlib-*
+ lib/libUPnP/Platinum/Build/Targets/mipsel-psp-linux
+ lib/libUPnP/Platinum/Build/Targets/x86-microsoft-win32-vs2010
+ lib/libUPnP/Platinum/ThirdParty/log4net
+ lib/win32
+ media/Fonts/arial.ttf
+ project/BuildDependencies
+ project/Win32BuildSetup
+ system/certs
+ tools/android
+ tools/codegenerator/groovy
+ tools/darwin
+ tools/depends/target
+ tools/EventClients/Clients/OSXRemote
+ tools/windows
+ xbmc/platform/android
+ xbmc/platform/darwin
+ xbmc/platform/win10
+ xbmc/platform/win32
+Files-Included: tools/depends/target/*-VERSION
+Files-Excluded-repo-resources-embedded: .github
+ *
+Files-Included-repo-resources-embedded: resource.language.*
+
+Files: *
+Copyright:
+ 2005-2023, Team Kodi <http://kodi.tv/>
+ the authors of ffmpeg and xvid
+ the authors of libPlatinum <http://www.plutinosoft.com/blog/category/platinum/>
+ 1997-2009, Sam Lantinga <slouken@libsdl.org>
+ 2000-2004, Convergence (integrated media) GmbH
+ 2001-2009, The world wide DirectFB Open Source Community <http://directfb.org/>
+ 2002, Albert Griscti-Soler (RUNTiME)
+ 2002, Phil Burr (d7o3g4q)
+ 2002,2007, Erwin Beckers (Frodo)
+ 2003, The Joker / Avalaunch team
+ 2003-2017, Team XBMC <http://xbmc.org/>
+ 2003,2006-2007, Ralf Baechle <ralf@linux-mips.org>
+ 2005, Free Software Foundation, Inc.
+ 2006, Joakim Plate (elupus)
+ 2006, Sylvain Rebaud (c0diq)
+ 2007, Jonathan Marshall (jcmarshall)
+ 2007, Roee Vulkan (vulkanr)
+ 2007-2008, Anoop Menon (d4rk)
+ 2007-2008, Eric Steil III
+ 2007,2011, Tobias Arrskog (topfs) <https://github.com/topfs2>
+ 2008, University Heidelberg
+ 2008, Wladimir J. van der Laan
+ 2010, Team Boxee <http://www.boxee.tv/>
+ 2012, Denis Yantarev
+ 2015-2016, Lauri Mylläri
+ 2016-2018, Chris Browet
+ 2016, 2017, Tobias Kortkamp <t@tobik.me>
+ 2018, Tyler Szabo
+License-Grant:
+ This Program 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, or (at your option) any later version.
+License: GPL-2+
+Comment:
+ Copyright holders "Team XboxMediaCenter" and "Team XBMC" assumed
+ to be equal to "Team Kodi".
+
+Files: addons/skin.estouchy/*
+Copyright: Team Kodi <http://kodi.tv/>
+License-Grant:
+ This work is licensed
+ under the Creative Commons Attribution-Share Alike 3.0 United States
+ License.
+License: CC-BY-SA-3.0~us
+Comment:
+ Copyright information missing from source files.
+ Copyright holder assumed to be main project author.
+ License assumed from license grant
+ located in <addons/skin.estouchy/LICENSE.txt>.
+
+Files: addons/skin.estuary/*
+Copyright: phil65 & Piers (Team Kodi)
+License-Grant:
+ Estuary code work is licensed
+ under GNU General Public License (GPL), Version 2.0
+License: GPL-2
+
+Files: addons/skin.estuary/*.jpg
+ addons/skin.estuary/*.png
+Copyright: phil65 & Piers (Team Kodi)
+License-Grant:
+ Estuary Artwork is licensed
+ under a Creative Commons Attribution-ShareAlike 4.0 Unported License.
+License: CC-BY-SA-4.0
+
+Files: addons/skin.estuary/extras/home-images/movie.jpg
+ addons/skin.estuary/extras/home-images/music.jpg
+Copyright: UNKNOWN
+License-Grant:
+ movie.jpg: https://creativecommons.org/publicdomain/zero/1.0/legalcode
+ music.jpg: https://creativecommons.org/publicdomain/zero/1.0/legalcode
+License: CC0-1.0
+Comment:
+ Missing copyright and licensing information in source file.
+ License assumed from license grant
+ located in addons/skin.estuary/extras/home-images/LICENSE.
+
+Files: addons/skin.estuary/media/windows/subtitles/flags/*
+Copyright: 2013, Go Squared Ltd. <http:www.gosquared.com/>
+License: Expat
+Comment:
+ Copyright and license assumed from
+ <addons/skin.estuary/media/windows/subtitles/flags/LICENSE.txt>.
+
+Files: cmake/modules/extra/ECMEnableSanitizers.cmake
+ cmake/modules/FindLibXml2.cmake
+Copyright:
+ 2006, Alexander Neundorf <neundorf@kde.org>
+ 2006-2009, Kitware, Inc.
+ 2014, Mathieu Tarral <mathieu.tarral@gmail.com>
+ 2016, Team Kodi <http://kodi.tv/>
+License-Grant:
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+License: BSD-3-clause
+Comment:
+ License grant ambiguous regarding exact BSD license.
+ License assumed to be the same as clarified
+ in CMake project commit 86578ec:
+ <https://github.com/Kitware/CMake/commit/86578eccf2e82286248796bad1032cd0e3a5e1e2>.
+
+Files: lib/libUPnP/Neptune/*
+Copyright: 2002-2012, Axiomatic Systems, LLC
+License: BSD-3-clause~Axiomatic
+
+Files: lib/libUPnP/Neptune/Source/Apps/*
+ lib/libUPnP/Neptune/Source/System/*
+ lib/libUPnP/Neptune/Source/Tests/*
+Copyright:
+ 2001-2014, Gilles Boccon-Gibod <bok@bok.net>
+ 2005-2010, Axiomatic Systems, LLC.
+License: BSD-3-clause~Axiomatic
+Comment:
+ Licensing information missing from source files.
+ License assumed from <lib/libUPnP/Neptune/LICENSE>,
+ and from Gilles Boccon-Gibod being former president for Axiomatic
+ according to
+ <https://www.corporationwiki.com/California/Los-Altos/gilles-boccon-gibod/43430379.aspx>
+
+Files: lib/libUPnP/Neptune/ThirdParty/axTLS/*
+Copyright: 2007, Cameron Rich
+License: BSD-3-clause~axTLS
+
+Files: lib/libUPnP/Platinum/*
+Copyright: 2004-2012, Plutinosoft, LLC
+License-Grant:
+ This program 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.
+License: GPL-2+
+Comment:
+ Licensing information missing from some source files:
+ <lib/libUPnP/Platinum/Source/Platform/Android/module/platinum/jni/platinum-jni.cpp>
+ <lib/libUPnP/Platinum/Source/Tests/MediaServerCocoaTest/main.mm>
+ License assumed to be same as related files
+ with same copyright holder.
+
+Files: lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltMediaServerObject.h
+ lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltMediaServerObject.mm
+ lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltUPnPObject.h
+ lib/libUPnP/Platinum/Source/Extras/ObjectiveC/PltUPnPObject.mm
+ lib/libUPnP/Platinum/Source/Tests/MediaServerCocoaTest/MediaServerCocoaTestController.h
+ lib/libUPnP/Platinum/Source/Tests/MediaServerCocoaTest/MediaServerCocoaTestController.mm
+Copyright: 2010-2011, Plutinosoft LLC
+License: GPL-2+
+Comment:
+ Licensing information missing from source files.
+ License assumed to be same as generally for same copyright holder.
+
+Files: libdvdnav-embedded/*
+Copyright: 2000-2001, Björn Englund
+ 2006-2007, Diego Pettenò <flameeyes@gmail.com>
+ 1989-1991, Free Software Foundation, Inc
+ 2000-2001, Håkan Hjort
+ 2000-2001, Martin Norbäck
+ 2000-2004, Rich Wareham <richwareham@users.sourceforge.net>
+ 2001-2004, the libdvdnav project
+ 2000-2007, the xine project
+ 2001-2023, The‌ VideoLAN Project
+License: GPL-2+
+
+Files: libdvdread-embedded/*
+Copyright: Apache Software Foundation
+ 2000-2004, Billy Biggs <vektor@dumbterm.net>
+ 2000-2003, Björn Englund <d4bjorn@dtek.chalmers.se>
+ 1999-2001, Christian Wolff <scarabaeus@convergence.de>
+ 2006-2007, Diego Pettenò <flameeyes@gmail.com>
+ 1989-1991, Free Software Foundation, Inc
+ 2000-2003, Håkan Hjort <d95hjort@dtek.chalmers.se>
+ 1997, Kevlin Henney
+ 2001, Rich Wareham <richwareham@users.sourceforge.net>
+ 2001-2002, Samuel Hocevar <sam@zoy.org>
+ 2000-2007, the xine project
+ 2000-2023, The VideoLAN Project
+License: GPL-2+
+
+Files: libdvdread-embedded/src/dvdread/version.h.in
+ libdvdread-embedded/src/md5.c
+ libdvdread-embedded/src/md5.h
+Copyright: 1995-2003, Free Software Foundation, Inc
+ 2004-2015, VLC authors and VideoLAN
+License: LGPL-2.1+
+
+Files: libdvdread-embedded/src/dvdread/nav_types.h
+ libdvdread-embedded/src/nav_print.c
+Copyright: 1998-1999, Eric Smith <eric@brouhaha.com>
+ 2000-2003, Håkan Hjort <d95hjort@dtek.chalmers.se>
+License: GPL-2 or GPL-3
+
+Files: repo-resources-embedded/*
+Copyright: 2005-2023, Team Kodi
+License: GPL-2+
+Comment: Translations are maintained via Kodi project on Weblate.
+
+Files: system/players/VideoPlayer/etc/fonts/conf.avail/65-fonts-persian.conf
+ system/players/VideoPlayer/etc/fonts/conf.d/65-fonts-persian.conf
+Copyright: 2005, Sharif FarsiWeb, Inc. <license@farsiweb.info>
+License: NTP~disclaimer~FarsiWeb
+
+Files: tools/depends/build-aux/config.guess
+ tools/depends/build-aux/config.sub
+Copyright: 1992-2016, Free Software Foundation, Inc.
+License-Grant:
+ This file 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 3 of the License, or (at your option) any later version.
+License: GPL-3+ with Autoconf exception
+ As a special exception to the GNU General Public License,
+ if you distribute this file as part of a program
+ that contains a configuration script generated by Autoconf,
+ you may include it under the same distribution terms
+ that you use for the rest of that program.
+ This Exception is an additional permission
+ under section 7 of the GNU General Public License, version 3 ("GPLv3").
+
+Files: tools/depends/build-aux/install-sh
+Copyright: 1994, X Consortium
+License: X11
+Comment: FSF changes to this file are in the public domain.
+
+Files: tools/depends/native/TexturePacker/src/Win32/dirent.c
+ tools/depends/native/TexturePacker/src/Win32/dirent.h
+Copyright: 1997,2003, Kevlin Henney <kevlin@acm.org>, <kevlin@curbralan.com>
+License: ISC~minimal-disclaimer
+
+Files: tools/depends/native/TexturePacker/src/md5.cpp
+ tools/depends/native/TexturePacker/src/md5.h
+Copyright: None (in the public domain)
+License: public-domain
+ This code was written by Colin Plumb in 1993, no copyright is claimed.
+ This code is in the public domain; do with it what you wish.
+
+Files: tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.cpp
+ tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.h
+Copyright: 2009, Cory Fields
+License-Grant:
+ This program 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 3 of the License, or (at your option) any later version.
+License: GPL-3+
+
+Files: tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/*
+Copyright: 2006-2007, Michael Laforest (para) <thepara@gmail.com>
+License-Grant:
+ This program 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 3 of the License, or (at your option) any later version.
+License: GPL-3+
+
+Files: tools/EventClients/icons/bluetooth.png
+Copyright: 2003, Jakub Steiner (jimmac) <http://jimmac.musichall.cz/>
+License: GPL-2+
+Comment:
+ Licensing information missing from source file.
+ I've asked upstream to clarify the license
+ https://github.com/xbmc/xbmc/issues/17252
+
+Files: xbmc/addons/AudioDecoder.cpp
+ xbmc/addons/AudioDecoder.h
+Copyright: 2013, 2014 Arne Morten Kvarving (cptspiff)
+License-Grant:
+ This Program 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, or (at your option) any later version.
+License: GPL-2+
+
+Files: xbmc/addons/VFSEntry.cpp
+ xbmc/addons/VFSEntry.h
+Copyright: 2013, 2014 Arne Morten Kvarving (cptspiff)
+License-Grant:
+ This Program 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, or (at your option) any later version.
+License: GPL-2+
+
+Files: xbmc/contrib/kissfft/*
+Copyright: 2003-2010, Mark Borgerding
+License: BSD-3-clause
+
+Files: xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp
+ xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp
+ xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h
+ xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp
+ xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h
+ xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp
+ xbmc/guilib/StereoscopicsManager.cpp
+ xbmc/guilib/StereoscopicsManager.h
+ xbmc/platform/linux/sse4/CopyFrame.cpp
+ xbmc/utils/ActorProtocol.cpp
+ xbmc/utils/ActorProtocol.h
+Copyright:
+ 2005-2015, Team Kodi <http://kodi.tv/>
+ 2005-2016, Team XBMC <http://xbmc.org/>
+License-Grant:
+ This library is free software;
+ you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation;
+ either version 2.1 of the License,
+ or (at your option) any later version.
+License: LGPL-2.1+
+
+Files: xbmc/cores/VideoPlayer/DVDCodecs/Overlay/contrib/cc_decoder.c
+ xbmc/cores/VideoPlayer/DVDCodecs/Overlay/contrib/cc_decoder.h
+Copyright:
+ 2000-2008, the xine project
+ 2001, Christian Vogler <cvogler@gradient.cis.upenn.edu>
+License-Grant:
+ xine 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.
+License: GPL-2+
+
+Files: xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h
+ xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h
+Copyright:
+ 2001, Håkan Hjort <d95hjort@dtek.chalmers.se>
+ 2001, Martin Norbäck
+ 2001-2004, Rich Wareham <richwareham@users.sourceforge.net>
+License-Grant:
+ libdvdnav 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.
+License: GPL-2+
+
+Files: xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h
+ xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h
+ xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h
+Copyright:
+ 2000-2002, Håkan Hjort <d95hjort@dtek.chalmers.se>
+ 2001, Rich Wareham <richwareham@users.sourceforge.net>
+ 2001-2002, Billy Biggs <vektor@dumbterm.net>
+ 2001-2002, Björn Englund <d4bjorn@dtek.chalmers.se>
+License-Grant:
+ libdvdread 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.
+License: GPL-2+
+Comment:
+ Copyright information missing from one source file:
+ <xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/remap.h>.
+ Copyright assumed to be same as (or a subset of) that of other files
+ with identical license grant.
+
+Files: xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h
+Copyright:
+ 1998-1999, Eric Smith <eric@brouhaha.com>
+ 2000-2002, Håkan Hjort <d95hjort@dtek.chalmers.se>
+License-Grant:
+ VOBDUMP is free software;
+ you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ Note that I am not granting permission
+ to redistribute or modify VOBDUMP
+ under the terms of any later version of the General Public License.
+License: GPL-2
+
+Files: xbmc/dbwrappers/dataset.cpp
+ xbmc/dbwrappers/dataset.h
+ xbmc/dbwrappers/qry_dat.cpp
+ xbmc/dbwrappers/qry_dat.h
+ xbmc/dbwrappers/sqlitedataset.cpp
+ xbmc/dbwrappers/sqlitedataset.h
+Copyright: 2002,2004, Leo Seib, Hannover <leoseib@web.de>
+License: Expat
+
+Files: xbmc/filesystem/NptXbmcFile.cpp
+Copyright: 2002-2008, Axiomatic Systems, LLC
+License: BSD-3-clause~Axiomatic
+
+Files: xbmc/input/XBMC_keyboard.h
+ xbmc/input/XBMC_keysym.h
+ xbmc/input/XBMC_vkeys.h
+Copyright: 1997-2009, Sam Lantinga <slouken@libsdl.org>
+License-Grant:
+ This library is free software;
+ you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation;
+ either version 2.1 of the License,
+ or (at your option) any later version.
+License: LGPL-2.1+
+
+Files: xbmc/network/AirPlayServer.cpp
+ xbmc/network/AirPlayServer.h
+ xbmc/network/AirTunesServer.cpp
+Copyright: 2011-2013, Team XBMC <http://xbmc.org/>
+License-Grant:
+ This Program 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.1, or (at your option) any later version.
+License: GPL-2+
+
+Files: xbmc/utils/BitstreamConverter.cpp
+ xbmc/utils/BitstreamConverter.h
+Copyright:
+ 2005, Michal Benes <michal.benes@itonis.tv>
+ 2006, Baptiste Coudurier <baptiste.coudurier@smartjog.com>
+ 2007, Benoit Fouet <benoit.fouet@free.fr>
+ 2008, Wim Taymans <wim.taymans@gmail.com>
+ 2010-2015, Team XBMC <http://xbmc.org/>
+License: GPL-2+
+
+Files: xbmc/utils/HttpParser.cpp
+ xbmc/utils/HttpParser.h
+Copyright: 2011-2013, Team XBMC <http://xbmc.org/>
+License-Grant:
+ This Program 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.
+License: GPL-2+ and public-domain
+ This code was written by Steve Hanov in 2009, no copyright is claimed.
+ This code is in the public domain.
+
+Files: xbmc/utils/StringUtils.cpp
+Copyright:
+ 2005-2013, Team XBMC <http://xbmc.org/>
+ 2012, Leigh Brasington
+License-Grant:
+ This Program 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, or (at your option) any later version.
+License: GPL-2+
+Comment: Also contains license for included snippet:
+ This code may be used and reproduced without written permission.
+ <http://www.leighb.com/tounicupper.htm>
+
+Files: xbmc-xrandr.c
+Copyright:
+ 2001, Keith Packard, member of The XFree86 Project, Inc.
+ 2002, Hewlett Packard Company, Inc.
+ 2006, Intel Corporation
+License: NTP~disclaimer
+
+Files: debian/*
+Copyright:
+ 2008-2009, Ouattara Oumar Aziz <wattazoum@gmail.com>
+ 2012-2013, Andres Mejia <amejia@debian.org>
+ 2014-2015, Balint Reczey <balint@balintreczey.hu>
+ 2020-2023, Vasyl Gello <vasek.gello@gmail.com>
+License-Grant:
+ This program 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;
+ version 2 dated June, 1991, or (at your option) any later version.
+License: GPL-2+
+
+Files: debian/extra/arial.ttf
+Copyright: Copyright © 2006, 2007, 2008, 2009, 2010 Google Corp.
+ Droid is a trademark of Google Corp.
+ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+ Bitstream Vera is a trademark of Bitstream, Inc.
+ DejaVu changes are in public domain.
+License: GPL-3+
+Comment: The file is merged from Apache-2-licensed
+ /usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf
+ and /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf , which is licensed
+ under the following license:
+ .
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of the fonts accompanying this license ("Fonts") and associated
+ documentation files (the "Font Software"), to reproduce and distribute the
+ Font Software, including without limitation the rights to use, copy, merge,
+ publish, distribute, and/or sell copies of the Font Software, and to permit
+ persons to whom the Font Software is furnished to do so, subject to the
+ following conditions:
+ .
+ The above copyright and trademark notices and this permission notice shall
+ be included in all copies of one or more of the Font Software typefaces.
+ .
+ The Font Software may be modified, altered, or added to, and in particular
+ the designs of glyphs or characters in the Fonts may be modified and
+ additional glyphs or characters may be added to the Fonts, only if the fonts
+ are renamed to names not containing either the words "Bitstream" or the word
+ "Vera".
+ .
+ This License becomes null and void to the extent applicable to Fonts or Font
+ Software that has been modified and is distributed under the "Bitstream
+ Vera" names.
+ .
+ The Font Software may be sold as part of a larger software package but no
+ copy of one or more of the Font Software typefaces may be sold by itself.
+ .
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+ TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+ FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
+ ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
+ FONT SOFTWARE.
+ .
+ Except as contained in this notice, the names of Gnome, the Gnome
+ Foundation, and Bitstream Inc., shall not be used in advertising or
+ otherwise to promote the sale, use or other dealings in this Font Software
+ without prior written authorization from the Gnome Foundation or Bitstream
+ Inc., respectively. For further information, contact: fonts at gnome dot
+ org.
+ .
+ .
+ I'm adding the result named arial.ttf under GPL-3+ because this is allowed
+ by the licenses of the original fonts.
+
+Files: debian/from-debian-logo.svg
+Copyright:
+ 1999, Software in the Public Interest, Inc.
+ 2015, Balint Reczey <balint@balintreczey.hu>
+License-Grant:
+ This package is free software;
+ you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation;
+ either version 3 of the License, or (at your option) any later version.
+License: LGPL-3+
+
+License: BSD-3-clause
+ Redistribution and use in source and binary forms,
+ with or without modification,
+ are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain
+ the above copyright notice, this list of conditions
+ and the following disclaimer.
+ * Redistributions in binary form must reproduce
+ the above copyright notice, this list of conditions
+ and the following disclaimer
+ in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the author
+ nor the names of any contributors
+ may be used to endorse or promote
+ products derived from this software
+ without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED
+ BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Files: debian/webinterface-default/*
+Copyright:
+ 2005-2021, Team Kodi <http://kodi.tv/>
+License-Grant:
+ 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.
+Comment: The default webinterface was imported from Kodi 17.1 as
+ component tarball and later moved inside the debian patch in 19.0.
+ See debian/README.source for more information.
+License: GPL-2+
+
+License: BSD-3-clause~Axiomatic
+ Redistribution and use in source and binary forms,
+ with or without modification,
+ are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain
+ the above copyright notice, this list of conditions
+ and the following disclaimer.
+ * Redistributions in binary form must reproduce
+ the above copyright notice, this list of conditions
+ and the following disclaimer
+ in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of Axiomatic Systems
+ nor the names of its contributors
+ may be used to endorse or promote
+ products derived from this software
+ without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.
+ IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: BSD-3-clause~axTLS
+ Redistribution and use in source and binary forms,
+ with or without modification,
+ are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain
+ the above copyright notice, this list of conditions
+ and the following disclaimer.
+ * Redistributions in binary form must reproduce
+ the above copyright notice, this list of conditions
+ and the following disclaimer
+ in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the axTLS project
+ nor the names of its contributors
+ may be used to endorse or promote
+ products derived from this software
+ without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED
+ BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: CC0-1.0
+ To the extent possible under law, the author(s) have dedicated all
+ copyright and related and neighboring rights to this software to the public
+ domain worldwide. This software is distributed without any warranty.
+ .
+ On Debian systems, the complete text of the CC0 license, version 1.0,
+ can be found in /usr/share/common-licenses/CC0-1.0.
+
+License: CC-BY-SA-3.0~us
+ THE WORK (AS DEFINED BELOW) IS PROVIDED
+ UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE
+ ("CCPL" OR "LICENSE").
+ THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.
+ ANY USE OF THE WORK OTHER THAN AS AUTHORIZED
+ UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+ .
+ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE,
+ YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE.
+ TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT,
+ THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE
+ IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
+ .
+ 1. Definitions
+ .
+ a. "Collective Work" means a work,
+ such as a periodical issue, anthology or encyclopedia,
+ in which the Work in its entirety in unmodified form,
+ along with one or more other contributions,
+ constituting separate and independent works in themselves,
+ are assembled into a collective whole.
+ A work that constitutes a Collective Work will not be considered
+ a Derivative Work (as defined below)
+ for the purposes of this License.
+ b. "Creative Commons Compatible License" means a license
+ that is listed at <https://creativecommons.org/compatiblelicenses>
+ that has been approved by Creative Commons
+ as being essentially equivalent to this License,
+ including, at a minimum,
+ because that license: (i) contains terms
+ that have the same purpose, meaning and effect
+ as the License Elements of this License;
+ and, (ii) explicitly permits the relicensing
+ of derivatives of works made available under that license
+ under this License or either a Creative Commons unported license
+ or a Creative Commons jurisdiction license
+ with the same License Elements as this License.
+ c. "Derivative Work" means a work
+ based upon the Work or upon the Work and other pre-existing works,
+ such as a translation, musical arrangement, dramatization,
+ fictionalization, motion picture version, sound recording,
+ art reproduction, abridgment, condensation,
+ or any other form
+ in which the Work may be recast, transformed, or adapted,
+ except that a work that constitutes a Collective Work
+ will not be considered a Derivative Work
+ for the purpose of this License.
+ For the avoidance of doubt,
+ where the Work is a musical composition or sound recording,
+ the synchronization of the Work
+ in timed-relation with a moving image ("synching")
+ will be considered a Derivative Work
+ for the purpose of this License.
+ d. "License Elements" means the following
+ high-level license attributes
+ as selected by Licensor
+ and indicated in the title of this License:
+ Attribution, ShareAlike.
+ e. "Licensor" means the individual, individuals, entity or entities
+ that offers the Work under the terms of this License.
+ f. "Original Author" means the individual, individuals,
+ entity or entities
+ who created the Work.
+ g. "Work" means the copyrightable work of authorship
+ offered under the terms of this License.
+ h. "You" means an individual or entity
+ exercising rights under this License
+ who has not previously violated the terms of this License
+ with respect to the Work,
+ or who has received express permission from the Licensor
+ to exercise rights under this License
+ despite a previous violation.
+ .
+ 2. Fair Use Rights.
+ Nothing in this license is intended
+ to reduce, limit, or restrict any rights
+ arising from fair use, first sale or other limitations
+ on the exclusive rights of the copyright owner
+ under copyright law or other applicable laws.
+ .
+ 3. License Grant.
+ Subject to the terms and conditions of this License,
+ Licensor hereby grants You
+ a worldwide, royalty-free, non-exclusive, perpetual
+ (for the duration of the applicable copyright)
+ license to exercise the rights in the Work
+ as stated below:
+ .
+ a. to reproduce the Work,
+ to incorporate the Work into one or more Collective Works,
+ and to reproduce the Work
+ as incorporated in the Collective Works;
+ b. to create and reproduce Derivative Works
+ provided that any such Derivative Work,
+ including any translation in any medium,
+ takes reasonable steps to clearly label, demarcate
+ or otherwise identify
+ that changes were made to the original Work.
+ For example, a translation could be marked
+ "The original work was translated from English to Spanish,"
+ or a modification could indicate
+ "The original work has been modified.";
+ c. to distribute copies or phonorecords of,
+ display publicly, perform publicly,
+ and perform publicly by means of a digital audio transmission
+ the Work
+ including as incorporated in Collective Works;
+ d. to distribute copies or phonorecords of,
+ display publicly, perform publicly,
+ and perform publicly by means of a digital audio transmission
+ Derivative Works.
+ e. For the avoidance of doubt,
+ where the Work is a musical composition:
+ i. Performance Royalties Under Blanket Licenses.
+ Licensor waives the exclusive right to collect,
+ whether individually or,
+ in the event that Licensor is a member
+ of a performance rights society
+ (e.g. ASCAP, BMI, SESAC),
+ via that society,
+ royalties for the public performance
+ or public digital performance (e.g. webcast)
+ of the Work.
+ ii. Mechanical Rights and Statutory Royalties.
+ Licensor waives the exclusive right to collect,
+ whether individually or via a music rights agency
+ or designated agent (e.g. Harry Fox Agency),
+ royalties for any phonorecord You create from the Work
+ ("cover version")
+ and distribute,
+ subject to the compulsory license
+ created by 17 USC Section 115 of the US Copyright Act
+ (or the equivalent in other jurisdictions).
+ f. Webcasting Rights and Statutory Royalties.
+ For the avoidance of doubt,
+ where the Work is a sound recording,
+ Licensor waives the exclusive right to collect,
+ whether individually
+ or via a performance-rights society (e.g. SoundExchange),
+ royalties for the public digital performance (e.g. webcast)
+ of the Work,
+ subject to the compulsory license
+ created by 17 USC Section 114 of the US Copyright Act
+ (or the equivalent in other jurisdictions).
+ .
+ The above rights may be exercised
+ in all media and formats
+ whether now known or hereafter devised.
+ The above rights include
+ the right to make such modifications
+ as are technically necessary to exercise the rights
+ in other media and formats.
+ All rights not expressly granted by Licensor are hereby reserved.
+ .
+ 4. Restrictions.
+ The license granted in Section 3 above is expressly
+ made subject to and limited by the following restrictions:
+ .
+ a. You may distribute, publicly display, publicly perform,
+ or publicly digitally perform the Work
+ only under the terms of this License,
+ and You must include a copy of,
+ or the Uniform Resource Identifier for,
+ this License
+ with every copy or phonorecord of the Work
+ You distribute, publicly display, publicly perform,
+ or publicly digitally perform.
+ You may not offer or impose any terms on the Work
+ that restrict the terms of this License
+ or the ability of a recipient of the Work to exercise
+ of the rights granted to that recipient
+ under the terms of the License.
+ You may not sublicense the Work.
+ You must keep intact all notices
+ that refer to this License
+ and to the disclaimer of warranties.
+ When You distribute, publicly display, publicly perform,
+ or publicly digitally perform the Work,
+ You may not impose any technological measures on the Work
+ that restrict the ability of a recipient of the Work from You
+ to exercise of the rights granted to that recipient
+ under the terms of the License.
+ This Section 4(a) applies to the Work
+ as incorporated in a Collective Work,
+ but this does not require the Collective Work
+ apart from the Work itself
+ to be made subject to the terms of this License.
+ If You create a Collective Work,
+ upon notice from any Licensor
+ You must, to the extent practicable, remove
+ from the Collective Work
+ any credit as required by Section 4(c), as requested.
+ If You create a Derivative Work,
+ upon notice from any Licensor
+ You must, to the extent practicable, remove
+ from the Derivative Work
+ any credit as required by Section 4(c), as requested.
+ b. You may distribute, publicly display, publicly perform,
+ or publicly digitally perform a Derivative Work
+ only under: (i) the terms of this License;
+ (ii) a later version of this License
+ with the same License Elements as this License;
+ (iii) either the Creative Commons (Unported) license
+ or a Creative Commons jurisdiction license
+ (either this or a later license version)
+ that contains the same License Elements as this License
+ (e.g. Attribution-ShareAlike 3.0 (Unported));
+ (iv) a Creative Commons Compatible License.
+ If you license the Derivative Work
+ under one of the licenses mentioned in (iv),
+ you must comply with the terms of that license.
+ If you license the Derivative Work
+ under the terms of any of the licenses
+ mentioned in (i), (ii) or (iii)
+ (the "Applicable License"),
+ you must comply with the terms of the Applicable License
+ generally and with the following provisions:
+ (I) You must include a copy of,
+ or the Uniform Resource Identifier for,
+ the Applicable License
+ with every copy or phonorecord of each Derivative Work
+ You distribute, publicly display, publicly perform,
+ or publicly digitally perform;
+ (II) You may not offer or impose any terms
+ on the Derivative Works
+ that restrict the terms of the Applicable License
+ or the ability of a recipient of the Work
+ to exercise the rights granted to that recipient
+ under the terms of the Applicable License;
+ (III) You must keep intact all notices
+ that refer to the Applicable License
+ and to the disclaimer of warranties;
+ and, (IV) when You distribute, publicly display, publicly perform,
+ or publicly digitally perform the Work,
+ You may not impose any technological measures
+ on the Derivative Work
+ that restrict the ability of a recipient
+ of the Derivative Work from You
+ to exercise the rights granted to that recipient
+ under the terms of the Applicable License.
+ This Section 4(b) applies to the Derivative Work
+ as incorporated in a Collective Work,
+ but this does not require the Collective Work
+ apart from the Derivative Work itself
+ to be made subject
+ to the terms of the Applicable License.
+ c. If You distribute, publicly display, publicly perform,
+ or publicly digitally perform the Work
+ (as defined in Section 1 above)
+ or any Derivative Works
+ (as defined in Section 1 above)
+ or Collective Works
+ (as defined in Section 1 above),
+ You must,
+ unless a request has been made pursuant to Section 4(a),
+ keep intact all copyright notices for the Work
+ and provide,
+ reasonable to the medium or means You are utilizing:
+ (i) the name of the Original Author
+ (or pseudonym, if applicable) if supplied,
+ and/or (ii) if the Original Author and/or Licensor designate
+ another party or parties
+ (e.g. a sponsor institute, publishing entity, journal)
+ for attribution ("Attribution Parties")
+ in Licensor's copyright notice, terms of service
+ or by other reasonable means,
+ the name of such party or parties;
+ the title of the Work if supplied;
+ to the extent reasonably practicable,
+ the Uniform Resource Identifier, if any,
+ that Licensor specifies to be associated with the Work,
+ unless such URI does not refer to the copyright notice
+ or licensing information for the Work;
+ and, consistent with Section 3(b)
+ in the case of a Derivative Work,
+ a credit identifying the use of the Work in the Derivative Work
+ (e.g., "French translation of the Work by Original Author,"
+ or "Screenplay based on original Work by Original Author").
+ The credit required by this Section 4(c) may be implemented
+ in any reasonable manner;
+ provided, however, that
+ in the case of a Derivative Work or Collective Work,
+ at a minimum such credit will appear,
+ if a credit for all contributing authors
+ of the Derivative Work or Collective Work appears,
+ then as part of these credits
+ and in a manner at least as prominent as the credits
+ for the other contributing authors.
+ For the avoidance of doubt,
+ You may only use the credit required by this Section
+ for the purpose of attribution
+ in the manner set out above
+ and, by exercising Your rights under this License,
+ You may not implicitly or explicitly assert or imply
+ any connection with, sponsorship or endorsement
+ by the Original Author, Licensor
+ and/or Attribution Parties, as appropriate,
+ of You or Your use of the Work,
+ without the separate, express prior written permission
+ of the Original Author, Licensor and/or Attribution Parties.
+ .
+ 5. Representations, Warranties and Disclaimer
+ .
+ UNLESS OTHERWISE MUTUALLY AGREED
+ TO BY THE PARTIES IN WRITING,
+ LICENSOR OFFERS THE WORK AS-IS
+ AND ONLY TO THE EXTENT OF ANY RIGHTS
+ HELD IN THE LICENSED WORK BY THE LICENSOR.
+ THE LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES
+ OF ANY KIND CONCERNING THE WORK,
+ EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
+ INCLUDING, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MARKETABILITY, MERCHANTIBILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
+ OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
+ OR THE PRESENCE OF ABSENCE OF ERRORS,
+ WHETHER OR NOT DISCOVERABLE.
+ SOME JURISDICTIONS DO NOT ALLOW
+ THE EXCLUSION OF IMPLIED WARRANTIES,
+ SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+ .
+ 6. Limitation on Liability.
+ EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW,
+ IN NO EVENT WILL LICENSOR BE LIABLE TO YOU
+ ON ANY LEGAL THEORY
+ FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
+ OR EXEMPLARY DAMAGES
+ ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK,
+ EVEN IF LICENSOR HAS BEEN ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGES.
+ .
+ 7. Termination
+ .
+ a. This License and the rights granted hereunder
+ will terminate automatically upon any breach by You
+ of the terms of this License.
+ Individuals or entities
+ who have received Derivative Works or Collective Works
+ from You under this License,
+ however, will not have their licenses terminated
+ provided such individuals or entities remain
+ in full compliance with those licenses.
+ Sections 1, 2, 5, 6, 7, and 8 will survive
+ any termination of this License.
+ b. Subject to the above terms and conditions,
+ the license granted here is perpetual
+ (for the duration of the applicable copyright in the Work).
+ Notwithstanding the above,
+ Licensor reserves the right to release the Work
+ under different license terms
+ or to stop distributing the Work
+ at any time;
+ provided, however that any such election will not serve
+ to withdraw this License
+ (or any other license that has been, or is required to be, granted
+ under the terms of this License),
+ and this License will continue in full force and effect
+ unless terminated as stated above.
+ .
+ 8. Miscellaneous
+ .
+ a. Each time You distribute or publicly digitally perform
+ the Work (as defined in Section 1 above)
+ or a Collective Work (as defined in Section 1 above),
+ the Licensor offers to the recipient a license to the Work
+ on the same terms and conditions
+ as the license granted to You under this License.
+ b. Each time You distribute
+ or publicly digitally perform a Derivative Work,
+ Licensor offers to the recipient
+ a license to the original Work
+ on the same terms and conditions
+ as the license granted to You under this License.
+ c. If any provision of this License is invalid
+ or unenforceable under applicable law,
+ it shall not affect the validity or enforceability
+ of the remainder of the terms of this License,
+ and without further action
+ by the parties to this agreement,
+ such provision shall be reformed
+ to the minimum extent necessary
+ to make such provision valid and enforceable.
+ d. No term or provision of this License shall be deemed waived
+ and no breach consented to
+ unless such waiver or consent shall be in writing
+ and signed by the party
+ to be charged with such waiver or consent.
+ e. This License constitutes the entire agreement between the parties
+ with respect to the Work licensed here.
+ There are no understandings, agreements or representations
+ with respect to the Work not specified here.
+ Licensor shall not be bound by any additional provisions
+ that may appear in any communication from You.
+ This License may not be modified
+ without the mutual written agreement of the Licensor and You.
+
+License: CC-BY-SA-4.0
+ Creative Commons Attribution-ShareAlike 4.0 International
+ Public License
+ .
+ By exercising the Licensed Rights (defined below),
+ You accept and agree to be bound by the terms and conditions
+ of this Creative Commons Attribution-ShareAlike 4.0 International
+ Public License ("Public License").
+ To the extent this Public License may be interpreted as a contract,
+ You are granted the Licensed Rights
+ in consideration of Your acceptance of these terms and conditions,
+ and the Licensor grants You such rights
+ in consideration of benefits the Licensor receives
+ from making the Licensed Material available
+ under these terms and conditions.
+ .
+ Section 1 – Definitions.
+ .
+ a. Adapted Material means material
+ subject to Copyright and Similar Rights
+ that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated,
+ altered, arranged, transformed,
+ or otherwise modified in a manner requiring permission
+ under the Copyright and Similar Rights held by the Licensor.
+ For purposes of this Public License,
+ where the Licensed Material is a musical work,
+ performance, or sound recording,
+ Adapted Material is always produced
+ where the Licensed Material is synched
+ in timed relation with a moving image.
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material
+ in accordance with the terms and conditions of this Public License.
+ c. BY-SA Compatible License means a license
+ listed at <https://creativecommons.org/compatiblelicenses>,
+ approved by Creative Commons
+ as essentially the equivalent of this Public License.
+ d. Copyright and Similar Rights means copyright
+ and/or similar rights closely related to copyright
+ including, without limitation,
+ performance, broadcast, sound recording,
+ and Sui Generis Database Rights,
+ without regard to how the rights are labeled or categorized.
+ For purposes of this Public License,
+ the rights specified in Section 2(b)(1)-(2)
+ are not Copyright and Similar Rights.
+ e. Effective Technological Measures means those measures
+ that, in the absence of proper authority, may not be circumvented
+ under laws fulfilling obligations
+ under Article 11 of the WIPO Copyright Treaty
+ adopted on December 20, 1996,
+ and/or similar international agreements.
+ f. Exceptions and Limitations means fair use, fair dealing,
+ and/or any other exception or limitation
+ to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+ g. License Elements means the license attributes
+ listed in the name of a Creative Commons Public License.
+ The License Elements of this Public License are
+ Attribution and ShareAlike.
+ h. Licensed Material means the artistic or literary work,
+ database, or other material
+ to which the Licensor applied this Public License.
+ i. Licensed Rights means the rights granted to You subject
+ to the terms and conditions of this Public License,
+ which are limited to all Copyright and Similar Rights
+ that apply to Your use of the Licensed Material
+ and that the Licensor has authority to license.
+ j. Licensor means the individual(s) or entity(ies)
+ granting rights under this Public License.
+ k. Share means to provide material to the public
+ by any means or process
+ that requires permission under the Licensed Rights,
+ such as reproduction, public display, public performance,
+ distribution, dissemination, communication, or importation,
+ and to make material available to the public
+ including in ways that members of the public may access
+ the material
+ from a place and at a time individually chosen by them.
+ l. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament
+ and of the Council of 11 March 1996
+ on the legal protection of databases,
+ as amended and/or succeeded,
+ as well as other essentially equivalent rights
+ anywhere in the world.
+ m. You means the individual or entity
+ exercising the Licensed Rights under this Public License.
+ Your has a corresponding meaning.
+ .
+ Section 2 – Scope.
+ .
+ a. License grant.
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You
+ a worldwide, royalty-free, non-sublicensable,
+ non-exclusive, irrevocable license
+ to exercise the Licensed Rights in the Licensed Material to:
+ A. reproduce and Share the Licensed Material,
+ in whole or in part; and
+ B. produce, reproduce, and Share Adapted Material.
+ 2. Exceptions and Limitations.
+ For the avoidance of doubt,
+ where Exceptions and Limitations apply to Your use,
+ this Public License does not apply,
+ and You do not need to comply
+ with its terms and conditions.
+ 3. Term.
+ The term of this Public License is specified in Section 6(a).
+ 4. Media and formats; technical modifications allowed.
+ The Licensor authorizes You to exercise the Licensed Rights
+ in all media and formats
+ whether now known or hereafter created,
+ and to make technical modifications necessary to do so.
+ The Licensor waives and/or agrees not to assert
+ any right or authority
+ to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights,
+ including technical modifications necessary
+ to circumvent Effective Technological Measures.
+ For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)(4)
+ never produces Adapted Material.
+ 5. Downstream recipients.
+ A. Offer from the Licensor – Licensed Material.
+ Every recipient of the Licensed Material
+ automatically receives an offer from the Licensor
+ to exercise the Licensed Rights
+ under the terms and conditions of this Public License.
+ B. Additional offer from the Licensor – Adapted Material.
+ Every recipient of Adapted Material from You
+ automatically receives an offer from the Licensor
+ to exercise the Licensed Rights in the Adapted Material
+ under the conditions of the Adapter’s License You apply.
+ C. No downstream restrictions.
+ You may not offer or impose
+ any additional or different terms or conditions on,
+ or apply any Effective Technological Measures to,
+ the Licensed Material
+ if doing so restricts exercise of the Licensed Rights
+ by any recipient of the Licensed Material.
+ 6. No endorsement.
+ Nothing in this Public License constitutes
+ or may be construed
+ as permission to assert or imply
+ that You are, or that Your use of the Licensed Material is,
+ connected with, or sponsored, endorsed,
+ or granted official status by,
+ the Licensor or others designated to receive attribution
+ as provided in Section 3(a)(1)(A)(i).
+ .
+ b. Other rights.
+ 1. Moral rights, such as the right of integrity,
+ are not licensed under this Public License,
+ nor are publicity, privacy,
+ and/or other similar personality rights;
+ however, to the extent possible,
+ the Licensor waives
+ and/or agrees not to assert
+ any such rights held by the Licensor
+ to the limited extent necessary
+ to allow You to exercise the Licensed Rights,
+ but not otherwise.
+ 2. Patent and trademark rights are not licensed
+ under this Public License.
+ 3. To the extent possible,
+ the Licensor waives any right
+ to collect royalties from You
+ for the exercise of the Licensed Rights,
+ whether directly or through a collecting society
+ under any voluntary or waivable
+ statutory or compulsory licensing scheme.
+ In all other cases
+ the Licensor expressly reserves any right
+ to collect such royalties.
+ .
+ Section 3 – License Conditions.
+ .
+ Your exercise of the Licensed Rights
+ is expressly made subject to the following conditions.
+ .
+ a. Attribution.
+ 1. If You Share the Licensed Material
+ (including in modified form),
+ You must:
+ A. retain the following
+ if it is supplied by the Licensor with the Licensed Material:
+ i. identification of the creator(s) of the Licensed Material
+ and any others designated to receive attribution,
+ in any reasonable manner requested by the Licensor
+ (including by pseudonym if designated);
+ ii. a copyright notice;
+ iii. a notice that refers to this Public License;
+ iv. a notice that refers to the disclaimer of warranties;
+ v. a URI or hyperlink to the Licensed Material
+ to the extent reasonably practicable;
+ B. indicate if You modified the Licensed Material
+ and retain an indication of any previous modifications; and
+ C. indicate the Licensed Material is licensed
+ under this Public License,
+ and include the text of, or the URI or hyperlink to,
+ this Public License.
+ 2. You may satisfy the conditions in Section 3(a)(1)
+ in any reasonable manner
+ based on the medium, means, and context
+ in which You Share the Licensed Material.
+ For example,
+ it may be reasonable to satisfy the conditions
+ by providing a URI or hyperlink to a resource
+ that includes the required information.
+ 3. If requested by the Licensor,
+ You must remove any of the information
+ required by Section 3(a)(1)(A)
+ to the extent reasonably practicable.
+ b. ShareAlike.
+ In addition to the conditions in Section 3(a),
+ if You Share Adapted Material You produce,
+ the following conditions also apply.
+ 1. The Adapter’s License You apply
+ must be a Creative Commons license
+ with the same License Elements,
+ this version or later,
+ or a BY-SA Compatible License.
+ 2. You must include
+ the text of, or the URI or hyperlink to,
+ the Adapter's License You apply.
+ You may satisfy this condition
+ in any reasonable manner
+ based on the medium, means, and context
+ in which You Share Adapted Material.
+ 3. You may not offer or impose
+ any additional or different terms or conditions on,
+ or apply any Effective Technological Measures to,
+ Adapted Material
+ that restrict exercise of the rights granted
+ under the Adapter's License You apply.
+ .
+ Section 4 – Sui Generis Database Rights.
+ .
+ Where the Licensed Rights include Sui Generis Database Rights
+ that apply to Your use of the Licensed Material:
+ .
+ a. for the avoidance of doubt,
+ Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share
+ all or a substantial portion of the contents of the database;
+ b. if You include all or a substantial portion of
+ the database contents in a database
+ in which You have Sui Generis Database Rights,
+ then the database
+ in which You have Sui Generis Database Rights
+ (but not its individual contents)
+ is Adapted Material,
+ including for purposes of Section 3(b); and
+ c. You must comply with the conditions in Section 3(a)
+ if You Share all or a substantial portion
+ of the contents of the database.
+ .
+ For the avoidance of doubt,
+ this Section 4 supplements and does not replace
+ Your obligations under this Public License
+ where the Licensed Rights include other Copyright and Similar Rights.
+ .
+ Section 5 – Disclaimer of Warranties and Limitation of Liability.
+ .
+ a. Unless otherwise separately undertaken by the Licensor,
+ to the extent possible,
+ the Licensor offers the Licensed Material as-is and as-available,
+ and makes no representations or warranties
+ of any kind concerning the Licensed Material,
+ whether express, implied, statutory, or other.
+ This includes, without limitation,
+ warranties of title, merchantability,
+ fitness for a particular purpose, non-infringement,
+ absence of latent or other defects, accuracy,
+ or the presence or absence of errors,
+ whether or not known or discoverable.
+ Where disclaimers of warranties are not allowed
+ in full or in part,
+ this disclaimer may not apply to You.
+ b. To the extent possible,
+ in no event will the Licensor be liable to You
+ on any legal theory
+ (including, without limitation, negligence)
+ or otherwise for any direct, special,
+ indirect, incidental, consequential, punitive, exemplary,
+ or other losses, costs, expenses, or damages
+ arising out of this Public License
+ or use of the Licensed Material,
+ even if the Licensor has been advised
+ of the possibility of such losses, costs,
+ expenses, or damages.
+ Where a limitation of liability is not allowed
+ in full or in part,
+ this limitation may not apply to You.
+ c. The disclaimer of warranties
+ and limitation of liability provided above
+ shall be interpreted in a manner that,
+ to the extent possible,
+ most closely approximates an absolute disclaimer
+ and waiver of all liability.
+ .
+ Section 6 – Term and Termination.
+ .
+ a. This Public License applies
+ for the term of the Copyright
+ and Similar Rights licensed here.
+ However, if You fail to comply with this Public License,
+ then Your rights under this Public License terminate
+ automatically.
+ b. Where Your right to use the Licensed Material has terminated
+ under Section 6(a), it reinstates:
+ 1. automatically as of the date the violation is cured,
+ provided it is cured within 30 days
+ of Your discovery of the violation; or
+ 2. upon express reinstatement by the Licensor.
+ c. For the avoidance of doubt,
+ this Section 6(b) does not affect
+ any right the Licensor may have to seek remedies
+ for Your violations of this Public License.
+ d. For the avoidance of doubt,
+ the Licensor may also offer the Licensed Material
+ under separate terms or conditions
+ or stop distributing the Licensed Material at any time;
+ however, doing so will not terminate this Public License.
+ e. Sections 1, 5, 6, 7, and 8 survive termination
+ of this Public License.
+ .
+ Section 7 – Other Terms and Conditions.
+ .
+ a. The Licensor shall not be bound
+ by any additional or different terms or conditions
+ communicated by You unless expressly agreed.
+ b. Any arrangements, understandings, or agreements
+ regarding the Licensed Material not stated herein
+ are separate from and independent of the terms and conditions
+ of this Public License.
+ .
+ Section 8 – Interpretation.
+ .
+ a. For the avoidance of doubt,
+ this Public License does not, and shall not be interpreted to,
+ reduce, limit, restrict, or impose conditions on
+ any use of the Licensed Material
+ that could lawfully be made without permission
+ under this Public License.
+ b. To the extent possible,
+ if any provision of this Public License is deemed unenforceable,
+ it shall be automatically reformed
+ to the minimum extent necessary to make it enforceable.
+ If the provision cannot be reformed,
+ it shall be severed from this Public License
+ without affecting the enforceability
+ of the remaining terms and conditions.
+ c. No term or condition of this Public License will be waived
+ and no failure to comply consented to
+ unless expressly agreed to by the Licensor.
+ d. Nothing in this Public License constitutes
+ or may be interpreted as a limitation upon, or waiver of,
+ any privileges and immunities that apply to the Licensor or You,
+ including from the legal processes
+ of any jurisdiction or authority.
+
+License: Expat
+ Permission is hereby granted,
+ free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction,
+ including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS",
+ WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+License: GPL-2
+ 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; version 2 of the License.
+ .
+ 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License can be found in `/usr/share/common-licenses/GPL-2'.
+
+License: GPL-2+
+ 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License can be found in `/usr/share/common-licenses/GPL-2'.
+
+License: GPL-3
+ 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 3 of the License.
+ .
+ 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License can be found in `/usr/share/common-licenses/GPL-3'.
+
+License: GPL-3+
+ 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 3 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License can be found in `/usr/share/common-licenses/GPL-3'.
+
+License: ISC~minimal-disclaimer
+ Permission to use, copy, modify, and distribute
+ this software and its documentation
+ for any purpose
+ is hereby granted without fee,
+ provided that this copyright and permissions notice appear
+ in all copies and derivatives.
+ .
+ This software is supplied "as is"
+ without express or implied warranty.
+
+License: LGPL-2.1+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ .
+ This 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
+ Lesser General Public License for more details.
+ .
+ You should have received a copy of the GNU Lesser General Public
+ License along with this package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU Lesser General
+ Public License can be found in `/usr/share/common-licenses/LGPL-2.1'.
+
+License: LGPL-3+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 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
+ Lesser General Public License for more details.
+ .
+ You should have received a copy of the GNU Lesser General Public
+ License along with this package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU Lesser General
+ Public License can be found in `/usr/share/common-licenses/LGPL-3'.
+
+License: NTP~disclaimer
+ Permission to use, copy, modify, distribute, and sell
+ this software and its documentation
+ for any purpose
+ is hereby granted without fee,
+ provided that the above copyright notice appear
+ in all copies
+ and that both that copyright notice and this permission notice appear
+ in supporting documentation,
+ and that the name of the copyright holders not be used
+ in advertising or publicity pertaining to distribution of the software
+ without specific, written prior permission.
+ The copyright holders make no representations
+ about the suitability of this software for any purpose.
+ It is provided "as is" without express or implied warranty.
+ .
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE,
+ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
+ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
+ OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH
+ THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+License: NTP~disclaimer~FarsiWeb
+ Permission to use, copy, modify, distribute, and sell
+ this software and its documentation
+ for any purpose
+ is hereby granted without fee,
+ provided that the above copyright notice appear
+ in all copies
+ and that both that copyright notice and this permission notice appear
+ in supporting documentation,
+ and that the name of Sharif FarsiWeb, Inc. not be used
+ in advertising or publicity pertaining to distribution of the software
+ without specific, written prior permission.
+ Sharif FarsiWeb, Inc. makes no representations
+ about the suitability of this software for any purpose.
+ It is provided "as is" without express or implied warranty.
+ .
+ SHARIF FARSIWEB, INC. DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE,
+ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ IN NO EVENT SHALL KEITH PACKARD BE LIABLE
+ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
+ OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH
+ THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+License: X11
+ Permission is hereby granted,
+ free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"),
+ to deal in the Software without restriction,
+ including without limitation
+ the rights to use, copy, modify, merge, publish, distribute,
+ sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS",
+ WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO
+ THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH
+ THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ .
+ Except as contained in this notice,
+ the name of the X Consortium shall not be used
+ in advertising or otherwise
+ to promote the sale, use or other dealings in this Software
+ without prior written authorization from the X Consortium.
diff --git a/debian/dh-addon/dh_kodiaddon_depends b/debian/dh-addon/dh_kodiaddon_depends
new file mode 100755
index 0000000..6e469a1
--- /dev/null
+++ b/debian/dh-addon/dh_kodiaddon_depends
@@ -0,0 +1,148 @@
+#! /usr/bin/perl -w
+
+=head1 NAME
+
+dh_kodiaddon_depends - Provides substvars for Kodi addons
+
+=cut
+
+use strict;
+use Debian::Debhelper::Dh_Lib;
+
+=head1 SYNOPSIS
+
+B<dh_kodiaddon_depends> [S<I<debhelper options>>]
+
+=head1 DESCRIPTION
+
+dh_kodiaddon_depends is a debhelper program, that is responsible for setting substvars
+providing the Kodi addon-API dependencies. Kodi provides a virtual package for each API
+which might be used by an addon. The following substvars will be set to a dependency
+clause which can be used directly in the "Depends"-line of the addons debian/control:
+
+${kodi:AUDIODECODERAPI} (ADDON_INSTANCE_VERSION_AUDIODECODER)
+${kodi:AUDIOENCODERAPI} (ADDON_INSTANCE_VERSION_AUDIOENCODER)
+${kodi:AUDIOENGINEAPI} (ADDON_GLOBAL_VERSION_AUDIOENGINE)
+${kodi:FILESYSTEMAPI} (ADDON_GLOBAL_VERSION_FILESYSTEM)
+${kodi:GAMEAPI} (ADDON_INSTANCE_VERSION_GAME)
+${kodi:GENERALAPI} (ADDON_GLOBAL_VERSION_GENERAL)
+${kodi:GUIAPI} (ADDON_GLOBAL_VERSION_GUI)
+${kodi:IMAGEDECODERAPI} (ADDON_INSTANCE_VERSION_IMAGEDECODER)
+${kodi:INPUTSTREAMAPI} (ADDON_INSTANCE_VERSION_INPUTSTREAM)
+${kodi:MAINAPI} (ADDON_GLOBAL_VERSION_MAIN)
+${kodi:NETWORKAPI} (ADDON_GLOBAL_VERSION_NETWORK)
+${kodi:PERIPHERALAPI} (ADDON_INSTANCE_VERSION_PERIPHERAL)
+${kodi:PVRAPI} (ADDON_INSTANCE_VERSION_PVR)
+${kodi:SCREENSAVERAPI} (ADDON_INSTANCE_VERSION_SCREENSAVER)
+${kodi:VFSAPI} (ADDON_INSTANCE_VERSION_VFS)
+${kodi:VIDEOCODECAPI} (ADDON_INSTANCE_VERSION_VIDEOCODEC)
+${kodi:VISUALIZATIONAPI} (ADDON_INSTANCE_VERSION_VISUALIZATION)
+
+=head1 EXAMPLES
+
+dh_kodiaddon_depends is usually called indirectly in a rules file via the dh command.
+
+ %:
+ dh $@ --with kodiaddon
+
+It can also be called directly, prior to calling dh_gencontrol.
+
+=head1 CONFORMS TO
+
+Debian policy, version 3.8.1
+
+=cut
+
+init ();
+
+no locale;
+
+sub get_api_version {
+ my $headerFileName = $_[0];
+ my $defineName = $_[1];
+ my $apiVersion;
+ my $apiVersionMin;
+ my $apiVersionMax;
+
+ open(HEADERFILE, "<$headerFileName") or die "$!";
+ while (<HEADERFILE>) {
+ if ($_ =~ /^#define $defineName\s+"(.*)"/) {
+ $apiVersion = $1;
+ }
+ if ($_ =~ /^#define ${defineName}_MIN\s+"(.*)"/) {
+ $apiVersionMin = $1;
+ }
+ if ($apiVersion && $apiVersionMin) {
+ last;
+ }
+ }
+ close(HEADERFILE);
+ if ($apiVersion =~ qr/(?:(\d+)\.(\d+)\.(\d+)|(\d+)\.(\d+)|(\d+))?(?:\.\*)?/) {
+ $apiVersionMax = int($2) + 1;
+ $apiVersionMax = "$1.$apiVersionMax.0";
+ }
+ $apiVersion or die "Could not find '$defineName' in $headerFileName";
+ $apiVersionMin or die "Could not find '${defineName}_MIN' in $headerFileName";
+ $apiVersionMax or die "Could not derive maximum API version from '$defineName' in $headerFileName";
+ ($apiVersion, $apiVersionMin, $apiVersionMax)
+}
+
+sub create_substvar {
+ my $substvarName = $_[0];
+ my $substvarValue = $_[1];
+ foreach my $package (@{$dh{DOPACKAGES}}) {
+ delsubstvar($package, $substvarName);
+ addsubstvar($package, $substvarName, $substvarValue);
+ }
+}
+
+my $baseDir = "debian/kodi-addons-dev-common";
+if (! -d "$baseDir/usr/include/kodi") {
+ $baseDir = "debian/tmp";
+ if (! -d "$baseDir/usr/include/kodi") {
+ $baseDir = ""
+ }
+}
+
+my @apis = (
+ ["kodi-api-audiodecoder", "kodi:AUDIODECODERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_AUDIODECODER"],
+ ["kodi-api-audioencoder", "kodi:AUDIOENCODERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_AUDIOENCODER"],
+ ["kodi-api-audioengine", "kodi:AUDIOENGINEAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_AUDIOENGINE"],
+ ["kodi-api-filesystem", "kodi:FILESYSTEMAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_FILESYSTEM"],
+ ["kodi-api-game", "kodi:GAMEAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_GAME"],
+ ["kodi-api-general", "kodi:GENERALAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_GENERAL"],
+ ["kodi-api-gui", "kodi:GUIAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_GUI"],
+ ["kodi-api-imagedecoder", "kodi:IMAGEDECODERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_IMAGEDECODER"],
+ ["kodi-api-inputstream", "kodi:INPUTSTREAMAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_INPUTSTREAM"],
+ ["kodi-api-main", "kodi:MAINAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_MAIN"],
+ ["kodi-api-network", "kodi:NETWORKAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_GLOBAL_VERSION_NETWORK"],
+ ["kodi-api-peripheral", "kodi:PERIPHERALAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_PERIPHERAL"],
+ ["kodi-api-pvr", "kodi:PVRAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_PVR"],
+ ["kodi-api-screensaver", "kodi:SCREENSAVERAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_SCREENSAVER"],
+ ["kodi-api-vfs", "kodi:VFSAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_VFS"],
+ ["kodi-api-videocodec", "kodi:VIDEOCODECAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_VIDEOCODEC"],
+ ["kodi-api-visualization", "kodi:VISUALIZATIONAPI", "$baseDir/usr/include/kodi/versions.h", "ADDON_INSTANCE_VERSION_VISUALIZATION"]
+);
+
+my @provides;
+
+foreach my $api (@apis) {
+ my ($apiName, $apiSubstvar, $apiHeader, $apiDefine) = @$api;
+ my ($apiVersion, $apiVersionMin, $apiVersionMax) = get_api_version($apiHeader, $apiDefine);
+ create_substvar($apiSubstvar, "$apiName (>= $apiVersionMin), $apiName (<< $apiVersionMax)");
+ push @provides, "$apiName (= $apiVersion)";
+}
+
+create_substvar("kodi:APIPROVIDES", join(", ", @provides));
+
+=head1 SEE ALSO
+
+L<debhelper(7)>
+
+This program is not a part of debhelper.
+
+=head1 AUTHOR
+
+Tobias Grimm <tobias.grimm@e-tobi.net>
+
+=cut
diff --git a/debian/dh-addon/kodiaddon.pm b/debian/dh-addon/kodiaddon.pm
new file mode 100644
index 0000000..019793c
--- /dev/null
+++ b/debian/dh-addon/kodiaddon.pm
@@ -0,0 +1,7 @@
+use warnings;
+use strict;
+use Debian::Debhelper::Dh_Lib;
+
+insert_before("dh_gencontrol", "dh_kodiaddon_depends");
+
+1
diff --git a/debian/extra/arial.ttf b/debian/extra/arial.ttf
new file mode 100644
index 0000000..d4b0962
--- /dev/null
+++ b/debian/extra/arial.ttf
Binary files differ
diff --git a/debian/from-debian-logo.svg b/debian/from-debian-logo.svg
new file mode 100644
index 0000000..e0779d9
--- /dev/null
+++ b/debian/from-debian-logo.svg
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 10.0, SVG Export Plug-In . SVG Version: 3.0.0 Build 77) -->
+
+<svg
+ xmlns:ns0="http://ns.adobe.com/SaveForWeb/1.0/"
+ xmlns:ns="http://ns.adobe.com/Variables/1.0/"
+ xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ i:viewOrigin="251 467"
+ i:rulerOrigin="0 0"
+ i:pageBounds="0 792 612 0"
+ width="124.60188"
+ height="41.382854"
+ viewBox="0 0 124.60188 41.382856"
+ overflow="visible"
+ enable-background="new 0 0 108.758 144.133"
+ xml:space="preserve"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="kodi-from-debian-logo.svg"
+ style="overflow:visible"><defs
+ id="defs49"><filter
+ inkscape:label="Drop Shadow"
+ id="filter4007"
+ color-interpolation-filters="sRGB"><feFlood
+ flood-opacity="0.267"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood4009" /><feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite4011" /><feGaussianBlur
+ stdDeviation="6"
+ result="blur"
+ id="feGaussianBlur4013" /><feOffset
+ dx="2.77556e-17"
+ dy="2.77556e-17"
+ result="offset"
+ id="feOffset4015" /><feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite4017" /></filter><filter
+ inkscape:label="Drop Shadow"
+ id="filter4019"
+ color-interpolation-filters="sRGB"><feFlood
+ flood-opacity="0.267"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood4021" /><feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite4023" /><feGaussianBlur
+ stdDeviation="6"
+ result="blur"
+ id="feGaussianBlur4025" /><feOffset
+ dx="2.77556e-17"
+ dy="2.77556e-17"
+ result="offset"
+ id="feOffset4027" /><feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite4029" /></filter><filter
+ inkscape:label="Drop Shadow"
+ id="filter4055"
+ y="-0.5"
+ height="2"
+ color-interpolation-filters="sRGB"><feFlood
+ flood-opacity="0.25"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood4057" /><feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite4059" /><feGaussianBlur
+ stdDeviation="6"
+ result="blur"
+ id="feGaussianBlur4061" /><feOffset
+ dx="2.77556e-17"
+ dy="2.77556e-17"
+ result="offset"
+ id="feOffset4063" /><feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite4065" /></filter></defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1438"
+ inkscape:window-height="879"
+ id="namedview47"
+ showgrid="false"
+ inkscape:zoom="2.3156003"
+ inkscape:cx="9.2522673"
+ inkscape:cy="8.9090173"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg2"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ showguides="true"
+ inkscape:guide-bbox="true" /><metadata
+ id="metadata4"><ns:variableSets><ns:variableSet
+ varSetName="binding1"
+ locked="none"><ns:variables /><ns:sampleDataSets /></ns:variableSet></ns:variableSets><ns0:sfw><ns0:slices /><ns0:sliceSourceBounds
+ y="322.867"
+ x="251"
+ width="108.758"
+ height="144.133"
+ bottomLeftOrigin="true" /></ns0:sfw><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g
+ id="g4043"
+ style="filter:url(#filter4055)"
+ transform="translate(-179.24258,-86.71267)"><g
+ transform="matrix(0.5678998,0,0,0.5678998,231.69733,35.897279)"
+ id="g4105"><path
+ i:knockout="Off"
+ d="m 13.437,125.506 c -0.045,0.047 -0.045,7.506 -0.138,9.453 -0.092,1.574 -0.232,4.957 -3.568,4.957 -3.429,0 -4.263,-3.939 -4.541,-5.652 -0.324,-1.9 -0.324,-3.477 -0.324,-4.17 0,-2.225 0.139,-8.436 5.375,-8.436 1.576,0 2.456,0.465 3.151,0.834 l 0.045,3.014 z M 0,130.975 c 0,13.066 6.951,13.066 7.97,13.066 2.873,0 4.727,-1.576 5.514,-4.309 l 0.093,4.123 c 0.881,-0.047 1.761,-0.139 3.197,-0.139 0.51,0 0.926,0 1.298,0.047 0.371,0 0.741,0.045 1.158,0.092 -0.741,-1.482 -1.297,-4.818 -1.297,-12.049 0,-7.043 0,-18.951 0.602,-22.566 -1.667,0.789 -3.105,1.299 -6.256,1.576 1.251,1.344 1.251,2.039 1.251,8.154 -0.879,-0.277 -1.992,-0.602 -3.892,-0.602 C 1.344,118.369 0,125.598 0,130.975"
+ id="path33"
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ i:knockout="Off"
+ d="m 25.13,128.609 c 0.047,-3.846 0.835,-7.275 4.124,-7.275 3.615,0 3.891,3.984 3.799,7.275 H 25.13 z m 12.51,0.465 c 0,-5.422 -1.065,-10.752 -7.923,-10.752 -9.452,0 -9.452,10.475 -9.452,12.697 0,9.406 4.216,13.113 11.306,13.113 3.149,0 4.68,-0.461 5.514,-0.695 -0.046,-1.668 0.185,-2.734 0.465,-4.17 -0.975,0.604 -2.226,1.391 -5.006,1.391 -7.229,0 -7.322,-6.582 -7.322,-8.852 H 37.55 l 0.09,-2.732"
+ id="path35"
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ i:knockout="Off"
+ d="m 52.715,131.066 c 0,4.309 -0.787,10.102 -6.162,10.102 -0.742,0 -1.668,-0.141 -2.27,-0.279 -0.093,-1.668 -0.093,-4.541 -0.093,-7.877 0,-3.986 0.416,-6.068 0.742,-7.09 0.972,-3.289 3.15,-3.334 3.566,-3.334 3.522,0 4.217,4.865 4.217,8.478 z m -13.298,5.051 c 0,3.43 0,5.375 -0.556,6.857 1.9,0.742 4.262,1.158 7.09,1.158 1.807,0 7.043,0 9.869,-5.791 1.344,-2.688 1.807,-6.303 1.807,-9.037 0,-1.668 -0.186,-5.328 -1.529,-7.646 -1.296,-2.176 -3.382,-3.289 -5.605,-3.289 -4.449,0 -5.746,3.707 -6.44,5.607 0,-2.363 0.045,-10.611 0.415,-14.828 -3.011,1.391 -4.866,1.621 -6.857,1.807 1.807,0.74 1.807,3.801 1.807,13.764 v 11.398"
+ id="path37"
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ i:knockout="Off"
+ d="m 66.535,143.855 c -0.928,-0.139 -1.578,-0.232 -2.922,-0.232 -1.48,0 -2.502,0.094 -3.566,0.232 0.463,-0.881 0.648,-1.299 0.787,-4.309 0.186,-4.125 0.232,-15.154 -0.092,-17.471 -0.232,-1.762 -0.648,-2.039 -1.297,-2.502 3.799,-0.371 4.865,-0.648 6.625,-1.482 -0.369,2.037 -0.418,3.059 -0.418,6.162 -0.091,15.989 -0.138,17.702 0.883,19.602"
+ id="path39"
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ i:knockout="Off"
+ d="m 81.373,130.74 c -0.092,2.92 -0.139,4.959 -0.928,6.58 -0.973,2.086 -2.594,2.688 -3.799,2.688 -2.783,0 -3.383,-2.316 -3.383,-4.586 0,-4.355 3.893,-4.682 5.652,-4.682 h 2.458 z m -12.744,5.701 c 0,2.92 0.881,5.838 3.477,7.09 1.158,0.51 2.316,0.51 2.688,0.51 4.264,0 5.699,-3.152 6.58,-5.098 -0.047,2.039 0,3.289 0.139,4.912 0.834,-0.047 1.668,-0.139 3.059,-0.139 0.787,0 1.529,0.092 2.316,0.139 -0.51,-0.787 -0.787,-1.252 -0.928,-3.059 -0.092,-1.76 -0.092,-3.521 -0.092,-5.977 l 0.047,-9.453 c 0,-3.523 -0.928,-6.998 -7.879,-6.998 -4.586,0 -7.273,1.391 -8.617,2.086 0.557,1.02 1.02,1.898 1.436,3.893 1.809,-1.576 4.172,-2.41 6.58,-2.41 3.848,0 3.848,2.549 3.848,6.162 -0.881,-0.045 -1.623,-0.137 -2.875,-0.137 -5.887,10e-4 -9.779,2.268 -9.779,8.479"
+ id="path41"
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ i:knockout="Off"
+ d="m 108.063,139.268 c 0.047,1.576 0.047,3.244 0.695,4.588 -1.021,-0.092 -1.623,-0.232 -3.521,-0.232 -1.113,0 -1.715,0.094 -2.596,0.232 0.184,-0.602 0.279,-0.834 0.371,-1.623 0.139,-1.064 0.232,-4.633 0.232,-5.885 v -5.004 c 0,-2.178 0,-5.33 -0.141,-6.441 -0.092,-0.787 -0.322,-2.918 -3.012,-2.918 -2.641,0 -3.521,1.945 -3.846,3.521 -0.369,1.621 -0.369,3.383 -0.369,10.24 0.045,5.932 0.045,6.486 0.508,8.109 -0.787,-0.092 -1.76,-0.184 -3.15,-0.184 -1.113,0 -1.854,0.045 -2.779,0.184 0.324,-0.742 0.51,-1.113 0.602,-3.707 0.094,-2.549 0.279,-15.061 -0.141,-18.025 -0.23,-1.809 -0.695,-2.225 -1.203,-2.688 3.754,-0.186 4.957,-0.789 6.117,-1.389 v 4.91 c 0.555,-1.438 1.713,-4.635 6.348,-4.635 5.793,0 5.838,4.217 5.885,6.996 v 13.951"
+ id="path43"
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1" /><path
+ i:knockout="Off"
+ d="m 66.926,111.533 -3.838,3.836 -3.836,-3.836 3.836,-3.836 3.838,3.836"
+ id="path45"
+ inkscape:connector-curvature="0"
+ style="fill:#a80030" /></g><text
+ sodipodi:linespacing="125%"
+ id="text4101"
+ y="113.59251"
+ x="189.35947"
+ style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
+ xml:space="preserve"><tspan
+ y="113.59251"
+ x="189.35947"
+ id="tspan4103"
+ sodipodi:role="line">from</tspan></text>
+</g></svg> \ No newline at end of file
diff --git a/debian/gbp.conf b/debian/gbp.conf
new file mode 100644
index 0000000..89e7f25
--- /dev/null
+++ b/debian/gbp.conf
@@ -0,0 +1,7 @@
+# Configuration file for git-buildpackage and friends
+
+[DEFAULT]
+filter = */.git*
+components = ["libdvdnav-embedded", "libdvdread-embedded", "repo-resources-embedded"]
+debian-branch = debian/sid
+upstream-branch = upstream/latest
diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
new file mode 100644
index 0000000..0c22dc4
--- /dev/null
+++ b/debian/gitlab-ci.yml
@@ -0,0 +1,3 @@
+include:
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
diff --git a/debian/headers-check.c b/debian/headers-check.c
new file mode 100644
index 0000000..b81900b
--- /dev/null
+++ b/debian/headers-check.c
@@ -0,0 +1,126 @@
+#include "kodi/AddonBase.h"
+#include "kodi/AudioEngine.h"
+#include "kodi/Filesystem.h"
+#include "kodi/General.h"
+#include "kodi/Network.h"
+#include "kodi/addon-instance/AudioDecoder.h"
+#include "kodi/addon-instance/AudioEncoder.h"
+#include "kodi/addon-instance/Game.h"
+#include "kodi/addon-instance/ImageDecoder.h"
+#include "kodi/addon-instance/Inputstream.h"
+#include "kodi/addon-instance/PVR.h"
+#include "kodi/addon-instance/Peripheral.h"
+#include "kodi/addon-instance/Screensaver.h"
+#include "kodi/addon-instance/VFS.h"
+#include "kodi/addon-instance/VideoCodec.h"
+#include "kodi/addon-instance/Visualization.h"
+#include "kodi/addon-instance/inputstream/DemuxPacket.h"
+#include "kodi/addon-instance/inputstream/StreamCodec.h"
+#include "kodi/addon-instance/inputstream/StreamConstants.h"
+#include "kodi/addon-instance/inputstream/StreamCrypto.h"
+#include "kodi/addon-instance/inputstream/TimingConstants.h"
+#include "kodi/addon-instance/peripheral/PeripheralUtils.h"
+#include "kodi/addon-instance/pvr/ChannelGroups.h"
+#include "kodi/addon-instance/pvr/Channels.h"
+#include "kodi/addon-instance/pvr/EDL.h"
+#include "kodi/addon-instance/pvr/EPG.h"
+#include "kodi/addon-instance/pvr/General.h"
+#include "kodi/addon-instance/pvr/MenuHook.h"
+#include "kodi/addon-instance/pvr/Providers.h"
+#include "kodi/addon-instance/pvr/Recordings.h"
+#include "kodi/addon-instance/pvr/Stream.h"
+#include "kodi/addon-instance/pvr/Timers.h"
+#include "kodi/c-api/addon-instance/audiodecoder.h"
+#include "kodi/c-api/addon-instance/audioencoder.h"
+#include "kodi/c-api/addon-instance/game.h"
+#include "kodi/c-api/addon-instance/imagedecoder.h"
+#include "kodi/c-api/addon-instance/inputstream.h"
+#include "kodi/c-api/addon-instance/inputstream/demux_packet.h"
+#include "kodi/c-api/addon-instance/inputstream/stream_codec.h"
+#include "kodi/c-api/addon-instance/inputstream/stream_constants.h"
+#include "kodi/c-api/addon-instance/inputstream/stream_crypto.h"
+#include "kodi/c-api/addon-instance/inputstream/timing_constants.h"
+#include "kodi/c-api/addon-instance/peripheral.h"
+#include "kodi/c-api/addon-instance/pvr.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_channels.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_channel_groups.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_defines.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_edl.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_epg.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_general.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_menu_hook.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_providers.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_recordings.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_stream.h"
+#include "kodi/c-api/addon-instance/pvr/pvr_timers.h"
+#include "kodi/c-api/addon-instance/screensaver.h"
+#include "kodi/c-api/addon-instance/vfs.h"
+#include "kodi/c-api/addon-instance/video_codec.h"
+#include "kodi/c-api/addon-instance/visualization.h"
+#include "kodi/c-api/addon_base.h"
+#include "kodi/c-api/audio_engine.h"
+#include "kodi/c-api/filesystem.h"
+#include "kodi/c-api/general.h"
+#include "kodi/c-api/gui/controls/button.h"
+#include "kodi/c-api/gui/controls/edit.h"
+#include "kodi/c-api/gui/controls/fade_label.h"
+#include "kodi/c-api/gui/controls/image.h"
+#include "kodi/c-api/gui/controls/label.h"
+#include "kodi/c-api/gui/controls/progress.h"
+#include "kodi/c-api/gui/controls/radio_button.h"
+#include "kodi/c-api/gui/controls/rendering.h"
+#include "kodi/c-api/gui/controls/settings_slider.h"
+#include "kodi/c-api/gui/controls/slider.h"
+#include "kodi/c-api/gui/controls/spin.h"
+#include "kodi/c-api/gui/controls/text_box.h"
+#include "kodi/c-api/gui/definitions.h"
+#include "kodi/c-api/gui/dialogs/context_menu.h"
+#include "kodi/c-api/gui/dialogs/extended_progress.h"
+#include "kodi/c-api/gui/dialogs/filebrowser.h"
+#include "kodi/c-api/gui/dialogs/keyboard.h"
+#include "kodi/c-api/gui/dialogs/numeric.h"
+#include "kodi/c-api/gui/dialogs/ok.h"
+#include "kodi/c-api/gui/dialogs/progress.h"
+#include "kodi/c-api/gui/dialogs/select.h"
+#include "kodi/c-api/gui/dialogs/text_viewer.h"
+#include "kodi/c-api/gui/dialogs/yes_no.h"
+#include "kodi/c-api/gui/general.h"
+#include "kodi/c-api/gui/input/action_ids.h"
+#include "kodi/c-api/gui/list_item.h"
+#include "kodi/c-api/gui/window.h"
+#include "kodi/c-api/network.h"
+#include "kodi/gui/General.h"
+#include "kodi/gui/ListItem.h"
+#include "kodi/gui/Window.h"
+#include "kodi/gui/controls/Button.h"
+#include "kodi/gui/controls/Edit.h"
+#include "kodi/gui/controls/FadeLabel.h"
+#include "kodi/gui/controls/Image.h"
+#include "kodi/gui/controls/Label.h"
+#include "kodi/gui/controls/Progress.h"
+#include "kodi/gui/controls/RadioButton.h"
+#include "kodi/gui/controls/Rendering.h"
+#include "kodi/gui/controls/SettingsSlider.h"
+#include "kodi/gui/controls/Slider.h"
+#include "kodi/gui/controls/Spin.h"
+#include "kodi/gui/controls/TextBox.h"
+#include "kodi/gui/dialogs/ContextMenu.h"
+#include "kodi/gui/dialogs/ExtendedProgress.h"
+#include "kodi/gui/dialogs/FileBrowser.h"
+#include "kodi/gui/dialogs/Keyboard.h"
+#include "kodi/gui/dialogs/Numeric.h"
+#include "kodi/gui/dialogs/OK.h"
+#include "kodi/gui/dialogs/Progress.h"
+#include "kodi/gui/dialogs/Select.h"
+#include "kodi/gui/dialogs/TextViewer.h"
+#include "kodi/gui/dialogs/YesNo.h"
+#include "kodi/gui/gl/GL.h"
+#include "kodi/gui/gl/Shader.h"
+#include "kodi/gui/input/ActionIDs.h"
+#include "kodi/gui/renderHelper.h"
+#include "kodi/tools/DllHelper.h"
+#include "kodi/tools/EndTime.h"
+#include "kodi/tools/StringUtils.h"
+#include "kodi/tools/Thread.h"
+#include "kodi/tools/Timer.h"
+#include "kodi/versions.h"
diff --git a/debian/kodi-addons-dev-common.README.Debian b/debian/kodi-addons-dev-common.README.Debian
new file mode 100644
index 0000000..9d87821
--- /dev/null
+++ b/debian/kodi-addons-dev-common.README.Debian
@@ -0,0 +1,2 @@
+The current PVR API version can be found in xbmc_pvr_types.h:
+XBMC_PVR_API_VERSION
diff --git a/debian/kodi-addons-dev-common.install b/debian/kodi-addons-dev-common.install
new file mode 100644
index 0000000..476a4e6
--- /dev/null
+++ b/debian/kodi-addons-dev-common.install
@@ -0,0 +1,3 @@
+usr/include/kodi
+usr/share/kodi/cmake/*.cmake
+debian/dh-addon/kodiaddon.pm usr/share/perl5/Debian/Debhelper/Sequence/
diff --git a/debian/kodi-addons-dev.install b/debian/kodi-addons-dev.install
new file mode 100644
index 0000000..de58205
--- /dev/null
+++ b/debian/kodi-addons-dev.install
@@ -0,0 +1,2 @@
+debian/dh-addon/dh_kodiaddon_depends usr/bin/
+usr/lib/*/kodi/cmake
diff --git a/debian/kodi-addons-dev.manpages b/debian/kodi-addons-dev.manpages
new file mode 100644
index 0000000..f83eeca
--- /dev/null
+++ b/debian/kodi-addons-dev.manpages
@@ -0,0 +1 @@
+debian/dh-addon/*.1
diff --git a/debian/kodi-bin.install b/debian/kodi-bin.install
new file mode 100644
index 0000000..72f940b
--- /dev/null
+++ b/debian/kodi-bin.install
@@ -0,0 +1,3 @@
+usr/lib/*/kodi/system
+usr/lib/*/kodi/kodi-xrandr
+usr/lib/*/kodi/kodi.bin
diff --git a/debian/kodi-bin.lintian-overrides b/debian/kodi-bin.lintian-overrides
new file mode 100644
index 0000000..28c9f96
--- /dev/null
+++ b/debian/kodi-bin.lintian-overrides
@@ -0,0 +1,20 @@
+# bindnow breaks wrappers used with libdvdread
+hardening-no-bindnow [usr/lib/*/kodi/kodi.bin]
+hardening-no-bindnow [usr/lib/*/kodi/kodi-xrandr]
+
+# kodi{.bin,-xrandr} are invoked by scripts /usr/bin/kodi*
+executable-in-usr-lib [usr/lib/*/kodi/kodi.bin]
+executable-in-usr-lib [usr/lib/*/kodi/kodi-xrandr]
+
+# Spelling errors in lib/libUPnP that can not be touched by Kodi
+# (https://github.com/xbmc/xbmc/pull/18100#pullrequestreview-436935700)
+spelling-error-in-binary Paramater Parameter [usr/lib/*/kodi/kodi.bin]
+spelling-error-in-binary ment meant [usr/lib/*/kodi/kodi.bin]
+spelling-error-in-binary unexected unexpected [usr/lib/*/kodi/kodi.bin]
+spelling-error-in-binary develope develop [usr/lib/*/kodi/kodi.bin]
+spelling-error-in-binary installe installer [usr/lib/*/kodi/kodi.bin]
+spelling-error-in-binary protocolL protocol [usr/lib/*/kodi/kodi.bin]
+spelling-error-in-binary rovided provided [usr/lib/*/kodi/kodi.bin]
+
+# The library in question really does not depend on external code
+shared-library-lacks-prerequisites [usr/lib/*/kodi/system/libsse4-*.so]
diff --git a/debian/kodi-bin.manpages b/debian/kodi-bin.manpages
new file mode 100644
index 0000000..ae989bf
--- /dev/null
+++ b/debian/kodi-bin.manpages
@@ -0,0 +1 @@
+docs/manpages/kodi.bin.1
diff --git a/debian/kodi-data.install b/debian/kodi-data.install
new file mode 100644
index 0000000..f9a237d
--- /dev/null
+++ b/debian/kodi-data.install
@@ -0,0 +1,11 @@
+usr/lib/firewalld/services/kodi-jsonrpc.xml
+usr/lib/firewalld/services/kodi-http.xml
+usr/lib/firewalld/services/kodi-eventserver.xml
+usr/share/kodi/addons
+usr/share/kodi/media
+usr/share/kodi/privacy-policy.txt
+usr/share/kodi/system
+usr/share/kodi/userdata
+usr/share/icons
+usr/share/kodi/addons/skin.*
+usr/share/xsessions/kodi.desktop
diff --git a/debian/kodi-data.links b/debian/kodi-data.links
new file mode 100644
index 0000000..bed7947
--- /dev/null
+++ b/debian/kodi-data.links
@@ -0,0 +1,7 @@
+usr/share/fonts/truetype/noto/NotoSans-Regular.ttf usr/share/kodi/addons/skin.estouchy/fonts/NotoSans-Regular.ttf
+usr/share/fonts/truetype/noto/NotoMono-Regular.ttf usr/share/kodi/addons/skin.estuary/fonts/NotoMono-Regular.ttf
+usr/share/fonts/truetype/noto/NotoSans-Bold.ttf usr/share/kodi/addons/skin.estuary/fonts/NotoSans-Bold.ttf
+usr/share/fonts/truetype/noto/NotoSans-Regular.ttf usr/share/kodi/addons/skin.estuary/fonts/NotoSans-Regular.ttf
+usr/share/fonts/truetype/roboto/hinted/Roboto-Thin.ttf usr/share/kodi/addons/skin.estuary/fonts/Roboto-Thin.ttf
+usr/share/javascript/jquery/jquery.min.js /usr/share/kodi/addons/webinterface.default/js/jquery-1.8.2.min.js
+usr/share/javascript/iscroll/iscroll-min.js /usr/share/kodi/addons/webinterface.default/js/iscroll-min.js
diff --git a/debian/kodi-data.lintian-overrides b/debian/kodi-data.lintian-overrides
new file mode 100644
index 0000000..1209223
--- /dev/null
+++ b/debian/kodi-data.lintian-overrides
@@ -0,0 +1,14 @@
+# Merged fonts used by Kodi as fallback
+font-in-non-font-package [usr/share/kodi/media/Fonts/arial.ttf]
+font-in-non-font-package [usr/share/kodi/media/Fonts/teletext.ttf]
+font-outside-font-dir [usr/share/kodi/media/Fonts/arial.ttf]
+font-outside-font-dir [usr/share/kodi/media/Fonts/teletext.ttf]
+
+# The majority of files found by this check are either changelog.txt or
+# other text files used by addon code (like versions.txt). The changelog.txt
+# is used by Kodi GUI to display the version history for the installed addons.
+# Despite https://github.com/xbmc/xbmc/pull/9351 merged, big part of community
+# insists on restoring the old behavior and this may happen before 19.0 final
+# release. Please note that this override guards only addons code, so text files
+# and documentation in other parts of Kodi will still be reported if found.
+package-contains-documentation-outside-usr-share-doc [usr/share/kodi/addons/*]
diff --git a/debian/kodi-eventclients-common.install b/debian/kodi-eventclients-common.install
new file mode 100644
index 0000000..291a7e8
--- /dev/null
+++ b/debian/kodi-eventclients-common.install
@@ -0,0 +1 @@
+usr/share/pixmaps/kodi
diff --git a/debian/kodi-eventclients-dev-common.examples b/debian/kodi-eventclients-dev-common.examples
new file mode 100644
index 0000000..6e4cc71
--- /dev/null
+++ b/debian/kodi-eventclients-dev-common.examples
@@ -0,0 +1 @@
+usr/share/doc/kodi/kodi-eventclients-dev/examples/*
diff --git a/debian/kodi-eventclients-dev-common.install b/debian/kodi-eventclients-dev-common.install
new file mode 100644
index 0000000..14e3505
--- /dev/null
+++ b/debian/kodi-eventclients-dev-common.install
@@ -0,0 +1 @@
+usr/include/kodi/xbmcclient.h
diff --git a/debian/kodi-eventclients-dev.install b/debian/kodi-eventclients-dev.install
new file mode 100644
index 0000000..2b7551e
--- /dev/null
+++ b/debian/kodi-eventclients-dev.install
@@ -0,0 +1 @@
+usr/lib/*/kodi/eventclients-dev
diff --git a/debian/kodi-eventclients-kodi-send.install b/debian/kodi-eventclients-kodi-send.install
new file mode 100644
index 0000000..0d4bff9
--- /dev/null
+++ b/debian/kodi-eventclients-kodi-send.install
@@ -0,0 +1 @@
+usr/bin/kodi-send
diff --git a/debian/kodi-eventclients-kodi-send.lintian-overrides b/debian/kodi-eventclients-kodi-send.lintian-overrides
new file mode 100644
index 0000000..7a665c7
--- /dev/null
+++ b/debian/kodi-eventclients-kodi-send.lintian-overrides
@@ -0,0 +1,2 @@
+# It is Python package dropping files in /usr/bin
+package-contains-no-arch-dependent-files
diff --git a/debian/kodi-eventclients-kodi-send.manpages b/debian/kodi-eventclients-kodi-send.manpages
new file mode 100644
index 0000000..18b822e
--- /dev/null
+++ b/debian/kodi-eventclients-kodi-send.manpages
@@ -0,0 +1 @@
+docs/manpages/kodi-send.1
diff --git a/debian/kodi-eventclients-ps3.install b/debian/kodi-eventclients-ps3.install
new file mode 100644
index 0000000..66bc049
--- /dev/null
+++ b/debian/kodi-eventclients-ps3.install
@@ -0,0 +1,2 @@
+usr/bin/kodi-ps3remote
+usr/lib/python*/*/kodi/ps3
diff --git a/debian/kodi-eventclients-ps3.lintian-overrides b/debian/kodi-eventclients-ps3.lintian-overrides
new file mode 100644
index 0000000..e4c91cf
--- /dev/null
+++ b/debian/kodi-eventclients-ps3.lintian-overrides
@@ -0,0 +1,6 @@
+# Python scripts meant to be run by end-user
+executable-in-usr-lib [usr/lib/python3/dist-packages/kodi/ps3/sixpair.py]
+executable-in-usr-lib [usr/lib/python3/dist-packages/kodi/ps3/sixwatch.py]
+
+# It is Python package dropping files in /usr/bin
+package-contains-no-arch-dependent-files
diff --git a/debian/kodi-eventclients-ps3.manpages b/debian/kodi-eventclients-ps3.manpages
new file mode 100644
index 0000000..a78c6b3
--- /dev/null
+++ b/debian/kodi-eventclients-ps3.manpages
@@ -0,0 +1 @@
+docs/manpages/kodi-ps3remote.1
diff --git a/debian/kodi-eventclients-python.install b/debian/kodi-eventclients-python.install
new file mode 100644
index 0000000..7e241a0
--- /dev/null
+++ b/debian/kodi-eventclients-python.install
@@ -0,0 +1 @@
+usr/lib/python*/*/kodi
diff --git a/debian/kodi-eventclients-python.lintian-overrides b/debian/kodi-eventclients-python.lintian-overrides
new file mode 100644
index 0000000..7a665c7
--- /dev/null
+++ b/debian/kodi-eventclients-python.lintian-overrides
@@ -0,0 +1,2 @@
+# It is Python package dropping files in /usr/bin
+package-contains-no-arch-dependent-files
diff --git a/debian/kodi-eventclients-wiiremote.install b/debian/kodi-eventclients-wiiremote.install
new file mode 100644
index 0000000..96ac87a
--- /dev/null
+++ b/debian/kodi-eventclients-wiiremote.install
@@ -0,0 +1 @@
+usr/bin/kodi-wiiremote
diff --git a/debian/kodi-eventclients-wiiremote.lintian-overrides b/debian/kodi-eventclients-wiiremote.lintian-overrides
new file mode 100644
index 0000000..981ca75
--- /dev/null
+++ b/debian/kodi-eventclients-wiiremote.lintian-overrides
@@ -0,0 +1,2 @@
+# bindnow breaks wrappers used with libdvdread
+hardening-no-bindnow [usr/bin/kodi-wiiremote]
diff --git a/debian/kodi-eventclients-wiiremote.manpages b/debian/kodi-eventclients-wiiremote.manpages
new file mode 100644
index 0000000..ca4297b
--- /dev/null
+++ b/debian/kodi-eventclients-wiiremote.manpages
@@ -0,0 +1 @@
+docs/manpages/kodi-wiiremote.1
diff --git a/debian/kodi-eventclients-zeroconf.install b/debian/kodi-eventclients-zeroconf.install
new file mode 100644
index 0000000..3aadf53
--- /dev/null
+++ b/debian/kodi-eventclients-zeroconf.install
@@ -0,0 +1 @@
+usr/lib/python*/*/kodi/zeroconf.py
diff --git a/debian/kodi-eventclients-zeroconf.lintian-overrides b/debian/kodi-eventclients-zeroconf.lintian-overrides
new file mode 100644
index 0000000..9826a0f
--- /dev/null
+++ b/debian/kodi-eventclients-zeroconf.lintian-overrides
@@ -0,0 +1,5 @@
+# It is Python package
+package-contains-no-arch-dependent-files
+
+# and it can be run by end-user
+executable-in-usr-lib [usr/lib/python3/dist-packages/kodi/zeroconf.py]
diff --git a/debian/kodi-tools-texturepacker.install b/debian/kodi-tools-texturepacker.install
new file mode 100644
index 0000000..588194f
--- /dev/null
+++ b/debian/kodi-tools-texturepacker.install
@@ -0,0 +1 @@
+usr/bin/*TexturePacker
diff --git a/debian/kodi-tools-texturepacker.lintian-overrides b/debian/kodi-tools-texturepacker.lintian-overrides
new file mode 100644
index 0000000..8fc7313
--- /dev/null
+++ b/debian/kodi-tools-texturepacker.lintian-overrides
@@ -0,0 +1,2 @@
+# bindnow breaks wrappers used with libdvdread
+hardening-no-bindnow [usr/bin/*TexturePacker]
diff --git a/debian/kodi-tools-texturepacker.manpages b/debian/kodi-tools-texturepacker.manpages
new file mode 100644
index 0000000..df26bba
--- /dev/null
+++ b/debian/kodi-tools-texturepacker.manpages
@@ -0,0 +1 @@
+docs/manpages/*TexturePacker.1
diff --git a/debian/kodi.install b/debian/kodi.install
new file mode 100644
index 0000000..c98127c
--- /dev/null
+++ b/debian/kodi.install
@@ -0,0 +1,4 @@
+usr/bin/kodi
+usr/bin/kodi-standalone
+usr/share/applications
+usr/share/metainfo
diff --git a/debian/kodi.lintian-overrides b/debian/kodi.lintian-overrides
new file mode 100644
index 0000000..5cb2ecb
--- /dev/null
+++ b/debian/kodi.lintian-overrides
@@ -0,0 +1,5 @@
+# /usr/bin/kodi is a script referencing /usr/lib/$(DEB_ARCH)/kodi
+package-contains-no-arch-dependent-files
+
+# Kodi uses metainfo file to store the info as it is translatable
+desktop-entry-lacks-keywords-entry
diff --git a/debian/kodi.manpages b/debian/kodi.manpages
new file mode 100644
index 0000000..f201e5e
--- /dev/null
+++ b/debian/kodi.manpages
@@ -0,0 +1,2 @@
+docs/manpages/kodi.1
+docs/manpages/kodi-standalone.1
diff --git a/debian/kodi.mime b/debian/kodi.mime
new file mode 100644
index 0000000..ed9a199
--- /dev/null
+++ b/debian/kodi.mime
@@ -0,0 +1,19 @@
+video/mpeg; kodi %s; description="MPEG Video";
+video/x-mpeg; kodi %s; description="MPEG Video";
+video/mpeg-system; kodi %s; description="MPEG Video";
+video/x-mpeg-system; kodi %s; description="MPEG Video";
+audio/x-wav; kodi %s; description="WAV Audio"; nametemplate=%s.wav;
+video/mpeg4; kodi %s; description="MPEG-4 Video";
+audio/mpeg; kodi %s; description="MPEG Audio"; nametemplate=%s.mpg;
+audio/mpegurl; kodi %s; description="MPEG Audio URL"; nametemplate=%s.m3u;
+audio/x-mp3; kodi %s; nametemplate=%s.mp3; description="MPEG Audio";
+audio/mpeg4; kodi %s; description="MPEG-4 Audio";
+application/mpeg4-iod; kodi %s; description="MPEG-4 Video";
+application/mpeg4-muxcodetable; kodi %s; description="MPEG-4 Video";
+video/x-msvideo; kodi %s; description="MS Video (AVI)";
+video/quicktime; kodi %s; description="Apple Quicktime Video";
+application/ogg; kodi %s; nametemplate=%s.ogg; description="Ogg stream";
+application/x-ogg; kodi %s; nametemplate=%s.ogg; description="Ogg stream";
+video/ogg; kodi %s; description="Ogg Video";
+application/x-ms-asf-plugin; kodi %s; description="Windows Media Video";
+application/x-mplayer2; kodi %s; description="Windows Media";
diff --git a/debian/mergefonts.ff b/debian/mergefonts.ff
new file mode 100755
index 0000000..c1a43c0
--- /dev/null
+++ b/debian/mergefonts.ff
@@ -0,0 +1,6 @@
+#!/usr/bin/fontforge
+# merge $1 and $2 to $3 fonts
+Open($1);
+ScaleToEm(2048)
+MergeFonts($2);
+Generate($3);
diff --git a/debian/not-installed b/debian/not-installed
new file mode 100644
index 0000000..a3906d4
--- /dev/null
+++ b/debian/not-installed
@@ -0,0 +1,7 @@
+# README and version.txt are superseded by manpages
+usr/share/doc/kodi/LICENSE.md
+usr/share/doc/kodi/README.Linux.md
+usr/share/doc/kodi/version.txt
+
+# JsonSchemaBuilder is not intended for end-user
+usr/bin/JsonSchemaBuilder
diff --git a/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch b/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch
new file mode 100644
index 0000000..5c553eb
--- /dev/null
+++ b/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch
@@ -0,0 +1,7004 @@
+From c34f01771ab31da1450e0e8aec0dd4654ea5c557 Mon Sep 17 00:00:00 2001
+From: Lukas Rusak <lorusak@gmail.com>
+Date: Mon, 17 Feb 2020 22:41:25 -0800
+Subject: [PATCH 01/19] add support for date library and tzdata
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ CMakeLists.txt | 6 +
+ cmake/modules/FindDate.cmake | 110 ++++++++++++++++++
+ cmake/modules/FindTZData.cmake | 33 ++++++
+ cmake/scripts/linux/Install.cmake | 7 ++
+ .../date/0001-cmake-install-all-headers.patch | 74 ++++++++++++
+ .../target/date/0002-Fix-Android-build.patch | 37 ++++++
+ .../target/date/0003-Fix-UWP-build.patch | 58 +++++++++
+ tools/depends/target/date/DATE-VERSION | 6 +
+ .../target/tzdata/001-cmakelists.patch | 11 ++
+ tools/depends/target/tzdata/TZDATA-VERSION | 5 +
+ 10 files changed, 347 insertions(+)
+ create mode 100644 cmake/modules/FindDate.cmake
+ create mode 100644 cmake/modules/FindTZData.cmake
+ create mode 100644 tools/depends/target/date/0001-cmake-install-all-headers.patch
+ create mode 100644 tools/depends/target/date/0002-Fix-Android-build.patch
+ create mode 100644 tools/depends/target/date/0003-Fix-UWP-build.patch
+ create mode 100644 tools/depends/target/date/DATE-VERSION
+ create mode 100644 tools/depends/target/tzdata/001-cmakelists.patch
+ create mode 100644 tools/depends/target/tzdata/TZDATA-VERSION
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 19881e4708..55344f7626 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -85,6 +85,10 @@ if(UNIX)
+ endif()
+ # prefer kissfft from xbmc/contrib but let use system one on unices
+ cmake_dependent_option(ENABLE_INTERNAL_KISSFFT "Enable internal kissfft?" ON "UNIX" ON)
++# prefer internal date and tzdata but let use system one on unices
++cmake_dependent_option(ENABLE_INTERNAL_DATE "Enable internal date library?" ON "UNIX" ON)
++cmake_dependent_option(ENABLE_INTERNAL_TZDATA "Use Kodi bundled timezone information?" ON "NOT ENABLE_INTERNAL_DATE" ON)
++cmake_dependent_option(DATE_HAS_STRINGVIEW "Is system date library compiled with StringView support?" ON "NOT ENABLE_INTERNAL_DATE" ON)
+ # System options
+ if(NOT WIN32)
+ option(WITH_ARCH "build with given arch" OFF)
+@@ -163,6 +167,7 @@ set(required_deps ASS
+ Cdio
+ CrossGUID
+ Curl
++ Date
+ FFMPEG
+ FlatBuffers
+ Fmt
+@@ -181,6 +186,7 @@ set(required_deps ASS
+ Sqlite3
+ TagLib
+ TinyXML
++ TZData
+ ZLIB
+ ${PLATFORM_REQUIRED_DEPS})
+
+diff --git a/cmake/modules/FindDate.cmake b/cmake/modules/FindDate.cmake
+new file mode 100644
+index 0000000000..61746e4d33
+--- /dev/null
++++ b/cmake/modules/FindDate.cmake
+@@ -0,0 +1,110 @@
++#.rst:
++# FindDate
++# -------
++# Finds the DATE library and builds internal
++# DATE if requested
++#
++# This will define the following variables::
++#
++# DATE_FOUND - system has DATE
++# DATE_INCLUDE_DIRS - the DATE include directory
++# DATE_LIBRARIES - the DATE libraries
++# DATE_DEFINITIONS - the DATE definitions
++#
++# and the following imported targets::
++#
++# Date::Date - The Date library
++
++if(ENABLE_INTERNAL_DATE)
++ include(cmake/scripts/common/ModuleHelpers.cmake)
++
++ set(MODULE_LC date)
++
++ SETUP_BUILD_VARS()
++
++ set(DATE_VERSION ${${MODULE}_VER})
++
++ # Debug postfix only used for windows
++ if(WIN32 OR WINDOWS_STORE)
++ set(DATE_DEBUG_POSTFIX "d")
++ endif()
++
++ # Propagate CMake definitions
++
++ if(CORE_SYSTEM_NAME STREQUAL darwin_embedded)
++ set(EXTRA_ARGS -DIOS=ON)
++ elseif(WINDOWS_STORE)
++ set(EXTRA_ARGS -DWINRT=ON)
++ endif()
++
++ set(CMAKE_ARGS -DCMAKE_CXX_STANDARD=17
++ -DUSE_SYSTEM_TZ_DB=OFF
++ -DMANUAL_TZ_DB=ON
++ -DUSE_TZ_DB_IN_DOT=OFF
++ -DBUILD_SHARED_LIBS=OFF
++ -DBUILD_TZ_LIB=ON
++ ${EXTRA_ARGS})
++
++ # Work around old release
++
++ file(GLOB patches "${CMAKE_SOURCE_DIR}/tools/depends/target/date/*.patch")
++
++ generate_patchcommand("${patches}")
++
++ BUILD_DEP_TARGET()
++else()
++ if(PKG_CONFIG_FOUND)
++ pkg_check_modules(PC_DATE libdate-tz>=3.0.1 QUIET)
++ endif()
++
++ find_path(DATE_INCLUDE_DIR date/date.h
++ PATHS ${PC_DATE_INCLUDEDIR})
++ find_library(DATE_LIBRARY_RELEASE NAMES date-tz libdate-tz
++ PATHS ${PC_DATE_LIBDIR})
++ find_library(DATE_LIBRARY_DEBUG NAMES date-tzd libdate-tzd
++ PATHS ${PC_DATE_LIBDIR})
++ set(DATE_VERSION ${PC_DATE_VERSION})
++endif()
++
++include(SelectLibraryConfigurations)
++select_library_configurations(DATE)
++
++include(FindPackageHandleStandardArgs)
++find_package_handle_standard_args(Date
++ REQUIRED_VARS DATE_LIBRARY DATE_INCLUDE_DIR
++ VERSION_VAR DATE_VERSION)
++
++if(DATE_FOUND)
++ set(DATE_INCLUDE_DIRS ${DATE_INCLUDE_DIR})
++ set(DATE_LIBRARIES ${DATE_LIBRARY})
++
++ if(ENABLE_INTERNAL_TZDATA)
++ set(DATE_DEFINITIONS ${DATE_DEFINITIONS} -DDATE_INTERNAL_TZDATA)
++ endif()
++
++ if(DATE_HAS_STRINGVIEW)
++ set(DATE_DEFINITIONS ${DATE_DEFINITIONS} -DDATE_HAS_STRINGVIEW)
++ endif()
++
++ if(NOT TARGET Date::Date)
++ add_library(Date::Date UNKNOWN IMPORTED)
++ if(DATE_LIBRARY_RELEASE)
++ set_target_properties(Date::Date PROPERTIES
++ IMPORTED_CONFIGURATIONS RELEASE
++ IMPORTED_LOCATION "${DATE_LIBRARY_RELEASE}")
++ endif()
++ if(DATE_LIBRARY_DEBUG)
++ set_target_properties(Date::Date PROPERTIES
++ IMPORTED_CONFIGURATIONS DEBUG
++ IMPORTED_LOCATION "${DATE_LIBRARY_DEBUG}")
++ endif()
++ set_target_properties(Date::Date PROPERTIES
++ INTERFACE_INCLUDE_DIRECTORIES "${DATE_INCLUDE_DIR}")
++ if(TARGET date)
++ add_dependencies(Date::Date date)
++ endif()
++ endif()
++ set_property(GLOBAL APPEND PROPERTY INTERNAL_DEPS_PROP Date::Date)
++endif()
++
++mark_as_advanced(DATE_INCLUDE_DIR DATE_LIBRARY)
+diff --git a/cmake/modules/FindTZData.cmake b/cmake/modules/FindTZData.cmake
+new file mode 100644
+index 0000000000..b7241a6b04
+--- /dev/null
++++ b/cmake/modules/FindTZData.cmake
+@@ -0,0 +1,33 @@
++#.rst:
++# FindTZData
++# -------
++# Populates resource.timezone with TZDATA if requested
++#
++# This will define the following variables::
++#
++# TZDATA_FOUND - system has internal TZDATA
++# TZDATA_VERSION - version of internal TZDATA
++
++if(ENABLE_INTERNAL_TZDATA)
++ include(cmake/scripts/common/ModuleHelpers.cmake)
++
++ set(MODULE_LC tzdata)
++
++ SETUP_BUILD_VARS()
++
++ # Mirror tzdata to resource.timezone
++
++ set(CMAKE_ARGS -DINSTALL_DIR=${CMAKE_BINARY_DIR}/addons/resource.timezone/resources/tzdata)
++
++ # Add CMakeLists.txt installing sources as target
++
++ set(patches ${CMAKE_SOURCE_DIR}/tools/depends/target/tzdata/001-cmakelists.patch)
++
++ generate_patchcommand("${patches}")
++
++ BUILD_DEP_TARGET()
++else()
++ set(TZDATA_VERSION "none")
++endif()
++
++set(TZDATA_FOUND TRUE)
+diff --git a/cmake/scripts/linux/Install.cmake b/cmake/scripts/linux/Install.cmake
+index 331722cb56..e3ceacbf76 100644
+--- a/cmake/scripts/linux/Install.cmake
++++ b/cmake/scripts/linux/Install.cmake
+@@ -85,6 +85,13 @@ foreach(file ${install_data})
+ COMPONENT kodi)
+ endforeach()
+
++# Install timezone resources
++if(ENABLE_INTERNAL_TZDATA)
++ install(DIRECTORY ${CMAKE_BINARY_DIR}/addons/resource.timezone/resources/tzdata
++ DESTINATION ${datarootdir}/${APP_NAME_LC}/addons/resource.timezone/resources
++ COMPONENT kodi)
++endif()
++
+ # Install xsession entry
+ install(FILES ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${APP_NAME_LC}-xsession.desktop
+ RENAME ${APP_NAME_LC}.desktop
+diff --git a/tools/depends/target/date/0001-cmake-install-all-headers.patch b/tools/depends/target/date/0001-cmake-install-all-headers.patch
+new file mode 100644
+index 0000000000..e8ac76a48b
+--- /dev/null
++++ b/tools/depends/target/date/0001-cmake-install-all-headers.patch
+@@ -0,0 +1,74 @@
++From 8b3fac88cb5e4fef81b55b7537232a6418752153 Mon Sep 17 00:00:00 2001
++From: Andrea Pappacoda <andrea@pappacoda.it>
++Date: Thu, 4 Aug 2022 11:35:41 +0200
++Subject: [PATCH 1/4] cmake: install all headers
++
++Lazy solution: mark all headers as either PUBLIC_ or PRIVATE_HEADER,
++requiring CMake 3.15.
++
++Bug: https://github.com/HowardHinnant/date/pull/503
++Bug-Debian: https://bugs.debian.org/1001895
++---
++ CMakeLists.txt | 20 +++++++++++++++-----
++ 1 file changed, 15 insertions(+), 5 deletions(-)
++
++diff --git a/CMakeLists.txt b/CMakeLists.txt
++index 012512a..c0bda7f 100644
++--- a/CMakeLists.txt
+++++ b/CMakeLists.txt
++@@ -75,7 +75,13 @@ target_sources( date INTERFACE
++ )
++ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
++ # public headers will get installed:
++- set_target_properties( date PROPERTIES PUBLIC_HEADER include/date/date.h )
+++ set_property(TARGET date PROPERTY PUBLIC_HEADER
+++ include/date/date.h
+++ include/date/islamic.h
+++ include/date/iso_week.h
+++ include/date/julian.h
+++ include/date/solar_hijri.h
+++ )
++ endif ()
++
++ # These used to be set with generator expressions,
++@@ -137,14 +143,16 @@ if( BUILD_TZ_LIB )
++ target_compile_definitions( date-tz PUBLIC DATE_BUILD_DLL=1 )
++ endif()
++
++- set(TZ_HEADERS include/date/tz.h)
+++ set(TZ_PUBLIC_HEADERS include/date/ptz.h include/date/tz.h)
+++ set(TZ_PRIVATE_HEADERS include/date/tz_private.h)
++
++ if( IOS )
++- list(APPEND TZ_HEADERS include/date/ios.h)
+++ list(APPEND TZ_PRIVATE_HEADERS include/date/ios.h)
++ endif( )
++ set_target_properties( date-tz PROPERTIES
++ POSITION_INDEPENDENT_CODE ON
++- PUBLIC_HEADER "${TZ_HEADERS}"
+++ PUBLIC_HEADER "${TZ_PUBLIC_HEADERS}"
+++ PRIVATE_HEADER "${TZ_PRIVATE_HEADERS}"
++ VERSION "${PROJECT_VERSION}"
++ SOVERSION "${ABI_VERSION}" )
++ if( NOT MSVC )
++@@ -170,7 +178,8 @@ write_basic_package_version_file( "${version_config}"
++
++ install( TARGETS date
++ EXPORT dateConfig
++- PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date )
+++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date
+++ PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date )
++ export( TARGETS date NAMESPACE date:: FILE dateTargets.cmake )
++ if (CMAKE_VERSION VERSION_LESS 3.15)
++ install(
++@@ -182,6 +191,7 @@ if( BUILD_TZ_LIB )
++ install( TARGETS date-tz
++ EXPORT dateConfig
++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date
+++ PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date
++ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
++ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # This is for Windows
++--
++2.39.0
++
+diff --git a/tools/depends/target/date/0002-Fix-Android-build.patch b/tools/depends/target/date/0002-Fix-Android-build.patch
+new file mode 100644
+index 0000000000..e497b41bcf
+--- /dev/null
++++ b/tools/depends/target/date/0002-Fix-Android-build.patch
+@@ -0,0 +1,37 @@
++From 5790d6aed57bda1dc1577860d8382678100ebfa3 Mon Sep 17 00:00:00 2001
++From: Vasyl Gello <vasek.gello@gmail.com>
++Date: Wed, 11 Jan 2023 11:35:41 +0200
++Subject: [PATCH 2/4] Fix Android build
++
++Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
++---
++ src/tz.cpp | 6 ++++--
++ 1 file changed, 4 insertions(+), 2 deletions(-)
++
++diff --git a/src/tz.cpp b/src/tz.cpp
++index 26babbd..69bab7c 100644
++--- a/src/tz.cpp
+++++ b/src/tz.cpp
++@@ -141,7 +141,7 @@
++ # endif // HAS_REMOTE_API
++ #else // !_WIN32
++ # include <unistd.h>
++-# if !USE_OS_TZDB && !defined(INSTALL)
+++# if !USE_OS_TZDB && !defined(INSTALL) && !defined(__ANDROID__)
++ # include <wordexp.h>
++ # endif
++ # include <limits.h>
++@@ -245,7 +245,9 @@ expand_path(std::string path)
++ {
++ # if TARGET_OS_IPHONE
++ return date::iOSUtils::get_tzdata_path();
++-# else // !TARGET_OS_IPHONE
+++# elif defined(__ANDROID__)
+++ return "/data/local/tmp";
+++# else // !TARGET_OS_IPHONE && !__ANDROID__
++ ::wordexp_t w{};
++ std::unique_ptr<::wordexp_t, void(*)(::wordexp_t*)> hold{&w, ::wordfree};
++ ::wordexp(path.c_str(), &w, 0);
++--
++2.39.0
++
+diff --git a/tools/depends/target/date/0003-Fix-UWP-build.patch b/tools/depends/target/date/0003-Fix-UWP-build.patch
+new file mode 100644
+index 0000000000..683ed4126d
+--- /dev/null
++++ b/tools/depends/target/date/0003-Fix-UWP-build.patch
+@@ -0,0 +1,58 @@
++From 1e512b082eb99b5d9cd790158f3bdaefcbac823d Mon Sep 17 00:00:00 2001
++From: Vasyl Gello <vasek.gello@gmail.com>
++Date: Wed, 11 Jan 2023 09:58:34 +0200
++Subject: [PATCH 3/4] Fix UWP build
++
++We don't need download_folder to be determined.
++Bringing full UWP runtime just for that is an overkill.
++---
++ CMakeLists.txt | 4 ++++
++ src/tz.cpp | 17 +++++++++++++++++
++ 2 files changed, 21 insertions(+)
++
++diff --git a/CMakeLists.txt b/CMakeLists.txt
++index c0bda7f..0fa3dc2 100644
++--- a/CMakeLists.txt
+++++ b/CMakeLists.txt
++@@ -133,6 +133,10 @@ if( BUILD_TZ_LIB )
++ target_compile_definitions( date-tz PRIVATE AUTO_DOWNLOAD=1 HAS_REMOTE_API=1 )
++ endif()
++
+++ if(WINRT)
+++ target_compile_definitions( date-tz PRIVATE WINRT=1 INSTALL=. )
+++ endif()
+++
++ if ( USE_SYSTEM_TZ_DB AND NOT WIN32 AND NOT MANUAL_TZ_DB )
++ target_compile_definitions( date-tz PRIVATE INSTALL=. PUBLIC USE_OS_TZDB=1 )
++ else()
++diff --git a/src/tz.cpp b/src/tz.cpp
++index 69bab7c..aa15192 100644
++--- a/src/tz.cpp
+++++ b/src/tz.cpp
++@@ -234,6 +234,23 @@ get_download_folder()
++
++ # endif // !INSTALL
++
+++# else // WINRT
+++static
+++std::string
+++get_program_folder()
+++{
+++ return "";
+++}
+++
+++# ifndef INSTALL
+++
+++static
+++std::string
+++get_download_folder()
+++{
+++ return "";
+++}
+++# endif // !INSTALL
++ # endif // WINRT
++ # else // !_WIN32
++
++--
++2.39.0
++
+diff --git a/tools/depends/target/date/DATE-VERSION b/tools/depends/target/date/DATE-VERSION
+new file mode 100644
+index 0000000000..0608029104
+--- /dev/null
++++ b/tools/depends/target/date/DATE-VERSION
+@@ -0,0 +1,6 @@
++LIBNAME=date
++VERSION=3.0.1
++ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz
++SHA512=6bdc7cba821d66e17a559250cc0ce0095808e9db81cec9e16eaa4c31abdfa705299c67b72016d9b06b302bc306d063e83a374eb00728071b83a5ad650d59034f
++BYPRODUCT=libdate-tz.a
++BYPRODUCT_WIN=date-tz.lib
+diff --git a/tools/depends/target/tzdata/001-cmakelists.patch b/tools/depends/target/tzdata/001-cmakelists.patch
+new file mode 100644
+index 0000000000..dda65fc542
+--- /dev/null
++++ b/tools/depends/target/tzdata/001-cmakelists.patch
+@@ -0,0 +1,11 @@
++diff --git a/CMakeLists.txt b/CMakeLists.txt
++new file mode 100644
++index 0000000..8a015cd
++--- /dev/null
+++++ b/CMakeLists.txt
++@@ -0,0 +1,5 @@
+++cmake_minimum_required(VERSION 3.2)
+++
+++project(kodi-tzdata)
+++
+++install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${INSTALL_DIR})
+diff --git a/tools/depends/target/tzdata/TZDATA-VERSION b/tools/depends/target/tzdata/TZDATA-VERSION
+new file mode 100644
+index 0000000000..7f92f0b74c
+--- /dev/null
++++ b/tools/depends/target/tzdata/TZDATA-VERSION
+@@ -0,0 +1,5 @@
++LIBNAME=tzdata
++VERSION=2022g
++ARCHIVE=$(LIBNAME)$(VERSION).tar.gz
++SHA512=7f79394295e00e3a24ebdbf9af3bc454a65f432a93b517e7e96c7f9db9949f6f5fdae9892a9d3789ff44ae0eb1bfe4744d36976b4624659af951d26414f94e65
++SOURCE_DIR=addons/resource.timezone/resources/tzdata
+--
+2.43.0
+
+
+From b4a3fafe6da802ae1d690ceb07fbf5a781e0301a Mon Sep 17 00:00:00 2001
+From: Lukas Rusak <lorusak@gmail.com>
+Date: Tue, 17 Mar 2020 13:12:04 -0700
+Subject: [PATCH 02/19] add resource.timezone
+
+---
+ addons/kodi.resource/addon.xml | 1 +
+ addons/kodi.resource/timezone.xsd | 16 ++++++++++++
+ addons/resource.timezone/addon.xml | 12 +++++++++
+ cmake/installdata/common/addons.txt | 1 +
+ system/addon-manifest.xml | 1 +
+ xbmc/ServiceManager.cpp | 20 +++++++++++++++
+ xbmc/addons/AddonBuilder.cpp | 3 +++
+ xbmc/addons/CMakeLists.txt | 2 ++
+ xbmc/addons/TimeZoneResource.cpp | 39 +++++++++++++++++++++++++++++
+ xbmc/addons/TimeZoneResource.h | 25 ++++++++++++++++++
+ xbmc/addons/addoninfo/AddonInfo.cpp | 3 ++-
+ xbmc/addons/addoninfo/AddonType.h | 1 +
+ xbmc/application/Application.cpp | 20 +++++++++++++++
+ 13 files changed, 143 insertions(+), 1 deletion(-)
+ create mode 100644 addons/kodi.resource/timezone.xsd
+ create mode 100644 addons/resource.timezone/addon.xml
+ create mode 100644 xbmc/addons/TimeZoneResource.cpp
+ create mode 100644 xbmc/addons/TimeZoneResource.h
+
+diff --git a/addons/kodi.resource/addon.xml b/addons/kodi.resource/addon.xml
+index 2bb3221b42..b615575744 100644
+--- a/addons/kodi.resource/addon.xml
++++ b/addons/kodi.resource/addon.xml
+@@ -7,4 +7,5 @@
+ <extension-point id="resource.language" schema="language.xsd"/>
+ <extension-point id="resource.uisounds" schema="uisounds.xsd"/>
+ <extension-point id="resource.images" schema="images.xsd"/>
++ <extension-point id="resource.timezone" schema="timezone.xsd"/>
+ </addon>
+diff --git a/addons/kodi.resource/timezone.xsd b/addons/kodi.resource/timezone.xsd
+new file mode 100644
+index 0000000000..990f8893ea
+--- /dev/null
++++ b/addons/kodi.resource/timezone.xsd
+@@ -0,0 +1,16 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd">
++<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
++ <xs:element name="extension">
++ <xs:complexType>
++ <xs:attribute name="point" type="xs:string" use="required"/>
++ <xs:attribute name="id" type="simpleIdentifier"/>
++ <xs:attribute name="name" type="xs:string"/>
++ </xs:complexType>
++ </xs:element>
++ <xs:simpleType name="simpleIdentifier">
++ <xs:restriction base="xs:string">
++ <xs:pattern value="kodi\.resource\.timezone"/>
++ </xs:restriction>
++ </xs:simpleType>
++</xs:schema>
+diff --git a/addons/resource.timezone/addon.xml b/addons/resource.timezone/addon.xml
+new file mode 100644
+index 0000000000..174b3f5687
+--- /dev/null
++++ b/addons/resource.timezone/addon.xml
+@@ -0,0 +1,12 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<addon id="resource.timezone" version="1.0.0" name="Kodi Timezone Database" provider-name="Team Kodi">
++ <requires>
++ <import addon="kodi.resource" version="1.0.0"/>
++ </requires>
++ <extension point="kodi.resource.timezone"/>
++ <extension point="kodi.addon.metadata">
++ <summary lang="en_GB">Kodi Timezone Database</summary>
++ <description lang="en_GB">Kodi Timezone Database</description>
++ <platform>all</platform>
++ </extension>
++</addon>
+diff --git a/cmake/installdata/common/addons.txt b/cmake/installdata/common/addons.txt
+index 263e57bb66..0411f8a3da 100644
+--- a/cmake/installdata/common/addons.txt
++++ b/cmake/installdata/common/addons.txt
+@@ -26,6 +26,7 @@ addons/metadata.tvshows.themoviedb.org.python/*
+ addons/repository.xbmc.org/*
+ addons/resource.images.weathericons.default/*
+ addons/resource.language.en_gb/*
++addons/resource.timezone/*
+ addons/resource.uisounds.kodi/*
+ addons/screensaver.xbmc.builtin.black/*
+ addons/screensaver.xbmc.builtin.dim/*
+diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml
+index 7df13a6d6f..842e4e8206 100644
+--- a/system/addon-manifest.xml
++++ b/system/addon-manifest.xml
+@@ -38,6 +38,7 @@
+ <addon optional="true">repository.xbmc.org</addon>
+ <addon>resource.images.weathericons.default</addon>
+ <addon>resource.language.en_gb</addon>
++ <addon>resource.timezone</addon>
+ <addon>resource.uisounds.kodi</addon>
+ <addon>screensaver.xbmc.builtin.black</addon>
+ <addon>screensaver.xbmc.builtin.dim</addon>
+diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp
+index 02d9900e9b..83070489e3 100644
+--- a/xbmc/ServiceManager.cpp
++++ b/xbmc/ServiceManager.cpp
+@@ -17,6 +17,7 @@
+ #include "addons/RepositoryUpdater.h"
+ #include "addons/Service.h"
+ #include "addons/VFSEntry.h"
++#include "addons/addoninfo/AddonType.h"
+ #include "addons/binary-addons/BinaryAddonManager.h"
+ #include "cores/DataCacheCore.h"
+ #include "cores/RetroPlayer/guibridge/GUIGameRenderManager.h"
+@@ -45,9 +46,14 @@
+ #endif
+ #include "storage/MediaManager.h"
+ #include "utils/FileExtensionProvider.h"
++#include "utils/URIUtils.h"
+ #include "utils/log.h"
+ #include "weather/WeatherManager.h"
+
++#define USE_OS_TZDB 0
++#define HAS_REMOTE_API 0
++#include <date/tz.h>
++
+ using namespace KODI;
+
+ CServiceManager::CServiceManager() = default;
+@@ -79,6 +85,20 @@ bool CServiceManager::InitForTesting()
+ m_extsMimeSupportList.reset(new ADDONS::CExtsMimeSupportList(*m_addonMgr));
+ m_fileExtensionProvider.reset(new CFileExtensionProvider(*m_addonMgr));
+
++#if defined(DATE_INTERNAL_TZDATA)
++ ADDON::AddonPtr addon;
++ if (!m_addonMgr->GetAddon("resource.timezone", addon, ADDON::AddonType::RESOURCE_TIMEZONE,
++ ADDON::OnlyEnabled::CHOICE_YES))
++ {
++ CLog::LogF(LOGFATAL, "failed to find resource.timezone");
++ return false;
++ }
++
++ std::string tzdataPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "tzdata");
++ CLog::LogF(LOGDEBUG, "tzdata path: {}", tzdataPath);
++ date::set_install(tzdataPath);
++#endif
++
+ init_level = 1;
+ return true;
+ }
+diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp
+index 7d52ee0431..dd72a08705 100644
+--- a/xbmc/addons/AddonBuilder.cpp
++++ b/xbmc/addons/AddonBuilder.cpp
+@@ -19,6 +19,7 @@
+ #include "addons/Scraper.h"
+ #include "addons/Service.h"
+ #include "addons/Skin.h"
++#include "addons/TimeZoneResource.h"
+ #include "addons/UISoundsResource.h"
+ #include "addons/Webinterface.h"
+ #include "addons/addoninfo/AddonInfo.h"
+@@ -106,6 +107,8 @@ AddonPtr CAddonBuilder::Generate(const AddonInfoPtr& info, AddonType type)
+ return std::make_shared<CLanguageResource>(info);
+ case AddonType::RESOURCE_UISOUNDS:
+ return std::make_shared<CUISoundsResource>(info);
++ case AddonType::RESOURCE_TIMEZONE:
++ return std::make_shared<CTimeZoneResource>(info);
+ case AddonType::REPOSITORY:
+ return std::make_shared<CRepository>(info);
+ case AddonType::CONTEXTMENU_ITEM:
+diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt
+index 947a885b4c..101371f12d 100644
+--- a/xbmc/addons/CMakeLists.txt
++++ b/xbmc/addons/CMakeLists.txt
+@@ -26,6 +26,7 @@ set(SOURCES Addon.cpp
+ ScreenSaver.cpp
+ Service.cpp
+ Skin.cpp
++ TimeZoneResource.cpp
+ UISoundsResource.cpp
+ VFSEntry.cpp
+ Visualization.cpp
+@@ -66,6 +67,7 @@ set(HEADERS Addon.h
+ ScreenSaver.h
+ Service.h
+ Skin.h
++ TimeZoneResource.h
+ UISoundsResource.h
+ VFSEntry.h
+ Visualization.h
+diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp
+new file mode 100644
+index 0000000000..94246c9e18
+--- /dev/null
++++ b/xbmc/addons/TimeZoneResource.cpp
+@@ -0,0 +1,39 @@
++/*
++ * Copyright (C) 2015-2018 Team Kodi
++ * This file is part of Kodi - https://kodi.tv
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ * See LICENSES/README.md for more information.
++ */
++#include "TimeZoneResource.h"
++
++#include "addons/addoninfo/AddonType.h"
++#include "utils/StringUtils.h"
++#include "utils/URIUtils.h"
++
++#include <date/tz.h>
++
++namespace ADDON
++{
++
++CTimeZoneResource::CTimeZoneResource(const AddonInfoPtr& addonInfo)
++ : CResource(addonInfo, AddonType::RESOURCE_TIMEZONE)
++{
++}
++
++bool CTimeZoneResource::IsAllowed(const std::string& file) const
++{
++ return true;
++}
++
++bool CTimeZoneResource::IsInUse() const
++{
++ return true;
++}
++
++void CTimeZoneResource::OnPostInstall(bool update, bool modal)
++{
++ date::reload_tzdb();
++}
++
++} // namespace ADDON
+diff --git a/xbmc/addons/TimeZoneResource.h b/xbmc/addons/TimeZoneResource.h
+new file mode 100644
+index 0000000000..a979f05dec
+--- /dev/null
++++ b/xbmc/addons/TimeZoneResource.h
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (C) 2015-2018 Team Kodi
++ * This file is part of Kodi - https://kodi.tv
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ * See LICENSES/README.md for more information.
++ */
++
++#pragma once
++
++#include "addons/Resource.h"
++
++namespace ADDON
++{
++
++class CTimeZoneResource : public CResource
++{
++public:
++ explicit CTimeZoneResource(const AddonInfoPtr& addonInfo);
++ bool IsAllowed(const std::string& file) const override;
++ bool IsInUse() const override;
++ void OnPostInstall(bool update, bool modal) override;
++};
++
++} // namespace ADDON
+diff --git a/xbmc/addons/addoninfo/AddonInfo.cpp b/xbmc/addons/addoninfo/AddonInfo.cpp
+index 61bc087443..f82a947981 100644
+--- a/xbmc/addons/addoninfo/AddonInfo.cpp
++++ b/xbmc/addons/addoninfo/AddonInfo.cpp
+@@ -37,7 +37,7 @@ typedef struct
+ } TypeMapping;
+
+ // clang-format off
+-static constexpr const std::array<TypeMapping, 40> types =
++static constexpr const std::array<TypeMapping, 41> types =
+ {{
+ {"unknown", "", AddonType::UNKNOWN, 0, AddonInstanceSupport::SUPPORT_NONE, "" },
+ {"xbmc.metadata.scraper.albums", "", AddonType::SCRAPER_ALBUMS, 24016, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonAlbumInfo.png" },
+@@ -73,6 +73,7 @@ static constexpr const std::array<TypeMapping, 40> types =
+ {"xbmc.service", "", AddonType::SERVICE, 24018, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonService.png" },
+ {"kodi.resource.images", "", AddonType::RESOURCE_IMAGES, 24035, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonImages.png" },
+ {"kodi.resource.language", "", AddonType::RESOURCE_LANGUAGE, 24026, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonLanguage.png" },
++ {"kodi.resource.timezone", "", AddonType::RESOURCE_TIMEZONE, 24026, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonTimeZone.png" },
+ {"kodi.resource.uisounds", "", AddonType::RESOURCE_UISOUNDS, 24006, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonUISounds.png" },
+ {"kodi.resource.games", "", AddonType::RESOURCE_GAMES, 35209, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonGame.png" },
+ {"kodi.resource.font", "", AddonType::RESOURCE_FONT, 13303, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonFont.png" },
+diff --git a/xbmc/addons/addoninfo/AddonType.h b/xbmc/addons/addoninfo/AddonType.h
+index 9a0ee260cf..27f49e3138 100644
+--- a/xbmc/addons/addoninfo/AddonType.h
++++ b/xbmc/addons/addoninfo/AddonType.h
+@@ -46,6 +46,7 @@ enum class AddonType
+ AUDIODECODER,
+ RESOURCE_IMAGES,
+ RESOURCE_LANGUAGE,
++ RESOURCE_TIMEZONE,
+ RESOURCE_UISOUNDS,
+ RESOURCE_GAMES,
+ RESOURCE_FONT,
+diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp
+index 0765cf3723..ea1b152dfd 100644
+--- a/xbmc/application/Application.cpp
++++ b/xbmc/application/Application.cpp
+@@ -195,8 +195,12 @@
+ #include "pictures/GUIWindowSlideShow.h"
+ #include "utils/CharsetConverter.h"
+
++#define USE_OS_TZDB 0
++#define HAS_REMOTE_API 0
+ #include <mutex>
+
++#include <date/tz.h>
++
+ using namespace ADDON;
+ using namespace XFILE;
+ #ifdef HAS_DVD_DRIVE
+@@ -435,6 +439,22 @@ bool CApplication::Create()
+ return false;
+ }
+
++ // Load timezone information
++#if defined(DATE_INTERNAL_TZDATA)
++ ADDON::AddonPtr addon;
++ if (!CServiceBroker::GetAddonMgr().GetAddon("resource.timezone", addon,
++ ADDON::AddonType::RESOURCE_TIMEZONE,
++ ADDON::OnlyEnabled::CHOICE_YES))
++ {
++ CLog::LogF(LOGFATAL, "failed to find resource.timezone");
++ return false;
++ }
++
++ std::string tzdataPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "tzdata");
++ CLog::LogF(LOGDEBUG, "tzdata path: {}", tzdataPath);
++ date::set_install(tzdataPath);
++#endif
++
+ m_pActiveAE.reset(new ActiveAE::CActiveAE());
+ CServiceBroker::RegisterAE(m_pActiveAE.get());
+
+--
+2.43.0
+
+
+From 6f004e0aa809505cbf71612df44343a15011d0cf Mon Sep 17 00:00:00 2001
+From: Lukas Rusak <lorusak@gmail.com>
+Date: Mon, 10 Feb 2020 15:13:43 -0800
+Subject: [PATCH 03/19] CDateTime: convert to use std::chrono
+
+---
+ xbmc/XBDateTime.cpp | 604 ++++++++--------------
+ xbmc/XBDateTime.h | 31 +-
+ xbmc/platform/posix/PosixTimezone.cpp | 3 -
+ xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp | 2 -
+ 4 files changed, 244 insertions(+), 396 deletions(-)
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index 85d5d466d3..47c6b8d1a6 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -17,29 +17,17 @@
+
+ #include <cstdlib>
+
+-#define SECONDS_PER_DAY 86400L
+-#define SECONDS_PER_HOUR 3600L
+-#define SECONDS_PER_MINUTE 60L
+-#define SECONDS_TO_FILETIME 10000000L
++#define USE_OS_TZDB 0
++#define HAS_REMOTE_API 0
++#include <date/date.h>
++#include <date/iso_week.h>
++#include <date/tz.h>
+
+-static const char *DAY_NAMES[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+ static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+-/////////////////////////////////////////////////
+-//
+-// CDateTimeSpan
+-//
+-
+-CDateTimeSpan::CDateTimeSpan()
+-{
+- m_timeSpan.highDateTime = 0;
+- m_timeSpan.lowDateTime = 0;
+-}
+-
+ CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span)
+ {
+- m_timeSpan.highDateTime = span.m_timeSpan.highDateTime;
+- m_timeSpan.lowDateTime = span.m_timeSpan.lowDateTime;
++ m_timeSpan = span.m_timeSpan;
+ }
+
+ CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second)
+@@ -49,7 +37,7 @@ CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second)
+
+ bool CDateTimeSpan::operator >(const CDateTimeSpan& right) const
+ {
+- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) > 0;
++ return m_timeSpan > right.m_timeSpan;
+ }
+
+ bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const
+@@ -59,7 +47,7 @@ bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const
+
+ bool CDateTimeSpan::operator <(const CDateTimeSpan& right) const
+ {
+- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) < 0;
++ return m_timeSpan < right.m_timeSpan;
+ }
+
+ bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const
+@@ -69,7 +57,7 @@ bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const
+
+ bool CDateTimeSpan::operator ==(const CDateTimeSpan& right) const
+ {
+- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) == 0;
++ return m_timeSpan == right.m_timeSpan;
+ }
+
+ bool CDateTimeSpan::operator !=(const CDateTimeSpan& right) const
+@@ -81,15 +69,7 @@ CDateTimeSpan CDateTimeSpan::operator +(const CDateTimeSpan& right) const
+ {
+ CDateTimeSpan left(*this);
+
+- LARGE_INTEGER timeLeft;
+- left.ToLargeInt(timeLeft);
+-
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
+-
+- timeLeft.QuadPart+=timeRight.QuadPart;
+-
+- left.FromLargeInt(timeLeft);
++ left.m_timeSpan += right.m_timeSpan;
+
+ return left;
+ }
+@@ -98,122 +78,75 @@ CDateTimeSpan CDateTimeSpan::operator -(const CDateTimeSpan& right) const
+ {
+ CDateTimeSpan left(*this);
+
+- LARGE_INTEGER timeLeft;
+- left.ToLargeInt(timeLeft);
+-
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
+-
+- timeLeft.QuadPart-=timeRight.QuadPart;
+-
+- left.FromLargeInt(timeLeft);
++ left.m_timeSpan -= right.m_timeSpan;
+
+ return left;
+ }
+
+ const CDateTimeSpan& CDateTimeSpan::operator +=(const CDateTimeSpan& right)
+ {
+- LARGE_INTEGER timeThis;
+- ToLargeInt(timeThis);
+-
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
+-
+- timeThis.QuadPart+=timeRight.QuadPart;
+-
+- FromLargeInt(timeThis);
++ m_timeSpan += right.m_timeSpan;
+
+ return *this;
+ }
+
+ const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right)
+ {
+- LARGE_INTEGER timeThis;
+- ToLargeInt(timeThis);
+-
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
+-
+- timeThis.QuadPart-=timeRight.QuadPart;
+-
+- FromLargeInt(timeThis);
++ m_timeSpan -= right.m_timeSpan;
+
+ return *this;
+ }
+
+-void CDateTimeSpan::ToLargeInt(LARGE_INTEGER& time) const
+-{
+- time.u.HighPart = m_timeSpan.highDateTime;
+- time.u.LowPart = m_timeSpan.lowDateTime;
+-}
+-
+-void CDateTimeSpan::FromLargeInt(const LARGE_INTEGER& time)
+-{
+- m_timeSpan.highDateTime = time.u.HighPart;
+- m_timeSpan.lowDateTime = time.u.LowPart;
+-}
+-
+ void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second)
+ {
+- LARGE_INTEGER time;
+- ToLargeInt(time);
+-
+- time.QuadPart= static_cast<long long>(day) *SECONDS_PER_DAY*SECONDS_TO_FILETIME;
+- time.QuadPart+= static_cast<long long>(hour) *SECONDS_PER_HOUR*SECONDS_TO_FILETIME;
+- time.QuadPart+= static_cast<long long>(minute) *SECONDS_PER_MINUTE*SECONDS_TO_FILETIME;
+- time.QuadPart+= static_cast<long long>(second) *SECONDS_TO_FILETIME;
+-
+- FromLargeInt(time);
++ m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(date::days(day)) +
++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(hour)) +
++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::minutes(minute)) +
++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::seconds(second));
+ }
+
+ void CDateTimeSpan::SetFromTimeString(const std::string& time) // hh:mm
+ {
+ if (time.size() >= 5 && time[2] == ':')
+ {
+- int hour = atoi(time.substr(0, 2).c_str());
+- int minutes = atoi(time.substr(3, 2).c_str());
+- SetDateTimeSpan(0,hour,minutes,0);
++ int hour = std::stoi(time.substr(0, 2));
++ int minutes = std::stoi(time.substr(3, 2));
++ SetDateTimeSpan(0, hour, minutes, 0);
+ }
+ }
+
+ int CDateTimeSpan::GetDays() const
+ {
+- LARGE_INTEGER time;
+- ToLargeInt(time);
+-
+- return (int)(time.QuadPart/SECONDS_TO_FILETIME)/SECONDS_PER_DAY;
++ return date::floor<date::days>(m_timeSpan).count();
+ }
+
+ int CDateTimeSpan::GetHours() const
+ {
+- LARGE_INTEGER time;
+- ToLargeInt(time);
++ auto time = date::floor<date::days>(m_timeSpan);
++ auto dp = date::make_time(m_timeSpan - time);
+
+- return (int)((time.QuadPart/SECONDS_TO_FILETIME)%SECONDS_PER_DAY)/SECONDS_PER_HOUR;
++ return dp.hours().count();
+ }
+
+ int CDateTimeSpan::GetMinutes() const
+ {
+- LARGE_INTEGER time;
+- ToLargeInt(time);
++ auto time = date::floor<date::days>(m_timeSpan);
++ auto dp = date::make_time(m_timeSpan - time);
+
+- return (int)((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)/SECONDS_PER_MINUTE;
++ return dp.minutes().count();
+ }
+
+ int CDateTimeSpan::GetSeconds() const
+ {
+- LARGE_INTEGER time;
+- ToLargeInt(time);
++ auto time = date::floor<date::days>(m_timeSpan);
++ auto dp = date::make_time(m_timeSpan - time);
+
+- return (int)(((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)%SECONDS_PER_MINUTE)%SECONDS_PER_MINUTE;
++ return dp.seconds().count();
+ }
+
+ int CDateTimeSpan::GetSecondsTotal() const
+ {
+- LARGE_INTEGER time;
+- ToLargeInt(time);
+-
+- return (int)(time.QuadPart/SECONDS_TO_FILETIME);
++ return std::chrono::duration_cast<std::chrono::seconds>(m_timeSpan).count();
+ }
+
+ void CDateTimeSpan::SetFromPeriod(const std::string &period)
+@@ -233,25 +166,26 @@ void CDateTimeSpan::SetFromPeriod(const std::string &period)
+ SetDateTimeSpan(days, 0, 0, 0);
+ }
+
+-/////////////////////////////////////////////////
+-//
+-// CDateTime
+-//
+-
+ CDateTime::CDateTime()
+ {
+ Reset();
+ }
+
+-CDateTime::CDateTime(const KODI::TIME::SystemTime& time)
++CDateTime::CDateTime(const KODI::TIME::SystemTime& systemTime)
+ {
+- // we store internally as a FileTime
+- m_state = ToFileTime(time, m_time) ? valid : invalid;
++ KODI::TIME::FileTime fileTime;
++ m_state = ToFileTime(systemTime, fileTime) ? valid : invalid;
++
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&fileTime, &time);
++ m_time = std::chrono::system_clock::from_time_t(time);
+ }
+
+-CDateTime::CDateTime(const KODI::TIME::FileTime& time) : m_time(time)
++CDateTime::CDateTime(const KODI::TIME::FileTime& fileTime)
+ {
+- SetValid(true);
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&fileTime, &time);
++ m_time = std::chrono::system_clock::from_time_t(time);
+ }
+
+ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time)
+@@ -261,12 +195,20 @@ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time)
+
+ CDateTime::CDateTime(const time_t& time)
+ {
+- m_state = ToFileTime(time, m_time) ? valid : invalid;
++ m_time = std::chrono::system_clock::from_time_t(time);
++ SetValid(true);
++}
++
++CDateTime::CDateTime(const std::chrono::system_clock::time_point& time)
++{
++ m_time = time;
++ SetValid(true);
+ }
+
+ CDateTime::CDateTime(const tm& time)
+ {
+- m_state = ToFileTime(time, m_time) ? valid : invalid;
++ m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&time)));
++ SetValid(true);
+ }
+
+ CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int second)
+@@ -276,52 +218,66 @@ CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int sec
+
+ CDateTime CDateTime::GetCurrentDateTime()
+ {
+- // get the current time
+- KODI::TIME::SystemTime time;
+- KODI::TIME::GetLocalTime(&time);
++ auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now());
+
+- return CDateTime(time);
++ return CDateTime(
++ std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch())
++ .count());
+ }
+
+ CDateTime CDateTime::GetUTCDateTime()
+ {
+- CDateTime time(GetCurrentDateTime());
+- time += GetTimezoneBias();
+- return time;
++ return CDateTime(std::chrono::system_clock::now());
+ }
+
+ const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right)
+ {
+- m_state = ToFileTime(right, m_time) ? valid : invalid;
++ KODI::TIME::FileTime fileTime;
++ m_state = ToFileTime(right, fileTime) ? valid : invalid;
++
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&fileTime, &time);
++ m_time = std::chrono::system_clock::from_time_t(time);
+
+ return *this;
+ }
+
+ const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right)
+ {
+- m_time=right;
+- SetValid(true);
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&right, &time);
++ m_time = std::chrono::system_clock::from_time_t(time);
+
+ return *this;
+ }
+
+ const CDateTime& CDateTime::operator =(const time_t& right)
+ {
+- m_state = ToFileTime(right, m_time) ? valid : invalid;
++ m_time = std::chrono::system_clock::from_time_t(right);
++ SetValid(true);
+
+ return *this;
+ }
+
+ const CDateTime& CDateTime::operator =(const tm& right)
+ {
+- m_state = ToFileTime(right, m_time) ? valid : invalid;
++ m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
++ SetValid(true);
++
++ return *this;
++}
++
++const CDateTime& CDateTime::operator=(const std::chrono::system_clock::time_point& right)
++{
++ m_time = right;
++ SetValid(true);
+
+ return *this;
+ }
+
+ bool CDateTime::operator >(const CDateTime& right) const
+ {
+- return operator >(right.m_time);
++ return m_time > right.m_time;
+ }
+
+ bool CDateTime::operator >=(const CDateTime& right) const
+@@ -331,7 +287,7 @@ bool CDateTime::operator >=(const CDateTime& right) const
+
+ bool CDateTime::operator <(const CDateTime& right) const
+ {
+- return operator <(right.m_time);
++ return m_time < right.m_time;
+ }
+
+ bool CDateTime::operator <=(const CDateTime& right) const
+@@ -341,7 +297,7 @@ bool CDateTime::operator <=(const CDateTime& right) const
+
+ bool CDateTime::operator ==(const CDateTime& right) const
+ {
+- return operator ==(right.m_time);
++ return m_time == right.m_time;
+ }
+
+ bool CDateTime::operator !=(const CDateTime& right) const
+@@ -351,7 +307,10 @@ bool CDateTime::operator !=(const CDateTime& right) const
+
+ bool CDateTime::operator>(const KODI::TIME::FileTime& right) const
+ {
+- return KODI::TIME::CompareFileTime(&m_time, &right) > 0;
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&right, &time);
++
++ return m_time > std::chrono::system_clock::from_time_t(time);
+ }
+
+ bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const
+@@ -361,7 +320,10 @@ bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const
+
+ bool CDateTime::operator<(const KODI::TIME::FileTime& right) const
+ {
+- return KODI::TIME::CompareFileTime(&m_time, &right) < 0;
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&right, &time);
++
++ return m_time < std::chrono::system_clock::from_time_t(time);
+ }
+
+ bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const
+@@ -371,7 +333,10 @@ bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const
+
+ bool CDateTime::operator==(const KODI::TIME::FileTime& right) const
+ {
+- return KODI::TIME::CompareFileTime(&m_time, &right) == 0;
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&right, &time);
++
++ return m_time == std::chrono::system_clock::from_time_t(time);
+ }
+
+ bool CDateTime::operator!=(const KODI::TIME::FileTime& right) const
+@@ -420,10 +385,7 @@ bool CDateTime::operator!=(const KODI::TIME::SystemTime& right) const
+
+ bool CDateTime::operator >(const time_t& right) const
+ {
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator >(time);
++ return m_time > std::chrono::system_clock::from_time_t(right);
+ }
+
+ bool CDateTime::operator >=(const time_t& right) const
+@@ -433,10 +395,7 @@ bool CDateTime::operator >=(const time_t& right) const
+
+ bool CDateTime::operator <(const time_t& right) const
+ {
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator <(time);
++ return m_time < std::chrono::system_clock::from_time_t(right);
+ }
+
+ bool CDateTime::operator <=(const time_t& right) const
+@@ -446,10 +405,7 @@ bool CDateTime::operator <=(const time_t& right) const
+
+ bool CDateTime::operator ==(const time_t& right) const
+ {
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator ==(time);
++ return m_time == std::chrono::system_clock::from_time_t(right);
+ }
+
+ bool CDateTime::operator !=(const time_t& right) const
+@@ -459,10 +415,7 @@ bool CDateTime::operator !=(const time_t& right) const
+
+ bool CDateTime::operator >(const tm& right) const
+ {
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator >(time);
++ return m_time > std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
+ }
+
+ bool CDateTime::operator >=(const tm& right) const
+@@ -472,10 +425,7 @@ bool CDateTime::operator >=(const tm& right) const
+
+ bool CDateTime::operator <(const tm& right) const
+ {
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator <(time);
++ return m_time < std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
+ }
+
+ bool CDateTime::operator <=(const tm& right) const
+@@ -485,10 +435,7 @@ bool CDateTime::operator <=(const tm& right) const
+
+ bool CDateTime::operator ==(const tm& right) const
+ {
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator ==(time);
++ return m_time == std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
+ }
+
+ bool CDateTime::operator !=(const tm& right) const
+@@ -496,66 +443,64 @@ bool CDateTime::operator !=(const tm& right) const
+ return !operator ==(right);
+ }
+
+-CDateTime CDateTime::operator +(const CDateTimeSpan& right) const
++bool CDateTime::operator>(const std::chrono::system_clock::time_point& right) const
+ {
+- CDateTime left(*this);
++ return m_time > right;
++}
+
+- LARGE_INTEGER timeLeft;
+- left.ToLargeInt(timeLeft);
++bool CDateTime::operator>=(const std::chrono::system_clock::time_point& right) const
++{
++ return operator>(right) || operator==(right);
++}
+
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
++bool CDateTime::operator<(const std::chrono::system_clock::time_point& right) const
++{
++ return m_time < right;
++}
+
+- timeLeft.QuadPart+=timeRight.QuadPart;
++bool CDateTime::operator<=(const std::chrono::system_clock::time_point& right) const
++{
++ return operator<(right) || operator==(right);
++}
+
+- left.FromLargeInt(timeLeft);
++bool CDateTime::operator==(const std::chrono::system_clock::time_point& right) const
++{
++ return m_time == right;
++}
+
+- return left;
++bool CDateTime::operator!=(const std::chrono::system_clock::time_point& right) const
++{
++ return !operator==(right);
+ }
+
+-CDateTime CDateTime::operator -(const CDateTimeSpan& right) const
++CDateTime CDateTime::operator+(const CDateTimeSpan& right) const
+ {
+ CDateTime left(*this);
+
+- LARGE_INTEGER timeLeft;
+- left.ToLargeInt(timeLeft);
++ left.m_time + right.m_timeSpan;
+
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
++ return left;
++}
+
+- timeLeft.QuadPart-=timeRight.QuadPart;
++CDateTime CDateTime::operator-(const CDateTimeSpan& right) const
++{
++ CDateTime left(*this);
+
+- left.FromLargeInt(timeLeft);
++ left.m_time - right.m_timeSpan;
+
+ return left;
+ }
+
+ const CDateTime& CDateTime::operator +=(const CDateTimeSpan& right)
+ {
+- LARGE_INTEGER timeThis;
+- ToLargeInt(timeThis);
+-
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
+-
+- timeThis.QuadPart+=timeRight.QuadPart;
+-
+- FromLargeInt(timeThis);
++ m_time += right.m_timeSpan;
+
+ return *this;
+ }
+
+ const CDateTime& CDateTime::operator -=(const CDateTimeSpan& right)
+ {
+- LARGE_INTEGER timeThis;
+- ToLargeInt(timeThis);
+-
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
+-
+- timeThis.QuadPart-=timeRight.QuadPart;
+-
+- FromLargeInt(timeThis);
++ m_time -= right.m_timeSpan;
+
+ return *this;
+ }
+@@ -564,25 +509,16 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const
+ {
+ CDateTimeSpan left;
+
+- LARGE_INTEGER timeLeft;
+- left.ToLargeInt(timeLeft);
+-
+- LARGE_INTEGER timeThis;
+- ToLargeInt(timeThis);
+-
+- LARGE_INTEGER timeRight;
+- right.ToLargeInt(timeRight);
+-
+- timeLeft.QuadPart=timeThis.QuadPart-timeRight.QuadPart;
+-
+- left.FromLargeInt(timeLeft);
+-
++ left.m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(m_time - right.m_time);
+ return left;
+ }
+
+ CDateTime::operator KODI::TIME::FileTime() const
+ {
+- return m_time;
++ KODI::TIME::FileTime fileTime;
++ time_t time = std::chrono::system_clock::to_time_t(m_time);
++ KODI::TIME::TimeTToFileTime(time, &fileTime);
++ return fileTime;
+ }
+
+ void CDateTime::Archive(CArchive& ar)
+@@ -607,25 +543,38 @@ void CDateTime::Archive(CArchive& ar)
+ {
+ KODI::TIME::SystemTime st;
+ ar>>st;
+- ToFileTime(st, m_time);
++ ToTimePoint(st, m_time);
+ }
+ }
+ }
+
+ void CDateTime::Reset()
+ {
+- SetDateTime(1601, 1, 1, 0, 0, 0);
++ m_time = {};
+ SetValid(false);
+ }
+
+ void CDateTime::SetValid(bool yesNo)
+ {
+- m_state=yesNo ? valid : invalid;
++ m_state = yesNo ? valid : invalid;
+ }
+
+ bool CDateTime::IsValid() const
+ {
+- return m_state==valid;
++ return m_state == valid;
++}
++
++bool CDateTime::ToTimePoint(const KODI::TIME::SystemTime& systemTime,
++ std::chrono::system_clock::time_point& timePoint) const
++{
++ KODI::TIME::FileTime fileTime;
++ KODI::TIME::SystemTimeToFileTime(&systemTime, &fileTime);
++
++ time_t time;
++ KODI::TIME::FileTimeToTimeT(&fileTime, &time);
++
++ timePoint = std::chrono::system_clock::from_time_t(time);
++ return true;
+ }
+
+ bool CDateTime::ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const
+@@ -646,33 +595,6 @@ bool CDateTime::ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) c
+ return true;
+ }
+
+-bool CDateTime::ToFileTime(const tm& time, KODI::TIME::FileTime& fileTime) const
+-{
+- KODI::TIME::SystemTime st = {};
+-
+- st.year = time.tm_year + 1900;
+- st.month = time.tm_mon + 1;
+- st.dayOfWeek = time.tm_wday;
+- st.day = time.tm_mday;
+- st.hour = time.tm_hour;
+- st.minute = time.tm_min;
+- st.second = time.tm_sec;
+-
+- return SystemTimeToFileTime(&st, &fileTime) == 1;
+-}
+-
+-void CDateTime::ToLargeInt(LARGE_INTEGER& time) const
+-{
+- time.u.HighPart = m_time.highDateTime;
+- time.u.LowPart = m_time.lowDateTime;
+-}
+-
+-void CDateTime::FromLargeInt(const LARGE_INTEGER& time)
+-{
+- m_time.highDateTime = time.u.HighPart;
+- m_time.lowDateTime = time.u.LowPart;
+-}
+-
+ bool CDateTime::SetFromDateString(const std::string &date)
+ {
+ //! @todo STRING_CLEANUP
+@@ -714,80 +636,83 @@ bool CDateTime::SetFromDateString(const std::string &date)
+
+ int CDateTime::GetDay() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto dp = date::floor<date::days>(m_time);
++ auto ymd = date::year_month_day{dp};
+
+- return st.day;
++ return static_cast<unsigned int>(ymd.day());
+ }
+
+ int CDateTime::GetMonth() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto dp = date::floor<date::days>(m_time);
++ auto ymd = date::year_month_day{dp};
+
+- return st.month;
++ return static_cast<unsigned int>(ymd.month());
+ }
+
+ int CDateTime::GetYear() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto dp = date::floor<date::days>(m_time);
++ auto ymd = date::year_month_day{dp};
+
+- return st.year;
++ return static_cast<int>(ymd.year());
+ }
+
+ int CDateTime::GetHour() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto dp = date::floor<date::days>(m_time);
++ auto time = date::make_time(m_time - dp);
+
+- return st.hour;
++ return time.hours().count();
+ }
+
+ int CDateTime::GetMinute() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto dp = date::floor<date::days>(m_time);
++ auto time = date::make_time(m_time - dp);
+
+- return st.minute;
++ return time.minutes().count();
+ }
+
+ int CDateTime::GetSecond() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto dp = date::floor<date::days>(m_time);
++ auto time = date::make_time(m_time - dp);
+
+- return st.second;
++ return time.seconds().count();
+ }
+
+ int CDateTime::GetDayOfWeek() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto dp = date::floor<date::days>(m_time);
++ auto yww = iso_week::year_weeknum_weekday{dp};
+
+- return st.dayOfWeek;
++ return static_cast<unsigned int>(yww.weekday());
+ }
+
+ int CDateTime::GetMinuteOfDay() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
+- return st.hour * 60 + st.minute;
++ auto dp = date::floor<std::chrono::hours>(m_time);
++ ;
++ auto time = date::make_time(m_time - dp);
++
++ return time.hours().count() * 60 + time.minutes().count();
+ }
+
+ bool CDateTime::SetDateTime(int year, int month, int day, int hour, int minute, int second)
+ {
+- KODI::TIME::SystemTime st = {};
++ auto ymd = date::year(year) / month / day;
++ if (!ymd.ok())
++ {
++ SetValid(false);
++ return false;
++ }
+
+- st.year = year;
+- st.month = month;
+- st.day = day;
+- st.hour = hour;
+- st.minute = minute;
+- st.second = second;
++ m_time = date::sys_days(ymd) + std::chrono::hours(hour) + std::chrono::minutes(minute) +
++ std::chrono::seconds(second);
+
+- m_state = ToFileTime(st, m_time) ? valid : invalid;
+- return m_state == valid;
++ SetValid(true);
++ return true;
+ }
+
+ bool CDateTime::SetDate(int year, int month, int day)
+@@ -797,119 +722,75 @@ bool CDateTime::SetDate(int year, int month, int day)
+
+ bool CDateTime::SetTime(int hour, int minute, int second)
+ {
+- // 01.01.1601 00:00:00 is 0 as filetime
+- return SetDateTime(1601, 1, 1, hour, minute, second);
++ m_time = date::sys_seconds(std::chrono::seconds(0)) + std::chrono::hours(hour) +
++ std::chrono::minutes(minute) + std::chrono::seconds(second);
++
++ SetValid(true);
++ return true;
+ }
+
+-void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& time) const
++void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& systemTime) const
+ {
+- FileTimeToSystemTime(&m_time, &time);
++ const time_t time = std::chrono::system_clock::to_time_t(m_time);
++ KODI::TIME::FileTime fileTime;
++ ToFileTime(time, fileTime);
++ KODI::TIME::FileTimeToSystemTime(&fileTime, &systemTime);
+ }
+
+-#define UNIX_BASE_TIME 116444736000000000LL /* nanoseconds since epoch */
+ void CDateTime::GetAsTime(time_t& time) const
+ {
+- long long ll = (static_cast<long long>(m_time.highDateTime) << 32) + m_time.lowDateTime;
+- time=(time_t)((ll - UNIX_BASE_TIME) / 10000000);
++ time = std::chrono::system_clock::to_time_t(m_time);
+ }
+
+ void CDateTime::GetAsTm(tm& time) const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto t = std::chrono::system_clock::to_time_t(m_time);
+
+ time = {};
+- time.tm_year = st.year - 1900;
+- time.tm_mon = st.month - 1;
+- time.tm_wday = st.dayOfWeek;
+- time.tm_mday = st.day;
+- time.tm_hour = st.hour;
+- time.tm_min = st.minute;
+- time.tm_sec = st.second;
+- time.tm_isdst = -1;
+-
+- mktime(&time);
++ localtime_r(&t, &time);
+ }
+
+-void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& time) const
++std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const
+ {
+- KODI::TIME::LocalFileTimeToFileTime(&m_time, &time);
++ return m_time;
+ }
+
++// void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& fileTime) const
++// {
++// time_t time = std::chrono::system_clock::to_time_t(m_time);
++// KODI::TIME::TimeTToFileTime(time, &fileTime);
++// }
++
+ std::string CDateTime::GetAsDBDate() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
+-
+- return StringUtils::Format("{:04}-{:02}-{:02}", st.year, st.month, st.day);
++ return date::format("%F", m_time);
+ }
+
+ std::string CDateTime::GetAsDBTime() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
+-
+- return StringUtils::Format("{:02}:{:02}:{:02}", st.hour, st.minute, st.second);
++ auto sp = date::floor<std::chrono::seconds>(m_time);
++ return date::format("%T", sp);
+ }
+
+ std::string CDateTime::GetAsDBDateTime() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto sp = date::floor<std::chrono::seconds>(m_time);
+
+- return StringUtils::Format("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", st.year, st.month, st.day,
+- st.hour, st.minute, st.second);
++ return date::format("%F %T", sp);
+ }
+
+ std::string CDateTime::GetAsSaveString() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
++ auto sp = date::floor<std::chrono::seconds>(m_time);
+
+- return StringUtils::Format("{:04}{:02}{:02}_{:02}{:02}{:02}", st.year, st.month, st.day, st.hour,
+- st.minute, st.second);
++ return date::format("%Y%m%d_%H%M%S", sp);
+ }
+
+ bool CDateTime::SetFromUTCDateTime(const CDateTime &dateTime)
+ {
+- CDateTime tmp(dateTime);
+- tmp -= GetTimezoneBias();
+-
+- m_time = tmp.m_time;
+- m_state = tmp.m_state;
+- return m_state == valid;
+-}
+-
+-static bool bGotTimezoneBias = false;
+-
+-void CDateTime::ResetTimezoneBias(void)
+-{
+- bGotTimezoneBias = false;
+-}
+-
+-CDateTimeSpan CDateTime::GetTimezoneBias(void)
+-{
+- static CDateTimeSpan timezoneBias;
+-
+- if (!bGotTimezoneBias)
+- {
+- bGotTimezoneBias = true;
+- KODI::TIME::TimeZoneInformation tz;
+- switch (KODI::TIME::GetTimeZoneInformation(&tz))
+- {
+- case KODI::TIME::KODI_TIME_ZONE_ID_DAYLIGHT:
+- timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.daylightBias, 0);
+- break;
+- case KODI::TIME::KODI_TIME_ZONE_ID_STANDARD:
+- timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.standardBias, 0);
+- break;
+- case KODI::TIME::KODI_TIME_ZONE_ID_UNKNOWN:
+- timezoneBias = CDateTimeSpan(0, 0, tz.bias, 0);
+- break;
+- }
+- }
+-
+- return timezoneBias;
++ m_time = dateTime.m_time;
++ m_state = valid;
++ return true;
+ }
+
+ bool CDateTime::SetFromUTCDateTime(const time_t &dateTime)
+@@ -1511,60 +1392,31 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds /
+ CDateTime CDateTime::GetAsUTCDateTime() const
+ {
+ CDateTime time(m_time);
+- time += GetTimezoneBias();
+ return time;
+ }
+
+ std::string CDateTime::GetAsRFC1123DateTime() const
+ {
+- CDateTime time(GetAsUTCDateTime());
++ auto time = date::floor<std::chrono::seconds>(m_time);
+
+- int weekDay = time.GetDayOfWeek();
+- if (weekDay < 0)
+- weekDay = 0;
+- else if (weekDay > 6)
+- weekDay = 6;
+- if (weekDay != time.GetDayOfWeek())
+- CLog::Log(LOGWARNING, "Invalid day of week {} in {}", time.GetDayOfWeek(),
+- time.GetAsDBDateTime());
+-
+- int month = time.GetMonth();
+- if (month < 1)
+- month = 1;
+- else if (month > 12)
+- month = 12;
+- if (month != time.GetMonth())
+- CLog::Log(LOGWARNING, "Invalid month {} in {}", time.GetMonth(), time.GetAsDBDateTime());
+-
+- return StringUtils::Format("{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT", DAY_NAMES[weekDay],
+- time.GetDay(), MONTH_NAMES[month - 1], time.GetYear(), time.GetHour(),
+- time.GetMinute(), time.GetSecond());
++ return date::format("%a, %d %b %Y %T GMT", time);
+ }
+
+ std::string CDateTime::GetAsW3CDate() const
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
+-
+- return StringUtils::Format("{:04}-{:02}-{:02}", st.year, st.month, st.day);
++ return GetAsDBDate();
+ }
+
+ std::string CDateTime::GetAsW3CDateTime(bool asUtc /* = false */) const
+ {
+- CDateTime w3cDate = *this;
+- if (asUtc)
+- w3cDate = GetAsUTCDateTime();
+- KODI::TIME::SystemTime st;
+- w3cDate.GetAsSystemTime(st);
++ auto time = date::floor<std::chrono::seconds>(m_time);
+
+- std::string result = StringUtils::Format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}", st.year, st.month,
+- st.day, st.hour, st.minute, st.second);
+ if (asUtc)
+- return result + "Z";
++ return date::format("%FT%TZ", time);
++
++ auto zt = date::make_zoned(date::current_zone(), time);
+
+- CDateTimeSpan bias = GetTimezoneBias();
+- return result + StringUtils::Format("{}{:02}:{:02}", (bias.GetSecondsTotal() >= 0 ? '+' : '-'),
+- abs(bias.GetHours()), abs(bias.GetMinutes()));
++ return date::format("%FT%T%Ez", zt);
+ }
+
+ int CDateTime::MonthStringToMonthNum(const std::string& month)
+diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h
+index fb18e7c0de..60d06e417a 100644
+--- a/xbmc/XBDateTime.h
++++ b/xbmc/XBDateTime.h
+@@ -12,6 +12,7 @@
+ #include "utils/TimeFormat.h"
+ #include "utils/XTimeUtils.h"
+
++#include <chrono>
+ #include <string>
+
+ #include "PlatformDefs.h"
+@@ -21,7 +22,7 @@ class CDateTime;
+ class CDateTimeSpan
+ {
+ public:
+- CDateTimeSpan();
++ CDateTimeSpan() = default;
+ CDateTimeSpan(const CDateTimeSpan& span);
+ CDateTimeSpan& operator=(const CDateTimeSpan&) = default;
+ CDateTimeSpan(int day, int hour, int minute, int second);
+@@ -50,11 +51,7 @@ public:
+ int GetSecondsTotal() const;
+
+ private:
+- void ToLargeInt(LARGE_INTEGER& time) const;
+- void FromLargeInt(const LARGE_INTEGER& time);
+-
+-private:
+- KODI::TIME::FileTime m_timeSpan;
++ std::chrono::duration<int64_t> m_timeSpan{0};
+
+ friend class CDateTime;
+ };
+@@ -70,6 +67,7 @@ public:
+ explicit CDateTime(const KODI::TIME::FileTime& time);
+ explicit CDateTime(const time_t& time);
+ explicit CDateTime(const tm& time);
++ explicit CDateTime(const std::chrono::system_clock::time_point& time);
+ CDateTime(int year, int month, int day, int hour, int minute, int second);
+
+ static CDateTime GetCurrentDateTime();
+@@ -90,6 +88,7 @@ public:
+ const CDateTime& operator=(const KODI::TIME::FileTime& right);
+ const CDateTime& operator =(const time_t& right);
+ const CDateTime& operator =(const tm& right);
++ const CDateTime& operator=(const std::chrono::system_clock::time_point& right);
+
+ bool operator >(const CDateTime& right) const;
+ bool operator >=(const CDateTime& right) const;
+@@ -126,6 +125,13 @@ public:
+ bool operator ==(const tm& right) const;
+ bool operator !=(const tm& right) const;
+
++ bool operator>(const std::chrono::system_clock::time_point& right) const;
++ bool operator>=(const std::chrono::system_clock::time_point& right) const;
++ bool operator<(const std::chrono::system_clock::time_point& right) const;
++ bool operator<=(const std::chrono::system_clock::time_point& right) const;
++ bool operator==(const std::chrono::system_clock::time_point& right) const;
++ bool operator!=(const std::chrono::system_clock::time_point& right) const;
++
+ CDateTime operator +(const CDateTimeSpan& right) const;
+ CDateTime operator -(const CDateTimeSpan& right) const;
+
+@@ -170,7 +176,7 @@ public:
+ void GetAsSystemTime(KODI::TIME::SystemTime& time) const;
+ void GetAsTime(time_t& time) const;
+ void GetAsTm(tm& time) const;
+- void GetAsTimeStamp(KODI::TIME::FileTime& time) const;
++ std::chrono::system_clock::time_point GetAsTimePoint() const;
+
+ CDateTime GetAsUTCDateTime() const;
+ std::string GetAsSaveString() const;
+@@ -189,19 +195,14 @@ public:
+ void SetValid(bool yesNo);
+ bool IsValid() const;
+
+- static void ResetTimezoneBias(void);
+- static CDateTimeSpan GetTimezoneBias(void);
+-
+ private:
++ bool ToTimePoint(const KODI::TIME::SystemTime& time,
++ std::chrono::system_clock::time_point& timePoint) const;
+ bool ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const;
+ bool ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const;
+- bool ToFileTime(const tm& time, KODI::TIME::FileTime& fileTime) const;
+-
+- void ToLargeInt(LARGE_INTEGER& time) const;
+- void FromLargeInt(const LARGE_INTEGER& time);
+
+ private:
+- KODI::TIME::FileTime m_time;
++ std::chrono::system_clock::time_point m_time;
+
+ typedef enum _STATE
+ {
+diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp
+index 6f276a37b2..ab2ddcf570 100644
+--- a/xbmc/platform/posix/PosixTimezone.cpp
++++ b/xbmc/platform/posix/PosixTimezone.cpp
+@@ -143,8 +143,6 @@ void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& set
+ if (settingId == CSettings::SETTING_LOCALE_TIMEZONE)
+ {
+ SetTimezone(std::static_pointer_cast<const CSettingString>(setting)->GetValue());
+-
+- CDateTime::ResetTimezoneBias();
+ }
+ else if (settingId == CSettings::SETTING_LOCALE_TIMEZONECOUNTRY)
+ {
+@@ -157,7 +155,6 @@ void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& set
+ void CPosixTimezone::OnSettingsLoaded()
+ {
+ SetTimezone(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONE));
+- CDateTime::ResetTimezoneBias();
+ }
+
+ std::vector<std::string> CPosixTimezone::GetCounties()
+diff --git a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp
+index 53bbf815f6..4ae42a4803 100644
+--- a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp
++++ b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp
+@@ -205,8 +205,6 @@ bool CPVRGUIActionsDatabase::ResetDatabase(bool bResetEPGOnly)
+ bResetClients = selector.IsResetClientsSelected();
+ }
+
+- CDateTime::ResetTimezoneBias();
+-
+ CLog::LogFC(LOGDEBUG, LOGPVR, "PVR clearing {} database", bResetEPGOnly ? "EPG" : "PVR and EPG");
+
+ pDlgProgress->SetHeading(CVariant{313}); // "Cleaning database"
+--
+2.43.0
+
+
+From 8433756427c68642013698c678263b4d6ee5759d Mon Sep 17 00:00:00 2001
+From: Lukas Rusak <lorusak@gmail.com>
+Date: Mon, 17 Feb 2020 22:40:56 -0800
+Subject: [PATCH 04/19] fix TestDateTime to work with std::chrono
+
+---
+ xbmc/test/TestDateTime.cpp | 89 ++++++++------------------------------
+ 1 file changed, 17 insertions(+), 72 deletions(-)
+
+diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp
+index 7e51df8cee..a553bd1887 100644
+--- a/xbmc/test/TestDateTime.cpp
++++ b/xbmc/test/TestDateTime.cpp
+@@ -13,6 +13,10 @@
+ #include <array>
+ #include <iostream>
+
++#define USE_OS_TZDB 0
++#define HAS_REMOTE_API 0
++#include <date/date.h>
++#include <date/tz.h>
+ #include <gtest/gtest.h>
+
+ class TestDateTime : public testing::Test
+@@ -32,24 +36,6 @@ TEST_F(TestDateTime, DateTimeOperators)
+ EXPECT_FALSE(dateTime1 == dateTime2);
+ }
+
+-TEST_F(TestDateTime, FileTimeOperators)
+-{
+- CDateTime dateTime1(1991, 5, 14, 12, 34, 56);
+- CDateTime dateTime2(1991, 5, 14, 12, 34, 57);
+-
+- KODI::TIME::FileTime fileTime1;
+- KODI::TIME::FileTime fileTime2;
+-
+- dateTime1.GetAsTimeStamp(fileTime1);
+- dateTime2.GetAsTimeStamp(fileTime2);
+-
+- CDateTime dateTime3(fileTime1);
+-
+- EXPECT_TRUE(dateTime3 < fileTime2);
+- EXPECT_FALSE(dateTime3 > fileTime2);
+- EXPECT_FALSE(dateTime3 == fileTime2);
+-}
+-
+ TEST_F(TestDateTime, SystemTimeOperators)
+ {
+ CDateTime dateTime1(1991, 5, 14, 12, 34, 56);
+@@ -161,7 +147,7 @@ TEST_F(TestDateTime, MonthStringToMonthNum)
+ }
+
+ // this method is broken as SetFromDBDate() will return true
+-TEST_F(TestDateTime, DISABLED_SetFromDateString)
++TEST_F(TestDateTime, SetFromDateString)
+ {
+ CDateTime dateTime;
+ EXPECT_TRUE(dateTime.SetFromDateString("tuesday may 14, 1991"));
+@@ -190,13 +176,7 @@ TEST_F(TestDateTime, SetFromDBDate)
+ EXPECT_EQ(dateTime.GetDay(), 2);
+ }
+
+-// disabled on osx and freebsd as their mktime functions
+-// don't work for dates before 1900
+-#if defined(TARGET_DARWIN_OSX) || defined(TARGET_FREEBSD)
+-TEST_F(TestDateTime, DISABLED_SetFromDBTime)
+-#else
+ TEST_F(TestDateTime, SetFromDBTime)
+-#endif
+ {
+ CDateTime dateTime1;
+ EXPECT_TRUE(dateTime1.SetFromDBTime("12:34"));
+@@ -237,10 +217,8 @@ TEST_F(TestDateTime, SetFromW3CDate)
+
+ TEST_F(TestDateTime, SetFromW3CDateTime)
+ {
+- CDateTimeSpan bias = CDateTime::GetTimezoneBias();
+ CDateTime dateTime;
+ dateTime.SetFromDBDateTime("1994-11-05 13:15:30");
+- dateTime += bias;
+ std::string dateTimeStr = dateTime.GetAsDBDate() + "T" + dateTime.GetAsDBTime() + "Z";
+
+ CDateTime dateTime1;
+@@ -264,11 +242,8 @@ TEST_F(TestDateTime, SetFromW3CDateTime)
+
+ TEST_F(TestDateTime, SetFromUTCDateTime)
+ {
+- CDateTimeSpan bias = CDateTime::GetTimezoneBias();
+-
+ CDateTime dateTime1;
+ dateTime1.SetFromDBDateTime("1991-05-14 12:34:56");
+- dateTime1 += bias;
+
+ CDateTime dateTime2;
+ EXPECT_TRUE(dateTime2.SetFromUTCDateTime(dateTime1));
+@@ -279,7 +254,7 @@ TEST_F(TestDateTime, SetFromUTCDateTime)
+ EXPECT_EQ(dateTime2.GetMinute(), 34);
+ EXPECT_EQ(dateTime2.GetSecond(), 56);
+
+- const time_t time = 674224496 + bias.GetSecondsTotal();
++ const time_t time = 674224496;
+
+ CDateTime dateTime3;
+ EXPECT_TRUE(dateTime3.SetFromUTCDateTime(time));
+@@ -325,18 +300,14 @@ TEST_F(TestDateTime, SetDateTime)
+ EXPECT_EQ(dateTime2.GetMinute(), 0);
+ EXPECT_EQ(dateTime2.GetSecond(), 0);
+
+-// disabled on osx and freebsd as their mktime functions
+-// don't work for dates before 1900
+-#if !defined(TARGET_DARWIN_OSX) && !defined(TARGET_FREEBSD)
+ CDateTime dateTime3;
+ EXPECT_TRUE(dateTime3.SetTime(12, 34, 56));
+- EXPECT_EQ(dateTime3.GetYear(), 1601);
++ EXPECT_EQ(dateTime3.GetYear(), 1970);
+ EXPECT_EQ(dateTime3.GetMonth(), 1);
+ EXPECT_EQ(dateTime3.GetDay(), 1);
+ EXPECT_EQ(dateTime3.GetHour(), 12);
+ EXPECT_EQ(dateTime3.GetMinute(), 34);
+ EXPECT_EQ(dateTime3.GetSecond(), 56);
+-#endif
+ }
+
+ TEST_F(TestDateTime, GetAsStrings)
+@@ -351,22 +322,20 @@ TEST_F(TestDateTime, GetAsStrings)
+ EXPECT_EQ(dateTime.GetAsW3CDate(), "1991-05-14");
+ }
+
+-// disabled because we have no way to validate these values
+-// GetTimezoneBias() always returns a positive value so
+-// there is no way to detect the direction of the offset
+-TEST_F(TestDateTime, DISABLED_GetAsStringsWithBias)
++TEST_F(TestDateTime, GetAsStringsWithBias)
+ {
+- CDateTimeSpan bias = CDateTime::GetTimezoneBias();
+-
+ CDateTime dateTime;
+ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56);
+
+- CDateTime dateTimeWithBias(dateTime);
+- dateTimeWithBias += bias;
++ std::cout << dateTime.GetAsRFC1123DateTime() << std::endl;
++ std::cout << dateTime.GetAsW3CDateTime(false) << std::endl;
++ std::cout << dateTime.GetAsW3CDateTime(true) << std::endl;
+
+- EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 20:34:56 GMT");
+- EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T12:34:56+08:00");
+- EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T20:34:56Z");
++ auto zone = date::make_zoned(date::current_zone(), dateTime.GetAsTimePoint());
++
++ EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT");
++ EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T05:34:56" + date::format("%Ez", zone));
++ EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T12:34:56Z");
+ }
+
+ TEST_F(TestDateTime, GetAsLocalized)
+@@ -604,31 +573,13 @@ TEST_F(TestDateTime, GetAsTm)
+ }
+ }
+
+-// Disabled pending std::chrono and std::date changes.
+-TEST_F(TestDateTime, DISABLED_GetAsTimeStamp)
+-{
+- CDateTimeSpan bias = CDateTime::GetTimezoneBias();
+-
+- CDateTime dateTime;
+- dateTime.SetDateTime(1991, 05, 14, 12, 34, 56);
+-
+- KODI::TIME::FileTime fileTime;
+- dateTime.GetAsTimeStamp(fileTime);
+- dateTime += bias;
+-
+- EXPECT_TRUE(dateTime == fileTime);
+-}
+-
+ TEST_F(TestDateTime, GetAsUTCDateTime)
+ {
+- CDateTimeSpan bias = CDateTime::GetTimezoneBias();
+-
+ CDateTime dateTime1;
+ dateTime1.SetDateTime(1991, 05, 14, 12, 34, 56);
+
+ CDateTime dateTime2;
+ dateTime2 = dateTime1.GetAsUTCDateTime();
+- dateTime2 -= bias;
+
+ EXPECT_EQ(dateTime2.GetYear(), 1991);
+ EXPECT_EQ(dateTime2.GetMonth(), 5);
+@@ -638,20 +589,14 @@ TEST_F(TestDateTime, GetAsUTCDateTime)
+ EXPECT_EQ(dateTime2.GetSecond(), 56);
+ }
+
+-// disabled on osx and freebsd as their mktime functions
+-// don't work for dates before 1900
+-#if defined(TARGET_DARWIN_OSX) || defined(TARGET_FREEBSD)
+-TEST_F(TestDateTime, DISABLED_Reset)
+-#else
+ TEST_F(TestDateTime, Reset)
+-#endif
+ {
+ CDateTime dateTime;
+ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56);
+
+ dateTime.Reset();
+
+- EXPECT_EQ(dateTime.GetYear(), 1601);
++ EXPECT_EQ(dateTime.GetYear(), 1970);
+ EXPECT_EQ(dateTime.GetMonth(), 1);
+ EXPECT_EQ(dateTime.GetDay(), 1);
+ EXPECT_EQ(dateTime.GetHour(), 0);
+--
+2.43.0
+
+
+From ca3e502a5c37975173e376653a167053928b5311 Mon Sep 17 00:00:00 2001
+From: Lukas Rusak <lorusak@gmail.com>
+Date: Thu, 10 Sep 2020 08:19:35 -0700
+Subject: [PATCH 05/19] cleanup CPosixTimezone
+
+---
+ xbmc/application/Application.cpp | 6 +-
+ xbmc/platform/posix/PosixTimezone.cpp | 418 ++++++++++++++++----------
+ xbmc/platform/posix/PosixTimezone.h | 16 +-
+ 3 files changed, 266 insertions(+), 174 deletions(-)
+
+diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp
+index ea1b152dfd..3227933296 100644
+--- a/xbmc/application/Application.cpp
++++ b/xbmc/application/Application.cpp
+@@ -172,8 +172,9 @@
+ #include "utils/URIUtils.h"
+
+ #ifdef TARGET_POSIX
+-#include "platform/posix/XHandle.h"
+ #include "platform/posix/PlatformPosix.h"
++#include "platform/posix/PosixTimezone.h"
++#include "platform/posix/XHandle.h"
+ #endif
+
+ #if defined(TARGET_ANDROID)
+@@ -358,6 +359,9 @@ bool CApplication::Create()
+ // Register JobManager service
+ CServiceBroker::RegisterJobManager(std::make_shared<CJobManager>());
+
++ // Initialize,timezone
++ g_timezone.Init();
++
+ // Announcement service
+ m_pAnnouncementManager = std::make_shared<ANNOUNCEMENT::CAnnouncementManager>();
+ m_pAnnouncementManager->Start();
+diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp
+index ab2ddcf570..7f0b8d4096 100644
+--- a/xbmc/platform/posix/PosixTimezone.cpp
++++ b/xbmc/platform/posix/PosixTimezone.cpp
+@@ -6,7 +6,6 @@
+ * See LICENSES/README.md for more information.
+ */
+
+-#include <time.h>
+ #ifdef TARGET_ANDROID
+ #include "platform/android/bionic_supplement/bionic_supplement.h"
+ #endif
+@@ -23,120 +22,215 @@
+ #include "settings/SettingsComponent.h"
+ #include <stdlib.h>
+
+-#include <algorithm>
++#define USE_OS_TZDB 0
++#define HAS_REMOTE_API 0
++#include "filesystem/File.h"
++#include "platform/MessagePrinter.h"
+
+-CPosixTimezone::CPosixTimezone()
++#include <date/tz.h>
++
++void CPosixTimezone::Init()
+ {
+- char* line = NULL;
+- size_t linelen = 0;
+- int nameonfourthfield = 0;
+- std::string s;
+- std::vector<std::string> tokens;
+-
+- // Load timezones
+- FILE* fp = fopen("/usr/share/zoneinfo/zone.tab", "r");
+- if (fp)
+- {
+- std::string countryCode;
+- std::string timezoneName;
+-
+- while (getdelim(&line, &linelen, '\n', fp) > 0)
++#if defined(DATE_INTERNAL_TZDATA)
++ XFILE::CFileStream zonetab;
++
++ if (!zonetab.Open("special://xbmc/addons/resource.timezone/resources/tzdata/zone.tab"))
++ {
++ CMessagePrinter::DisplayMessage("failed to open zone.tab");
++ return;
++ }
++
++ std::string countryCode;
++ std::string timezoneName;
++
++ std::vector<std::string> tokens;
++
++ for (std::string s; std::getline(zonetab, s);)
++ {
++ tokens.clear();
++ std::string line = s;
++ StringUtils::Trim(line);
++
++ if (line.length() == 0)
++ continue;
++
++ if (line[0] == '#')
++ continue;
++
++ StringUtils::Tokenize(line, tokens, " \t");
++ if (tokens.size() < 3)
++ continue;
++
++ countryCode = tokens[0];
++ timezoneName = tokens[2];
++
++ if (m_timezonesByCountryCode.count(countryCode) == 0)
++ {
++ std::vector<std::string> timezones;
++ timezones.push_back(timezoneName);
++ m_timezonesByCountryCode[countryCode] = timezones;
++ }
++ else
++ {
++ std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode];
++ timezones.push_back(timezoneName);
++ }
++
++ m_countriesByTimezoneName[timezoneName] = countryCode;
++ }
++
++ XFILE::CFileStream isotab;
++
++ if (!isotab.Open("special://xbmc/addons/resource.timezone/resources/tzdata/iso3166.tab"))
++ {
++ CMessagePrinter::DisplayMessage("failed to open iso3166.tab");
++ return;
++ }
++
++ std::string countryName;
++
++ for (std::string s; std::getline(isotab, s);)
++ {
++ tokens.clear();
++ std::string line = s;
++ StringUtils::Trim(line);
++
++ if (line.length() == 0)
++ continue;
++
++ if (line[0] == '#')
++ continue;
++
++ StringUtils::Tokenize(line, tokens, "\t");
++ if (tokens.size() < 2)
++ continue;
++
++ countryCode = tokens[0];
++ countryName = tokens[1];
++
++ m_countries.push_back(countryName);
++ m_countryByCode[countryCode] = countryName;
++ m_countryByName[countryName] = countryCode;
++ }
++
++ sort(m_countries.begin(), m_countries.end(), sortstringbyname());
++#else
++ char* line = NULL;
++ size_t linelen = 0;
++ int nameonfourthfield = 0;
++ std::string s;
++ std::vector<std::string> tokens;
++
++ // Load timezones
++ FILE* fp = fopen("/usr/share/zoneinfo/zone.tab", "r");
++ if (fp)
++ {
++ std::string countryCode;
++ std::string timezoneName;
++
++ while (getdelim(&line, &linelen, '\n', fp) > 0)
++ {
++ tokens.clear();
++ s = line;
++ StringUtils::Trim(s);
++
++ if (s.length() == 0)
++ continue;
++
++ if (s[0] == '#')
++ continue;
++
++ StringUtils::Tokenize(s, tokens, " \t");
++ if (tokens.size() < 3)
++ continue;
++
++ countryCode = tokens[0];
++ timezoneName = tokens[2];
++
++ if (m_timezonesByCountryCode.count(countryCode) == 0)
++ {
++ std::vector<std::string> timezones;
++ timezones.push_back(timezoneName);
++ m_timezonesByCountryCode[countryCode] = timezones;
++ }
++ else
+ {
+- tokens.clear();
+- s = line;
+- StringUtils::Trim(s);
+-
+- if (s.length() == 0)
+- continue;
+-
+- if (s[0] == '#')
+- continue;
+-
+- StringUtils::Tokenize(s, tokens, " \t");
+- if (tokens.size() < 3)
+- continue;
+-
+- countryCode = tokens[0];
+- timezoneName = tokens[2];
+-
+- if (m_timezonesByCountryCode.count(countryCode) == 0)
+- {
+- std::vector<std::string> timezones;
+- timezones.push_back(timezoneName);
+- m_timezonesByCountryCode[countryCode] = timezones;
+- }
+- else
+- {
+- std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode];
+- timezones.push_back(timezoneName);
+- }
+-
+- m_countriesByTimezoneName[timezoneName] = countryCode;
++ std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode];
++ timezones.push_back(timezoneName);
+ }
+- fclose(fp);
+- }
+-
+- if (line)
+- {
+- free(line);
+- line = NULL;
+- linelen = 0;
+- }
+-
+- // Load countries
+- fp = fopen("/usr/share/zoneinfo/iso3166.tab", "r");
+- if (!fp)
+- {
+- fp = fopen("/usr/share/misc/iso3166", "r");
+- nameonfourthfield = 1;
+- }
+- if (fp)
+- {
+- std::string countryCode;
+- std::string countryName;
+-
+- while (getdelim(&line, &linelen, '\n', fp) > 0)
++
++ m_countriesByTimezoneName[timezoneName] = countryCode;
++ }
++ fclose(fp);
++ }
++
++ if (line)
++ {
++ free(line);
++ line = NULL;
++ linelen = 0;
++ }
++
++ // Load countries
++ fp = fopen("/usr/share/zoneinfo/iso3166.tab", "r");
++ if (!fp)
++ {
++ fp = fopen("/usr/share/misc/iso3166", "r");
++ nameonfourthfield = 1;
++ }
++ if (fp)
++ {
++ std::string countryCode;
++ std::string countryName;
++
++ while (getdelim(&line, &linelen, '\n', fp) > 0)
++ {
++ s = line;
++ StringUtils::Trim(s);
++
++ //! @todo STRING_CLEANUP
++ if (s.length() == 0)
++ continue;
++
++ if (s[0] == '#')
++ continue;
++
++ // Search for the first non space from the 2nd character and on
++ int i = 2;
++ while (s[i] == ' ' || s[i] == '\t')
++ i++;
++
++ if (nameonfourthfield)
+ {
+- s = line;
+- StringUtils::Trim(s);
+-
+- //! @todo STRING_CLEANUP
+- if (s.length() == 0)
+- continue;
+-
+- if (s[0] == '#')
+- continue;
+-
+- // Search for the first non space from the 2nd character and on
+- int i = 2;
+- while (s[i] == ' ' || s[i] == '\t') i++;
+-
+- if (nameonfourthfield)
+- {
+- // skip three letter
+- while (s[i] != ' ' && s[i] != '\t') i++;
+- while (s[i] == ' ' || s[i] == '\t') i++;
+- // skip number
+- while (s[i] != ' ' && s[i] != '\t') i++;
+- while (s[i] == ' ' || s[i] == '\t') i++;
+- }
+-
+- countryCode = s.substr(0, 2);
+- countryName = s.substr(i);
+-
+- m_counties.push_back(countryName);
+- m_countryByCode[countryCode] = countryName;
+- m_countryByName[countryName] = countryCode;
++ // skip three letter
++ while (s[i] != ' ' && s[i] != '\t')
++ i++;
++ while (s[i] == ' ' || s[i] == '\t')
++ i++;
++ // skip number
++ while (s[i] != ' ' && s[i] != '\t')
++ i++;
++ while (s[i] == ' ' || s[i] == '\t')
++ i++;
+ }
+- sort(m_counties.begin(), m_counties.end(), sortstringbyname());
+- fclose(fp);
+- }
+- free(line);
++
++ countryCode = s.substr(0, 2);
++ countryName = s.substr(i);
++
++ m_countries.push_back(countryName);
++ m_countryByCode[countryCode] = countryName;
++ m_countryByName[countryName] = countryCode;
++ }
++ sort(m_countries.begin(), m_countries.end(), sortstringbyname());
++ fclose(fp);
++ }
++ free(line);
++#endif
+ }
+
+ void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
+ {
+- if (setting == NULL)
++ if (setting == nullptr)
+ return;
+
+ const std::string &settingId = setting->GetId();
+@@ -157,82 +251,74 @@ void CPosixTimezone::OnSettingsLoaded()
+ SetTimezone(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONE));
+ }
+
+-std::vector<std::string> CPosixTimezone::GetCounties()
++std::vector<std::string> CPosixTimezone::GetCountries()
+ {
+- return m_counties;
++ return m_countries;
+ }
+
+ std::vector<std::string> CPosixTimezone::GetTimezonesByCountry(const std::string& country)
+ {
+- return m_timezonesByCountryCode[m_countryByName[country]];
++ return m_timezonesByCountryCode[m_countryByName[country]];
+ }
+
+ std::string CPosixTimezone::GetCountryByTimezone(const std::string& timezone)
+ {
+ #if defined(TARGET_DARWIN)
+- return "?";
+-#else
+- return m_countryByCode[m_countriesByTimezoneName[timezone]];
++ return "?";
+ #endif
++
++ return m_countryByCode[m_countriesByTimezoneName[timezone]];
+ }
+
+ void CPosixTimezone::SetTimezone(const std::string& timezoneName)
+ {
+-#if !defined(TARGET_DARWIN)
+- bool use_timezone = true;
+-#else
+- bool use_timezone = false;
++#if defined(TARGET_DARWIN)
++ return;
+ #endif
+
+- if (use_timezone)
+- {
+- static char env_var[255];
+- sprintf(env_var, "TZ=:%s", timezoneName.c_str());
+- putenv(env_var);
+- tzset();
+- }
++ setenv("TZ", timezoneName.c_str(), 1);
++ tzset();
+ }
+
+ std::string CPosixTimezone::GetOSConfiguredTimezone()
+ {
+- char timezoneName[255];
+-
+- // try Slackware approach first
+- ssize_t rlrc = readlink("/etc/localtime-copied-from"
+- , timezoneName, sizeof(timezoneName)-1);
+-
+- // RHEL and maybe other distros make /etc/localtime a symlink
+- if (rlrc == -1)
+- rlrc = readlink("/etc/localtime", timezoneName, sizeof(timezoneName)-1);
+-
+- if (rlrc != -1)
+- {
+- timezoneName[rlrc] = '\0';
+-
+- char* p = strrchr(timezoneName,'/');
+- if (p)
+- { // we want the previous '/'
+- char* q = p;
+- *q = 0;
+- p = strrchr(timezoneName,'/');
+- *q = '/';
+- if (p)
+- p++;
+- }
+- return p;
+- }
+-
+- // now try Debian approach
+- timezoneName[0] = 0;
+- FILE* fp = fopen("/etc/timezone", "r");
+- if (fp)
+- {
+- if (fgets(timezoneName, sizeof(timezoneName), fp))
+- timezoneName[strlen(timezoneName)-1] = '\0';
+- fclose(fp);
+- }
+-
+- return timezoneName;
++ char timezoneName[255];
++
++ // try Slackware approach first
++ ssize_t rlrc = readlink("/etc/localtime-copied-from", timezoneName, sizeof(timezoneName) - 1);
++
++ // RHEL and maybe other distros make /etc/localtime a symlink
++ if (rlrc == -1)
++ rlrc = readlink("/etc/localtime", timezoneName, sizeof(timezoneName) - 1);
++
++ if (rlrc != -1)
++ {
++ timezoneName[rlrc] = '\0';
++
++ char* p = strrchr(timezoneName, '/');
++ if (p)
++ { // we want the previous '/'
++ char* q = p;
++ *q = 0;
++ p = strrchr(timezoneName, '/');
++ *q = '/';
++ if (p)
++ p++;
++ }
++ return p;
++ }
++
++ // now try Debian approach
++ timezoneName[0] = 0;
++ FILE* fp = fopen("/etc/timezone", "r");
++ if (fp)
++ {
++ if (fgets(timezoneName, sizeof(timezoneName), fp))
++ timezoneName[strlen(timezoneName) - 1] = '\0';
++ fclose(fp);
++ }
++
++ return timezoneName;
+ }
+
+ void CPosixTimezone::SettingOptionsTimezoneCountriesFiller(
+@@ -241,9 +327,9 @@ void CPosixTimezone::SettingOptionsTimezoneCountriesFiller(
+ std::string& current,
+ void* data)
+ {
+- std::vector<std::string> countries = g_timezone.GetCounties();
+- for (unsigned int i = 0; i < countries.size(); i++)
+- list.emplace_back(countries[i], countries[i]);
++ std::vector<std::string> countries = g_timezone.GetCountries();
++ for (const auto& country : countries)
++ list.emplace_back(country, country);
+ }
+
+ void CPosixTimezone::SettingOptionsTimezonesFiller(const std::shared_ptr<const CSetting>& setting,
+@@ -254,12 +340,12 @@ void CPosixTimezone::SettingOptionsTimezonesFiller(const std::shared_ptr<const C
+ current = std::static_pointer_cast<const CSettingString>(setting)->GetValue();
+ bool found = false;
+ std::vector<std::string> timezones = g_timezone.GetTimezonesByCountry(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONECOUNTRY));
+- for (unsigned int i = 0; i < timezones.size(); i++)
++ for (const auto& timezone : timezones)
+ {
+- if (!found && StringUtils::EqualsNoCase(timezones[i], current))
++ if (!found && StringUtils::EqualsNoCase(timezone, current))
+ found = true;
+
+- list.emplace_back(timezones[i], timezones[i]);
++ list.emplace_back(timezone, timezone);
+ }
+
+ if (!found && !timezones.empty())
+diff --git a/xbmc/platform/posix/PosixTimezone.h b/xbmc/platform/posix/PosixTimezone.h
+index 076e87fa51..238c6daf85 100644
+--- a/xbmc/platform/posix/PosixTimezone.h
++++ b/xbmc/platform/posix/PosixTimezone.h
+@@ -21,7 +21,9 @@ struct StringSettingOption;
+ class CPosixTimezone : public ISettingCallback, public ISettingsHandler
+ {
+ public:
+- CPosixTimezone();
++ CPosixTimezone() = default;
++
++ void Init();
+
+ void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override;
+
+@@ -29,7 +31,7 @@ public:
+
+ std::string GetOSConfiguredTimezone();
+
+- std::vector<std::string> GetCounties();
++ std::vector<std::string> GetCountries();
+ std::vector<std::string> GetTimezonesByCountry(const std::string& country);
+ std::string GetCountryByTimezone(const std::string& timezone);
+
+@@ -46,12 +48,12 @@ public:
+ void* data);
+
+ private:
+- std::vector<std::string> m_counties;
+- std::map<std::string, std::string> m_countryByCode;
+- std::map<std::string, std::string> m_countryByName;
++ std::vector<std::string> m_countries;
++ std::map<std::string, std::string> m_countryByCode;
++ std::map<std::string, std::string> m_countryByName;
+
+- std::map<std::string, std::vector<std::string> > m_timezonesByCountryCode;
+- std::map<std::string, std::string> m_countriesByTimezoneName;
++ std::map<std::string, std::vector<std::string>> m_timezonesByCountryCode;
++ std::map<std::string, std::string> m_countriesByTimezoneName;
+ };
+
+ extern CPosixTimezone g_timezone;
+--
+2.43.0
+
+
+From a36c95155a2b8d22f69ad0809d895c11838620ed Mon Sep 17 00:00:00 2001
+From: Lukas Rusak <lorusak@gmail.com>
+Date: Thu, 10 Sep 2020 08:41:57 -0700
+Subject: [PATCH 06/19] utils/XTimeUtils: clean up SystemTime and FileTime
+ functions
+
+---
+ xbmc/XBDateTime.cpp | 213 ++----------------
+ xbmc/XBDateTime.h | 27 ---
+ .../addons/interfaces/gui/dialogs/Numeric.cpp | 10 +-
+ xbmc/dialogs/GUIDialogNumeric.cpp | 203 ++++++++++-------
+ xbmc/dialogs/GUIDialogNumeric.h | 12 +-
+ xbmc/filesystem/NFSDirectory.cpp | 18 +-
+ xbmc/guilib/GUIEditControl.cpp | 13 +-
+ xbmc/guilib/GUIRSSControl.h | 2 +-
+ xbmc/interfaces/legacy/Dialog.cpp | 44 ++--
+ xbmc/music/infoscanner/MusicInfoScanner.cpp | 4 +-
+ xbmc/network/upnp/UPnPInternal.cpp | 18 +-
+ xbmc/platform/posix/XTimeUtils.cpp | 211 -----------------
+ .../posix/filesystem/PosixDirectory.cpp | 5 +-
+ .../posix/filesystem/SMBDirectory.cpp | 16 +-
+ .../pvr/dialogs/GUIDialogPVRTimerSettings.cpp | 18 +-
+ xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h | 1 -
+ xbmc/pvr/windows/GUIWindowPVRGuide.cpp | 7 +-
+ xbmc/settings/windows/GUIControlSettings.cpp | 14 +-
+ xbmc/test/TestDateTime.cpp | 18 +-
+ xbmc/utils/Archive.cpp | 8 +-
+ xbmc/utils/Archive.h | 4 +-
+ xbmc/utils/RssManager.cpp | 2 +-
+ xbmc/utils/RssManager.h | 2 +-
+ xbmc/utils/RssReader.cpp | 25 +-
+ xbmc/utils/RssReader.h | 10 +-
+ xbmc/utils/XTimeUtils.h | 44 ----
+ xbmc/utils/test/TestArchive.cpp | 22 +-
+ xbmc/video/VideoInfoScanner.cpp | 4 +-
+ 28 files changed, 253 insertions(+), 722 deletions(-)
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index 47c6b8d1a6..d8187b71e6 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -171,23 +171,6 @@ CDateTime::CDateTime()
+ Reset();
+ }
+
+-CDateTime::CDateTime(const KODI::TIME::SystemTime& systemTime)
+-{
+- KODI::TIME::FileTime fileTime;
+- m_state = ToFileTime(systemTime, fileTime) ? valid : invalid;
+-
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&fileTime, &time);
+- m_time = std::chrono::system_clock::from_time_t(time);
+-}
+-
+-CDateTime::CDateTime(const KODI::TIME::FileTime& fileTime)
+-{
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&fileTime, &time);
+- m_time = std::chrono::system_clock::from_time_t(time);
+-}
+-
+ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time)
+ {
+ m_state=time.m_state;
+@@ -230,27 +213,6 @@ CDateTime CDateTime::GetUTCDateTime()
+ return CDateTime(std::chrono::system_clock::now());
+ }
+
+-const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right)
+-{
+- KODI::TIME::FileTime fileTime;
+- m_state = ToFileTime(right, fileTime) ? valid : invalid;
+-
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&fileTime, &time);
+- m_time = std::chrono::system_clock::from_time_t(time);
+-
+- return *this;
+-}
+-
+-const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right)
+-{
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&right, &time);
+- m_time = std::chrono::system_clock::from_time_t(time);
+-
+- return *this;
+-}
+-
+ const CDateTime& CDateTime::operator =(const time_t& right)
+ {
+ m_time = std::chrono::system_clock::from_time_t(right);
+@@ -305,84 +267,6 @@ bool CDateTime::operator !=(const CDateTime& right) const
+ return !operator ==(right);
+ }
+
+-bool CDateTime::operator>(const KODI::TIME::FileTime& right) const
+-{
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&right, &time);
+-
+- return m_time > std::chrono::system_clock::from_time_t(time);
+-}
+-
+-bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const
+-{
+- return operator >(right) || operator ==(right);
+-}
+-
+-bool CDateTime::operator<(const KODI::TIME::FileTime& right) const
+-{
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&right, &time);
+-
+- return m_time < std::chrono::system_clock::from_time_t(time);
+-}
+-
+-bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const
+-{
+- return operator <(right) || operator ==(right);
+-}
+-
+-bool CDateTime::operator==(const KODI::TIME::FileTime& right) const
+-{
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&right, &time);
+-
+- return m_time == std::chrono::system_clock::from_time_t(time);
+-}
+-
+-bool CDateTime::operator!=(const KODI::TIME::FileTime& right) const
+-{
+- return !operator ==(right);
+-}
+-
+-bool CDateTime::operator>(const KODI::TIME::SystemTime& right) const
+-{
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator >(time);
+-}
+-
+-bool CDateTime::operator>=(const KODI::TIME::SystemTime& right) const
+-{
+- return operator >(right) || operator ==(right);
+-}
+-
+-bool CDateTime::operator<(const KODI::TIME::SystemTime& right) const
+-{
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator <(time);
+-}
+-
+-bool CDateTime::operator<=(const KODI::TIME::SystemTime& right) const
+-{
+- return operator <(right) || operator ==(right);
+-}
+-
+-bool CDateTime::operator==(const KODI::TIME::SystemTime& right) const
+-{
+- KODI::TIME::FileTime time;
+- ToFileTime(right, time);
+-
+- return operator ==(time);
+-}
+-
+-bool CDateTime::operator!=(const KODI::TIME::SystemTime& right) const
+-{
+- return !operator ==(right);
+-}
+-
+ bool CDateTime::operator >(const time_t& right) const
+ {
+ return m_time > std::chrono::system_clock::from_time_t(right);
+@@ -477,7 +361,7 @@ CDateTime CDateTime::operator+(const CDateTimeSpan& right) const
+ {
+ CDateTime left(*this);
+
+- left.m_time + right.m_timeSpan;
++ left.m_time += right.m_timeSpan;
+
+ return left;
+ }
+@@ -486,7 +370,7 @@ CDateTime CDateTime::operator-(const CDateTimeSpan& right) const
+ {
+ CDateTime left(*this);
+
+- left.m_time - right.m_timeSpan;
++ left.m_time -= right.m_timeSpan;
+
+ return left;
+ }
+@@ -513,14 +397,6 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const
+ return left;
+ }
+
+-CDateTime::operator KODI::TIME::FileTime() const
+-{
+- KODI::TIME::FileTime fileTime;
+- time_t time = std::chrono::system_clock::to_time_t(m_time);
+- KODI::TIME::TimeTToFileTime(time, &fileTime);
+- return fileTime;
+-}
+-
+ void CDateTime::Archive(CArchive& ar)
+ {
+ if (ar.IsStoring())
+@@ -528,9 +404,7 @@ void CDateTime::Archive(CArchive& ar)
+ ar<<(int)m_state;
+ if (m_state==valid)
+ {
+- KODI::TIME::SystemTime st;
+- GetAsSystemTime(st);
+- ar<<st;
++ ar << GetAsTimePoint();
+ }
+ }
+ else
+@@ -541,9 +415,7 @@ void CDateTime::Archive(CArchive& ar)
+ m_state = CDateTime::STATE(state);
+ if (m_state==valid)
+ {
+- KODI::TIME::SystemTime st;
+- ar>>st;
+- ToTimePoint(st, m_time);
++ ar >> m_time;
+ }
+ }
+ }
+@@ -564,37 +436,6 @@ bool CDateTime::IsValid() const
+ return m_state == valid;
+ }
+
+-bool CDateTime::ToTimePoint(const KODI::TIME::SystemTime& systemTime,
+- std::chrono::system_clock::time_point& timePoint) const
+-{
+- KODI::TIME::FileTime fileTime;
+- KODI::TIME::SystemTimeToFileTime(&systemTime, &fileTime);
+-
+- time_t time;
+- KODI::TIME::FileTimeToTimeT(&fileTime, &time);
+-
+- timePoint = std::chrono::system_clock::from_time_t(time);
+- return true;
+-}
+-
+-bool CDateTime::ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const
+-{
+- return KODI::TIME::SystemTimeToFileTime(&time, &fileTime) == 1 &&
+- (fileTime.lowDateTime > 0 || fileTime.highDateTime > 0);
+-}
+-
+-bool CDateTime::ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const
+-{
+- long long ll = time;
+- ll *= 10000000ll;
+- ll += 0x19DB1DED53E8000LL;
+-
+- fileTime.lowDateTime = (DWORD)(ll & 0xFFFFFFFF);
+- fileTime.highDateTime = (DWORD)(ll >> 32);
+-
+- return true;
+-}
+-
+ bool CDateTime::SetFromDateString(const std::string &date)
+ {
+ //! @todo STRING_CLEANUP
+@@ -729,14 +570,6 @@ bool CDateTime::SetTime(int hour, int minute, int second)
+ return true;
+ }
+
+-void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& systemTime) const
+-{
+- const time_t time = std::chrono::system_clock::to_time_t(m_time);
+- KODI::TIME::FileTime fileTime;
+- ToFileTime(time, fileTime);
+- KODI::TIME::FileTimeToSystemTime(&fileTime, &systemTime);
+-}
+-
+ void CDateTime::GetAsTime(time_t& time) const
+ {
+ time = std::chrono::system_clock::to_time_t(m_time);
+@@ -755,12 +588,6 @@ std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const
+ return m_time;
+ }
+
+-// void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& fileTime) const
+-// {
+-// time_t time = std::chrono::system_clock::to_time_t(m_time);
+-// KODI::TIME::TimeTToFileTime(time, &fileTime);
+-// }
+-
+ std::string CDateTime::GetAsDBDate() const
+ {
+ return date::format("%F", m_time);
+@@ -1052,12 +879,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe
+ std::string strOut;
+ const std::string& strFormat = format.empty() ? g_langInfo.GetTimeFormat() : format;
+
+- KODI::TIME::SystemTime dateTime;
+- GetAsSystemTime(dateTime);
+-
+ // Prefetch meridiem symbol
+ const std::string& strMeridiem =
+- CLangInfo::MeridiemSymbolToString(dateTime.hour > 11 ? MeridiemSymbolPM : MeridiemSymbolAM);
++ CLangInfo::MeridiemSymbolToString(GetHour() > 11 ? MeridiemSymbolPM : MeridiemSymbolAM);
+
+ size_t length = strFormat.size();
+ for (size_t i=0; i < length; ++i)
+@@ -1106,7 +930,7 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe
+ i=length;
+ }
+
+- int hour = dateTime.hour;
++ int hour = GetHour();
+ if (c=='h')
+ { // recalc to 12 hour clock
+ if (hour > 11)
+@@ -1145,9 +969,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe
+ // Format minute string with the length of the mask
+ std::string str;
+ if (partLength==1)
+- str = std::to_string(dateTime.minute);
++ str = std::to_string(GetMinute());
+ else
+- str = StringUtils::Format("{:02}", dateTime.minute);
++ str = StringUtils::Format("{:02}", GetMinute());
+
+ strOut+=str;
+ }
+@@ -1174,9 +998,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe
+ // Format seconds string with the length of the mask
+ std::string str;
+ if (partLength==1)
+- str = std::to_string(dateTime.second);
++ str = std::to_string(GetSecond());
+ else
+- str = StringUtils::Format("{:02}", dateTime.second);
++ str = StringUtils::Format("{:02}", GetSecond());
+
+ strOut+=str;
+ }
+@@ -1215,9 +1039,6 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const
+ {
+ std::string strOut;
+
+- KODI::TIME::SystemTime dateTime;
+- GetAsSystemTime(dateTime);
+-
+ size_t length = strFormat.size();
+ for (size_t i = 0; i < length; ++i)
+ {
+@@ -1267,12 +1088,12 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const
+ // Format string with the length of the mask
+ std::string str;
+ if (partLength==1) // single-digit number
+- str = std::to_string(dateTime.day);
++ str = std::to_string(GetDay());
+ else if (partLength==2) // two-digit number
+- str = StringUtils::Format("{:02}", dateTime.day);
++ str = StringUtils::Format("{:02}", GetDay());
+ else // Day of week string
+ {
+- int wday = dateTime.dayOfWeek;
++ int wday = GetDayOfWeek();
+ if (wday < 1 || wday > 7) wday = 7;
+ str = g_localizeStrings.Get((c =='d' ? 40 : 10) + wday);
+ }
+@@ -1299,12 +1120,12 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const
+ // Format string with the length of the mask
+ std::string str;
+ if (partLength==1) // single-digit number
+- str = std::to_string(dateTime.month);
++ str = std::to_string(GetMonth());
+ else if (partLength==2) // two-digit number
+- str = StringUtils::Format("{:02}", dateTime.month);
++ str = StringUtils::Format("{:02}", GetMonth());
+ else // Month string
+ {
+- int wmonth = dateTime.month;
++ int wmonth = GetMonth();
+ if (wmonth < 1 || wmonth > 12) wmonth = 12;
+ str = g_localizeStrings.Get((c =='m' ? 50 : 20) + wmonth);
+ }
+@@ -1329,7 +1150,7 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const
+ }
+
+ // Format string with the length of the mask
+- std::string str = std::to_string(dateTime.year); // four-digit number
++ std::string str = std::to_string(GetYear()); // four-digit number
+ if (partLength <= 2)
+ str.erase(0, 2); // two-digit number
+
+diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h
+index 60d06e417a..16d6217c8a 100644
+--- a/xbmc/XBDateTime.h
++++ b/xbmc/XBDateTime.h
+@@ -63,8 +63,6 @@ public:
+ CDateTime();
+ CDateTime(const CDateTime& time);
+ CDateTime& operator=(const CDateTime&) = default;
+- explicit CDateTime(const KODI::TIME::SystemTime& time);
+- explicit CDateTime(const KODI::TIME::FileTime& time);
+ explicit CDateTime(const time_t& time);
+ explicit CDateTime(const tm& time);
+ explicit CDateTime(const std::chrono::system_clock::time_point& time);
+@@ -84,8 +82,6 @@ public:
+ static CDateTime FromUTCDateTime(const time_t &dateTime);
+ static CDateTime FromRFC1123DateTime(const std::string &dateTime);
+
+- const CDateTime& operator=(const KODI::TIME::SystemTime& right);
+- const CDateTime& operator=(const KODI::TIME::FileTime& right);
+ const CDateTime& operator =(const time_t& right);
+ const CDateTime& operator =(const tm& right);
+ const CDateTime& operator=(const std::chrono::system_clock::time_point& right);
+@@ -97,20 +93,6 @@ public:
+ bool operator ==(const CDateTime& right) const;
+ bool operator !=(const CDateTime& right) const;
+
+- bool operator>(const KODI::TIME::FileTime& right) const;
+- bool operator>=(const KODI::TIME::FileTime& right) const;
+- bool operator<(const KODI::TIME::FileTime& right) const;
+- bool operator<=(const KODI::TIME::FileTime& right) const;
+- bool operator==(const KODI::TIME::FileTime& right) const;
+- bool operator!=(const KODI::TIME::FileTime& right) const;
+-
+- bool operator>(const KODI::TIME::SystemTime& right) const;
+- bool operator>=(const KODI::TIME::SystemTime& right) const;
+- bool operator<(const KODI::TIME::SystemTime& right) const;
+- bool operator<=(const KODI::TIME::SystemTime& right) const;
+- bool operator==(const KODI::TIME::SystemTime& right) const;
+- bool operator!=(const KODI::TIME::SystemTime& right) const;
+-
+ bool operator >(const time_t& right) const;
+ bool operator >=(const time_t& right) const;
+ bool operator <(const time_t& right) const;
+@@ -140,8 +122,6 @@ public:
+
+ CDateTimeSpan operator -(const CDateTime& right) const;
+
+- operator KODI::TIME::FileTime() const;
+-
+ void Archive(CArchive& ar) override;
+
+ void Reset();
+@@ -173,7 +153,6 @@ public:
+ */
+ bool SetFromDBDateTime(const std::string &dateTime);
+
+- void GetAsSystemTime(KODI::TIME::SystemTime& time) const;
+ void GetAsTime(time_t& time) const;
+ void GetAsTm(tm& time) const;
+ std::chrono::system_clock::time_point GetAsTimePoint() const;
+@@ -195,12 +174,6 @@ public:
+ void SetValid(bool yesNo);
+ bool IsValid() const;
+
+-private:
+- bool ToTimePoint(const KODI::TIME::SystemTime& time,
+- std::chrono::system_clock::time_point& timePoint) const;
+- bool ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const;
+- bool ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const;
+-
+ private:
+ std::chrono::system_clock::time_point m_time;
+
+diff --git a/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp
+index a78aa4af60..3acc48e768 100644
+--- a/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp
++++ b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp
+@@ -135,12 +135,9 @@ bool Interface_GUIDialogNumeric::show_and_get_time(KODI_HANDLE kodiBase,
+ return false;
+ }
+
+- KODI::TIME::SystemTime systemTime;
+ CDateTime dateTime(*time);
+- dateTime.GetAsSystemTime(systemTime);
+- if (CGUIDialogNumeric::ShowAndGetTime(systemTime, heading))
++ if (CGUIDialogNumeric::ShowAndGetTime(dateTime, heading))
+ {
+- dateTime = systemTime;
+ dateTime.GetAsTm(*time);
+ return true;
+ }
+@@ -167,12 +164,9 @@ bool Interface_GUIDialogNumeric::show_and_get_date(KODI_HANDLE kodiBase,
+ return false;
+ }
+
+- KODI::TIME::SystemTime systemTime;
+ CDateTime dateTime(*date);
+- dateTime.GetAsSystemTime(systemTime);
+- if (CGUIDialogNumeric::ShowAndGetDate(systemTime, heading))
++ if (CGUIDialogNumeric::ShowAndGetDate(dateTime, heading))
+ {
+- dateTime = systemTime;
+ dateTime.GetAsTm(*date);
+ return true;
+ }
+diff --git a/xbmc/dialogs/GUIDialogNumeric.cpp b/xbmc/dialogs/GUIDialogNumeric.cpp
+index 182cf6a3af..bba219e44e 100644
+--- a/xbmc/dialogs/GUIDialogNumeric.cpp
++++ b/xbmc/dialogs/GUIDialogNumeric.cpp
+@@ -45,7 +45,7 @@ CGUIDialogNumeric::CGUIDialogNumeric(void)
+ m_lastblock{},
+ m_dirty{false}
+ {
+- memset(&m_datetime, 0, sizeof(KODI::TIME::SystemTime));
++ m_datetime.Reset();
+ m_loadType = KEEP_IN_MEMORY;
+ }
+
+@@ -231,59 +231,76 @@ void CGUIDialogNumeric::OnBackSpace()
+ }
+ else if (m_mode == INPUT_TIME)
+ {
++ int hour = m_datetime.GetHour();
++ int minute = m_datetime.GetMinute();
++
+ if (m_block == 0)
+- m_datetime.hour /= 10;
+- else if (m_datetime.minute)
+- m_datetime.minute /= 10;
++ hour /= 10;
++ else if (minute)
++ minute /= 10;
+ else
+ {
+ m_block = 0;
+ m_dirty = false;
+ }
++
++ m_datetime.SetTime(hour, minute, 0);
+ }
+ else if (m_mode == INPUT_TIME_SECONDS)
+ {
++ int hour = m_datetime.GetHour();
++ int minute = m_datetime.GetMinute();
++ int second = m_datetime.GetSecond();
++
+ if (m_block == 0)
+- m_datetime.hour /= 10;
++ hour /= 10;
+ else if (m_block == 1)
+ {
+- if (m_datetime.minute)
+- m_datetime.minute /= 10;
++ if (minute)
++ minute /= 10;
+ else
+ {
+ m_block = 0;
+ m_dirty = false;
+ }
+ }
+- else if (m_datetime.second)
+- m_datetime.minute /= 10;
++ else if (second)
++ minute /= 10;
+ else
+ {
+ m_block = 0;
+ m_dirty = false;
+ }
++
++ m_datetime.SetTime(hour, minute, second);
+ }
+ else if (m_mode == INPUT_DATE)
+ {
++ int day = m_datetime.GetDay();
++ int month = m_datetime.GetMonth();
++ int year = m_datetime.GetYear();
++
+ if (m_block == 0)
+- m_datetime.day /= 10;
++ day /= 10;
+ else if (m_block == 1)
+ {
+- if (m_datetime.month)
+- m_datetime.month /= 10;
++ if (month)
++ month /= 10;
+ else
+ {
+ m_block = 0;
+ m_dirty = false;
+ }
+ }
+- else if (m_datetime.year) // m_block == 2
+- m_datetime.year /= 10;
++ else if (year) // m_block == 2
++ year /= 10;
+ else
+ {
+ m_block = 1;
+ m_dirty = false;
+ }
++
++ m_datetime.SetDate(year, month, day);
+ }
+ }
+
+@@ -317,21 +334,21 @@ void CGUIDialogNumeric::FrameMove()
+ strLabel = m_number;
+ else if (m_mode == INPUT_TIME)
+ { // format up the time
+- strLabel = StringUtils::Format("{:2}:{:02}", m_datetime.hour, m_datetime.minute);
++ strLabel = StringUtils::Format("{:2}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute());
+ start = m_block * 3;
+ end = m_block * 3 + 2;
+ }
+ else if (m_mode == INPUT_TIME_SECONDS)
+ { // format up the time
+- strLabel = StringUtils::Format("{:2}:{:02}:{:02}", m_datetime.hour, m_datetime.minute,
+- m_datetime.second);
++ strLabel = StringUtils::Format("{:2}:{:02}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute(),
++ m_datetime.GetSecond());
+ start = m_block * 3;
+ end = m_block * 3 + 2;
+ }
+ else if (m_mode == INPUT_DATE)
+ { // format up the date
+- strLabel =
+- StringUtils::Format("{:2}/{:2}/{:4}", m_datetime.day, m_datetime.month, m_datetime.year);
++ strLabel = StringUtils::Format("{:2}/{:2}/{:4}", m_datetime.GetDay(), m_datetime.GetMonth(),
++ m_datetime.GetYear());
+ start = m_block * 3;
+ end = m_block * 3 + 2;
+ if (m_block == 2)
+@@ -377,7 +394,7 @@ void CGUIDialogNumeric::OnNumber(uint32_t num)
+ }
+ }
+
+-void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const KODI::TIME::SystemTime& initial)
++void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const CDateTime& initial)
+ {
+ m_mode = mode;
+ m_block = 0;
+@@ -425,7 +442,7 @@ void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const std::string &initial)
+ if (!dateTime.IsValid())
+ return;
+
+- dateTime.GetAsSystemTime(m_datetime);
++ m_datetime = dateTime;
+ m_lastblock = (m_mode == INPUT_DATE) ? 2 : 1;
+ }
+ else if (m_mode == INPUT_IP_ADDRESS)
+@@ -447,7 +464,7 @@ void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const std::string &initial)
+ m_number = initial;
+ }
+
+-KODI::TIME::SystemTime CGUIDialogNumeric::GetOutput() const
++CDateTime CGUIDialogNumeric::GetOutput() const
+ {
+ assert(m_mode == INPUT_TIME || m_mode == INPUT_TIME_SECONDS || m_mode == INPUT_DATE);
+ return m_datetime;
+@@ -458,13 +475,13 @@ std::string CGUIDialogNumeric::GetOutputString() const
+ switch (m_mode)
+ {
+ case INPUT_DATE:
+- return StringUtils::Format("{:02}/{:02}/{:04}", m_datetime.day, m_datetime.month,
+- m_datetime.year);
++ return StringUtils::Format("{:02}/{:02}/{:04}", m_datetime.GetDay(), m_datetime.GetMonth(),
++ m_datetime.GetYear());
+ case INPUT_TIME:
+- return StringUtils::Format("{}:{:02}", m_datetime.hour, m_datetime.minute);
++ return StringUtils::Format("{}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute());
+ case INPUT_TIME_SECONDS:
+- return StringUtils::Format("{}:{:02}:{:02}", m_datetime.hour, m_datetime.minute,
+- m_datetime.second);
++ return StringUtils::Format("{}:{:02}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute(),
++ m_datetime.GetSecond());
+ case INPUT_IP_ADDRESS:
+ return StringUtils::Format("{}.{}.{}.{}", m_ip[0], m_ip[1], m_ip[2], m_ip[3]);
+ case INPUT_NUMBER:
+@@ -480,23 +497,25 @@ bool CGUIDialogNumeric::ShowAndGetSeconds(std::string &timeString, const std::st
+ {
+ CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
+ if (!pDialog) return false;
+- int seconds = StringUtils::TimeStringToSeconds(timeString);
+- KODI::TIME::SystemTime time = {};
+- time.hour = seconds / 3600;
+- time.minute = (seconds - time.hour * 3600) / 60;
+- time.second = seconds - time.hour * 3600 - time.minute * 60;
+- pDialog->SetMode(INPUT_TIME_SECONDS, time);
++
++ std::chrono::system_clock::time_point time{
++ std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}};
++
++ CDateTime datetime(time);
++
++ pDialog->SetMode(INPUT_TIME_SECONDS, datetime);
+ pDialog->SetHeading(heading);
+ pDialog->Open();
+ if (!pDialog->IsConfirmed() || pDialog->IsCanceled())
+ return false;
+- time = pDialog->GetOutput();
+- seconds = time.hour * 3600 + time.minute * 60 + time.second;
+- timeString = StringUtils::SecondsToTimeString(seconds);
++ datetime = pDialog->GetOutput();
++ time = datetime.GetAsTimePoint();
++ timeString = StringUtils::SecondsToTimeString(
++ std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count());
+ return true;
+ }
+
+-bool CGUIDialogNumeric::ShowAndGetTime(KODI::TIME::SystemTime& time, const std::string& heading)
++bool CGUIDialogNumeric::ShowAndGetTime(CDateTime& time, const std::string& heading)
+ {
+ CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
+ if (!pDialog) return false;
+@@ -509,7 +528,7 @@ bool CGUIDialogNumeric::ShowAndGetTime(KODI::TIME::SystemTime& time, const std::
+ return true;
+ }
+
+-bool CGUIDialogNumeric::ShowAndGetDate(KODI::TIME::SystemTime& date, const std::string& heading)
++bool CGUIDialogNumeric::ShowAndGetDate(CDateTime& date, const std::string& heading)
+ {
+ CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
+ if (!pDialog) return false;
+@@ -680,28 +699,33 @@ void CGUIDialogNumeric::SetHeading(const std::string& strHeading)
+
+ void CGUIDialogNumeric::VerifyDate(bool checkYear)
+ {
+- if (m_datetime.day == 0)
+- m_datetime.day = 1;
+- if (m_datetime.month == 0)
+- m_datetime.month = 1;
++ int day = m_datetime.GetDay();
++ int month = m_datetime.GetMonth();
++ int year = m_datetime.GetYear();
++
++ if (day == 0)
++ day = 1;
++ if (month == 0)
++ month = 1;
+ // check for number of days in the month
+- if (m_datetime.day == 31)
++ if (day == 31)
+ {
+- if (m_datetime.month == 4 || m_datetime.month == 6 || m_datetime.month == 9 ||
+- m_datetime.month == 11)
+- m_datetime.day = 30;
++ if (month == 4 || month == 6 || month == 9 || month == 11)
++ day = 30;
+ }
+- if (m_datetime.month == 2 && m_datetime.day > 28)
++ if (month == 2 && day > 28)
+ {
+- m_datetime.day = 29; // max in february.
++ day = 29; // max in february.
+ if (checkYear)
+ {
+ // leap years occur when the year is divisible by 4 but not by 100, or the year is divisible by 400
+ // thus they don't occur, if the year has a remainder when divided by 4, or when the year is divisible by 100 but not by 400
+- if ((m_datetime.year % 4) || (!(m_datetime.year % 100) && (m_datetime.year % 400)))
+- m_datetime.day = 28;
++ if ((year % 4) || (!(year % 100) && (year % 400)))
++ day = 28;
+ }
+ }
++
++ m_datetime.SetDate(year, month, day);
+ }
+
+ void CGUIDialogNumeric::OnOK()
+@@ -741,17 +765,21 @@ void CGUIDialogNumeric::HandleInputIP(uint32_t num)
+
+ void CGUIDialogNumeric::HandleInputDate(uint32_t num)
+ {
++ int day = m_datetime.GetDay();
++ int month = m_datetime.GetMonth();
++ int year = m_datetime.GetYear();
++
+ if (m_block == 0) // day of month
+ {
+- if (m_dirty && (m_datetime.day < 3 || num < 2))
++ if (m_dirty && (day < 3 || num < 2))
+ {
+- m_datetime.day *= 10;
+- m_datetime.day += num;
++ day *= 10;
++ day += num;
+ }
+ else
+- m_datetime.day = num;
++ day = num;
+
+- if (m_datetime.day > 3)
++ if (day > 3)
+ {
+ m_block = 1; // move to months
+ m_dirty = false;
+@@ -763,13 +791,13 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num)
+ {
+ if (m_dirty && num < 3)
+ {
+- m_datetime.month *= 10;
+- m_datetime.month += num;
++ month *= 10;
++ month += num;
+ }
+ else
+- m_datetime.month = num;
++ month = num;
+
+- if (m_datetime.month > 1)
++ if (month > 1)
+ {
+ VerifyDate(false);
+ m_block = 2; // move to year
+@@ -780,15 +808,15 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num)
+ }
+ else // year
+ {
+- if (m_dirty && m_datetime.year < 1000) // have taken input
++ if (m_dirty && year < 1000) // have taken input
+ {
+- m_datetime.year *= 10;
+- m_datetime.year += num;
++ year *= 10;
++ year += num;
+ }
+ else
+- m_datetime.year = num;
++ year = num;
+
+- if (m_datetime.year > 1000)
++ if (year > 1000)
+ {
+ VerifyDate(true);
+ m_block = 0; // move to day of month
+@@ -797,22 +825,28 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num)
+ else
+ m_dirty = true;
+ }
++
++ m_datetime.SetDate(year, month, day);
+ }
+
+ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num)
+ {
++ int hour = m_datetime.GetHour();
++ int minute = m_datetime.GetMinute();
++ int second = m_datetime.GetSecond();
++
+ if (m_block == 0) // hour
+ {
+ if (m_dirty) // have input the first digit
+ {
+- m_datetime.hour *= 10;
+- m_datetime.hour += num;
++ hour *= 10;
++ hour += num;
+ m_block = 1; // move to minutes - allows up to 99 hours
+ m_dirty = false;
+ }
+ else // this is the first digit
+ {
+- m_datetime.hour = num;
++ hour = num;
+ m_dirty = true;
+ }
+ }
+@@ -820,14 +854,14 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num)
+ {
+ if (m_dirty) // have input the first digit
+ {
+- m_datetime.minute *= 10;
+- m_datetime.minute += num;
++ minute *= 10;
++ minute += num;
+ m_block = 2; // move to seconds - allows up to 99 minutes
+ m_dirty = false;
+ }
+ else // this is the first digit
+ {
+- m_datetime.minute = num;
++ minute = num;
+ if (num > 5)
+ {
+ m_block = 2; // move to seconds
+@@ -841,14 +875,14 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num)
+ {
+ if (m_dirty) // have input the first digit
+ {
+- m_datetime.second *= 10;
+- m_datetime.second += num;
++ second *= 10;
++ second += num;
+ m_block = 0; // move to hours
+ m_dirty = false;
+ }
+ else // this is the first digit
+ {
+- m_datetime.second = num;
++ second = num;
+ if (num > 5)
+ {
+ m_block = 0; // move to hours
+@@ -858,28 +892,33 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num)
+ m_dirty = true;
+ }
+ }
++
++ m_datetime.SetTime(hour, minute, second);
+ }
+
+ void CGUIDialogNumeric::HandleInputTime(uint32_t num)
+ {
++ int hour = m_datetime.GetHour();
++ int minute = m_datetime.GetMinute();
++
+ if (m_block == 0) // hour
+ {
+ if (m_dirty) // have input the first digit
+ {
+- if (m_datetime.hour < 2 || num < 4)
++ if (hour < 2 || num < 4)
+ {
+- m_datetime.hour *= 10;
+- m_datetime.hour += num;
++ hour *= 10;
++ hour += num;
+ }
+ else
+- m_datetime.hour = num;
++ hour = num;
+
+ m_block = 1; // move to minutes
+ m_dirty = false;
+ }
+ else // this is the first digit
+ {
+- m_datetime.hour = num;
++ hour = num;
+
+ if (num > 2)
+ {
+@@ -894,14 +933,14 @@ void CGUIDialogNumeric::HandleInputTime(uint32_t num)
+ {
+ if (m_dirty) // have input the first digit
+ {
+- m_datetime.minute *= 10;
+- m_datetime.minute += num;
++ minute *= 10;
++ minute += num;
+ m_block = 0; // move to hours
+ m_dirty = false;
+ }
+ else // this is the first digit
+ {
+- m_datetime.minute = num;
++ minute = num;
+
+ if (num > 5)
+ {
+@@ -912,5 +951,7 @@ void CGUIDialogNumeric::HandleInputTime(uint32_t num)
+ m_dirty = true;
+ }
+ }
++
++ m_datetime.SetTime(hour, minute, 0);
+ }
+
+diff --git a/xbmc/dialogs/GUIDialogNumeric.h b/xbmc/dialogs/GUIDialogNumeric.h
+index 2932053021..d39b2702cd 100644
+--- a/xbmc/dialogs/GUIDialogNumeric.h
++++ b/xbmc/dialogs/GUIDialogNumeric.h
+@@ -8,8 +8,8 @@
+
+ #pragma once
+
++#include "XBDateTime.h"
+ #include "guilib/GUIDialog.h"
+-#include "utils/XTimeUtils.h"
+
+ #include <cstdint>
+
+@@ -41,13 +41,13 @@ public:
+ static InputVerificationResult ShowAndVerifyInput(std::string& strPassword, const std::string& strHeading, bool bGetUserInput);
+
+ void SetHeading(const std::string &strHeading);
+- void SetMode(INPUT_MODE mode, const KODI::TIME::SystemTime& initial);
++ void SetMode(INPUT_MODE mode, const CDateTime& initial);
+ void SetMode(INPUT_MODE mode, const std::string &initial);
+- KODI::TIME::SystemTime GetOutput() const;
++ CDateTime GetOutput() const;
+ std::string GetOutputString() const;
+
+- static bool ShowAndGetTime(KODI::TIME::SystemTime& time, const std::string& heading);
+- static bool ShowAndGetDate(KODI::TIME::SystemTime& date, const std::string& heading);
++ static bool ShowAndGetTime(CDateTime& time, const std::string& heading);
++ static bool ShowAndGetDate(CDateTime& date, const std::string& heading);
+ static bool ShowAndGetIPAddress(std::string &IPAddress, const std::string &heading);
+ static bool ShowAndGetNumber(std::string& strInput, const std::string &strHeading, unsigned int iAutoCloseTimeoutMs = 0, bool bSetHidden = false);
+ static bool ShowAndGetSeconds(std::string& timeString, const std::string &heading);
+@@ -73,7 +73,7 @@ protected:
+ bool m_bCanceled;
+
+ INPUT_MODE m_mode; // the current input mode
+- KODI::TIME::SystemTime m_datetime; // for time and date modes
++ CDateTime m_datetime; // for time and date modes
+ uint8_t m_ip[4]; // for ip address mode
+ uint32_t m_block; // for time, date, and IP methods.
+ uint32_t m_lastblock;
+diff --git a/xbmc/filesystem/NFSDirectory.cpp b/xbmc/filesystem/NFSDirectory.cpp
+index 7feba534c7..69a5dad0f6 100644
+--- a/xbmc/filesystem/NFSDirectory.cpp
++++ b/xbmc/filesystem/NFSDirectory.cpp
+@@ -202,7 +202,6 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ {
+ // We accept nfs://server/path[/file]]]]
+ int ret = 0;
+- KODI::TIME::FileTime fileTime, localTime;
+ std::unique_lock<CCriticalSection> lock(gNfsConnection);
+ std::string strDirName="";
+ std::string myStrPath(url.Get());
+@@ -248,7 +247,6 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ std::string path(myStrPath + strName);
+ int64_t iSize = 0;
+ bool bIsDir = false;
+- int64_t lTimeDate = 0;
+
+ //reslove symlinks
+ if(tmpDirent.type == NF3LNK)
+@@ -265,25 +263,13 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+
+ iSize = tmpDirent.size;
+ bIsDir = tmpDirent.type == NF3DIR;
+- lTimeDate = tmpDirent.mtime.tv_sec;
+
+ if (!StringUtils::EqualsNoCase(strName,".") && !StringUtils::EqualsNoCase(strName,"..")
+ && !StringUtils::EqualsNoCase(strName,"lost+found"))
+ {
+- if(lTimeDate == 0) // if modification date is missing, use create date
+- {
+- lTimeDate = tmpDirent.ctime.tv_sec;
+- }
+-
+- long long ll = lTimeDate & 0xffffffff;
+- ll *= 10000000ll;
+- ll += 116444736000000000ll;
+- fileTime.lowDateTime = (DWORD)(ll & 0xffffffff);
+- fileTime.highDateTime = (DWORD)(ll >> 32);
+- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime);
+-
+ CFileItemPtr pItem(new CFileItem(tmpDirent.name));
+- pItem->m_dateTime=localTime;
++ pItem->m_dateTime =
++ tmpDirent.mtime.tv_sec != 0 ? tmpDirent.mtime.tv_sec : tmpDirent.ctime.tv_sec;
+ pItem->m_dwSize = iSize;
+
+ if (bIsDir)
+diff --git a/xbmc/guilib/GUIEditControl.cpp b/xbmc/guilib/GUIEditControl.cpp
+index 325a703152..f5c25adb37 100644
+--- a/xbmc/guilib/GUIEditControl.cpp
++++ b/xbmc/guilib/GUIEditControl.cpp
+@@ -297,11 +297,9 @@ void CGUIEditControl::OnClick()
+ {
+ CDateTime dateTime;
+ dateTime.SetFromDBTime(utf8);
+- KODI::TIME::SystemTime time;
+- dateTime.GetAsSystemTime(time);
+- if (CGUIDialogNumeric::ShowAndGetTime(time, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
++ if (CGUIDialogNumeric::ShowAndGetTime(
++ dateTime, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
+ {
+- dateTime = CDateTime(time);
+ utf8 = dateTime.GetAsLocalizedTime("", false);
+ textChanged = true;
+ }
+@@ -313,11 +311,10 @@ void CGUIEditControl::OnClick()
+ dateTime.SetFromDBDate(utf8);
+ if (dateTime < CDateTime(2000,1, 1, 0, 0, 0))
+ dateTime = CDateTime(2000, 1, 1, 0, 0, 0);
+- KODI::TIME::SystemTime date;
+- dateTime.GetAsSystemTime(date);
+- if (CGUIDialogNumeric::ShowAndGetDate(date, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
++
++ if (CGUIDialogNumeric::ShowAndGetDate(
++ dateTime, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420)))
+ {
+- dateTime = CDateTime(date);
+ utf8 = dateTime.GetAsDBDate();
+ textChanged = true;
+ }
+diff --git a/xbmc/guilib/GUIRSSControl.h b/xbmc/guilib/GUIRSSControl.h
+index 851f72fb3c..1ade92dbaf 100644
+--- a/xbmc/guilib/GUIRSSControl.h
++++ b/xbmc/guilib/GUIRSSControl.h
+@@ -62,7 +62,7 @@ protected:
+ KODI::GUILIB::GUIINFO::CGUIInfoColor m_headlineColor;
+
+ std::vector<std::string> m_vecUrls;
+- std::vector<int> m_vecIntervals;
++ std::vector<std::chrono::nanoseconds> m_vecIntervals;
+ bool m_rtl;
+ CScrollInfo m_scrollInfo;
+ bool m_dirty;
+diff --git a/xbmc/interfaces/legacy/Dialog.cpp b/xbmc/interfaces/legacy/Dialog.cpp
+index 6dd00f179b..5e9db03da6 100644
+--- a/xbmc/interfaces/legacy/Dialog.cpp
++++ b/xbmc/interfaces/legacy/Dialog.cpp
+@@ -286,8 +286,8 @@ namespace XBMCAddon
+ {
+ DelayedCallGuard dcguard(languageHook);
+ std::string value;
+- KODI::TIME::SystemTime timedate;
+- KODI::TIME::GetLocalTime(&timedate);
++
++ auto timedate = CDateTime::GetCurrentDateTime();
+
+ if (!heading.empty())
+ {
+@@ -295,14 +295,13 @@ namespace XBMCAddon
+ {
+ if (!defaultt.empty() && defaultt.size() == 10)
+ {
+- const std::string& sDefault = defaultt;
+- timedate.day = atoi(sDefault.substr(0, 2).c_str());
+- timedate.month = atoi(sDefault.substr(3, 4).c_str());
+- timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str());
++ const std::string sDefault = defaultt;
++ timedate.SetFromDBDate(sDefault.substr(sDefault.size() - 4) + "-" +
++ sDefault.substr(3, 4) + "-" + sDefault.substr(0, 2));
+ }
+ if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading))
+- value =
+- StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month, timedate.year);
++ value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.GetDay(), timedate.GetMonth(),
++ timedate.GetYear());
+ else
+ return emptyString;
+ }
+@@ -310,12 +309,11 @@ namespace XBMCAddon
+ {
+ if (!defaultt.empty() && defaultt.size() == 5)
+ {
+- const std::string& sDefault = defaultt;
+- timedate.hour = atoi(sDefault.substr(0, 2).c_str());
+- timedate.minute = atoi(sDefault.substr(3, 2).c_str());
++ const std::string sDefault = defaultt;
++ timedate.SetFromDBTime(sDefault.substr(0, 2) + ":" + sDefault.substr(3, 2));
+ }
+ if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading))
+- value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute);
++ value = StringUtils::Format("{:2}:{:02}", timedate.GetHour(), timedate.GetMinute());
+ else
+ return emptyString;
+ }
+@@ -367,8 +365,8 @@ namespace XBMCAddon
+ {
+ DelayedCallGuard dcguard(languageHook);
+ std::string value(defaultt);
+- KODI::TIME::SystemTime timedate;
+- KODI::TIME::GetLocalTime(&timedate);
++
++ auto timedate = CDateTime::GetCurrentDateTime();
+
+ switch (type)
+ {
+@@ -389,14 +387,13 @@ namespace XBMCAddon
+ {
+ if (!defaultt.empty() && defaultt.size() == 10)
+ {
+- const std::string& sDefault = defaultt;
+- timedate.day = atoi(sDefault.substr(0, 2).c_str());
+- timedate.month = atoi(sDefault.substr(3, 4).c_str());
+- timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str());
++ const std::string sDefault = defaultt;
++ timedate.SetFromDBDate(sDefault.substr(sDefault.size() - 4) + "-" +
++ sDefault.substr(3, 4) + "-" + sDefault.substr(0, 2));
+ }
+ if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading))
+- value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month,
+- timedate.year);
++ value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.GetDay(), timedate.GetMonth(),
++ timedate.GetYear());
+ else
+ value = emptyString;
+ }
+@@ -405,12 +402,11 @@ namespace XBMCAddon
+ {
+ if (!defaultt.empty() && defaultt.size() == 5)
+ {
+- const std::string& sDefault = defaultt;
+- timedate.hour = atoi(sDefault.substr(0, 2).c_str());
+- timedate.minute = atoi(sDefault.substr(3, 2).c_str());
++ const std::string sDefault = defaultt;
++ timedate.SetFromDBTime(sDefault.substr(0, 2) + ":" + sDefault.substr(3, 2));
+ }
+ if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading))
+- value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute);
++ value = StringUtils::Format("{:2}:{:02}", timedate.GetHour(), timedate.GetMinute());
+ else
+ value = emptyString;
+ }
+diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp
+index f828b44914..3912892343 100644
+--- a/xbmc/music/infoscanner/MusicInfoScanner.cpp
++++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp
+@@ -1269,8 +1269,8 @@ int CMusicInfoScanner::GetPathHash(const CFileItemList &items, std::string &hash
+ const CFileItemPtr pItem = items[i];
+ digest.Update(pItem->GetPath());
+ digest.Update((unsigned char *)&pItem->m_dwSize, sizeof(pItem->m_dwSize));
+- KODI::TIME::FileTime time = pItem->m_dateTime;
+- digest.Update((unsigned char*)&time, sizeof(KODI::TIME::FileTime));
++ const auto time = pItem->m_dateTime.GetAsTimePoint().time_since_epoch().count();
++ digest.Update(&time, sizeof(std::chrono::nanoseconds));
+ if (pItem->IsAudio() && !pItem->IsPlayList() && !pItem->IsNFO())
+ count++;
+ }
+diff --git a/xbmc/network/upnp/UPnPInternal.cpp b/xbmc/network/upnp/UPnPInternal.cpp
+index 406615768a..1a98b86c50 100644
+--- a/xbmc/network/upnp/UPnPInternal.cpp
++++ b/xbmc/network/upnp/UPnPInternal.cpp
+@@ -1067,11 +1067,19 @@ std::shared_ptr<CFileItem> BuildObject(PLT_MediaObject* entry,
+ }
+
+ // look for date?
+- if(entry->m_Description.date.GetLength()) {
+- KODI::TIME::SystemTime time = {};
+- sscanf(entry->m_Description.date, "%hu-%hu-%huT%hu:%hu:%hu", &time.year, &time.month, &time.day,
+- &time.hour, &time.minute, &time.second);
+- pItem->m_dateTime = time;
++ if (entry->m_Description.date.GetLength())
++ {
++ int year;
++ int month;
++ int day;
++ int hour;
++ int minute;
++ int second;
++
++ sscanf(entry->m_Description.date, "%u-%u-%uT%u:%u:%u", &year, &month, &day, &hour, &minute,
++ &second);
++
++ pItem->m_dateTime.SetDateTime(year, month, day, hour, minute, second);
+ }
+
+ // if there is a thumbnail available set it here
+diff --git a/xbmc/platform/posix/XTimeUtils.cpp b/xbmc/platform/posix/XTimeUtils.cpp
+index e78e5cff48..7d4b17686a 100644
+--- a/xbmc/platform/posix/XTimeUtils.cpp
++++ b/xbmc/platform/posix/XTimeUtils.cpp
+@@ -8,221 +8,10 @@
+
+ #include "utils/XTimeUtils.h"
+
+-#include "PosixTimezone.h"
+-
+-#include <errno.h>
+-#include <mutex>
+-#include <time.h>
+-
+-#include <sys/times.h>
+-
+-#if defined(TARGET_ANDROID) && !defined(__LP64__)
+-#include <time64.h>
+-#endif
+-
+-#define WIN32_TIME_OFFSET ((unsigned long long)(369 * 365 + 89) * 24 * 3600 * 10000000)
+-
+ namespace KODI
+ {
+ namespace TIME
+ {
+
+-/*
+- * A Leap year is any year that is divisible by four, but not by 100 unless also
+- * divisible by 400
+- */
+-#define IsLeapYear(y) ((!(y % 4)) ? (((!(y % 400)) && (y % 100)) ? 1 : 0) : 0)
+-
+-uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation)
+-{
+- if (!timeZoneInformation)
+- return KODI_TIME_ZONE_ID_INVALID;
+-
+- struct tm t;
+- time_t tt = time(NULL);
+- if (localtime_r(&tt, &t))
+- timeZoneInformation->bias = -t.tm_gmtoff / 60;
+-
+- timeZoneInformation->standardName = tzname[0];
+- timeZoneInformation->daylightName = tzname[1];
+-
+- return KODI_TIME_ZONE_ID_UNKNOWN;
+-}
+-
+-void GetLocalTime(SystemTime* systemTime)
+-{
+- const time_t t = time(NULL);
+- struct tm now;
+-
+- localtime_r(&t, &now);
+- systemTime->year = now.tm_year + 1900;
+- systemTime->month = now.tm_mon + 1;
+- systemTime->dayOfWeek = now.tm_wday;
+- systemTime->day = now.tm_mday;
+- systemTime->hour = now.tm_hour;
+- systemTime->minute = now.tm_min;
+- systemTime->second = now.tm_sec;
+- systemTime->milliseconds = 0;
+- // NOTE: localtime_r() is not required to set this, but we Assume that it's set here.
+- g_timezone.m_IsDST = now.tm_isdst;
+-}
+-
+-int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime)
+-{
+- ULARGE_INTEGER l;
+- l.u.LowPart = fileTime->lowDateTime;
+- l.u.HighPart = fileTime->highDateTime;
+-
+- time_t ft;
+- struct tm tm_ft;
+- FileTimeToTimeT(fileTime, &ft);
+- localtime_r(&ft, &tm_ft);
+-
+- l.QuadPart += static_cast<unsigned long long>(tm_ft.tm_gmtoff) * 10000000;
+-
+- localFileTime->lowDateTime = l.u.LowPart;
+- localFileTime->highDateTime = l.u.HighPart;
+- return 1;
+-}
+-
+-int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime)
+-{
+- static const int dayoffset[12] = {0, 31, 59, 90, 120, 151, 182, 212, 243, 273, 304, 334};
+-#if defined(TARGET_DARWIN)
+- static std::mutex timegm_lock;
+-#endif
+-
+- struct tm sysTime = {};
+- sysTime.tm_year = systemTime->year - 1900;
+- sysTime.tm_mon = systemTime->month - 1;
+- sysTime.tm_wday = systemTime->dayOfWeek;
+- sysTime.tm_mday = systemTime->day;
+- sysTime.tm_hour = systemTime->hour;
+- sysTime.tm_min = systemTime->minute;
+- sysTime.tm_sec = systemTime->second;
+- sysTime.tm_yday = dayoffset[sysTime.tm_mon] + (sysTime.tm_mday - 1);
+- sysTime.tm_isdst = g_timezone.m_IsDST;
+-
+- // If this is a leap year, and we're past the 28th of Feb, increment tm_yday.
+- if (IsLeapYear(systemTime->year) && (sysTime.tm_yday > 58))
+- sysTime.tm_yday++;
+-
+-#if defined(TARGET_DARWIN)
+- std::lock_guard<std::mutex> lock(timegm_lock);
+-#endif
+-
+-#if defined(TARGET_ANDROID) && !defined(__LP64__)
+- time64_t t = timegm64(&sysTime);
+-#else
+- time_t t = timegm(&sysTime);
+-#endif
+-
+- LARGE_INTEGER result;
+- result.QuadPart = (long long)t * 10000000 + (long long)systemTime->milliseconds * 10000;
+- result.QuadPart += WIN32_TIME_OFFSET;
+-
+- fileTime->lowDateTime = result.u.LowPart;
+- fileTime->highDateTime = result.u.HighPart;
+-
+- return 1;
+-}
+-
+-long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2)
+-{
+- ULARGE_INTEGER t1;
+- t1.u.LowPart = fileTime1->lowDateTime;
+- t1.u.HighPart = fileTime1->highDateTime;
+-
+- ULARGE_INTEGER t2;
+- t2.u.LowPart = fileTime2->lowDateTime;
+- t2.u.HighPart = fileTime2->highDateTime;
+-
+- if (t1.QuadPart == t2.QuadPart)
+- return 0;
+- else if (t1.QuadPart < t2.QuadPart)
+- return -1;
+- else
+- return 1;
+-}
+-
+-int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime)
+-{
+- LARGE_INTEGER file;
+- file.u.LowPart = fileTime->lowDateTime;
+- file.u.HighPart = fileTime->highDateTime;
+-
+- file.QuadPart -= WIN32_TIME_OFFSET;
+- file.QuadPart /= 10000; /* to milliseconds */
+- systemTime->milliseconds = file.QuadPart % 1000;
+- file.QuadPart /= 1000; /* to seconds */
+-
+- time_t ft = file.QuadPart;
+-
+- struct tm tm_ft;
+- gmtime_r(&ft, &tm_ft);
+-
+- systemTime->year = tm_ft.tm_year + 1900;
+- systemTime->month = tm_ft.tm_mon + 1;
+- systemTime->dayOfWeek = tm_ft.tm_wday;
+- systemTime->day = tm_ft.tm_mday;
+- systemTime->hour = tm_ft.tm_hour;
+- systemTime->minute = tm_ft.tm_min;
+- systemTime->second = tm_ft.tm_sec;
+-
+- return 1;
+-}
+-
+-int LocalFileTimeToFileTime(const FileTime* localFileTime, FileTime* fileTime)
+-{
+- ULARGE_INTEGER l;
+- l.u.LowPart = localFileTime->lowDateTime;
+- l.u.HighPart = localFileTime->highDateTime;
+-
+- l.QuadPart += (unsigned long long) timezone * 10000000;
+-
+- fileTime->lowDateTime = l.u.LowPart;
+- fileTime->highDateTime = l.u.HighPart;
+-
+- return 1;
+-}
+-
+-
+-int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT)
+-{
+- if (!localFileTime || !pTimeT)
+- return false;
+-
+- ULARGE_INTEGER fileTime;
+- fileTime.u.LowPart = localFileTime->lowDateTime;
+- fileTime.u.HighPart = localFileTime->highDateTime;
+-
+- fileTime.QuadPart -= WIN32_TIME_OFFSET;
+- fileTime.QuadPart /= 10000; /* to milliseconds */
+- fileTime.QuadPart /= 1000; /* to seconds */
+-
+- time_t ft = fileTime.QuadPart;
+-
+- struct tm tm_ft;
+- localtime_r(&ft, &tm_ft);
+-
+- *pTimeT = mktime(&tm_ft);
+- return 1;
+-}
+-
+-int TimeTToFileTime(time_t timeT, FileTime* localFileTime)
+-{
+- if (!localFileTime)
+- return false;
+-
+- ULARGE_INTEGER result;
+- result.QuadPart = (unsigned long long) timeT * 10000000;
+- result.QuadPart += WIN32_TIME_OFFSET;
+-
+- localFileTime->lowDateTime = result.u.LowPart;
+- localFileTime->highDateTime = result.u.HighPart;
+-
+- return 1;
+-}
+-
+ } // namespace TIME
+ } // namespace KODI
+diff --git a/xbmc/platform/posix/filesystem/PosixDirectory.cpp b/xbmc/platform/posix/filesystem/PosixDirectory.cpp
+index 6685c0e1db..7482a73960 100644
+--- a/xbmc/platform/posix/filesystem/PosixDirectory.cpp
++++ b/xbmc/platform/posix/filesystem/PosixDirectory.cpp
+@@ -79,10 +79,7 @@ bool CPosixDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ {
+ if (bStat || stat(pItem->GetPath().c_str(), &buffer) == 0)
+ {
+- KODI::TIME::FileTime fileTime, localTime;
+- KODI::TIME::TimeTToFileTime(buffer.st_mtime, &fileTime);
+- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime);
+- pItem->m_dateTime = localTime;
++ pItem->m_dateTime = buffer.st_mtime;
+
+ if (!pItem->m_bIsFolder)
+ pItem->m_dwSize = buffer.st_size;
+diff --git a/xbmc/platform/posix/filesystem/SMBDirectory.cpp b/xbmc/platform/posix/filesystem/SMBDirectory.cpp
+index e2305afb4a..f0b94c22fc 100644
+--- a/xbmc/platform/posix/filesystem/SMBDirectory.cpp
++++ b/xbmc/platform/posix/filesystem/SMBDirectory.cpp
+@@ -134,10 +134,10 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ && strFile != "lost+found"
+ && aDir.type != SMBC_PRINTER_SHARE && aDir.type != SMBC_IPC_SHARE)
+ {
+- int64_t iSize = 0;
++ int64_t iSize = 0;
+ bool bIsDir = true;
+- int64_t lTimeDate = 0;
+ bool hidden = false;
++ struct stat info = {};
+
+ if(StringUtils::EndsWith(strFile, "$") && aDir.type == SMBC_FILE_SHARE )
+ continue;
+@@ -152,7 +152,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ // set this here to if the stat should fail
+ bIsDir = (aDir.type == SMBC_DIR);
+
+- struct stat info = {};
+ if ((m_flags & DIR_FLAG_NO_FILE_INFO)==0 && CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_sambastatfiles)
+ {
+ // make sure we use the authenticated path which contains any default username
+@@ -187,9 +186,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ CURL::GetRedacted(strFullName), errno, strerror(errno));
+
+ bIsDir = S_ISDIR(info.st_mode);
+- lTimeDate = info.st_mtime;
+- if(lTimeDate == 0) // if modification date is missing, use create date
+- lTimeDate = info.st_ctime;
+ iSize = info.st_size;
+ }
+ else
+@@ -200,10 +196,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ }
+ }
+
+- KODI::TIME::FileTime fileTime, localTime;
+- KODI::TIME::TimeTToFileTime(lTimeDate, &fileTime);
+- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime);
+-
+ if (bIsDir)
+ {
+ CFileItemPtr pItem(new CFileItem(strFile));
+@@ -223,7 +215,7 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ URIUtils::AddSlashAtEnd(path);
+ pItem->SetPath(path);
+ pItem->m_bIsFolder = true;
+- pItem->m_dateTime=localTime;
++ pItem->m_dateTime = info.st_mtime != 0 ? info.st_mtime : info.st_ctime;
+ if (hidden)
+ pItem->SetProperty("file:hidden", true);
+ items.Add(pItem);
+@@ -234,7 +226,7 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items)
+ pItem->SetPath(strRoot + aDir.name);
+ pItem->m_bIsFolder = false;
+ pItem->m_dwSize = iSize;
+- pItem->m_dateTime=localTime;
++ pItem->m_dateTime = info.st_mtime != 0 ? info.st_mtime : info.st_ctime;
+ if (hidden)
+ pItem->SetProperty("file:hidden", true);
+ items.Add(pItem);
+diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp
+index f7866278e7..e61761b0ab 100644
+--- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp
++++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp
+@@ -573,22 +573,16 @@ void CGUIDialogPVRTimerSettings::OnSettingAction(const std::shared_ptr<const CSe
+ const std::string& settingId = setting->GetId();
+ if (settingId == SETTING_TMR_BEGIN)
+ {
+- KODI::TIME::SystemTime timerStartTime;
+- m_startLocalTime.GetAsSystemTime(timerStartTime);
+- if (CGUIDialogNumeric::ShowAndGetTime(timerStartTime, g_localizeStrings.Get(14066)))
++ if (CGUIDialogNumeric::ShowAndGetTime(m_startLocalTime, g_localizeStrings.Get(14066)))
+ {
+- SetTimeFromSystemTime(m_startLocalTime, timerStartTime);
+ m_timerStartTimeStr = m_startLocalTime.GetAsLocalizedTime("", false);
+ SetButtonLabels();
+ }
+ }
+ else if (settingId == SETTING_TMR_END)
+ {
+- KODI::TIME::SystemTime timerEndTime;
+- m_endLocalTime.GetAsSystemTime(timerEndTime);
+- if (CGUIDialogNumeric::ShowAndGetTime(timerEndTime, g_localizeStrings.Get(14066)))
++ if (CGUIDialogNumeric::ShowAndGetTime(m_endLocalTime, g_localizeStrings.Get(14066)))
+ {
+- SetTimeFromSystemTime(m_endLocalTime, timerEndTime);
+ m_timerEndTimeStr = m_endLocalTime.GetAsLocalizedTime("", false);
+ SetButtonLabels();
+ }
+@@ -800,14 +794,6 @@ void CGUIDialogPVRTimerSettings::SetDateFromIndex(CDateTime& datetime, int date)
+ datetime.GetMinute(), datetime.GetSecond());
+ }
+
+-void CGUIDialogPVRTimerSettings::SetTimeFromSystemTime(CDateTime& datetime,
+- const KODI::TIME::SystemTime& time)
+-{
+- const CDateTime newTime(time);
+- datetime.SetDateTime(datetime.GetYear(), datetime.GetMonth(), datetime.GetDay(),
+- newTime.GetHour(), newTime.GetMinute(), newTime.GetSecond());
+-}
+-
+ void CGUIDialogPVRTimerSettings::InitializeTypesList()
+ {
+ m_typeEntries.clear();
+diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h
+index d3e9e3eadf..d419e4a722 100644
+--- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h
++++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h
+@@ -59,7 +59,6 @@ private:
+
+ static int GetDateAsIndex(const CDateTime& datetime);
+ static void SetDateFromIndex(CDateTime& datetime, int date);
+- static void SetTimeFromSystemTime(CDateTime& datetime, const KODI::TIME::SystemTime& time);
+
+ static int GetWeekdaysFromSetting(const std::shared_ptr<const CSetting>& setting);
+
+diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp
+index f4c247f910..d85e7bf493 100644
+--- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp
++++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp
+@@ -800,13 +800,12 @@ bool CGUIWindowPVRGuideBase::OpenDateSelectionDialog()
+ {
+ bool bReturn = false;
+
+- KODI::TIME::SystemTime date;
+ CGUIEPGGridContainer* epgGridContainer = GetGridControl();
+- epgGridContainer->GetSelectedDate().GetAsSystemTime(date);
++ CDateTime datetime = epgGridContainer->GetSelectedDate();
+
+- if (CGUIDialogNumeric::ShowAndGetDate(date, g_localizeStrings.Get(19288))) /* Go to date */
++ if (CGUIDialogNumeric::ShowAndGetDate(datetime, g_localizeStrings.Get(19288))) /* Go to date */
+ {
+- epgGridContainer->GoToDate(CDateTime(date));
++ epgGridContainer->GoToDate(datetime);
+ bReturn = true;
+ }
+
+diff --git a/xbmc/settings/windows/GUIControlSettings.cpp b/xbmc/settings/windows/GUIControlSettings.cpp
+index fcbf1fa908..6c9eb3ea68 100644
+--- a/xbmc/settings/windows/GUIControlSettings.cpp
++++ b/xbmc/settings/windows/GUIControlSettings.cpp
+@@ -989,21 +989,19 @@ bool CGUIControlButtonSetting::OnClick()
+ std::shared_ptr<CSettingDate> settingDate =
+ std::static_pointer_cast<CSettingDate>(m_pSetting);
+
+- KODI::TIME::SystemTime systemdate;
+- settingDate->GetDate().GetAsSystemTime(systemdate);
+- if (CGUIDialogNumeric::ShowAndGetDate(systemdate, Localize(buttonControl->GetHeading())))
+- SetValid(settingDate->SetDate(CDateTime(systemdate)));
++ CDateTime datetime = settingDate->GetDate();
++ if (CGUIDialogNumeric::ShowAndGetDate(datetime, Localize(buttonControl->GetHeading())))
++ SetValid(settingDate->SetDate(datetime));
+ }
+ else if (controlFormat == "time")
+ {
+ std::shared_ptr<CSettingTime> settingTime =
+ std::static_pointer_cast<CSettingTime>(m_pSetting);
+
+- KODI::TIME::SystemTime systemtime;
+- settingTime->GetTime().GetAsSystemTime(systemtime);
++ CDateTime datetime = settingTime->GetTime();
+
+- if (CGUIDialogNumeric::ShowAndGetTime(systemtime, Localize(buttonControl->GetHeading())))
+- SetValid(settingTime->SetTime(CDateTime(systemtime)));
++ if (CGUIDialogNumeric::ShowAndGetTime(datetime, Localize(buttonControl->GetHeading())))
++ SetValid(settingTime->SetTime(datetime));
+ }
+ else if (controlFormat == "action")
+ {
+diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp
+index a553bd1887..a8e61e9785 100644
+--- a/xbmc/test/TestDateTime.cpp
++++ b/xbmc/test/TestDateTime.cpp
+@@ -36,17 +36,16 @@ TEST_F(TestDateTime, DateTimeOperators)
+ EXPECT_FALSE(dateTime1 == dateTime2);
+ }
+
+-TEST_F(TestDateTime, SystemTimeOperators)
++TEST_F(TestDateTime, TimePointOperators)
+ {
+ CDateTime dateTime1(1991, 5, 14, 12, 34, 56);
+ CDateTime dateTime2(1991, 5, 14, 12, 34, 57);
+
+- KODI::TIME::SystemTime systemTime;
+- dateTime2.GetAsSystemTime(systemTime);
++ auto tp = dateTime2.GetAsTimePoint();
+
+- EXPECT_TRUE(dateTime1 < systemTime);
+- EXPECT_FALSE(dateTime1 > systemTime);
+- EXPECT_FALSE(dateTime1 == systemTime);
++ EXPECT_TRUE(dateTime1 < tp);
++ EXPECT_FALSE(dateTime1 > tp);
++ EXPECT_FALSE(dateTime1 == tp);
+ }
+
+ TEST_F(TestDateTime, TimeTOperators)
+@@ -529,15 +528,14 @@ TEST_F(TestDateTime, GetAsLocalized)
+ EXPECT_EQ(dateTime2.GetAsLocalizedTime(TIME_FORMAT(256)), "5");
+ }
+
+-TEST_F(TestDateTime, GetAsSystemTime)
++TEST_F(TestDateTime, GetAsTimePoint)
+ {
+ CDateTime dateTime;
+ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56);
+
+- KODI::TIME::SystemTime systemTime;
+- dateTime.GetAsSystemTime(systemTime);
++ auto tp = dateTime.GetAsTimePoint();
+
+- EXPECT_TRUE(dateTime == systemTime);
++ EXPECT_TRUE(dateTime == tp);
+ }
+
+ TEST_F(TestDateTime, GetAsTime)
+diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp
+index 4f69929a42..0275c057f9 100644
+--- a/xbmc/utils/Archive.cpp
++++ b/xbmc/utils/Archive.cpp
+@@ -152,9 +152,9 @@ CArchive& CArchive::operator<<(const std::wstring& wstr)
+ return streamout(wstr.data(), size * sizeof(wchar_t));
+ }
+
+-CArchive& CArchive::operator<<(const KODI::TIME::SystemTime& time)
++CArchive& CArchive::operator<<(const std::chrono::system_clock::time_point& time)
+ {
+- return streamout(&time, sizeof(KODI::TIME::SystemTime));
++ return streamout(&time, sizeof(std::chrono::system_clock::time_point));
+ }
+
+ CArchive& CArchive::operator<<(IArchivable& obj)
+@@ -265,9 +265,9 @@ CArchive& CArchive::operator>>(std::wstring& wstr)
+ return *this;
+ }
+
+-CArchive& CArchive::operator>>(KODI::TIME::SystemTime& time)
++CArchive& CArchive::operator>>(std::chrono::system_clock::time_point& time)
+ {
+- return streamin(&time, sizeof(KODI::TIME::SystemTime));
++ return streamin(&time, sizeof(std::chrono::system_clock::time_point));
+ }
+
+ CArchive& CArchive::operator>>(IArchivable& obj)
+diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h
+index a1af0c3cf8..86a2bebc23 100644
+--- a/xbmc/utils/Archive.h
++++ b/xbmc/utils/Archive.h
+@@ -57,7 +57,7 @@ public:
+ CArchive& operator<<(char c);
+ CArchive& operator<<(const std::string &str);
+ CArchive& operator<<(const std::wstring& wstr);
+- CArchive& operator<<(const KODI::TIME::SystemTime& time);
++ CArchive& operator<<(const std::chrono::system_clock::time_point& time);
+ CArchive& operator<<(IArchivable& obj);
+ CArchive& operator<<(const CVariant& variant);
+ CArchive& operator<<(const std::vector<std::string>& strArray);
+@@ -126,7 +126,7 @@ public:
+
+ CArchive& operator>>(std::string &str);
+ CArchive& operator>>(std::wstring& wstr);
+- CArchive& operator>>(KODI::TIME::SystemTime& time);
++ CArchive& operator>>(std::chrono::system_clock::time_point& time);
+ CArchive& operator>>(IArchivable& obj);
+ CArchive& operator>>(CVariant& variant);
+ CArchive& operator>>(std::vector<std::string>& strArray);
+diff --git a/xbmc/utils/RssManager.cpp b/xbmc/utils/RssManager.cpp
+index b8d350cac5..5e77dd7c13 100644
+--- a/xbmc/utils/RssManager.cpp
++++ b/xbmc/utils/RssManager.cpp
+@@ -142,7 +142,7 @@ bool CRssManager::Load()
+ //! What about the xml encoding?
+ std::string strUrl = pFeed->FirstChild()->ValueStr();
+ set.url.push_back(strUrl);
+- set.interval.push_back(iInterval);
++ set.interval.push_back(std::chrono::minutes(iInterval));
+ }
+ pFeed = pFeed->NextSiblingElement("feed");
+ }
+diff --git a/xbmc/utils/RssManager.h b/xbmc/utils/RssManager.h
+index 2b807d739f..59ac506307 100644
+--- a/xbmc/utils/RssManager.h
++++ b/xbmc/utils/RssManager.h
+@@ -22,7 +22,7 @@ class IRssObserver;
+ typedef struct
+ {
+ bool rtl;
+- std::vector<int> interval;
++ std::vector<std::chrono::nanoseconds> interval;
+ std::vector<std::string> url;
+ } RssSet;
+ typedef std::map<int, RssSet> RssUrls;
+diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp
+index 0b227b63d3..f9f1e4a845 100644
+--- a/xbmc/utils/RssReader.cpp
++++ b/xbmc/utils/RssReader.cpp
+@@ -51,11 +51,14 @@ CRssReader::~CRssReader()
+ if (m_pObserver)
+ m_pObserver->OnFeedRelease();
+ StopThread();
+- for (unsigned int i = 0; i < m_vecTimeStamps.size(); i++)
+- delete m_vecTimeStamps[i];
++ m_vecTimeStamps.clear();
+ }
+
+-void CRssReader::Create(IRssObserver* aObserver, const std::vector<std::string>& aUrls, const std::vector<int> &times, int spacesBetweenFeeds, bool rtl)
++void CRssReader::Create(IRssObserver* aObserver,
++ const std::vector<std::string>& aUrls,
++ const std::vector<std::chrono::nanoseconds>& times,
++ int spacesBetweenFeeds,
++ bool rtl)
+ {
+ std::unique_lock<CCriticalSection> lock(m_critical);
+
+@@ -73,9 +76,7 @@ void CRssReader::Create(IRssObserver* aObserver, const std::vector<std::string>&
+ for (unsigned int i = 0; i < m_vecUpdateTimes.size(); ++i)
+ {
+ AddToQueue(i);
+- KODI::TIME::SystemTime* time = new KODI::TIME::SystemTime;
+- KODI::TIME::GetLocalTime(time);
+- m_vecTimeStamps.push_back(time);
++ m_vecTimeStamps.push_back(std::chrono::system_clock::now().time_since_epoch());
+ }
+ }
+
+@@ -395,18 +396,14 @@ void CRssReader::UpdateObserver()
+
+ void CRssReader::CheckForUpdates()
+ {
+- KODI::TIME::SystemTime time;
+- KODI::TIME::GetLocalTime(&time);
+-
+ for (unsigned int i = 0;i < m_vecUpdateTimes.size(); ++i )
+ {
+- if (m_requestRefresh || ((time.day * 24 * 60) + (time.hour * 60) + time.minute) -
+- ((m_vecTimeStamps[i]->day * 24 * 60) +
+- (m_vecTimeStamps[i]->hour * 60) + m_vecTimeStamps[i]->minute) >
+- m_vecUpdateTimes[i])
++ if (m_requestRefresh ||
++ (std::chrono::system_clock::now().time_since_epoch() - m_vecTimeStamps[i] >
++ m_vecUpdateTimes[i]))
+ {
+ CLog::Log(LOGDEBUG, "Updating RSS");
+- KODI::TIME::GetLocalTime(m_vecTimeStamps[i]);
++ m_vecTimeStamps[i] = std::chrono::system_clock::now().time_since_epoch();
+ AddToQueue(i);
+ }
+ }
+diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h
+index ae9d2f73ca..43c6bde609 100644
+--- a/xbmc/utils/RssReader.h
++++ b/xbmc/utils/RssReader.h
+@@ -28,7 +28,11 @@ public:
+ CRssReader();
+ ~CRssReader() override;
+
+- void Create(IRssObserver* aObserver, const std::vector<std::string>& aUrl, const std::vector<int>& times, int spacesBetweenFeeds, bool rtl);
++ void Create(IRssObserver* aObserver,
++ const std::vector<std::string>& aUrl,
++ const std::vector<std::chrono::nanoseconds>& times,
++ int spacesBetweenFeeds,
++ bool rtl);
+ bool Parse(const std::string& data, int iFeed, const std::string& charset);
+ void getFeed(vecText &text);
+ void AddTag(const std::string &addTag);
+@@ -52,8 +56,8 @@ private:
+
+ std::vector<std::wstring> m_strFeed;
+ std::vector<std::wstring> m_strColors;
+- std::vector<KODI::TIME::SystemTime*> m_vecTimeStamps;
+- std::vector<int> m_vecUpdateTimes;
++ std::vector<std::chrono::nanoseconds> m_vecTimeStamps;
++ std::vector<std::chrono::nanoseconds> m_vecUpdateTimes;
+ int m_spacesBetweenFeeds;
+ CXBMCTinyXML m_xml;
+ std::list<std::string> m_tagSet;
+diff --git a/xbmc/utils/XTimeUtils.h b/xbmc/utils/XTimeUtils.h
+index 91cda40305..9d3b0e86a3 100644
+--- a/xbmc/utils/XTimeUtils.h
++++ b/xbmc/utils/XTimeUtils.h
+@@ -27,42 +27,6 @@ namespace KODI
+ {
+ namespace TIME
+ {
+-struct SystemTime
+-{
+- unsigned short year;
+- unsigned short month;
+- unsigned short dayOfWeek;
+- unsigned short day;
+- unsigned short hour;
+- unsigned short minute;
+- unsigned short second;
+- unsigned short milliseconds;
+-};
+-
+-struct TimeZoneInformation
+-{
+- long bias;
+- std::string standardName;
+- SystemTime standardDate;
+- long standardBias;
+- std::string daylightName;
+- SystemTime daylightDate;
+- long daylightBias;
+-};
+-
+-constexpr int KODI_TIME_ZONE_ID_INVALID{-1};
+-constexpr int KODI_TIME_ZONE_ID_UNKNOWN{0};
+-constexpr int KODI_TIME_ZONE_ID_STANDARD{1};
+-constexpr int KODI_TIME_ZONE_ID_DAYLIGHT{2};
+-
+-struct FileTime
+-{
+- unsigned int lowDateTime;
+- unsigned int highDateTime;
+-};
+-
+-void GetLocalTime(SystemTime* systemTime);
+-uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation);
+
+ template<typename Rep, typename Period>
+ void Sleep(std::chrono::duration<Rep, Period> duration)
+@@ -76,13 +40,5 @@ void Sleep(std::chrono::duration<Rep, Period> duration)
+ std::this_thread::sleep_for(duration);
+ }
+
+-int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime);
+-int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime);
+-long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2);
+-int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime);
+-int LocalFileTimeToFileTime(const FileTime* LocalFileTime, FileTime* fileTime);
+-
+-int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT);
+-int TimeTToFileTime(time_t timeT, FileTime* localFileTime);
+ } // namespace TIME
+ } // namespace KODI
+diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp
+index 90628ea2ed..b9ab780cf9 100644
+--- a/xbmc/utils/test/TestArchive.cpp
++++ b/xbmc/utils/test/TestArchive.cpp
+@@ -220,22 +220,22 @@ TEST_F(TestArchive, StringArchive)
+ EXPECT_STREQ(string_ref.c_str(), string_var.c_str());
+ }
+
+-TEST_F(TestArchive, SystemTimeArchive)
++TEST_F(TestArchive, TimePointArchive)
+ {
+ ASSERT_NE(nullptr, file);
+- KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8};
+- KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0};
++ std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now();
++ std::chrono::system_clock::time_point tp_var;
+
+ CArchive arstore(file, CArchive::store);
+- arstore << SystemTime_ref;
++ arstore << tp_ref;
+ arstore.Close();
+
+ ASSERT_EQ(0, file->Seek(0, SEEK_SET));
+ CArchive arload(file, CArchive::load);
+- arload >> SystemTime_var;
++ arload >> tp_var;
+ arload.Close();
+
+- EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime)));
++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point)));
+ }
+
+ TEST_F(TestArchive, CVariantArchive)
+@@ -335,8 +335,8 @@ TEST_F(TestArchive, MultiTypeArchive)
+ char char_ref = 'A', char_var = '\0';
+ std::string string_ref = "test string", string_var;
+ std::wstring wstring_ref = L"test wstring", wstring_var;
+- KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8};
+- KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0};
++ std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now();
++ std::chrono::system_clock::time_point tp_var;
+ CVariant CVariant_ref((int)1), CVariant_var;
+ std::vector<std::string> strArray_ref, strArray_var;
+ strArray_ref.emplace_back("test strArray_ref 0");
+@@ -362,7 +362,7 @@ TEST_F(TestArchive, MultiTypeArchive)
+ arstore << char_ref;
+ arstore << string_ref;
+ arstore << wstring_ref;
+- arstore << SystemTime_ref;
++ arstore << tp_ref;
+ arstore << CVariant_ref;
+ arstore << strArray_ref;
+ arstore << iArray_ref;
+@@ -382,7 +382,7 @@ TEST_F(TestArchive, MultiTypeArchive)
+ arload >> char_var;
+ arload >> string_var;
+ arload >> wstring_var;
+- arload >> SystemTime_var;
++ arload >> tp_var;
+ arload >> CVariant_var;
+ arload >> strArray_var;
+ arload >> iArray_var;
+@@ -398,7 +398,7 @@ TEST_F(TestArchive, MultiTypeArchive)
+ EXPECT_EQ(char_ref, char_var);
+ EXPECT_STREQ(string_ref.c_str(), string_var.c_str());
+ EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str());
+- EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime)));
++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point)));
+ EXPECT_TRUE(CVariant_var.isInteger());
+ EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str());
+ EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str());
+diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp
+index 92fa5c191f..8d9cf6979d 100644
+--- a/xbmc/video/VideoInfoScanner.cpp
++++ b/xbmc/video/VideoInfoScanner.cpp
+@@ -2005,8 +2005,8 @@ namespace VIDEO
+ else
+ {
+ digest.Update(&pItem->m_dwSize, sizeof(pItem->m_dwSize));
+- KODI::TIME::FileTime time = pItem->m_dateTime;
+- digest.Update(&time, sizeof(KODI::TIME::FileTime));
++ const auto time = pItem->m_dateTime.GetAsTimePoint().time_since_epoch().count();
++ digest.Update(&time, sizeof(std::chrono::nanoseconds));
+ }
+ if (pItem->IsVideo() && !pItem->IsPlayList() && !pItem->IsNFO())
+ count++;
+--
+2.43.0
+
+
+From 466178a3ca4239ff1c837f28ba84283777519990 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Wed, 21 Oct 2020 09:17:33 +0300
+Subject: [PATCH 07/19] TestDateTime: fix GetAsStringsWithBias and add Tzdata
+ tests
+
+The 'GetAsStringsWithBias' test logic assumed the timezone on
+machine bullding Kodi is set to 'UTC'. This is not always the case,
+plus hour value was declared with a typo.
+
+To address this, we compare outputs of two runs of date library,
+and instead add a 'Tzdata' test case comparing local date and time
+against computed values from different timezones:
+
+find /usr/share/zoneinfo/Etc/ -type f | sort -Vu | sed 's,^/usr/share/zoneinfo/,,' | while read TZ
+do
+ TMSTR=$(LANG=C TZ="$TZ" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/')
+ echo " // LANG=C TZ=\"$TZ\" date '+%Y-%m-%dT%H:%M:%S%Ez' -d \"1991-05-14 12:34:56 UTC\" | sed 's/[0-9][0-9]$/:&/'"
+ echo " tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());"
+ echo " zone = date::make_zoned(\"$TZ\", tps);"
+ echo " EXPECT_EQ(date::format(\"%FT%T%Ez\", zone), \"$TMSTR\") << \"tzdata information not valid for '$TZ'\";"
+ echo ""
+done
+---
+ xbmc/test/TestDateTime.cpp | 168 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 166 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp
+index a8e61e9785..0ff2bb443b 100644
+--- a/xbmc/test/TestDateTime.cpp
++++ b/xbmc/test/TestDateTime.cpp
+@@ -11,6 +11,7 @@
+ #include "guilib/LocalizeStrings.h"
+
+ #include <array>
++#include <chrono>
+ #include <iostream>
+
+ #define USE_OS_TZDB 0
+@@ -330,10 +331,11 @@ TEST_F(TestDateTime, GetAsStringsWithBias)
+ std::cout << dateTime.GetAsW3CDateTime(false) << std::endl;
+ std::cout << dateTime.GetAsW3CDateTime(true) << std::endl;
+
+- auto zone = date::make_zoned(date::current_zone(), dateTime.GetAsTimePoint());
++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ auto zone = date::make_zoned(date::current_zone(), tps);
+
+ EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT");
+- EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T05:34:56" + date::format("%Ez", zone));
++ EXPECT_EQ(dateTime.GetAsW3CDateTime(false), date::format("%FT%T%Ez", zone));
+ EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T12:34:56Z");
+ }
+
+@@ -601,3 +603,165 @@ TEST_F(TestDateTime, Reset)
+ EXPECT_EQ(dateTime.GetMinute(), 0);
+ EXPECT_EQ(dateTime.GetSecond(), 0);
+ }
++
++TEST_F(TestDateTime, Tzdata)
++{
++ CDateTime dateTime;
++ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56);
++
++ // LANG=C TZ="Etc/GMT+1" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ auto zone = date::make_zoned("Etc/GMT+1", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T11:34:56-01:00")
++ << "tzdata information not valid for 'Etc/GMT+1'";
++
++ // LANG=C TZ="Etc/GMT+2" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+2", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T10:34:56-02:00")
++ << "tzdata information not valid for 'Etc/GMT+2'";
++
++ // LANG=C TZ="Etc/GMT+3" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+3", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T09:34:56-03:00")
++ << "tzdata information not valid for 'Etc/GMT+3'";
++
++ // LANG=C TZ="Etc/GMT+4" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+4", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T08:34:56-04:00")
++ << "tzdata information not valid for 'Etc/GMT+4'";
++
++ // LANG=C TZ="Etc/GMT+5" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+5", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T07:34:56-05:00")
++ << "tzdata information not valid for 'Etc/GMT+5'";
++
++ // LANG=C TZ="Etc/GMT+6" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+6", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T06:34:56-06:00")
++ << "tzdata information not valid for 'Etc/GMT+6'";
++
++ // LANG=C TZ="Etc/GMT+7" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+7", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T05:34:56-07:00")
++ << "tzdata information not valid for 'Etc/GMT+7'";
++
++ // LANG=C TZ="Etc/GMT+8" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+8", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T04:34:56-08:00")
++ << "tzdata information not valid for 'Etc/GMT+8'";
++
++ // LANG=C TZ="Etc/GMT+9" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+9", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T03:34:56-09:00")
++ << "tzdata information not valid for 'Etc/GMT+9'";
++
++ // LANG=C TZ="Etc/GMT+10" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+10", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T02:34:56-10:00")
++ << "tzdata information not valid for 'Etc/GMT+10'";
++
++ // LANG=C TZ="Etc/GMT+11" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+11", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T01:34:56-11:00")
++ << "tzdata information not valid for 'Etc/GMT+11'";
++
++ // LANG=C TZ="Etc/GMT+12" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT+12", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T00:34:56-12:00")
++ << "tzdata information not valid for 'Etc/GMT+12'";
++
++ // LANG=C TZ="Etc/GMT-1" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-1", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T13:34:56+01:00")
++ << "tzdata information not valid for 'Etc/GMT-1'";
++
++ // LANG=C TZ="Etc/GMT-2" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-2", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T14:34:56+02:00")
++ << "tzdata information not valid for 'Etc/GMT-2'";
++
++ // LANG=C TZ="Etc/GMT-3" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-3", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T15:34:56+03:00")
++ << "tzdata information not valid for 'Etc/GMT-3'";
++
++ // LANG=C TZ="Etc/GMT-4" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-4", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T16:34:56+04:00")
++ << "tzdata information not valid for 'Etc/GMT-4'";
++
++ // LANG=C TZ="Etc/GMT-5" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-5", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T17:34:56+05:00")
++ << "tzdata information not valid for 'Etc/GMT-5'";
++
++ // LANG=C TZ="Etc/GMT-6" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-6", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T18:34:56+06:00")
++ << "tzdata information not valid for 'Etc/GMT-6'";
++
++ // LANG=C TZ="Etc/GMT-7" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-7", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T19:34:56+07:00")
++ << "tzdata information not valid for 'Etc/GMT-7'";
++
++ // LANG=C TZ="Etc/GMT-8" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-8", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T20:34:56+08:00")
++ << "tzdata information not valid for 'Etc/GMT-8'";
++
++ // LANG=C TZ="Etc/GMT-9" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-9", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T21:34:56+09:00")
++ << "tzdata information not valid for 'Etc/GMT-9'";
++
++ // LANG=C TZ="Etc/GMT-10" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-10", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T22:34:56+10:00")
++ << "tzdata information not valid for 'Etc/GMT-10'";
++
++ // LANG=C TZ="Etc/GMT-11" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-11", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T23:34:56+11:00")
++ << "tzdata information not valid for 'Etc/GMT-11'";
++
++ // LANG=C TZ="Etc/GMT-12" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-12", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T00:34:56+12:00")
++ << "tzdata information not valid for 'Etc/GMT-12'";
++
++ // LANG=C TZ="Etc/GMT-13" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-13", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T01:34:56+13:00")
++ << "tzdata information not valid for 'Etc/GMT-13'";
++
++ // LANG=C TZ="Etc/GMT-14" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/'
++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ zone = date::make_zoned("Etc/GMT-14", tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00")
++ << "tzdata information not valid for 'Etc/GMT-14'";
++}
+--
+2.43.0
+
+
+From 72720c4e84bbbb1d5859cd727b1068a74a8be3af Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Tue, 3 Nov 2020 17:51:26 +0200
+Subject: [PATCH 08/19] Remove GetAsUTCDateTime and add GetAsLocalDateTime
+
+The 'm_time' now represents a UTC time-point, so 'GetAsUTCDateTime'
+does nothing useful. Remove it fully, and add 'GetAsLocalDateTime'
+function that we will use later to convert UTC (system) time to the
+local time needed to get displayed in UI.
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/XBDateTime.cpp | 9 ++++++---
+ xbmc/XBDateTime.h | 4 +++-
+ xbmc/network/WebServer.cpp | 6 +++---
+ xbmc/pvr/epg/EpgContainer.cpp | 14 +++++++-------
+ xbmc/pvr/epg/EpgInfoTag.cpp | 4 ++--
+ xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp | 1 -
+ xbmc/pvr/timers/PVRTimerRuleMatcher.cpp | 2 +-
+ xbmc/pvr/timers/PVRTimers.cpp | 1 -
+ xbmc/test/TestDateTime.cpp | 16 ++++++++--------
+ 9 files changed, 30 insertions(+), 27 deletions(-)
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index d8187b71e6..afd2d8c6a5 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -1210,10 +1210,13 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds /
+ return GetAsLocalizedTime("", false);
+ }
+
+-CDateTime CDateTime::GetAsUTCDateTime() const
++CDateTime CDateTime::GetAsLocalDateTime() const
+ {
+- CDateTime time(m_time);
+- return time;
++ auto zone = date::make_zoned(date::current_zone(), m_time);
++
++ return CDateTime(
++ std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch())
++ .count());
+ }
+
+ std::string CDateTime::GetAsRFC1123DateTime() const
+diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h
+index 16d6217c8a..a810619566 100644
+--- a/xbmc/XBDateTime.h
++++ b/xbmc/XBDateTime.h
+@@ -157,7 +157,9 @@ public:
+ void GetAsTm(tm& time) const;
+ std::chrono::system_clock::time_point GetAsTimePoint() const;
+
+- CDateTime GetAsUTCDateTime() const;
++ /*! \brief convert UTC datetime to local datetime
++ */
++ CDateTime GetAsLocalDateTime() const;
+ std::string GetAsSaveString() const;
+ std::string GetAsDBDateTime() const;
+ std::string GetAsDBDate() const;
+diff --git a/xbmc/network/WebServer.cpp b/xbmc/network/WebServer.cpp
+index 0ee1696033..fc3583c16d 100644
+--- a/xbmc/network/WebServer.cpp
++++ b/xbmc/network/WebServer.cpp
+@@ -222,7 +222,7 @@ MHD_RESULT CWebServer::HandlePartialRequest(struct MHD_Connection* connection,
+ CDateTime ifUnmodifiedSinceDate;
+ // handle If-Modified-Since (but only if the response is cacheable)
+ if (cacheable && ifModifiedSinceDate.SetFromRFC1123DateTime(ifModifiedSince) &&
+- lastModified.GetAsUTCDateTime() <= ifModifiedSinceDate)
++ lastModified <= ifModifiedSinceDate)
+ {
+ struct MHD_Response* response = create_response(0, nullptr, MHD_NO, MHD_NO);
+ if (response == nullptr)
+@@ -235,7 +235,7 @@ MHD_RESULT CWebServer::HandlePartialRequest(struct MHD_Connection* connection,
+ }
+ // handle If-Unmodified-Since
+ else if (ifUnmodifiedSinceDate.SetFromRFC1123DateTime(ifUnmodifiedSince) &&
+- lastModified.GetAsUTCDateTime() > ifUnmodifiedSinceDate)
++ lastModified > ifUnmodifiedSinceDate)
+ return SendErrorResponse(request, MHD_HTTP_PRECONDITION_FAILED, request.method);
+ }
+
+@@ -504,7 +504,7 @@ bool CWebServer::IsRequestRanged(const HTTPRequest& request, const CDateTime& la
+
+ // check if the last modification is newer than the If-Range date
+ // if so we have to server the whole file instead
+- if (lastModified.GetAsUTCDateTime() > ifRangeDate)
++ if (lastModified > ifRangeDate)
+ ranges.Clear();
+ }
+ }
+diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp
+index d6f20153ef..38aa15809e 100644
+--- a/xbmc/pvr/epg/EpgContainer.cpp
++++ b/xbmc/pvr/epg/EpgContainer.cpp
+@@ -335,7 +335,7 @@ void CPVREpgContainer::Process()
+ time_t iLastEpgCleanup = 0;
+ bool bUpdateEpg = true;
+
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow);
++ CDateTime::GetUTCDateTime().GetAsTime(iNow);
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ bUpdateEpg = (iNow >= m_iNextEpgUpdate) && !m_bSuspended;
+@@ -593,7 +593,7 @@ std::shared_ptr<CPVREpg> CPVREpgContainer::CreateChannelEpg(int iEpgId, const st
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ m_bPreventUpdates = false;
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iNextEpgUpdate);
++ CDateTime::GetUTCDateTime().GetAsTime(m_iNextEpgUpdate);
+ }
+
+ m_events.Publish(PVREvent::EpgContainer);
+@@ -613,7 +613,7 @@ bool CPVREpgContainer::RemoveOldEntries()
+ epgEntry.second->Cleanup(cleanupTime);
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iLastEpgCleanup);
++ CDateTime::GetUTCDateTime().GetAsTime(m_iLastEpgCleanup);
+
+ return true;
+ }
+@@ -787,7 +787,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */)
+ {
+ /* the update has been interrupted. try again later */
+ time_t iNow;
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow);
++ CDateTime::GetUTCDateTime().GetAsTime(iNow);
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ m_iNextEpgUpdate = iNow + advancedSettings->m_iEpgRetryInterruptedUpdateInterval;
+@@ -795,7 +795,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */)
+ else
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iNextEpgUpdate);
++ CDateTime::GetUTCDateTime().GetAsTime(m_iNextEpgUpdate);
+ m_iNextEpgUpdate += advancedSettings->m_iEpgUpdateCheckInterval;
+ if (m_pendingUpdates == pendingUpdates)
+ m_pendingUpdates = 0;
+@@ -852,7 +852,7 @@ bool CPVREpgContainer::CheckPlayingEvents()
+ m_critSection.unlock();
+
+ time_t iNow;
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow);
++ CDateTime::GetUTCDateTime().GetAsTime(iNow);
+ if (iNow >= iNextEpgActiveTagCheck)
+ {
+ bFoundChanges = std::accumulate(epgs.cbegin(), epgs.cend(), bFoundChanges,
+@@ -860,7 +860,7 @@ bool CPVREpgContainer::CheckPlayingEvents()
+ return epgEntry.second->CheckPlayingEvent() ? true : found;
+ });
+
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNextEpgActiveTagCheck);
++ CDateTime::GetUTCDateTime().GetAsTime(iNextEpgActiveTagCheck);
+ iNextEpgActiveTagCheck += CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iEpgActiveTagCheckInterval;
+
+ /* pvr tags always start on the full minute */
+diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp
+index 8b0930e5d2..70daa5033b 100644
+--- a/xbmc/pvr/epg/EpgInfoTag.cpp
++++ b/xbmc/pvr/epg/EpgInfoTag.cpp
+@@ -233,7 +233,7 @@ float CPVREpgInfoTag::ProgressPercentage() const
+ float fReturn = 0.0f;
+
+ time_t currentTime, startTime, endTime;
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime);
++ CDateTime::GetUTCDateTime().GetAsTime(currentTime);
+ m_startTime.GetAsTime(startTime);
+ m_endTime.GetAsTime(endTime);
+ int iDuration = endTime - startTime > 0 ? endTime - startTime : 3600;
+@@ -249,7 +249,7 @@ float CPVREpgInfoTag::ProgressPercentage() const
+ int CPVREpgInfoTag::Progress() const
+ {
+ time_t currentTime, startTime;
+- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime);
++ CDateTime::GetUTCDateTime().GetAsTime(currentTime);
+ m_startTime.GetAsTime(startTime);
+ int iDuration = currentTime - startTime;
+
+diff --git a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp
+index 1a0a99a7a2..5e27ea69c5 100644
+--- a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp
++++ b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp
+@@ -92,7 +92,6 @@ bool CPVRGUIActionsPowerManagement::CanSystemPowerdown(bool bAskUser /*= true*/)
+ CDateTime dailywakeuptime;
+ dailywakeuptime.SetFromDBTime(
+ m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME));
+- dailywakeuptime = dailywakeuptime.GetAsUTCDateTime();
+
+ const CDateTimeSpan diff(dailywakeuptime - now);
+ int mins = diff.GetSecondsTotal() / 60;
+diff --git a/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp b/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp
+index 9178e85ec2..b34688bdce 100644
+--- a/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp
++++ b/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp
+@@ -66,7 +66,7 @@ CDateTime CPVRTimerRuleMatcher::GetNextTimerStart() const
+ }
+ }
+
+- return nextStart.GetAsUTCDateTime();
++ return nextStart;
+ }
+
+ bool CPVRTimerRuleMatcher::Matches(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const
+diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp
+index 760bb192f7..5fe64ec7e4 100644
+--- a/xbmc/pvr/timers/PVRTimers.cpp
++++ b/xbmc/pvr/timers/PVRTimers.cpp
+@@ -1274,7 +1274,6 @@ CDateTime CPVRTimers::GetNextEventTime() const
+ CDateTime dailywakeuptime;
+ dailywakeuptime.SetFromDBTime(
+ m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME));
+- dailywakeuptime = dailywakeuptime.GetAsUTCDateTime();
+
+ dailywakeuptime.SetDateTime(now.GetYear(), now.GetMonth(), now.GetDay(),
+ dailywakeuptime.GetHour(), dailywakeuptime.GetMinute(),
+diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp
+index 0ff2bb443b..4c55fafe06 100644
+--- a/xbmc/test/TestDateTime.cpp
++++ b/xbmc/test/TestDateTime.cpp
+@@ -573,20 +573,20 @@ TEST_F(TestDateTime, GetAsTm)
+ }
+ }
+
+-TEST_F(TestDateTime, GetAsUTCDateTime)
++TEST_F(TestDateTime, GetAsLocalDateTime)
+ {
+ CDateTime dateTime1;
+ dateTime1.SetDateTime(1991, 05, 14, 12, 34, 56);
+
+ CDateTime dateTime2;
+- dateTime2 = dateTime1.GetAsUTCDateTime();
++ dateTime2 = dateTime1.GetAsLocalDateTime();
+
+- EXPECT_EQ(dateTime2.GetYear(), 1991);
+- EXPECT_EQ(dateTime2.GetMonth(), 5);
+- EXPECT_EQ(dateTime2.GetDay(), 14);
+- EXPECT_EQ(dateTime2.GetHour(), 12);
+- EXPECT_EQ(dateTime2.GetMinute(), 34);
+- EXPECT_EQ(dateTime2.GetSecond(), 56);
++ auto zoned_time = date::make_zoned(date::current_zone(), dateTime1.GetAsTimePoint());
++ auto time = zoned_time.get_local_time().time_since_epoch();
++
++ CDateTime cmpTime(std::chrono::duration_cast<std::chrono::seconds>(time).count());
++
++ EXPECT_TRUE(dateTime1 == cmpTime);
+ }
+
+ TEST_F(TestDateTime, Reset)
+--
+2.43.0
+
+
+From d394f4639fd434647a393b99956d22417c68401b Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Tue, 3 Nov 2020 22:49:09 +0200
+Subject: [PATCH 09/19] Compensate the representation change
+
+... from local time by default to UTC time by default.
+
+Namely, 'CDateTime::SetFromUTCDateTime' converted the UTC time
+to local time in the implementation of CDateTime before
+'std::chrono'. Now this conversion has gone, and to avoid
+displaying PVR times in UTC, 'GetAsLocalDateTime' is added
+where necessary.
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/pvr/epg/EpgInfoTag.cpp | 8 ++------
+ xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp | 4 ++--
+ xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp | 2 +-
+ xbmc/pvr/recordings/PVRRecording.cpp | 4 ++--
+ 4 files changed, 7 insertions(+), 11 deletions(-)
+
+diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp
+index 70daa5033b..3f104aa032 100644
+--- a/xbmc/pvr/epg/EpgInfoTag.cpp
++++ b/xbmc/pvr/epg/EpgInfoTag.cpp
+@@ -293,9 +293,7 @@ CDateTime CPVREpgInfoTag::StartAsUTC() const
+
+ CDateTime CPVREpgInfoTag::StartAsLocalTime() const
+ {
+- CDateTime retVal;
+- retVal.SetFromUTCDateTime(m_startTime);
+- return retVal;
++ return m_startTime.GetAsLocalDateTime();
+ }
+
+ CDateTime CPVREpgInfoTag::EndAsUTC() const
+@@ -305,9 +303,7 @@ CDateTime CPVREpgInfoTag::EndAsUTC() const
+
+ CDateTime CPVREpgInfoTag::EndAsLocalTime() const
+ {
+- CDateTime retVal;
+- retVal.SetFromUTCDateTime(m_endTime);
+- return retVal;
++ return m_endTime.GetAsLocalDateTime();
+ }
+
+ void CPVREpgInfoTag::SetEndFromUTC(const CDateTime& end)
+diff --git a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp
+index e8fac010ca..ef7a715f70 100644
+--- a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp
++++ b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp
+@@ -121,9 +121,9 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList>&
+ ////////////////////////////////////////////////////////////////////////
+ // Create ruler items
+ CDateTime ruler;
+- ruler.SetFromUTCDateTime(m_gridStart);
++ ruler.SetFromUTCDateTime(m_gridStart.GetAsLocalDateTime());
+ CDateTime rulerEnd;
+- rulerEnd.SetFromUTCDateTime(m_gridEnd);
++ rulerEnd.SetFromUTCDateTime(m_gridEnd.GetAsLocalDateTime());
+ CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true)));
+ rulerItem->SetProperty("DateLabel", true);
+ m_rulerItems.emplace_back(rulerItem);
+diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
+index e5dfdb9ea0..3d2cf09b3f 100644
+--- a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
++++ b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
+@@ -239,7 +239,7 @@ std::string CPVRGUITimesInfo::TimeToTimeString(time_t datetime, TIME_FORMAT form
+ {
+ CDateTime time;
+ time.SetFromUTCDateTime(datetime);
+- return time.GetAsLocalizedTime(format, withSeconds);
++ return time.GetAsLocalDateTime().GetAsLocalizedTime(format, withSeconds);
+ }
+
+ std::string CPVRGUITimesInfo::GetTimeshiftStartTime(TIME_FORMAT format) const
+diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp
+index a2e1cbd131..8e047b8d52 100644
+--- a/xbmc/pvr/recordings/PVRRecording.cpp
++++ b/xbmc/pvr/recordings/PVRRecording.cpp
+@@ -524,7 +524,7 @@ void CPVRRecording::UpdatePath()
+ const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const
+ {
+ static CDateTime tmp;
+- tmp.SetFromUTCDateTime(m_recordingTime);
++ tmp.SetFromUTCDateTime(m_recordingTime.GetAsLocalDateTime());
+
+ return tmp;
+ }
+@@ -538,7 +538,7 @@ CDateTime CPVRRecording::EndTimeAsUTC() const
+ CDateTime CPVRRecording::EndTimeAsLocalTime() const
+ {
+ CDateTime ret;
+- ret.SetFromUTCDateTime(EndTimeAsUTC());
++ ret.SetFromUTCDateTime(EndTimeAsUTC().GetAsLocalDateTime());
+ return ret;
+ }
+
+--
+2.43.0
+
+
+From e9cbb86184358f6eb3235a76936fedbf38ab4d97 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Wed, 4 Nov 2020 11:13:15 +0200
+Subject: [PATCH 10/19] Get rid of {Set,}FromUTCDateTime
+
+ * The 'const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const'
+ method needs 'static' CDateTime instance set explicitly. This manifested
+ in Debian Bug #980038 : the return value of function is explicitly nulled
+ out causing immediate crash when using any PVR addon manipulating PVR
+ recordings.
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/FileItem.cpp | 2 +-
+ xbmc/XBDateTime.cpp | 33 ++-----------------
+ xbmc/XBDateTime.h | 4 ---
+ .../savestates/SavestateDatabase.cpp | 2 +-
+ xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp | 8 ++---
+ xbmc/pvr/epg/Epg.cpp | 2 +-
+ xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp | 4 +--
+ xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp | 3 +-
+ xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp | 3 +-
+ xbmc/pvr/recordings/PVRRecording.cpp | 8 ++---
+ xbmc/test/TestDateTime.cpp | 26 ---------------
+ 11 files changed, 14 insertions(+), 81 deletions(-)
+
+diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp
+index 2eb5eb072c..8f14467aff 100644
+--- a/xbmc/FileItem.cpp
++++ b/xbmc/FileItem.cpp
+@@ -199,7 +199,7 @@ CFileItem::CFileItem(const std::shared_ptr<PVR::CPVREpgSearchFilter>& filter)
+
+ const CDateTime lastExec = filter->GetLastExecutedDateTime();
+ if (lastExec.IsValid())
+- m_dateTime.SetFromUTCDateTime(lastExec);
++ m_dateTime = lastExec;
+
+ SetArt("icon", "DefaultPVRSearch.png");
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index afd2d8c6a5..86168ecc13 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -613,19 +613,6 @@ std::string CDateTime::GetAsSaveString() const
+ return date::format("%Y%m%d_%H%M%S", sp);
+ }
+
+-bool CDateTime::SetFromUTCDateTime(const CDateTime &dateTime)
+-{
+- m_time = dateTime.m_time;
+- m_state = valid;
+- return true;
+-}
+-
+-bool CDateTime::SetFromUTCDateTime(const time_t &dateTime)
+-{
+- CDateTime tmp(dateTime);
+- return SetFromUTCDateTime(tmp);
+-}
+-
+ bool CDateTime::SetFromW3CDate(const std::string &dateTime)
+ {
+ std::string date;
+@@ -700,10 +687,8 @@ bool CDateTime::SetFromW3CDateTime(const std::string &dateTime, bool ignoreTimez
+
+ if (!ignoreTimezone && !zone.empty())
+ {
+- // check if the timezone is UTC
+- if (StringUtils::StartsWith(zone, "Z"))
+- return SetFromUTCDateTime(tmpDateTime);
+- else
++ // check if the timezone is not UTC
++ if (!StringUtils::StartsWith(zone, "Z"))
+ {
+ // retrieve the timezone offset (ignoring the + or -)
+ CDateTimeSpan zoneSpan; zoneSpan.SetFromTimeString(zone.substr(1));
+@@ -853,20 +838,6 @@ CDateTime CDateTime::FromW3CDateTime(const std::string &date, bool ignoreTimezon
+ return dt;
+ }
+
+-CDateTime CDateTime::FromUTCDateTime(const CDateTime &dateTime)
+-{
+- CDateTime dt;
+- dt.SetFromUTCDateTime(dateTime);
+- return dt;
+-}
+-
+-CDateTime CDateTime::FromUTCDateTime(const time_t &dateTime)
+-{
+- CDateTime dt;
+- dt.SetFromUTCDateTime(dateTime);
+- return dt;
+-}
+-
+ CDateTime CDateTime::FromRFC1123DateTime(const std::string &dateTime)
+ {
+ CDateTime dt;
+diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h
+index a810619566..ff2d758caa 100644
+--- a/xbmc/XBDateTime.h
++++ b/xbmc/XBDateTime.h
+@@ -78,8 +78,6 @@ public:
+ static CDateTime FromDBTime(const std::string &time);
+ static CDateTime FromW3CDate(const std::string &date);
+ static CDateTime FromW3CDateTime(const std::string &date, bool ignoreTimezone = false);
+- static CDateTime FromUTCDateTime(const CDateTime &dateTime);
+- static CDateTime FromUTCDateTime(const time_t &dateTime);
+ static CDateTime FromRFC1123DateTime(const std::string &dateTime);
+
+ const CDateTime& operator =(const time_t& right);
+@@ -144,8 +142,6 @@ public:
+ bool SetFromDBTime(const std::string &time);
+ bool SetFromW3CDate(const std::string &date);
+ bool SetFromW3CDateTime(const std::string &date, bool ignoreTimezone = false);
+- bool SetFromUTCDateTime(const CDateTime &dateTime);
+- bool SetFromUTCDateTime(const time_t &dateTime);
+ bool SetFromRFC1123DateTime(const std::string &dateTime);
+
+ /*! \brief set from a database datetime format YYYY-MM-DD HH:MM:SS
+diff --git a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp
+index 2611f25ad8..2a44e07596 100644
+--- a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp
++++ b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp
+@@ -149,7 +149,7 @@ void CSavestateDatabase::GetSavestateItem(const ISavestate& savestate,
+ const std::string& savestatePath,
+ CFileItem& item)
+ {
+- CDateTime dateUTC = CDateTime::FromUTCDateTime(savestate.Created());
++ CDateTime dateUTC = savestate.Created();
+
+ std::string label;
+ std::string label2;
+diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp
+index 4cf7f2f0c4..13b826c1b1 100644
+--- a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp
++++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp
+@@ -252,7 +252,7 @@ CDateTime CGUIDialogPVRGuideSearch::ReadDateTime(const std::string& strDate, con
+ sscanf(strTime.c_str(), "%d:%d", &iHours, &iMinutes);
+ dateTime.SetFromDBDate(strDate);
+ dateTime.SetDateTime(dateTime.GetYear(), dateTime.GetMonth(), dateTime.GetDay(), iHours, iMinutes, 0);
+- return dateTime.GetAsUTCDateTime();
++ return dateTime;
+ }
+
+ bool CGUIDialogPVRGuideSearch::IsRadioSelected(int controlID)
+@@ -358,10 +358,8 @@ void CGUIDialogPVRGuideSearch::Update()
+ if (!m_endDateTime.IsValid())
+ m_endDateTime = m_startDateTime + CDateTimeSpan(10, 0, 0, 0); // default to start + 10 days
+
+- CDateTime startLocal;
+- startLocal.SetFromUTCDateTime(m_startDateTime);
+- CDateTime endLocal;
+- endLocal.SetFromUTCDateTime(m_endDateTime);
++ CDateTime startLocal = m_startDateTime;
++ CDateTime endLocal = m_endDateTime;
+
+ SET_CONTROL_LABEL2(CONTROL_EDIT_START_TIME, startLocal.GetAsLocalizedTime("", false));
+ {
+diff --git a/xbmc/pvr/epg/Epg.cpp b/xbmc/pvr/epg/Epg.cpp
+index 1112b2ff89..bb0dbf967b 100644
+--- a/xbmc/pvr/epg/Epg.cpp
++++ b/xbmc/pvr/epg/Epg.cpp
+@@ -264,7 +264,7 @@ bool CPVREpg::Update(time_t start,
+
+ if (!m_lastScanTime.IsValid())
+ {
+- m_lastScanTime.SetFromUTCDateTime(time_t(0));
++ m_lastScanTime = time_t(0);
+ m_bUpdateLastScanTime = true;
+ }
+ }
+diff --git a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp
+index ef7a715f70..3e89c06d6e 100644
+--- a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp
++++ b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp
+@@ -121,9 +121,9 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList>&
+ ////////////////////////////////////////////////////////////////////////
+ // Create ruler items
+ CDateTime ruler;
+- ruler.SetFromUTCDateTime(m_gridStart.GetAsLocalDateTime());
++ ruler = m_gridStart.GetAsLocalDateTime();
+ CDateTime rulerEnd;
+- rulerEnd.SetFromUTCDateTime(m_gridEnd.GetAsLocalDateTime());
++ rulerEnd = m_gridEnd.GetAsLocalDateTime();
+ CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true)));
+ rulerItem->SetProperty("DateLabel", true);
+ m_rulerItems.emplace_back(rulerItem);
+diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp
+index 9cffb9a934..80c25118b0 100644
+--- a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp
++++ b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp
+@@ -568,8 +568,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem* item,
+ {
+ case LISTITEM_DATE:
+ {
+- CDateTime lastExecLocal;
+- lastExecLocal.SetFromUTCDateTime(filter->GetLastExecutedDateTime());
++ CDateTime lastExecLocal = filter->GetLastExecutedDateTime();
+ strValue = GetAsLocalizedDateTimeString(lastExecLocal);
+ if (strValue.empty())
+ strValue = g_localizeStrings.Get(10006); // "N/A"
+diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
+index 3d2cf09b3f..c5b44b840c 100644
+--- a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
++++ b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp
+@@ -237,8 +237,7 @@ void CPVRGUITimesInfo::Update()
+
+ std::string CPVRGUITimesInfo::TimeToTimeString(time_t datetime, TIME_FORMAT format, bool withSeconds)
+ {
+- CDateTime time;
+- time.SetFromUTCDateTime(datetime);
++ CDateTime time(datetime);
+ return time.GetAsLocalDateTime().GetAsLocalizedTime(format, withSeconds);
+ }
+
+diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp
+index 8e047b8d52..5a82c7b1dc 100644
+--- a/xbmc/pvr/recordings/PVRRecording.cpp
++++ b/xbmc/pvr/recordings/PVRRecording.cpp
+@@ -523,9 +523,7 @@ void CPVRRecording::UpdatePath()
+
+ const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const
+ {
+- static CDateTime tmp;
+- tmp.SetFromUTCDateTime(m_recordingTime.GetAsLocalDateTime());
+-
++ static CDateTime tmp = m_recordingTime.GetAsLocalDateTime();
+ return tmp;
+ }
+
+@@ -537,9 +535,7 @@ CDateTime CPVRRecording::EndTimeAsUTC() const
+
+ CDateTime CPVRRecording::EndTimeAsLocalTime() const
+ {
+- CDateTime ret;
+- ret.SetFromUTCDateTime(EndTimeAsUTC().GetAsLocalDateTime());
+- return ret;
++ return EndTimeAsUTC().GetAsLocalDateTime();
+ }
+
+ bool CPVRRecording::WillBeExpiredWithNewLifetime(int iLifetime) const
+diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp
+index 4c55fafe06..ea910a8763 100644
+--- a/xbmc/test/TestDateTime.cpp
++++ b/xbmc/test/TestDateTime.cpp
+@@ -240,32 +240,6 @@ TEST_F(TestDateTime, SetFromW3CDateTime)
+ EXPECT_EQ(dateTime2.GetSecond(), 30);
+ }
+
+-TEST_F(TestDateTime, SetFromUTCDateTime)
+-{
+- CDateTime dateTime1;
+- dateTime1.SetFromDBDateTime("1991-05-14 12:34:56");
+-
+- CDateTime dateTime2;
+- EXPECT_TRUE(dateTime2.SetFromUTCDateTime(dateTime1));
+- EXPECT_EQ(dateTime2.GetYear(), 1991);
+- EXPECT_EQ(dateTime2.GetMonth(), 5);
+- EXPECT_EQ(dateTime2.GetDay(), 14);
+- EXPECT_EQ(dateTime2.GetHour(), 12);
+- EXPECT_EQ(dateTime2.GetMinute(), 34);
+- EXPECT_EQ(dateTime2.GetSecond(), 56);
+-
+- const time_t time = 674224496;
+-
+- CDateTime dateTime3;
+- EXPECT_TRUE(dateTime3.SetFromUTCDateTime(time));
+- EXPECT_EQ(dateTime3.GetYear(), 1991);
+- EXPECT_EQ(dateTime3.GetMonth(), 5);
+- EXPECT_EQ(dateTime3.GetDay(), 14);
+- EXPECT_EQ(dateTime3.GetHour(), 12);
+- EXPECT_EQ(dateTime3.GetMinute(), 34);
+- EXPECT_EQ(dateTime3.GetSecond(), 56);
+-}
+-
+ TEST_F(TestDateTime, SetFromRFC1123DateTime)
+ {
+ std::string dateTime1("Mon, 21 Oct 2018 12:16:24 GMT");
+--
+2.43.0
+
+
+From 9583d0b325df73f5e29b4c901715b9a6bc389295 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Thu, 13 May 2021 11:18:31 +0000
+Subject: [PATCH 11/19] Fix one-time assignment of PVR recording times
+
+Fixes pvr.dvbviewer#49
+Closes: #984682
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/pvr/recordings/PVRRecording.cpp | 5 ++---
+ xbmc/pvr/recordings/PVRRecording.h | 2 +-
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp
+index 5a82c7b1dc..39eea88740 100644
+--- a/xbmc/pvr/recordings/PVRRecording.cpp
++++ b/xbmc/pvr/recordings/PVRRecording.cpp
+@@ -521,10 +521,9 @@ void CPVRRecording::UpdatePath()
+ m_strChannelName, m_recordingTime, m_strRecordingId);
+ }
+
+-const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const
++CDateTime CPVRRecording::RecordingTimeAsLocalTime() const
+ {
+- static CDateTime tmp = m_recordingTime.GetAsLocalDateTime();
+- return tmp;
++ return m_recordingTime.GetAsLocalDateTime();
+ }
+
+ CDateTime CPVRRecording::EndTimeAsUTC() const
+diff --git a/xbmc/pvr/recordings/PVRRecording.h b/xbmc/pvr/recordings/PVRRecording.h
+index bdd8378225..dd125ad1ea 100644
+--- a/xbmc/pvr/recordings/PVRRecording.h
++++ b/xbmc/pvr/recordings/PVRRecording.h
+@@ -188,7 +188,7 @@ public:
+ * @brief Retrieve the recording start as local time
+ * @return the recording start time
+ */
+- const CDateTime& RecordingTimeAsLocalTime() const;
++ CDateTime RecordingTimeAsLocalTime() const;
+
+ /*!
+ * @brief Retrieve the recording end as UTC time
+--
+2.43.0
+
+
+From 732620e37163d653ec75bbefd2a58293e2303420 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Wed, 21 Dec 2022 18:27:24 +0000
+Subject: [PATCH 12/19] Move date includes to separate header
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/ServiceManager.cpp | 5 +----
+ xbmc/XBDateTime.cpp | 8 +-------
+ xbmc/addons/TimeZoneResource.cpp | 5 +++--
+ xbmc/application/Application.cpp | 5 +----
+ xbmc/platform/posix/PosixTimezone.cpp | 21 +++++++++------------
+ xbmc/test/TestDateTime.cpp | 5 +----
+ xbmc/utils/CMakeLists.txt | 1 +
+ xbmc/utils/DateLib.h | 24 ++++++++++++++++++++++++
+ 8 files changed, 41 insertions(+), 33 deletions(-)
+ create mode 100644 xbmc/utils/DateLib.h
+
+diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp
+index 83070489e3..b95091e993 100644
+--- a/xbmc/ServiceManager.cpp
++++ b/xbmc/ServiceManager.cpp
+@@ -45,15 +45,12 @@
+ #include "storage/DetectDVDType.h"
+ #endif
+ #include "storage/MediaManager.h"
++#include "utils/DateLib.h"
+ #include "utils/FileExtensionProvider.h"
+ #include "utils/URIUtils.h"
+ #include "utils/log.h"
+ #include "weather/WeatherManager.h"
+
+-#define USE_OS_TZDB 0
+-#define HAS_REMOTE_API 0
+-#include <date/tz.h>
+-
+ using namespace KODI;
+
+ CServiceManager::CServiceManager() = default;
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index 86168ecc13..12ae853c43 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -11,18 +11,12 @@
+ #include "LangInfo.h"
+ #include "guilib/LocalizeStrings.h"
+ #include "utils/Archive.h"
++#include "utils/DateLib.h"
+ #include "utils/StringUtils.h"
+-#include "utils/XTimeUtils.h"
+ #include "utils/log.h"
+
+ #include <cstdlib>
+
+-#define USE_OS_TZDB 0
+-#define HAS_REMOTE_API 0
+-#include <date/date.h>
+-#include <date/iso_week.h>
+-#include <date/tz.h>
+-
+ static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span)
+diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp
+index 94246c9e18..6dfba75e89 100644
+--- a/xbmc/addons/TimeZoneResource.cpp
++++ b/xbmc/addons/TimeZoneResource.cpp
+@@ -8,11 +8,10 @@
+ #include "TimeZoneResource.h"
+
+ #include "addons/addoninfo/AddonType.h"
++#include "utils/DateLib.h"
+ #include "utils/StringUtils.h"
+ #include "utils/URIUtils.h"
+
+-#include <date/tz.h>
+-
+ namespace ADDON
+ {
+
+@@ -33,7 +32,9 @@ bool CTimeZoneResource::IsInUse() const
+
+ void CTimeZoneResource::OnPostInstall(bool update, bool modal)
+ {
++#if defined(DATE_INTERNAL_TZDATA)
+ date::reload_tzdb();
++#endif
+ }
+
+ } // namespace ADDON
+diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp
+index 3227933296..6aa584e5c9 100644
+--- a/xbmc/application/Application.cpp
++++ b/xbmc/application/Application.cpp
+@@ -100,6 +100,7 @@
+ #include "speech/ISpeechRecognition.h"
+ #include "threads/SingleLock.h"
+ #include "utils/CPUInfo.h"
++#include "utils/DateLib.h"
+ #include "utils/FileExtensionProvider.h"
+ #include "utils/RegExp.h"
+ #include "utils/SystemInfo.h"
+@@ -196,12 +197,8 @@
+ #include "pictures/GUIWindowSlideShow.h"
+ #include "utils/CharsetConverter.h"
+
+-#define USE_OS_TZDB 0
+-#define HAS_REMOTE_API 0
+ #include <mutex>
+
+-#include <date/tz.h>
+-
+ using namespace ADDON;
+ using namespace XFILE;
+ #ifdef HAS_DVD_DRIVE
+diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp
+index 7f0b8d4096..fa9ea1dde9 100644
+--- a/xbmc/platform/posix/PosixTimezone.cpp
++++ b/xbmc/platform/posix/PosixTimezone.cpp
+@@ -9,25 +9,22 @@
+ #ifdef TARGET_ANDROID
+ #include "platform/android/bionic_supplement/bionic_supplement.h"
+ #endif
+-#include "PlatformDefs.h"
+ #include "PosixTimezone.h"
+-#include "utils/SystemInfo.h"
+-
+ #include "ServiceBroker.h"
+-#include "utils/StringUtils.h"
+ #include "XBDateTime.h"
+-#include "settings/lib/Setting.h"
+-#include "settings/lib/SettingDefinitions.h"
++#include "filesystem/File.h"
++#include "platform/MessagePrinter.h"
+ #include "settings/Settings.h"
+ #include "settings/SettingsComponent.h"
+-#include <stdlib.h>
++#include "settings/lib/Setting.h"
++#include "settings/lib/SettingDefinitions.h"
++#include "utils/DateLib.h"
++#include "utils/StringUtils.h"
++#include "utils/SystemInfo.h"
+
+-#define USE_OS_TZDB 0
+-#define HAS_REMOTE_API 0
+-#include "filesystem/File.h"
+-#include "platform/MessagePrinter.h"
++#include <stdlib.h>
+
+-#include <date/tz.h>
++#include "PlatformDefs.h"
+
+ void CPosixTimezone::Init()
+ {
+diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp
+index ea910a8763..de3f75e5e4 100644
+--- a/xbmc/test/TestDateTime.cpp
++++ b/xbmc/test/TestDateTime.cpp
+@@ -9,15 +9,12 @@
+ #include "LangInfo.h"
+ #include "XBDateTime.h"
+ #include "guilib/LocalizeStrings.h"
++#include "utils/DateLib.h"
+
+ #include <array>
+ #include <chrono>
+ #include <iostream>
+
+-#define USE_OS_TZDB 0
+-#define HAS_REMOTE_API 0
+-#include <date/date.h>
+-#include <date/tz.h>
+ #include <gtest/gtest.h>
+
+ class TestDateTime : public testing::Test
+diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt
+index 8e1328999f..bb4851c0ce 100644
+--- a/xbmc/utils/CMakeLists.txt
++++ b/xbmc/utils/CMakeLists.txt
+@@ -97,6 +97,7 @@ set(HEADERS ActorProtocol.h
+ Crc32.h
+ CSSUtils.h
+ DatabaseUtils.h
++ DateLib.h
+ Digest.h
+ DiscsUtils.h
+ EndianSwap.h
+diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h
+new file mode 100644
+index 0000000000..e39650aa03
+--- /dev/null
++++ b/xbmc/utils/DateLib.h
+@@ -0,0 +1,24 @@
++/*
++ * Copyright (C) 2005-2022 Team Kodi
++ * This file is part of Kodi - https://kodi.tv
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ * See LICENSES/README.md for more information.
++ */
++
++#if defined(DATE_INTERNAL_TZDATA)
++#define USE_OS_TZDB 0
++#else
++#define USE_OS_TZDB 1
++#endif
++
++#if defined(DATE_HAS_STRINGVIEW)
++#define HAS_STRING_VIEW 1
++#else
++#define HAS_STRING_VIEW 0
++#endif
++
++#define HAS_REMOTE_API 0
++#include <date/date.h>
++#include <date/iso_week.h>
++#include <date/tz.h>
+--
+2.43.0
+
+
+From 46f92320cc18c3975bddb5dbe8e0d5b66a0b64c6 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Fri, 14 May 2021 09:39:55 +0000
+Subject: [PATCH 13/19] CDateTime: Use 'long double' as underlying storage type
+ for time points
+
+This should fix the GUI date dialog issue:
+
+https://github.com/xbmc/xbmc/pull/18727#issuecomment-840805031
+https://github.com/xbmc/xbmc/pull/18727#issuecomment-840805031
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/XBDateTime.cpp | 18 +++++++++---------
+ xbmc/XBDateTime.h | 20 ++++++++++----------
+ xbmc/dialogs/GUIDialogNumeric.cpp | 3 +--
+ xbmc/utils/Archive.cpp | 8 ++++----
+ xbmc/utils/Archive.h | 6 ++++--
+ xbmc/utils/XTimeUtils.h | 3 +++
+ xbmc/utils/test/TestArchive.cpp | 12 ++++++------
+ 7 files changed, 37 insertions(+), 33 deletions(-)
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index 12ae853c43..fdcc27c9af 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -176,7 +176,7 @@ CDateTime::CDateTime(const time_t& time)
+ SetValid(true);
+ }
+
+-CDateTime::CDateTime(const std::chrono::system_clock::time_point& time)
++CDateTime::CDateTime(const KODI::TIME::time_point& time)
+ {
+ m_time = time;
+ SetValid(true);
+@@ -223,7 +223,7 @@ const CDateTime& CDateTime::operator =(const tm& right)
+ return *this;
+ }
+
+-const CDateTime& CDateTime::operator=(const std::chrono::system_clock::time_point& right)
++const CDateTime& CDateTime::operator=(const KODI::TIME::time_point& right)
+ {
+ m_time = right;
+ SetValid(true);
+@@ -321,32 +321,32 @@ bool CDateTime::operator !=(const tm& right) const
+ return !operator ==(right);
+ }
+
+-bool CDateTime::operator>(const std::chrono::system_clock::time_point& right) const
++bool CDateTime::operator>(const KODI::TIME::time_point& right) const
+ {
+ return m_time > right;
+ }
+
+-bool CDateTime::operator>=(const std::chrono::system_clock::time_point& right) const
++bool CDateTime::operator>=(const KODI::TIME::time_point& right) const
+ {
+ return operator>(right) || operator==(right);
+ }
+
+-bool CDateTime::operator<(const std::chrono::system_clock::time_point& right) const
++bool CDateTime::operator<(const KODI::TIME::time_point& right) const
+ {
+ return m_time < right;
+ }
+
+-bool CDateTime::operator<=(const std::chrono::system_clock::time_point& right) const
++bool CDateTime::operator<=(const KODI::TIME::time_point& right) const
+ {
+ return operator<(right) || operator==(right);
+ }
+
+-bool CDateTime::operator==(const std::chrono::system_clock::time_point& right) const
++bool CDateTime::operator==(const KODI::TIME::time_point& right) const
+ {
+ return m_time == right;
+ }
+
+-bool CDateTime::operator!=(const std::chrono::system_clock::time_point& right) const
++bool CDateTime::operator!=(const KODI::TIME::time_point& right) const
+ {
+ return !operator==(right);
+ }
+@@ -577,7 +577,7 @@ void CDateTime::GetAsTm(tm& time) const
+ localtime_r(&t, &time);
+ }
+
+-std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const
++KODI::TIME::time_point CDateTime::GetAsTimePoint() const
+ {
+ return m_time;
+ }
+diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h
+index ff2d758caa..b0a7f386d9 100644
+--- a/xbmc/XBDateTime.h
++++ b/xbmc/XBDateTime.h
+@@ -65,7 +65,7 @@ public:
+ CDateTime& operator=(const CDateTime&) = default;
+ explicit CDateTime(const time_t& time);
+ explicit CDateTime(const tm& time);
+- explicit CDateTime(const std::chrono::system_clock::time_point& time);
++ explicit CDateTime(const KODI::TIME::time_point& time);
+ CDateTime(int year, int month, int day, int hour, int minute, int second);
+
+ static CDateTime GetCurrentDateTime();
+@@ -82,7 +82,7 @@ public:
+
+ const CDateTime& operator =(const time_t& right);
+ const CDateTime& operator =(const tm& right);
+- const CDateTime& operator=(const std::chrono::system_clock::time_point& right);
++ const CDateTime& operator=(const KODI::TIME::time_point& right);
+
+ bool operator >(const CDateTime& right) const;
+ bool operator >=(const CDateTime& right) const;
+@@ -105,12 +105,12 @@ public:
+ bool operator ==(const tm& right) const;
+ bool operator !=(const tm& right) const;
+
+- bool operator>(const std::chrono::system_clock::time_point& right) const;
+- bool operator>=(const std::chrono::system_clock::time_point& right) const;
+- bool operator<(const std::chrono::system_clock::time_point& right) const;
+- bool operator<=(const std::chrono::system_clock::time_point& right) const;
+- bool operator==(const std::chrono::system_clock::time_point& right) const;
+- bool operator!=(const std::chrono::system_clock::time_point& right) const;
++ bool operator>(const KODI::TIME::time_point& right) const;
++ bool operator>=(const KODI::TIME::time_point& right) const;
++ bool operator<(const KODI::TIME::time_point& right) const;
++ bool operator<=(const KODI::TIME::time_point& right) const;
++ bool operator==(const KODI::TIME::time_point& right) const;
++ bool operator!=(const KODI::TIME::time_point& right) const;
+
+ CDateTime operator +(const CDateTimeSpan& right) const;
+ CDateTime operator -(const CDateTimeSpan& right) const;
+@@ -151,7 +151,7 @@ public:
+
+ void GetAsTime(time_t& time) const;
+ void GetAsTm(tm& time) const;
+- std::chrono::system_clock::time_point GetAsTimePoint() const;
++ KODI::TIME::time_point GetAsTimePoint() const;
+
+ /*! \brief convert UTC datetime to local datetime
+ */
+@@ -173,7 +173,7 @@ public:
+ bool IsValid() const;
+
+ private:
+- std::chrono::system_clock::time_point m_time;
++ KODI::TIME::time_point m_time;
+
+ typedef enum _STATE
+ {
+diff --git a/xbmc/dialogs/GUIDialogNumeric.cpp b/xbmc/dialogs/GUIDialogNumeric.cpp
+index bba219e44e..985fd05722 100644
+--- a/xbmc/dialogs/GUIDialogNumeric.cpp
++++ b/xbmc/dialogs/GUIDialogNumeric.cpp
+@@ -498,8 +498,7 @@ bool CGUIDialogNumeric::ShowAndGetSeconds(std::string &timeString, const std::st
+ CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
+ if (!pDialog) return false;
+
+- std::chrono::system_clock::time_point time{
+- std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}};
++ KODI::TIME::time_point time{std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}};
+
+ CDateTime datetime(time);
+
+diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp
+index 0275c057f9..bb207c6ca5 100644
+--- a/xbmc/utils/Archive.cpp
++++ b/xbmc/utils/Archive.cpp
+@@ -152,9 +152,9 @@ CArchive& CArchive::operator<<(const std::wstring& wstr)
+ return streamout(wstr.data(), size * sizeof(wchar_t));
+ }
+
+-CArchive& CArchive::operator<<(const std::chrono::system_clock::time_point& time)
++CArchive& CArchive::operator<<(const KODI::TIME::time_point& time)
+ {
+- return streamout(&time, sizeof(std::chrono::system_clock::time_point));
++ return streamout(&time, sizeof(KODI::TIME::time_point));
+ }
+
+ CArchive& CArchive::operator<<(IArchivable& obj)
+@@ -265,9 +265,9 @@ CArchive& CArchive::operator>>(std::wstring& wstr)
+ return *this;
+ }
+
+-CArchive& CArchive::operator>>(std::chrono::system_clock::time_point& time)
++CArchive& CArchive::operator>>(KODI::TIME::time_point& time)
+ {
+- return streamin(&time, sizeof(std::chrono::system_clock::time_point));
++ return streamin(&time, sizeof(KODI::TIME::time_point));
+ }
+
+ CArchive& CArchive::operator>>(IArchivable& obj)
+diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h
+index 86a2bebc23..ece5f9ac9c 100644
+--- a/xbmc/utils/Archive.h
++++ b/xbmc/utils/Archive.h
+@@ -8,6 +8,8 @@
+
+ #pragma once
+
++#include "utils/XTimeUtils.h"
++
+ #include <cstring>
+ #include <memory>
+ #include <string>
+@@ -57,7 +59,7 @@ public:
+ CArchive& operator<<(char c);
+ CArchive& operator<<(const std::string &str);
+ CArchive& operator<<(const std::wstring& wstr);
+- CArchive& operator<<(const std::chrono::system_clock::time_point& time);
++ CArchive& operator<<(const KODI::TIME::time_point& time);
+ CArchive& operator<<(IArchivable& obj);
+ CArchive& operator<<(const CVariant& variant);
+ CArchive& operator<<(const std::vector<std::string>& strArray);
+@@ -126,7 +128,7 @@ public:
+
+ CArchive& operator>>(std::string &str);
+ CArchive& operator>>(std::wstring& wstr);
+- CArchive& operator>>(std::chrono::system_clock::time_point& time);
++ CArchive& operator>>(KODI::TIME::time_point& time);
+ CArchive& operator>>(IArchivable& obj);
+ CArchive& operator>>(CVariant& variant);
+ CArchive& operator>>(std::vector<std::string>& strArray);
+diff --git a/xbmc/utils/XTimeUtils.h b/xbmc/utils/XTimeUtils.h
+index 9d3b0e86a3..ed1b25fb74 100644
+--- a/xbmc/utils/XTimeUtils.h
++++ b/xbmc/utils/XTimeUtils.h
+@@ -28,6 +28,9 @@ namespace KODI
+ namespace TIME
+ {
+
++using time_point = std::chrono::time_point<std::chrono::system_clock,
++ std::chrono::duration<long double, std::nano>>;
++
+ template<typename Rep, typename Period>
+ void Sleep(std::chrono::duration<Rep, Period> duration)
+ {
+diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp
+index b9ab780cf9..de912eba21 100644
+--- a/xbmc/utils/test/TestArchive.cpp
++++ b/xbmc/utils/test/TestArchive.cpp
+@@ -223,8 +223,8 @@ TEST_F(TestArchive, StringArchive)
+ TEST_F(TestArchive, TimePointArchive)
+ {
+ ASSERT_NE(nullptr, file);
+- std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now();
+- std::chrono::system_clock::time_point tp_var;
++ KODI::TIME::time_point tp_ref = std::chrono::system_clock::now();
++ KODI::TIME::time_point tp_var;
+
+ CArchive arstore(file, CArchive::store);
+ arstore << tp_ref;
+@@ -235,7 +235,7 @@ TEST_F(TestArchive, TimePointArchive)
+ arload >> tp_var;
+ arload.Close();
+
+- EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point)));
++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(KODI::TIME::time_point)));
+ }
+
+ TEST_F(TestArchive, CVariantArchive)
+@@ -335,8 +335,8 @@ TEST_F(TestArchive, MultiTypeArchive)
+ char char_ref = 'A', char_var = '\0';
+ std::string string_ref = "test string", string_var;
+ std::wstring wstring_ref = L"test wstring", wstring_var;
+- std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now();
+- std::chrono::system_clock::time_point tp_var;
++ KODI::TIME::time_point tp_ref = std::chrono::system_clock::now();
++ KODI::TIME::time_point tp_var;
+ CVariant CVariant_ref((int)1), CVariant_var;
+ std::vector<std::string> strArray_ref, strArray_var;
+ strArray_ref.emplace_back("test strArray_ref 0");
+@@ -398,7 +398,7 @@ TEST_F(TestArchive, MultiTypeArchive)
+ EXPECT_EQ(char_ref, char_var);
+ EXPECT_STREQ(string_ref.c_str(), string_var.c_str());
+ EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str());
+- EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point)));
++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(KODI::TIME::time_point)));
+ EXPECT_TRUE(CVariant_var.isInteger());
+ EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str());
+ EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str());
+--
+2.43.0
+
+
+From c2f4add32ebf1c3a965f1a88af0d49afcdf9e847 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Fri, 14 May 2021 12:35:54 +0000
+Subject: [PATCH 14/19] Use "long double" type in time_t / tm conversions
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/XBDateTime.cpp | 60 +++++++++++++++++++++++++--------------------
+ 1 file changed, 34 insertions(+), 26 deletions(-)
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index fdcc27c9af..c71478085b 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -93,10 +93,10 @@ const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right)
+
+ void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second)
+ {
+- m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(date::days(day)) +
+- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(hour)) +
+- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::minutes(minute)) +
+- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::seconds(second));
++ m_timeSpan = date::floor<std::chrono::seconds>(date::days(day)) +
++ date::floor<std::chrono::seconds>(std::chrono::hours(hour)) +
++ date::floor<std::chrono::seconds>(std::chrono::minutes(minute)) +
++ date::floor<std::chrono::seconds>(std::chrono::seconds(second));
+ }
+
+ void CDateTimeSpan::SetFromTimeString(const std::string& time) // hh:mm
+@@ -140,7 +140,7 @@ int CDateTimeSpan::GetSeconds() const
+
+ int CDateTimeSpan::GetSecondsTotal() const
+ {
+- return std::chrono::duration_cast<std::chrono::seconds>(m_timeSpan).count();
++ return date::floor<std::chrono::seconds>(m_timeSpan).count();
+ }
+
+ void CDateTimeSpan::SetFromPeriod(const std::string &period)
+@@ -172,7 +172,8 @@ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time)
+
+ CDateTime::CDateTime(const time_t& time)
+ {
+- m_time = std::chrono::system_clock::from_time_t(time);
++ Reset();
++ m_time += std::chrono::duration<long double>(time);
+ SetValid(true);
+ }
+
+@@ -184,7 +185,8 @@ CDateTime::CDateTime(const KODI::TIME::time_point& time)
+
+ CDateTime::CDateTime(const tm& time)
+ {
+- m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&time)));
++ Reset();
++ m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&time)));
+ SetValid(true);
+ }
+
+@@ -198,8 +200,7 @@ CDateTime CDateTime::GetCurrentDateTime()
+ auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now());
+
+ return CDateTime(
+- std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch())
+- .count());
++ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count());
+ }
+
+ CDateTime CDateTime::GetUTCDateTime()
+@@ -209,7 +210,8 @@ CDateTime CDateTime::GetUTCDateTime()
+
+ const CDateTime& CDateTime::operator =(const time_t& right)
+ {
+- m_time = std::chrono::system_clock::from_time_t(right);
++ Reset();
++ m_time += std::chrono::duration<long double>(right);
+ SetValid(true);
+
+ return *this;
+@@ -217,7 +219,8 @@ const CDateTime& CDateTime::operator =(const time_t& right)
+
+ const CDateTime& CDateTime::operator =(const tm& right)
+ {
+- m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
++ Reset();
++ m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
+ SetValid(true);
+
+ return *this;
+@@ -263,7 +266,8 @@ bool CDateTime::operator !=(const CDateTime& right) const
+
+ bool CDateTime::operator >(const time_t& right) const
+ {
+- return m_time > std::chrono::system_clock::from_time_t(right);
++ return m_time >
++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right);
+ }
+
+ bool CDateTime::operator >=(const time_t& right) const
+@@ -273,7 +277,8 @@ bool CDateTime::operator >=(const time_t& right) const
+
+ bool CDateTime::operator <(const time_t& right) const
+ {
+- return m_time < std::chrono::system_clock::from_time_t(right);
++ return m_time <
++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right);
+ }
+
+ bool CDateTime::operator <=(const time_t& right) const
+@@ -283,7 +288,8 @@ bool CDateTime::operator <=(const time_t& right) const
+
+ bool CDateTime::operator ==(const time_t& right) const
+ {
+- return m_time == std::chrono::system_clock::from_time_t(right);
++ return m_time ==
++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right);
+ }
+
+ bool CDateTime::operator !=(const time_t& right) const
+@@ -293,7 +299,8 @@ bool CDateTime::operator !=(const time_t& right) const
+
+ bool CDateTime::operator >(const tm& right) const
+ {
+- return m_time > std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
++ return m_time > std::chrono::system_clock::from_time_t(0) +
++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
+ }
+
+ bool CDateTime::operator >=(const tm& right) const
+@@ -303,7 +310,8 @@ bool CDateTime::operator >=(const tm& right) const
+
+ bool CDateTime::operator <(const tm& right) const
+ {
+- return m_time < std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
++ return m_time < std::chrono::system_clock::from_time_t(0) +
++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
+ }
+
+ bool CDateTime::operator <=(const tm& right) const
+@@ -313,7 +321,8 @@ bool CDateTime::operator <=(const tm& right) const
+
+ bool CDateTime::operator ==(const tm& right) const
+ {
+- return m_time == std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right)));
++ return m_time == std::chrono::system_clock::from_time_t(0) +
++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
+ }
+
+ bool CDateTime::operator !=(const tm& right) const
+@@ -387,7 +396,7 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const
+ {
+ CDateTimeSpan left;
+
+- left.m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(m_time - right.m_time);
++ left.m_timeSpan = date::floor<std::chrono::seconds>(m_time - right.m_time);
+ return left;
+ }
+
+@@ -496,7 +505,7 @@ int CDateTime::GetYear() const
+ int CDateTime::GetHour() const
+ {
+ auto dp = date::floor<date::days>(m_time);
+- auto time = date::make_time(m_time - dp);
++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp));
+
+ return time.hours().count();
+ }
+@@ -504,7 +513,7 @@ int CDateTime::GetHour() const
+ int CDateTime::GetMinute() const
+ {
+ auto dp = date::floor<date::days>(m_time);
+- auto time = date::make_time(m_time - dp);
++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp));
+
+ return time.minutes().count();
+ }
+@@ -512,7 +521,7 @@ int CDateTime::GetMinute() const
+ int CDateTime::GetSecond() const
+ {
+ auto dp = date::floor<date::days>(m_time);
+- auto time = date::make_time(m_time - dp);
++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp));
+
+ return time.seconds().count();
+ }
+@@ -529,7 +538,7 @@ int CDateTime::GetMinuteOfDay() const
+ {
+ auto dp = date::floor<std::chrono::hours>(m_time);
+ ;
+- auto time = date::make_time(m_time - dp);
++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp));
+
+ return time.hours().count() * 60 + time.minutes().count();
+ }
+@@ -566,12 +575,12 @@ bool CDateTime::SetTime(int hour, int minute, int second)
+
+ void CDateTime::GetAsTime(time_t& time) const
+ {
+- time = std::chrono::system_clock::to_time_t(m_time);
++ time = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count();
+ }
+
+ void CDateTime::GetAsTm(tm& time) const
+ {
+- auto t = std::chrono::system_clock::to_time_t(m_time);
++ auto t = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count();
+
+ time = {};
+ localtime_r(&t, &time);
+@@ -1180,8 +1189,7 @@ CDateTime CDateTime::GetAsLocalDateTime() const
+ auto zone = date::make_zoned(date::current_zone(), m_time);
+
+ return CDateTime(
+- std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch())
+- .count());
++ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count());
+ }
+
+ std::string CDateTime::GetAsRFC1123DateTime() const
+--
+2.43.0
+
+
+From 0a476801a4d337a1e3e9c7115a03c58d302cdd75 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Mon, 17 May 2021 09:41:32 +0000
+Subject: [PATCH 15/19] Avoid time_t in tm conversions
+
+This should leave the possibility of time_t truncation on 32-bit
+architectures only in GetAsTime(), what we can do nothing with.
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/XBDateTime.cpp | 56 +++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 46 insertions(+), 10 deletions(-)
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index c71478085b..ce5c242128 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -186,7 +186,16 @@ CDateTime::CDateTime(const KODI::TIME::time_point& time)
+ CDateTime::CDateTime(const tm& time)
+ {
+ Reset();
+- m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&time)));
++
++ auto ymd = date::local_days(date::year(time.tm_year + 1900) / date::month(time.tm_mon + 1) /
++ time.tm_mday);
++ auto dur = ymd + std::chrono::hours(time.tm_hour) + std::chrono::minutes(time.tm_min) +
++ std::chrono::seconds(time.tm_sec);
++
++ auto timeT = date::floor<std::chrono::seconds>(dur.time_since_epoch()).count();
++
++ m_time += std::chrono::duration<long double>(timeT);
++
+ SetValid(true);
+ }
+
+@@ -220,7 +229,16 @@ const CDateTime& CDateTime::operator =(const time_t& right)
+ const CDateTime& CDateTime::operator =(const tm& right)
+ {
+ Reset();
+- m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
++
++ auto ymd = date::local_days(date::year(right.tm_year + 1900) / date::month(right.tm_mon + 1) /
++ right.tm_mday);
++ auto dur = ymd + std::chrono::hours(right.tm_hour) + std::chrono::minutes(right.tm_min) +
++ std::chrono::seconds(right.tm_sec);
++
++ auto timeT = date::floor<std::chrono::seconds>(dur.time_since_epoch()).count();
++
++ m_time += std::chrono::duration<long double>(timeT);
++
+ SetValid(true);
+
+ return *this;
+@@ -299,8 +317,8 @@ bool CDateTime::operator !=(const time_t& right) const
+
+ bool CDateTime::operator >(const tm& right) const
+ {
+- return m_time > std::chrono::system_clock::from_time_t(0) +
+- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
++ CDateTime temp(right);
++ return m_time > temp.m_time;
+ }
+
+ bool CDateTime::operator >=(const tm& right) const
+@@ -310,8 +328,8 @@ bool CDateTime::operator >=(const tm& right) const
+
+ bool CDateTime::operator <(const tm& right) const
+ {
+- return m_time < std::chrono::system_clock::from_time_t(0) +
+- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
++ CDateTime temp(right);
++ return m_time < temp.m_time;
+ }
+
+ bool CDateTime::operator <=(const tm& right) const
+@@ -321,8 +339,8 @@ bool CDateTime::operator <=(const tm& right) const
+
+ bool CDateTime::operator ==(const tm& right) const
+ {
+- return m_time == std::chrono::system_clock::from_time_t(0) +
+- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right)));
++ CDateTime temp(right);
++ return m_time == temp.m_time;
+ }
+
+ bool CDateTime::operator !=(const tm& right) const
+@@ -580,10 +598,28 @@ void CDateTime::GetAsTime(time_t& time) const
+
+ void CDateTime::GetAsTm(tm& time) const
+ {
+- auto t = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count();
++ auto dp = date::floor<date::days>(m_time);
+
+ time = {};
+- localtime_r(&t, &time);
++
++ auto ymd = date::year_month_day{dp};
++ time.tm_year = int(ymd.year()) - 1900;
++ time.tm_mon = unsigned(ymd.month()) - 1;
++ time.tm_mday = unsigned(ymd.day());
++
++ auto hms = date::make_time(date::floor<std::chrono::seconds>(m_time - dp));
++ time.tm_hour = hms.hours().count();
++ time.tm_min = hms.minutes().count();
++ time.tm_sec = hms.seconds().count();
++
++ date::weekday wd{dp};
++ time.tm_wday = wd.c_encoding();
++
++ auto newyear = date::sys_days(date::year(time.tm_year + 1900) / 1 / 1);
++ auto seconds_to_newyear = date::floor<std::chrono::seconds>(m_time - newyear);
++ time.tm_yday = seconds_to_newyear.count() / 86400;
++
++ time.tm_isdst = date::current_zone()->get_info(m_time).save.count() != 0;
+ }
+
+ KODI::TIME::time_point CDateTime::GetAsTimePoint() const
+--
+2.43.0
+
+
+From 431a3cdbdc388bb8661d4d35fe5a42b579e3fc86 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?P=C3=A4r=20Bj=C3=B6rklund?= <per.bjorklund@gmail.com>
+Date: Sun, 31 Oct 2021 10:33:30 +0100
+Subject: [PATCH 16/19] Windows patches
+
+---
+ xbmc/application/Application.cpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp
+index 6aa584e5c9..df55665b5e 100644
+--- a/xbmc/application/Application.cpp
++++ b/xbmc/application/Application.cpp
+@@ -357,7 +357,9 @@ bool CApplication::Create()
+ CServiceBroker::RegisterJobManager(std::make_shared<CJobManager>());
+
+ // Initialize,timezone
++#if defined(TARGET_POSIX)
+ g_timezone.Init();
++#endif
+
+ // Announcement service
+ m_pAnnouncementManager = std::make_shared<ANNOUNCEMENT::CAnnouncementManager>();
+--
+2.43.0
+
+
+From 257a56972008869e448fd81b15c67bb46c17f338 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Mon, 11 Jul 2022 09:24:01 +0000
+Subject: [PATCH 17/19] XBDateTime: Use timezone info specified via timezone
+ picker.
+
+Fixes broken timezone picker as reported in Debian Bug#1011294.
+
+Also fixes TZ-related issue spotted on reproducibility build
+where TZ envvar specifying timezone as absolute pathname on Linux
+and FreeBSD screwed date lib up.
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/XBDateTime.cpp | 8 +++---
+ xbmc/test/TestDateTime.cpp | 20 ++++++++++++---
+ xbmc/utils/CMakeLists.txt | 1 +
+ xbmc/utils/DateLib.cpp | 51 ++++++++++++++++++++++++++++++++++++++
+ xbmc/utils/DateLib.h | 13 ++++++++++
+ 5 files changed, 86 insertions(+), 7 deletions(-)
+ create mode 100644 xbmc/utils/DateLib.cpp
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index ce5c242128..29118e7570 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -206,7 +206,7 @@ CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int sec
+
+ CDateTime CDateTime::GetCurrentDateTime()
+ {
+- auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now());
++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), std::chrono::system_clock::now());
+
+ return CDateTime(
+ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count());
+@@ -619,7 +619,7 @@ void CDateTime::GetAsTm(tm& time) const
+ auto seconds_to_newyear = date::floor<std::chrono::seconds>(m_time - newyear);
+ time.tm_yday = seconds_to_newyear.count() / 86400;
+
+- time.tm_isdst = date::current_zone()->get_info(m_time).save.count() != 0;
++ time.tm_isdst = KODI::TIME::GetTimeZone()->get_info(m_time).save.count() != 0;
+ }
+
+ KODI::TIME::time_point CDateTime::GetAsTimePoint() const
+@@ -1222,7 +1222,7 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds /
+
+ CDateTime CDateTime::GetAsLocalDateTime() const
+ {
+- auto zone = date::make_zoned(date::current_zone(), m_time);
++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), m_time);
+
+ return CDateTime(
+ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count());
+@@ -1247,7 +1247,7 @@ std::string CDateTime::GetAsW3CDateTime(bool asUtc /* = false */) const
+ if (asUtc)
+ return date::format("%FT%TZ", time);
+
+- auto zt = date::make_zoned(date::current_zone(), time);
++ auto zt = date::make_zoned(KODI::TIME::GetTimeZone(), time);
+
+ return date::format("%FT%T%Ez", zt);
+ }
+diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp
+index de3f75e5e4..6604146a61 100644
+--- a/xbmc/test/TestDateTime.cpp
++++ b/xbmc/test/TestDateTime.cpp
+@@ -303,7 +303,7 @@ TEST_F(TestDateTime, GetAsStringsWithBias)
+ std::cout << dateTime.GetAsW3CDateTime(true) << std::endl;
+
+ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
+- auto zone = date::make_zoned(date::current_zone(), tps);
++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), tps);
+
+ EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT");
+ EXPECT_EQ(dateTime.GetAsW3CDateTime(false), date::format("%FT%T%Ez", zone));
+@@ -552,12 +552,12 @@ TEST_F(TestDateTime, GetAsLocalDateTime)
+ CDateTime dateTime2;
+ dateTime2 = dateTime1.GetAsLocalDateTime();
+
+- auto zoned_time = date::make_zoned(date::current_zone(), dateTime1.GetAsTimePoint());
++ auto zoned_time = date::make_zoned(KODI::TIME::GetTimeZone(), dateTime1.GetAsTimePoint());
+ auto time = zoned_time.get_local_time().time_since_epoch();
+
+ CDateTime cmpTime(std::chrono::duration_cast<std::chrono::seconds>(time).count());
+
+- EXPECT_TRUE(dateTime1 == cmpTime);
++ EXPECT_TRUE(dateTime2 == cmpTime);
+ }
+
+ TEST_F(TestDateTime, Reset)
+@@ -736,3 +736,17 @@ TEST_F(TestDateTime, Tzdata)
+ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00")
+ << "tzdata information not valid for 'Etc/GMT-14'";
+ }
++
++TEST_F(TestDateTime, ExtractTzName)
++{
++ CDateTime dateTime;
++ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56);
++
++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());
++ auto zone = date::make_zoned(KODI::TIME::ExtractTzName("/usr/share/zoneinfo/Etc/GMT-14"), tps);
++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00")
++ << "extractTzName failed for '/usr/share/zoneinfo/Etc/GMT-14'";
++
++ EXPECT_EQ(KODI::TIME::ExtractTzName("/usr/share/z0neinfo/Etc/GMT+12"), "")
++ << "extractTzName failed for '/usr/share/z0neinfo/Etc/GMT+12'";
++}
+diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt
+index bb4851c0ce..8f3a199a65 100644
+--- a/xbmc/utils/CMakeLists.txt
++++ b/xbmc/utils/CMakeLists.txt
+@@ -17,6 +17,7 @@ set(SOURCES ActorProtocol.cpp
+ Crc32.cpp
+ CSSUtils.cpp
+ DatabaseUtils.cpp
++ DateLib.cpp
+ Digest.cpp
+ DiscsUtils.cpp
+ EndianSwap.cpp
+diff --git a/xbmc/utils/DateLib.cpp b/xbmc/utils/DateLib.cpp
+new file mode 100644
+index 0000000000..bd86dd5791
+--- /dev/null
++++ b/xbmc/utils/DateLib.cpp
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2005-2022 Team Kodi
++ * This file is part of Kodi - https://kodi.tv
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ * See LICENSES/README.md for more information.
++ */
++
++#include "DateLib.h"
++
++#include "utils/XTimeUtils.h"
++
++#include <cstdlib>
++
++const std::string KODI::TIME::ExtractTzName(const char* tzname)
++{
++ if (tzname[0] != '/')
++ return tzname;
++
++ std::string result = tzname;
++ const char zoneinfo[] = "zoneinfo";
++ size_t pos = result.rfind(zoneinfo);
++ if (pos == result.npos)
++ {
++ return "";
++ }
++
++ pos = result.find('/', pos);
++ result.erase(0, pos + 1);
++ return result;
++}
++
++const date::time_zone* KODI::TIME::GetTimeZone()
++{
++#if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
++ const date::time_zone* tz = nullptr;
++ const char* tzname = std::getenv("TZ");
++
++ if (tzname && tzname[0] != '\0')
++ {
++ const std::string tzn = ExtractTzName(tzname);
++ if (!tzn.empty())
++ tz = date::locate_zone(tzn);
++ }
++
++ if (tz)
++ return tz;
++ else
++#endif
++ return date::current_zone();
++}
+diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h
+index e39650aa03..9838dd94fe 100644
+--- a/xbmc/utils/DateLib.h
++++ b/xbmc/utils/DateLib.h
+@@ -19,6 +19,19 @@
+ #endif
+
+ #define HAS_REMOTE_API 0
++#include <cstring>
++
+ #include <date/date.h>
+ #include <date/iso_week.h>
+ #include <date/tz.h>
++
++namespace KODI
++{
++namespace TIME
++{
++
++const std::string ExtractTzName(const char* tzname);
++const date::time_zone* GetTimeZone();
++
++} // namespace TIME
++} // namespace KODI
+--
+2.43.0
+
+
+From b67dabf8a304565713b413d4efb30c567a0a639b Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Mon, 9 Jan 2023 23:00:17 +0200
+Subject: [PATCH 18/19] Apply formatting fixes
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/XBDateTime.cpp | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp
+index 29118e7570..402aecfa9c 100644
+--- a/xbmc/XBDateTime.cpp
++++ b/xbmc/XBDateTime.cpp
+@@ -167,7 +167,7 @@ CDateTime::CDateTime()
+
+ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time)
+ {
+- m_state=time.m_state;
++ m_state = time.m_state;
+ }
+
+ CDateTime::CDateTime(const time_t& time)
+@@ -217,7 +217,7 @@ CDateTime CDateTime::GetUTCDateTime()
+ return CDateTime(std::chrono::system_clock::now());
+ }
+
+-const CDateTime& CDateTime::operator =(const time_t& right)
++const CDateTime& CDateTime::operator=(const time_t& right)
+ {
+ Reset();
+ m_time += std::chrono::duration<long double>(right);
+@@ -226,7 +226,7 @@ const CDateTime& CDateTime::operator =(const time_t& right)
+ return *this;
+ }
+
+-const CDateTime& CDateTime::operator =(const tm& right)
++const CDateTime& CDateTime::operator=(const tm& right)
+ {
+ Reset();
+
+@@ -282,68 +282,68 @@ bool CDateTime::operator !=(const CDateTime& right) const
+ return !operator ==(right);
+ }
+
+-bool CDateTime::operator >(const time_t& right) const
++bool CDateTime::operator>(const time_t& right) const
+ {
+ return m_time >
+ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right);
+ }
+
+-bool CDateTime::operator >=(const time_t& right) const
++bool CDateTime::operator>=(const time_t& right) const
+ {
+ return operator >(right) || operator ==(right);
+ }
+
+-bool CDateTime::operator <(const time_t& right) const
++bool CDateTime::operator<(const time_t& right) const
+ {
+ return m_time <
+ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right);
+ }
+
+-bool CDateTime::operator <=(const time_t& right) const
++bool CDateTime::operator<=(const time_t& right) const
+ {
+ return operator <(right) || operator ==(right);
+ }
+
+-bool CDateTime::operator ==(const time_t& right) const
++bool CDateTime::operator==(const time_t& right) const
+ {
+ return m_time ==
+ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right);
+ }
+
+-bool CDateTime::operator !=(const time_t& right) const
++bool CDateTime::operator!=(const time_t& right) const
+ {
+ return !operator ==(right);
+ }
+
+-bool CDateTime::operator >(const tm& right) const
++bool CDateTime::operator>(const tm& right) const
+ {
+ CDateTime temp(right);
+ return m_time > temp.m_time;
+ }
+
+-bool CDateTime::operator >=(const tm& right) const
++bool CDateTime::operator>=(const tm& right) const
+ {
+ return operator >(right) || operator ==(right);
+ }
+
+-bool CDateTime::operator <(const tm& right) const
++bool CDateTime::operator<(const tm& right) const
+ {
+ CDateTime temp(right);
+ return m_time < temp.m_time;
+ }
+
+-bool CDateTime::operator <=(const tm& right) const
++bool CDateTime::operator<=(const tm& right) const
+ {
+ return operator <(right) || operator ==(right);
+ }
+
+-bool CDateTime::operator ==(const tm& right) const
++bool CDateTime::operator==(const tm& right) const
+ {
+ CDateTime temp(right);
+ return m_time == temp.m_time;
+ }
+
+-bool CDateTime::operator !=(const tm& right) const
++bool CDateTime::operator!=(const tm& right) const
+ {
+ return !operator ==(right);
+ }
+--
+2.43.0
+
+
+From ae3e34c85b2c8fe476d22b7adbe9e2457a025edd Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Thu, 13 Apr 2023 20:18:28 +0300
+Subject: [PATCH 19/19] Move LoadTimeZoneDatabase to xbmc/utils/DateLib.cpp
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/addons/TimeZoneResource.cpp | 4 +---
+ xbmc/settings/SettingsComponent.cpp | 5 +++++
+ xbmc/utils/DateLib.cpp | 23 +++++++++++++++++++++++
+ xbmc/utils/DateLib.h | 1 +
+ 4 files changed, 30 insertions(+), 3 deletions(-)
+
+diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp
+index 6dfba75e89..12c4371e19 100644
+--- a/xbmc/addons/TimeZoneResource.cpp
++++ b/xbmc/addons/TimeZoneResource.cpp
+@@ -32,9 +32,7 @@ bool CTimeZoneResource::IsInUse() const
+
+ void CTimeZoneResource::OnPostInstall(bool update, bool modal)
+ {
+-#if defined(DATE_INTERNAL_TZDATA)
+- date::reload_tzdb();
+-#endif
++ KODI::TIME::LoadTimeZoneDatabase();
+ }
+
+ } // namespace ADDON
+diff --git a/xbmc/settings/SettingsComponent.cpp b/xbmc/settings/SettingsComponent.cpp
+index 0f5f7ae8da..8ce2730d3b 100644
+--- a/xbmc/settings/SettingsComponent.cpp
++++ b/xbmc/settings/SettingsComponent.cpp
+@@ -24,6 +24,7 @@
+ #include "settings/AdvancedSettings.h"
+ #include "settings/Settings.h"
+ #include "settings/SubtitlesSettings.h"
++#include "utils/DateLib.h"
+ #include "utils/StringUtils.h"
+ #include "utils/URIUtils.h"
+ #include "utils/log.h"
+@@ -56,6 +57,10 @@ void CSettingsComponent::Initialize()
+ if (!inited)
+ inited = InitDirectoriesWin32(params->HasPlatformDirectories());
+
++ // Try loading timezone information after directories were provisioned
++ //!@todo check if the whole dirs logic should be moved to AppEnvironment
++ KODI::TIME::LoadTimeZoneDatabase();
++
+ m_settings->Initialize();
+
+ m_advancedSettings->Initialize(*m_settings->GetSettingsManager());
+diff --git a/xbmc/utils/DateLib.cpp b/xbmc/utils/DateLib.cpp
+index bd86dd5791..d8a6d67764 100644
+--- a/xbmc/utils/DateLib.cpp
++++ b/xbmc/utils/DateLib.cpp
+@@ -49,3 +49,26 @@ const date::time_zone* KODI::TIME::GetTimeZone()
+ #endif
+ return date::current_zone();
+ }
++
++void KODI::TIME::LoadTimeZoneDatabase()
++{
++#if defined(DATE_INTERNAL_TZDATA)
++ // First check the timezone resource from userprofile
++ auto tzdataPath =
++ CSpecialProtocol::TranslatePath("special://home/addons/resource.timezone/resources/tzdata");
++ if (!XFILE::CDirectory::Exists(tzdataPath))
++ {
++ // Then check system-wide Kodi profile and bail out if not found
++ tzdataPath =
++ CSpecialProtocol::TranslatePath("special://xbmc/addons/resource.timezone/resources/tzdata");
++ if (!XFILE::CDirectory::Exists(tzdataPath))
++ {
++ CLog::LogF(LOGFATAL, "failed to find resource.timezone");
++ return;
++ }
++ }
++
++ CLog::LogF(LOGDEBUG, "Loading tzdata from path: {}", tzdataPath);
++ date::set_install(tzdataPath);
++#endif
++}
+diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h
+index 9838dd94fe..09c4ba0b17 100644
+--- a/xbmc/utils/DateLib.h
++++ b/xbmc/utils/DateLib.h
+@@ -32,6 +32,7 @@ namespace TIME
+
+ const std::string ExtractTzName(const char* tzname);
+ const date::time_zone* GetTimeZone();
++void LoadTimeZoneDatabase();
+
+ } // namespace TIME
+ } // namespace KODI
+--
+2.43.0
+
diff --git a/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch b/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch
new file mode 100644
index 0000000..10c46de
--- /dev/null
+++ b/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch
@@ -0,0 +1,145 @@
+From 418ce26d409cadc089c5e2e624578432727d7de5 Mon Sep 17 00:00:00 2001
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Fri, 22 Feb 2019 23:03:21 +0100
+Subject: [PATCH] Implement hashes using Libgcrypt
+Forwarded: not-needed
+
+---
+ xbmc/utils/Digest.cpp | 36 ++++++++++++++++--------------------
+ xbmc/utils/Digest.h | 10 +++++-----
+ 2 files changed, 21 insertions(+), 25 deletions(-)
+
+diff --git a/xbmc/utils/Digest.cpp b/xbmc/utils/Digest.cpp
+index 445a755..63ce81e 100644
+--- a/xbmc/utils/Digest.cpp
++++ b/xbmc/utils/Digest.cpp
+@@ -13,7 +13,7 @@
+ #include <array>
+ #include <stdexcept>
+
+-#include <openssl/evp.h>
++#include <gcrypt.h>
+
+ namespace KODI
+ {
+@@ -23,18 +23,18 @@ namespace UTILITY
+ namespace
+ {
+
+-EVP_MD const * TypeToEVPMD(CDigest::Type type)
++int const TypeToInt(CDigest::Type type)
+ {
+ switch (type)
+ {
+ case CDigest::Type::MD5:
+- return EVP_md5();
++ return GCRY_MD_MD5;
+ case CDigest::Type::SHA1:
+- return EVP_sha1();
++ return GCRY_MD_SHA1;
+ case CDigest::Type::SHA256:
+- return EVP_sha256();
++ return GCRY_MD_SHA256;
+ case CDigest::Type::SHA512:
+- return EVP_sha512();
++ return GCRY_MD_SHA512;
+ default:
+ throw std::invalid_argument("Unknown digest type");
+ }
+@@ -92,18 +92,20 @@ CDigest::Type CDigest::TypeFromString(std::string const& type)
+ }
+ }
+
+-void CDigest::MdCtxDeleter::operator()(EVP_MD_CTX* context)
++void CDigest::MdCtxDeleter::operator()(gcry_md_hd_t context)
+ {
+- EVP_MD_CTX_destroy(context);
++ gcry_md_close(context);
+ }
+
+ CDigest::CDigest(Type type)
+-: m_context{EVP_MD_CTX_create()}, m_md(TypeToEVPMD(type))
++ : m_context(), m_md(TypeToInt(type))
+ {
+- if (1 != EVP_DigestInit_ex(m_context.get(), m_md, nullptr))
++ gcry_md_hd_t hd = NULL;
++ if (GPG_ERR_NO_ERROR != gcry_md_open(&hd, m_md, 0))
+ {
+- throw std::runtime_error("EVP_DigestInit_ex failed");
++ throw std::runtime_error("gcry_md_open failed");
+ }
++ m_context.reset(hd);
+ }
+
+ void CDigest::Update(std::string const& data)
+@@ -118,10 +120,7 @@ void CDigest::Update(void const* data, std::size_t size)
+ throw std::logic_error("Finalized digest cannot be updated any more");
+ }
+
+- if (1 != EVP_DigestUpdate(m_context.get(), data, size))
+- {
+- throw std::runtime_error("EVP_DigestUpdate failed");
+- }
++ gcry_md_write(m_context.get(), data, size);
+ }
+
+ std::string CDigest::FinalizeRaw()
+@@ -134,15 +133,12 @@ std::string CDigest::FinalizeRaw()
+ m_finalized = true;
+
+ std::array<unsigned char, 64> digest;
+- std::size_t size = EVP_MD_size(m_md);
++ std::size_t size = gcry_md_get_algo_dlen(m_md);
+ if (size > digest.size())
+ {
+ throw std::runtime_error("Digest unexpectedly long");
+ }
+- if (1 != EVP_DigestFinal_ex(m_context.get(), digest.data(), nullptr))
+- {
+- throw std::runtime_error("EVP_DigestFinal_ex failed");
+- }
++ memcpy(digest.data(), gcry_md_read(m_context.get(), m_md), size);
+ return {reinterpret_cast<char*> (digest.data()), size};
+ }
+
+diff --git a/xbmc/utils/Digest.h b/xbmc/utils/Digest.h
+index 6452857..6dfed47 100644
+--- a/xbmc/utils/Digest.h
++++ b/xbmc/utils/Digest.h
+@@ -15,7 +15,7 @@
+ #include <stdexcept>
+ #include <string>
+
+-#include <openssl/evp.h>
++#include <gcrypt.h>
+
+ namespace KODI
+ {
+@@ -23,7 +23,7 @@ namespace UTILITY
+ {
+
+ /**
+- * Utility class for calculating message digests/hashes, currently using OpenSSL
++ * Utility class for calculating message digests/hashes
+ */
+ class CDigest
+ {
+@@ -93,12 +93,12 @@ public:
+ private:
+ struct MdCtxDeleter
+ {
+- void operator()(EVP_MD_CTX* context);
++ void operator()(gcry_md_hd_t context);
+ };
+
+ bool m_finalized{false};
+- std::unique_ptr<EVP_MD_CTX, MdCtxDeleter> m_context;
+- EVP_MD const* m_md;
++ std::unique_ptr<struct gcry_md_handle, MdCtxDeleter> m_context;
++ int const m_md;
+ };
+
+ struct TypedDigest
+--
+2.20.1
+
diff --git a/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch b/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch
new file mode 100644
index 0000000..30be79a
--- /dev/null
+++ b/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch
@@ -0,0 +1,58 @@
+From 9f0f2742dee33c33303b6158751a0baab17543f2 Mon Sep 17 00:00:00 2001
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Sat, 23 Feb 2019 11:06:43 +0100
+Subject: [PATCH] Find and link with Libgcrypt
+Forwarded: not-needed
+
+---
+ CMakeLists.txt | 1 +
+ cmake/modules/FindLibgcrypt.cmake | 25 +++++++++++++++++++++++++
+ 2 files changed, 26 insertions(+)
+ create mode 100644 cmake/modules/FindLibgcrypt.cmake
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index f902211..f20909a 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -139,6 +139,7 @@
+ Iconv
+ KissFFT
+ LibDvd
++ Libgcrypt
+ Lzo2
+ OpenSSL>=1.1.0
+ PCRE
+diff --git a/cmake/modules/FindLibgcrypt.cmake b/cmake/modules/FindLibgcrypt.cmake
+new file mode 100644
+index 0000000..9de789a
+--- /dev/null
++++ b/cmake/modules/FindLibgcrypt.cmake
+@@ -0,0 +1,25 @@
++#.rst:
++# FindLibgcrypt
++# -------
++# Finds the Libgcrypt library
++#
++# This will define the following variables::
++#
++# LIBGCRYPT_FOUND - system has Libgcrypt
++# LIBGCRYPT_INCLUDE_DIRS - the Libgcrypt include directory
++# LIBGCRYPT_LIBRARIES - the Libgcrypt libraries
++# LIBGCRYPT_DEFINITIONS - the Libgcrypt compile definitions
++
++find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h)
++find_library(LIBGCRYPT_LIBRARY NAMES gcrypt)
++
++include(FindPackageHandleStandardArgs)
++find_package_handle_standard_args(Libgcrypt REQUIRED_VARS LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR)
++
++if(LIBGCRYPT_FOUND)
++ set(LIBGCRYPT_LIBRARIES ${LIBGCRYPT_LIBRARY})
++ set(LIBGCRYPT_INCLUDE_DIRS ${LIBGCRYPT_INCLUDE_DIR})
++ set(LIBGCRYPT_DEFINITIONS -DHAVE_GCRYPT=1)
++endif()
++
++mark_as_advanced(LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR)
+--
+2.20.1
+
diff --git a/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch b/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch
new file mode 100644
index 0000000..f909400
--- /dev/null
+++ b/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch
@@ -0,0 +1,90 @@
+From d7ce565e1de5515afab869f8d1de35840567af7a Mon Sep 17 00:00:00 2001
+From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org>
+Date: Wed, 26 Feb 2020 13:48:55 +0100
+Subject: [PATCH] differentiate-from-vanilla-Kodi
+Forwarded: not-needed
+
+---
+ addons/skin.estuary/xml/Home.xml | 8 ++++++++
+ xbmc/utils/SystemInfo.cpp | 12 ++++++++----
+ xbmc/utils/test/TestSystemInfo.cpp | 2 +-
+ 3 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/addons/skin.estuary/xml/Home.xml b/addons/skin.estuary/xml/Home.xml
+index b5e1290..f441b04 100644
+--- a/addons/skin.estuary/xml/Home.xml
++++ b/addons/skin.estuary/xml/Home.xml
+@@ -1046,6 +1046,14 @@
+ <param name="visible" value="Player.HasMedia" />
+ </include>
+ </control>
++ <control type="image">
++ <left>140</left>
++ <top>71</top>
++ <width>250</width>
++ <height>56</height>
++ <aspectratio>keep</aspectratio>
++ <texture>from-debian-logo.png</texture>
++ </control>
+ </control>
+ <include>BottomBar</include>
+ <control type="group">
+diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp
+index f14d1e8a..c64821e9 100644
+--- a/xbmc/utils/SystemInfo.cpp
++++ b/xbmc/utils/SystemInfo.cpp
+@@ -75,6 +75,9 @@ using namespace winrt::Windows::System::Profile;
+
+ #include <system_error>
+
++#include <algorithm>
++#include <cctype>
++
+ /* Expand macro before stringify */
+ #define STR_MACRO(x) #x
+ #define XSTR_MACRO(x) STR_MACRO(x)
+@@ -422,7 +425,7 @@ bool CSysInfo::Save(TiXmlNode *settings) const
+ const std::string& CSysInfo::GetAppName(void)
+ {
+ assert(CCompileInfo::GetAppName() != NULL);
+- static const std::string appName(CCompileInfo::GetAppName());
++ static const std::string appName(StringUtils::Format("{} from Debian", CCompileInfo::GetAppName()));
+
+ return appName;
+ }
+@@ -1017,7 +1020,9 @@ std::string CSysInfo::GetUserAgent()
+ if (!result.empty())
+ return result;
+
+- result = GetAppName() + "/" + CSysInfo::GetVersionShort() + " (";
++ std::string appName = GetAppName();
++ appName.erase(std::remove_if(appName.begin(), appName.end(), ::isspace), appName.end());
++ result = appName + "/" + CSysInfo::GetVersionShort() + " (";
+ #if defined(TARGET_WINDOWS)
+ result += GetKernelName() + " " + GetKernelVersion();
+ #ifndef TARGET_WINDOWS_STORE
+@@ -1185,8 +1190,7 @@ std::string CSysInfo::GetVersionShort()
+
+ std::string CSysInfo::GetVersion()
+ {
+- return GetVersionShort() + " (" + CCompileInfo::GetVersionCode() + ")" +
+- " Git:" + CCompileInfo::GetSCMID();
++ return GetVersionShort() + StringUtils::Format(" Debian package version: {}", DEB_VERSION);
+ }
+
+ std::string CSysInfo::GetVersionCode()
+diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp
+index 1f2b0a1..1145aa4 100644
+--- a/xbmc/utils/test/TestSystemInfo.cpp
++++ b/xbmc/utils/test/TestSystemInfo.cpp
+@@ -208,7 +208,7 @@ TEST_F(TestSystemInfo, GetXbmcBitness)
+
+ TEST_F(TestSystemInfo, GetUserAgent)
+ {
+- EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'";
++ // EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'";
+ EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' must contain brackets around second parameter";
+ EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(')')) << "'GetUserAgent()' must contain brackets around second parameter";
+ EXPECT_EQ(g_sysinfo.GetUserAgent().find(' '), g_sysinfo.GetUserAgent().find(" (")) << "Second parameter in 'GetUserAgent()' string must be in brackets";
+--
+2.27.0.rc2
diff --git a/debian/patches/kodi/0004-use-system-groovy.patch b/debian/patches/kodi/0004-use-system-groovy.patch
new file mode 100644
index 0000000..e2df3c2
--- /dev/null
+++ b/debian/patches/kodi/0004-use-system-groovy.patch
@@ -0,0 +1,128 @@
+From 9c5f184cee41bb65c6dbe49b0c0b8cf049785d51 Mon Sep 17 00:00:00 2001
+From: Balint Reczey <balint@balintreczey.hu>
+Date: Tue, 3 Mar 2020 23:56:06 +0100
+Subject: [PATCH] Use system's groovy instead of the embedded one
+Forwarded: not-needed
+
+---
+ xbmc/interfaces/swig/CMakeLists.txt | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/xbmc/interfaces/swig/CMakeLists.txt b/xbmc/interfaces/swig/CMakeLists.txt
+index fc73821..0b5895b 100644
+--- a/xbmc/interfaces/swig/CMakeLists.txt
++++ b/xbmc/interfaces/swig/CMakeLists.txt
+@@ -1,8 +1,6 @@
+ function(generate_file file)
+- set(classpath ${GROOVY_DIR}/groovy-${GROOVY_VER}.jar
+- ${GROOVY_DIR}/groovy-xml-${GROOVY_VER}.jar
+- ${GROOVY_DIR}/groovy-templates-${GROOVY_VER}.jar
+- ${GROOVY_DIR}/commons-lang-${COMMONS_VER}.jar
++ set(classpath /usr/share/java/groovy.jar
++ /usr/share/java/commons-lang-2.6.jar
+ ${CMAKE_SOURCE_DIR}/tools/codegenerator
+ ${CMAKE_CURRENT_SOURCE_DIR}/../python)
+ if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
+@@ -24,8 +24,8 @@
+ add_custom_command(OUTPUT ${CPP_FILE}
+ COMMAND ${SWIG_EXECUTABLE}
+ ARGS -w401 -c++ -o ${file}.xml -xml -I${CMAKE_SOURCE_DIR}/xbmc -xmllang python ${CMAKE_CURRENT_SOURCE_DIR}/../swig/${file}
+- COMMAND ${Java_JAVA_EXECUTABLE}
+- ARGS ${JAVA_OPEN_OPTS} -cp "${classpath}" groovy.ui.GroovyMain ${CMAKE_SOURCE_DIR}/tools/codegenerator/Generator.groovy ${file}.xml ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template ${file}.cpp > ${devnull}
++ COMMAND groovy
++ ARGS -cp "${classpath}" ${CMAKE_SOURCE_DIR}/tools/codegenerator/Generator.groovy ${file}.xml ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template ${file}.cpp > ${devnull}
+ ${CLANG_FORMAT_COMMAND}
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../swig/${file} ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template)
+ set(SOURCES ${SOURCES} "${CPP_FILE}" PARENT_SCOPE)
+--
+2.20.1
+
+
+From 8178f46f2f692bd57d5fe851e16b1b377bb4867b Mon Sep 17 00:00:00 2001
+From: Jose Luis Marti <joseluis.marti@gmail.com>
+Date: Sun, 23 Oct 2022 23:54:58 +0200
+Subject: [PATCH 2/2] add imports needed for the bump
+
+---
+ tools/codegenerator/Generator.groovy | 1 -
+ tools/codegenerator/Helper.groovy | 1 -
+ tools/codegenerator/SwigTypeParser.groovy | 2 --
+ 3 files changed, 4 deletions(-)
+
+diff --git b/tools/codegenerator/Generator.groovy a/tools/codegenerator/Generator.groovy
+index 79cfe4f5fb..53cf7864f9 100644
+--- b/tools/codegenerator/Generator.groovy
++++ a/tools/codegenerator/Generator.groovy
+@@ -19,7 +19,6 @@
+ */
+
+ import groovy.text.SimpleTemplateEngine
+-import groovy.xml.XmlParser
+ import groovy.xml.XmlUtil
+
+ import Helper
+diff --git b/tools/codegenerator/Helper.groovy a/tools/codegenerator/Helper.groovy
+index 4308ffd3f3..6324e537e1 100644
+--- b/tools/codegenerator/Helper.groovy
++++ a/tools/codegenerator/Helper.groovy
+@@ -18,7 +18,6 @@
+ *
+ */
+
+-import groovy.xml.XmlParser
+ import groovy.xml.XmlUtil
+ import org.apache.commons.lang.StringEscapeUtils
+
+diff --git b/tools/codegenerator/SwigTypeParser.groovy a/tools/codegenerator/SwigTypeParser.groovy
+index 24dfa8f8ab..ab4e5292f9 100644
+--- b/tools/codegenerator/SwigTypeParser.groovy
++++ a/tools/codegenerator/SwigTypeParser.groovy
+@@ -18,8 +18,6 @@
+ *
+ */
+
+-import groovy.xml.XmlParser
+-
+ /**
+ * These methods are somewhat ugly because they have been copied out of
+ * the Swig source code and simply made compilable with groovy. They could
+--
+2.35.1
+
+
+From b99c39bee1c12d4471959c4854927a60f5dc4393 Mon Sep 17 00:00:00 2001
+From: Jose Luis Marti <joseluis.marti@gmail.com>
+Date: Sun, 23 Oct 2022 23:46:38 +0200
+Subject: [PATCH 1/2] delete imports that were unnecessary
+
+---
+ tools/codegenerator/Generator.groovy | 1 +
+ tools/codegenerator/Helper.groovy | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git b/tools/codegenerator/Generator.groovy a/tools/codegenerator/Generator.groovy
+index 53cf7864f9..305fb0a94b 100644
+--- b/tools/codegenerator/Generator.groovy
++++ a/tools/codegenerator/Generator.groovy
+@@ -18,6 +18,7 @@
+ *
+ */
+
++import groovy.util.Node
+ import groovy.text.SimpleTemplateEngine
+ import groovy.xml.XmlUtil
+
+diff --git b/tools/codegenerator/Helper.groovy a/tools/codegenerator/Helper.groovy
+index 6324e537e1..764e6c83a9 100644
+--- b/tools/codegenerator/Helper.groovy
++++ a/tools/codegenerator/Helper.groovy
+@@ -21,6 +21,7 @@
+ import groovy.xml.XmlUtil
+ import org.apache.commons.lang.StringEscapeUtils
+
++import groovy.text.SimpleTemplateEngine
+ import groovy.text.SimpleTemplateEngine
+ import java.util.regex.Pattern
+
+--
+2.35.1
diff --git a/debian/patches/kodi/0005-fix-tests.patch b/debian/patches/kodi/0005-fix-tests.patch
new file mode 100644
index 0000000..4099ced
--- /dev/null
+++ b/debian/patches/kodi/0005-fix-tests.patch
@@ -0,0 +1,28 @@
+From 239e1d72ebe9c2a8c3cd890b443317877f04d42b Mon Sep 17 00:00:00 2001
+From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org>
+Date: Tue, 3 Mar 2020 23:56:07 +0100
+Subject: [PATCH] fix-tests
+Forwarded: not-needed
+
+---
+ xbmc/utils/test/TestSystemInfo.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp
+index 1145aa4..7b5f00d 100644
+--- a/xbmc/utils/test/TestSystemInfo.cpp
++++ b/xbmc/utils/test/TestSystemInfo.cpp
+@@ -73,8 +73,8 @@ TEST_F(TestSystemInfo, GetKernelName)
+ TEST_F(TestSystemInfo, GetKernelVersionFull)
+ {
+ EXPECT_FALSE(g_sysinfo.GetKernelVersionFull().empty()) << "'GetKernelVersionFull()' must not return empty string";
+- EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'";
+- EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'";
++ // EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'";
++ // EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'";
+ EXPECT_EQ(0U, g_sysinfo.GetKernelVersionFull().find_first_of("0123456789")) << "'GetKernelVersionFull()' must not return version not starting from digit";
+ }
+
+--
+2.20.1
+
diff --git a/debian/patches/kodi/0006-dont-use-openssl.patch b/debian/patches/kodi/0006-dont-use-openssl.patch
new file mode 100644
index 0000000..012f187
--- /dev/null
+++ b/debian/patches/kodi/0006-dont-use-openssl.patch
@@ -0,0 +1,29 @@
+From 7eda44dad7fc5964d934c73612bb3c2a7001c26f Mon Sep 17 00:00:00 2001
+From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org>
+Date: Tue, 3 Mar 2020 23:56:07 +0100
+Subject: [PATCH] dont-use-openssl
+Forwarded: not-needed
+
+---
+ CMakeLists.txt | 2 +-
+ xbmc/utils/CryptThreading.cpp | 2 +-
+ xbmc/utils/CryptThreading.h | 4 +---
+ xbmc/utils/test/TestCryptThreading.cpp | 2 +-
+ 4 files changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index f20909a..400707d 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -141,7 +141,7 @@
+ LibDvd
+ Libgcrypt
+ Lzo2
+- OpenSSL>=1.1.0
++# OpenSSL>=1.1.0
+ PCRE
+ RapidJSON
+ Spdlog
+--
+2.20.1
+
diff --git a/debian/patches/kodi/0007-support-omitting-addons-service.patch b/debian/patches/kodi/0007-support-omitting-addons-service.patch
new file mode 100644
index 0000000..c63e58f
--- /dev/null
+++ b/debian/patches/kodi/0007-support-omitting-addons-service.patch
@@ -0,0 +1,27 @@
+From: Jonas Smedegaard <dr@jones.dk>
+Date: Tue, 3 Mar 2020 23:56:07 +0100
+Subject: Support omitting addons repository feed
+Forwarded: not-needed
+Last-Update: 2017-10-03
+
+Upstream official addon repository feed contain non-free addons.
+
+Extending the system at runtime is arguably an anti-feature -
+either for political reasons or due to security risks.
+
+This patch makes it possible to omit the addons repository feed.
+---
+ system/addon-manifest.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/system/addon-manifest.xml
++++ b/system/addon-manifest.xml
+@@ -37,7 +37,7 @@
+ <addon>metadata.local</addon>
+ <addon>metadata.themoviedb.org.python</addon>
+ <addon>metadata.tvshows.themoviedb.org.python</addon>
+- <addon>repository.xbmc.org</addon>
++ <addon optional="true">repository.xbmc.org</addon>
+ <addon>resource.images.weathericons.default</addon>
+ <addon>resource.language.en_gb</addon>
+ <addon>resource.uisounds.kodi</addon>
diff --git a/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch b/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch
new file mode 100644
index 0000000..9c22ab0
--- /dev/null
+++ b/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch
@@ -0,0 +1,22 @@
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Thu, 5 Mar 2020 16:14:33 +0100
+Subject: Find test fixtures in source directory
+Forwarded: not-needed
+
+---
+ xbmc/test/TestUtils.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/xbmc/test/TestUtils.h b/xbmc/test/TestUtils.h
+index b0dbcf6..0e46579 100644
+--- a/xbmc/test/TestUtils.h
++++ b/xbmc/test/TestUtils.h
+@@ -94,7 +94,7 @@ private:
+ double probability;
+ };
+
+-#define XBMC_REF_FILE_PATH(s) CXBMCTestUtils::Instance().ReferenceFilePath(s)
++#define XBMC_REF_FILE_PATH(s) std::string("../" s)
+ #define XBMC_CREATETEMPFILE(a) CXBMCTestUtils::Instance().CreateTempFile(a)
+ #define XBMC_DELETETEMPFILE(a) CXBMCTestUtils::Instance().DeleteTempFile(a)
+ #define XBMC_TEMPFILEPATH(a) CXBMCTestUtils::Instance().TempFilePath(a)
diff --git a/debian/patches/kodi/0009-Skip-long-time-broken-test.patch b/debian/patches/kodi/0009-Skip-long-time-broken-test.patch
new file mode 100644
index 0000000..eadf33f
--- /dev/null
+++ b/debian/patches/kodi/0009-Skip-long-time-broken-test.patch
@@ -0,0 +1,23 @@
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Thu, 5 Mar 2020 19:27:51 +0100
+Subject: Skip long time broken test
+Forwarded: not-needed
+
+---
+ xbmc/network/test/TestWebServer.cpp | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/xbmc/network/test/TestWebServer.cpp b/xbmc/network/test/TestWebServer.cpp
+index a87d9f4..3a4e9e2 100644
+--- a/xbmc/network/test/TestWebServer.cpp
++++ b/xbmc/network/test/TestWebServer.cpp
+@@ -155,7 +155,8 @@
+ // Must be only one "Content-Length" header
+ ASSERT_EQ(1U, httpHeader.GetValues(MHD_HTTP_HEADER_CONTENT_LENGTH).size());
+ // Content-Length must be "4"
+- EXPECT_STREQ("4", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str());
++ // FIXME it is "0" actually
++ // EXPECT_STREQ("4", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str());
+ // Accept-Ranges must be "bytes"
+ EXPECT_STREQ("bytes", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str());
+
diff --git a/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch b/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch
new file mode 100644
index 0000000..7572210
--- /dev/null
+++ b/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch
@@ -0,0 +1,31 @@
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Sat, 7 Mar 2020 20:31:55 +0100
+Subject: Disable flaky TestMassEvent.General and TestMassEvent.Polling tests
+Forwarded: not-needed
+
+---
+ xbmc/threads/test/TestEvent.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/xbmc/threads/test/TestEvent.cpp b/xbmc/threads/test/TestEvent.cpp
+index 1e3bb93..3293ca8 100644
+--- a/xbmc/threads/test/TestEvent.cpp
++++ b/xbmc/threads/test/TestEvent.cpp
+@@ -593,7 +593,7 @@ template <class W> void RunMassEventTest(std::vector<std::shared_ptr<W>>& m, boo
+ }
+
+
+-TEST(TestMassEvent, General)
++TEST(DISABLED_TestMassEvent, General)
+ {
+ g_event = new CEvent();
+
+@@ -605,7 +605,7 @@ TEST(TestMassEvent, General)
+ delete g_event;
+ }
+
+-TEST(TestMassEvent, Polling)
++TEST(DISABLED_TestMassEvent, Polling)
+ {
+ g_event = new CEvent(true); // polling needs to avoid the auto-reset
+
diff --git a/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch b/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch
new file mode 100644
index 0000000..8f6d155
--- /dev/null
+++ b/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch
@@ -0,0 +1,22 @@
+From: Balint Reczey <balint.reczey@canonical.com>
+Date: Tue, 17 Mar 2020 08:19:53 +0100
+Subject: Skip checking errno against ENOENT because this test fails on armhf
+Forwarded: not-needed
+
+---
+ xbmc/filesystem/test/TestFile.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/xbmc/filesystem/test/TestFile.cpp b/xbmc/filesystem/test/TestFile.cpp
+index 898bdf9..d5f7a17 100644
+--- a/xbmc/filesystem/test/TestFile.cpp
++++ b/xbmc/filesystem/test/TestFile.cpp
+@@ -133,7 +133,7 @@ TEST(TestFile, Stat)
+ file->Close();
+ EXPECT_NE(0U, buffer.st_mode | _S_IFREG);
+ EXPECT_EQ(-1, XFILE::CFile::Stat("", &buffer));
+- EXPECT_EQ(ENOENT, errno);
++ // EXPECT_EQ(ENOENT, errno);
+ EXPECT_TRUE(XBMC_DELETETEMPFILE(file));
+ }
+
diff --git a/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch b/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch
new file mode 100644
index 0000000..fc0d6f9
--- /dev/null
+++ b/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch
@@ -0,0 +1,96 @@
+From 93dd546db947f872f337d25038de60e6bc939440 Mon Sep 17 00:00:00 2001
+From: Adrian Bunk <bunk@debian.org>
+Date: Sat, 30 May 2020 21:50:37 +0200
+Subject: [PATCH] The baseline of the i386 port does not include SSE
+
+SSE2 is always enabled on amd64.
+---
+ cmake/scripts/linux/ArchSetup.cmake | 2 +-
+ xbmc/cores/AudioEngine/CMakeLists.txt | 16 ++++++++--------
+ xbmc/rendering/CMakeLists.txt | 16 ++++++++--------
+ xbmc/utils/CMakeLists.txt | 10 +++++-----
+ 4 files changed, 22 insertions(+), 22 deletions(-)
+
+diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake
+index d3ad51a7..c02ac4a1 100644
+--- a/cmake/scripts/linux/ArchSetup.cmake
++++ b/cmake/scripts/linux/ArchSetup.cmake
+@@ -18,7 +18,7 @@ else()
+ elseif(CPU MATCHES "i.86")
+ set(ARCH i486-linux)
+ set(NEON False)
+- add_options(CXX ALL_BUILDS "-msse")
++ #add_options(CXX ALL_BUILDS "-msse")
+ elseif(CPU STREQUAL arm1176jzf-s)
+ set(ARCH arm)
+ set(NEON False)
+diff --git a/xbmc/cores/AudioEngine/CMakeLists.txt b/xbmc/cores/AudioEngine/CMakeLists.txt
+index c5d4d978..f5ad9a47 100644
+--- a/xbmc/cores/AudioEngine/CMakeLists.txt
++++ b/xbmc/cores/AudioEngine/CMakeLists.txt
+@@ -156,11 +156,11 @@ endif()
+
+ core_add_library(audioengine)
+ target_include_directories(${CORE_LIBRARY} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
+- if(HAVE_SSE)
+- target_compile_options(${CORE_LIBRARY} PRIVATE -msse)
+- endif()
+- if(HAVE_SSE2)
+- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2)
+- endif()
+-endif()
++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
++# if(HAVE_SSE)
++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse)
++# endif()
++# if(HAVE_SSE2)
++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2)
++# endif()
++#endif()
+diff --git a/xbmc/rendering/CMakeLists.txt b/xbmc/rendering/CMakeLists.txt
+index c212a962..aa999703 100644
+--- a/xbmc/rendering/CMakeLists.txt
++++ b/xbmc/rendering/CMakeLists.txt
+@@ -16,12 +16,12 @@ if(OPENGL_FOUND OR OPENGLES_FOUND)
+ endif()
+
+ core_add_library(rendering)
+-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
+- if(HAVE_SSE)
+- target_compile_options(${CORE_LIBRARY} PRIVATE -msse)
+- endif()
+- if(HAVE_SSE2)
+- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2)
+- endif()
+-endif()
++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
++# if(HAVE_SSE)
++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse)
++# endif()
++# if(HAVE_SSE2)
++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2)
++# endif()
++#endif()
+
+diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt
+index 904b5cc9..48406633 100644
+--- a/xbmc/utils/CMakeLists.txt
++++ b/xbmc/utils/CMakeLists.txt
+@@ -232,8 +232,8 @@ endif()
+
+ core_add_library(utils)
+
+-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
+- if(HAVE_SSE2)
+- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2)
+- endif()
+-endif()
++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore)
++# if(HAVE_SSE2)
++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2)
++# endif()
++#endif()
+--
+2.35.1
+
diff --git a/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch b/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch
new file mode 100644
index 0000000..fe06a92
--- /dev/null
+++ b/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch
@@ -0,0 +1,22 @@
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Mon, 02 Nov 2020 08:05:00 +0200
+Subject: Disable TestCPUInfo.GetCPUFrequency test
+Origin: vendor
+Forwarded: not-needed
+
+Fixes test failure on many architectures, like s390x.
+See #970236 for example.
+
+---
+
+--- a/xbmc/utils/test/TestCPUInfo.cpp
++++ b/xbmc/utils/test/TestCPUInfo.cpp
+@@ -36,7 +36,7 @@
+ EXPECT_GT(CServiceBroker::GetCPUInfo()->GetCPUCount(), 0);
+ }
+
+-TEST_F(TestCPUInfo, GetCPUFrequency)
++TEST_F(TestCPUInfo, DISABLED_GetCPUFrequency)
+ {
+ EXPECT_GE(CServiceBroker::GetCPUInfo()->GetCPUFrequency(), 0.f);
+ }
diff --git a/debian/patches/kodi/0014-Fix-C++-example-includes.patch b/debian/patches/kodi/0014-Fix-C++-example-includes.patch
new file mode 100644
index 0000000..a37339c
--- /dev/null
+++ b/debian/patches/kodi/0014-Fix-C++-example-includes.patch
@@ -0,0 +1,52 @@
+From: Vasyl Gello <vaek.gello@gmail.com>
+Date: Mon, 16 Nov 2020 20:20:00 +0200
+Subject: Fix C++ example includes
+Forwarded: not-needed
+
+---
+
+--- a/tools/EventClients/examples/c++/example_button1.cpp
++++ b/tools/EventClients/examples/c++/example_button1.cpp
+@@ -1,4 +1,5 @@
+-#include "../../lib/c++/xbmcclient.h"
++#include <kodi/xbmcclient.h>
++
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/socket.h>
+--- a/tools/EventClients/examples/c++/example_button2.cpp
++++ b/tools/EventClients/examples/c++/example_button2.cpp
+@@ -1,4 +1,5 @@
+-#include "../../lib/c++/xbmcclient.h"
++#include <kodi/xbmcclient.h>
++
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/socket.h>
+--- a/tools/EventClients/examples/c++/example_log.cpp
++++ b/tools/EventClients/examples/c++/example_log.cpp
+@@ -1,4 +1,5 @@
+-#include "../../lib/c++/xbmcclient.h"
++#include <kodi/xbmcclient.h>
++
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/socket.h>
+--- a/tools/EventClients/examples/c++/example_mouse.cpp
++++ b/tools/EventClients/examples/c++/example_mouse.cpp
+@@ -1,4 +1,5 @@
+-#include "../../lib/c++/xbmcclient.h"
++#include <kodi/xbmcclient.h>
++
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/socket.h>
+--- a/tools/EventClients/examples/c++/example_notification.cpp
++++ b/tools/EventClients/examples/c++/example_notification.cpp
+@@ -1,4 +1,5 @@
+-#include "../../lib/c++/xbmcclient.h"
++#include <kodi/xbmcclient.h>
++
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/socket.h>
diff --git a/debian/patches/kodi/0015-debian-cross-compile.patch b/debian/patches/kodi/0015-debian-cross-compile.patch
new file mode 100644
index 0000000..6d315bc
--- /dev/null
+++ b/debian/patches/kodi/0015-debian-cross-compile.patch
@@ -0,0 +1,33 @@
+Author: Vasyl Gello <vasek.gello@gmail.com>
+Last-Updated: 2021-10-30
+Forwarded: not-needed
+Subject: Patch native dependencies for cross-compiling
+
+ * Don't build TexturePacker statically - it breaks fakeroot
+
+---
+
+diff --git a/tools/depends/native/TexturePacker/Makefile b/tools/depends/native/TexturePacker/Makefile
+index f50dc879..9ba9da48 100644
+--- a/tools/depends/native/TexturePacker/Makefile
++++ b/tools/depends/native/TexturePacker/Makefile
+@@ -10,15 +10,15 @@ endif
+
+ ifeq ($(NATIVEPLATFORM),)
+ PLATFORM = native
+- EXTRA_CONFIGURE = --enable-static
++# EXTRA_CONFIGURE = --enable-static
+ else
+ PLATFORM = $(NATIVEPLATFORM)
+ DEPS += ../../Makefile.include
+ endif
+
+-ifeq ($(NATIVE_OS), linux)
+- EXTRA_CONFIGURE = --enable-static
+-endif
++#ifeq ($(NATIVE_OS), linux)
++# EXTRA_CONFIGURE = --enable-static
++#endif
+ ifeq ($(NATIVE_OS), android)
+ EXTRA_CONFIGURE = --enable-static
+ endif
diff --git a/debian/patches/kodi/0016-ports-architectures.patch b/debian/patches/kodi/0016-ports-architectures.patch
new file mode 100644
index 0000000..6595d31
--- /dev/null
+++ b/debian/patches/kodi/0016-ports-architectures.patch
@@ -0,0 +1,132 @@
+From 5627432b717cf7df565c30490400ef11efa016e0 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Fri, 30 Dec 2022 14:39:36 +0200
+Subject: [PATCH] Introduce buildable Debian ports architectures
+
+Tested by building against sid/ppc64 and running via
+xvfb + x11vnc.
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ cmake/scripts/linux/ArchSetup.cmake | 18 ++++++++++++++++++
+ xbmc/cores/DllLoader/DllLoader.h | 1 +
+ xbmc/cores/DllLoader/ldt_keeper.c | 1 +
+ xbmc/utils/MathUtils.h | 1 +
+ xbmc/utils/SystemInfo.cpp | 19 ++++++++++++++++++-
+ 5 files changed, 39 insertions(+), 1 deletion(-)
+
+diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake
+index 4083483173..917d8f06a4 100644
+--- a/cmake/scripts/linux/ArchSetup.cmake
++++ b/cmake/scripts/linux/ArchSetup.cmake
+@@ -40,9 +40,27 @@ else()
+ elseif(CPU MATCHES riscv64)
+ set(ARCH riscv64)
+ set(NEON False)
++ elseif(CPU MATCHES ppc)
++ set(ARCH ppc)
++ set(NEON False)
++ elseif(CPU MATCHES ppc64)
++ set(ARCH ppc64)
++ set(NEON False)
+ elseif(CPU MATCHES ppc64le)
+ set(ARCH ppc64le)
+ set(NEON False)
++ elseif(CPU MATCHES m68k)
++ set(ARCH m68k)
++ set(NEON False)
++ elseif(CPU MATCHES sh4)
++ set(ARCH sh4)
++ set(NEON False)
++ elseif(CPU MATCHES sparc64)
++ set(ARCH sparc64)
++ set(NEON False)
++ elseif(CPU MATCHES alpha)
++ set(ARCH alpha)
++ set(NEON False)
+ elseif(CPU MATCHES loongarch64)
+ set(ARCH loongarch64)
+ set(NEON False)
+diff --git a/xbmc/cores/DllLoader/DllLoader.h b/xbmc/cores/DllLoader/DllLoader.h
+index 79e019d0e3..216c2dd067 100644
+--- a/xbmc/cores/DllLoader/DllLoader.h
++++ b/xbmc/cores/DllLoader/DllLoader.h
+@@ -18,6 +18,7 @@
+ !defined(__arc__) && \
+ !defined(__arm__) && \
+ !defined(__loongarch__) && \
++ !defined(__m68k__) && \
+ !defined(__mips__) && \
+ !defined(__powerpc__) && \
+ !defined(__or1k__) && \
+diff --git a/xbmc/cores/DllLoader/ldt_keeper.c b/xbmc/cores/DllLoader/ldt_keeper.c
+index 325d50cb70..01e2e9ad61 100644
+--- a/xbmc/cores/DllLoader/ldt_keeper.c
++++ b/xbmc/cores/DllLoader/ldt_keeper.c
+@@ -24,6 +24,7 @@
+ !defined(__arc__) &&\
+ !defined(__arm__) && \
+ !defined(__loongarch__) && \
++ !defined(__m68k__) && \
+ !defined(__mips__) && \
+ !defined(__or1k__) && \
+ !defined(__powerpc__) && \
+diff --git a/xbmc/utils/MathUtils.h b/xbmc/utils/MathUtils.h
+index 2b1dbcc51f..62301deef9 100644
+--- a/xbmc/utils/MathUtils.h
++++ b/xbmc/utils/MathUtils.h
+@@ -29,6 +29,7 @@
+ defined(__arm__) || \
+ defined(__loongarch__) || \
+ defined(_M_ARM) || \
++ defined(__m68k__) || \
+ defined(__mips__) || \
+ defined(__or1k__) || \
+ defined(__powerpc__) || \
+diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp
+index 6e4c1ff2a9..e3da06d70e 100644
+--- a/xbmc/utils/SystemInfo.cpp
++++ b/xbmc/utils/SystemInfo.cpp
+@@ -933,7 +933,8 @@ int CSysInfo::GetKernelBitness(void)
+ std::string machine(un.machine);
+ if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" ||
+ machine == "ppc64" || machine == "ppc64el" || machine == "ppc64le" || machine == "ia64" ||
+- machine == "mips64" || machine == "s390x" || machine == "riscv64")
++ machine == "mips64" || machine == "s390x" || machine == "riscv64" ||
++ machine == "sparc64" || machine == "alpha")
+ kernelBitness = 64;
+ else
+ kernelBitness = 32;
+@@ -990,6 +991,14 @@ const std::string& CSysInfo::GetKernelCpuFamily(void)
+ kernelCpuFamily = "PowerPC";
+ else if (machine.compare(0, 5, "riscv", 5) == 0)
+ kernelCpuFamily = "RISC-V";
++ else if (machine.compare(0, 4, "m68k", 4) == 0)
++ kernelCpuFamily = "m68k";
++ else if (machine.compare(0, 3, "sh4", 3) == 0)
++ kernelCpuFamily = "sh4";
++ else if (machine.compare(0, 7, "sparc64", 7) == 0)
++ kernelCpuFamily = "SPARC";
++ else if (machine.compare(0, 5, "alpha", 5) == 0)
++ kernelCpuFamily = "alpha";
+ }
+ #endif
+ if (kernelCpuFamily.empty())
+@@ -1373,6 +1382,14 @@ std::string CSysInfo::GetBuildTargetCpuFamily(void)
+ return "PowerPC";
+ #elif defined(__riscv)
+ return "RISC-V";
++#elif defined(__m68k__)
++ return "m68k";
++#elif defined(__SH4__)
++ return "sh4";
++#elif defined(__sparc__)
++ return "SPARC";
++#elif defined(__alpha__)
++ return "alpha";
+ #else
+ return "unknown CPU family";
+ #endif
+--
+2.39.0
+
diff --git a/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch b/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch
new file mode 100644
index 0000000..17ae1fa
--- /dev/null
+++ b/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch
@@ -0,0 +1,184 @@
+From 3984a232ae432fc9aca028a980139d12b087b32e Mon Sep 17 00:00:00 2001
+From: Miguel Borges de Freitas <enen92@kodi.tv>
+Date: Tue, 26 Jul 2022 18:20:50 +0100
+Subject: [PATCH] dvdnav_open_files implementation
+
+Attempts to open files given that the calling application provides the dvd_reader_filesystem implementation
+and the path to the file. Supports logging callbacks similarly to other dvdnav_open methods.
+Useful for opening files located on a virtual file system (vfs) such as smb, nfs, etc
+---
+ libdvdnav-embedded/src/dvdnav.c | 21 ++++++++++++++-------
+ libdvdnav-embedded/src/dvdnav/dvdnav.h | 12 ++++++++++++
+ libdvdnav-embedded/src/vm/vm.c | 9 ++++++---
+ libdvdnav-embedded/src/vm/vm.h | 3 ++-
+ 4 files changed, 34 insertions(+), 11 deletions(-)
+
+diff --git a/libdvdnav-embedded/src/dvdnav.c b/libdvdnav-embedded/src/dvdnav.c
+index 4ef7d1a..b180b18 100644
+--- a/libdvdnav-embedded/src/dvdnav.c
++++ b/libdvdnav-embedded/src/dvdnav.c
+@@ -151,7 +151,8 @@ dvdnav_status_t dvdnav_free_dup(dvdnav_t *this) {
+ static dvdnav_status_t dvdnav_open_common(dvdnav_t** dest,
+ void *priv, const dvdnav_logger_cb *logcb,
+ const char *path,
+- dvdnav_stream_cb *stream_cb) {
++ dvdnav_stream_cb *stream_cb,
++ dvdnav_filesystem_h *fs) {
+ dvdnav_t *this;
+ struct timeval time;
+
+@@ -174,7 +175,7 @@ static dvdnav_status_t dvdnav_open_common(dvdnav_t** dest,
+ if(!this->vm) {
+ goto fail;
+ }
+- if(!vm_reset(this->vm, path, priv, stream_cb)) {
++ if(!vm_reset(this->vm, path, priv, stream_cb, fs)) {
+ goto fail;
+ }
+
+@@ -213,24 +214,30 @@ fail:
+ }
+
+ dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) {
+- return dvdnav_open_common(dest, NULL, NULL, path, NULL);
++ return dvdnav_open_common(dest, NULL, NULL, path, NULL, NULL);
+ }
+
+ dvdnav_status_t dvdnav_open2(dvdnav_t** dest,
+ void *priv,const dvdnav_logger_cb *logcb,
+ const char *path) {
+- return dvdnav_open_common(dest, priv, logcb, path, NULL);
++ return dvdnav_open_common(dest, priv, logcb, path, NULL, NULL);
+ }
+
+ dvdnav_status_t dvdnav_open_stream(dvdnav_t** dest,
+ void *priv, dvdnav_stream_cb *stream_cb) {
+- return dvdnav_open_common(dest, priv, NULL, NULL, stream_cb);
++ return dvdnav_open_common(dest, priv, NULL, NULL, stream_cb, NULL);
+ }
+
+ dvdnav_status_t dvdnav_open_stream2(dvdnav_t** dest,
+ void *priv,const dvdnav_logger_cb *logcb,
+ dvdnav_stream_cb *stream_cb) {
+- return dvdnav_open_common(dest, priv, logcb, NULL, stream_cb);
++ return dvdnav_open_common(dest, priv, logcb, NULL, stream_cb, NULL);
++}
++
++dvdnav_status_t dvdnav_open_files(dvdnav_t** dest,
++ void *priv, const dvdnav_logger_cb *logcb,
++ const char *path, dvdnav_filesystem_h *fs) {
++ return dvdnav_open_common(dest, priv, logcb, path, NULL, fs);
+ }
+
+ dvdnav_status_t dvdnav_close(dvdnav_t *this) {
+@@ -280,7 +287,7 @@ dvdnav_status_t dvdnav_reset(dvdnav_t *this) {
+ #ifdef LOG_DEBUG
+ Log3(this, "resetting vm");
+ #endif
+- if(!vm_reset(this->vm, NULL, NULL, NULL)) {
++ if(!vm_reset(this->vm, NULL, NULL, NULL, NULL)) {
+ printerr("Error restarting the VM.");
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+diff --git a/libdvdnav-embedded/src/dvdnav/dvdnav.h b/libdvdnav-embedded/src/dvdnav/dvdnav.h
+index 85136a4..ebb3751 100644
+--- a/libdvdnav-embedded/src/dvdnav/dvdnav.h
++++ b/libdvdnav-embedded/src/dvdnav/dvdnav.h
+@@ -32,6 +32,7 @@ extern "C" {
+
+ #include "version.h"
+ #include <dvdnav/dvd_types.h>
++#include <dvdread/dvd_filesystem.h>
+ #include <dvdread/dvd_reader.h>
+ #include <dvdread/nav_types.h>
+ #include <dvdnav/dvdnav_events.h>
+@@ -55,6 +56,8 @@ typedef int32_t dvdnav_status_t;
+
+ typedef dvd_reader_stream_cb dvdnav_stream_cb;
+
++typedef dvd_reader_filesystem_h dvdnav_filesystem_h;
++
+ /*
+ * Unless otherwise stated, all functions return DVDNAV_STATUS_OK if
+ * they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may
+@@ -110,6 +113,15 @@ dvdnav_status_t dvdnav_open_stream2(dvdnav_t **dest,
+ void *priv, const dvdnav_logger_cb *,
+ dvdnav_stream_cb *stream_cb);
+
++/*
++ * Attempts to open files given that the calling application provides the dvd_reader_filesystem implementation
++ * and the path to the file. Supports logging callbacks similarly to other dvdnav_open methods.
++ * Useful for opening files located on a virtual file system (vfs) such as smb, nfs, etc
++ */
++dvdnav_status_t dvdnav_open_files(dvdnav_t **dest,
++ void *priv, const dvdnav_logger_cb *,
++ const char *path, dvdnav_filesystem_h *fs);
++
+ dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src);
+ dvdnav_status_t dvdnav_free_dup(dvdnav_t * _this);
+
+diff --git a/libdvdnav-embedded/src/vm/vm.c b/libdvdnav-embedded/src/vm/vm.c
+index 9276c91..23c187b 100644
+--- a/libdvdnav-embedded/src/vm/vm.c
++++ b/libdvdnav-embedded/src/vm/vm.c
+@@ -334,7 +334,7 @@ dvd_reader_t *vm_get_dvd_reader(vm_t *vm) {
+
+ int vm_start(vm_t *vm) {
+ if (vm->stopped) {
+- if (!vm_reset(vm, NULL, NULL, NULL))
++ if (!vm_reset(vm, NULL, NULL, NULL, NULL))
+ return 0;
+
+ vm->stopped = 0;
+@@ -368,7 +368,7 @@ static void vm_close(vm_t *vm) {
+ }
+
+ int vm_reset(vm_t *vm, const char *dvdroot,
+- void *priv, dvdnav_stream_cb *stream_cb) {
++ void *priv, dvdnav_stream_cb *stream_cb, dvdnav_filesystem_h *fs) {
+ /* Setup State */
+ memset(vm->state.registers.SPRM, 0, sizeof(vm->state.registers.SPRM));
+ memset(vm->state.registers.GPRM, 0, sizeof(vm->state.registers.GPRM));
+@@ -410,6 +410,7 @@ int vm_reset(vm_t *vm, const char *dvdroot,
+ vm->streamcb = *stream_cb;
+ else
+ vm->streamcb = (dvdnav_stream_cb) { NULL, NULL, NULL };
++ vm->dvdreaderfs = fs;
+
+ /* bind local callbacks */
+ vm->dvdstreamcb.pf_seek = vm->streamcb.pf_seek ? dvd_reader_seek_handler : NULL;
+@@ -426,7 +427,9 @@ int vm_reset(vm_t *vm, const char *dvdroot,
+ dvd_logger_cb dvdread_logcb = { .pf_log = dvd_reader_logger_handler };
+ /* Only install log handler if we have one ourself */
+ dvd_logger_cb *p_dvdread_logcb = vm->logcb.pf_log ? &dvdread_logcb : NULL;
+- if(dvdroot)
++ if(dvdroot && fs)
++ vm->dvd = DVDOpenFiles(vm, p_dvdread_logcb, dvdroot, vm->dvdreaderfs);
++ else if(dvdroot)
+ vm->dvd = DVDOpen2(vm, p_dvdread_logcb, dvdroot);
+ else if(vm->priv && vm->dvdstreamcb.pf_read)
+ vm->dvd = DVDOpenStream2(vm, p_dvdread_logcb, &vm->dvdstreamcb);
+diff --git a/libdvdnav-embedded/src/vm/vm.h b/libdvdnav-embedded/src/vm/vm.h
+index bada9f0..e97c6c0 100644
+--- a/libdvdnav-embedded/src/vm/vm.h
++++ b/libdvdnav-embedded/src/vm/vm.h
+@@ -72,6 +72,7 @@ typedef struct {
+ dvdnav_stream_cb streamcb;
+ dvd_reader_t *dvd;
+ dvd_reader_stream_cb dvdstreamcb;
++ dvdnav_filesystem_h *dvdreaderfs;
+ ifo_handle_t *vmgi;
+ ifo_handle_t *vtsi;
+ dvd_state_t state;
+@@ -119,7 +120,7 @@ dvd_reader_t *vm_get_dvd_reader(vm_t *vm);
+ int vm_start(vm_t *vm);
+ void vm_stop(vm_t *vm);
+ int vm_reset(vm_t *vm, const char *dvdroot, void *priv,
+- dvdnav_stream_cb *stream_cb);
++ dvdnav_stream_cb *stream_cb, dvdnav_filesystem_h *fs);
+
+ /* copying and merging - useful for try-running an operation */
+ vm_t *vm_new_copy(vm_t *vm);
+--
+2.35.1
+
diff --git a/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch
new file mode 100644
index 0000000..f512696
--- /dev/null
+++ b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch
@@ -0,0 +1,1694 @@
+From 4510e2ab7f85f87f781b59cafb0ad278c9edeb61 Mon Sep 17 00:00:00 2001
+From: Miguel Borges de Freitas <enen92@kodi.tv>
+Date: Fri, 17 Jun 2022 09:43:49 +0100
+Subject: [PATCH 1/3] Split filesystem implementation into platform based code
+
+---
+ libdvdread-embedded/Makefile.am | 17 ++-
+ libdvdread-embedded/configure.ac | 4 +
+ libdvdread-embedded/src/dvd_input.c | 58 +++-------
+ libdvdread-embedded/src/dvd_input.h | 23 +---
+ libdvdread-embedded/src/dvd_reader.c | 216 ++++++++++-------------------------
+ libdvdread-embedded/src/dvdread/dvd_filesystem.h | 124 ++++++++++++++++++++
+ libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +--
+ libdvdread-embedded/src/dvdread_internal.h | 1 +
+ libdvdread-embedded/src/file/dir_posix.c | 98 ++++++++++++++++
+ libdvdread-embedded/src/file/dir_win32.c | 108 ++++++++++++++++++
+ libdvdread-embedded/src/file/file_posix.c | 113 ++++++++++++++++++
+ libdvdread-embedded/src/file/file_win32.c | 98 ++++++++++++++++
+ libdvdread-embedded/src/file/filesystem.c | 37 ++++++
+ libdvdread-embedded/src/file/filesystem.h | 46 ++++++++
+ libdvdread-embedded/src/file/stat_posix.c | 36 ++++++
+ libdvdread-embedded/src/file/stat_win32.c | 53 +++++++++
+ 16 files changed, 821 insertions(+), 224 deletions(-)
+ create mode 100644 libdvdread-embedded/src/dvdread/dvd_filesystem.h
+ create mode 100644 libdvdread-embedded/src/file/dir_posix.c
+ create mode 100644 libdvdread-embedded/src/file/dir_win32.c
+ create mode 100644 libdvdread-embedded/src/file/file_posix.c
+ create mode 100644 libdvdread-embedded/src/file/file_win32.c
+ create mode 100644 libdvdread-embedded/src/file/filesystem.c
+ create mode 100644 libdvdread-embedded/src/file/filesystem.h
+ create mode 100644 libdvdread-embedded/src/file/stat_posix.c
+ create mode 100644 libdvdread-embedded/src/file/stat_win32.c
+
+diff --git a/libdvdread-embedded/Makefile.am b/libdvdread-embedded/Makefile.am
+index f2849b8..29dca92 100644
+--- a/libdvdread-embedded/Makefile.am
++++ b/libdvdread-embedded/Makefile.am
+@@ -32,7 +32,21 @@ libdvdread_la_SOURCES = \
+ src/md5.h \
+ src/nav_print.c \
+ src/nav_read.c \
+- msvc/contrib/win32_cs.h
++ msvc/contrib/win32_cs.h \
++ src/file/filesystem.c \
++ src/file/filesystem.h
++
++if HAVE_WIN32
++libdvdread_la_SOURCES+= \
++ src/file/dir_win32.c \
++ src/file/file_win32.c \
++ src/file/stat_win32.c
++else
++libdvdread_la_SOURCES+= \
++ src/file/dir_posix.c \
++ src/file/file_posix.c \
++ src/file/stat_posix.c
++endif
+
+ libdvdread_la_LIBADD = $(CSS_LIBS)
+
+@@ -42,6 +56,7 @@ libdvdread_la_LDFLAGS = -version-info $(DVDREAD_LTVERSION) \
+ pkgincludedir = $(includedir)/dvdread
+ pkginclude_HEADERS = \
+ src/dvdread/bitreader.h \
++ src/dvdread/dvd_filesystem.h \
+ src/dvdread/dvd_reader.h \
+ src/dvdread/dvd_udf.h \
+ src/dvdread/ifo_print.h \
+diff --git a/libdvdread-embedded/configure.ac b/libdvdread-embedded/configure.ac
+index a60ef0c..e3cb5ac 100644
+--- a/libdvdread-embedded/configure.ac
++++ b/libdvdread-embedded/configure.ac
+@@ -77,6 +77,9 @@ AC_ARG_ENABLE([dlfcn],
+ [use_builtin_dlfcn=$enableval],
+ [use_builtin_dlfcn=no])
+
++# for filesystem/dir access
++AC_CHECK_HEADERS([dirent.h])
++
+ AS_IF([test x"$with_libdvdcss" = "xyes"], [
+ CSS_REQUIRES="libdvdcss >= 1.2"
+ PKG_CHECK_MODULES([CSS], [$CSS_REQUIRES])
+@@ -108,6 +111,7 @@ AS_IF([test "x$DOXYGEN" = "x"], [
+ ])
+ ])
+ AM_CONDITIONAL([APIDOC], [test "x$DOXYGEN" != "x" && test "x$enable_apidoc" = "xyes"])
++AM_CONDITIONAL(HAVE_WIN32, expr $host : '.*-mingw' >/dev/null 2>&1)
+
+ AS_IF([test "x$ac_cv_c_compiler_gnu" = "xyes"], [
+ AC_DEFINE([UNUSED], [__attribute__((unused))], [Unused parameter annotation])
+diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c
+index 17f0d36..1baf8f7 100644
+--- a/libdvdread-embedded/src/dvd_input.c
++++ b/libdvdread-embedded/src/dvd_input.c
+@@ -22,16 +22,9 @@
+ #include "config.h" /* Required for HAVE_DVDCSS_DVDCSS_H */
+ #include <stdio.h> /* fprintf */
+ #include <stdlib.h> /* free */
+-#include <fcntl.h> /* open */
+-#include <unistd.h> /* lseek */
+ #include <string.h> /* strerror */
+ #include <errno.h>
+
+-#ifdef _WIN32
+-#include <windows.h>
+-#include "../msvc/contrib/win32_cs.h"
+-#endif
+-
+ #include "dvdread/dvd_reader.h" /* DVD_VIDEO_LB_LEN */
+ #include "dvdread_internal.h"
+ #include "dvd_input.h"
+@@ -40,7 +33,8 @@
+
+ /* The function pointers that is the exported interface of this file. */
+ dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *,
+- const char *,dvd_reader_stream_cb *);
++ const char *, dvd_reader_stream_cb *,
++ dvd_reader_filesystem_h *);
+ int (*dvdinput_close) (dvd_input_t);
+ int (*dvdinput_seek) (dvd_input_t, int);
+ int (*dvdinput_title) (dvd_input_t, int);
+@@ -77,22 +71,6 @@ static int (*DVDcss_read) (dvdcss_t, void *, int, int);
+ #define DVDCSS_SEEK_KEY (1 << 1)
+ #endif
+
+-#ifdef _WIN32
+-static int open_win32(const char *path, int flags)
+-{
+- wchar_t *wpath;
+- int fd;
+-
+- wpath = _utf8_to_wchar(path);
+- if (!wpath) {
+- return -1;
+- }
+- fd = _wopen(wpath, flags);
+- free(wpath);
+- return fd;
+-}
+-#endif
+-
+ /* The DVDinput handle, add stuff here for new input methods.
+ * NOTE: All members of this structure must be initialized in dvd_input_New
+ */
+@@ -104,8 +82,8 @@ struct dvd_input_s {
+ dvd_logger_cb *logcb;
+ off_t ipos;
+
+- /* dummy file input */
+- int fd;
++ /* file input */
++ dvd_file_h* file;
+ /* stream input */
+ dvd_reader_stream_cb *stream_cb;
+ };
+@@ -121,7 +99,7 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb)
+
+ /* Initialize all inputs to safe defaults */
+ dev->dvdcss = NULL;
+- dev->fd = -1;
++ dev->file = NULL;
+ dev->stream_cb = NULL;
+ }
+ return dev;
+@@ -132,7 +110,8 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb)
+ */
+ static dvd_input_t css_open(void *priv, dvd_logger_cb *logcb,
+ const char *target,
+- dvd_reader_stream_cb *stream_cb)
++ dvd_reader_stream_cb *stream_cb,
++ dvd_reader_filesystem_h *fs UNUSED)
+ {
+ dvd_input_t dev;
+
+@@ -210,7 +189,8 @@ static int css_close(dvd_input_t dev)
+ */
+ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb,
+ const char *target,
+- dvd_reader_stream_cb *stream_cb)
++ dvd_reader_stream_cb *stream_cb,
++ dvd_reader_filesystem_h *fs)
+ {
+ dvd_input_t dev;
+
+@@ -239,14 +219,8 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb,
+ free(dev);
+ return NULL;
+ }
+-#if defined(_WIN32)
+- dev->fd = open_win32(target, O_RDONLY | O_BINARY);
+-#elif defined(__OS2__)
+- dev->fd = open(target, O_RDONLY | O_BINARY);
+-#else
+- dev->fd = open(target, O_RDONLY);
+-#endif
+- if(dev->fd < 0) {
++ dev->file = fs->file_open(fs, target);
++ if(!dev->file) {
+ char buf[256];
+ #if defined(HAVE_STRERROR_R) && defined(HAVE_DECL_STRERROR_R)
+ #ifdef STRERROR_R_CHAR_P
+@@ -279,7 +253,7 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb,
+ */
+ static int file_seek(dvd_input_t dev, int blocks)
+ {
+- off_t pos = -1;
++ int64_t pos = -1;
+
+ if(dev->ipos == blocks)
+ {
+@@ -298,7 +272,7 @@ static int file_seek(dvd_input_t dev, int blocks)
+ /* Returns position as the number of bytes from beginning of file
+ * or -1 on error
+ */
+- pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET);
++ pos = dev->file->seek(dev->file, (int64_t)blocks * (int64_t)DVD_VIDEO_LB_LEN, SEEK_SET);
+
+ if (pos >= 0) {
+ dev->ipos = pos / DVD_VIDEO_LB_LEN;
+@@ -342,7 +316,7 @@ static int file_read(dvd_input_t dev, void *buffer, int blocks,
+ ret = dev->stream_cb->pf_read(dev->priv, ((char*)buffer) + bytes, len);
+ } else {
+ /* Returns the number of bytes read or -1 on error */
+- ret = read(dev->fd, ((char*)buffer) + bytes, len);
++ ret = dev->file->read(dev->file, ((char*)buffer) + bytes, len);
+ }
+
+ if(ret < 0) {
+@@ -381,8 +355,8 @@ static int file_close(dvd_input_t dev)
+
+ /* close file if it was open */
+
+- if (dev->fd >= 0) {
+- ret = close(dev->fd);
++ if (dev->file) {
++ ret = dev->file->close(dev->file);
+ }
+
+ free(dev);
+diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h
+index 470cfa4..56fe170 100644
+--- a/libdvdread-embedded/src/dvd_input.h
++++ b/libdvdread-embedded/src/dvd_input.h
+@@ -31,33 +31,14 @@
+
+ typedef struct dvd_input_s *dvd_input_t;
+
+-#if defined( __MINGW32__ )
+-# undef lseek
+-# define lseek _lseeki64
+-# undef off_t
+-# define off_t off64_t
+-# undef stat
+-# define stat _stati64
+-# undef fstat
+-# define fstat _fstati64
+-# undef wstat
+-# define wstat _wstati64
+-#endif
+-
+-#ifdef __ANDROID__
+-# undef lseek
+-# define lseek lseek64
+-# undef off_t
+-# define off_t off64_t
+-#endif
+-
+ /**
+ * Function pointers that will be filled in by the input implementation.
+ * These functions provide the main API.
+ */
+ extern dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *,
+ const char *,
+- dvd_reader_stream_cb *);
++ dvd_reader_stream_cb *,
++ dvd_reader_filesystem_h *);
+ extern int (*dvdinput_close) (dvd_input_t);
+ extern int (*dvdinput_seek) (dvd_input_t, int);
+ extern int (*dvdinput_title) (dvd_input_t, int);
+diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c
+index c4d9641..5a21056 100644
+--- a/libdvdread-embedded/src/dvd_reader.c
++++ b/libdvdread-embedded/src/dvd_reader.c
+@@ -21,17 +21,13 @@
+ */
+
+ #include "config.h"
+-#include <sys/types.h> /* off_t */
+-#include <sys/stat.h> /* stat */
+ #include <sys/time.h> /* For the timing of dvdcss_title crack. */
+-#include <fcntl.h> /* open */
+ #include <stdlib.h> /* free */
+ #include <stdio.h> /* fprintf */
+ #include <errno.h> /* errno, EIN* */
+ #include <string.h> /* memcpy, strlen */
+ #include <unistd.h> /* pclose */
+ #include <limits.h> /* PATH_MAX */
+-#include <dirent.h> /* opendir, readdir */
+ #include <ctype.h> /* isalpha */
+
+ #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__)
+@@ -57,11 +53,8 @@
+ #include "dvdread_internal.h"
+ #include "md5.h"
+ #include "dvdread/ifo_read.h"
++#include "file/filesystem.h"
+
+-#if defined(_WIN32)
+-# include <windows.h>
+-# include "msvc/contrib/win32_cs.h"
+-#endif
+
+ /* misc win32 helpers */
+
+@@ -81,107 +74,6 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz )
+ # endif
+ #endif /* _WIN32 */
+
+-/* Compat wrapper for stat() */
+-
+-#if defined(_WIN32)
+-/* can't re-define stat (used in both function name and struct name) */
+-typedef struct _stat64 dvdstat_t;
+-static inline int dvdstat(const char *path, dvdstat_t *st)
+-{
+- wchar_t *wpath, *it;
+- int ret;
+-
+- wpath = _utf8_to_wchar(path);
+- if (!wpath) {
+- return -1;
+- }
+-
+- /* need to strip possible trailing \\ */
+- for (it = wpath; *it; it++)
+- if ((*it == '\\' || *it == '/') && *(it+1) == 0)
+- *it = 0;
+-
+- ret = _wstat64(wpath, st);
+- free(wpath);
+- return ret;
+-}
+-#else
+-typedef struct stat dvdstat_t;
+-static inline int dvdstat(const char *file, dvdstat_t *st) {
+- return stat(file, st);
+-}
+-#endif
+-
+-#if defined(_WIN32)
+-/* UTF-8 aware version of opendir()/readdir() */
+-
+-#include <io.h>
+-
+-typedef struct {
+- intptr_t handle;
+- struct _wfinddata_t went;
+- struct dirent ent;
+-} win32_dir_t;
+-
+-win32_dir_t *win32_opendir(const char *path)
+-{
+- char *filespec;
+- wchar_t *wfilespec;
+- win32_dir_t *d;
+-
+- d = calloc(1, sizeof(*d));
+- if (!d)
+- return NULL;
+-
+- filespec = malloc(strlen(path) + 3);
+- if (!filespec) {
+- goto fail;
+- }
+- sprintf(filespec, "%s\\*", path);
+-
+- wfilespec = _utf8_to_wchar(filespec);
+- free(filespec);
+- if (!wfilespec) {
+- goto fail;
+- }
+-
+- d->handle = _wfindfirst(wfilespec, &d->went);
+- free(wfilespec);
+- if (d->handle != -1) {
+- return d;
+- }
+-
+- fail:
+- free(d);
+- return NULL;
+-}
+-
+-static struct dirent *win32_readdir(win32_dir_t *dir)
+-{
+- if (dir->went.name[0]) {
+- if (!WideCharToMultiByte(CP_UTF8, 0, dir->went.name, -1, dir->ent.d_name, sizeof(dir->ent.d_name), NULL, NULL))
+- dir->ent.d_name[0] = 0; /* allow reading next */
+- dir->went.name[0] = 0;
+- _wfindnext(dir->handle, &dir->went);
+- return &dir->ent;
+- }
+-
+- return NULL;
+-}
+-
+-static void win32_closedir(win32_dir_t *dir)
+-{
+- _findclose(dir->handle);
+- free(dir);
+-}
+-
+-#define DIR win32_dir_t
+-#define opendir win32_opendir
+-#define readdir win32_readdir
+-#define closedir win32_closedir
+-
+-#endif /* _WIN32 */
+-
+ #define DEFAULT_UDF_CACHE_LEVEL 1
+
+ struct dvd_reader_device_s {
+@@ -338,7 +230,7 @@ static dvd_reader_device_t *DVDOpenImageFile( dvd_reader_t *ctx,
+ dvd_reader_device_t *dvd;
+ dvd_input_t dev;
+
+- dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb );
++ dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb, ctx->fs );
+ if( !dev ) {
+ Log0(ctx,"Can't open %s for reading", location );
+ return NULL;
+@@ -452,6 +344,13 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ if(logcb)
+ ctx->logcb = *logcb;
+
++ ctx->fs = InitInternalFilesystem();
++ if (!ctx->fs)
++ {
++ free(ctx);
++ return NULL;
++ }
++
+ #if defined(_WIN32) || defined(__OS2__)
+ int len;
+ #endif
+@@ -490,7 +389,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ }
+ #endif
+
+- ret = dvdstat( path, &fileinfo );
++ ret = ctx->fs->stat(ctx->fs, path, &fileinfo);
+
+ if( ret < 0 ) {
+
+@@ -513,9 +412,9 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ }
+
+ /* First check if this is a block/char device or a file*/
+- if( S_ISBLK( fileinfo.st_mode ) ||
+- S_ISCHR( fileinfo.st_mode ) ||
+- S_ISREG( fileinfo.st_mode ) ) {
++ if( (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFBLK ||
++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFCHR ||
++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFREG ) {
+
+ /**
+ * Block devices and regular files are assumed to be DVD-Video images.
+@@ -538,7 +437,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ return NULL;
+ }
+ return ctx;
+- } else if( S_ISDIR( fileinfo.st_mode ) ) {
++ } else if ((fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFDIR ) {
+ #if defined(SYS_BSD)
+ struct fstab* fe;
+ #elif defined(__sun) || defined(__linux__)
+@@ -758,6 +657,9 @@ void DVDClose( dvd_reader_t *dvd )
+ if( dvd->rd->path_root ) free( dvd->rd->path_root );
+ if( dvd->rd->udfcache ) FreeUDFCache( dvd->rd->udfcache );
+ free( dvd->rd );
++ if (dvd->fs) {
++ dvd->fs->close(dvd->fs);
++ }
+ free( dvd );
+ }
+ }
+@@ -813,24 +715,33 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *ctx, const char *filename,
+ * or -1 on file not found.
+ * or -2 on path not found.
+ */
+-static int findDirFile( const char *path, const char *file, char *filename )
++static int findDirFile(dvd_reader_t *ctx, const char *path, const char *file, char *filename )
+ {
+- DIR *dir;
+- struct dirent *ent;
+-
+- dir = opendir( path );
+- if( !dir ) return -2;
++ dvd_dirent_t entry;
++ dvd_dir_h *dir = ctx->fs->dir_open(ctx->fs, path);
++ if( !dir ) {
++ Log0(ctx, "findDirFile: Could not open dir %s ", path);
++ return -2;
++ }
+
+- while( ( ent = readdir( dir ) ) != NULL ) {
+- if( !strcasecmp( ent->d_name, file ) ) {
++ int result = 0;
++ do
++ {
++ result = dir->read(dir, &entry);
++ if (result < 0) {
++ Log0(ctx, "findDirFile: Error reading dir %s (errorno: %d)", path, result);
++ return -1;
++ }
++ if( !strcasecmp( entry.d_name, file ) ) {
+ sprintf( filename, "%s%s%s", path,
+ ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
+- ent->d_name );
+- closedir(dir);
++ entry.d_name );
++ dir->close(dir);
+ return 0;
+ }
+- }
+- closedir(dir);
++ } while (result == 0);
++
++ dir->close(dir);
+ return -1;
+ }
+
+@@ -846,17 +757,17 @@ static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename )
+ nodirfile = file;
+ }
+
+- ret = findDirFile( dvd->rd->path_root, nodirfile, filename );
++ ret = findDirFile(dvd, dvd->rd->path_root, nodirfile, filename );
+ if( ret < 0 ) {
+ char video_path[ PATH_MAX + 1 ];
+
+ /* Try also with adding the path, just in case. */
+ sprintf( video_path, "%s/VIDEO_TS/", dvd->rd->path_root );
+- ret = findDirFile( video_path, nodirfile, filename );
++ ret = findDirFile(dvd, video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ /* Try with the path, but in lower case. */
+ sprintf( video_path, "%s/video_ts/", dvd->rd->path_root );
+- ret = findDirFile( video_path, nodirfile, filename );
++ ret = findDirFile(dvd, video_path, nodirfile, filename );
+ if( ret < 0 ) {
+ return 0;
+ }
+@@ -882,7 +793,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename )
+ return NULL;
+ }
+
+- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL );
++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs );
+ if( !dev ) {
+ Log0(ctx, "DVDOpenFilePath:dvdinput_open %s failed", full_path );
+ return NULL;
+@@ -896,13 +807,13 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename )
+ }
+ dvd_file->ctx = ctx;
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) {
+ Log0(ctx, "Can't stat() %s.", filename );
+ free( dvd_file );
+ dvdinput_close( dev );
+ return NULL;
+ }
+- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_devs[ 0 ] = dev;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
+@@ -979,23 +890,22 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
+ return NULL;
+ }
+
+- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL );
++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs );
+ if( dev == NULL ) {
+ free( dvd_file );
+ return NULL;
+ }
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) > 0) {
+ Log0(ctx, "Can't stat() %s.", filename );
+ dvdinput_close(dev);
+ free( dvd_file );
+ return NULL;
+ }
+- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN;
+ dvd_file->title_devs[ 0 ] = dev;
+ dvdinput_title( dvd_file->title_devs[0], 0);
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+-
+ } else {
+ int i;
+
+@@ -1006,13 +916,13 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
+ break;
+ }
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) {
+ Log0(ctx, "Can't stat() %s.", filename );
+ break;
+ }
+
+- dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
+- dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL );
++ dvd_file->title_sizes[ i ] = fileinfo.size / DVD_VIDEO_LB_LEN;
++ dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs );
+ dvdinput_title( dvd_file->title_devs[ i ], 0 );
+ dvd_file->filesize += dvd_file->title_sizes[ i ];
+ }
+@@ -1105,8 +1015,8 @@ static int DVDFileStatVOBUDF( dvd_reader_t *dvd, int title,
+ {
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ uint32_t size;
+- off_t tot_size;
+- off_t parts_size[ 9 ];
++ int64_t tot_size;
++ int64_t parts_size[ 9 ];
+ int nr_parts = 0;
+ int n;
+
+@@ -1151,8 +1061,8 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
+ char filename[ MAX_UDF_FILE_NAME_LEN ];
+ char full_path[ PATH_MAX + 1 ];
+ dvdstat_t fileinfo;
+- off_t tot_size;
+- off_t parts_size[ 9 ];
++ int64_t tot_size;
++ int64_t parts_size[ 9 ];
+ int nr_parts = 0;
+ int n;
+
+@@ -1164,14 +1074,14 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
+ if( !findDVDFile( dvd, filename, full_path ) )
+ return -1;
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) {
+ Log1(dvd, "Can't stat() %s.", filename );
+ return -1;
+ }
+
+- tot_size = fileinfo.st_size;
++ tot_size = fileinfo.size;
+ nr_parts = 1;
+- parts_size[ 0 ] = fileinfo.st_size;
++ parts_size[ 0 ] = fileinfo.size;
+
+ if( !menu ) {
+ int cur;
+@@ -1180,12 +1090,12 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title,
+ if( !findDVDFile( dvd, filename, full_path ) )
+ break;
+
+- if( dvdstat( full_path, &fileinfo ) < 0 ) {
++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) {
+ Log1(dvd, "Can't stat() %s.", filename );
+ break;
+ }
+
+- parts_size[ nr_parts ] = fileinfo.st_size;
++ parts_size[ nr_parts ] = fileinfo.size;
+ tot_size += parts_size[ nr_parts ];
+ nr_parts++;
+ }
+@@ -1263,10 +1173,10 @@ int DVDFileStat( dvd_reader_t *reader, int titlenum,
+ char full_path[ PATH_MAX + 1 ];
+
+ if( findDVDFile( reader, filename, full_path ) ) {
+- if( dvdstat( full_path, &fileinfo ) < 0 )
++ if (reader->fs->stat(reader->fs, full_path, &fileinfo) < 0)
+ Log1(reader, "Can't stat() %s.", filename );
+ else {
+- statbuf->size = fileinfo.st_size;
++ statbuf->size = fileinfo.size;
+ statbuf->nr_parts = 1;
+ statbuf->parts_size[ 0 ] = statbuf->size;
+ return 0;
+@@ -1318,8 +1228,8 @@ static int DVDReadBlocksUDF( const dvd_file_t *dvd_file, uint32_t offset,
+
+ /* Copy the cache at a specified offset into data. offset and block_count
+ * must be converted into bytes */
+- memcpy( data, dvd_file->cache + (off_t)offset * (off_t)DVD_VIDEO_LB_LEN,
+- (off_t)block_count * (off_t)DVD_VIDEO_LB_LEN );
++ memcpy( data, dvd_file->cache + (int64_t)offset * (int64_t)DVD_VIDEO_LB_LEN,
++ (int64_t)block_count * (int64_t)DVD_VIDEO_LB_LEN );
+
+ /* return the amount of blocks copied */
+ return block_count;
+diff --git a/libdvdread-embedded/src/dvdread/dvd_filesystem.h b/libdvdread-embedded/src/dvdread/dvd_filesystem.h
+new file mode 100644
+index 0000000..291f4d9
+--- /dev/null
++++ b/libdvdread-embedded/src/dvdread/dvd_filesystem.h
+@@ -0,0 +1,124 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef DVDREAD_FILESYSTEM_H_
++#define DVDREAD_FILESYSTEM_H_
++
++#include <stdint.h>
++#include <sys/types.h>
++
++/*
++ * directory access
++ */
++
++/**
++ * The dvd_dirent_t struct abstracts dirent usage from the respective platform implementation.
++ * For this reason, it only includes the parts the lib cares about (in this case d_name - the directory name)
++ */
++typedef struct
++{
++ char d_name[256];
++} dvd_dirent_t;
++
++typedef struct dvd_filesystem_dir_s dvd_dir_h;
++/**
++ * Abstraction for directory access
++ * internal - opaque handler internal to the specific implementation used to store the data type of directory stream objects.
++ * This is tipically a dir handler (e.g. a DIR* in posix)
++ * close(dvd_dir_h *dir) - called to close the directory and cleanup any alloc'd dir structures
++ * read(dvd_dir_h *dir, dvd_dirent_t *entry) - provided the dvd_dirent_t, reads the respective directory and returns -1 if the
++ * directory could not be read, 0 if successfully read.
++ */
++struct dvd_filesystem_dir_s
++{
++ void *internal;
++ void (*close)(dvd_dir_h *dir);
++ int (*read)(dvd_dir_h *dir, dvd_dirent_t *entry);
++};
++
++/*
++ * Stat access
++ */
++
++#define DVD_S_IFMT 0170000 /* These bits determine file type. */
++
++#define DVD_S_IFCHR 0020000 /* character special */
++#define DVD_S_IFDIR 0040000 /* directory */
++#define DVD_S_IFBLK 0060000 /* block special */
++#define DVD_S_IFREG 0100000 /* regular */
++
++/**
++ * Abstraction for stat buffer structure
++ * size - size of the stat'd file
++ * st_mode - file mode
++ */
++typedef struct
++{
++ off_t size;
++ unsigned int st_mode;
++} dvdstat_t;
++
++
++/*
++ * file access
++ */
++
++/**
++ * Abstraction for file access
++ * internal - opaque handler internal to the specific implementation used to store the data type of the file object.
++ * This is tipically a file reference (e.g. the file descriptor/fd)
++ * close(dvd_file_h *file) - called to close the file and cleanup any alloc'd file structs
++ * seek(dvd_file_h *file, int64_t offset, int32_t origin) - used to seek into the given file (provided the offset and the origin). Returns
++ * the position on the file after seek.
++ * read(dvd_file_h *file, char *buf, int64_t size) - used to read the file into the passed buffer, given the read size. Returns the read
++ * read from the file
++ */
++typedef struct dvd_filesystem_file_s dvd_file_h;
++struct dvd_filesystem_file_s
++{
++ void *internal;
++ int (*close) (dvd_file_h *file);
++ int64_t (*seek) (dvd_file_h *file, int64_t offset, int32_t origin);
++ ssize_t (*read) (dvd_file_h *file, char *buf, size_t size);
++};
++
++/*
++ * Filesystem implementation
++ */
++
++/**
++ * Groups all filesystem operations into a common struct. This is the struct external applications should override to
++ * provide custom filesystem implementations:
++ * internal - opaque data pointer to user data (used to convey custom data within the filesystem struct)
++ * close(dvd_reader_filesystem_h *fs) - called to destroy the filesystem implementation (free any alloc'd structs)
++ * stat(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) - stat a file/dir provided the statbuf, initializes the dvdstat_t.
++ * dir_open(dvd_reader_filesystem_h *fs, const char* dirname) - open the provided dir, initializes dvd_dir_h
++ * file_open(dvd_reader_filesystem_h *fs, const char* filename, const char *mode) - open a file, initializes dvd_file_h
++ */
++typedef struct dvd_reader_filesystem_s dvd_reader_filesystem_h;
++struct dvd_reader_filesystem_s
++{
++ void *internal;
++ void (*close) (dvd_reader_filesystem_h *fs);
++ int (*stat) (dvd_reader_filesystem_h *fs, const char *path, dvdstat_t *statbuf);
++ dvd_dir_h* (*dir_open) (dvd_reader_filesystem_h *fs, const char *dirname);
++ dvd_file_h* (*file_open) (dvd_reader_filesystem_h *fs, const char *filename);
++};
++
++#endif /* DVDREAD_FILESYSTEM_H_ */
+diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h
+index 54ef5dd..5b15704 100644
+--- a/libdvdread-embedded/src/dvdread/dvd_reader.h
++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h
+@@ -23,13 +23,6 @@
+ #ifndef LIBDVDREAD_DVD_READER_H
+ #define LIBDVDREAD_DVD_READER_H
+
+-#ifdef _MSC_VER
+-#include <config.h>
+-
+-#include <stdio.h>
+-#include <stdlib.h>
+-#endif
+-
+ #include <sys/types.h>
+ #include <inttypes.h>
+ #include <stdarg.h>
+@@ -46,6 +39,12 @@
+ */
+ #include "version.h"
+
++/**
++ * Filesystem types
++ */
++#include "dvd_filesystem.h"
++
++
+ /**
+ * The length of one Logical Block of a DVD.
+ */
+diff --git a/libdvdread-embedded/src/dvdread_internal.h b/libdvdread-embedded/src/dvdread_internal.h
+index bf4e2e1..1a35059 100644
+--- a/libdvdread-embedded/src/dvdread_internal.h
++++ b/libdvdread-embedded/src/dvdread_internal.h
+@@ -39,6 +39,7 @@ struct dvd_reader_s
+ dvd_reader_device_t *rd;
+ void *priv; /* User provided context */
+ dvd_logger_cb logcb;
++ dvd_reader_filesystem_h* fs;
+ /* Set 100 flags for BUP fallback, most signifiant left
+ [0] for upper remaining VTS, [1] for the first Main + 63 VTS */
+ uint64_t ifoBUPflags[2];
+diff --git a/libdvdread-embedded/src/file/dir_posix.c b/libdvdread-embedded/src/file/dir_posix.c
+new file mode 100644
+index 0000000..f55e62a
+--- /dev/null
++++ b/libdvdread-embedded/src/file/dir_posix.c
+@@ -0,0 +1,98 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include "config.h"
++
++#include <stdlib.h>
++#include <string.h>
++#if HAVE_DIRENT_H
++#include <dirent.h>
++#endif
++
++#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
++# if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24)
++# define USE_READDIR
++# include <errno.h>
++# endif
++#endif
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++void _dir_close_posix(dvd_dir_h *dir)
++{
++ if (dir) {
++ closedir((DIR *)dir->internal);
++ free(dir);
++ dir = NULL;
++ }
++}
++
++int _dir_read_posix(dvd_dir_h *dir, dvd_dirent_t *entry)
++{
++ struct dirent *p_e;
++
++#ifdef USE_READDIR
++ errno = 0;
++ p_e = readdir((DIR*)dir->internal);
++ if (!p_e && errno) {
++ return -errno;
++ }
++#else /* USE_READDIR */
++ int result;
++ struct dirent e;
++
++ result = readdir_r((DIR*)dir->internal, &e, &p_e);
++ if (result) {
++ return -result;
++ }
++#endif /* USE_READDIR */
++
++ if (p_e == NULL) {
++ return 1;
++ }
++ strncpy(entry->d_name, p_e->d_name, sizeof(entry->d_name));
++ entry->d_name[sizeof(entry->d_name) - 1] = 0;
++
++ return 0;
++}
++
++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname)
++{
++ if (!fs)
++ return NULL;
++
++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h));
++
++ if (!dir) {
++ return NULL;
++ }
++
++ dir->close = _dir_close_posix;
++ dir->read = _dir_read_posix;
++
++ if ((dir->internal = opendir(dirname))) {
++ return dir;
++ }
++
++ free(dir);
++ dir = NULL;
++
++ return NULL;
++}
+diff --git a/libdvdread-embedded/src/file/dir_win32.c b/libdvdread-embedded/src/file/dir_win32.c
+new file mode 100644
+index 0000000..cb89728
+--- /dev/null
++++ b/libdvdread-embedded/src/file/dir_win32.c
+@@ -0,0 +1,108 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <io.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++
++#include <windows.h>
++#include "../msvc/contrib/win32_cs.h"
++
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++
++typedef struct {
++ intptr_t handle;
++ struct _wfinddata_t went;
++} win32_dir_t;
++
++
++void _dir_close_win32(dvd_dir_h *dir)
++{
++ if (dir) {
++ _findclose(((win32_dir_t*)dir->internal)->handle);
++ free((win32_dir_t*)dir->internal);
++ free(dir);
++ dir = NULL;
++ }
++}
++
++int _dir_read_win32(dvd_dir_h *dir, dvd_dirent_t *entry)
++{
++ win32_dir_t *wdir = (win32_dir_t*)dir->internal;
++ if (wdir->went.name[0]) {
++ if (!WideCharToMultiByte(CP_UTF8, 0, wdir->went.name, -1, entry->d_name, sizeof(entry->d_name), NULL, NULL))
++ entry->d_name[0] = 0; /* allow reading next */
++ wdir->went.name[0] = 0;
++ _wfindnext(wdir->handle, &wdir->went);
++ return 0;
++ }
++ return -1;
++}
++
++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname)
++{
++ if (!fs)
++ return NULL;
++
++ char *filespec;
++ wchar_t *wfilespec;
++ win32_dir_t *d;
++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h));
++
++ if (!dir) {
++ return NULL;
++ }
++
++ d = calloc(1, sizeof(*d));
++ if (!d)
++ {
++ free(dir);
++ return NULL;
++ }
++
++ filespec = malloc(strlen(dirname) + 3);
++ if (!filespec) {
++ goto fail;
++ }
++ sprintf(filespec, "%s\\*", dirname);
++
++ wfilespec = _utf8_to_wchar(filespec);
++ free(filespec);
++ if (!wfilespec) {
++ goto fail;
++ }
++
++ d->handle = _wfindfirst(wfilespec, &d->went);
++ free(wfilespec);
++ if (d->handle != -1) {
++ dir->internal = (void*)d;
++ dir->close = _dir_close_win32;
++ dir->read = _dir_read_win32;
++ return dir;
++ }
++
++ fail:
++ free(d);
++ free(dir);
++ return NULL;
++}
+diff --git a/libdvdread-embedded/src/file/file_posix.c b/libdvdread-embedded/src/file/file_posix.c
+new file mode 100644
+index 0000000..cbdbd58
+--- /dev/null
++++ b/libdvdread-embedded/src/file/file_posix.c
+@@ -0,0 +1,113 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++
++
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <dvdread/dvd_filesystem.h>
++
++#include "filesystem.h"
++
++#ifdef __ANDROID__
++# undef lseek
++# define lseek lseek64
++# undef off_t
++# define off_t off64_t
++#endif
++
++
++int _file_close(dvd_file_h *file)
++{
++ if (file) {
++ int ret = close((int)(intptr_t)file->internal);
++ free(file);
++ return ret;
++ }
++ return 0;
++}
++
++int64_t _file_seek(dvd_file_h *file, int64_t offset, int32_t origin)
++{
++ off_t result = lseek((int)(intptr_t)file->internal, offset, origin);
++ if (result == (off_t)-1) {
++ return -1;
++ }
++ return (int64_t)result;
++}
++
++ssize_t _file_read(dvd_file_h *file, char *buf, size_t size)
++{
++ ssize_t result;
++
++ if (size <= 0) {
++ return 0;
++ }
++
++ result = read((int)(intptr_t)file->internal, buf, size);
++ return result;
++}
++
++
++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename)
++{
++ if (!fs)
++ return NULL;
++
++ dvd_file_h *file;
++ int fd = -1;
++ int flags = 0;
++ int mode = 0;
++
++ #if defined(__OS2__) // not posix but kept here for legacy compatibility reasons
++ flags = O_RDONLY | O_BINARY;
++ #else
++ flags = O_RDONLY;
++ #endif
++
++#ifdef O_CLOEXEC
++ flags |= O_CLOEXEC;
++#endif
++#ifdef O_BINARY
++ flags |= O_BINARY;
++#endif
++
++ if ((fd = open(filename, flags, mode)) < 0) {
++ return NULL;
++ }
++
++ file = calloc(1, sizeof(dvd_file_h));
++ if (!file) {
++ close(fd);
++ return NULL;
++ }
++
++ file->close = _file_close;
++ file->read = _file_read;
++ file->seek = _file_seek;
++ file->internal = (void*)(intptr_t)fd;
++
++ return file;
++}
+diff --git a/libdvdread-embedded/src/file/file_win32.c b/libdvdread-embedded/src/file/file_win32.c
+new file mode 100644
+index 0000000..9787076
+--- /dev/null
++++ b/libdvdread-embedded/src/file/file_win32.c
+@@ -0,0 +1,98 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <errno.h>
++
++#include <sys/stat.h>
++#include <fcntl.h>
++
++#include <windows.h>
++#include "../msvc/contrib/win32_cs.h"
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++
++int _file_close_win32(dvd_file_h *file)
++{
++ if (file) {
++ int ret = close((int)(intptr_t)file->internal);
++ free(file);
++ return ret;
++ }
++ return 0;
++}
++
++int64_t _file_seek_win32(dvd_file_h *file, int64_t offset, int32_t origin)
++{
++ off64_t result = _lseeki64((int)(intptr_t)file->internal, offset, origin);
++ if (result == (off64_t)-1) {
++ return -1;
++ }
++ return (int64_t)result;
++}
++
++ssize_t _file_read_win32(dvd_file_h *file, char *buf, size_t size)
++{
++ ssize_t result;
++
++ if (size <= 0) {
++ return 0;
++ }
++
++ result = read((int)(intptr_t)file->internal, buf, size);
++ return result;
++}
++
++
++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename)
++{
++ if (!fs)
++ return NULL;
++
++ dvd_file_h *file;
++ int fd = -1;
++ wchar_t *wpath;
++
++ wpath = _utf8_to_wchar(filename);
++ if (!wpath) {
++ return NULL;
++ }
++
++ if ((fd = _wopen(wpath, O_RDONLY | O_BINARY)) < 0) {
++ free(wpath);
++ return NULL;
++ }
++
++ file = calloc(1, sizeof(dvd_file_h));
++ if (!file) {
++ close(fd);
++ return NULL;
++ }
++
++ file->close = _file_close_win32;
++ file->read = _file_read_win32;
++ file->seek = _file_seek_win32;
++ file->internal = (void*)(intptr_t)fd;
++
++ return file;
++}
+diff --git a/libdvdread-embedded/src/file/filesystem.c b/libdvdread-embedded/src/file/filesystem.c
+new file mode 100644
+index 0000000..b79edae
+--- /dev/null
++++ b/libdvdread-embedded/src/file/filesystem.c
+@@ -0,0 +1,37 @@
++/*
++ * This file is part of libdvdread.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as published by
++ * the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
++ */
++
++#include "filesystem.h"
++
++#include <stdlib.h>
++
++static void default_filesystem_close(dvd_reader_filesystem_h *fs) {
++ free(fs);
++}
++
++dvd_reader_filesystem_h* InitInternalFilesystem() {
++ dvd_reader_filesystem_h* fs = calloc( 1, sizeof(dvd_reader_filesystem_h));
++ if (!fs) {
++ return NULL;
++ }
++ fs->dir_open = dir_open_default;
++ fs->stat = stat_default;
++ fs->file_open = file_open_default;
++ fs->close = default_filesystem_close;
++ return fs;
++}
+diff --git a/libdvdread-embedded/src/file/filesystem.h b/libdvdread-embedded/src/file/filesystem.h
+new file mode 100644
+index 0000000..1b8a014
+--- /dev/null
++++ b/libdvdread-embedded/src/file/filesystem.h
+@@ -0,0 +1,46 @@
++/*
++ * This file is part of libdvdread.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as published by
++ * the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
++ */
++
++#ifndef LIBDVDREAD_FILESYSTEM_H
++#define LIBDVDREAD_FILESYSTEM_H
++
++#include "dvdread/dvd_filesystem.h"
++
++/**
++ * Prototype definition for default file open function (implemented by each platform)
++ */
++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename);
++
++/**
++ * Prototype definition for default dir open function (implemented by each platform)
++ */
++dvd_dir_h* dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname);
++
++/**
++ * Prototype definition for default stat function (implemented by each platform)
++ */
++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf);
++
++/**
++ * Inits the internal (platform specific) filesystem implementation
++ * bundled with libdvdread. This includes initializing the default internal
++ * implmentations of file_open, dir_open, stat, etc.
++ */
++dvd_reader_filesystem_h* InitInternalFilesystem();
++
++#endif
+diff --git a/libdvdread-embedded/src/file/stat_posix.c b/libdvdread-embedded/src/file/stat_posix.c
+new file mode 100644
+index 0000000..61670fc
+--- /dev/null
++++ b/libdvdread-embedded/src/file/stat_posix.c
+@@ -0,0 +1,36 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <stdlib.h>
++#include <sys/stat.h>
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf)
++{
++ if (!fs)
++ return -1;
++
++ struct stat posixstatbuf;
++ int ret = stat(path, &posixstatbuf);
++ statbuf->size = posixstatbuf.st_size;
++ statbuf->st_mode = posixstatbuf.st_mode;
++ return ret;
++}
+diff --git a/libdvdread-embedded/src/file/stat_win32.c b/libdvdread-embedded/src/file/stat_win32.c
+new file mode 100644
+index 0000000..0b8245d
+--- /dev/null
++++ b/libdvdread-embedded/src/file/stat_win32.c
+@@ -0,0 +1,53 @@
++/*
++ * This file is part of libdvdread
++ * Copyright (C) 2022 VideoLAN
++ *
++ * This file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This file is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <stdlib.h>
++#include <sys/stat.h>
++
++#include <windows.h>
++#include "../msvc/contrib/win32_cs.h"
++
++#include <dvdread/dvd_filesystem.h>
++#include "filesystem.h"
++
++
++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf)
++{
++ if (!fs)
++ return -1;
++
++ struct _stat64 win32statbuf;
++
++ wchar_t *wpath, *it;
++
++ wpath = _utf8_to_wchar(path);
++ if (!wpath) {
++ return -1;
++ }
++
++ /* need to strip possible trailing \\ */
++ for (it = wpath; *it; it++)
++ if ((*it == '\\' || *it == '/') && *(it+1) == 0)
++ *it = 0;
++
++ int ret = _wstat64(wpath, &win32statbuf);
++ statbuf->size = win32statbuf.st_size;
++ statbuf->st_mode = win32statbuf.st_mode;
++ return ret;
++}
+--
+2.35.1
+
+
+From 7215ed052b632be49c4f1ed444c7c9447e2d4c61 Mon Sep 17 00:00:00 2001
+From: Miguel Borges de Freitas <enen92@kodi.tv>
+Date: Fri, 29 Jul 2022 12:50:24 +0100
+Subject: [PATCH 2/3] Decouple dvdinput_setup providing dvdinput_setup_builtin
+ for minimal/internal fs access
+
+---
+ libdvdread-embedded/src/dvd_input.c | 23 +++++++++++++++++------
+ libdvdread-embedded/src/dvd_input.h | 8 ++++++++
+ 2 files changed, 25 insertions(+), 6 deletions(-)
+
+diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c
+index 1baf8f7..70f31b3 100644
+--- a/libdvdread-embedded/src/dvd_input.c
++++ b/libdvdread-embedded/src/dvd_input.c
+@@ -446,12 +446,23 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb)
+ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_WARN,
+ "Encrypted DVD support unavailable.");
+
+- /* libdvdcss replacement functions */
+- dvdinput_open = file_open;
+- dvdinput_close = file_close;
+- dvdinput_seek = file_seek;
+- dvdinput_title = file_title;
+- dvdinput_read = file_read;
++ dvdinput_setup_builtin(priv, logcb);
+ return 0;
+ }
+ }
++
++/**
++ * Setup read functions with the builtin libdvdread implementation (minimal DVD access without css).
++ */
++void dvdinput_setup_builtin(void *priv, dvd_logger_cb *logcb)
++{
++ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_INFO,
++ "Setting up builtin libdvdread implementation");
++
++ /* libdvdcss replacement functions */
++ dvdinput_open = file_open;
++ dvdinput_close = file_close;
++ dvdinput_seek = file_seek;
++ dvdinput_title = file_title;
++ dvdinput_read = file_read;
++}
+diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h
+index 56fe170..36fe279 100644
+--- a/libdvdread-embedded/src/dvd_input.h
++++ b/libdvdread-embedded/src/dvd_input.h
+@@ -46,7 +46,15 @@ extern int (*dvdinput_read) (dvd_input_t, void *, int, int);
+
+ /**
+ * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support.
++ * Otherwise it falls back to the internal dvdread implementation (without css support)
++ * which is basically the same as calling dvdinput_setup_builtin.
+ */
+ int dvdinput_setup(void *, dvd_logger_cb *);
+
++/**
++ * Setup function accessed by dvd_reader.c using the builtin libdvdread implementation
++ * (without css support)
++ */
++void dvdinput_setup_builtin(void *, dvd_logger_cb *);
++
+ #endif /* LIBDVDREAD_DVD_INPUT_H */
+--
+2.35.1
+
+
+From 665a98ee15896e97aa8f0c0d6499b281d0602e60 Mon Sep 17 00:00:00 2001
+From: Miguel Borges de Freitas <enen92@kodi.tv>
+Date: Fri, 29 Jul 2022 12:55:19 +0100
+Subject: [PATCH 3/3] Add DVDOpenFiles supporting caller provided filesystem
+ implementation
+
+---
+ libdvdread-embedded/src/dvd_reader.c | 32 +++++++++++++++++++++++++++-----
+ libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +++++++++++++
+ 2 files changed, 40 insertions(+), 5 deletions(-)
+
+diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c
+index 5a21056..84bef88 100644
+--- a/libdvdread-embedded/src/dvd_reader.c
++++ b/libdvdread-embedded/src/dvd_reader.c
+@@ -330,7 +330,8 @@ static char *bsd_block2char( const char *path )
+ static dvd_reader_t *DVDOpenCommon( void *priv,
+ const dvd_logger_cb *logcb,
+ const char *ppath,
+- dvd_reader_stream_cb *stream_cb )
++ dvd_reader_stream_cb *stream_cb,
++ dvd_reader_filesystem_h * fs )
+ {
+ dvdstat_t fileinfo;
+ int ret, have_css, cdir = -1;
+@@ -344,6 +345,21 @@ static dvd_reader_t *DVDOpenCommon( void *priv,
+ if(logcb)
+ ctx->logcb = *logcb;
+
++ // open files using the provided filesystem implementation
++ if (fs != NULL && ppath != NULL)
++ {
++ ctx->fs = fs;
++ dvdinput_setup_builtin(ctx->priv, &ctx->logcb);
++ ctx->rd = DVDOpenPath(ppath);
++ if (!ctx->rd)
++ {
++ free(ctx);
++ return NULL;
++ }
++ return ctx;
++ }
++
++ // create the internal filesystem
+ ctx->fs = InitInternalFilesystem();
+ if (!ctx->fs)
+ {
+@@ -629,25 +645,31 @@ DVDOpen_error:
+
+ dvd_reader_t *DVDOpen( const char *ppath )
+ {
+- return DVDOpenCommon( NULL, NULL, ppath, NULL );
++ return DVDOpenCommon( NULL, NULL, ppath, NULL, NULL );
+ }
+
+ dvd_reader_t *DVDOpenStream( void *stream,
+ dvd_reader_stream_cb *stream_cb )
+ {
+- return DVDOpenCommon( stream, NULL, NULL, stream_cb );
++ return DVDOpenCommon( stream, NULL, NULL, stream_cb, NULL );
+ }
+
+ dvd_reader_t *DVDOpen2( void *priv, const dvd_logger_cb *logcb,
+ const char *ppath )
+ {
+- return DVDOpenCommon( priv, logcb, ppath, NULL );
++ return DVDOpenCommon( priv, logcb, ppath, NULL, NULL );
+ }
+
+ dvd_reader_t *DVDOpenStream2( void *priv, const dvd_logger_cb *logcb,
+ dvd_reader_stream_cb *stream_cb )
+ {
+- return DVDOpenCommon( priv, logcb, NULL, stream_cb );
++ return DVDOpenCommon( priv, logcb, NULL, stream_cb, NULL );
++}
++
++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb,
++ const char *ppath, dvd_reader_filesystem_h *fs)
++{
++ return DVDOpenCommon( priv, logcb, ppath, NULL, fs);
+ }
+
+ void DVDClose( dvd_reader_t *dvd )
+diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h
+index 5b15704..40ddaf2 100644
+--- a/libdvdread-embedded/src/dvdread/dvd_reader.h
++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h
+@@ -153,6 +153,19 @@ dvd_reader_t *DVDOpenStream( void *, dvd_reader_stream_cb * );
+ dvd_reader_t *DVDOpen2( void *, const dvd_logger_cb *, const char * );
+ dvd_reader_t *DVDOpenStream2( void *, const dvd_logger_cb *, dvd_reader_stream_cb * );
+
++/**
++ * Open unencrypted DVD files providing the respective filesystem implementation
++ * Useful to open files located on virtual file systems
++ *
++ * @param path Specifies the file or directory to use
++ * @param priv is a private handle
++ * @param logcb is a custom logger callback struct, or NULL if none needed
++ * @param fs is a struct containing the filesystem implementation
++ * @return If successful a read handle is returned. Otherwise 0 is returned.
++ *
++ */
++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb, const char * path, dvd_reader_filesystem_h *fs);
++
+ /**
+ * Closes and cleans up the DVD reader object.
+ *
+--
+2.35.1
+
diff --git a/debian/patches/libdvdread/debian-0001-libdvdcss.patch b/debian/patches/libdvdread/debian-0001-libdvdcss.patch
new file mode 100644
index 0000000..3b30917
--- /dev/null
+++ b/debian/patches/libdvdread/debian-0001-libdvdcss.patch
@@ -0,0 +1,25 @@
+From: Daniel Baumann <mail@daniel-baumann.ch>
+Date: Tue, 22 Apr 2014 11:14:26 +0200
+Subject: libdvdcss
+Forwarded: not-needed
+
+Print information about the CSS README.
+---
+ libdvdread-embedded/src/dvd_input.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c
+index 0c44387..f640020 100644
+--- a/libdvdread-embedded/src/dvd_input.c
++++ b/libdvdread-embedded/src/dvd_input.c
+@@ -477,8 +477,8 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb, unsigned char stream_mode)
+
+ } else {
+ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_WARN,
+- "Encrypted DVD support unavailable.");
+-
++ "Encrypted DVD support unavailable. No css library available. "
++ "See /usr/share/doc/libdvdread4/README.css for more information");
+ dvdinput_setup_builtin(priv, logcb);
+ return 0;
+ }
diff --git a/debian/patches/libdvdread/debian-0002-descriptor.patch b/debian/patches/libdvdread/debian-0002-descriptor.patch
new file mode 100644
index 0000000..a61d4f4
--- /dev/null
+++ b/debian/patches/libdvdread/debian-0002-descriptor.patch
@@ -0,0 +1,104 @@
+From: Mario Holbe <mario.holbe@tu-ilmenau.de>
+Date: Tue, 22 Apr 2014 11:49:42 +0200
+Subject: descriptor
+Forwarded: not-needed
+
+libdvdread is very likely to fail on discs/images that store their File
+System Descriptor at the end of the disc/image rather than at the
+beginning. This is due to the "strategy" libdvdread uses to find it:
+libdvdread scans sequentially from the beginning of the disc/image for
+the File System Descriptor and identifies it by a single byte tag.
+
+Aside from wasting lots of time on discs/images that store their File
+System Descriptor at the end there is quite a good chance to stumble
+across a random data block that accidentally starts with this tag (and
+failing on it) before finding the real File System Descriptor.
+
+As far as I can see, at least CDBurnerXP seems to (be able to) create
+such images - at least if my interpretation of the Implementation
+Identifier "NMS DVDProLib" is correct.
+
+This... well, let's call it ugly hack fixes this by obtaining
+the File System Descriptor location from the Logical Volume Descriptor
+
+Closes: #663512
+---
+ libdvdread-embedded/src/dvd_udf.c | 37 ++++++++++++++++++++++++++++++++++---
+ 1 file changed, 34 insertions(+), 3 deletions(-)
+
+diff --git a/libdvdread-embedded/src/dvd_udf.c b/libdvdread-embedded/src/dvd_udf.c
+index 41517fa..7b22b43 100644
+--- a/libdvdread-embedded/src/dvd_udf.c
++++ b/libdvdread-embedded/src/dvd_udf.c
+@@ -82,6 +82,8 @@ struct Partition {
+ uint32_t AccessType;
+ uint32_t Start;
+ uint32_t Length;
++ uint32_t FSD_Location;
++ uint32_t FSD_Length;
+ };
+
+ struct AD {
+@@ -101,6 +103,12 @@ struct avdp_t {
+ struct extent_ad rvds;
+ };
+
++struct fsd_t {
++ uint16_t Partition;
++ uint32_t Location;
++ uint32_t Length;
++};
++
+ struct pvd_t {
+ uint8_t VolumeIdentifier[32];
+ uint8_t VolumeSetIdentifier[128];
+@@ -427,6 +435,16 @@ static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor )
+ return 0;
+ }
+
++/**
++ * Reads the File Set Descriptor from the Logical Volume Descriptor.
++ */
++static void UDFFSD( uint8_t *data, struct fsd_t *fsd )
++{
++ fsd->Length = GETN4(248); /* always 2048? */
++ fsd->Location = GETN4(252);
++ fsd->Partition = GETN2(256); /* always 0? */
++}
++
+ static int UDFFileEntry( uint8_t *data, uint8_t *FileType,
+ struct Partition *partition, struct AD *ad )
+ {
+@@ -801,8 +819,18 @@ static int UDFFindPartition( dvd_reader_t *ctx, int partnum,
+ /* Logical Volume Descriptor */
+ if( UDFLogVolume( LogBlock ) ) {
+ /* TODO: sector size wrong! */
+- } else
+- volvalid = 1;
++ } else {
++ struct fsd_t fsd;
++
++ UDFFSD(LogBlock, &fsd);
++ if(part->Number == fsd.Partition) {
++ part->FSD_Location = fsd.Location;
++ part->FSD_Length = fsd.Length;
++ volvalid = 1;
++ } else {
++ /* TODO: Oups, how to handle this? */
++ }
++ }
+ }
+
+ } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 )
+@@ -845,7 +873,10 @@ uint32_t UDFFindFile( dvd_reader_t *ctx, const char *filename,
+ SetUDFCache(ctx, PartitionCache, 0, &partition);
+
+ /* Find root dir ICB */
+- lbnum = partition.Start;
++ lbnum = partition.Start + partition.FSD_Location;
++ /*
++ fprintf(stderr, "Looking for FSD at 0x%x\n", lbnum);
++ */
+ do {
+ ret = DVDReadLBUDF( ctx, lbnum++, 1, LogBlock, 0 );
+ if( ret < 0 ) {
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..3b63e5d
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,28 @@
+kodi/0001-Implement-hashes-using-Libgcrypt.patch
+kodi/0002-Find-and-link-with-Libgcrypt.patch
+kodi/0003-differentiate-from-vanilla-Kodi.patch
+kodi/0004-use-system-groovy.patch
+kodi/0005-fix-tests.patch
+kodi/0006-dont-use-openssl.patch
+kodi/0007-support-omitting-addons-service.patch
+kodi/0008-Find-test-fixtures-in-source-directory.patch
+kodi/0009-Skip-long-time-broken-test.patch
+kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch
+kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch
+kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch
+kodi/0013-Disable-GetCPUFrequency-test.patch
+kodi/0014-Fix-C++-example-includes.patch
+kodi/0015-debian-cross-compile.patch
+kodi/0016-ports-architectures.patch
+libdvdnav/0001-libdvdnav-PR48-enen92.patch
+libdvdread/0001-libdvdread-PR40-enen92.patch
+libdvdread/debian-0001-libdvdcss.patch
+libdvdread/debian-0002-descriptor.patch
+cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch
+workarounds/0001-Workaround-989814.patch
+workarounds/0002-ffmpeg5.patch
+workarounds/0003-xbmc-libdvd_vfs-enen92.patch
+workarounds/0004-ffmpeg6.patch
+workarounds/0005-pcre2.patch
+workarounds/0006-loongarch.patch
+workarounds/0007-swig.patch
diff --git a/debian/patches/workarounds/0001-Workaround-989814.patch b/debian/patches/workarounds/0001-Workaround-989814.patch
new file mode 100644
index 0000000..aac9c94
--- /dev/null
+++ b/debian/patches/workarounds/0001-Workaround-989814.patch
@@ -0,0 +1,71 @@
+From 82880587b3a578d61e8335199f316e6794750ba6 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Fri, 25 Jun 2021 01:37:02 +0000
+Subject: [PATCH 1/2] Check if applied locale correctly lowers chars and
+ fallback
+
+.. to default region if it does not.
+
+Fixes #19883.
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/LangInfo.cpp | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/xbmc/LangInfo.cpp b/xbmc/LangInfo.cpp
+index 24f0419cfe..1c93ebf440 100644
+--- a/xbmc/LangInfo.cpp
++++ b/xbmc/LangInfo.cpp
+@@ -981,6 +981,18 @@ void CLangInfo::SetCurrentRegion(const std::string& strName)
+
+ m_currentRegion->SetGlobalLocale();
+
++ // Check if locale is affected by "Turkish I"
++ // See https://github.com/xbmc/xbmc/issue/19883 for details
++ if (std::tolower('i') != std::tolower('I'))
++ {
++ CLog::Log(
++ LOGWARNING,
++ "region '{}' is affected by 'Turkish I' problem - falling back to default region '{}'",
++ m_currentRegion->m_strName, m_defaultRegion.m_strName);
++ m_currentRegion = &m_defaultRegion;
++ m_currentRegion->SetGlobalLocale();
++ }
++
+ const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
+ if (settings->GetString(CSettings::SETTING_LOCALE_SHORTDATEFORMAT) == SETTING_REGIONAL_DEFAULT)
+ SetShortDateFormat(m_currentRegion->m_strDateFormatShort);
+--
+2.33.0
+
+
+From 2be9ed286e1478c7b1a3002242330b6101492621 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Sun, 27 Jun 2021 19:31:39 +0000
+Subject: [PATCH 2/2] kodi.sh.in: Unset LC_{ALL,CTYPE}, LANG
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ tools/Linux/kodi.sh.in | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/tools/Linux/kodi.sh.in b/tools/Linux/kodi.sh.in
+index 108c0b007b..b148fd49ee 100644
+--- a/tools/Linux/kodi.sh.in
++++ b/tools/Linux/kodi.sh.in
+@@ -171,6 +171,11 @@ if command_exists gdb; then
+ fi
+ fi
+
++
++# Check if locale is affected by "Turkish I"
++# See https://github.com/xbmc/xbmc/issue/19883 for details
++unset LC_CTYPE LC_ALL LANG
++
+ LOOP=1
+ while [ $(( $LOOP )) = "1" ]
+ do
+--
+2.33.0
+
diff --git a/debian/patches/workarounds/0002-ffmpeg5.patch b/debian/patches/workarounds/0002-ffmpeg5.patch
new file mode 100644
index 0000000..64c31d2
--- /dev/null
+++ b/debian/patches/workarounds/0002-ffmpeg5.patch
@@ -0,0 +1,2429 @@
+From 2218c1c37c16df4ce3da34c8566f5e1335a66c01 Mon Sep 17 00:00:00 2001
+From: Alwin Esch <alwin.esch@web.de>
+Date: Sun, 10 Jul 2022 18:59:52 +0200
+Subject: [PATCH 1/3] FFmpeg5 port
+
+---
+ xbmc/cdrip/EncoderFFmpeg.cpp | 95 ++++++---------
+ xbmc/cdrip/EncoderFFmpeg.h | 1 -
+ .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 111 +++++++++++-------
+ .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 14 +--
+ xbmc/cores/FFmpeg.cpp | 14 ++-
+ xbmc/cores/FFmpeg.h | 26 ++++
+ .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 12 +-
+ .../Overlay/DVDOverlayCodecFFmpeg.cpp | 3 +-
+ .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 36 +++++-
+ .../DVDCodecs/Video/DVDVideoPPFFmpeg.cpp | 5 +
+ .../VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 10 +-
+ .../DVDDemuxers/DVDDemuxClient.cpp | 3 +-
+ .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 71 +++++++++--
+ .../DVDInputStreams/InputStreamAddon.cpp | 3 +-
+ xbmc/filesystem/AudioBookFileDirectory.cpp | 3 +-
+ xbmc/guilib/FFmpegImage.cpp | 6 +-
+ xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp | 2 +-
+ xbmc/video/tags/VideoTagLoaderFFmpeg.cpp | 2 +-
+ 18 files changed, 281 insertions(+), 136 deletions(-)
+
+diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp
+index 2867b7cb67..4c0628b5cc 100644
+--- a/xbmc/cdrip/EncoderFFmpeg.cpp
++++ b/xbmc/cdrip/EncoderFFmpeg.cpp
+@@ -11,6 +11,7 @@
+ #include "ServiceBroker.h"
+ #include "addons/Addon.h"
+ #include "addons/AddonManager.h"
++#include "cores/FFmpeg.h"
+ #include "settings/Settings.h"
+ #include "settings/SettingsComponent.h"
+ #include "utils/StringUtils.h"
+@@ -19,23 +20,8 @@
+ #include "utils/log.h"
+
+ using namespace KODI::CDRIP;
+-
+-namespace
+-{
+-
+-struct EncoderException : public std::exception
+-{
+- std::string s;
+- template<typename... Args>
+- EncoderException(const std::string& fmt, Args&&... args)
+- : s(StringUtils::Format(fmt, std::forward<Args>(args)...))
+- {
+- }
+- ~EncoderException() throw() {} // Updated
+- const char* what() const throw() { return s.c_str(); }
+-};
+-
+-} /* namespace */
++using FFMPEG_HELP_TOOLS::FFMpegErrorToString;
++using FFMPEG_HELP_TOOLS::FFMpegException;
+
+ bool CEncoderFFmpeg::Init()
+ {
+@@ -54,7 +40,7 @@ bool CEncoderFFmpeg::Init()
+ }
+ else
+ {
+- throw EncoderException("Could not get add-on: {}", addonId);
++ throw FFMpegException("Could not get add-on: {}", addonId);
+ }
+
+ // Hack fix about PTS on generated files.
+@@ -66,45 +52,45 @@ bool CEncoderFFmpeg::Init()
+ else if (addonId == "audioencoder.kodi.builtin.wma")
+ m_samplesCountMultiply = 1000;
+ else
+- throw EncoderException("Internal add-on id \"{}\" not known as usable", addonId);
++ throw FFMpegException("Internal add-on id \"{}\" not known as usable", addonId);
+
+ const std::string filename = URIUtils::GetFileName(m_strFile);
+
+ m_formatCtx = avformat_alloc_context();
+ if (!m_formatCtx)
+- throw EncoderException("Could not allocate output format context");
++ throw FFMpegException("Could not allocate output format context");
+
+ m_bcBuffer = static_cast<uint8_t*>(av_malloc(BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE));
+ if (!m_bcBuffer)
+- throw EncoderException("Could not allocate buffer");
++ throw FFMpegException("Could not allocate buffer");
+
+ m_formatCtx->pb = avio_alloc_context(m_bcBuffer, BUFFER_SIZE, AVIO_FLAG_WRITE, this, nullptr,
+ avio_write_callback, avio_seek_callback);
+ if (!m_formatCtx->pb)
+- throw EncoderException("Failed to allocate ByteIOContext");
++ throw FFMpegException("Failed to allocate ByteIOContext");
+
+ /* Guess the desired container format based on the file extension. */
+ m_formatCtx->oformat = av_guess_format(nullptr, filename.c_str(), nullptr);
+ if (!m_formatCtx->oformat)
+- throw EncoderException("Could not find output file format");
++ throw FFMpegException("Could not find output file format");
+
+ m_formatCtx->url = av_strdup(filename.c_str());
+ if (!m_formatCtx->url)
+- throw EncoderException("Could not allocate url");
++ throw FFMpegException("Could not allocate url");
+
+ /* Find the encoder to be used by its name. */
+- AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec);
++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec);
+ if (!codec)
+- throw EncoderException("Unable to find a suitable FFmpeg encoder");
++ throw FFMpegException("Unable to find a suitable FFmpeg encoder");
+
+ /* Create a new audio stream in the output file container. */
+ m_stream = avformat_new_stream(m_formatCtx, nullptr);
+ if (!m_stream)
+- throw EncoderException("Failed to allocate AVStream context");
++ throw FFMpegException("Failed to allocate AVStream context");
+
+ m_codecCtx = avcodec_alloc_context3(codec);
+ if (!m_codecCtx)
+- throw EncoderException("Failed to allocate the encoder context");
++ throw FFMpegException("Failed to allocate the encoder context");
+
+ /* Set the basic encoder parameters.
+ * The input file's sample rate is used to avoid a sample rate conversion. */
+@@ -128,14 +114,14 @@ bool CEncoderFFmpeg::Init()
+
+ int err = avcodec_open2(m_codecCtx, codec, nullptr);
+ if (err < 0)
+- throw EncoderException("Failed to open the codec {} (error '{}')",
+- codec->long_name ? codec->long_name : codec->name,
+- FFmpegErrorToString(err));
++ throw FFMpegException("Failed to open the codec {} (error '{}')",
++ codec->long_name ? codec->long_name : codec->name,
++ FFMpegErrorToString(err));
+
+ err = avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx);
+ if (err < 0)
+- throw EncoderException("Failed to copy encoder parameters to output stream (error '{}')",
+- FFmpegErrorToString(err));
++ throw FFMpegException("Failed to copy encoder parameters to output stream (error '{}')",
++ FFMpegErrorToString(err));
+
+ m_inFormat = GetInputFormat(m_iInBitsPerSample);
+ m_outFormat = m_codecCtx->sample_fmt;
+@@ -150,7 +136,7 @@ bool CEncoderFFmpeg::Init()
+
+ m_bufferFrame = av_frame_alloc();
+ if (!m_bufferFrame || !m_buffer)
+- throw EncoderException("Failed to allocate necessary buffers");
++ throw FFMpegException("Failed to allocate necessary buffers");
+
+ m_bufferFrame->nb_samples = m_codecCtx->frame_size;
+ m_bufferFrame->format = m_inFormat;
+@@ -159,8 +145,8 @@ bool CEncoderFFmpeg::Init()
+
+ err = av_frame_get_buffer(m_bufferFrame, 0);
+ if (err < 0)
+- throw EncoderException("Could not allocate output frame samples (error '{}')",
+- FFmpegErrorToString(err));
++ throw FFMpegException("Could not allocate output frame samples (error '{}')",
++ FFMpegErrorToString(err));
+
+ avcodec_fill_audio_frame(m_bufferFrame, m_iInChannels, m_inFormat, m_buffer, m_neededBytes, 0);
+
+@@ -170,14 +156,14 @@ bool CEncoderFFmpeg::Init()
+ m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat,
+ m_codecCtx->sample_rate, 0, nullptr);
+ if (!m_swrCtx || swr_init(m_swrCtx) < 0)
+- throw EncoderException("Failed to initialize the resampler");
++ throw FFMpegException("Failed to initialize the resampler");
+
+ m_resampledBufferSize =
+ av_samples_get_buffer_size(nullptr, m_iInChannels, m_neededFrames, m_outFormat, 0);
+ m_resampledBuffer = static_cast<uint8_t*>(av_malloc(m_resampledBufferSize));
+ m_resampledFrame = av_frame_alloc();
+ if (!m_resampledBuffer || !m_resampledFrame)
+- throw EncoderException("Failed to allocate a frame for resampling");
++ throw FFMpegException("Failed to allocate a frame for resampling");
+
+ m_resampledFrame->nb_samples = m_neededFrames;
+ m_resampledFrame->format = m_outFormat;
+@@ -186,8 +172,8 @@ bool CEncoderFFmpeg::Init()
+
+ err = av_frame_get_buffer(m_resampledFrame, 0);
+ if (err < 0)
+- throw EncoderException("Could not allocate output resample frame samples (error '{}')",
+- FFmpegErrorToString(err));
++ throw FFMpegException("Could not allocate output resample frame samples (error '{}')",
++ FFMpegErrorToString(err));
+
+ avcodec_fill_audio_frame(m_resampledFrame, m_iInChannels, m_outFormat, m_resampledBuffer,
+ m_resampledBufferSize, 0);
+@@ -204,7 +190,7 @@ bool CEncoderFFmpeg::Init()
+ /* write the header */
+ err = avformat_write_header(m_formatCtx, nullptr);
+ if (err != 0)
+- throw EncoderException("Failed to write the header (error '{}')", FFmpegErrorToString(err));
++ throw FFMpegException("Failed to write the header (error '{}')", FFMpegErrorToString(err));
+
+ CLog::Log(LOGDEBUG, "CEncoderFFmpeg::{} - Successfully initialized with muxer {} and codec {}",
+ __func__,
+@@ -212,7 +198,7 @@ bool CEncoderFFmpeg::Init()
+ : m_formatCtx->oformat->name,
+ codec->long_name ? codec->long_name : codec->name);
+ }
+- catch (EncoderException& caught)
++ catch (const FFMpegException& caught)
+ {
+ CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what());
+
+@@ -299,7 +285,7 @@ bool CEncoderFFmpeg::WriteFrame()
+ if (swr_convert(m_swrCtx, m_resampledFrame->data, m_neededFrames,
+ const_cast<const uint8_t**>(m_bufferFrame->extended_data),
+ m_neededFrames) < 0)
+- throw EncoderException("Error resampling audio");
++ throw FFMpegException("Error resampling audio");
+
+ frame = m_resampledFrame;
+ }
+@@ -316,8 +302,8 @@ bool CEncoderFFmpeg::WriteFrame()
+ m_bufferSize = 0;
+ err = avcodec_send_frame(m_codecCtx, frame);
+ if (err < 0)
+- throw EncoderException("Error sending a frame for encoding (error '{}')", __func__,
+- FFmpegErrorToString(err));
++ throw FFMpegException("Error sending a frame for encoding (error '{}')",
++ FFMpegErrorToString(err));
+
+ while (err >= 0)
+ {
+@@ -329,19 +315,18 @@ bool CEncoderFFmpeg::WriteFrame()
+ }
+ else if (err < 0)
+ {
+- throw EncoderException("Error during encoding (error '{}')", __func__,
+- FFmpegErrorToString(err));
++ throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err));
+ }
+
+ err = av_write_frame(m_formatCtx, pkt);
+ if (err < 0)
+- throw EncoderException("Failed to write the frame data (error '{}')", __func__,
+- FFmpegErrorToString(err));
++ throw FFMpegException("Failed to write the frame data (error '{}')",
++ FFMpegErrorToString(err));
+
+ av_packet_unref(pkt);
+ }
+ }
+- catch (EncoderException& caught)
++ catch (const FFMpegException& caught)
+ {
+ CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what());
+ }
+@@ -400,14 +385,6 @@ AVSampleFormat CEncoderFFmpeg::GetInputFormat(int inBitsPerSample)
+ case 32:
+ return AV_SAMPLE_FMT_S32;
+ default:
+- throw EncoderException("Invalid input bits per sample");
++ throw FFMpegException("Invalid input bits per sample");
+ }
+ }
+-
+-std::string CEncoderFFmpeg::FFmpegErrorToString(int err)
+-{
+- std::string text;
+- text.reserve(AV_ERROR_MAX_STRING_SIZE);
+- av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE);
+- return text;
+-}
+diff --git a/xbmc/cdrip/EncoderFFmpeg.h b/xbmc/cdrip/EncoderFFmpeg.h
+index 39112ba3ba..0c2391c7ab 100644
+--- a/xbmc/cdrip/EncoderFFmpeg.h
++++ b/xbmc/cdrip/EncoderFFmpeg.h
+@@ -39,7 +39,6 @@ private:
+ void SetTag(const std::string& tag, const std::string& value);
+ bool WriteFrame();
+ AVSampleFormat GetInputFormat(int inBitsPerSample);
+- std::string FFmpegErrorToString(int err);
+
+ AVFormatContext* m_formatCtx{nullptr};
+ AVCodecContext* m_codecCtx{nullptr};
+diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
+index 09bb26a327..86f65f57f3 100644
+--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
+@@ -10,13 +10,24 @@
+ #define DTS_ENCODE_BITRATE 1411200
+
+ #include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
+-#include "cores/AudioEngine/Utils/AEUtil.h"
++
+ #include "ServiceBroker.h"
+-#include "utils/log.h"
++#include "cores/AudioEngine/Utils/AEUtil.h"
++#include "cores/FFmpeg.h"
+ #include "settings/Settings.h"
+ #include "settings/SettingsComponent.h"
+-#include <string.h>
++#include "utils/log.h"
++
++extern "C"
++{
++#include <libavutil/channel_layout.h>
++}
++
+ #include <cassert>
++#include <string.h>
++
++using FFMPEG_HELP_TOOLS::FFMpegErrorToString;
++using FFMPEG_HELP_TOOLS::FFMpegException;
+
+ CAEEncoderFFmpeg::CAEEncoderFFmpeg() : m_CodecCtx(NULL), m_SwrCtx(NULL)
+ {
+@@ -81,7 +92,7 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input
+
+ bool ac3 = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_AC3PASSTHROUGH);
+
+- AVCodec *codec = NULL;
++ FFMPEG_FMT_CONST AVCodec* codec = nullptr;
+
+ /* fallback to ac3 if we support it, we might not have DTS support */
+ if (ac3)
+@@ -242,63 +253,77 @@ unsigned int CAEEncoderFFmpeg::GetFrames()
+
+ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_size)
+ {
+- int got_output;
+- AVFrame *frame;
++ int size = 0;
++ int err = AVERROR_UNKNOWN;
++ AVFrame* frame = nullptr;
++ AVPacket* pkt = nullptr;
+
+ if (!m_CodecCtx)
+- return 0;
+-
+- /* allocate the input frame
+- * sadly, we have to alloc/dealloc it everytime since we have no guarantee the
+- * data argument will be constant over iterated calls and the frame needs to
+- * setup pointers inside data */
+- frame = av_frame_alloc();
+- if (!frame)
+- return 0;
++ return size;
+
+- frame->nb_samples = m_CodecCtx->frame_size;
+- frame->format = m_CodecCtx->sample_fmt;
+- frame->channel_layout = m_CodecCtx->channel_layout;
+- frame->channels = m_CodecCtx->channels;
++ try
++ {
++ /* allocate the input frame and output packet
++ * sadly, we have to alloc/dealloc it everytime since we have no guarantee the
++ * data argument will be constant over iterated calls and the frame needs to
++ * setup pointers inside data */
++ frame = av_frame_alloc();
++ pkt = av_packet_alloc();
++ if (!frame || !pkt)
++ throw FFMpegException(
++ "Failed to allocate \"AVFrame\" or \"AVPacket\" for encoding (error '{}')",
++ strerror(errno));
++
++ frame->nb_samples = m_CodecCtx->frame_size;
++ frame->format = m_CodecCtx->sample_fmt;
++ frame->channel_layout = m_CodecCtx->channel_layout;
++ frame->channels = m_CodecCtx->channels;
++
++ avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0);
++
++ pkt->size = out_size;
++ pkt->data = out;
++
++ /* encode it */
++ err = avcodec_send_frame(m_CodecCtx, frame);
++ if (err < 0)
++ throw FFMpegException("Error sending a frame for encoding (error '{}')",
++ FFMpegErrorToString(err));
++
++ while (err >= 0)
++ {
++ err = avcodec_receive_packet(m_CodecCtx, pkt);
++ if (err == AVERROR(EAGAIN) || err == AVERROR_EOF)
++ {
++ av_frame_free(&frame);
++ av_packet_free(&pkt);
++ return (err == AVERROR(EAGAIN)) ? -1 : 0;
++ }
++ else if (err < 0)
++ {
++ throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err));
++ }
+
+- avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt,
+- in, in_size, 0);
++ av_packet_unref(pkt);
++ }
+
+- /* initialize the output packet */
+- AVPacket* pkt = av_packet_alloc();
+- if (!pkt)
++ size = pkt->size;
++ }
++ catch (const FFMpegException& caught)
+ {
+- CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - av_packet_alloc failed: {}", __FUNCTION__,
+- strerror(errno));
+- av_frame_free(&frame);
+- return 0;
++ CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - {}", __func__, caught.what());
+ }
+
+- pkt->size = out_size;
+- pkt->data = out;
+-
+- /* encode it */
+- int ret = avcodec_encode_audio2(m_CodecCtx, pkt, frame, &got_output);
+-
+- int size = pkt->size;
+-
+ /* free temporary data */
+ av_frame_free(&frame);
+
+ /* free the packet */
+ av_packet_free(&pkt);
+
+- if (ret < 0 || !got_output)
+- {
+- CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Encoding failed");
+- return 0;
+- }
+-
+ /* return the number of frames used */
+ return size;
+ }
+
+-
+ int CAEEncoderFFmpeg::GetData(uint8_t **data)
+ {
+ int size;
+diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+index 3947dd5523..6000fe9c63 100644
+--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+@@ -16,17 +16,17 @@ using namespace ActiveAE;
+ #include "ActiveAESound.h"
+ #include "ActiveAEStream.h"
+ #include "ServiceBroker.h"
++#include "cores/AudioEngine/AEResampleFactory.h"
++#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
+ #include "cores/AudioEngine/Interfaces/IAudioCallback.h"
+-#include "cores/AudioEngine/Utils/AEUtil.h"
+ #include "cores/AudioEngine/Utils/AEStreamData.h"
+ #include "cores/AudioEngine/Utils/AEStreamInfo.h"
+-#include "cores/AudioEngine/AEResampleFactory.h"
+-#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
+-
++#include "cores/AudioEngine/Utils/AEUtil.h"
++#include "cores/FFmpeg.h"
+ #include "settings/Settings.h"
+ #include "settings/SettingsComponent.h"
+-#include "windowing/WinSystem.h"
+ #include "utils/log.h"
++#include "windowing/WinSystem.h"
+
+ using namespace std::chrono_literals;
+
+@@ -3016,8 +3016,8 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file)
+ AVFormatContext *fmt_ctx = nullptr;
+ AVCodecContext *dec_ctx = nullptr;
+ AVIOContext *io_ctx;
+- AVInputFormat *io_fmt = nullptr;
+- AVCodec *dec = nullptr;
++ FFMPEG_FMT_CONST AVInputFormat* io_fmt = nullptr;
++ FFMPEG_FMT_CONST AVCodec* dec = nullptr;
+ SampleConfig config;
+
+ // No custom deleter until sound is registered
+diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp
+index 03a29f7db4..de1765ed52 100644
+--- a/xbmc/cores/FFmpeg.cpp
++++ b/xbmc/cores/FFmpeg.cpp
+@@ -21,6 +21,19 @@
+
+ static thread_local CFFmpegLog* CFFmpegLogTls;
+
++namespace FFMPEG_HELP_TOOLS
++{
++
++std::string FFMpegErrorToString(int err)
++{
++ std::string text;
++ text.resize(AV_ERROR_MAX_STRING_SIZE);
++ av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE);
++ return text;
++}
++
++} // namespace FFMPEG_HELP_TOOLS
++
+ void CFFmpegLog::SetLogLevel(int level)
+ {
+ CFFmpegLog::ClearLogLevel();
+@@ -116,4 +129,3 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va)
+ }
+ buffer.erase(0, start);
+ }
+-
+diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h
+index e1194d19e9..8230701ba7 100644
+--- a/xbmc/cores/FFmpeg.h
++++ b/xbmc/cores/FFmpeg.h
+@@ -10,6 +10,7 @@
+
+ #include "ServiceBroker.h"
+ #include "utils/CPUInfo.h"
++#include "utils/StringUtils.h"
+
+ extern "C" {
+ #include <libavcodec/avcodec.h>
+@@ -21,6 +22,31 @@ extern "C" {
+ #include <libpostproc/postprocess.h>
+ }
+
++// https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26
++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100)
++#define FFMPEG_FMT_CONST const
++#else
++#define FFMPEG_FMT_CONST
++#endif
++
++namespace FFMPEG_HELP_TOOLS
++{
++
++struct FFMpegException : public std::exception
++{
++ std::string s;
++ template<typename... Args>
++ FFMpegException(const std::string& fmt, Args&&... args)
++ : s(StringUtils::Format(fmt, std::forward<Args>(args)...))
++ {
++ }
++ const char* what() const noexcept override { return s.c_str(); }
++};
++
++std::string FFMpegErrorToString(int err);
++
++} // namespace FFMPEG_HELP_TOOLS
++
+ inline int PPCPUFlags()
+ {
+ unsigned int cpuFeatures = CServiceBroker::GetCPUInfo()->GetCPUFeatures();
+diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
+index 25f3f08e1f..87e7ae2c57 100644
+--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
+@@ -7,14 +7,16 @@
+ */
+
+ #include "DVDAudioCodecFFmpeg.h"
+-#include "ServiceBroker.h"
++
+ #include "../../DVDStreamInfo.h"
+-#include "utils/log.h"
++#include "DVDCodecs/DVDCodecs.h"
++#include "ServiceBroker.h"
++#include "cores/AudioEngine/Utils/AEUtil.h"
++#include "cores/FFmpeg.h"
+ #include "settings/AdvancedSettings.h"
+ #include "settings/Settings.h"
+ #include "settings/SettingsComponent.h"
+-#include "DVDCodecs/DVDCodecs.h"
+-#include "cores/AudioEngine/Utils/AEUtil.h"
++#include "utils/log.h"
+
+ extern "C" {
+ #include <libavutil/opt.h>
+@@ -44,7 +46,7 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
+ return false;
+ }
+
+- AVCodec* pCodec = NULL;
++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr;
+ bool allowdtshddecode = true;
+
+ // set any special options
+diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp
+index 8c26cad306..3657fc093c 100644
+--- a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp
++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp
+@@ -10,6 +10,7 @@
+
+ #include "DVDOverlayImage.h"
+ #include "DVDStreamInfo.h"
++#include "cores/FFmpeg.h"
+ #include "cores/VideoPlayer/Interface/DemuxPacket.h"
+ #include "cores/VideoPlayer/Interface/TimingConstants.h"
+ #include "utils/EndianSwap.h"
+@@ -39,7 +40,7 @@ bool CDVDOverlayCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &optio
+ if (hints.codec == AV_CODEC_ID_EIA_608)
+ return false;
+
+- AVCodec* pCodec = avcodec_find_decoder(hints.codec);
++ FFMPEG_FMT_CONST AVCodec* pCodec = avcodec_find_decoder(hints.codec);
+ if (!pCodec)
+ {
+ CLog::Log(LOGDEBUG, "{} - Unable to find codec {}", __FUNCTION__, hints.codec);
+diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+index 881c02ec12..21b5e834b2 100644
+--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
+@@ -12,6 +12,7 @@
+ #include "DVDCodecs/DVDFactoryCodec.h"
+ #include "DVDStreamInfo.h"
+ #include "ServiceBroker.h"
++#include "cores/FFmpeg.h"
+ #include "cores/VideoPlayer/Interface/TimingConstants.h"
+ #include "cores/VideoPlayer/VideoRenderers/RenderManager.h"
+ #include "cores/VideoSettings.h"
+@@ -27,12 +28,13 @@
+ #include <mutex>
+
+ extern "C" {
+-#include <libavutil/opt.h>
+-#include <libavutil/mastering_display_metadata.h>
+ #include <libavfilter/avfilter.h>
+ #include <libavfilter/buffersink.h>
+ #include <libavfilter/buffersrc.h>
++#include <libavutil/mastering_display_metadata.h>
++#include <libavutil/opt.h>
+ #include <libavutil/pixdesc.h>
++#include <libavutil/video_enc_params.h>
+ }
+
+ #ifndef TARGET_POSIX
+@@ -327,7 +329,7 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
+ m_hints = hints;
+ m_options = options;
+
+- AVCodec* pCodec = nullptr;
++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr;
+
+ m_iOrientation = hints.orientation;
+
+@@ -1048,6 +1050,33 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture)
+ pVideoPicture->qscale_type = 0;
+
+ AVFrameSideData* sd;
++
++ // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20
++ // basilgello: AV_VIDEO_ENC_PARAMS_MPEG2 is introduced in 4.4!
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 134, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100)
++ sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_VIDEO_ENC_PARAMS);
++ if (sd)
++ {
++ unsigned int mb_h = (m_pFrame->height + 15) / 16;
++ unsigned int mb_w = (m_pFrame->width + 15) / 16;
++ unsigned int nb_mb = mb_h * mb_w;
++ unsigned int block_idx;
++
++ auto par = reinterpret_cast<AVVideoEncParams*>(sd->data);
++ if (par->type == AV_VIDEO_ENC_PARAMS_MPEG2 && (par->nb_blocks == 0 || par->nb_blocks == nb_mb))
++ {
++ pVideoPicture->qstride = mb_w;
++ pVideoPicture->qscale_type = par->type;
++ pVideoPicture->qp_table = static_cast<int8_t*>(av_malloc(nb_mb));
++ for (block_idx = 0; block_idx < nb_mb; block_idx++)
++ {
++ AVVideoBlockParams* b = av_video_enc_params_block(par, block_idx);
++ pVideoPicture->qp_table[block_idx] = par->qp + b->delta_qp;
++ }
++ }
++ }
++#else
+ sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_QP_TABLE_PROPERTIES);
+ if (sd)
+ {
+@@ -1068,6 +1097,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture)
+ pVideoPicture->qscale_type = qp->type;
+ }
+ }
++#endif
+
+ pVideoPicture->pict_type = m_pFrame->pict_type;
+
+diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp
+index a98fbb1710..3b2739cd22 100644
+--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp
++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp
+@@ -118,6 +118,11 @@ void CDVDVideoPPFFmpeg::Process(VideoPicture* pPicture)
+ m_pMode, m_pContext,
+ pSource->pict_type | pSource->qscale_type ? PP_PICT_TYPE_QP2 : 0);
+
++ // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 84, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100)
++ av_free(pSource->qp_table);
++#endif
+
+ pPicture->SetParams(*pSource);
+ if (pPicture->videoBuffer)
+diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp
+index 7ad891083c..eaf7b78d32 100644
+--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp
++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp
+@@ -1259,8 +1259,16 @@ void CDecoder::ReturnRenderPicture(CVaapiRenderPicture *renderPic)
+
+ IHardwareDecoder* CDecoder::Create(CDVDStreamInfo &hint, CProcessInfo &processInfo, AVPixelFormat fmt)
+ {
+- if (fmt == AV_PIX_FMT_VAAPI_VLD && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI))
++ // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4fdda160f4039fc2ae33edfd27765c9/doc/APIchanges#L18-L26
++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 8, 0)
++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI
++#else
++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI_VLD
++#endif
++ if (fmt == PIX_FMT_VAAPI &&
++ CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI))
+ return new VAAPI::CDecoder(processInfo);
++#undef PIX_FMT_VAAPI
+
+ return nullptr;
+ }
+diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
+index 2bdc3ea5a9..5be134e381 100644
+--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
+@@ -10,6 +10,7 @@
+
+ #include "DVDDemuxUtils.h"
+ #include "DVDInputStreams/DVDInputStream.h"
++#include "cores/FFmpeg.h"
+ #include "cores/VideoPlayer/Interface/TimingConstants.h"
+ #include "utils/log.h"
+
+@@ -130,7 +131,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt)
+
+ if (stream->m_context == nullptr)
+ {
+- AVCodec *codec = avcodec_find_decoder(st->codec);
++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codec);
+ if (codec == nullptr)
+ {
+ CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__);
+diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+index 739bf51922..bf6f322274 100644
+--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+@@ -38,6 +38,7 @@
+
+ extern "C"
+ {
++#include "libavutil/channel_layout.h"
+ #include "libavutil/pixdesc.h"
+ }
+
+@@ -235,7 +236,7 @@ bool CDVDDemuxFFmpeg::Aborted()
+
+ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool fileinfo)
+ {
+- AVInputFormat* iformat = NULL;
++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr;
+ std::string strFile;
+ m_streaminfo = !pInput->IsRealtime() && !m_reopen;
+ m_reopen = false;
+@@ -422,9 +423,7 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool
+ // is present, we assume it is PCM audio.
+ // AC3 is always wrapped in iec61937 (ffmpeg "spdif"), while DTS
+ // may be just padded.
+- AVInputFormat* iformat2;
+- iformat2 = av_find_input_format("spdif");
+-
++ FFMPEG_FMT_CONST AVInputFormat* iformat2 = av_find_input_format("spdif");
+ if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4)
+ {
+ iformat = iformat2;
+@@ -544,11 +543,14 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool
+ m_streaminfo = true;
+ }
+
++ // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26
++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 0, 100)
+ if (iformat && (strcmp(iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0))
+ {
+ if (URIUtils::IsRemote(strFile))
+ m_pFormatContext->iformat->flags |= AVFMT_NOGENSEARCH;
+ }
++#endif
+
+ // we need to know if this is matroska, avi or sup later
+ m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm"
+@@ -604,8 +606,11 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool
+ // if format can be nonblocking, let's use that
+ m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK;
+
+- // deprecated, will be always set in future versions
++ // https://github.com/FFmpeg/FFmpeg/blob/d682ae70b4/doc/APIchanges#L18-L21
++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(57, 66, 105) && \
++ LIBAVCODEC_BUILD < AV_VERSION_INT(57, 83, 101)
+ m_pFormatContext->flags |= AVFMT_FLAG_KEEP_SIDE_DATA;
++#endif
+
+ UpdateCurrentPTS();
+
+@@ -647,12 +652,24 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool
+ {
+ int idx = m_pFormatContext->programs[i]->stream_index[j];
+ AVStream* st = m_pFormatContext->streams[idx];
++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 3, 100)
++ // Related to https://patchwork.ffmpeg.org/project/ffmpeg/patch/20210429143825.53040-1-jamrial@gmail.com/
++ // has been replaced with AVSTREAM_EVENT_FLAG_NEW_PACKETS.
++ if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
++ (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)) ||
++ (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0))
++ {
++ nProgram = i;
++ break;
++ }
++#else
+ if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 0) ||
+ (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0))
+ {
+ nProgram = i;
+ break;
+ }
++#endif
+ }
+ }
+ }
+@@ -1401,11 +1418,19 @@ void CDVDDemuxFFmpeg::UpdateCurrentPTS()
+ if (idx >= 0)
+ {
+ AVStream* stream = m_pFormatContext->streams[idx];
++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100)
++ if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE)
++ {
++ double ts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num);
++ m_currentPts = ts;
++ }
++#else
+ if (stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE)
+ {
+ double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num);
+ m_currentPts = ts;
+ }
++#endif
+ }
+ }
+
+@@ -1621,7 +1646,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx)
+ st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample;
+ st->iChannelLayout = pStream->codecpar->channel_layout;
+ char buf[32] = {};
++ // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53
++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 24, 100)
++ av_channel_layout_describe(st->iChannelLayout, buf, sizeof(buf));
++#else
+ av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout);
++#endif
+ st->m_channelLayoutName = buf;
+ if (st->iBitsPerSample == 0)
+ st->iBitsPerSample = pStream->codecpar->bits_per_coded_sample;
+@@ -1663,6 +1693,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx)
+ st->iFpsScale = 0;
+ }
+
++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 3, 100)
+ if (pStream->codec_info_nb_frames > 0 &&
+ pStream->codec_info_nb_frames <= 2 &&
+ m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
+@@ -1672,6 +1703,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx)
+ st->iFpsRate = 0;
+ st->iFpsScale = 0;
+ }
++#endif
+
+ st->iWidth = pStream->codecpar->width;
+ st->iHeight = pStream->codecpar->height;
+@@ -1693,7 +1725,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx)
+ st->colorRange = pStream->codecpar->color_range;
+ st->hdr_type = DetermineHdrType(pStream);
+
++ // https://github.com/FFmpeg/FFmpeg/blob/release/5.0/doc/APIchanges
++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 10, 100)
++ size_t size = 0;
++#else
+ int size = 0;
++#endif
+ uint8_t* side_data = nullptr;
+
+ side_data = av_stream_get_side_data(pStream, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, &size);
+@@ -2103,7 +2140,7 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId)
+ return strName;
+ }
+
+- AVCodec* codec = avcodec_find_decoder(stream->codec);
++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(stream->codec);
+ if (codec)
+ strName = avcodec_get_name(codec->id);
+ }
+@@ -2279,7 +2316,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt)
+
+ parser->second->m_parserCtx = av_parser_init(st->codecpar->codec_id);
+
+- AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id);
++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id);
+ if (codec == nullptr)
+ {
+ CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__);
+@@ -2357,7 +2394,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState()
+ {
+ if (!m_startTime)
+ {
++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100)
++ m_startTime =
++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001;
++#else
+ m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001;
++#endif
+ m_seekStream = idx;
+ }
+ return TRANSPORT_STREAM_STATE::READY;
+@@ -2377,7 +2419,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState()
+ {
+ if (!m_startTime)
+ {
++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100)
++ m_startTime =
++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001;
++#else
+ m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001;
++#endif
+ m_seekStream = i;
+ }
+ return TRANSPORT_STREAM_STATE::READY;
+@@ -2410,7 +2457,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState()
+ {
+ if (!m_startTime)
+ {
++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100)
++ m_startTime =
++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001;
++#else
+ m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001;
++#endif
+ m_seekStream = idx;
+ }
+ return TRANSPORT_STREAM_STATE::READY;
+@@ -2430,7 +2482,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState()
+ {
+ if (!m_startTime)
+ {
++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100)
++ m_startTime =
++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001;
++#else
+ m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001;
++#endif
+ m_seekStream = i;
+ }
+ return TRANSPORT_STREAM_STATE::READY;
+diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp
+index b8494e504e..392853cc68 100644
+--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp
++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp
+@@ -12,6 +12,7 @@
+ #include "addons/addoninfo/AddonType.h"
+ #include "addons/binary-addons/AddonDll.h"
+ #include "addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h"
++#include "cores/FFmpeg.h"
+ #include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h"
+ #include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h"
+ #include "cores/VideoPlayer/Interface/DemuxCrypto.h"
+@@ -392,7 +393,7 @@ KODI_HANDLE CInputStreamAddon::cb_get_stream_transfer(KODI_HANDLE handle,
+ return nullptr;
+
+ std::string codecName(stream->m_codecName);
+- AVCodec* codec = nullptr;
++ FFMPEG_FMT_CONST AVCodec* codec = nullptr;
+
+ if (stream->m_streamType != INPUTSTREAM_TYPE_TELETEXT &&
+ stream->m_streamType != INPUTSTREAM_TYPE_RDS && stream->m_streamType != INPUTSTREAM_TYPE_ID3)
+diff --git a/xbmc/filesystem/AudioBookFileDirectory.cpp b/xbmc/filesystem/AudioBookFileDirectory.cpp
+index 04d1c14343..d82b2a9bbd 100644
+--- a/xbmc/filesystem/AudioBookFileDirectory.cpp
++++ b/xbmc/filesystem/AudioBookFileDirectory.cpp
+@@ -11,6 +11,7 @@
+ #include "TextureDatabase.h"
+ #include "URL.h"
+ #include "Util.h"
++#include "cores/FFmpeg.h"
+ #include "filesystem/File.h"
+ #include "guilib/LocalizeStrings.h"
+ #include "music/tags/MusicInfoTag.h"
+@@ -149,7 +150,7 @@ bool CAudioBookFileDirectory::ContainsFiles(const CURL& url)
+
+ m_ioctx->max_packet_size = 32768;
+
+- AVInputFormat* iformat=nullptr;
++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr;
+ av_probe_input_buffer(m_ioctx, &iformat, url.Get().c_str(), nullptr, 0, 0);
+
+ bool contains = false;
+diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp
+index fa255278b7..9d01a21f38 100644
+--- a/xbmc/guilib/FFmpegImage.cpp
++++ b/xbmc/guilib/FFmpegImage.cpp
+@@ -52,7 +52,7 @@ struct ThumbDataManagement
+ AVFrame* frame_temporary = nullptr;
+ SwsContext* sws = nullptr;
+ AVCodecContext* avOutctx = nullptr;
+- AVCodec* codec = nullptr;
++ FFMPEG_FMT_CONST AVCodec* codec = nullptr;
+ ~ThumbDataManagement()
+ {
+ av_free(intermediateBuffer);
+@@ -198,7 +198,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize)
+ bool is_png = (bufSize > 3 && buffer[1] == 'P' && buffer[2] == 'N' && buffer[3] == 'G');
+ bool is_tiff = (bufSize > 2 && buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*');
+
+- AVInputFormat* inp = nullptr;
++ FFMPEG_FMT_CONST AVInputFormat* inp = nullptr;
+ if (is_jpeg)
+ inp = av_find_input_format("image2");
+ else if (m_strMimeType == "image/apng")
+@@ -236,7 +236,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize)
+ return false;
+ }
+ AVCodecParameters* codec_params = m_fctx->streams[0]->codecpar;
+- AVCodec* codec = avcodec_find_decoder(codec_params->codec_id);
++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(codec_params->codec_id);
+ m_codec_ctx = avcodec_alloc_context3(codec);
+ if (!m_codec_ctx)
+ {
+diff --git a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp
+index 9bb2cdc09b..dbd8893c97 100644
+--- a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp
++++ b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp
+@@ -58,7 +58,7 @@ bool CMusicInfoTagLoaderFFmpeg::Load(const std::string& strFileName, CMusicInfoT
+ if (file.IoControl(IOCTRL_SEEK_POSSIBLE, NULL) != 1)
+ ioctx->seekable = 0;
+
+- AVInputFormat* iformat=NULL;
++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr;
+ av_probe_input_buffer(ioctx, &iformat, strFileName.c_str(), NULL, 0, 0);
+
+ if (avformat_open_input(&fctx, strFileName.c_str(), iformat, NULL) < 0)
+diff --git a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp
+index c1b0495179..5564696be6 100644
+--- a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp
++++ b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp
+@@ -65,7 +65,7 @@ CVideoTagLoaderFFmpeg::CVideoTagLoaderFFmpeg(const CFileItem& item,
+ if (m_file->IoControl(IOCTRL_SEEK_POSSIBLE, nullptr) != 1)
+ m_ioctx->seekable = 0;
+
+- AVInputFormat* iformat = nullptr;
++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr;
+ av_probe_input_buffer(m_ioctx, &iformat, m_item.GetPath().c_str(), nullptr, 0, 0);
+ if (avformat_open_input(&m_fctx, m_item.GetPath().c_str(), iformat, nullptr) < 0)
+ {
+--
+2.35.1
+
+
+From 3de036ef45b0df3368997500d210090a7f6ff5e7 Mon Sep 17 00:00:00 2001
+From: Vasyl Gello <vasek.gello@gmail.com>
+Date: Thu, 13 Oct 2022 04:56:26 +0000
+Subject: [PATCH 2/3] Use Channel Layout API if built against FFmpeg 5.1
+
+Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
+---
+ xbmc/cdrip/EncoderFFmpeg.cpp | 51 +++++++++++++
+ .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 60 ++++++++++++++-
+ .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 22 ++++++
+ .../Engines/ActiveAE/ActiveAEFilter.cpp | 38 +++++++++-
+ .../ActiveAE/ActiveAEResampleFFMPEG.cpp | 55 +++++++++++++-
+ .../Engines/ActiveAE/ActiveAEStream.cpp | 2 +-
+ xbmc/cores/AudioEngine/Utils/AEUtil.cpp | 73 +++++++++++++++++--
+ xbmc/cores/AudioEngine/Utils/AEUtil.h | 9 ++-
+ .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 58 ++++++++++++---
+ .../DVDDemuxers/DVDDemuxClient.cpp | 15 +++-
+ .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 42 +++++++++--
+ 11 files changed, 388 insertions(+), 37 deletions(-)
+
+diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp
+index 4c0628b5cc..c05cdeab9e 100644
+--- a/xbmc/cdrip/EncoderFFmpeg.cpp
++++ b/xbmc/cdrip/EncoderFFmpeg.cpp
+@@ -94,8 +94,14 @@ bool CEncoderFFmpeg::Init()
+
+ /* Set the basic encoder parameters.
+ * The input file's sample rate is used to avoid a sample rate conversion. */
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_codecCtx->ch_layout);
++ av_channel_layout_default(&m_codecCtx->ch_layout, m_iInChannels);
++#else
+ m_codecCtx->channels = m_iInChannels;
+ m_codecCtx->channel_layout = av_get_default_channel_layout(m_iInChannels);
++#endif
+ m_codecCtx->sample_rate = m_iInSampleRate;
+ m_codecCtx->sample_fmt = codec->sample_fmts[0];
+ m_codecCtx->bit_rate = bitrate;
+@@ -140,7 +146,14 @@ bool CEncoderFFmpeg::Init()
+
+ m_bufferFrame->nb_samples = m_codecCtx->frame_size;
+ m_bufferFrame->format = m_inFormat;
++
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_bufferFrame->ch_layout);
++ av_channel_layout_copy(&m_bufferFrame->ch_layout, &m_codecCtx->ch_layout);
++#else
+ m_bufferFrame->channel_layout = m_codecCtx->channel_layout;
++#endif
+ m_bufferFrame->sample_rate = m_codecCtx->sample_rate;
+
+ err = av_frame_get_buffer(m_bufferFrame, 0);
+@@ -152,10 +165,18 @@ bool CEncoderFFmpeg::Init()
+
+ if (m_needConversion)
+ {
++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ int ret = swr_alloc_set_opts2(&m_swrCtx, &m_codecCtx->ch_layout, m_outFormat,
++ m_codecCtx->sample_rate, &m_codecCtx->ch_layout, m_inFormat,
++ m_codecCtx->sample_rate, 0, nullptr);
++ if (ret || swr_init(m_swrCtx) < 0)
++#else
+ m_swrCtx = swr_alloc_set_opts(nullptr, m_codecCtx->channel_layout, m_outFormat,
+ m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat,
+ m_codecCtx->sample_rate, 0, nullptr);
+ if (!m_swrCtx || swr_init(m_swrCtx) < 0)
++#endif
+ throw FFMpegException("Failed to initialize the resampler");
+
+ m_resampledBufferSize =
+@@ -167,7 +188,13 @@ bool CEncoderFFmpeg::Init()
+
+ m_resampledFrame->nb_samples = m_neededFrames;
+ m_resampledFrame->format = m_outFormat;
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_resampledFrame->ch_layout);
++ av_channel_layout_copy(&m_resampledFrame->ch_layout, &m_codecCtx->ch_layout);
++#else
+ m_resampledFrame->channel_layout = m_codecCtx->channel_layout;
++#endif
+ m_resampledFrame->sample_rate = m_codecCtx->sample_rate;
+
+ err = av_frame_get_buffer(m_resampledFrame, 0);
+@@ -203,11 +230,23 @@ bool CEncoderFFmpeg::Init()
+ CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what());
+
+ av_freep(&m_buffer);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_bufferFrame->ch_layout);
++#endif
+ av_frame_free(&m_bufferFrame);
+ swr_free(&m_swrCtx);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_resampledFrame->ch_layout);
++#endif
+ av_frame_free(&m_resampledFrame);
+ av_freep(&m_resampledBuffer);
+ av_free(m_bcBuffer);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_codecCtx->ch_layout);
++#endif
+ avcodec_free_context(&m_codecCtx);
+ if (m_formatCtx)
+ {
+@@ -351,8 +390,16 @@ bool CEncoderFFmpeg::Close()
+
+ /* Flush if needed */
+ av_freep(&m_buffer);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_bufferFrame->ch_layout);
++#endif
+ av_frame_free(&m_bufferFrame);
+ swr_free(&m_swrCtx);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_resampledFrame->ch_layout);
++#endif
+ av_frame_free(&m_resampledFrame);
+ av_freep(&m_resampledBuffer);
+ m_needConversion = false;
+@@ -364,6 +411,10 @@ bool CEncoderFFmpeg::Close()
+
+ /* cleanup */
+ av_free(m_bcBuffer);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_codecCtx->ch_layout);
++#endif
+ avcodec_free_context(&m_codecCtx);
+ av_freep(&m_formatCtx->pb);
+ avformat_free_context(m_formatCtx);
+diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
+index 86f65f57f3..5d8ca71de1 100644
+--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp
+@@ -37,6 +37,10 @@ CAEEncoderFFmpeg::~CAEEncoderFFmpeg()
+ {
+ Reset();
+ swr_free(&m_SwrCtx);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_CodecCtx->ch_layout);
++#endif
+ avcodec_free_context(&m_CodecCtx);
+ }
+
+@@ -113,7 +117,13 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input
+
+ m_CodecCtx->bit_rate = m_BitRate;
+ m_CodecCtx->sample_rate = format.m_sampleRate;
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_CodecCtx->ch_layout);
++ av_channel_layout_from_mask(&m_CodecCtx->ch_layout, AV_CH_LAYOUT_5POINT1_BACK);
++#else
+ m_CodecCtx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
++#endif
+
+ /* select a suitable data format */
+ if (codec->sample_fmts)
+@@ -190,22 +200,44 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input
+ LOGERROR,
+ "CAEEncoderFFmpeg::Initialize - Unable to find a suitable data format for the codec ({})",
+ m_CodecName);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_CodecCtx->ch_layout);
++#endif
+ avcodec_free_context(&m_CodecCtx);
+ return false;
+ }
+ }
+
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ uint64_t mask = m_CodecCtx->ch_layout.u.mask;
++ av_channel_layout_uninit(&m_CodecCtx->ch_layout);
++ av_channel_layout_from_mask(&m_CodecCtx->ch_layout, mask);
++ m_CodecCtx->ch_layout.nb_channels = BuildChannelLayout(mask, m_Layout);
++#else
+ m_CodecCtx->channels = BuildChannelLayout(m_CodecCtx->channel_layout, m_Layout);
++#endif
+
+ /* open the codec */
+ if (avcodec_open2(m_CodecCtx, codec, NULL))
+ {
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_CodecCtx->ch_layout);
++#endif
+ avcodec_free_context(&m_CodecCtx);
+ return false;
+ }
+
+ format.m_frames = m_CodecCtx->frame_size;
+- format.m_frameSize = m_CodecCtx->channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ int channels = m_CodecCtx->ch_layout.nb_channels;
++#else
++ int channels = m_CodecCtx->channels;
++#endif
++ format.m_frameSize = channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
+ format.m_channelLayout = m_Layout;
+
+ m_CurrentFormat = format;
+@@ -215,14 +247,26 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input
+
+ if (m_NeedConversion)
+ {
++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ int ret = swr_alloc_set_opts2(&m_SwrCtx, &m_CodecCtx->ch_layout, m_CodecCtx->sample_fmt,
++ m_CodecCtx->sample_rate, &m_CodecCtx->ch_layout,
++ AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, 0, NULL);
++ if (ret || swr_init(m_SwrCtx) < 0)
++#else
+ m_SwrCtx = swr_alloc_set_opts(NULL,
+ m_CodecCtx->channel_layout, m_CodecCtx->sample_fmt, m_CodecCtx->sample_rate,
+ m_CodecCtx->channel_layout, AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate,
+ 0, NULL);
+ if (!m_SwrCtx || swr_init(m_SwrCtx) < 0)
++#endif
+ {
+ CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Initialize - Failed to initialise resampler.");
+ swr_free(&m_SwrCtx);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_CodecCtx->ch_layout);
++#endif
+ avcodec_free_context(&m_CodecCtx);
+ return false;
+ }
+@@ -276,10 +320,18 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz
+
+ frame->nb_samples = m_CodecCtx->frame_size;
+ frame->format = m_CodecCtx->sample_fmt;
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&frame->ch_layout);
++ av_channel_layout_copy(&frame->ch_layout, &m_CodecCtx->ch_layout);
++ int channelNum = m_CodecCtx->ch_layout.nb_channels;
++#else
+ frame->channel_layout = m_CodecCtx->channel_layout;
+ frame->channels = m_CodecCtx->channels;
++ int channelNum = m_CodecCtx->channels;
++#endif
+
+- avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0);
++ avcodec_fill_audio_frame(frame, channelNum, m_CodecCtx->sample_fmt, in, in_size, 0);
+
+ pkt->size = out_size;
+ pkt->data = out;
+@@ -295,6 +347,10 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz
+ err = avcodec_receive_packet(m_CodecCtx, pkt);
+ if (err == AVERROR(EAGAIN) || err == AVERROR_EOF)
+ {
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&frame->ch_layout);
++#endif
+ av_frame_free(&frame);
+ av_packet_free(&pkt);
+ return (err == AVERROR(EAGAIN)) ? -1 : 0;
+diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+index 6000fe9c63..9cd3bddda8 100644
+--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+@@ -3069,8 +3069,14 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file)
+ AVCodecID codecId = fmt_ctx->streams[0]->codecpar->codec_id;
+ dec = avcodec_find_decoder(codecId);
+ config.sample_rate = fmt_ctx->streams[0]->codecpar->sample_rate;
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ config.channels = fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels;
++ config.channel_layout = fmt_ctx->streams[0]->codecpar->ch_layout.u.mask;
++#else
+ config.channels = fmt_ctx->streams[0]->codecpar->channels;
+ config.channel_layout = fmt_ctx->streams[0]->codecpar->channel_layout;
++#endif
+ }
+ }
+ if (dec == nullptr)
+@@ -3086,10 +3092,22 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file)
+
+ dec_ctx = avcodec_alloc_context3(dec);
+ dec_ctx->sample_rate = config.sample_rate;
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ AVChannelLayout layout = {};
++ if (!config.channel_layout)
++ av_channel_layout_default(&layout, config.channels);
++ else
++ av_channel_layout_from_mask(&layout, config.channel_layout);
++ config.channel_layout = layout.u.mask;
++ av_channel_layout_copy(&dec_ctx->ch_layout, &layout);
++ av_channel_layout_uninit(&layout);
++#else
+ dec_ctx->channels = config.channels;
+ if (!config.channel_layout)
+ config.channel_layout = av_get_default_channel_layout(config.channels);
+ dec_ctx->channel_layout = config.channel_layout;
++#endif
+
+ AVPacket* avpkt = av_packet_alloc();
+ if (!avpkt)
+@@ -3156,6 +3174,10 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file)
+
+ av_packet_free(&avpkt);
+ av_frame_free(&decoded_frame);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&dec_ctx->ch_layout);
++#endif
+ avcodec_free_context(&dec_ctx);
+ avformat_close_input(&fmt_ctx);
+ if (io_ctx)
+diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp
+index 26b669a2cf..1d79dc6db4 100644
+--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp
++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp
+@@ -12,10 +12,11 @@
+ #include <algorithm>
+
+ extern "C" {
+-#include <libavfilter/avfilter.h>
+ #include <libavcodec/avcodec.h>
++#include <libavfilter/avfilter.h>
+ #include <libavfilter/buffersink.h>
+ #include <libavfilter/buffersrc.h>
++#include <libavutil/version.h>
+ #include <libswresample/swresample.h>
+ }
+
+@@ -171,7 +172,13 @@ void CActiveAEFilter::CloseFilter()
+ }
+
+ if (m_pOutFrame)
++ {
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_pOutFrame->ch_layout);
++#endif
+ av_frame_free(&m_pOutFrame);
++ }
+
+ if (m_pConvertFrame)
+ av_frame_free(&m_pConvertFrame);
+@@ -205,10 +212,17 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_
+ if (!frame)
+ return -1;
+
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&frame->ch_layout);
++ av_channel_layout_from_mask(&frame->ch_layout, m_channelLayout);
++ int channels = frame->ch_layout.nb_channels;
++#else
+ int channels = av_get_channel_layout_nb_channels(m_channelLayout);
+
+ frame->channel_layout = m_channelLayout;
+ frame->channels = channels;
++#endif
+ frame->sample_rate = m_sampleRate;
+ frame->nb_samples = src_samples;
+ frame->format = m_sampleFormat;
+@@ -224,6 +238,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_
+ src_buffer[0], src_bufsize, 16);
+ if (result < 0)
+ {
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&frame->ch_layout);
++#endif
+ av_frame_free(&frame);
+ CLog::Log(LOGERROR, "CActiveAEFilter::ProcessFilter - avcodec_fill_audio_frame failed");
+ m_filterEof = true;
+@@ -231,6 +249,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_
+ }
+
+ result = av_buffersrc_write_frame(m_pFilterCtxIn, frame);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&frame->ch_layout);
++#endif
+ av_frame_free(&frame);
+ if (result < 0)
+ {
+@@ -284,7 +306,13 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_
+ {
+ av_frame_unref(m_pOutFrame);
+ m_pOutFrame->format = m_sampleFormat;
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_pOutFrame->ch_layout);
++ av_channel_layout_from_mask(&m_pOutFrame->ch_layout, m_channelLayout);
++#else
+ m_pOutFrame->channel_layout = m_channelLayout;
++#endif
+ m_pOutFrame->sample_rate = m_sampleRate;
+ result = swr_convert_frame(m_pConvertCtx, m_pOutFrame, m_pConvertFrame);
+ av_frame_unref(m_pConvertFrame);
+@@ -302,7 +330,15 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_
+
+ if (m_hasData)
+ {
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ AVChannelLayout layout = {};
++ av_channel_layout_from_mask(&layout, m_channelLayout);
++ int channels = layout.nb_channels;
++ av_channel_layout_uninit(&layout);
++#else
+ int channels = av_get_channel_layout_nb_channels(m_channelLayout);
++#endif
+ int planes = av_sample_fmt_is_planar(m_sampleFormat) ? channels : 1;
+ int samples = std::min(dst_samples, m_pOutFrame->nb_samples - m_sampleOffset);
+ int bytes = samples * av_get_bytes_per_sample(m_sampleFormat) * channels / planes;
+diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
+index bfef837114..379dfe6446 100644
+--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp
+@@ -11,8 +11,10 @@
+ #include "utils/log.h"
+
+ extern "C" {
++#include <libavcodec/version.h>
+ #include <libavutil/channel_layout.h>
+ #include <libavutil/opt.h>
++#include <libavutil/version.h>
+ #include <libswresample/swresample.h>
+ }
+
+@@ -49,15 +51,49 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi
+ m_doesResample = true;
+
+ if (m_dst_chan_layout == 0)
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ {
++ AVChannelLayout layout = {};
++ av_channel_layout_default(&layout, m_dst_channels);
++ m_dst_chan_layout = layout.u.mask;
++ av_channel_layout_uninit(&layout);
++ }
++#else
+ m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels);
++#endif
+ if (m_src_chan_layout == 0)
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ {
++ AVChannelLayout layout = {};
++ av_channel_layout_default(&layout, m_src_channels);
++ m_src_chan_layout = layout.u.mask;
++ av_channel_layout_uninit(&layout);
++ }
++#else
+ m_src_chan_layout = av_get_default_channel_layout(m_src_channels);
++#endif
++
++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ AVChannelLayout dstChLayout = {};
++ AVChannelLayout srcChLayout = {};
+
++ av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout);
++ av_channel_layout_from_mask(&srcChLayout, m_src_chan_layout);
++
++ int ret = swr_alloc_set_opts2(&m_pContext, &dstChLayout, m_dst_fmt, m_dst_rate, &srcChLayout,
++ m_src_fmt, m_src_rate, 0, NULL);
++
++ if (ret)
++#else
+ m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, m_dst_fmt, m_dst_rate,
+ m_src_chan_layout, m_src_fmt, m_src_rate,
+ 0, NULL);
+
+ if (!m_pContext)
++#endif
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - create context failed");
+ return false;
+@@ -126,10 +162,20 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi
+ else if (upmix && m_src_channels == 2 && m_dst_channels > 2)
+ {
+ memset(m_rematrix, 0, sizeof(m_rematrix));
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&dstChLayout);
++ av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout);
++#endif
+ for (int out=0; out<m_dst_channels; out++)
+ {
+- uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out);
+- switch(out_chan)
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ AVChannel outChan = av_channel_layout_channel_from_index(&dstChLayout, out);
++#else
++ uint64_t outChan = av_channel_layout_extract_channel(m_dst_chan_layout, out);
++#endif
++ switch (outChan)
+ {
+ case AV_CH_FRONT_LEFT:
+ case AV_CH_BACK_LEFT:
+@@ -154,6 +200,11 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi
+ }
+ }
+
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&dstChLayout);
++#endif
++
+ if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
+ {
+ CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - setting channel matrix failed");
+diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
+index 858b0f2f22..a52ac2829f 100644
+--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
+@@ -88,7 +88,7 @@ void CActiveAEStream::InitRemapper()
+ for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
+ {
+ avLast = avCur;
+- avCur = CAEUtil::GetAVChannel(m_format.m_channelLayout[i]);
++ avCur = CAEUtil::GetAVChannelMask(m_format.m_channelLayout[i]);
+ if(avCur < avLast)
+ {
+ needRemap = true;
+diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp
+index bfa2cf9e4c..98f82816ef 100644
+--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp
++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp
+@@ -19,10 +19,6 @@
+ #include <xmmintrin.h>
+ #endif
+
+-extern "C" {
+-#include <libavutil/channel_layout.h>
+-}
+-
+ void AEDelayStatus::SetDelay(double d)
+ {
+ delay = d;
+@@ -550,8 +546,15 @@ AVSampleFormat CAEUtil::GetAVSampleFormat(AEDataFormat format)
+ }
+ }
+
+-uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel)
++uint64_t CAEUtil::GetAVChannelMask(enum AEChannel aechannel)
+ {
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ enum AVChannel ch = GetAVChannel(aechannel);
++ if (ch == AV_CHAN_NONE)
++ return 0;
++ return (1ULL << ch);
++#else
+ switch (aechannel)
+ {
+ case AE_CH_FL: return AV_CH_FRONT_LEFT;
+@@ -575,9 +578,67 @@ uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel)
+ default:
+ return 0;
+ }
++#endif
+ }
+
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++enum AVChannel CAEUtil::GetAVChannel(enum AEChannel aechannel)
++{
++ switch (aechannel)
++ {
++ case AE_CH_FL:
++ return AV_CHAN_FRONT_LEFT;
++ case AE_CH_FR:
++ return AV_CHAN_FRONT_RIGHT;
++ case AE_CH_FC:
++ return AV_CHAN_FRONT_CENTER;
++ case AE_CH_LFE:
++ return AV_CHAN_LOW_FREQUENCY;
++ case AE_CH_BL:
++ return AV_CHAN_BACK_LEFT;
++ case AE_CH_BR:
++ return AV_CHAN_BACK_RIGHT;
++ case AE_CH_FLOC:
++ return AV_CHAN_FRONT_LEFT_OF_CENTER;
++ case AE_CH_FROC:
++ return AV_CHAN_FRONT_RIGHT_OF_CENTER;
++ case AE_CH_BC:
++ return AV_CHAN_BACK_CENTER;
++ case AE_CH_SL:
++ return AV_CHAN_SIDE_LEFT;
++ case AE_CH_SR:
++ return AV_CHAN_SIDE_RIGHT;
++ case AE_CH_TC:
++ return AV_CHAN_TOP_CENTER;
++ case AE_CH_TFL:
++ return AV_CHAN_TOP_FRONT_LEFT;
++ case AE_CH_TFC:
++ return AV_CHAN_TOP_FRONT_CENTER;
++ case AE_CH_TFR:
++ return AV_CHAN_TOP_FRONT_RIGHT;
++ case AE_CH_TBL:
++ return AV_CHAN_TOP_BACK_LEFT;
++ case AE_CH_TBC:
++ return AV_CHAN_TOP_BACK_CENTER;
++ case AE_CH_TBR:
++ return AV_CHAN_TOP_BACK_RIGHT;
++ default:
++ return AV_CHAN_NONE;
++ }
++}
++#endif
++
+ int CAEUtil::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout)
+ {
+- return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel));
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ AVChannelLayout ch_layout = {};
++ av_channel_layout_from_mask(&ch_layout, layout);
++ int idx = av_channel_layout_index_from_channel(&ch_layout, GetAVChannel(aechannel));
++ av_channel_layout_uninit(&ch_layout);
++ return idx;
++#else
++ return av_get_channel_layout_channel_index(layout, GetAVChannelMask(aechannel));
++#endif
+ }
+diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h
+index 034e115ee8..8acbeec442 100644
+--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h
++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h
+@@ -13,7 +13,10 @@
+ #include <math.h>
+
+ extern "C" {
++#include <libavcodec/version.h>
++#include <libavutil/channel_layout.h>
+ #include <libavutil/samplefmt.h>
++#include <libavutil/version.h>
+ }
+
+ // AV sync options
+@@ -171,6 +174,10 @@ public:
+ static uint64_t GetAVChannelLayout(const CAEChannelInfo &info);
+ static CAEChannelInfo GetAEChannelLayout(uint64_t layout);
+ static AVSampleFormat GetAVSampleFormat(AEDataFormat format);
+- static uint64_t GetAVChannel(enum AEChannel aechannel);
++ static uint64_t GetAVChannelMask(enum AEChannel aechannel);
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ static enum AVChannel GetAVChannel(enum AEChannel aechannel);
++#endif
+ static int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout);
+ };
+diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
+index 87e7ae2c57..44dcb32620 100644
+--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
+@@ -78,7 +78,14 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
+
+ m_matrixEncoding = AV_MATRIX_ENCODING_NONE;
+ m_channels = 0;
++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \
++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100)
++ av_channel_layout_uninit(&m_pCodecContext->ch_lay