mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-28 13:16:41 +00:00
librespot: initial addon
This commit is contained in:
parent
4862642f6e
commit
ab246ebe97
2
packages/addons/service/librespot/changelog.txt
Normal file
2
packages/addons/service/librespot/changelog.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
100
|
||||||
|
- Initial addon
|
BIN
packages/addons/service/librespot/icon/icon.png
Normal file
BIN
packages/addons/service/librespot/icon/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
64
packages/addons/service/librespot/package.mk
Normal file
64
packages/addons/service/librespot/package.mk
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
################################################################################
|
||||||
|
# This file is part of LibreELEC - https://libreelec.tv
|
||||||
|
# Copyright (C) 2017-present Team LibreELEC
|
||||||
|
# Copyright (C) 2017 Shane Meagher (shanemeagher)
|
||||||
|
#
|
||||||
|
# LibreELEC 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.
|
||||||
|
#
|
||||||
|
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
PKG_NAME="librespot"
|
||||||
|
PKG_VERSION="2259188"
|
||||||
|
PKG_REV="100"
|
||||||
|
PKG_ARCH="any"
|
||||||
|
PKG_LICENSE="prop."
|
||||||
|
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 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_AUTORECONF="no"
|
||||||
|
|
||||||
|
PKG_IS_ADDON="yes"
|
||||||
|
PKG_ADDON_NAME="Librespot"
|
||||||
|
PKG_ADDON_TYPE="xbmc.service"
|
||||||
|
PKG_MAINTAINER="Anton Voyl (awiouy)"
|
||||||
|
|
||||||
|
configure_target() {
|
||||||
|
. "$ROOT/$TOOLCHAIN/.cargo/env"
|
||||||
|
export PKG_CONFIG_ALLOW_CROSS=0
|
||||||
|
strip_lto
|
||||||
|
}
|
||||||
|
|
||||||
|
make_target() {
|
||||||
|
cd src
|
||||||
|
$CARGO_BUILD --no-default-features --features "alsa-backend with-avahi"
|
||||||
|
}
|
||||||
|
|
||||||
|
makeinstall_target() {
|
||||||
|
:
|
||||||
|
}
|
||||||
|
|
||||||
|
addon() {
|
||||||
|
mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/bin"
|
||||||
|
cp "$PKG_BUILD/.$TARGET_NAME"/*/release/librespot \
|
||||||
|
"$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/"
|
||||||
|
}
|
@ -0,0 +1,222 @@
|
|||||||
|
From a825f84d9d00b196232fcccc5b5e441654c4e5a0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: shanemeagher <shanemeagher@outlook.com>
|
||||||
|
Date: Fri, 9 Jun 2017 22:43:54 +0800
|
||||||
|
Subject: [PATCH] Build librespot with avahi support for Discovery
|
||||||
|
|
||||||
|
rust-mdns is still the default and can be specified explicitly with --with-rust-mdns switch.
|
||||||
|
Added --with-avahi switch to build librespot to use avahi for discovery using dns-sd package.
|
||||||
|
---
|
||||||
|
Cargo.lock | 10 ++++++++++
|
||||||
|
Cargo.toml | 7 +++++--
|
||||||
|
contrib/Dockerfile | 3 +++
|
||||||
|
contrib/docker-build-avahi.sh | 24 ++++++++++++++++++++++++
|
||||||
|
src/authentication/discovery.rs | 27 ++++++++++++++++++++++++++-
|
||||||
|
src/lib.rs | 6 +++++-
|
||||||
|
6 files changed, 73 insertions(+), 4 deletions(-)
|
||||||
|
create mode 100755 contrib/docker-build-avahi.sh
|
||||||
|
|
||||||
|
diff --git a/Cargo.lock b/Cargo.lock
|
||||||
|
index 30fafca..eff0925 100644
|
||||||
|
--- a/Cargo.lock
|
||||||
|
+++ b/Cargo.lock
|
||||||
|
@@ -6,6 +6,7 @@ dependencies = [
|
||||||
|
"base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
+ "dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"error-chain 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@@ -144,6 +145,15 @@ dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
+name = "dns-sd"
|
||||||
|
+version = "0.1.3"
|
||||||
|
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
+dependencies = [
|
||||||
|
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
+ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
+]
|
||||||
|
+
|
||||||
|
+[[package]]
|
||||||
|
name = "dtoa"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
diff --git a/Cargo.toml b/Cargo.toml
|
||||||
|
index 5d64719..c543e92 100644
|
||||||
|
--- a/Cargo.toml
|
||||||
|
+++ b/Cargo.toml
|
||||||
|
@@ -52,7 +52,8 @@ alsa = { git = "https://github.com/plietar/rust-alsa", optional = tru
|
||||||
|
portaudio-rs = { version = "0.3.0", optional = true }
|
||||||
|
libpulse-sys = { git = "https://github.com/astro/libpulse-sys", optional = true }
|
||||||
|
|
||||||
|
-mdns = { git = "https://github.com/plietar/rust-mdns" }
|
||||||
|
+mdns = { git = "https://github.com/plietar/rust-mdns", optional = true }
|
||||||
|
+dns-sd = { version = "~0.1.3", optional = true }
|
||||||
|
|
||||||
|
error-chain = { version = "0.9.0", default_features = false }
|
||||||
|
futures = "0.1.8"
|
||||||
|
@@ -71,8 +72,10 @@ portaudio-backend = ["portaudio-rs"]
|
||||||
|
pulseaudio-backend = ["libpulse-sys"]
|
||||||
|
|
||||||
|
with-tremor = ["tremor"]
|
||||||
|
+with-rust-mdns = ["mdns"]
|
||||||
|
+with-avahi = ["dns-sd"]
|
||||||
|
|
||||||
|
-default = ["portaudio-backend"]
|
||||||
|
+default = ["portaudio-backend","with-rust-mdns"]
|
||||||
|
|
||||||
|
[package.metadata.deb]
|
||||||
|
maintainer = "nobody"
|
||||||
|
diff --git a/contrib/Dockerfile b/contrib/Dockerfile
|
||||||
|
index 68a39b7..f6aec14 100644
|
||||||
|
--- a/contrib/Dockerfile
|
||||||
|
+++ b/contrib/Dockerfile
|
||||||
|
@@ -4,6 +4,8 @@
|
||||||
|
#
|
||||||
|
# The resulting image can be used to build librespot for linux x86_64, armhf and armel.
|
||||||
|
# $ docker run -v /tmp/librespot-build:/build librespot-cross
|
||||||
|
+# To build librespot with avahi support
|
||||||
|
+# $ docker run -v /tmp/librespot-build:/build librespot-cross /src/contrib/docker-build-avahi.sh
|
||||||
|
#
|
||||||
|
# The compiled binaries will be located in /tmp/librespot-build
|
||||||
|
#
|
||||||
|
@@ -23,6 +25,7 @@ RUN apt-get update
|
||||||
|
|
||||||
|
RUN apt-get install -y curl git build-essential crossbuild-essential-arm64 crossbuild-essential-armel crossbuild-essential-armhf crossbuild-essential-mipsel
|
||||||
|
RUN apt-get install -y libasound2-dev libasound2-dev:arm64 libasound2-dev:armel libasound2-dev:armhf libasound2-dev:mipsel
|
||||||
|
+RUN apt-get install -y libavahi-compat-libdnssd-dev libavahi-compat-libdnssd-dev:arm64 libavahi-compat-libdnssd-dev:armel libavahi-compat-libdnssd-dev:armhf libavahi-compat-libdnssd-dev:mipsel
|
||||||
|
|
||||||
|
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
|
ENV PATH="/root/.cargo/bin/:${PATH}"
|
||||||
|
diff --git a/contrib/docker-build-avahi.sh b/contrib/docker-build-avahi.sh
|
||||||
|
new file mode 100755
|
||||||
|
index 0000000..c25b248
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/contrib/docker-build-avahi.sh
|
||||||
|
@@ -0,0 +1,24 @@
|
||||||
|
+#!/usr/bin/env bash
|
||||||
|
+set -eux
|
||||||
|
+
|
||||||
|
+cargo build --release --no-default-features --features "alsa-backend with-avahi"
|
||||||
|
+cp /usr/lib/x86_64-linux-gnu/libdns_sd.so.1 /build/release
|
||||||
|
+
|
||||||
|
+export PKG_CONFIG_ALLOW_CROSS=0
|
||||||
|
+
|
||||||
|
+export PKG_CONFIG_PATH=/usr/lib/aarch64-unknown-linux-gnu/pkgconfig
|
||||||
|
+cargo build --release --target aarch64-unknown-linux-gnu --no-default-features --features "alsa-backend with-avahi"
|
||||||
|
+cp /usr/lib/aarch64-linux-gnu/libdns_sd.so.1 /build/aarch64-unknown-linux-gnu/release
|
||||||
|
+
|
||||||
|
+export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabi/pkgconfig
|
||||||
|
+cargo build --release --target arm-unknown-linux-gnueabi --no-default-features --features "alsa-backend with-avahi"
|
||||||
|
+cp /usr/lib/arm-linux-gnueabi/libdns_sd.so.1 /build/arm-unknown-linux-gnueabi/release
|
||||||
|
+
|
||||||
|
+export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig
|
||||||
|
+cargo build --release --target arm-unknown-linux-gnueabihf --no-default-features --features "alsa-backend with-avahi"
|
||||||
|
+cp /usr/lib/arm-linux-gnueabihf/libdns_sd.so.1 /build/arm-unknown-linux-gnueabihf/release
|
||||||
|
+
|
||||||
|
+export PKG_CONFIG_PATH=/usr/lib/mipsel-linux-gnu/pkgconfig
|
||||||
|
+cargo build --release --target mipsel-unknown-linux-gnu --no-default-features --features "alsa-backend with-avahi"
|
||||||
|
+cp /usr/libmipsel-linux-gnu/libdns_sd.so.1 /build/mipsel-unknown-linux-gnu/release
|
||||||
|
+
|
||||||
|
diff --git a/src/authentication/discovery.rs b/src/authentication/discovery.rs
|
||||||
|
index 8c5b005..d385294 100644
|
||||||
|
--- a/src/authentication/discovery.rs
|
||||||
|
+++ b/src/authentication/discovery.rs
|
||||||
|
@@ -7,7 +7,6 @@ use futures::sync::mpsc;
|
||||||
|
use futures::{Future, Stream, BoxFuture, Poll, Async};
|
||||||
|
use hyper::server::{Service, NewService, Request, Response, Http};
|
||||||
|
use hyper::{self, Get, Post, StatusCode};
|
||||||
|
-use mdns;
|
||||||
|
use num_bigint::BigUint;
|
||||||
|
use rand;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
@@ -20,6 +19,12 @@ use url;
|
||||||
|
use authentication::Credentials;
|
||||||
|
use util;
|
||||||
|
|
||||||
|
+#[cfg(feature = "with-rust-mdns")]
|
||||||
|
+use mdns;
|
||||||
|
+
|
||||||
|
+#[cfg(feature = "with-avahi")]
|
||||||
|
+use dns_sd::DNSService;
|
||||||
|
+
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Discovery(Arc<DiscoveryInner>);
|
||||||
|
struct DiscoveryInner {
|
||||||
|
@@ -202,7 +207,10 @@ impl NewService for Discovery {
|
||||||
|
|
||||||
|
pub struct DiscoveryStream {
|
||||||
|
credentials: mpsc::UnboundedReceiver<Credentials>,
|
||||||
|
+ #[cfg(feature = "with-rust-mdns")]
|
||||||
|
_svc: mdns::Service,
|
||||||
|
+ #[cfg(feature = "with-avahi")]
|
||||||
|
+ _svc: DNSService,
|
||||||
|
task: Box<Future<Item=(), Error=io::Error>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -212,8 +220,13 @@ pub fn discovery(handle: &Handle, device_name: String, device_id: String)
|
||||||
|
let (discovery, creds_rx) = Discovery::new(device_name.clone(), device_id);
|
||||||
|
|
||||||
|
let listener = TcpListener::bind(&"0.0.0.0:0".parse().unwrap(), handle)?;
|
||||||
|
+
|
||||||
|
+ #[cfg(feature = "with-rust-mdns")]
|
||||||
|
let addr = listener.local_addr()?;
|
||||||
|
|
||||||
|
+ #[cfg(feature = "with-avahi")]
|
||||||
|
+ let port = listener.local_addr().unwrap().port();
|
||||||
|
+
|
||||||
|
let http = Http::new();
|
||||||
|
let handle_ = handle.clone();
|
||||||
|
let task = Box::new(listener.incoming().for_each(move |(socket, addr)| {
|
||||||
|
@@ -221,13 +234,25 @@ pub fn discovery(handle: &Handle, device_name: String, device_id: String)
|
||||||
|
Ok(())
|
||||||
|
}));
|
||||||
|
|
||||||
|
+ #[cfg(feature = "with-rust-mdns")]
|
||||||
|
let responder = mdns::Responder::spawn(&handle)?;
|
||||||
|
+
|
||||||
|
+ #[cfg(feature = "with-rust-mdns")]
|
||||||
|
let svc = responder.register(
|
||||||
|
"_spotify-connect._tcp".to_owned(),
|
||||||
|
device_name,
|
||||||
|
addr.port(),
|
||||||
|
&["VERSION=1.0", "CPath=/"]);
|
||||||
|
|
||||||
|
+ #[cfg(feature = "with-avahi")]
|
||||||
|
+ let svc = DNSService::register(Some(&*device_name),
|
||||||
|
+ "_spotify-connect._tcp",
|
||||||
|
+ None,
|
||||||
|
+ None,
|
||||||
|
+ port,
|
||||||
|
+ &["VERSION=1.0", "CPath=/"])
|
||||||
|
+ .unwrap();
|
||||||
|
+
|
||||||
|
Ok(DiscoveryStream {
|
||||||
|
credentials: creds_rx,
|
||||||
|
_svc: svc,
|
||||||
|
diff --git a/src/lib.rs b/src/lib.rs
|
||||||
|
index 2a50249..b1b77ef 100644
|
||||||
|
--- a/src/lib.rs
|
||||||
|
+++ b/src/lib.rs
|
||||||
|
@@ -19,7 +19,6 @@ extern crate crypto;
|
||||||
|
extern crate getopts;
|
||||||
|
extern crate hyper;
|
||||||
|
extern crate linear_map;
|
||||||
|
-extern crate mdns;
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_integer;
|
||||||
|
extern crate num_traits;
|
||||||
|
@@ -50,6 +49,11 @@ extern crate portaudio_rs;
|
||||||
|
#[cfg(feature = "libpulse-sys")]
|
||||||
|
extern crate libpulse_sys;
|
||||||
|
|
||||||
|
+#[cfg(feature = "with-rust-mdns")]
|
||||||
|
+extern crate mdns;
|
||||||
|
+
|
||||||
|
+#[cfg(feature = "with-avahi")]
|
||||||
|
+extern crate dns_sd;
|
||||||
|
|
||||||
|
#[macro_use] mod component;
|
||||||
|
pub mod album_cover;
|
@ -0,0 +1,48 @@
|
|||||||
|
diff -Naur librespot/src/audio_file.rs librespot.nocache/src/audio_file.rs
|
||||||
|
--- librespot/src/audio_file.rs 2017-06-14 00:14:21.000000000 +0200
|
||||||
|
+++ librespot.nocache/src/audio_file.rs 2017-06-20 00:35:14.060020000 +0200
|
||||||
|
@@ -3,7 +3,7 @@
|
||||||
|
use futures::Stream;
|
||||||
|
use futures::sync::{oneshot, mpsc};
|
||||||
|
use futures::{Poll, Async, Future};
|
||||||
|
-use futures::future::{self, FutureResult};
|
||||||
|
+use futures::future::FutureResult;
|
||||||
|
use std::cmp::min;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{self, Read, Write, Seek, SeekFrom};
|
||||||
|
@@ -129,15 +129,9 @@
|
||||||
|
|
||||||
|
impl AudioFileManager {
|
||||||
|
pub fn open(&self, file_id: FileId) -> AudioFileOpen {
|
||||||
|
- let cache = self.session().cache().cloned();
|
||||||
|
-
|
||||||
|
- if let Some(file) = cache.as_ref().and_then(|cache| cache.file(file_id)) {
|
||||||
|
- debug!("File {} already in cache", file_id);
|
||||||
|
- return AudioFileOpen::Cached(future::ok(file));
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
debug!("Downloading file {}", file_id);
|
||||||
|
|
||||||
|
+ #[allow(unused_variables)]
|
||||||
|
let (complete_tx, complete_rx) = oneshot::channel();
|
||||||
|
let (headers, data) = request_chunk(&self.session(), file_id, 0).split();
|
||||||
|
|
||||||
|
@@ -151,18 +145,6 @@
|
||||||
|
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(()))
|
||||||
|
- });
|
||||||
|
-
|
||||||
|
AudioFileOpen::Streaming(open)
|
||||||
|
}
|
||||||
|
}
|
99
packages/addons/service/librespot/source/bin/librespot.start
Executable file
99
packages/addons/service/librespot/source/bin/librespot.start
Executable file
@ -0,0 +1,99 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
################################################################################
|
||||||
|
# This file is part of LibreELEC - https://libreelec.tv
|
||||||
|
# Copyright (C) 2017-present Team LibreELEC
|
||||||
|
#
|
||||||
|
# LibreELEC 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.
|
||||||
|
#
|
||||||
|
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
. /etc/os-release
|
||||||
|
. /etc/profile
|
||||||
|
oe_setup_addon service.librespot
|
||||||
|
|
||||||
|
activate_card() {
|
||||||
|
if [ -e "/proc/asound/$1" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
case "$LIBREELEC_ARCH" in
|
||||||
|
RPi*.arm)
|
||||||
|
if [ "$1" = "ALSA" ]; then
|
||||||
|
dtparam audio=on
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unable to activate card $1 on $LIBREELEC_ARCH"
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -n "$ls_o" ]; then
|
||||||
|
echo "Unknown playback device specification $ls_o"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "$ls_b" -a "$ls_b" != "-" ]; then
|
||||||
|
bitrate="--bitrate $ls_b"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ls_o" ]; then
|
||||||
|
device="--device $ls_o"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ls_p" -a -n "$ls_u" ]; then
|
||||||
|
discovery="--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
|
||||||
|
|
||||||
|
librespot $bitrate \
|
||||||
|
--cache "$ADDON_HOME/cache" \
|
||||||
|
$device \
|
||||||
|
$discovery \
|
||||||
|
--name "Librespot@$HOSTNAME"
|
35
packages/addons/service/librespot/source/default.py
Normal file
35
packages/addons/service/librespot/source/default.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
################################################################################
|
||||||
|
# This file is part of LibreELEC - https://libreelec.tv
|
||||||
|
# Copyright (C) 2017-present Team LibreELEC
|
||||||
|
#
|
||||||
|
# LibreELEC 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.
|
||||||
|
#
|
||||||
|
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import xbmc
|
||||||
|
import xbmcaddon
|
||||||
|
|
||||||
|
|
||||||
|
class Monitor(xbmc.Monitor):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
xbmc.Monitor.__init__(self)
|
||||||
|
self.id = xbmcaddon.Addon().getAddonInfo('id')
|
||||||
|
|
||||||
|
def onSettingsChanged(self):
|
||||||
|
subprocess.call(['systemctl', 'restart', self.id])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Monitor().waitForAbort()
|
@ -0,0 +1,72 @@
|
|||||||
|
# Kodi Media Center language file
|
||||||
|
# Addon Name: librespot
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#30100"
|
||||||
|
msgid "Configuration"
|
||||||
|
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"
|
||||||
|
msgid "-"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#30114"
|
||||||
|
msgid "90"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#30115"
|
||||||
|
msgid "160"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#30116"
|
||||||
|
msgid "320"
|
||||||
|
msgstr ""
|
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||||
|
<settings>
|
||||||
|
<category label="30100" >
|
||||||
|
<setting label="30101" type="lsep" />
|
||||||
|
<setting label="30102" type="action" action="RunScript(/storage/.kodi/addons/service.librespot/wizard/wizard.py)" />
|
||||||
|
<setting label="30103" type="text" id="ls_o" default="" />
|
||||||
|
<setting label="30104" type="enum" id="pcm_3" lvalues="30105|30106|30107" visible="eq(-1,default:CARD=ALSA)|eq(-1,sysdefault:CARD=ALSA)" />
|
||||||
|
<setting label="30108" type="lsep" />
|
||||||
|
<setting label="30109" type="text" id="ls_u" />
|
||||||
|
<setting label="30110" type="text" id="ls_p" option="hidden" visible="!eq(-1,)" />
|
||||||
|
<setting label="30111" type="bool" id="ls_d" default="true" enable="false" visible="eq(-1,)|eq(-2,)" />
|
||||||
|
<setting label="30112" type="labelenum" id="ls_b" lvalues="30113|30114|30115|30116" />
|
||||||
|
</category>
|
||||||
|
</settings>
|
@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=librespot
|
||||||
|
After=network-online.target
|
||||||
|
Requires=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh /storage/.kodi/addons/service.librespot/bin/librespot.start
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=kodi.target
|
39
packages/addons/service/librespot/source/wizard/wizard.py
Normal file
39
packages/addons/service/librespot/source/wizard/wizard.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
################################################################################
|
||||||
|
# This file is part of LibreELEC - https://libreelec.tv
|
||||||
|
# Copyright (C) 2017-present Team LibreELEC
|
||||||
|
#
|
||||||
|
# LibreELEC 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.
|
||||||
|
#
|
||||||
|
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
import alsaaudio as alsa
|
||||||
|
import xbmcaddon
|
||||||
|
import xbmcgui
|
||||||
|
|
||||||
|
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
|
Loading…
x
Reference in New Issue
Block a user