From ac96279a5db8f179d4149cc83fb7f368d7bf2b86 Mon Sep 17 00:00:00 2001 From: Ian Leonard Date: Sat, 30 Nov 2019 21:40:56 +0000 Subject: [PATCH 1/8] steamlink-png: shared libpng for steamlink Signed-off-by: Ian Leonard --- .../steamlink-libpng/package.mk | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk new file mode 100644 index 00000000000..101347a9dfe --- /dev/null +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +. $(get_pkg_directory libpng)/package.mk + +PKG_NAME="steamlink-libpng" +PKG_LONGDESC="libpng for steamlink-rpi" +PKG_URL="" +PKG_DEPENDS_TARGET+=" libpng" + +PKG_CONFIGURE_OPTS_TARGET+=" --disable-static \ + --enable-shared" + +unpack() { + mkdir -p ${PKG_BUILD} + tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.xz -C ${PKG_BUILD} +} + +makeinstall_target() { + : +} + +post_makeinstall_target() { + : +} From f5caac822abd3ab37da5ce7220a28fcaad41ac3e Mon Sep 17 00:00:00 2001 From: Ian Leonard Date: Sat, 30 Nov 2019 21:45:52 +0000 Subject: [PATCH 2/8] steamlink-libjpeg-turbo: build shared libjpeg-turbo for steamlink Signed-off-by: Ian Leonard --- .../steamlink-libjpeg-turbo/package.mk | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk new file mode 100644 index 00000000000..d01a82f2691 --- /dev/null +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +. $(get_pkg_directory libjpeg-turbo)/package.mk + +PKG_NAME="steamlink-libjpeg-turbo" +PKG_LONGDESC="libjpeg-turbo for steamlink" +PKG_URL="" +PKG_DEPENDS_UNPACK+=" libjpeg-turbo" + +PKG_CMAKE_OPTS_TARGET+=" -DENABLE_STATIC=OFF \ + -DENABLE_SHARED=ON \ + -DWITH_JPEG8=OFF" + +unpack() { + mkdir -p ${PKG_BUILD} + tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.gz -C ${PKG_BUILD} +} + +makeinstall_target() { + : +} + +post_makeinstall_target() { + : +} From ff767ee4ac37e88d440f738bd6be735774d19221 Mon Sep 17 00:00:00 2001 From: Ian Leonard Date: Mon, 2 Dec 2019 05:57:19 +0000 Subject: [PATCH 3/8] steamlink-libXext: add package Signed-off-by: Ian Leonard --- .../steamlink-libXext/package.mk | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk new file mode 100644 index 00000000000..585cf84cbd5 --- /dev/null +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +. $(get_pkg_directory libXext)/package.mk + +PKG_NAME="steamlink-libXext" +PKG_LONGDESC="libXext for steamlink-rpi" +PKG_URL="" +PKG_DEPENDS_TARGET+=" libXext" + +unpack() { + mkdir -p ${PKG_BUILD} + tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.bz2 -C ${PKG_BUILD} +} + +makeinstall_target() { + : +} From 3dc924445fed5b92b17b06bbf3df2e674df48f0c Mon Sep 17 00:00:00 2001 From: Ian Leonard Date: Mon, 2 Dec 2019 06:11:54 +0000 Subject: [PATCH 4/8] steamlink-libX11: add package Signed-off-by: Ian Leonard --- .../steamlink-libX11/package.mk | 18 ++++++++++++++++++ .../patches/libX11-disable_nls_tests.patch | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk create mode 100644 packages/addons/addon-depends/steamlink-depends/steamlink-libX11/patches/libX11-disable_nls_tests.patch diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk new file mode 100644 index 00000000000..2cc45f2b669 --- /dev/null +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +. $(get_pkg_directory libX11)/package.mk + +PKG_NAME="steamlink-libX11" +PKG_LONGDESC="libX11 for steamlink-rpi" +PKG_URL="" +PKG_DEPENDS_TARGET+=" libX11" + +unpack() { + mkdir -p ${PKG_BUILD} + tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.bz2 -C ${PKG_BUILD} +} + +makeinstall-target() { + : +} diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/patches/libX11-disable_nls_tests.patch b/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/patches/libX11-disable_nls_tests.patch new file mode 100644 index 00000000000..3afa79a753f --- /dev/null +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/patches/libX11-disable_nls_tests.patch @@ -0,0 +1,18 @@ +diff -Naur libX11-1.6.0/nls/Makefile.am libX11-1.6.0.patch/nls/Makefile.am +--- libX11-1.6.0/nls/Makefile.am 2013-06-04 04:21:16.000000000 +0200 ++++ libX11-1.6.0.patch/nls/Makefile.am 2013-06-04 17:07:11.962522739 +0200 +@@ -36,10 +36,10 @@ + < locale.dir.l1 > locale.dir.l2 + cat locale.dir.l2 locale.dir.l1 > locale.dir + +-if HAVE_PERL +-LOG_COMPILER = $(PERL) +-TESTS = compose-check.pl +-endif HAVE_PERL ++# if HAVE_PERL ++# LOG_COMPILER = $(PERL) ++# TESTS = compose-check.pl ++# endif HAVE_PERL + + + # Per-locale data files From 4d78ed461e32c02598b9025fdb5e7e4c419a2850 Mon Sep 17 00:00:00 2001 From: Ian Leonard Date: Sat, 30 Nov 2019 20:24:58 +0000 Subject: [PATCH 5/8] steamlink-rpi: add package as addon Icon artwork provided by chewitt. Signed-off-by: Ian Leonard --- .../addons/script/steamlink-rpi/changelog.txt | 2 + .../addons/script/steamlink-rpi/icon/icon.png | Bin 0 -> 23579 bytes .../addons/script/steamlink-rpi/package.mk | 52 ++++++++ .../source/bin/steamlink-start.sh | 41 +++++++ .../script/steamlink-rpi/source/default.py | 116 ++++++++++++++++++ .../system.d/steamlink-rpi.watchdog.service | 11 ++ 6 files changed, 222 insertions(+) create mode 100644 packages/addons/script/steamlink-rpi/changelog.txt create mode 100644 packages/addons/script/steamlink-rpi/icon/icon.png create mode 100644 packages/addons/script/steamlink-rpi/package.mk create mode 100755 packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh create mode 100644 packages/addons/script/steamlink-rpi/source/default.py create mode 100644 packages/addons/script/steamlink-rpi/source/system.d/steamlink-rpi.watchdog.service diff --git a/packages/addons/script/steamlink-rpi/changelog.txt b/packages/addons/script/steamlink-rpi/changelog.txt new file mode 100644 index 00000000000..ed5784c55b0 --- /dev/null +++ b/packages/addons/script/steamlink-rpi/changelog.txt @@ -0,0 +1,2 @@ +100 +- Initial Release diff --git a/packages/addons/script/steamlink-rpi/icon/icon.png b/packages/addons/script/steamlink-rpi/icon/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..649937176bbcbed30e891d4df49c91796e9fa472 GIT binary patch literal 23579 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 W^3s=q+k*e?;+dMZYN^T_|NjSq8pk^T literal 0 HcmV?d00001 diff --git a/packages/addons/script/steamlink-rpi/package.mk b/packages/addons/script/steamlink-rpi/package.mk new file mode 100644 index 00000000000..0a29ef18bde --- /dev/null +++ b/packages/addons/script/steamlink-rpi/package.mk @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +PKG_NAME="steamlink-rpi" +PKG_VERSION="1.0" +PKG_REV="100" +PKG_ARCH="arm" +PKG_ADDON_PROJECTS="RPi2" +PKG_LICENSE="custom" +PKG_SITE="https://support.steampowered.com/kb_article.php?ref=6153-IFGH-6589" +PKG_DEPENDS_TARGET="toolchain steamlink-libjpeg-turbo steamlink-libpng steamlink-libXext steamlink-libX11" +PKG_SECTION="script" +PKG_SHORTDESC="Steam Link App for Raspberry Pi" +PKG_LONGDESC="Installs the Steam Link App for Raspberry Pi 3 or newer from Valve for use in streaming from Steam clients. Addon is not associated with Valve. Steam and the Steam logo are trademarks and/or registered trademarks of Valve Corporation in the U.S. and/or other countries." +PKG_TOOLCHAIN="manual" + +PKG_IS_ADDON="yes" +PKG_ADDON_NAME="steamlink-rpi" +PKG_ADDON_TYPE="xbmc.python.script" +PKG_ADDON_PROVIDES="executable" + +PKG_STEAMLINK_VERSION="1.1.64.162" +PKG_STEAMLINK_HASH="1ea1c41802bd6cc3efdba7ba258b9d25d5c07cdd1d0ffe9f2d47597588a09155" + +make_target() { + : +} + +addon() { + # Add needed libraries + mkdir -p ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs + + # libpng + cp -L $(get_build_dir steamlink-libpng)/.${TARGET_NAME}/.libs/libpng16.so.16 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + + # libjpeg-turbo + cp -L $(get_build_dir steamlink-libjpeg-turbo)/.${TARGET_NAME}/libjpeg.so.62 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + + # libXext + cp -L $(get_build_dir steamlink-libXext)/.${TARGET_NAME}/src/.libs/libXext.so.6 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + + # libX11 + cp -L $(get_build_dir steamlink-libX11)/.${TARGET_NAME}/src/.libs/libX11.so.6 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + cp -L $(get_build_dir steamlink-libX11)/.${TARGET_NAME}/src/.libs/libX11-xcb.so.1 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ +} + +post_install_addon() { + # Add steamlink version to download to addon + sed -e "s/@STEAMLINK_VERSION@/${PKG_STEAMLINK_VERSION}/" \ + -e "s/@STEAMLINK_HASH@/${PKG_STEAMLINK_HASH}/" \ + -i ${ADDON_BUILD}/${PKG_ADDON_ID}/default.py +} diff --git a/packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh b/packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh new file mode 100755 index 00000000000..d72625faa1a --- /dev/null +++ b/packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +. /etc/profile +oe_setup_addon script.steamlink-rpi + +# Steamlink not ready; abort +if [ ! -f ${ADDON_DIR}/prep.ok ]; then + if [ -f /tmp/steamlink.watchdog ]; then + rm /tmp/steamlink.watchdog + fi + exit 0 +fi + +# Adapt to meet steamlink requirements + +# mount an overlay for udev rules and reload udev rules +if [ $(grep -c "/lib/udev/rules.d" /proc/mounts) -eq 0 ]; then + if [ ! -d ${ADDON_DIR}/steamlink/.overlay ]; then + mkdir -p ${ADDON_DIR}/steamlink/.overlay + fi + mount -t overlay overlay -o lowerdir=/lib/udev/rules.d,upperdir=${ADDON_DIR}/steamlink/udev/rules.d/,workdir=${ADDON_DIR}/steamlink/.overlay /lib/udev/rules.d + udevadm trigger +fi + +# Launch steamlink +# xxx: shutdown kodi or controller input goes to kodi too +systemctl stop kodi +# xxx: shutdown pulseaudio or no sound +systemctl stop pulseaudio +${ADDON_DIR}/steamlink/steamlink.sh +sleep 2 +# Cleanup +umount /lib/udev/rules.d +rm /tmp/steamlink.watchdog +systemctl start pulseaudio +systemctl start kodi + +exit 0 diff --git a/packages/addons/script/steamlink-rpi/source/default.py b/packages/addons/script/steamlink-rpi/source/default.py new file mode 100644 index 00000000000..18883b3d4ee --- /dev/null +++ b/packages/addons/script/steamlink-rpi/source/default.py @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +import os +import tarfile +import subprocess +import xbmcaddon +import xbmcgui +from hashlib import sha256 +from pathlib import Path +from tempfile import TemporaryDirectory +from shutil import rmtree +from sys import exit +from urllib.request import urlretrieve + + +STEAMLINK_VERSION = "@STEAMLINK_VERSION@" +STEAMLINK_HASH = "@STEAMLINK_HASH@" +STEAMLINK_TARBALL_NAME = f"steamlink-rpi3-{STEAMLINK_VERSION}.tar.gz" +STEAMLINK_URL = f"http://media.steampowered.com/steamlink/rpi/{STEAMLINK_TARBALL_NAME}" +ADDON_DIR = xbmcaddon.Addon().getAddonInfo("path") + + +def GetSHA256Hash(file_name): + """ Get sha256sum of file_name in 8kb chunks """ + with open(file_name,"rb") as file: + SHA256HASH = sha256() + while True: + data_block = file.read(8192) + if not data_block: + break + SHA256HASH.update(data_block) + return SHA256HASH.hexdigest() + +def GetRPiProcessor(): + """ Use vcgencmd to obtain cpu identifier as int """ + VC_CMD_OUTPUT=subprocess.check_output(["vcgencmd", "otp_dump"], encoding="utf-8") + + for line in VC_CMD_OUTPUT.splitlines(): + if line[0:3] == "30:": + PROCESSOR=line.split(":")[1] # entire processor id + return int(PROCESSOR[4:5]) # only cpu id + + return 0 + +def OutputFileContents(file): + """ Read everything in file """ + with open(file) as data: + return data.read() + +def DownloadSteamlink(): + """ Download Steam Link for RPi """ + with TemporaryDirectory() as temp_dir: + STEAMLINK_TEMP_PATH = os.path.join(temp_dir, STEAMLINK_TARBALL_NAME) + + xbmcgui.Dialog().notification("Steam Link", "Downloading Steam Link (about 60MiB)", xbmcgui.NOTIFICATION_INFO, 5000) + urlretrieve(STEAMLINK_URL, STEAMLINK_TEMP_PATH) + if tarfile.is_tarfile(STEAMLINK_TEMP_PATH): + DOWNLOAD_HASH = GetSHA256Hash(STEAMLINK_TEMP_PATH) + if STEAMLINK_HASH == DOWNLOAD_HASH: + xbmcgui.Dialog().notification("Steam Link", "Download complete, extracting...", xbmcgui.NOTIFICATION_INFO, 5000) + STEAMLINK_TARBALL = tarfile.open(STEAMLINK_TEMP_PATH) + STEAMLINK_TARBALL.extractall(path=f"{ADDON_DIR}/") + else: + xbmcgui.Dialog().notification("Steam Link", "Download error: bad file hash, try again later", xbmcgui.NOTIFICATION_INFO, 5000) + exit(1) + else: + xbmcgui.Dialog().notification("Steam Link", "Download error: bad download or missing file", xbmcgui.NOTIFICATION_INFO, 5000) + exit(1) + +def PrepareSteamlink(): + """ System preparation before launching Steam Link """ + + # Disable Steam Link's cpu check + if not os.path.isfile(f"{ADDON_DIR}/steamlink/.ignore_cpuinfo"): + Path(f"{ADDON_DIR}/steamlink/.ignore_cpuinfo").touch() + + # Add system libraries to bundled + for file in os.listdir(f"{ADDON_DIR}/system-libs/"): + os.symlink(f"{ADDON_DIR}/system-libs/{file}", f"{ADDON_DIR}/steamlink/lib/{file}") + + # systemd setup + if not os.path.isfile(f"{str(Path.home())}/.config/system.d/steamlink-rpi.watchdog.service"): + os.symlink(f"{ADDON_DIR}/system.d/steamlink-rpi.watchdog.service", f"{str(Path.home())}/.config/system.d/steamlink-rpi.watchdog.service") + subprocess.run(["systemctl", "enable", f"{str(Path.home())}/.config/system.d/steamlink-rpi.watchdog.service"]) + + # Finalize + Path(f"{ADDON_DIR}/prep.ok").touch() + +def StartSteamlink(): + # Check if running on RPi3 or higher + if not os.path.isfile(f"{ADDON_DIR}/steamlink/.ignore_cpuinfo") and GetRPiProcessor() < 2: + xbmcgui.Dialog.notification("Steam Link", "Steam Link will not run on this hardware. Aborting...", xbmcgui.NOTIFICATION_INFO, 5000) + exit(1) + + # Check if addon wants to update Steam Link + if os.path.isfile(f"{ADDON_DIR}/steamlink/version.txt"): + STEAMLINK_INSTALLED_VERSION = OutputFileContents(f"{ADDON_DIR}/steamlink/version.txt").rstrip() + + # Update Steamlink handling + if STEAMLINK_VERSION != STEAMLINK_INSTALLED_VERSION: + rmtree(f"{ADDON_DIR}/steamlink/") + os.remove(f"{ADDON_DIR}/prep.ok") + + # Download Steam Link if not present + if not os.path.isfile(f"{ADDON_DIR}/prep.ok"): + DownloadSteamlink() + PrepareSteamlink() + + # Start Steamlink + xbmcgui.Dialog().notification("Steam Link", "Starting Steam Link", xbmcgui.NOTIFICATION_INFO, 3000) + Path("/tmp/steamlink.watchdog").touch() + subprocess.run(["systemctl", "start", "steamlink-rpi.watchdog.service"]) + + +StartSteamlink() diff --git a/packages/addons/script/steamlink-rpi/source/system.d/steamlink-rpi.watchdog.service b/packages/addons/script/steamlink-rpi/source/system.d/steamlink-rpi.watchdog.service new file mode 100644 index 00000000000..3a52b1b4156 --- /dev/null +++ b/packages/addons/script/steamlink-rpi/source/system.d/steamlink-rpi.watchdog.service @@ -0,0 +1,11 @@ +[Unit] +Description="Watchdog to start Steamlink" +After=graphical.target +ConditionPathExists=/tmp/steamlink.watchdog + +[Service] +Type=oneshot +ExecStart=/storage/.kodi/addons/script.steamlink-rpi/bin/steamlink-start.sh + +[Install] +WantedBy=graphical.target From 3a29d89983be55a5afc42747338e83bb1a0e19c4 Mon Sep 17 00:00:00 2001 From: Ian Leonard Date: Tue, 12 May 2020 23:25:15 +0000 Subject: [PATCH 6/8] steamlink-rpi: use integrated audio if no sound card configured Signed-off-by: Ian Leonard --- .../script/steamlink-rpi/source/bin/steamlink-start.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh b/packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh index d72625faa1a..ffdc72a5e06 100755 --- a/packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh +++ b/packages/addons/script/steamlink-rpi/source/bin/steamlink-start.sh @@ -25,6 +25,11 @@ if [ $(grep -c "/lib/udev/rules.d" /proc/mounts) -eq 0 ]; then udevadm trigger fi +# use alsa for steamlink; make sure a sound card is present +if [ ! -d /proc/asound ]; then + dtparam audio=on +fi + # Launch steamlink # xxx: shutdown kodi or controller input goes to kodi too systemctl stop kodi From 77af3eb84fdf592be11aa25b35c23f245f3091b8 Mon Sep 17 00:00:00 2001 From: MilhouseVH Date: Sun, 8 Mar 2020 15:45:17 +0000 Subject: [PATCH 7/8] steamlink-rpi: add autoremove fixes --- .../steamlink-depends/steamlink-libX11/package.mk | 5 +---- .../steamlink-depends/steamlink-libXext/package.mk | 5 +---- .../steamlink-libjpeg-turbo/package.mk | 9 +-------- .../steamlink-depends/steamlink-libpng/package.mk | 5 +---- packages/addons/script/steamlink-rpi/package.mk | 14 +++++--------- 5 files changed, 9 insertions(+), 29 deletions(-) diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk index 2cc45f2b669..e779ed63530 100644 --- a/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libX11/package.mk @@ -7,12 +7,9 @@ PKG_NAME="steamlink-libX11" PKG_LONGDESC="libX11 for steamlink-rpi" PKG_URL="" PKG_DEPENDS_TARGET+=" libX11" +PKG_BUILD_FLAGS+=" -sysroot" unpack() { mkdir -p ${PKG_BUILD} tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.bz2 -C ${PKG_BUILD} } - -makeinstall-target() { - : -} diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk index 585cf84cbd5..c67f02754a2 100644 --- a/packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libXext/package.mk @@ -7,12 +7,9 @@ PKG_NAME="steamlink-libXext" PKG_LONGDESC="libXext for steamlink-rpi" PKG_URL="" PKG_DEPENDS_TARGET+=" libXext" +PKG_BUILD_FLAGS+=" -sysroot" unpack() { mkdir -p ${PKG_BUILD} tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.bz2 -C ${PKG_BUILD} } - -makeinstall_target() { - : -} diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk index d01a82f2691..cbb9b8cdec9 100644 --- a/packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libjpeg-turbo/package.mk @@ -7,6 +7,7 @@ PKG_NAME="steamlink-libjpeg-turbo" PKG_LONGDESC="libjpeg-turbo for steamlink" PKG_URL="" PKG_DEPENDS_UNPACK+=" libjpeg-turbo" +PKG_BUILD_FLAGS+=" -sysroot" PKG_CMAKE_OPTS_TARGET+=" -DENABLE_STATIC=OFF \ -DENABLE_SHARED=ON \ @@ -16,11 +17,3 @@ unpack() { mkdir -p ${PKG_BUILD} tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.gz -C ${PKG_BUILD} } - -makeinstall_target() { - : -} - -post_makeinstall_target() { - : -} diff --git a/packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk b/packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk index 101347a9dfe..297e28f4e29 100644 --- a/packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk +++ b/packages/addons/addon-depends/steamlink-depends/steamlink-libpng/package.mk @@ -7,6 +7,7 @@ PKG_NAME="steamlink-libpng" PKG_LONGDESC="libpng for steamlink-rpi" PKG_URL="" PKG_DEPENDS_TARGET+=" libpng" +PKG_BUILD_FLAGS+=" -sysroot" PKG_CONFIGURE_OPTS_TARGET+=" --disable-static \ --enable-shared" @@ -16,10 +17,6 @@ unpack() { tar --strip-components=1 -xf ${SOURCES}/${PKG_NAME:10}/${PKG_NAME:10}-${PKG_VERSION}.tar.xz -C ${PKG_BUILD} } -makeinstall_target() { - : -} - post_makeinstall_target() { : } diff --git a/packages/addons/script/steamlink-rpi/package.mk b/packages/addons/script/steamlink-rpi/package.mk index 0a29ef18bde..3463eb5bfd8 100644 --- a/packages/addons/script/steamlink-rpi/package.mk +++ b/packages/addons/script/steamlink-rpi/package.mk @@ -22,26 +22,22 @@ PKG_ADDON_PROVIDES="executable" PKG_STEAMLINK_VERSION="1.1.64.162" PKG_STEAMLINK_HASH="1ea1c41802bd6cc3efdba7ba258b9d25d5c07cdd1d0ffe9f2d47597588a09155" -make_target() { - : -} - addon() { # Add needed libraries mkdir -p ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs # libpng - cp -L $(get_build_dir steamlink-libpng)/.${TARGET_NAME}/.libs/libpng16.so.16 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + cp -L $(get_install_dir steamlink-libpng)/usr/lib/libpng16.so.16 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ # libjpeg-turbo - cp -L $(get_build_dir steamlink-libjpeg-turbo)/.${TARGET_NAME}/libjpeg.so.62 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + cp -L $(get_install_dir steamlink-libjpeg-turbo)/usr/lib/libjpeg.so.62 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ # libXext - cp -L $(get_build_dir steamlink-libXext)/.${TARGET_NAME}/src/.libs/libXext.so.6 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + cp -L $(get_install_dir steamlink-libXext)/usr/lib/libXext.so.6 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ # libX11 - cp -L $(get_build_dir steamlink-libX11)/.${TARGET_NAME}/src/.libs/libX11.so.6 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ - cp -L $(get_build_dir steamlink-libX11)/.${TARGET_NAME}/src/.libs/libX11-xcb.so.1 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + cp -L $(get_install_dir steamlink-libX11)/usr/lib/libX11.so.6 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ + cp -L $(get_install_dir steamlink-libX11)/usr/lib/libX11-xcb.so.1 ${ADDON_BUILD}/${PKG_ADDON_ID}/system-libs/ } post_install_addon() { From 58f789ae665811862e4907d119ac099cdae368e0 Mon Sep 17 00:00:00 2001 From: Ian Leonard Date: Tue, 7 Jul 2020 05:49:49 +0000 Subject: [PATCH 8/8] steamlink-rpi: add progress bar to download Signed-off-by: Ian Leonard --- .../script/steamlink-rpi/source/default.py | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/addons/script/steamlink-rpi/source/default.py b/packages/addons/script/steamlink-rpi/source/default.py index 18883b3d4ee..230be11d60e 100644 --- a/packages/addons/script/steamlink-rpi/source/default.py +++ b/packages/addons/script/steamlink-rpi/source/default.py @@ -8,9 +8,10 @@ import xbmcgui from hashlib import sha256 from pathlib import Path -from tempfile import TemporaryDirectory from shutil import rmtree from sys import exit +from tempfile import TemporaryDirectory +from time import sleep from urllib.request import urlretrieve @@ -19,6 +20,7 @@ STEAMLINK_TARBALL_NAME = f"steamlink-rpi3-{STEAMLINK_VERSION}.tar.gz" STEAMLINK_URL = f"http://media.steampowered.com/steamlink/rpi/{STEAMLINK_TARBALL_NAME}" ADDON_DIR = xbmcaddon.Addon().getAddonInfo("path") +PROGRESS_BAR = xbmcgui.DialogProgress() def GetSHA256Hash(file_name): @@ -48,24 +50,38 @@ def OutputFileContents(file): with open(file) as data: return data.read() +def ProgressBarReport(chunk_count, chunk_size, total_size): + """ Use urlretrieve's reporthook to report progress """ + if total_size != -1: + progress_percentage = int(chunk_count * chunk_size / total_size * 100) + PROGRESS_BAR.update(progress_percentage) + else: + PROGRESS_BAR.update(0, "Filesize Unknown") + def DownloadSteamlink(): """ Download Steam Link for RPi """ with TemporaryDirectory() as temp_dir: STEAMLINK_TEMP_PATH = os.path.join(temp_dir, STEAMLINK_TARBALL_NAME) - xbmcgui.Dialog().notification("Steam Link", "Downloading Steam Link (about 60MiB)", xbmcgui.NOTIFICATION_INFO, 5000) - urlretrieve(STEAMLINK_URL, STEAMLINK_TEMP_PATH) + PROGRESS_BAR.create("Steam Link", f"Downloading Steam Link Version: {STEAMLINK_VERSION}...") + urlretrieve(STEAMLINK_URL, STEAMLINK_TEMP_PATH, ProgressBarReport) + if tarfile.is_tarfile(STEAMLINK_TEMP_PATH): DOWNLOAD_HASH = GetSHA256Hash(STEAMLINK_TEMP_PATH) if STEAMLINK_HASH == DOWNLOAD_HASH: - xbmcgui.Dialog().notification("Steam Link", "Download complete, extracting...", xbmcgui.NOTIFICATION_INFO, 5000) + PROGRESS_BAR.update(100, f"Extracting Steam Link Version {STEAMLINK_VERSION}...") STEAMLINK_TARBALL = tarfile.open(STEAMLINK_TEMP_PATH) STEAMLINK_TARBALL.extractall(path=f"{ADDON_DIR}/") + PROGRESS_BAR.close() else: - xbmcgui.Dialog().notification("Steam Link", "Download error: bad file hash, try again later", xbmcgui.NOTIFICATION_INFO, 5000) + PROGRESS_BAR.update(0, "Download Error: bad file hash. Try again later.") + sleep(5) + PROGRESS_BAR.close() exit(1) else: - xbmcgui.Dialog().notification("Steam Link", "Download error: bad download or missing file", xbmcgui.NOTIFICATION_INFO, 5000) + PROGRESS_BAR.update(0, "Download Error: bad download or missing file") + sleep(5) + PROGRESS_BAR.close() exit(1) def PrepareSteamlink():