diff --git a/config/addon/xbmc.service.library.xml b/config/addon/xbmc.service.library.xml
new file mode 100644
index 0000000000..f5a1aaefac
--- /dev/null
+++ b/config/addon/xbmc.service.library.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+@REQUIRES@
+
+
+ @PKG_ADDON_PROVIDES@
+
+
+
+
+
+ @PKG_SHORTDESC@
+
+@PKG_LONGDESC@
+
+
+@PKG_DISCLAIMER@
+
+ all
+
+@PKG_ADDON_NEWS@
+
+
+ resources/icon.png
+ resources/fanart.png
+@PKG_ADDON_SCREENSHOT@
+
+
+
diff --git a/packages/addons/service/librespot/changelog.txt b/packages/addons/service/librespot/changelog.txt
index ffbebe8438..70d297ec79 100644
--- a/packages/addons/service/librespot/changelog.txt
+++ b/packages/addons/service/librespot/changelog.txt
@@ -1,2 +1,5 @@
+101
+- Enable streaming to Kodi
+
100
- Initial addon
diff --git a/packages/addons/service/librespot/package.mk b/packages/addons/service/librespot/package.mk
index d954fe6880..4912b3c891 100644
--- a/packages/addons/service/librespot/package.mk
+++ b/packages/addons/service/librespot/package.mk
@@ -18,20 +18,21 @@
################################################################################
PKG_NAME="librespot"
-PKG_VERSION="2259188"
-PKG_REV="100"
+PKG_VERSION="67deb07"
+PKG_REV="101"
PKG_ARCH="any"
-PKG_LICENSE="prop."
+PKG_LICENSE="MIT"
PKG_SITE="https://github.com/plietar/$PKG_NAME/"
PKG_URL="https://github.com/plietar/$PKG_NAME/archive/$PKG_VERSION.zip"
-PKG_DEPENDS_TARGET="toolchain avahi libvorbis pyalsaaudio rust"
+PKG_DEPENDS_TARGET="toolchain avahi ffmpegx libvorbis pyalsaaudio rust"
PKG_SECTION="service"
-PKG_LONGDESC="Librespot ($PKG_VERSION) plays Spotify through LibreELEC using the opensource librespot library using a Spotify app as a remote."
+PKG_SHORTDESC="Librespot: play Spotify through LibreELEC using a Spotify app as a remote"
+PKG_LONGDESC="Librespot ($PKG_VERSION) plays Spotify through LibreELEC using the open source librespot library using a Spotify app as a remote."
PKG_AUTORECONF="no"
PKG_IS_ADDON="yes"
PKG_ADDON_NAME="Librespot"
-PKG_ADDON_TYPE="xbmc.service"
+PKG_ADDON_TYPE="xbmc.service.library"
PKG_MAINTAINER="Anton Voyl (awiouy)"
configure_target() {
@@ -43,6 +44,8 @@ configure_target() {
make_target() {
cd src
$CARGO_BUILD --no-default-features --features "alsa-backend with-avahi"
+ cd "$PKG_BUILD/.$TARGET_NAME"/*/release
+ $STRIP librespot
}
makeinstall_target() {
@@ -50,15 +53,16 @@ makeinstall_target() {
}
addon() {
+ mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID"
+ cp "$(get_build_dir pyalsaaudio)/.install_pkg/usr/lib/python2.7/site-packages/alsaaudio.so" \
+ "$ADDON_BUILD/$PKG_ADDON_ID"
+
mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/bin"
cp "$PKG_BUILD/.$TARGET_NAME"/*/release/librespot \
+ "$(get_build_dir ffmpegx)/.install_pkg/usr/local/bin/ffmpegx" \
"$ADDON_BUILD/$PKG_ADDON_ID/bin"
mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/lib"
cp "$(get_build_dir avahi)/avahi-compat-libdns_sd/.libs/libdns_sd.so.1" \
"$ADDON_BUILD/$PKG_ADDON_ID/lib"
-
- mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/wizard"
- cp "$(get_build_dir pyalsaaudio)/.install_pkg/usr/lib/python2.7/site-packages/alsaaudio.so" \
- "$ADDON_BUILD/$PKG_ADDON_ID/wizard/"
}
diff --git a/packages/addons/service/librespot/patches/librespot-02_disable_audio_cache.patch b/packages/addons/service/librespot/patches/librespot-02_disable_audio_cache.patch
deleted file mode 100644
index 42502b0df3..0000000000
--- a/packages/addons/service/librespot/patches/librespot-02_disable_audio_cache.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-From 031cc0a420db9d3ae8dd3543d07ff8503bdc508d Mon Sep 17 00:00:00 2001
-From: Michael Herger
-Date: Tue, 20 Jun 2017 12:31:55 +0200
-Subject: [PATCH] Add --disable-audio-cache startup parameter
-
-Disable caching of downloaded audio files at runtime. Comes in handy when running librespot on a small device with SD card or other small storage.
----
- src/audio_file.rs | 24 +++++++++++++-----------
- src/main.rs | 2 ++
- src/session.rs | 2 ++
- 3 files changed, 17 insertions(+), 11 deletions(-)
-
-diff --git a/src/audio_file.rs b/src/audio_file.rs
-index 369d5ca..d014ba2 100644
---- a/src/audio_file.rs
-+++ b/src/audio_file.rs
-@@ -151,17 +151,19 @@ impl AudioFileManager {
- complete_tx: Some(complete_tx),
- };
-
-- let session = self.session();
-- self.session().spawn(move |_| {
-- complete_rx.map(move |mut file| {
-- if let Some(cache) = session.cache() {
-- cache.save_file(file_id, &mut file);
-- debug!("File {} complete, saving to cache", file_id);
-- } else {
-- debug!("File {} complete", file_id);
-- }
-- }).or_else(|oneshot::Canceled| Ok(()))
-- });
-+ if self.session().config().use_audio_cache {
-+ let session = self.session();
-+ self.session().spawn(move |_| {
-+ complete_rx.map(move |mut file| {
-+ if let Some(cache) = session.cache() {
-+ cache.save_file(file_id, &mut file);
-+ debug!("File {} complete, saving to cache", file_id);
-+ } else {
-+ debug!("File {} complete", file_id);
-+ }
-+ }).or_else(|oneshot::Canceled| Ok(()))
-+ });
-+ }
-
- AudioFileOpen::Streaming(open)
- }
-diff --git a/src/main.rs b/src/main.rs
-index 38c57fd..8a31a44 100644
---- a/src/main.rs
-+++ b/src/main.rs
-@@ -86,6 +86,7 @@ struct Setup {
- fn setup(args: &[String]) -> Setup {
- let mut opts = getopts::Options::new();
- opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
-+ .optflag("", "disable-audio-cache", "Disable caching of the audio data.")
- .reqopt("n", "name", "Device name", "NAME")
- .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE")
- .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
-@@ -152,6 +153,7 @@ fn setup(args: &[String]) -> Setup {
- bitrate: bitrate,
- onstart: matches.opt_str("onstart"),
- onstop: matches.opt_str("onstop"),
-+ use_audio_cache: !matches.opt_present("disable-audio-cache"),
- };
-
- let device = matches.opt_str("device");
-diff --git a/src/session.rs b/src/session.rs
-index 86162bd..a5d397e 100644
---- a/src/session.rs
-+++ b/src/session.rs
-@@ -49,6 +49,7 @@ pub struct Config {
- pub bitrate: Bitrate,
- pub onstart: Option,
- pub onstop: Option,
-+ pub use_audio_cache: bool,
- }
-
- impl Default for Config {
-@@ -60,6 +61,7 @@ impl Default for Config {
- bitrate: Bitrate::Bitrate160,
- onstart: None,
- onstop: None,
-+ use_audio_cache: true,
- }
- }
- }
diff --git a/packages/addons/service/librespot/source/wizard/wizard.py b/packages/addons/service/librespot/source/addon.py
similarity index 68%
rename from packages/addons/service/librespot/source/wizard/wizard.py
rename to packages/addons/service/librespot/source/addon.py
index 585a4b92dc..86a51cca4e 100644
--- a/packages/addons/service/librespot/source/wizard/wizard.py
+++ b/packages/addons/service/librespot/source/addon.py
@@ -16,24 +16,8 @@
# along with LibreELEC. If not, see .
################################################################################
-import alsaaudio as alsa
-import xbmcaddon
-import xbmcgui
+from default import addon as addon
+
if __name__ == '__main__':
-
- addon = xbmcaddon.Addon('service.librespot')
- dialog = xbmcgui.Dialog()
- strings = addon.getLocalizedString
-
- while True:
- pcms = alsa.pcms()[1:]
- if len(pcms) == 0:
- dialog.ok(strings(30211), strings(30212))
- break
- pcmx = dialog.select(strings(30113), pcms)
- if pcmx == -1:
- break
- pcm = pcms[pcmx]
- addon.setSetting('ls_o', pcm)
- break
+ addon()
diff --git a/packages/addons/service/librespot/source/bin/librespot.start b/packages/addons/service/librespot/source/bin/librespot.start
index 0d5aaed6b4..aefaa45f47 100755
--- a/packages/addons/service/librespot/source/bin/librespot.start
+++ b/packages/addons/service/librespot/source/bin/librespot.start
@@ -17,10 +17,6 @@
# along with LibreELEC. If not, see .
################################################################################
-. /etc/os-release
-. /etc/profile
-oe_setup_addon service.librespot
-
activate_card() {
if [ -e "/proc/asound/$1" ]; then
return
@@ -39,62 +35,83 @@ activate_card() {
esac
}
-if [ ! "$(cat /proc/asound/pcm 2> /dev/null)" ]; then
- case "$LIBREELEC_ARCH" in
- RPi*.arm)
- activate_card "ALSA"
+init_alsa() {
+ . /etc/os-release
+
+ if [ ! "$(cat /proc/asound/pcm 2> /dev/null)" ]; then
+ case "$LIBREELEC_ARCH" in
+ RPi*.arm)
+ activate_card "ALSA"
+ ;;
+ *)
+ echo "Unable to activate an audio interface on $LIBREELEC_ARCH"
+ exit
+ ;;
+ esac
+ fi
+
+ case "$ls_o" in
+ *:CARD=*)
+ card="${ls_o##*:CARD=}"
+ card="${card%%,*}"
+ activate_card "$card"
+ index="$(readlink /proc/asound/$card)"
+ index="${index##*card}"
;;
+ hw:*,*)
+ echo "The hw:d,s specification is unreliable, use device:CARD=card instead"
+ index="${ls_o##hw:}"
+ index="${index%%,*}"
+ card="card$index"
+ activate_card "$card"
+ ;;
*)
- echo "Unable to activate an audio interface on $LIBREELEC_ARCH"
- exit
+ if [ -n "$ls_o" ]; then
+ echo "Unknown playback device specification $ls_o"
+ fi
;;
esac
-fi
-case "$ls_o" in
- *:CARD=*)
- card="${ls_o##*:CARD=}"
- card="${card%%,*}"
- activate_card "$card"
- index="$(readlink /proc/asound/$card)"
- index="${index##*card}"
- ;;
- hw:*,*)
- echo "The hw:d,s specification is unreliable, use device:CARD=card instead"
- index="${ls_o##hw:}"
- index="${index%%,*}"
- card="card$index"
- activate_card "$card"
- ;;
- *)
- if [ -n "$ls_o" ]; then
- echo "Unknown playback device specification $ls_o"
- fi
- ;;
-esac
+ case "$LIBREELEC_ARCH" in
+ RPi*.arm)
+ [ "$(readlink /proc/asound/ALSA)" == "card$index" ] && [ "$pcm_3" ] &&
+ amixer -c "$index" cset name="PCM Playback Route" "$pcm_3"
+ ;;
+ esac
+}
+
+
+. /etc/profile
+oe_setup_addon service.librespot
+
+LIBRESPOT="librespot --cache \"$ADDON_HOME/cache\"
+ --disable-audio-cache \
+ --name \"Librespot@$HOSTNAME\""
if [ -n "$ls_b" -a "$ls_b" != "-" ]; then
- bitrate="--bitrate $ls_b"
-fi
-
-if [ -n "$ls_o" ]; then
- device="--device $ls_o"
+ LIBRESPOT="$LIBRESPOT --bitrate $ls_b"
fi
if [ -n "$ls_p" -a -n "$ls_u" ]; then
- discovery="--disable-discovery --password $ls_p --username $ls_u"
+ LIBRESPOT="$LIBRESPOT --disable-discovery \
+ --password \"$ls_p\" \
+ --username \"$ls_u\""
fi
-case "$LIBREELEC_ARCH" in
- RPi*.arm)
- [ "$(readlink /proc/asound/ALSA)" == "card$index" ] && [ "$pcm_3" ] &&
- amixer -c "$index" cset name="PCM Playback Route" "$pcm_3"
- ;;
-esac
+if [ "$ls_O" == "Kodi" ]; then
+ LIBRESPOT="$LIBRESPOT --backend pipe \
+ --onstart=\"kodi-send \
+ --action=RunAddon(service.librespot)\" \
+ | ffmpegx -hide_banner -loglevel warning \
+ -avioflags direct -fflags nobuffer \
+ -re -ac 2 -ar 44100 -channel_layout stereo -f s16le -i pipe: \
+ -sdp_file \"$ADDON_HOME/librespot.sdp\" \
+ -f rtp rtp://127.0.0.1:5555"
+else
+ init_alsa
+ if [ -n "$ls_o" ]; then
+ LIBRESPOT="$LIBRESPOT --device \"$ls_o\""
+ fi
+fi
-librespot $bitrate \
- --cache "$ADDON_HOME/cache" \
- $device \
- --disable-audio-cache \
- $discovery \
- --name "Librespot@$HOSTNAME"
+eval $LIBRESPOT
diff --git a/packages/addons/service/librespot/source/default.py b/packages/addons/service/librespot/source/default.py
index 1388ab8636..149b4a2169 100644
--- a/packages/addons/service/librespot/source/default.py
+++ b/packages/addons/service/librespot/source/default.py
@@ -16,20 +16,91 @@
# along with LibreELEC. If not, see .
################################################################################
+import alsaaudio as alsa
+import os
import subprocess
+import sys
import xbmc
import xbmcaddon
+import xbmcgui
+
+
+ICON = xbmcaddon.Addon().getAddonInfo('icon')
+ID = xbmcaddon.Addon().getAddonInfo('id')
+NAME = xbmcaddon.Addon().getAddonInfo('name')
+PROFILE = xbmcaddon.Addon().getAddonInfo('profile')
+STRINGS = xbmcaddon.Addon().getLocalizedString
+
+ITEM = os.path.join(PROFILE, 'librespot.sdp')
+LISTITEM = xbmcgui.ListItem(NAME)
+LISTITEM.setArt({'thumb': ICON})
+
+
+def addon():
+ if len(sys.argv) == 1:
+ Player().play()
+ elif sys.argv[1] == 'wizard':
+ dialog = xbmcgui.Dialog()
+ while True:
+ pcms = alsa.pcms()[1:]
+ if len(pcms) == 0:
+ dialog.ok(NAME, STRINGS(30210))
+ break
+ pcmx = dialog.select(STRINGS(30112), pcms)
+ if pcmx == -1:
+ break
+ pcm = pcms[pcmx]
+ xbmcaddon.Addon().setSetting('ls_o', pcm)
+ break
+
+
+def systemctl(command):
+ subprocess.call(['systemctl', command, ID])
class Monitor(xbmc.Monitor):
def __init__(self, *args, **kwargs):
- xbmc.Monitor.__init__(self)
- self.id = xbmcaddon.Addon().getAddonInfo('id')
+ super(Monitor, self).__init__(self)
+ self.player = Player()
def onSettingsChanged(self):
- subprocess.call(['systemctl', 'restart', self.id])
+ self.player.stop()
+class Player(xbmc.Player):
+
+ def __init__(self, *args, **kwargs):
+ super(Player, self).__init__(self)
+ if self.isPlaying():
+ self.onPlayBackStarted()
+
+ def onPlayBackEnded(self):
+ if not self.islibrespot:
+ xbmc.sleep(5000)
+ if not self.isPlaying():
+ systemctl('start')
+
+ def onPlayBackStarted(self):
+ if self.getPlayingFile() == ITEM:
+ self.islibrespot = True
+ else:
+ self.islibrespot = False
+ systemctl('stop')
+
+ def onPlayBackStopped(self):
+ systemctl('restart')
+
+ def play(self):
+ if not self.isPlaying():
+ super(Player, self).play(ITEM, LISTITEM)
+
+ def stop(self):
+ if self.isPlaying():
+ if self.getPlayingFile() == ITEM:
+ super(Player, self).stop()
+ else:
+ systemctl('restart')
+
if __name__ == '__main__':
Monitor().waitForAbort()
diff --git a/packages/addons/service/librespot/source/resources/language/English/strings.po b/packages/addons/service/librespot/source/resources/language/English/strings.po
index 02ec26527d..3b62e23c88 100644
--- a/packages/addons/service/librespot/source/resources/language/English/strings.po
+++ b/packages/addons/service/librespot/source/resources/language/English/strings.po
@@ -4,69 +4,73 @@ msgid ""
msgstr ""
msgctxt "#30100"
-msgid "Configuration"
+msgid "Librespot"
msgstr ""
msgctxt "#30101"
-msgid "ALSA"
-msgstr ""
-
-msgctxt "#30102"
-msgid "Configuration wizard"
-msgstr ""
-
-msgctxt "#30103"
-msgid "Playback device"
-msgstr ""
-
-msgctxt "#30104"
-msgid "Playback route"
-msgstr ""
-
-msgctxt "#30105"
-msgid "auto detect"
-msgstr ""
-
-msgctxt "#30106"
-msgid "headphone jack"
-msgstr ""
-
-msgctxt "#30107"
-msgid "HDMI"
-msgstr ""
-
-msgctxt "#30108"
-msgid "Spotify"
-msgstr ""
-
-msgctxt "#30109"
-msgid "Username"
-msgstr ""
-
-msgctxt "#30110"
-msgid "Password"
-msgstr ""
-
-msgctxt "#30111"
-msgid "Discovery mode (set username and password to disable)"
-msgstr ""
-
-msgctxt "#30112"
msgid "Bit rate"
msgstr ""
-msgctxt "#30113"
+msgctxt "#30102"
msgid "-"
msgstr ""
-msgctxt "#30114"
-msgid "90"
+msgctxt "#30103"
+msgid "96"
msgstr ""
-msgctxt "#30115"
+msgctxt "#30104"
msgid "160"
msgstr ""
-msgctxt "#30116"
+msgctxt "#30105"
msgid "320"
msgstr ""
+
+msgctxt "#30106"
+msgid "Output"
+msgstr ""
+
+msgctxt "#30107"
+msgid "Username"
+msgstr ""
+
+msgctxt "#30108"
+msgid "Password"
+msgstr ""
+
+msgctxt "#30109"
+msgid "Discovery mode (set username and password to disable)"
+msgstr ""
+
+msgctxt "#30110"
+msgid "ALSA"
+msgstr ""
+
+msgctxt "#30111"
+msgid "Configuration wizard"
+msgstr ""
+
+msgctxt "#30112"
+msgid "Playback device"
+msgstr ""
+
+msgctxt "#30113"
+msgid "Playback route"
+msgstr ""
+
+msgctxt "#30114"
+msgid "auto detect"
+msgstr ""
+
+msgctxt "#30115"
+msgid "headphone jack"
+msgstr ""
+
+msgctxt "#30116"
+msgid "HDMI"
+msgstr ""
+
+msgctxt "#30210"
+msgid "Could not find a playback device"
+msgstr ""
diff --git a/packages/addons/service/librespot/source/resources/settings.xml b/packages/addons/service/librespot/source/resources/settings.xml
index 7292787476..bc502031c0 100644
--- a/packages/addons/service/librespot/source/resources/settings.xml
+++ b/packages/addons/service/librespot/source/resources/settings.xml
@@ -1,14 +1,17 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+