mirror of
https://github.com/LibreELEC/LibreELEC.tv
synced 2025-09-24 19:46:01 +07:00
Compare commits
466 Commits
5d61b746fa
...
9.1.501
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
572c3ad9a2 | ||
|
|
728d0ee3ee | ||
|
|
b615639ab1 | ||
|
|
23434e18ca | ||
|
|
480fc09d5a | ||
|
|
077ee9572b | ||
|
|
38f45582e2 | ||
|
|
f43acfbbde | ||
|
|
a80ee9d033 | ||
|
|
d58acf754d | ||
|
|
0bd3e610a3 | ||
|
|
a076e074ef | ||
|
|
a3cab3855a | ||
|
|
4e2e7c824c | ||
|
|
e117405cec | ||
|
|
3ac9286fbf | ||
|
|
be5afc4cdd | ||
|
|
4d9d148629 | ||
|
|
9ae87b9e15 | ||
|
|
58430ffe6a | ||
|
|
a7c4f092e1 | ||
|
|
61461cd8e1 | ||
|
|
b7d6680f15 | ||
|
|
b2b2eea1c2 | ||
|
|
cebad6b63f | ||
|
|
b8d6a1dfc9 | ||
|
|
0225a0342b | ||
|
|
d81cc10a81 | ||
|
|
4533bf3ea7 | ||
|
|
7da4fa4dc9 | ||
|
|
316620cdb9 | ||
|
|
7deb7b0236 | ||
|
|
827e3f1444 | ||
|
|
50935255f0 | ||
|
|
ee2503e625 | ||
|
|
86f677ceea | ||
|
|
50afe5e20c | ||
|
|
55a50f3ec7 | ||
|
|
210f15173c | ||
|
|
db3061c294 | ||
|
|
7437f95512 | ||
|
|
7f8b26a001 | ||
|
|
ea370a93cf | ||
|
|
8883bab7b5 | ||
|
|
b8637f24ee | ||
|
|
3e0369fac2 | ||
|
|
b081a83003 | ||
|
|
50fe8d25bb | ||
|
|
3487aa4f59 | ||
|
|
538793e0e8 | ||
|
|
2c2a752bb4 | ||
|
|
bcb6fbb2dd | ||
|
|
066d1f4915 | ||
|
|
f3ec7145ab | ||
|
|
810135dfb1 | ||
|
|
cc3f393bce | ||
|
|
87a3e42c97 | ||
|
|
e7e3247c27 | ||
|
|
b6d91f188f | ||
|
|
d044026689 | ||
|
|
3aa1bc4080 | ||
|
|
854f65ff6f | ||
|
|
fdd66d5dc9 | ||
|
|
6a1675d0c4 | ||
|
|
352fa92689 | ||
|
|
7b1fe3b40f | ||
|
|
9243994d4d | ||
|
|
e45756a624 | ||
|
|
4c82cf416b | ||
|
|
2b05e02808 | ||
|
|
7fdcfe9d4a | ||
|
|
a30489aef6 | ||
|
|
5b9312d366 | ||
|
|
0af77e49db | ||
|
|
027f5f9542 | ||
|
|
1ca4b9e2ab | ||
|
|
0a63988817 | ||
|
|
dc56cf1aa0 | ||
|
|
c31b78aa65 | ||
|
|
7f2c559952 | ||
|
|
f07b611b85 | ||
|
|
9be01dd43b | ||
|
|
d9f5c1f594 | ||
|
|
ea070a4252 | ||
|
|
5052df5098 | ||
|
|
11c50fa049 | ||
|
|
51952298df | ||
|
|
fb481d6e8b | ||
|
|
692820c7e6 | ||
|
|
49665d0f56 | ||
|
|
10b73fa523 | ||
|
|
be4588cba8 | ||
|
|
f4ba1c8d0a | ||
|
|
ba7682954f | ||
|
|
32fb0dbdb6 | ||
|
|
2307fc6682 | ||
|
|
9689856e11 | ||
|
|
dc79a08ac8 | ||
|
|
f7d3be64e8 | ||
|
|
158db2052d | ||
|
|
31ae0db426 | ||
|
|
4136121967 | ||
|
|
76abc3a94e | ||
|
|
e7ea4cda81 | ||
|
|
be5631bfca | ||
|
|
0e2c544636 | ||
|
|
dff7803273 | ||
|
|
3a2cb71bdb | ||
|
|
cc23c1aa7d | ||
|
|
63dc844972 | ||
|
|
9fca79227d | ||
|
|
73aef806ae | ||
|
|
27a9b68274 | ||
|
|
d676a82920 | ||
|
|
434b5dcd20 | ||
|
|
ff14fc75de | ||
|
|
ee01247de3 | ||
|
|
62f0784860 | ||
|
|
151ff51d3d | ||
|
|
a62c0088b7 | ||
|
|
6fce87427b | ||
|
|
ec6cd1c748 | ||
|
|
af21cb6650 | ||
|
|
e5204380fa | ||
|
|
a2c343813a | ||
|
|
ad6a9f656e | ||
|
|
6a0e35e8c4 | ||
|
|
838b7587c4 | ||
|
|
a5480b6fbb | ||
|
|
089293d1b1 | ||
|
|
60c0025939 | ||
|
|
d40e6da679 | ||
|
|
02781b9cbf | ||
|
|
2ae4537216 | ||
|
|
43e58805d7 | ||
|
|
212c181de6 | ||
|
|
af7dd480fd | ||
|
|
4200d032e3 | ||
|
|
f2340cbcc9 | ||
|
|
e25aee7b70 | ||
|
|
3d3548216e | ||
|
|
9a21fc75d9 | ||
|
|
66d3241701 | ||
|
|
224bbd25a8 | ||
|
|
0ebb14559d | ||
|
|
7b0de5b7f6 | ||
|
|
161b7d7942 | ||
|
|
1ebce4e7eb | ||
|
|
5a6715c5aa | ||
|
|
d93bd49a02 | ||
|
|
426ff4cb1f | ||
|
|
8fc217337c | ||
|
|
82f70d28c9 | ||
|
|
eaf81e7277 | ||
|
|
fc97f456dc | ||
|
|
8380877cf5 | ||
|
|
ff8c463b31 | ||
|
|
7d84fbe6fa | ||
|
|
cff7ea1ab8 | ||
|
|
e0dc24ea42 | ||
|
|
79b31b45fd | ||
|
|
341aa35c3c | ||
|
|
02601a2500 | ||
|
|
adbe82298a | ||
|
|
365faa110f | ||
|
|
f1614bbac7 | ||
|
|
e89045361a | ||
|
|
ff813fca35 | ||
|
|
3e1563cb68 | ||
|
|
b50aa11e7d | ||
|
|
05a8e96592 | ||
|
|
2caa3e3b8b | ||
|
|
ff815836c5 | ||
|
|
39a81f5182 | ||
|
|
e826e18033 | ||
|
|
a6bc84ddd3 | ||
|
|
f04ec17bed | ||
|
|
357615473e | ||
|
|
96d92948a7 | ||
|
|
28b122f38b | ||
|
|
1e68ced1fb | ||
|
|
8dbe022c96 | ||
|
|
c2a626cdb6 | ||
|
|
266954d8b0 | ||
|
|
94aa4aebf6 | ||
|
|
6536414a46 | ||
|
|
a4a45cb3ba | ||
|
|
8c216956fd | ||
|
|
2b95120495 | ||
|
|
e44dd201a7 | ||
|
|
69e818ad25 | ||
|
|
bf06da5c6b | ||
|
|
973b437725 | ||
|
|
5fd83ea792 | ||
|
|
78e9965676 | ||
|
|
8aad391e89 | ||
|
|
fd1a20ede9 | ||
|
|
5ae38dba9d | ||
|
|
1fb4d27773 | ||
|
|
84e70210df | ||
|
|
664cadb820 | ||
|
|
237ed098f2 | ||
|
|
f1ef2f099c | ||
|
|
8bf41b5646 | ||
|
|
285ff64f93 | ||
|
|
f51e242eb6 | ||
|
|
5f4af38bda | ||
|
|
15cf6edcda | ||
|
|
fad82f0e52 | ||
|
|
f999f5818e | ||
|
|
60541fc7a4 | ||
|
|
1da93cec4f | ||
|
|
5c211cf5d1 | ||
|
|
965be3346f | ||
|
|
d46852e00c | ||
|
|
8fc25d9216 | ||
|
|
bb6cb4a18c | ||
|
|
75104714e1 | ||
|
|
788419c782 | ||
|
|
30f1e06c23 | ||
|
|
5cd2c6e4c9 | ||
|
|
aba8d19930 | ||
|
|
27130e8aa1 | ||
|
|
c29f446179 | ||
|
|
87eb94dc15 | ||
|
|
e76f0a39c0 | ||
|
|
b26a38279d | ||
|
|
0644052754 | ||
|
|
7678359759 | ||
|
|
5a5768aa60 | ||
|
|
eb8a4720ae | ||
|
|
541d29df36 | ||
|
|
f8ebb2f97a | ||
|
|
bd95afbae4 | ||
|
|
4ba7e76c64 | ||
|
|
d7c2207b8a | ||
|
|
c4b17555e1 | ||
|
|
7562b1f433 | ||
|
|
1aebc8cbf5 | ||
|
|
6f8b63acfe | ||
|
|
331d203edf | ||
|
|
f63b7fba07 | ||
|
|
60e06a17a3 | ||
|
|
2a9c4bb5be | ||
|
|
3cf175b0b2 | ||
|
|
a4b0706441 | ||
|
|
240d6f7917 | ||
|
|
e8a8df3f00 | ||
|
|
92e234cb70 | ||
|
|
a5bdc03af1 | ||
|
|
8f3af234a2 | ||
|
|
e7e91da91c | ||
|
|
6a01a9db3b | ||
|
|
243ca122d3 | ||
|
|
e910fb0626 | ||
|
|
d64d3819b0 | ||
|
|
10050ae75e | ||
|
|
ca4b9da4c6 | ||
|
|
d41d3b9cc6 | ||
|
|
ab0021b78f | ||
|
|
a7004681fa | ||
|
|
c3cc72fe3c | ||
|
|
c7babb3620 | ||
|
|
fc72e5d751 | ||
|
|
68570a6588 | ||
|
|
3adcb6ca9b | ||
|
|
ba818a4e9c | ||
|
|
c010cd4852 | ||
|
|
06a4a58835 | ||
|
|
3365ab2af7 | ||
|
|
818afbc013 | ||
|
|
a8cffb1142 | ||
|
|
bdd90f6c23 | ||
|
|
4c7e6a19d2 | ||
|
|
67de716210 | ||
|
|
bde8334d50 | ||
|
|
edf491d1c1 | ||
|
|
40b068464b | ||
|
|
d7ca15cce3 | ||
|
|
1f64a8165d | ||
|
|
9917b60837 | ||
|
|
a94ed02bac | ||
|
|
12169b7387 | ||
|
|
23c75ecd68 | ||
|
|
4d65280e66 | ||
|
|
439d3ff31e | ||
|
|
5e495a2bd2 | ||
|
|
26b2b6317c | ||
|
|
df47b8be68 | ||
|
|
ce7b145f29 | ||
|
|
2d400f1239 | ||
|
|
8a7f1edad0 | ||
|
|
b6027210f5 | ||
|
|
113b2829ab | ||
|
|
0e2b1c616b | ||
|
|
0ef9bd02e5 | ||
|
|
b63c7cfe41 | ||
|
|
b4a9b00c60 | ||
|
|
5225394e95 | ||
|
|
8daa6cd4a2 | ||
|
|
bd66701ec9 | ||
|
|
1279115624 | ||
|
|
2d418f67cc | ||
|
|
934cb939f3 | ||
|
|
a032fbd82e | ||
|
|
2f3ef07ca5 | ||
|
|
dc44c45496 | ||
|
|
97c44d6185 | ||
|
|
8cb1faf75a | ||
|
|
1d18803bd6 | ||
|
|
0f9583da99 | ||
|
|
e748d109b4 | ||
|
|
95422fadf0 | ||
|
|
d7e956544a | ||
|
|
267a536c16 | ||
|
|
987f53ca59 | ||
|
|
a3f6e5a14a | ||
|
|
91594773df | ||
|
|
0019bbb7db | ||
|
|
1f360da59f | ||
|
|
42d2f83366 | ||
|
|
3c36022773 | ||
|
|
7bd39a17c5 | ||
|
|
f0b6c134bc | ||
|
|
68a053bf5d | ||
|
|
61e8300e84 | ||
|
|
a01d717b01 | ||
|
|
ef00cbec7a | ||
|
|
ba4d163046 | ||
|
|
d44512f065 | ||
|
|
644437a35c | ||
|
|
86a09910c8 | ||
|
|
324c9b9e91 | ||
|
|
18835008d7 | ||
|
|
424156e8c2 | ||
|
|
58652ed54f | ||
|
|
7fe797c21d | ||
|
|
8a44aff0ae | ||
|
|
b350409a87 | ||
|
|
02c26cf74c | ||
|
|
10ceab95eb | ||
|
|
19eab3c0b4 | ||
|
|
1de4183ac9 | ||
|
|
8468cb546d | ||
|
|
1ef9d61701 | ||
|
|
8b74db943e | ||
|
|
a25d0284bb | ||
|
|
6c35c7744d | ||
|
|
d015207763 | ||
|
|
309c06aa95 | ||
|
|
48454e8f09 | ||
|
|
dce3e3d9b2 | ||
|
|
bf92570214 | ||
|
|
f308199746 | ||
|
|
33a9e93a8b | ||
|
|
7e8d54b030 | ||
|
|
44e5a963ec | ||
|
|
84b141fb03 | ||
|
|
549631cc92 | ||
|
|
79faa669af | ||
|
|
ef314ac176 | ||
|
|
1994796f5f | ||
|
|
c5c03e9217 | ||
|
|
ae802aa241 | ||
|
|
45b4a7eaf9 | ||
|
|
2e82cb8bfe | ||
|
|
a8f0af8f9f | ||
|
|
b01294dfbd | ||
|
|
075cd80895 | ||
|
|
17402b185f | ||
|
|
ecfc4182fb | ||
|
|
997b403b4c | ||
|
|
b66f07ff23 | ||
|
|
3c407df2fc | ||
|
|
65b88d4550 | ||
|
|
5224281992 | ||
|
|
ed3f230d16 | ||
|
|
37fb055954 | ||
|
|
531c4785ec | ||
|
|
5897e8155e | ||
|
|
61ad04c423 | ||
|
|
10e8774143 | ||
|
|
0423b4c8b6 | ||
|
|
c01f524e80 | ||
|
|
89c4916d11 | ||
|
|
f25a4c7159 | ||
|
|
48bda22cbc | ||
|
|
43df7485f8 | ||
|
|
2c5d302d8e | ||
|
|
02cca7dc25 | ||
|
|
0127603ce4 | ||
|
|
78cb67eebf | ||
|
|
d7d0f551e2 | ||
|
|
6027f4759b | ||
|
|
076d6c901a | ||
|
|
a48dc02c2e | ||
|
|
2ab4c72852 | ||
|
|
b1ace294eb | ||
|
|
1e505759d7 | ||
|
|
2082afff78 | ||
|
|
fb0007845a | ||
|
|
d7fc0eb6f0 | ||
|
|
8bfb08e555 | ||
|
|
abc9d658a2 | ||
|
|
0e5401939e | ||
|
|
6e69cd582f | ||
|
|
54072e33c8 | ||
|
|
08c38cb59a | ||
|
|
235fb0c12b | ||
|
|
8ac3106fb6 | ||
|
|
5b5284cd6a | ||
|
|
08565fa0e3 | ||
|
|
0bd4793492 | ||
|
|
04b8036e32 | ||
|
|
0eb36d786b | ||
|
|
195c206669 | ||
|
|
fbf0c54b71 | ||
|
|
9a24528e3f | ||
|
|
775df5da16 | ||
|
|
7604df2686 | ||
|
|
17ab4518fd | ||
|
|
bb9f7fa623 | ||
|
|
c3e674ed7d | ||
|
|
5f777dcbe8 | ||
|
|
6400a8cb7e | ||
|
|
7aabe781cb | ||
|
|
5cdbdf0303 | ||
|
|
9d6a971612 | ||
|
|
dc1d83925e | ||
|
|
f8ec58745e | ||
|
|
85cb44de99 | ||
|
|
c10e761b0d | ||
|
|
6c8ab49eec | ||
|
|
9e9e6befb3 | ||
|
|
f470d833b7 | ||
|
|
06f48133bb | ||
|
|
8ebda35e84 | ||
|
|
4fb34fc66a | ||
|
|
26e3588d79 | ||
|
|
e50834fd82 | ||
|
|
0b13c7b6fe | ||
|
|
b96e205f14 | ||
|
|
7ae3eb5b10 | ||
|
|
9e39ce6f1c | ||
|
|
1122893a50 | ||
|
|
ffdd6878a3 | ||
|
|
4ef5e73ae6 | ||
|
|
69f3db483e | ||
|
|
2fb1df6623 | ||
|
|
6202251a6c | ||
|
|
caaf067615 | ||
|
|
18d9847829 | ||
|
|
505ccecbc8 | ||
|
|
50fc3b5569 | ||
|
|
8f4bdc77cc | ||
|
|
902f198d46 | ||
|
|
3d10ea2d16 | ||
|
|
0f73329ce0 | ||
|
|
1fd115b699 | ||
|
|
58fc3e7ea9 | ||
|
|
c0ed05c6f6 | ||
|
|
ca952e8937 | ||
|
|
08c06b05cf | ||
|
|
284432cf4f | ||
|
|
c502b14ce6 | ||
|
|
707655ced2 |
19
Makefile
19
Makefile
@@ -14,25 +14,6 @@ image:
|
||||
noobs:
|
||||
./scripts/image noobs
|
||||
|
||||
amlpkg:
|
||||
./scripts/image amlpkg
|
||||
|
||||
# legacy sequential build targets
|
||||
system-st:
|
||||
./scripts/image_st
|
||||
|
||||
release-st:
|
||||
./scripts/image_st release
|
||||
|
||||
image-st:
|
||||
./scripts/image_st mkimage
|
||||
|
||||
noobs-st:
|
||||
./scripts/image_st noobs
|
||||
|
||||
amlpkg-st:
|
||||
./scripts/image_st amlpkg
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIRS)/* $(BUILD_DIRS)/.stamps
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ safe_remove() {
|
||||
|
||||
[ -z "${path}" ] && return 0
|
||||
|
||||
if [ -f "${path}" -o -d "${path}" ]; then
|
||||
if [ -e "${path}" -o -L "${path}" ]; then
|
||||
rm -r "${path}"
|
||||
elif [ -n "${PKG_NAME}" ]; then
|
||||
print_color CLR_WARNING "safe_remove: path does not exist: [${PKG_NAME}]: ${path}\n"
|
||||
@@ -242,12 +242,12 @@ setup_toolchain() {
|
||||
fi
|
||||
|
||||
# parallel
|
||||
if ! flag_enabled "parallel" "yes"; then
|
||||
NINJA_OPTS="$NINJA_OPTS -j1"
|
||||
export MAKEFLAGS="-j1"
|
||||
else
|
||||
if flag_enabled "parallel" "yes"; then
|
||||
NINJA_OPTS="$NINJA_OPTS -j$CONCURRENCY_MAKE_LEVEL"
|
||||
export MAKEFLAGS="-j$CONCURRENCY_MAKE_LEVEL"
|
||||
else
|
||||
NINJA_OPTS="$NINJA_OPTS -j1"
|
||||
export MAKEFLAGS="-j1"
|
||||
fi
|
||||
|
||||
# verbose flag
|
||||
@@ -357,11 +357,9 @@ setup_toolchain() {
|
||||
create_meson_conf() {
|
||||
local endian root properties
|
||||
case "$1" in
|
||||
target|init) endian="little"
|
||||
root="$SYSROOT_PREFIX/usr"
|
||||
target|init) root="$SYSROOT_PREFIX/usr"
|
||||
;;
|
||||
host|bootstrap) endian="big"
|
||||
root="$TOOLCHAIN"
|
||||
host|bootstrap) root="$TOOLCHAIN"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -380,12 +378,14 @@ llvm-config = '$SYSROOT_PREFIX/usr/bin/llvm-config-host'
|
||||
system = 'linux'
|
||||
cpu_family = '$TARGET_ARCH'
|
||||
cpu = '$TARGET_SUBARCH'
|
||||
endian = '$endian'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
root = '$root'
|
||||
$(python -c "import os; print('c_args = {}'.format([x for x in os.getenv('CFLAGS').split()]))")
|
||||
$(python -c "import os; print('c_link_args = {}'.format([x for x in os.getenv('LDFLAGS').split()]))")
|
||||
$(python -c "import os; print('cpp_args = {}'.format([x for x in os.getenv('CXXFLAGS').split()]))")
|
||||
$(python -c "import os; print('cpp_link_args = {}'.format([x for x in os.getenv('LDFLAGS').split()]))")
|
||||
${!properties}
|
||||
EOF
|
||||
}
|
||||
@@ -714,7 +714,7 @@ get_pkg_variable() {
|
||||
|
||||
# get package's build dir
|
||||
get_build_dir() {
|
||||
local _PKG_NAME="$(get_pkg_variable "$1" PKG_NAME)" _PKG_VERSION="$(get_pkg_version "$1")"
|
||||
local _PKG_NAME="${1%:*}" _PKG_VERSION="$(get_pkg_version "$1")"
|
||||
if [ -n "$_PKG_NAME" -a -n "$_PKG_VERSION" ]; then
|
||||
echo $BUILD/${_PKG_NAME}-${_PKG_VERSION}
|
||||
fi
|
||||
@@ -989,8 +989,10 @@ kernel_config_path() {
|
||||
$pkg_linux_dir/config/$config_name \
|
||||
; do
|
||||
[[ $cfg =~ /devices//linux/ ]] && continue
|
||||
[ -f "$cfg" ] && echo "$cfg" && break
|
||||
[ -f "$cfg" ] && echo "$cfg" && return
|
||||
done
|
||||
|
||||
die "ERROR: Unable to locate kernel config for ${LINUX} - looking for ${config_name}"
|
||||
}
|
||||
|
||||
kernel_make() {
|
||||
@@ -1155,6 +1157,8 @@ done
|
||||
}
|
||||
|
||||
install_addon_files() {
|
||||
mkdir -p "$1"
|
||||
|
||||
install_addon_source "$1"
|
||||
install_addon_images "$1"
|
||||
create_addon_xml "$1"
|
||||
@@ -1190,7 +1194,7 @@ add_user() {
|
||||
|
||||
mkdir -p ${INSTALL}/usr/cache
|
||||
touch ${INSTALL}/usr/cache/shadow
|
||||
ln -sf /storage/.cache/shadow ${INSTALL}/etc/shadow
|
||||
ln -sf /storage/.cache/shadow ${INSTALL}/etc/shadow 2>/dev/null || true
|
||||
|
||||
PASSWORD="$2"
|
||||
if [ "$PASSWORD" = "x" ]; then
|
||||
@@ -1235,6 +1239,8 @@ enable_service() {
|
||||
|
||||
|
||||
### MULTI-THREADED FUNCTION HELPERS ###
|
||||
# Test MTWITHLOCKS so that these functions are a no-op during non-multithreaded builds.
|
||||
|
||||
# Prevent concurrent modifications to a package (unpack) or
|
||||
# package:target (install/build).
|
||||
#
|
||||
@@ -1245,7 +1251,7 @@ pkg_lock() {
|
||||
|
||||
local pkg="$1" task="$2" parent_pkg="$3"
|
||||
local this_job="${MTJOBID}"
|
||||
local lock_job lock_seq lock_task lock_pkg locked=no
|
||||
local lock_job lock_seq lock_task lock_pkg locked=no idwidth
|
||||
local fail_seq
|
||||
|
||||
exec 98>"${THREAD_CONTROL}/locks/${pkg}.${task}"
|
||||
@@ -1256,13 +1262,14 @@ pkg_lock() {
|
||||
done
|
||||
|
||||
if [ "${locked}" = "no" -a "${lock_job}/${lock_seq}" != "${this_job}/${PARALLEL_SEQ}" ]; then
|
||||
pkg_lock_status "STALLED" "${parent_pkg}" "${task}" "$(printf "waiting on [%02d] %s %s" ${lock_job} "${lock_task}" "${lock_pkg}")"
|
||||
[ "${THREADCOUNT}" = "0" ] && idwidth=${#MTMAXJOBS} || idwidth=2
|
||||
pkg_lock_status "STALLED" "${parent_pkg}" "${task}" "$(printf "waiting on [%0*d] %s %s" ${idwidth} ${lock_job} "${lock_task}" "${lock_pkg}")"
|
||||
flock --exclusive 98
|
||||
fi
|
||||
|
||||
# As we now have the lock, if .failed still exists then a previous process must have failed
|
||||
if [ -f "${THREAD_CONTROL}/locks/${pkg}.${task}.failed" ]; then
|
||||
fail_seq="$(cat "${THREAD_CONTROL}/locks/${pkg}.${task}.failed")"
|
||||
fail_seq="$(< "${THREAD_CONTROL}/locks/${pkg}.${task}.failed")"
|
||||
print_color CLR_ERROR "FAILURE: ${pkg}.${task}.failed exists, a previous dependency process has failed (seq: ${fail_seq})\n"
|
||||
if [ -d "${THREAD_CONTROL}/logs" ]; then
|
||||
cat <<EOF
|
||||
@@ -1284,13 +1291,15 @@ pkg_lock_status() {
|
||||
[ "${MTWITHLOCKS}" != "yes" ] && return 0
|
||||
|
||||
local status="$1" pkg="$2" task="$3" msg="$4"
|
||||
local this_job="${MTJOBID}" line
|
||||
local this_job="${MTJOBID}" line idwidth
|
||||
|
||||
[ "${THREADCOUNT}" = "0" ] && idwidth=${#MTMAXJOBS} || idwidth=2
|
||||
|
||||
(
|
||||
flock --exclusive 94
|
||||
|
||||
printf -v line "%s: <%05d> [%02d/%0*d] %-7s %-7s %-35s" \
|
||||
"$(date +%Y-%m-%d\ %H:%M:%S.%N)" $$ ${this_job} ${#MTMAXJOBS} ${PARALLEL_SEQ:-0} "${status}" "${task}" "${pkg}"
|
||||
printf -v line "%s: <%06d> [%0*d/%0*d] %-7s %-7s %-35s" \
|
||||
"$(date +%Y-%m-%d\ %H:%M:%S.%N)" $$ ${idwidth} ${this_job} ${#MTMAXJOBS} ${PARALLEL_SEQ:-0} "${status}" "${task}" "${pkg}"
|
||||
[ -n "${msg}" ] && line+=" (${msg})"
|
||||
|
||||
echo "${line}" >>"${THREAD_CONTROL}/history"
|
||||
@@ -1316,19 +1325,25 @@ update_dashboard() {
|
||||
|
||||
local status="$1" pkg="$2" task="$3" msg="$4"
|
||||
local line sedline preamble num elapsed projdevarch
|
||||
local boldred boldgreen boldyellow endcolor
|
||||
local boldred boldgreen boldyellow endcolor idwidth
|
||||
|
||||
sedline=$((MTJOBID + 2))
|
||||
|
||||
num=$(cat "${THREAD_CONTROL}/status" | wc -l)
|
||||
while [ ${num} -lt ${sedline} ]; do echo "" >>"${THREAD_CONTROL}/status"; num=$((num + 1)); done
|
||||
[ "${THREADCOUNT}" = "0" ] && idwidth=${#MTMAXJOBS} || idwidth=2
|
||||
|
||||
num=$(($(cat "${THREAD_CONTROL}/progress.prev") + 1))
|
||||
num=$(< "${THREAD_CONTROL}/status.max")
|
||||
if [ ${num} -lt ${sedline} ]; then
|
||||
echo ${sedline} >"${THREAD_CONTROL}/status.max"
|
||||
for i in $(seq $((num + 1)) ${sedline}); do echo "" >>"${THREAD_CONTROL}/status"; done
|
||||
fi
|
||||
|
||||
num=$(< "${THREAD_CONTROL}/progress.prev")
|
||||
projdevarch="${PROJECT}/"
|
||||
[ -n "${DEVICE}" ] && projdevarch+="${DEVICE}/"
|
||||
projdevarch+="${TARGET_ARCH}"
|
||||
[ -n "${BUILD_SUFFIX}" ] && projdevarch+=", ${BUILD_SUFFIX}"
|
||||
TZ=UTC0 printf -v elapsed "%(%H:%M:%S)T" $(($(date +%s) - MTBUILDSTART))
|
||||
printf -v preamble "%s Dashboard (%s) - %d of %d jobs completed, %s elapsed" "${DISTRONAME}" "${projdevarch}" ${num} ${MTMAXJOBS} "${elapsed}"
|
||||
printf -v preamble "%s Dashboard (%s) - %d of %d jobs completed, %s elapsed" "${DISTRONAME}" "${projdevarch}" $((num + 1)) ${MTMAXJOBS} "${elapsed}"
|
||||
printf -v preamble "%b%-105s %s" "\e[2J\e[0;0H" "${preamble//\//\\/}" "$(date "+%Y-%m-%d %H:%M:%S")"
|
||||
|
||||
if [ "${DISABLE_COLORS}" != "yes" ]; then
|
||||
@@ -1347,7 +1362,7 @@ update_dashboard() {
|
||||
esac
|
||||
fi
|
||||
|
||||
printf -v line "[%02d\/%0*d] %b%-7s%b %-7s %-35s" ${MTJOBID} ${#MTMAXJOBS} ${PARALLEL_SEQ:-0} "${color}" "${status//\//\\/}" "${endcolor}" "${task}" "${pkg}"
|
||||
printf -v line "[%0*d\/%0*d] %b%-7s%b %-7s %-35s" ${idwidth} ${MTJOBID} ${#MTMAXJOBS} ${PARALLEL_SEQ:-0} "${color}" "${status//\//\\/}" "${endcolor}" "${task}" "${pkg}"
|
||||
[ -n "${msg}" ] && line+=" ${msg//\//\\/}"
|
||||
|
||||
sed -e "1s/.*/${preamble}/;${sedline}s/.*/${line}/" -i "${THREAD_CONTROL}/status"
|
||||
@@ -1355,13 +1370,12 @@ update_dashboard() {
|
||||
|
||||
# Thread concurrency helpers to avoid concurrency issues with some code,
|
||||
# eg. when Python installs directly into $TOOLCHAIN.
|
||||
# Test MTJOBID so that these functions are a no-op during non-multithreaded builds.
|
||||
acquire_exclusive_lock() {
|
||||
[ "${MTWITHLOCKS}" != "yes" ] && return 0
|
||||
|
||||
local pkg="$1" task="$2" lockfile="${3:-global}"
|
||||
local this_job="${MTJOBID}"
|
||||
local lock_job lock_seq lock_task lock_pkg locked=no
|
||||
local lock_job lock_seq lock_task lock_pkg locked=no idwidth
|
||||
|
||||
exec 96>"${THREAD_CONTROL}/locks/.mutex.${lockfile}"
|
||||
while [ : ]; do
|
||||
@@ -1371,7 +1385,8 @@ acquire_exclusive_lock() {
|
||||
done
|
||||
|
||||
if [ "${locked}" = "no" -a "${lock_job}/${lock_seq}" != "${this_job}/${PARALLEL_SEQ}" ]; then
|
||||
pkg_lock_status "MUTEX/W" "${pkg}" "${task}" "$(printf "mutex: %s; waiting on [%02d] %s %s" "${lockfile}" ${lock_job} "${lock_task}" "${lock_pkg}")"
|
||||
[ "${THREADCOUNT}" = "0" ] && idwidth=${#MTMAXJOBS} || idwidth=2
|
||||
pkg_lock_status "MUTEX/W" "${pkg}" "${task}" "$(printf "mutex: %s; waiting on [%0*d] %s %s" "${lockfile}" ${idwidth} ${lock_job} "${lock_task}" "${lock_pkg}")"
|
||||
flock --exclusive 96
|
||||
fi
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ get_graphicdrivers() {
|
||||
fi
|
||||
|
||||
if listcontains "${GRAPHIC_DRIVERS}" "vc4"; then
|
||||
GALLIUM_DRIVERS+=" vc4"
|
||||
GALLIUM_DRIVERS+=" vc4 v3d kmsro"
|
||||
V4L2_SUPPORT="yes"
|
||||
VAAPI_SUPPORT="no"
|
||||
VDPAU_SUPPORT="no"
|
||||
|
||||
@@ -107,8 +107,9 @@ package_worker() {
|
||||
(
|
||||
flock --exclusive 95
|
||||
[ ${result} -eq 0 ] && status="DONE" || status="FAIL"
|
||||
num=$(($(cat "${THREAD_CONTROL}/progress") + 1))
|
||||
num=$(< "${THREAD_CONTROL}/progress")
|
||||
mv "${THREAD_CONTROL}/progress" "${THREAD_CONTROL}/progress.prev"
|
||||
num=$((num + 1))
|
||||
echo ${num} >"${THREAD_CONTROL}/progress"
|
||||
printf "[%0*d/%0*d] [%-4s] %-7s %s\n" ${#jobs} ${num} ${#jobs} ${jobs} "${status}" "${task}" "${pkgname}" >&2
|
||||
) 95>"${THREAD_CONTROL}/locks/.progress"
|
||||
@@ -143,17 +144,19 @@ start_multithread_build() {
|
||||
mkdir -p "${THREAD_CONTROL}/locks"
|
||||
echo -1 >"${THREAD_CONTROL}/progress.prev"
|
||||
echo 0 >"${THREAD_CONTROL}/progress"
|
||||
echo 0 >"${THREAD_CONTROL}/status.max"
|
||||
touch "${THREAD_CONTROL}/status"
|
||||
|
||||
[ "${THREADCOUNT}" = "0" ] && THREADCOUNT=1
|
||||
# Increase file descriptors if building one thread/package
|
||||
[ "${THREADCOUNT}" = "0" ] && ulimit -n ${ULIMITN:-10240}
|
||||
|
||||
# Bootstrap GNU parallel
|
||||
$SCRIPTS/build parallel:host 2>&1 || die "Unable to bootstrap parallel package"
|
||||
MTWITHLOCKS=no $SCRIPTS/build parallel:host 2>&1 || die "Unable to bootstrap parallel package"
|
||||
|
||||
# if number of detected slots is 1 then don't bother using inter-process locks as this is a sequential build
|
||||
# determine number of available slots for the given THREADCOUNT - optimise logging for single threaded builds
|
||||
[ $(seq 1 32 | ${TOOLCHAIN}/bin/parallel --plain --no-notice --max-procs ${THREADCOUNT} echo {%} | sort -n | tail -1) -eq 1 ] && singlethread=yes || singlethread=no
|
||||
|
||||
# create a single log file by default if not using locks (single build process), or the builder is a masochist
|
||||
# create a single log file by default for a single threaded build (or the builder is a masochist)
|
||||
if [ "${singlethread}" = "yes" -a "${ONELOG,,}" != "no" ] || [ "${ONELOG,,}" = "yes" ]; then
|
||||
buildopts+=" --ungroup"
|
||||
else
|
||||
@@ -172,6 +175,8 @@ start_multithread_build() {
|
||||
${SCRIPTS}/genbuildplan.py --no-reorder --show-wants --build ${@} > "${THREAD_CONTROL}"/plan || result=1
|
||||
|
||||
if [ ${result} -eq 0 ]; then
|
||||
save_build_config
|
||||
|
||||
cat "${THREAD_CONTROL}"/plan | awk '{print $1 " " $2}' | \
|
||||
MTBUILDSTART=$(date +%s) MTWITHLOCKS=yes ${TOOLCHAIN}/bin/parallel \
|
||||
--plain --no-notice --max-procs ${THREADCOUNT} --joblog="${THREAD_CONTROL}/joblog" --plus ${buildopts} \
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"description": "@DESCRIPTION@",
|
||||
"username": "root",
|
||||
"password": "@ROOT_PASSWORD@",
|
||||
"supported_models": [@NOOBS_SUPPORTED_MODELS@],
|
||||
"supported_hex_revisions": "@NOOBS_HEX@"
|
||||
"supported_hex_revisions": "@NOOBS_HEX@",
|
||||
"supported_models": [@NOOBS_SUPPORTED_MODELS@]
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ show_config() {
|
||||
config_message="$config_message\n $dashes$dashes"
|
||||
|
||||
config_message="$config_message\n - Remote support:\t\t\t $REMOTE_SUPPORT"
|
||||
config_message="$config_message\n - ATV Remote support:\t\t\t $ATVCLIENT_SUPPORT"
|
||||
config_message="$config_message\n - CEC Adapter support:\t\t\t $CEC_SUPPORT"
|
||||
config_message="$config_message\n - CEC Framework support:\t\t $CEC_FRAMEWORK_SUPPORT"
|
||||
config_message="$config_message\n - Kodi Joystick support:\t\t $JOYSTICK_SUPPORT"
|
||||
@@ -105,10 +104,6 @@ show_config() {
|
||||
config_message="$config_message\n - OEM Support:\t\t\t\t $OEM_SUPPORT"
|
||||
config_message="$config_message\n - Default ROOT Password:\t\t $ROOT_PASSWORD"
|
||||
config_message="$config_message\n - Bootloader:\t\t\t\t $BOOTLOADER"
|
||||
if [ "$BOOTLOADER" = "u-boot" ]; then
|
||||
config_message="$config_message\n - U-Boot configuration:\t\t $UBOOT_CONFIG"
|
||||
config_message="$config_message\n - U-Boot config file:\t\t $UBOOT_CONFIGFILE"
|
||||
fi
|
||||
config_message="$config_message\n - UDevil support:\t\t\t $UDEVIL"
|
||||
config_message="$config_message\n - Installer support:\t\t\t $INSTALLER_SUPPORT"
|
||||
for config_package in $ADDITIONAL_PACKAGES; do
|
||||
|
||||
@@ -140,9 +140,6 @@
|
||||
# build and install remote support (yes / no)
|
||||
REMOTE_SUPPORT="yes"
|
||||
|
||||
# build and install ATV IR remote support (yes / no)
|
||||
ATVCLIENT_SUPPORT="yes"
|
||||
|
||||
# build and install Joystick support (yes / no)
|
||||
JOYSTICK_SUPPORT="yes"
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
OS_VERSION="9.1"
|
||||
|
||||
# ADDON_VERSION: Addon version
|
||||
ADDON_VERSION="9.1"
|
||||
ADDON_VERSION="9.1.901"
|
||||
|
||||
@@ -7,6 +7,7 @@ PKG_SHA256="d007f89ae8a2543a53525c74359b65b36412fa84b3349f1400be6dcf409fafef"
|
||||
PKG_LICENSE="Custom"
|
||||
PKG_SITE="http://www.icu-project.org"
|
||||
PKG_URL="http://download.icu-project.org/files/icu4c/${PKG_VERSION}/icu4c-${PKG_VERSION//./_}-src.tgz"
|
||||
PKG_DEPENDS_HOST="gcc:host"
|
||||
PKG_DEPENDS_TARGET="toolchain icu:host"
|
||||
PKG_LONGDESC="International Components for Unicode library."
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ PKG_SHA256="5c0133ec4e228e41bdf52f726d271a2d821499c2ab97afd3aa3d6cf43efcdc83"
|
||||
PKG_LICENSE="GPL2"
|
||||
PKG_SITE="https://freedesktop.org/wiki/Software/shared-mime-info/"
|
||||
PKG_URL="http://freedesktop.org/~hadess/shared-mime-info-$PKG_VERSION.tar.xz"
|
||||
PKG_DEPENDS_TARGET="toolchain libxml2"
|
||||
PKG_DEPENDS_TARGET="toolchain glib libxml2"
|
||||
PKG_LONGDESC="The shared-mime-info package contains the core database of common types."
|
||||
PKG_BUILD_FLAGS="-parallel"
|
||||
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="comskip"
|
||||
PKG_VERSION="6030aa0d3b589161ec96c6c986c48aa826fb9f72"
|
||||
PKG_SHA256="df0b4b0354aef5acc17e4e94a20a396fa69c474af7579c94aad09dd490e0ee38"
|
||||
PKG_VERSION="14dffb241fac0126e261d4ff5bf929479e2592b6"
|
||||
PKG_SHA256="025bfd532aa6ccfd513f4d88f34ec95a9b5a34c763ed13c17433b36415e5bfd4"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://www.kaashoek.com/comskip/"
|
||||
PKG_URL="https://github.com/erikkaashoek/Comskip/archive/${PKG_VERSION}.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain argtable2 ffmpeg"
|
||||
PKG_DEPENDS_TARGET="toolchain argtable2 ffmpeg gnutls"
|
||||
PKG_LONGDESC="Comskip detects commercial breaks from a video stream. It can be used for post-processing recordings."
|
||||
PKG_TOOLCHAIN="autotools"
|
||||
|
||||
pre_configure_target() {
|
||||
LDFLAGS="$LDFLAGS -ldl"
|
||||
LDFLAGS+=" -ldl"
|
||||
|
||||
export argtable2_CFLAGS="-I$(get_build_dir argtable2)/src"
|
||||
export argtable2_LIBS="-L$(get_build_dir argtable2)/src/.libs -largtable2"
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="containerd"
|
||||
PKG_VERSION="1.2.6"
|
||||
PKG_SHA256="f2d578b743fb9faa5b3477b7cf4b33d00501087043a53b27754f14bbe741f891"
|
||||
PKG_VERSION="1.2.7"
|
||||
PKG_SHA256="7179c709a0d187708a1eeddcbdecd7206b2c642dc4413bcdb049cd6b38d06801"
|
||||
PKG_LICENSE="APL"
|
||||
PKG_SITE="https://containerd.tools/"
|
||||
PKG_URL="https://github.com/containerd/containerd/archive/v$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="krb5"
|
||||
PKG_VERSION="1.16.2-final"
|
||||
PKG_SHA256="92f62e5a54404d22aa2a7eee9fba64d1be8d10d8dd3aa052e1799993208acce4"
|
||||
PKG_VERSION="1.17-final"
|
||||
PKG_SHA256="bd170f6aadea5d753cc9a93a3a915a5bde07bd3d294a00651ed647dcf964e867"
|
||||
PKG_LICENSE="MIT"
|
||||
PKG_SITE="http://web.mit.edu/kerberos/"
|
||||
PKG_URL="https://github.com/krb5/krb5/archive/krb5-$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="lttng-ust"
|
||||
PKG_VERSION="2.10.2"
|
||||
PKG_SHA256="015452be6f94e4468315d0478cd5a4d01d9e52672bcea122b4ff7426198d5803"
|
||||
PKG_VERSION="2.10.4"
|
||||
PKG_SHA256="9df458fbfeac5a380672751decbd9b57356075acbfe106cb8820e803a94a0d96"
|
||||
PKG_LICENSE="LGPLv2.1"
|
||||
PKG_SITE="https://lttng.org/"
|
||||
PKG_URL="https://github.com/lttng/lttng-ust/archive/v$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="userspace-rcu"
|
||||
PKG_VERSION="0.10.1"
|
||||
PKG_SHA256="4ddbca9927b459b7a295dec612cf43df5886d398161d50c59d0097995e368a3b"
|
||||
PKG_VERSION="0.11.1"
|
||||
PKG_SHA256="a0ed8995edfbeac5f5eb2f152a8f3654040ecfc99a746bfe3da3bccf435b7d5d"
|
||||
PKG_LICENSE="LGPLv2.1"
|
||||
PKG_SITE="http://liburcu.org"
|
||||
PKG_URL="https://github.com/urcu/userspace-rcu/archive/v$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -10,14 +10,6 @@ PKG_URL="https://github.com/mighty-p/t2scan/archive/$PKG_VERSION.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain"
|
||||
PKG_LONGDESC="A small channel scan tool which generates DVB-T/T2 channels.conf files."
|
||||
|
||||
# aml 3.14 hack
|
||||
pre_configure_target() {
|
||||
if [ "$LINUX" = "amlogic-3.14" -o "$LINUX" = "amlogic-3.10" ]; then
|
||||
sed -i 's/DVB_HEADER=0/DVB_HEADER=1/g' $PKG_BUILD/configure*
|
||||
sed -i 's/HAS_DVB_API5=0/HAS_DVB_API5=1/g' $PKG_BUILD/configure*
|
||||
fi
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
:
|
||||
}
|
||||
|
||||
@@ -11,14 +11,6 @@ PKG_DEPENDS_TARGET="toolchain"
|
||||
PKG_LONGDESC="A channel scan tool which generates ATSC, DVB-C, DVB-S/S2 and DVB-T channels.conf files."
|
||||
PKG_TOOLCHAIN="autotools"
|
||||
|
||||
# aml 3.14 hack
|
||||
pre_configure_target() {
|
||||
if [ "$LINUX" = "amlogic-3.14" -o "$LINUX" = "amlogic-3.10" ]; then
|
||||
sed -i 's/DVB_HEADER=0/DVB_HEADER=1/g' $PKG_BUILD/configure*
|
||||
sed -i 's/HAS_DVB_API5=0/HAS_DVB_API5=1/g' $PKG_BUILD/configure*
|
||||
fi
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
:
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="imagemagick"
|
||||
PKG_VERSION="7.0.8-11"
|
||||
PKG_SHA256="95e4da5fa109bc8b59b5e7a54cdfcf1af3230067c95adf608ff21c08eca1de20"
|
||||
PKG_VERSION="7.0.8-60"
|
||||
PKG_SHA256="a0ffa621051aa66b4eec919761d1a741aefea8b993acc2425e3ed5855c540156"
|
||||
PKG_LICENSE="http://www.imagemagick.org/script/license.php"
|
||||
PKG_SITE="http://www.imagemagick.org/"
|
||||
PKG_URL="https://github.com/ImageMagick/ImageMagick/archive/$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="libvpx"
|
||||
PKG_VERSION="1.7.0"
|
||||
PKG_SHA256="1fec931eb5c94279ad219a5b6e0202358e94a93a90cfb1603578c326abfc1238"
|
||||
PKG_VERSION="1.8.0"
|
||||
PKG_SHA256="86df18c694e1c06cc8f83d2d816e9270747a0ce6abe316e93a4f4095689373f6"
|
||||
PKG_LICENSE="BSD"
|
||||
PKG_SITE="https://www.webmproject.org"
|
||||
PKG_URL="https://github.com/webmproject/libvpx/archive/v${PKG_VERSION}.tar.gz"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="x264"
|
||||
PKG_VERSION="545de2ffec6ae9a80738de1b2c8cf820249a2530"
|
||||
PKG_SHA256="74725cf7036b2c96387c2c014ef00d181942d00230f21e16277f11d2d9683adc"
|
||||
PKG_VERSION="d4099dd4c722f52c4f3c14575d7d39eb8fadb97f"
|
||||
PKG_SHA256="9b6688b81e13cf342fc9b6b7adf1759eebd300c243c0707566ffe7ea9f0ccc7e"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://www.videolan.org/developers/x264.html"
|
||||
PKG_URL="http://repo.or.cz/x264.git/snapshot/$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="x265"
|
||||
PKG_VERSION="2.9"
|
||||
PKG_SHA256="ebae687c84a39f54b995417c52a2fdde65a4e2e7ebac5730d251471304b91024"
|
||||
PKG_VERSION="3.0"
|
||||
PKG_SHA256="c5b9fc260cabbc4a81561a448f4ce9cad7218272b4011feabc3a6b751b2f0662"
|
||||
PKG_ARCH="x86_64"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://www.videolan.org/developers/x265.html"
|
||||
|
||||
@@ -19,7 +19,7 @@ if [ "$KODIPLAYER_DRIVER" == "bcm2835-driver" ]; then
|
||||
fi
|
||||
|
||||
if [ "$TARGET_ARCH" = "x86_64" ]; then
|
||||
PKG_DEPENDS_TARGET+=" nasm:host x265"
|
||||
PKG_DEPENDS_TARGET+=" nasm:host intel-vaapi-driver x265"
|
||||
fi
|
||||
|
||||
if [[ ! $TARGET_ARCH = arm ]] || target_has_feature neon; then
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="go"
|
||||
PKG_VERSION="1.12.3"
|
||||
PKG_SHA256="b710a65982e9001ef99a167cf6e8636e46ec36a10e487e7c1c7384cdcd6fcd7c"
|
||||
PKG_VERSION="1.12.6"
|
||||
PKG_SHA256="d61ff8fa5685b911653c8153de6e6501728ec3aee26a9d5a56880bab3120426b"
|
||||
PKG_LICENSE="BSD"
|
||||
PKG_SITE="https://golang.org"
|
||||
PKG_URL="https://github.com/golang/go/archive/${PKG_NAME}${PKG_VERSION}.tar.gz"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2019-present Peter Vicman (peter.vicman@gmail.com)
|
||||
|
||||
PKG_NAME="apache-ant"
|
||||
PKG_VERSION="1.10.6"
|
||||
PKG_SHA256="a4adf371696089e1730d4f55fd4d0c6f3784dea1eee402fcc981f2330f8d6fc1"
|
||||
PKG_LICENSE="Apache License 2.0"
|
||||
PKG_SITE="https://ant.apache.org/"
|
||||
PKG_URL="https://archive.apache.org/dist/ant/source/${PKG_NAME}-${PKG_VERSION}-src.tar.xz"
|
||||
PKG_DEPENDS_HOST="jdk-x86_64-zulu:host"
|
||||
PKG_LONGDESC="Apache Ant is a Java library and command-line tool that help building software."
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
make_host() {
|
||||
(
|
||||
export JAVA_HOME=$(get_build_dir jdk-x86_64-zulu)
|
||||
|
||||
./bootstrap.sh
|
||||
./bootstrap/bin/ant -f fetch.xml -Ddest=optional
|
||||
./build.sh -Ddist.dir=${PKG_BUILD}/binary dist
|
||||
|
||||
cp binary/bin/ant ${TOOLCHAIN}/bin
|
||||
cp -r binary/lib ${TOOLCHAIN}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2019-present Peter Vicman (peter.vicman@gmail.com)
|
||||
|
||||
PKG_NAME="jdk-aarch64-zulu"
|
||||
PKG_VERSION="8.38.0.162-1.8.0_212"
|
||||
PKG_SHA256="2afa6b9a86fea6f9275856506b5cc1efd8420f674c5e2dc3e1b04e140d6ad852"
|
||||
PKG_LICENSE="GPLv2"
|
||||
PKG_SITE="https://www.azul.com/products/zulu-embedded/"
|
||||
PKG_URL="http://cdn.azul.com/zulu-embedded/bin/zulu${PKG_VERSION%%-*}-ca-jdk${PKG_VERSION##*-}-linux_aarch64.tar.gz"
|
||||
PKG_LONGDESC="Zulu, the open Java(TM) platform from Azul Systems."
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
post_unpack() {
|
||||
rm -f $PKG_BUILD/src.zip
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2019-present Peter Vicman (peter.vicman@gmail.com)
|
||||
|
||||
PKG_NAME="jdk-arm-zulu"
|
||||
PKG_VERSION="8.38.0.163-1.8.0_212"
|
||||
PKG_SHA256="bc45f41eab6e55c4e740e980001831c5e35db85745ec61a2b110e816e1074715"
|
||||
PKG_LICENSE="GPLv2"
|
||||
PKG_SITE="https://www.azul.com/products/zulu-embedded/"
|
||||
PKG_URL="https://cdn.azul.com/zulu-embedded/bin/zulu${PKG_VERSION%%-*}-ca-jdk${PKG_VERSION##*-}-linux_aarch32hf.tar.gz"
|
||||
PKG_LONGDESC="Zulu, the open Java(TM) platform from Azul Systems."
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
post_unpack() {
|
||||
rm -f $PKG_BUILD/src.zip
|
||||
|
||||
# libbluray needs arm/server
|
||||
mv $PKG_BUILD/jre/lib/aarch32 $PKG_BUILD/jre/lib/arm
|
||||
mv $PKG_BUILD/jre/lib/arm/client $PKG_BUILD/jre/lib/arm/server
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2019-present Peter Vicman (peter.vicman@gmail.com)
|
||||
|
||||
PKG_NAME="jdk-x86_64-zulu"
|
||||
PKG_VERSION="8.38.0.13-8.0.212"
|
||||
PKG_SHA256="568e7578f1b20b1e62a8ed2c374bad4eb0e75d221323ccfa6ba8d7bc56cf33cf"
|
||||
PKG_LICENSE="GPLv2"
|
||||
PKG_SITE="https://www.azul.com/products/zulu-enterprise/"
|
||||
PKG_URL="https://cdn.azul.com/zulu/bin/zulu${PKG_VERSION%%-*}-ca-jdk${PKG_VERSION##*-}-linux_x64.tar.gz"
|
||||
PKG_LONGDESC="Zulu, the open Java(TM) platform from Azul Systems."
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
post_unpack() {
|
||||
rm -f $PKG_BUILD/src.zip
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
. $(get_pkg_directory libXinerama)/package.mk
|
||||
|
||||
PKG_NAME="jre-libXinerama"
|
||||
PKG_LONGDESC="libXinerama for JRE"
|
||||
PKG_URL=""
|
||||
PKG_DEPENDS_UNPACK+=" libXinerama"
|
||||
|
||||
PKG_CONFIGURE_OPTS_TARGET+=" --disable-static --enable-shared"
|
||||
|
||||
unpack() {
|
||||
mkdir -p $PKG_BUILD
|
||||
tar --strip-components=1 -xf $SOURCES/${PKG_NAME:4}/${PKG_NAME:4}-$PKG_VERSION.tar.bz2 -C $PKG_BUILD
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
:
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
. $(get_pkg_directory libbluray)/package.mk
|
||||
|
||||
PKG_NAME="jre-libbluray"
|
||||
PKG_DEPENDS_TARGET+=" jdk-x86_64-zulu:host apache-ant:host"
|
||||
PKG_LONGDESC="libbluray jar for BD-J menus"
|
||||
PKG_URL=""
|
||||
PKG_DEPENDS_UNPACK+=" libbluray"
|
||||
PKG_PATCH_DIRS+=" $(get_pkg_directory libbluray)/patches"
|
||||
|
||||
unpack() {
|
||||
mkdir -p $PKG_BUILD
|
||||
tar --strip-components=1 -xf $SOURCES/${PKG_NAME:4}/${PKG_NAME:4}-$PKG_VERSION.tar.bz2 -C $PKG_BUILD
|
||||
}
|
||||
|
||||
pre_configure_target() {
|
||||
# build also jar
|
||||
PKG_CONFIGURE_OPTS_TARGET="${PKG_CONFIGURE_OPTS_TARGET/disable-bdjava-jar/enable-bdjava-jar}"
|
||||
}
|
||||
|
||||
make_target() {
|
||||
(
|
||||
export JAVA_HOME="$(get_build_dir jdk-x86_64-zulu)"
|
||||
|
||||
make all-local
|
||||
)
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
:
|
||||
}
|
||||
@@ -26,16 +26,14 @@ pre_configure_target() {
|
||||
export ac_cv_path_LIBUSB_CONFIG=$SYSROOT_PREFIX/usr/bin/libusb-config
|
||||
}
|
||||
|
||||
post_make_target() {
|
||||
makeinstall_target() {
|
||||
# copy necessary libs and headers to build serdisplib support
|
||||
# into the driver glcd from lcdproc
|
||||
mkdir -p $SYSROOT_PREFIX/usr/include/serdisplib
|
||||
cp include/serdisplib/*.h $SYSROOT_PREFIX/usr/include/serdisplib
|
||||
mkdir -p $SYSROOT_PREFIX/usr/lib
|
||||
cp lib/libserdisp.so* $SYSROOT_PREFIX/usr/lib
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
mkdir -p $INSTALL/usr/lib
|
||||
cp lib/libserdisp.so* $INSTALL/usr/lib
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="libnetwork"
|
||||
PKG_VERSION="4725f2163fb214a6312f3beae5991f838ec36326"
|
||||
PKG_SHA256="049bddc1e584f30c29e0fed8716b3c7023d4bb31789d7c3aa48d17b979f1522b"
|
||||
PKG_VERSION="e7933d41e7b206756115aa9df5e0599fc5169742"
|
||||
PKG_SHA256="b9695c4d7711487543b2eff8ca74cc2deb9828f7f4582196324d39d20eab3855"
|
||||
PKG_LICENSE="APL"
|
||||
PKG_SITE="https://github.com/docker/libnetwork"
|
||||
PKG_URL="https://github.com/docker/libnetwork/archive/${PKG_VERSION}.tar.gz"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="pyalsaaudio"
|
||||
PKG_VERSION="0.8.4"
|
||||
PKG_SHA256="84e8f8da544d7f4bd96479ce4a237600077984d9be1d7f16c1d9a492ecf50085"
|
||||
PKG_LICENSE="PSF"
|
||||
PKG_SITE="http://larsimmisch.github.io/pyalsaaudio/"
|
||||
PKG_URL="https://files.pythonhosted.org/packages/source/${PKG_NAME:0:1}/$PKG_NAME/$PKG_NAME-$PKG_VERSION.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain Python2 distutilscross:host alsa-lib"
|
||||
PKG_LONGDESC="ALSA bindings"
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
make_target() {
|
||||
export LDSHARED="$CC -shared"
|
||||
export PYTHONXCPREFIX="$SYSROOT_PREFIX/usr"
|
||||
python setup.py build --cross-compile
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
python setup.py install --root=$INSTALL --prefix=/usr
|
||||
find $INSTALL/usr/lib -name "*.py" -exec rm -rf "{}" ";"
|
||||
rm -rf $INSTALL/usr/lib/python*/site-packages/*.egg-info \
|
||||
$INSTALL/usr/lib/python*/site-packages/*/tests
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="rust"
|
||||
PKG_VERSION="1.31.1"
|
||||
PKG_VERSION="1.36.0"
|
||||
PKG_LICENSE="MIT"
|
||||
PKG_SITE="https://www.rust-lang.org"
|
||||
PKG_DEPENDS_TARGET="toolchain rustup.rs"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="rustup.rs"
|
||||
PKG_VERSION="1.16.0"
|
||||
PKG_SHA256="8c4ffeda2088dbdd5ea2eac8acef5ddd57dfcfe1f06a503e3da790f93161e1a6"
|
||||
PKG_VERSION="1.18.3"
|
||||
PKG_SHA256="9a2ae2c85bbbfc838b25d86d049bc677532950d78765725beabb8a61df1c2710"
|
||||
PKG_LICENSE="MIT"
|
||||
PKG_SITE="https://www.rust-lang.org"
|
||||
PKG_URL="https://github.com/rust-lang-nursery/rustup.rs/archive/$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv)
|
||||
# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="libzip"
|
||||
PKG_VERSION="0.11.2"
|
||||
@@ -7,7 +8,7 @@ PKG_SHA256="7cfbbc2c540e154b933b6e9ec781e2671086bd8114eb744ae1a1ade34d2bb6bb"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://www.nih.at/libzip/"
|
||||
PKG_URL="http://www.nih.at/libzip/${PKG_NAME}-${PKG_VERSION}.tar.xz"
|
||||
PKG_DEPENDS_TARGET="toolchain"
|
||||
PKG_DEPENDS_TARGET="toolchain zlib"
|
||||
PKG_LONGDESC="A C library for reading, creating, and modifying zip archives."
|
||||
PKG_TOOLCHAIN="configure"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ PKG_SHA256="6c1337aee2e4bf993299851c70b7db11faec785303cfca3a5c3eb5f329ba7023"
|
||||
PKG_LICENSE="LGPLv2"
|
||||
PKG_SITE="http://www.mpg123.org/"
|
||||
PKG_URL="http://downloads.sourceforge.net/sourceforge/mpg123/mpg123-$PKG_VERSION.tar.bz2"
|
||||
PKG_DEPENDS_TARGET="toolchain alsa-lib SDL2"
|
||||
PKG_DEPENDS_TARGET="toolchain alsa-lib"
|
||||
PKG_LONGDESC="A console based real time MPEG Audio Player for Layer 1, 2 and 3."
|
||||
|
||||
PKG_CONFIGURE_OPTS_TARGET="--disable-shared \
|
||||
|
||||
@@ -7,7 +7,7 @@ PKG_SHA256="c9d77f98b31d53f521e3179003a9cb66b0586704717e9d401f3bc0dafa243865"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://www.avalpa.com/the-key-values/15-free-software/33-opencaster"
|
||||
PKG_URL="http://ftp.de.debian.org/debian/pool/main/o/opencaster/opencaster_${PKG_VERSION}+dfsg.orig.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain"
|
||||
PKG_DEPENDS_TARGET="toolchain zlib"
|
||||
PKG_LONGDESC="A free and open source MPEG2 transport stream data generator and packet manipulator."
|
||||
|
||||
pre_configure_target() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv)
|
||||
# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="tsdecrypt"
|
||||
PKG_VERSION="10.0"
|
||||
@@ -7,7 +8,7 @@ PKG_SHA256="a337a7d60cc8f78b9dffbd7d675390497763bcb8f878ec9f1bec3eb80f32b1f1"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://georgi.unixsol.org/programs/tsdecrypt"
|
||||
PKG_URL="http://georgi.unixsol.org/programs/tsdecrypt/${PKG_NAME}-${PKG_VERSION}.tar.bz2"
|
||||
PKG_DEPENDS_TARGET="toolchain libdvbcsa"
|
||||
PKG_DEPENDS_TARGET="toolchain libdvbcsa openssl"
|
||||
PKG_LONGDESC="A tool that reads incoming mpeg transport stream over UDP/RTP and then decrypts it using libdvbcsa/ffdecsa."
|
||||
|
||||
make_target() {
|
||||
|
||||
@@ -7,7 +7,7 @@ PKG_SHA256="4ebc271e9e5cea84a683375a0f7e91086e5dac90c5d51bb3f169f75386107a62"
|
||||
PKG_LICENSE="GPLv3"
|
||||
PKG_SITE="http://lftp.yar.ru/"
|
||||
PKG_URL="http://lftp.yar.ru/ftp/${PKG_NAME}-${PKG_VERSION}.tar.xz"
|
||||
PKG_DEPENDS_TARGET="toolchain readline openssl zlib"
|
||||
PKG_DEPENDS_TARGET="toolchain readline openssl zlib libidn2"
|
||||
PKG_LONGDESC="A sophisticated ftp/http client, and a file transfer program supporting a number of network protocols."
|
||||
|
||||
PKG_CONFIGURE_OPTS_TARGET="--disable-nls \
|
||||
|
||||
@@ -10,6 +10,10 @@ PKG_URL="http://www.udpxy.com/download/1_23/${PKG_NAME}.${PKG_VERSION}-prod.tar.
|
||||
PKG_DEPENDS_TARGET="toolchain"
|
||||
PKG_LONGDESC="A UDP-to-HTTP multicast traffic relay daemon."
|
||||
|
||||
configure_target() {
|
||||
export CFLAGS+=" -Wno-stringop-truncation"
|
||||
}
|
||||
|
||||
makeinstall_target() {
|
||||
:
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ PKG_SHA256="dd779b6992de37995555e1d54caf0716a694765efc65480eed2c713105ab46fe"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://www.liblognorm.com"
|
||||
PKG_URL="https://github.com/rsyslog/liblognorm/archive/v$PKG_VERSION.tar.gz"
|
||||
PKG_DEPENDS_TARGET="toolchain libestr"
|
||||
PKG_DEPENDS_TARGET="toolchain libestr libfastjson"
|
||||
PKG_TOOLCHAIN="autotools"
|
||||
PKG_LONGDESC="A fast samples-based log normalization library."
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="runc"
|
||||
PKG_VERSION="v1.0.0-rc7"
|
||||
PKG_SHA256="e8388b812d93a8a131a2a2fdd851847295c8e341721002940dadd2999fb81b51"
|
||||
PKG_VERSION="v1.0.0-rc8"
|
||||
PKG_SHA256="efe4ff9bbe49b19074346d65c914d809c0a3e90d062ea9619fe240f931f0b700"
|
||||
PKG_LICENSE="APL"
|
||||
PKG_SITE="https://github.com/opencontainers/runc"
|
||||
PKG_URL="https://github.com/opencontainers/runc/archive/${PKG_VERSION}.tar.gz"
|
||||
|
||||
@@ -8,6 +8,7 @@ PKG_ARCH="x86_64"
|
||||
PKG_LICENSE="LGPL"
|
||||
PKG_SITE="https://github.com/rhboot/efivar"
|
||||
PKG_URL="https://github.com/rhboot/efivar/archive/$PKG_VERSION.tar.gz"
|
||||
PKG_DEPENDS_HOST="gcc:host"
|
||||
PKG_DEPENDS_TARGET="toolchain efivar:host"
|
||||
PKG_LONGDESC="Tools and library to manipulate EFI variables."
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ PKG_SHA256="acc16f878576ad0bb29bbb7c724e29d2827f14ddb39fe94d76c3a859d4a3d0d9"
|
||||
PKG_LICENSE="BSD"
|
||||
PKG_SITE="http://www.darwinsys.com/file/"
|
||||
PKG_URL="https://github.com/file/file/archive/${PKG_VERSION}.tar.gz"
|
||||
PKG_DEPENDS_HOST="ccache:host"
|
||||
PKG_DEPENDS_HOST="toolchain"
|
||||
PKG_DEPENDS_TARGET="toolchain file:host zlib"
|
||||
PKG_LONGDESC="The file utility is used to determine the types of various files."
|
||||
PKG_TOOLCHAIN="autotools"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
From c4c59790f3191c1a233fc1a61f8fedad85de1aeb Mon Sep 17 00:00:00 2001
|
||||
From: Peter Fink <pfink@christ-es.de>
|
||||
Date: Wed, 8 Feb 2017 14:04:45 +0100
|
||||
Subject: [PATCH] fbutils: Fix x64 execution. Call malloc not with a hardcoded
|
||||
sizeof(__u32). This caused the application to crash with segfaults on x64
|
||||
machines.
|
||||
|
||||
---
|
||||
tests/fbutils.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/fbutils.c b/tests/fbutils.c
|
||||
index 8ee494bc..fd7fbfe9 100644
|
||||
--- a/tests/fbutils.c
|
||||
+++ b/tests/fbutils.c
|
||||
@@ -138,7 +138,7 @@ int open_framebuffer(void)
|
||||
memset(fbuffer,0,fix.smem_len);
|
||||
|
||||
bytes_per_pixel = (var.bits_per_pixel + 7) / 8;
|
||||
- line_addr = malloc (sizeof (__u32) * var.yres_virtual);
|
||||
+ line_addr = malloc (sizeof (line_addr) * var.yres_virtual);
|
||||
addr = 0;
|
||||
for (y = 0; y < var.yres_virtual; y++, addr += fix.line_length)
|
||||
line_addr [y] = fbuffer + addr;
|
||||
@@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="vdr-plugin-epgsearch"
|
||||
PKG_VERSION="84b59b81137887a48533cc897551bccf2e9e10f6"
|
||||
PKG_SHA256="d6c4a9136588a7cdf2eb43b6b9643a5bb81a44c542c6e6fcf7448b2383901914"
|
||||
PKG_VERSION="770de32f1908b1f9c60f66bf288a4c8a03f97d52"
|
||||
PKG_SHA256="8b6144ee3d22b0c13ba81be94920b421b05fd9b921dfe8245ed582db407acac8"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://winni.vdr-developer.org/epgsearch/"
|
||||
PKG_URL="https://github.com/vdr-projects/vdr-plugin-epgsearch/archive/$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="vdr-plugin-robotv"
|
||||
PKG_VERSION="50d4bdcdbe3bdb6e85fe02de4c4086ca1f8db94d"
|
||||
PKG_SHA256="062489e55111f0ba2420463cc506865ac59b1c1d080b318cb81d58ec3f4fbd3f"
|
||||
PKG_VERSION="13b691af63743ce6481e2558dc50ee89dd7a0349"
|
||||
PKG_SHA256="1bd508383d3b393dd1273af9bef07a1a64ac22c8eada85c96e5aa541c3abf228"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/pipelka/roboTV"
|
||||
PKG_URL="https://github.com/pipelka/vdr-plugin-robotv/archive/$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="vdr-plugin-satip"
|
||||
PKG_VERSION="a4051bf88c1f3c86cfe5133fd703517296f7f590"
|
||||
PKG_SHA256="ea9f930b829e4c333f8401e64b5e03a82efb88a4c6db3320463b295d297b0035"
|
||||
PKG_VERSION="b697e435d4bf42754309e6b5a9c5f8ff43463077"
|
||||
PKG_SHA256="9ccb90b4b55848bad738236e07e0feb2af9e78e6c9ee6614b5a1172db3e00fb0"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://www.saunalahti.fi/~rahrenbe/vdr/satip/"
|
||||
PKG_URL="https://github.com/rofafor/vdr-plugin-satip/archive/$PKG_VERSION.tar.gz"
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="vdr"
|
||||
PKG_VERSION="2.4.0"
|
||||
PKG_SHA256="93af49fe87048073dc38ef5e6c71e9704344d730f21c261afac69e3c937f8cce"
|
||||
PKG_VERSION="2.4.1"
|
||||
PKG_SHA256="25c3f835c4f3ff92cd2db10c004439ef22c2e895193c77fbe8cc7eac4858a1dc"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="http://www.tvdr.de"
|
||||
PKG_URL="ftp://ftp.tvdr.de/vdr/vdr-$PKG_VERSION.tar.bz2"
|
||||
PKG_URL="http://ftp.tvdr.de/vdr-$PKG_VERSION.tar.bz2"
|
||||
PKG_DEPENDS_TARGET="toolchain bzip2 fontconfig freetype libcap libiconv libjpeg-turbo"
|
||||
PKG_LONGDESC="A DVB TV server application."
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
ftp://ftp.tvdr.de/vdr/Developer/Patches/vdr-2.4/
|
||||
|
||||
# This patch fixes a bug in handling the tfRecording flag in the SVDRP commands MODT
|
||||
# and UPDT. The tfRecording flag must only be handled by the VDR that actually hosts
|
||||
# and processes the timer.
|
||||
#
|
||||
--- a/svdrp.c 2018/03/19 12:16:33 5.0
|
||||
+++ b/svdrp.c 2018/04/19 09:45:08
|
||||
@@ -2036,6 +2036,7 @@
|
||||
LOCK_TIMERS_WRITE;
|
||||
Timers->SetExplicitModify();
|
||||
if (cTimer *Timer = Timers->GetById(Id)) {
|
||||
+ bool IsRecording = Timer->HasFlags(tfRecording);
|
||||
cTimer t = *Timer;
|
||||
if (strcasecmp(tail, "ON") == 0)
|
||||
t.SetFlags(tfActive);
|
||||
@@ -2046,6 +2047,10 @@
|
||||
return;
|
||||
}
|
||||
*Timer = t;
|
||||
+ if (IsRecording)
|
||||
+ Timer->SetFlags(tfRecording);
|
||||
+ else
|
||||
+ Timer->ClrFlags(tfRecording);
|
||||
Timers->SetModified();
|
||||
isyslog("SVDRP %s < %s modified timer %s (%s)", Setup.SVDRPHostName, *clientName, *Timer->ToDescr(), Timer->HasFlags(tfActive) ? "active" : "inactive");
|
||||
Reply(250, "%d %s", Timer->Id(), *Timer->ToText(true));
|
||||
@@ -2478,12 +2483,18 @@
|
||||
if (Timer->Parse(Option)) {
|
||||
LOCK_TIMERS_WRITE;
|
||||
if (cTimer *t = Timers->GetTimer(Timer)) {
|
||||
+ bool IsRecording = t->HasFlags(tfRecording);
|
||||
t->Parse(Option);
|
||||
delete Timer;
|
||||
Timer = t;
|
||||
+ if (IsRecording)
|
||||
+ Timer->SetFlags(tfRecording);
|
||||
+ else
|
||||
+ Timer->ClrFlags(tfRecording);
|
||||
isyslog("SVDRP %s < %s updated timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr());
|
||||
}
|
||||
else {
|
||||
+ Timer->ClrFlags(tfRecording);
|
||||
Timers->Add(Timer);
|
||||
isyslog("SVDRP %s < %s added timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr());
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
# This patch fixes a possible invalid locking sequence in case a remote timer handling error message
|
||||
# is displayed on the OSD and the skin tries to lock the Recordings or DeletedRecordings
|
||||
# list in its Flush() function (for instance by calling cVideoDiskUsage::HasChanged()).
|
||||
# To do this, the call to Skins.Message() in menu.c's HandleRemoteModifications() has
|
||||
# been changed to Skins.QueueMessage(), and cSkins::ProcessQueuedMessages() is now called
|
||||
# unconditionally in the main loop, and checks whether the current cSkinDisplay object
|
||||
# (if any) implements SetMessage().
|
||||
#
|
||||
--- 1/menu.c 2018/04/14 10:24:41 5.0
|
||||
+++ 1/menu.c 2018/04/28 12:09:45
|
||||
@@ -1075,7 +1075,7 @@
|
||||
{
|
||||
cString ErrorMessage;
|
||||
if (!HandleRemoteTimerModifications(NewTimer, OldTimer, &ErrorMessage)) {
|
||||
- Skins.Message(mtError, ErrorMessage);
|
||||
+ Skins.QueueMessage(mtError, ErrorMessage);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
--- 1/skins.c 2013/08/18 12:07:22 5.0
|
||||
+++ 1/skins.c 2018/04/28 12:13:01
|
||||
@@ -352,6 +352,14 @@
|
||||
dsyslog("cSkins::ProcessQueuedMessages() called from background thread - ignored!");
|
||||
return;
|
||||
}
|
||||
+ // Check whether there is a cSkinDisplay object (if any) that implements SetMessage():
|
||||
+ if (cSkinDisplay *sd = cSkinDisplay::Current()) {
|
||||
+ if (!(dynamic_cast<cSkinDisplayChannel *>(sd) ||
|
||||
+ dynamic_cast<cSkinDisplayMenu *>(sd) ||
|
||||
+ dynamic_cast<cSkinDisplayReplay *>(sd) ||
|
||||
+ dynamic_cast<cSkinDisplayMessage *>(sd)))
|
||||
+ return;
|
||||
+ }
|
||||
cSkinQueuedMessage *msg = NULL;
|
||||
// Get the first waiting message:
|
||||
queueMessageMutex.Lock();
|
||||
--- 1/vdr.c 2018/04/10 13:24:43 5.0
|
||||
+++ 1/vdr.c 2018/04/28 11:27:48
|
||||
@@ -1176,8 +1176,7 @@
|
||||
if (!Menu && !cOsd::IsOpen())
|
||||
Menu = CamControl();
|
||||
// Queued messages:
|
||||
- if (!Skins.IsOpen())
|
||||
- Skins.ProcessQueuedMessages();
|
||||
+ Skins.ProcessQueuedMessages();
|
||||
// User Input:
|
||||
cOsdObject *Interact = Menu ? Menu : cControl::Control();
|
||||
eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());
|
||||
@@ -1,89 +0,0 @@
|
||||
# Fixed locking the Channels list in cDisplayChannel, where the lock was still held
|
||||
# when Flush() was called.
|
||||
#
|
||||
--- 1/menu.c 2018/04/28 12:09:45 5.1
|
||||
+++ 1/menu.c 2018/05/06 09:30:11
|
||||
@@ -4626,14 +4626,17 @@
|
||||
cOsdProvider::OsdSizeChanged(osdState); // just to get the current state
|
||||
positioner = NULL;
|
||||
channel = NULL;
|
||||
- LOCK_CHANNELS_READ;
|
||||
- channel = Channels->GetByNumber(Number);
|
||||
- lastPresent = lastFollowing = NULL;
|
||||
- if (channel) {
|
||||
- DisplayChannel();
|
||||
- DisplayInfo();
|
||||
+ {
|
||||
+ LOCK_CHANNELS_READ;
|
||||
+ channel = Channels->GetByNumber(Number);
|
||||
+ lastPresent = lastFollowing = NULL;
|
||||
+ if (channel) {
|
||||
+ DisplayChannel();
|
||||
+ DisplayInfo();
|
||||
+ }
|
||||
+ }
|
||||
+ if (channel)
|
||||
displayChannel->Flush();
|
||||
- }
|
||||
lastTime.Set();
|
||||
}
|
||||
|
||||
@@ -4868,31 +4871,33 @@
|
||||
}
|
||||
};
|
||||
if (positioner || !timeout || lastTime.Elapsed() < (uint64_t)(Setup.ChannelInfoTime * 1000)) {
|
||||
- LOCK_CHANNELS_READ;
|
||||
- if (Key == kNone && !number && group < 0 && !NewChannel && channel && channel->Number() != cDevice::CurrentChannel()) {
|
||||
- // makes sure a channel switch through the SVDRP CHAN command is displayed
|
||||
- channel = Channels->GetByNumber(cDevice::CurrentChannel());
|
||||
- Refresh();
|
||||
- lastTime.Set();
|
||||
- }
|
||||
- DisplayInfo();
|
||||
- if (NewChannel) {
|
||||
- SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
|
||||
- Channels->SwitchTo(NewChannel->Number());
|
||||
- SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
|
||||
- channel = NewChannel;
|
||||
- }
|
||||
- const cPositioner *Positioner = cDevice::ActualDevice()->Positioner();
|
||||
- bool PositionerMoving = Positioner && Positioner->IsMoving();
|
||||
- SetNeedsFastResponse(PositionerMoving);
|
||||
- if (!PositionerMoving) {
|
||||
- if (positioner)
|
||||
- lastTime.Set(); // to keep the channel display up a few seconds after the target position has been reached
|
||||
- Positioner = NULL;
|
||||
- }
|
||||
- if (Positioner || positioner) // making sure we call SetPositioner(NULL) if there is a switch from "with" to "without" positioner
|
||||
- displayChannel->SetPositioner(Positioner);
|
||||
- positioner = Positioner;
|
||||
+ {
|
||||
+ LOCK_CHANNELS_READ;
|
||||
+ if (Key == kNone && !number && group < 0 && !NewChannel && channel && channel->Number() != cDevice::CurrentChannel()) {
|
||||
+ // makes sure a channel switch through the SVDRP CHAN command is displayed
|
||||
+ channel = Channels->GetByNumber(cDevice::CurrentChannel());
|
||||
+ Refresh();
|
||||
+ lastTime.Set();
|
||||
+ }
|
||||
+ DisplayInfo();
|
||||
+ if (NewChannel) {
|
||||
+ SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
|
||||
+ Channels->SwitchTo(NewChannel->Number());
|
||||
+ SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
|
||||
+ channel = NewChannel;
|
||||
+ }
|
||||
+ const cPositioner *Positioner = cDevice::ActualDevice()->Positioner();
|
||||
+ bool PositionerMoving = Positioner && Positioner->IsMoving();
|
||||
+ SetNeedsFastResponse(PositionerMoving);
|
||||
+ if (!PositionerMoving) {
|
||||
+ if (positioner)
|
||||
+ lastTime.Set(); // to keep the channel display up a few seconds after the target position has been reached
|
||||
+ Positioner = NULL;
|
||||
+ }
|
||||
+ if (Positioner || positioner) // making sure we call SetPositioner(NULL) if there is a switch from "with" to "without" positioner
|
||||
+ displayChannel->SetPositioner(Positioner);
|
||||
+ positioner = Positioner;
|
||||
+ }
|
||||
displayChannel->Flush();
|
||||
return osContinue;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
# Fixed locking the Channels list in cDisplayChannel, where the lock was still held
|
||||
# when Flush() was called (cont'd).
|
||||
#
|
||||
--- 1/menu.c 2018/05/06 09:30:11 5.2
|
||||
+++ 1/menu.c 2018/05/27 09:51:56 5.3
|
||||
@@ -4654,8 +4654,10 @@
|
||||
displayChannel = Skins.Current()->DisplayChannel(withInfo);
|
||||
positioner = NULL;
|
||||
channel = NULL;
|
||||
- LOCK_CHANNELS_READ;
|
||||
- channel = Channels->GetByNumber(cDevice::CurrentChannel());
|
||||
+ {
|
||||
+ LOCK_CHANNELS_READ;
|
||||
+ channel = Channels->GetByNumber(cDevice::CurrentChannel());
|
||||
+ }
|
||||
ProcessKey(FirstKey);
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# Fixed shutdown after user inactivity in case a plugin is keeping the OSD open.
|
||||
#
|
||||
--- a/vdr.c 2018/04/28 11:27:48 5.1
|
||||
+++ b/vdr.c 2018/07/16 08:52:40 5.2
|
||||
@@ -1514,9 +1514,7 @@
|
||||
ShutdownHandler.countdown.Cancel();
|
||||
}
|
||||
|
||||
- if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
|
||||
- // Handle housekeeping tasks
|
||||
-
|
||||
+ if (!cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
|
||||
// Shutdown:
|
||||
// Check whether VDR will be ready for shutdown in SHUTDOWNWAIT seconds:
|
||||
time_t Soon = Now + SHUTDOWNWAIT;
|
||||
@@ -1535,7 +1533,8 @@
|
||||
// Do this again a bit later:
|
||||
ShutdownHandler.SetRetry(SHUTDOWNRETRY);
|
||||
}
|
||||
-
|
||||
+ // Handle housekeeping tasks
|
||||
+ if ((Now - LastInteract) > ACTIVITYTIMEOUT) {
|
||||
// Disk housekeeping:
|
||||
RemoveDeletedRecordings();
|
||||
ListGarbageCollector.Purge();
|
||||
@@ -1543,6 +1542,7 @@
|
||||
// Plugins housekeeping:
|
||||
PluginManager.Housekeeping();
|
||||
}
|
||||
+ }
|
||||
|
||||
ReportEpgBugFixStats();
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# Fixed switching through encrypted channels with the Up/Down keys
|
||||
#
|
||||
--- a/device.c 2018/03/24 09:49:14 5.0
|
||||
+++ b/device.c 2018/07/16 09:29:57
|
||||
@@ -787,6 +787,7 @@
|
||||
if (LiveView) {
|
||||
isyslog("switching to channel %d %s (%s)", Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
|
||||
cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
|
||||
+ // and, if decrypted, this removes the now superflous PIDs from the CAM, too
|
||||
}
|
||||
for (int i = 3; i--;) {
|
||||
switch (SetChannel(Channel, LiveView)) {
|
||||
@@ -809,6 +810,7 @@
|
||||
Direction = sgn(Direction);
|
||||
if (Direction) {
|
||||
cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
|
||||
+ // and, if decrypted, this removes the now superflous PIDs from the CAM, too
|
||||
int n = CurrentChannel() + Direction;
|
||||
int first = n;
|
||||
LOCK_CHANNELS_READ;
|
||||
--- a/menu.c 2018/05/27 09:51:56 5.3
|
||||
+++ b/menu.c 2018/07/16 09:29:57
|
||||
@@ -4704,6 +4704,8 @@
|
||||
const cChannel *cDisplayChannel::NextAvailableChannel(const cChannel *Channel, int Direction)
|
||||
{
|
||||
if (Direction) {
|
||||
+ cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
|
||||
+ // and, if decrypted, this removes the now superflous PIDs from the CAM, too
|
||||
LOCK_CHANNELS_READ;
|
||||
while (Channel) {
|
||||
Channel = Direction > 0 ? Channels->Next(Channel) : Channels->Prev(Channel);
|
||||
@@ -1,13 +0,0 @@
|
||||
# Now deactivating MTD support if a non MCD capable CAM is inserted after removing
|
||||
# a previously used CAM that is MCD capable.
|
||||
#
|
||||
--- a/ci.c 2018/03/19 16:37:03 5.0
|
||||
+++ b/ci.c 2018/09/23 10:17:20
|
||||
@@ -1213,6 +1213,7 @@
|
||||
}
|
||||
else {
|
||||
dsyslog("CAM %d: doesn't reply to QUERY - only a single channel can be decrypted", CamSlot()->SlotNumber());
|
||||
+ CamSlot()->MtdActivate(false);
|
||||
state = 4; // normal operation
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ PKG_NAME="repository.linuxserver.docker"
|
||||
PKG_VERSION="9.0"
|
||||
PKG_REV="102"
|
||||
PKG_ARCH="any"
|
||||
PKG_ADDON_PROJECTS="any !WeTek_Core !WeTek_Play"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://linuxserver.io"
|
||||
PKG_URL=""
|
||||
|
||||
@@ -48,7 +48,6 @@ addon() {
|
||||
mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/bin
|
||||
cp -P $PKG_BUILD/.$TARGET_NAME/src/boblightd $ADDON_BUILD/$PKG_ADDON_ID/bin
|
||||
cp -P $PKG_BUILD/.$TARGET_NAME/src/boblight-constant $ADDON_BUILD/$PKG_ADDON_ID/bin
|
||||
cp -P $PKG_BUILD/.$TARGET_NAME/src/boblight-aml $ADDON_BUILD/$PKG_ADDON_ID/bin
|
||||
if [ "$DISPLAYSERVER" = "x11" ] ; then
|
||||
cp -P $PKG_BUILD/.$TARGET_NAME/src/boblight-X11 $ADDON_BUILD/$PKG_ADDON_ID/bin
|
||||
fi
|
||||
|
||||
@@ -1,632 +0,0 @@
|
||||
diff --git a/src/Makefile.am b/src/Makefile.am
|
||||
index 9ba5381..c5a4dc6 100644
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -7,6 +7,7 @@ AM_CFLAGS =\
|
||||
-g
|
||||
|
||||
bin_PROGRAMS = boblightd \
|
||||
+ boblight-aml \
|
||||
boblight-constant
|
||||
|
||||
|
||||
@@ -19,6 +20,11 @@ endif
|
||||
|
||||
endif
|
||||
|
||||
+boblight_aml_SOURCES = clients/boblight-aml/boblight-aml.cpp
|
||||
+boblight_aml_SOURCES += clients/boblight-aml/flagmanager-aml.cpp
|
||||
+boblight_aml_SOURCES += clients/flagmanager.cpp
|
||||
+boblight_aml_SOURCES += util/misc.cpp
|
||||
+
|
||||
boblight_v4l_SOURCES = \
|
||||
clients/boblight-v4l/boblight-v4l.cpp \
|
||||
clients/boblight-v4l/flagmanager-v4l.cpp \
|
||||
diff -urPp src/clients/boblight-aml.cpp src/clients/boblight-aml/boblight-aml.cpp
|
||||
--- /dev/null Thu Jan 1 00:00:00 1970
|
||||
+++ b/src/clients/boblight-aml/boblight-aml.cpp Thu Jan 15 10:24:16 2015
|
||||
@@ -0,0 +1,491 @@
|
||||
+/*
|
||||
+ * boblight
|
||||
+ * Copyright (C) Bob 2009
|
||||
+ *
|
||||
+ * boblight 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.
|
||||
+ *
|
||||
+ * boblight is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
+ * See the GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along
|
||||
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#define BOBLIGHT_DLOPEN
|
||||
+#include "lib/boblight.h"
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <unistd.h>
|
||||
+#include <signal.h>
|
||||
+#include <algorithm>
|
||||
+
|
||||
+#include <fcntl.h>
|
||||
+#include <errno.h>
|
||||
+#include <sys/stat.h>
|
||||
+#include <sys/poll.h>
|
||||
+#include <sys/types.h>
|
||||
+#include <sys/time.h>
|
||||
+#include <sys/ioctl.h>
|
||||
+
|
||||
+#include "config.h"
|
||||
+#include "util/misc.h"
|
||||
+#include "util/timeutils.h"
|
||||
+#include "flagmanager-aml.h"
|
||||
+
|
||||
+using namespace std;
|
||||
+
|
||||
+//from linux/amlogic/amports/amvideocap.h
|
||||
+#define AMVIDEOCAP_IOC_MAGIC 'V'
|
||||
+#define AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH _IOW(AMVIDEOCAP_IOC_MAGIC, 0x02, int)
|
||||
+#define AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x03, int)
|
||||
+
|
||||
+
|
||||
+// helper class - tries to load the "movie" settings from the script.xbmc.boblight addon
|
||||
+// and pass them to the boblight-aml client
|
||||
+class CBoblightAddonSettings
|
||||
+{
|
||||
+ public:
|
||||
+ CBoblightAddonSettings() : m_bobdisable(false), m_settingsLoaded(false)
|
||||
+ {
|
||||
+ m_settingsLoaded = loadBoblightAddonSettings();
|
||||
+ }
|
||||
+
|
||||
+ std::string getBoblightClientCmdLine()
|
||||
+ {
|
||||
+ std::string cmdLine = "";
|
||||
+ //convert bool string to lowercase
|
||||
+ transform(m_interpolation.begin(), m_interpolation.end(), m_interpolation.begin(), ::tolower);
|
||||
+
|
||||
+ cmdLine += "-s " + m_ip + ":" + m_port;
|
||||
+ cmdLine += " -o autospeed=" + m_autospeed;
|
||||
+ cmdLine += " -o interpolation=" + m_interpolation;
|
||||
+ cmdLine += " -o saturation=" + m_saturation;
|
||||
+ cmdLine += " -o speed=" + m_speed;
|
||||
+ cmdLine += " -o threshold=" + m_threshold;
|
||||
+ cmdLine += " -o value=" + m_value;
|
||||
+ return cmdLine;
|
||||
+ }
|
||||
+
|
||||
+ bool m_bobdisable;
|
||||
+ bool m_settingsLoaded;
|
||||
+ std::string m_ip;
|
||||
+ std::string m_port;
|
||||
+ std::string m_autospeed;
|
||||
+ std::string m_interpolation;
|
||||
+ std::string m_saturation;
|
||||
+ std::string m_speed;
|
||||
+ std::string m_threshold;
|
||||
+ std::string m_value;
|
||||
+
|
||||
+ private:
|
||||
+ #define SETTINGS_ATTR_BOBDISABLE "bobdisable"
|
||||
+ #define SETTINGS_ATTR_IP "hostip"
|
||||
+ #define SETTINGS_ATTR_PORT "hostport"
|
||||
+ #define SETTINGS_ATTR_AUTOSPEED "movie_autospeed"
|
||||
+ #define SETTINGS_ATTR_INTERPOLATION "movie_interpolation"
|
||||
+ #define SETTINGS_ATTR_SATURATION "movie_saturation"
|
||||
+ #define SETTINGS_ATTR_SPEED "movie_speed"
|
||||
+ #define SETTINGS_ATTR_THRESHOLD "movie_threshold"
|
||||
+ #define SETTINGS_ATTR_VALUE "movie_value"
|
||||
+ #define KODI_HOME_ENV_VAR "HOME"
|
||||
+
|
||||
+ bool loadBoblightAddonSettings()
|
||||
+ {
|
||||
+ bool ret = false;
|
||||
+ char *kodiHome = getenv(KODI_HOME_ENV_VAR);
|
||||
+ //fallback to custom settings file in case boblight addon is not installed
|
||||
+ std::string settingsFile = "/storage/boblight-aml.xml";
|
||||
+
|
||||
+ if (kodiHome != NULL)
|
||||
+ {
|
||||
+ settingsFile = std::string(kodiHome) + "/.kodi/userdata/addon_data/script.xbmc.boblight/settings.xml";
|
||||
+ }
|
||||
+
|
||||
+ FILE *fd = fopen(settingsFile.c_str(), "r");
|
||||
+
|
||||
+ if (fd != NULL)
|
||||
+ {
|
||||
+ fseek(fd, 0, SEEK_END);
|
||||
+ size_t fileSize = ftell(fd);
|
||||
+ fseek(fd, 0, SEEK_SET);
|
||||
+ if (fileSize > 0)
|
||||
+ {
|
||||
+ if (fileSize > 32000)//read 16k max - there shouldn't be a bigger settings.xml from boblight [tm]
|
||||
+ fileSize = 32000;
|
||||
+ char *xmlBuffer = new char[fileSize];
|
||||
+ size_t readCount = fread(xmlBuffer, fileSize, 1, fd);
|
||||
+ fclose(fd);
|
||||
+
|
||||
+ if (readCount == 1)
|
||||
+ {
|
||||
+ parseBoblightSettings(std::string(xmlBuffer));
|
||||
+ ret = true;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ fprintf(stderr, "Failed reading boblight addon settings.xml");
|
||||
+ }
|
||||
+ delete[] xmlBuffer;
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ void parseBoblightSettings(std::string xmlBuffer)
|
||||
+ {
|
||||
+ std::string settings_bobdisable_str;
|
||||
+ settings_bobdisable_str = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_BOBDISABLE);
|
||||
+ if (settings_bobdisable_str == "true" || settings_bobdisable_str == "True")
|
||||
+ m_bobdisable = true;
|
||||
+
|
||||
+ m_ip = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_IP);
|
||||
+ m_port = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_PORT);
|
||||
+ m_autospeed = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_AUTOSPEED);
|
||||
+ m_interpolation = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_INTERPOLATION);
|
||||
+ m_saturation = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_SATURATION);
|
||||
+ m_speed = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_SPEED);
|
||||
+ m_threshold = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_THRESHOLD);
|
||||
+ m_value = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ std::string getValueFromXmlBuffer(const std::string &xmlBuffer, const char* xmlAttribute)
|
||||
+ {
|
||||
+ size_t strPos = 0;
|
||||
+ std::string valueStr;
|
||||
+
|
||||
+ // each line in the xml looks like this:
|
||||
+ // <setting id="movie_value" value="1.000006" />
|
||||
+ // find the attribute
|
||||
+ if ((strPos = xmlBuffer.find(xmlAttribute)) != std::string::npos)
|
||||
+ {
|
||||
+ size_t strPos2 = 0;
|
||||
+ // from movie_value" value="1.000006" /> look for "value"
|
||||
+ if ((strPos2 = xmlBuffer.find("value", strPos)) != std::string::npos)
|
||||
+ {
|
||||
+ size_t strPos3 = 0;
|
||||
+ // from value="1.000006" /> look for "="
|
||||
+ if ((strPos3 = xmlBuffer.find("=", strPos2)) != std::string::npos)
|
||||
+ {
|
||||
+ //extract the value - strPos3 points to ="1.000006"
|
||||
+ int valueOffset = 1; //skip the "="
|
||||
+ if (xmlBuffer[strPos3 + valueOffset] == '"')
|
||||
+ valueOffset++;//skip " if needed
|
||||
+ int strLen = 0;
|
||||
+ do
|
||||
+ {
|
||||
+ // value stops with " or space
|
||||
+ if (xmlBuffer[strPos3 + valueOffset + strLen] == '"' ||
|
||||
+ xmlBuffer[strPos3 + valueOffset + strLen] == ' ')
|
||||
+ break;
|
||||
+ strLen++;
|
||||
+ } while (strLen < 20);// no insane xml garbage ...
|
||||
+
|
||||
+ valueStr = xmlBuffer.substr(strPos3 + valueOffset, strLen);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return valueStr;
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+struct aml_snapshot_t {
|
||||
+ unsigned int dst_width;
|
||||
+ unsigned int dst_height;
|
||||
+ unsigned int dst_stride;
|
||||
+ unsigned int dst_size;
|
||||
+ void *dst_vaddr;
|
||||
+};
|
||||
+
|
||||
+volatile bool g_stop = false;
|
||||
+CFlagManagerAML g_flagmanager;
|
||||
+/*********************************************************
|
||||
+ *********************************************************/
|
||||
+static void SignalHandler(int signum)
|
||||
+{
|
||||
+ if (signum == SIGTERM)
|
||||
+ {
|
||||
+ fprintf(stderr, "caught SIGTERM\n");
|
||||
+ g_stop = true;
|
||||
+ }
|
||||
+ else if (signum == SIGINT)
|
||||
+ {
|
||||
+ fprintf(stderr, "caught SIGTERM\n");
|
||||
+ g_stop = true;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#define VIDEO_PATH "/dev/amvideo"
|
||||
+#define AMSTREAM_IOC_MAGIC 'S'
|
||||
+#define AMSTREAM_IOC_GET_VIDEO_DISABLE _IOR(AMSTREAM_IOC_MAGIC, 0x48, unsigned long)
|
||||
+static int amvideo_utils_video_playing()
|
||||
+{
|
||||
+ int video_fd;
|
||||
+ int video_disable;
|
||||
+
|
||||
+ video_fd = open(VIDEO_PATH, O_RDWR);
|
||||
+ if (video_fd < 0) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ ioctl(video_fd, AMSTREAM_IOC_GET_VIDEO_DISABLE, &video_disable);
|
||||
+ if (video_disable)
|
||||
+ {
|
||||
+ close(video_fd);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ close(video_fd);
|
||||
+
|
||||
+// fprintf(stderr, "pos x %d y %d w %d h %d\n",snapshot.src_x, snapshot.src_y,snapshot.src_width,snapshot.src_height);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int capture_frame(int fd, aml_snapshot_t &snapshot)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ ssize_t readResult = pread(fd, snapshot.dst_vaddr, snapshot.dst_size, 0);
|
||||
+
|
||||
+ if (readResult < snapshot.dst_size)
|
||||
+ {
|
||||
+ fprintf(stderr, "frame read returned %d\n", readResult);
|
||||
+ }
|
||||
+ //fprintf(stderr, "requ: %d read %d \n", snapshot.dst_size, readResult);
|
||||
+ fprintf(stderr, ".");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int configure_capture(int fd, aml_snapshot_t &snapshot)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ int ioctlret = 0;
|
||||
+
|
||||
+ if ((ioctlret = ioctl(fd, AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH, snapshot.dst_width)) != 0)
|
||||
+ {
|
||||
+ ret = 2;
|
||||
+ fprintf(stderr, "Error setting frame width (ret: %d errno: %d)\n", ioctlret, errno);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ if ((ioctlret = ioctl(fd, AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT, snapshot.dst_height)) != 0)
|
||||
+ {
|
||||
+ ret = 3;
|
||||
+ fprintf(stderr, "Error setting frame height (ret: %d errno: %d)\n", ioctlret, errno);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void frameToboblight(void *boblight, uint8_t* outputptr, int w, int h, int stride)
|
||||
+{
|
||||
+ if (!boblight)
|
||||
+ {
|
||||
+ fprintf(stderr, "no boblight\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!outputptr)
|
||||
+ {
|
||||
+ fprintf(stderr, "no outputptr\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ //read out pixels and hand them to libboblight
|
||||
+ uint8_t* buffptr;
|
||||
+ for (int y = h; y > 0; y--) {
|
||||
+ buffptr = outputptr + stride * y;
|
||||
+ for (int x = 0; x < w; x++) {
|
||||
+ int rgb[3];
|
||||
+ rgb[2] = *(buffptr++);
|
||||
+ rgb[1] = *(buffptr++);
|
||||
+ rgb[0] = *(buffptr++);
|
||||
+
|
||||
+ //fprintf(stdout, "frameToboblight: x(%d), y(%d)\n", x, y);
|
||||
+
|
||||
+ boblight_addpixelxy(boblight, x, y, rgb);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int Run(void* boblight)
|
||||
+{
|
||||
+ int snapshot_fd = -1;
|
||||
+ aml_snapshot_t aml_snapshot = {0};
|
||||
+ int lastPriority = 255;
|
||||
+
|
||||
+ aml_snapshot.dst_width = 160;
|
||||
+ aml_snapshot.dst_height = 160;
|
||||
+
|
||||
+ // calc stride, size and alloc mem
|
||||
+ aml_snapshot.dst_stride = aml_snapshot.dst_width * 3;
|
||||
+ aml_snapshot.dst_size = aml_snapshot.dst_stride * aml_snapshot.dst_height;
|
||||
+ aml_snapshot.dst_vaddr = calloc(aml_snapshot.dst_size, 1);
|
||||
+
|
||||
+ fprintf(stdout, "Connection to boblightd config: width(%d), height(%d)\n",
|
||||
+ aml_snapshot.dst_width, aml_snapshot.dst_height);
|
||||
+ //tell libboblight how big our image is
|
||||
+ boblight_setscanrange(boblight, (int)aml_snapshot.dst_width, (int)aml_snapshot.dst_height);
|
||||
+
|
||||
+ while(!g_stop)
|
||||
+ {
|
||||
+ int64_t bgn = GetTimeUs();
|
||||
+
|
||||
+ if (snapshot_fd == -1) {
|
||||
+ snapshot_fd = open(g_flagmanager.m_device.c_str(), O_RDWR, 0);
|
||||
+
|
||||
+ if (snapshot_fd == -1) {
|
||||
+ sleep(1);
|
||||
+ continue;
|
||||
+ } else {
|
||||
+ fprintf(stdout, "snapshot_fd(%d) \n", snapshot_fd);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // match source ratio if possible
|
||||
+ if (amvideo_utils_video_playing() != 0) {
|
||||
+ if ( lastPriority != 255)
|
||||
+ {
|
||||
+ boblight_setpriority(boblight, 255);
|
||||
+ lastPriority = 255;
|
||||
+ }
|
||||
+ sleep(1);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (configure_capture(snapshot_fd, aml_snapshot) == 0)
|
||||
+ {
|
||||
+ if (capture_frame(snapshot_fd, aml_snapshot) == 0)
|
||||
+ {
|
||||
+ // image to boblight convert.
|
||||
+ frameToboblight(boblight, (uint8_t*)aml_snapshot.dst_vaddr,
|
||||
+ aml_snapshot.dst_width, aml_snapshot.dst_height, aml_snapshot.dst_stride);
|
||||
+
|
||||
+ if (lastPriority != g_flagmanager.m_priority)
|
||||
+ {
|
||||
+ boblight_setpriority(boblight, g_flagmanager.m_priority);
|
||||
+ lastPriority = g_flagmanager.m_priority;
|
||||
+ }
|
||||
+ if (!boblight_sendrgb(boblight, 1, NULL))
|
||||
+ {
|
||||
+ // some error happened, probably connection broken, so bitch and try again
|
||||
+ PrintError(boblight_geterror(boblight));
|
||||
+ boblight_destroy(boblight);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ fprintf(stdout, "nap time\n");
|
||||
+ sleep(1);
|
||||
+ }
|
||||
+ }
|
||||
+ int64_t end = GetTimeUs();
|
||||
+ float calc_time_ms = (float)(end - bgn) / 1000.0;
|
||||
+ // throttle to 100ms max cycle rate
|
||||
+ calc_time_ms -= 100.0;
|
||||
+ if ((int)calc_time_ms < 0)
|
||||
+ usleep((int)(-calc_time_ms * 1000));
|
||||
+ }
|
||||
+
|
||||
+ // last image is black
|
||||
+ boblight_setpriority(boblight, 255);
|
||||
+ boblight_destroy(boblight);
|
||||
+ close(snapshot_fd);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*********************************************************
|
||||
+ *********************************************************/
|
||||
+int main(int argc, char *argv[])
|
||||
+{
|
||||
+ //load the boblight lib, if it fails we get a char* from dlerror()
|
||||
+ const char* boblight_error = boblight_loadlibrary(NULL);
|
||||
+ if (boblight_error)
|
||||
+ {
|
||||
+ PrintError(boblight_error);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ //try to parse the flags and bitch to stderr if there's an error
|
||||
+ try {
|
||||
+ g_flagmanager.ParseFlags(argc, argv);
|
||||
+ }
|
||||
+ catch (string error) {
|
||||
+ PrintError(error);
|
||||
+ g_flagmanager.PrintHelpMessage();
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (g_flagmanager.m_printhelp) {
|
||||
+ g_flagmanager.PrintHelpMessage();
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (g_flagmanager.m_printboblightoptions) {
|
||||
+ g_flagmanager.PrintBoblightOptions();
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ // check if we only should generate a cmdline based
|
||||
+ // on settings from possible found boblight addon
|
||||
+ if (g_flagmanager.generateCmdLine)
|
||||
+ {
|
||||
+ CBoblightAddonSettings settings;
|
||||
+ string cmdLine = "-p 100"; //default cmdline just contains priority 100
|
||||
+
|
||||
+ if (settings.m_settingsLoaded)
|
||||
+ cmdLine += " " + settings.getBoblightClientCmdLine();
|
||||
+ fprintf(stdout, "%s", cmdLine.c_str());
|
||||
+ return 0;//exit
|
||||
+ }
|
||||
+
|
||||
+ fprintf(stderr, "Using device: %s \n", g_flagmanager.m_device.c_str());
|
||||
+
|
||||
+ //set up signal handlers
|
||||
+ signal(SIGINT, SignalHandler);
|
||||
+ signal(SIGTERM, SignalHandler);
|
||||
+
|
||||
+ //keep running until we want to quit
|
||||
+ while(!g_stop) {
|
||||
+ //init boblight
|
||||
+ void* boblight = boblight_init();
|
||||
+
|
||||
+ fprintf(stdout, "Connecting to boblightd(%p)\n", boblight);
|
||||
+
|
||||
+ //try to connect, if we can't then bitch to stderr and destroy boblight
|
||||
+ if (!boblight_connect(boblight, g_flagmanager.m_address, g_flagmanager.m_port, 5000000) ||
|
||||
+ !boblight_setpriority(boblight, 255)) {
|
||||
+ PrintError(boblight_geterror(boblight));
|
||||
+ fprintf(stdout, "Waiting 10 seconds before trying again\n");
|
||||
+ boblight_destroy(boblight);
|
||||
+ sleep(2);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ fprintf(stdout, "Connection to boblightd opened\n");
|
||||
+
|
||||
+ //try to parse the boblight flags and bitch to stderr if we can't
|
||||
+ try {
|
||||
+ g_flagmanager.ParseBoblightOptions(boblight);
|
||||
+ }
|
||||
+ catch (string error) {
|
||||
+ PrintError(error);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ Run(boblight);
|
||||
+ }
|
||||
+ catch (string error) {
|
||||
+ PrintError(error);
|
||||
+ boblight_destroy(boblight);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+ fprintf(stdout, "Exiting\n");
|
||||
+}
|
||||
diff -urPp src/clients/flagmanager-aml.cpp src/clients/boblight-aml/flagmanager-aml.cpp
|
||||
--- /dev/null Thu Jan 1 00:00:00 1970
|
||||
+++ b/src/clients/boblight-aml/flagmanager-aml.cpp Thu Jan 15 10:21:40 2015
|
||||
@@ -0,0 +1,68 @@
|
||||
+/*
|
||||
+ * boblight
|
||||
+ * Copyright (C) Bob 2009
|
||||
+ *
|
||||
+ * boblight 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.
|
||||
+ *
|
||||
+ * boblight is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
+ * See the GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along
|
||||
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <iostream>
|
||||
+
|
||||
+#include "flagmanager-aml.h"
|
||||
+#include "util/misc.h"
|
||||
+#include "config.h"
|
||||
+
|
||||
+#define DEFAULT_CAPTURE_DEVICE "/dev/amvideocap0"
|
||||
+
|
||||
+using namespace std;
|
||||
+
|
||||
+CFlagManagerAML::CFlagManagerAML()
|
||||
+{
|
||||
+ // extend the flags -d -> device
|
||||
+ // -g -> only generate cmdline from possible found boblight addon settings.xml
|
||||
+ m_flags += "d:g";
|
||||
+ m_device = DEFAULT_CAPTURE_DEVICE;
|
||||
+ generateCmdLine = false;
|
||||
+}
|
||||
+
|
||||
+void CFlagManagerAML::ParseFlagsExtended(int& argc, char**& argv, int& c, char*& optarg)
|
||||
+{
|
||||
+ if (c == 'd') //devicename
|
||||
+ {
|
||||
+ if (optarg) //optional device
|
||||
+ {
|
||||
+ m_device = optarg;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (c == 'g') //generate cmdline
|
||||
+ {
|
||||
+ generateCmdLine = true;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void CFlagManagerAML::PrintHelpMessage()
|
||||
+{
|
||||
+ cout << "Usage: boblight-aml\n";
|
||||
+ cout << "\n";
|
||||
+ cout << " options:\n";
|
||||
+ cout << "\n";
|
||||
+ cout << " -p priority, from 0 to 255, default is 128\n";
|
||||
+ cout << " -s address[:port], set the address and optional port to connect to\n";
|
||||
+ cout << " -o add libboblight option, syntax: [light:]option=value\n";
|
||||
+ cout << " -l list libboblight options\n";
|
||||
+ cout << " -f fork\n";
|
||||
+ cout << " -d <device> (defaults to " << m_device << ")\n";
|
||||
+ cout << " -g try to find the settings.xml file from boblight addon and return the cmdline to use its options\n";
|
||||
+ cout << "\n";
|
||||
+}
|
||||
diff -urPp src/clients/flagmanager-aml.h src/clients/boblight-aml/flagmanager-aml.h
|
||||
--- /dev/null Thu Jan 1 00:00:00 1970
|
||||
+++ b/src/clients/boblight-aml/flagmanager-aml.h Thu Jan 15 10:20:15 2015
|
||||
@@ -0,0 +1,36 @@
|
||||
+/*
|
||||
+ * boblight
|
||||
+ * Copyright (C) Bob 2009
|
||||
+ *
|
||||
+ * boblight 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.
|
||||
+ *
|
||||
+ * boblight is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
+ * See the GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along
|
||||
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef FLAGMANAGERAML
|
||||
+#define FLAGMANAGERAML
|
||||
+
|
||||
+#include "clients/flagmanager.h"
|
||||
+
|
||||
+class CFlagManagerAML : public CFlagManager
|
||||
+{
|
||||
+ public:
|
||||
+ CFlagManagerAML();
|
||||
+ void ParseFlagsExtended(int& argc, char**& argv, int& c, char*& optarg);
|
||||
+
|
||||
+ void PrintHelpMessage();
|
||||
+ std::string m_device; //device to open for amvideocap
|
||||
+ bool generateCmdLine;
|
||||
+
|
||||
+};
|
||||
+
|
||||
+#endif //FLAGMANAGERAML
|
||||
\ No newline at end of file
|
||||
@@ -18,10 +18,4 @@ if [ -x $ADDON_DIR/bin/boblight-X11 -a -e $ADDON_HOME/boblight.X11 ] ; then
|
||||
boblight-X11 -f >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ -x $ADDON_DIR/bin/boblight-aml -a -e /dev/amvideocap0 ] ; then
|
||||
#generates cmdline from boblight addon settings
|
||||
CMDLINE=`boblight-aml -g`
|
||||
boblight-aml $CMDLINE >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
exec boblightd -c $ADDON_HOME/boblight.conf > $ADDON_LOG_FILE 2>&1
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
126
|
||||
- Update to docker 18.09.7
|
||||
|
||||
125
|
||||
- Update to docker 18.09.5
|
||||
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="docker"
|
||||
PKG_VERSION="18.09.5"
|
||||
PKG_SHA256="57f2a5d3374d86a8eb680c91df4351f5cb648351b9b32520c6fd2d66e7e97fd5"
|
||||
PKG_REV="125"
|
||||
PKG_VERSION="18.09.7"
|
||||
PKG_SHA256="f05dc15f5c11635472534c3aaf759c39c1bba842dd1ac23059431c2fd1ae1795"
|
||||
PKG_REV="126"
|
||||
PKG_ARCH="any"
|
||||
PKG_ADDON_PROJECTS="any !WeTek_Core !WeTek_Play"
|
||||
PKG_LICENSE="ASL"
|
||||
PKG_SITE="http://www.docker.com/"
|
||||
PKG_URL="https://github.com/docker/docker-ce/archive/v${PKG_VERSION}.tar.gz"
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
From 9979cbaa4d0108da552fd452294788a042766995 Mon Sep 17 00:00:00 2001
|
||||
From de25daa9281709a90e4dc23b4c27cbcdcef32fd3 Mon Sep 17 00:00:00 2001
|
||||
From: 5schatten <supervisedthinking@gmail.com>
|
||||
Date: Wed, 7 Nov 2018 12:22:23 +0100
|
||||
Date: Sat, 29 Jun 2019 17:58:09 +0200
|
||||
Subject: [PATCH] use Kodi addon storage location
|
||||
|
||||
---
|
||||
.../github.com/docker/docker/registry/config_unix.go | 2 +-
|
||||
.../github.com/docker/docker/registry/endpoint_v1.go | 2 +-
|
||||
components/engine/cmd/dockerd/daemon_unix.go | 4 ++--
|
||||
components/engine/daemon/config/config_test.go | 2 +-
|
||||
.../engine/integration-cli/docker_cli_daemon_test.go | 12 ++++++------
|
||||
.../docker_cli_external_volume_driver_unix_test.go | 8 ++++----
|
||||
.../integration-cli/docker_cli_network_unix_test.go | 8 ++++----
|
||||
.../engine/integration-cli/docker_cli_swarm_test.go | 8 ++++----
|
||||
.../integration/plugin/authz/authz_plugin_test.go | 6 +++---
|
||||
.../integration/plugin/graphdriver/external_test.go | 6 +++---
|
||||
components/engine/pkg/plugins/discovery_unix.go | 2 +-
|
||||
components/engine/pkg/plugins/plugins.go | 2 +-
|
||||
components/engine/registry/config_unix.go | 2 +-
|
||||
components/engine/registry/endpoint_v1.go | 2 +-
|
||||
14 files changed, 33 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/components/cli/vendor/github.com/docker/docker/registry/config_unix.go b/components/cli/vendor/github.com/docker/docker/registry/config_unix.go
|
||||
index 20fb47bcae..a023df7895 100644
|
||||
--- a/components/cli/vendor/github.com/docker/docker/registry/config_unix.go
|
||||
@@ -65,7 +82,7 @@ index 6998ed3312..c255b62146 100644
|
||||
flags.String("config-file", configFile, "")
|
||||
err := Reload(configFile, flags, func(c *Config) {
|
||||
diff --git a/components/engine/integration-cli/docker_cli_daemon_test.go b/components/engine/integration-cli/docker_cli_daemon_test.go
|
||||
index 986cc27530..7a0c2805cd 100644
|
||||
index d3cd5f1676..b5e504489d 100644
|
||||
--- a/components/engine/integration-cli/docker_cli_daemon_test.go
|
||||
+++ b/components/engine/integration-cli/docker_cli_daemon_test.go
|
||||
@@ -546,11 +546,11 @@ func (s *DockerDaemonSuite) TestDaemonAllocatesListeningPort(c *check.C) {
|
||||
@@ -121,11 +138,11 @@ index da8bb7e011..605a162e79 100644
|
||||
|
||||
- err := os.MkdirAll("/etc/docker/plugins", 0755)
|
||||
+ err := os.MkdirAll("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins", 0755)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
|
||||
- err = ioutil.WriteFile("/etc/docker/plugins/"+name+".spec", []byte(s.Server.URL), 0644)
|
||||
+ err = ioutil.WriteFile("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins/"+name+".spec", []byte(s.Server.URL), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
return s
|
||||
}
|
||||
@@ -278,7 +278,7 @@ func newVolumePlugin(c *check.C, name string) *volumePlugin {
|
||||
@@ -134,7 +151,7 @@ index da8bb7e011..605a162e79 100644
|
||||
|
||||
- err := os.RemoveAll("/etc/docker/plugins")
|
||||
+ err := os.RemoveAll("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins")
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ func hostVolumePath(name string) string {
|
||||
@@ -156,17 +173,17 @@ index d3d6256a75..a0f0ae973d 100644
|
||||
|
||||
- err := os.MkdirAll("/etc/docker/plugins", 0755)
|
||||
+ err := os.MkdirAll("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins", 0755)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
|
||||
- fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
|
||||
+ fileName := fmt.Sprintf("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins/%s.spec", netDrv)
|
||||
err = ioutil.WriteFile(fileName, []byte(url), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
|
||||
- ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
|
||||
+ ipamFileName := fmt.Sprintf("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins/%s.spec", ipamDrv)
|
||||
err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
@@ -227,7 +227,7 @@ func (s *DockerNetworkSuite) TearDownSuite(c *check.C) {
|
||||
|
||||
@@ -174,11 +191,11 @@ index d3d6256a75..a0f0ae973d 100644
|
||||
|
||||
- err := os.RemoveAll("/etc/docker/plugins")
|
||||
+ err := os.RemoveAll("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins")
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
|
||||
diff --git a/components/engine/integration-cli/docker_cli_swarm_test.go b/components/engine/integration-cli/docker_cli_swarm_test.go
|
||||
index 9f99d0c849..2d9a4b088e 100644
|
||||
index f6fadcf995..5d0b5256c1 100644
|
||||
--- a/components/engine/integration-cli/docker_cli_swarm_test.go
|
||||
+++ b/components/engine/integration-cli/docker_cli_swarm_test.go
|
||||
@@ -783,14 +783,14 @@ func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv,
|
||||
@@ -187,17 +204,17 @@ index 9f99d0c849..2d9a4b088e 100644
|
||||
|
||||
- err := os.MkdirAll("/etc/docker/plugins", 0755)
|
||||
+ err := os.MkdirAll("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins", 0755)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
|
||||
- fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
|
||||
+ fileName := fmt.Sprintf("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins/%s.spec", netDrv)
|
||||
err = ioutil.WriteFile(fileName, []byte(url), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
|
||||
- ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
|
||||
+ ipamFileName := fmt.Sprintf("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins/%s.spec", ipamDrv)
|
||||
err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
}
|
||||
@@ -802,7 +802,7 @@ func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) {
|
||||
setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
|
||||
@@ -205,11 +222,11 @@ index 9f99d0c849..2d9a4b088e 100644
|
||||
s.server.Close()
|
||||
- err := os.RemoveAll("/etc/docker/plugins")
|
||||
+ err := os.RemoveAll("/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins")
|
||||
c.Assert(err, checker.IsNil)
|
||||
assert.NilError(c, err)
|
||||
}()
|
||||
|
||||
diff --git a/components/engine/integration/plugin/authz/authz_plugin_test.go b/components/engine/integration/plugin/authz/authz_plugin_test.go
|
||||
index d0f5d8a783..ba626c6310 100644
|
||||
index 105affc1af..fa631a377a 100644
|
||||
--- a/components/engine/integration/plugin/authz/authz_plugin_test.go
|
||||
+++ b/components/engine/integration/plugin/authz/authz_plugin_test.go
|
||||
@@ -55,15 +55,15 @@ func setupTestV1(t *testing.T) func() {
|
||||
@@ -268,7 +285,7 @@ index 58058f2828..a7b449ca25 100644
|
||||
-var specsPaths = []string{"/etc/docker/plugins", "/usr/lib/docker/plugins"}
|
||||
+var specsPaths = []string{"/storage/.kodi/userdata/addon_data/service.system.docker/config/plugins", "/usr/lib/docker/plugins"}
|
||||
diff --git a/components/engine/pkg/plugins/plugins.go b/components/engine/pkg/plugins/plugins.go
|
||||
index 28c06ff693..c24cad2b63 100644
|
||||
index 6962079df9..77b69265b1 100644
|
||||
--- a/components/engine/pkg/plugins/plugins.go
|
||||
+++ b/components/engine/pkg/plugins/plugins.go
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
105
|
||||
- Update to 4.2.1.0
|
||||
|
||||
104
|
||||
- Update to 4.2.0.40
|
||||
|
||||
103
|
||||
- Update to 4.1.1.0
|
||||
|
||||
102
|
||||
- Update to 4.1.0.26
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="emby4"
|
||||
PKG_VERSION="4.1.0.26"
|
||||
PKG_SHA256="ccb9bb463e6ff5e084f731ccbb48119176cdc3592b3234796eefa09ec9e03e0f"
|
||||
PKG_REV="102"
|
||||
PKG_VERSION="4.2.1.0"
|
||||
PKG_SHA256="684a47c36700063141257c6325bbb2519ba11a7c7711e54e128d96f30adecdff"
|
||||
PKG_REV="105"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="prop."
|
||||
PKG_SITE="http://emby.media"
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
110
|
||||
- Rewrite add-on from scratch
|
||||
- Add support for APPS, SETUP, CVBS (X92) and POWER (A1 Max) indicators.
|
||||
- Add a configuration dialog:
|
||||
* Adjust display brightness.
|
||||
* Storage access indication.
|
||||
* Advanced hardware configuration of the display.
|
||||
- Fix crash if aml_fd628 module is not loaded (led_on, led_off files don't exist)
|
||||
- Fix disable add-on from Kodi UI.
|
||||
- Turn off indicators when add-on is disabled.
|
||||
|
||||
100
|
||||
- Initial add-on
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
@@ -1,30 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="fd628"
|
||||
PKG_VERSION="1.1"
|
||||
PKG_REV="100"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://libreelec.tv"
|
||||
PKG_URL=""
|
||||
PKG_DEPENDS_TARGET="toolchain"
|
||||
PKG_SECTION="service"
|
||||
PKG_SHORTDESC="fd628: Kodi service to light up additional icons on devices with FD628 display"
|
||||
PKG_LONGDESC="fd628: Kodi service to light up additional icons on devices with FD628 display"
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
PKG_IS_ADDON="yes"
|
||||
PKG_ADDON_NAME="service.fd628"
|
||||
PKG_ADDON_PROJECTS="S905 S912"
|
||||
PKG_ADDON_TYPE="xbmc.service"
|
||||
|
||||
make_target() {
|
||||
sed -e "s|@PKG_VERSION@|$PKG_VERSION|g" \
|
||||
-i addon.xml
|
||||
}
|
||||
|
||||
addon() {
|
||||
mkdir -p $ADDON_BUILD/$PKG_ADDON_ID
|
||||
cp -R $PKG_BUILD/* $ADDON_BUILD/$PKG_ADDON_ID
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<addon id="service.fd628"
|
||||
name="FD628 Display"
|
||||
version="@PKG_VERSION@"
|
||||
provider-name="Team LibreELEC">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="2.1.0"/>
|
||||
</requires>
|
||||
<extension point="xbmc.service"
|
||||
library="resources/lib/service.py"
|
||||
start="startup">
|
||||
</extension>
|
||||
<extension point="xbmc.addon.metadata">
|
||||
<summary>Service for controlling FD628 VFD display icons</summary>
|
||||
<description>Service for controlling FD628 VFD display icons, e.g. Ethernet/WiFi connection status and Time</description>
|
||||
<platform>all</platform>
|
||||
<assets>
|
||||
<icon>resources/icon.png</icon>
|
||||
</assets>
|
||||
</extension>
|
||||
</addon>
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
# Kodi Media Center language file
|
||||
# Addon Name: FD628 Display
|
||||
# Addon id: service.fd628
|
||||
# Addon Provider: Team LibreELEC
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: XBMC-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2018-02-12 17:48+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en_GB\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
# Kodi Settings
|
||||
msgctxt "#30000"
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Turn on display"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30002"
|
||||
msgid "Display brightness"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Advanced settings"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30004"
|
||||
msgid "Display type"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Common anode display (transposed ram)"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30013"
|
||||
msgid "Enable storage access (RW) indicator"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Select which icon is to be used as the access indicator"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30028"
|
||||
msgid "Clock colon (:) always on"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "play"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "pause"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "hdmi"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "cvbs"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "eth"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "wifi"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "setup"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "apps"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "usb"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "sd"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "alarm"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "power"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "Reorder character indexes"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Index 0"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Index 1"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Index 2"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Index 3"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30009"
|
||||
msgid "Index 4"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30010"
|
||||
msgid "Index 5"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "Index 6"
|
||||
msgstr ""
|
||||
|
||||
# Max index 30028
|
||||
@@ -1,78 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
import os
|
||||
import struct
|
||||
from fd628utils import *
|
||||
|
||||
_led_cmd = '/sys/class/leds/le-vfd/led_cmd'
|
||||
|
||||
class fd628Dev:
|
||||
def __init__(self):
|
||||
import ioctl
|
||||
import ctypes
|
||||
size = ctypes.sizeof(ctypes.c_int(0))
|
||||
self._FD628_IOC_MAGIC = ord('M')
|
||||
self._FD628_IOC_SMODE = ioctl.IOW(self._FD628_IOC_MAGIC, 1, size)
|
||||
self._FD628_IOC_GMODE = ioctl.IOR(self._FD628_IOC_MAGIC, 2, size)
|
||||
self._FD628_IOC_SBRIGHT = ioctl.IOW(self._FD628_IOC_MAGIC, 3, size)
|
||||
self._FD628_IOC_GBRIGHT = ioctl.IOR(self._FD628_IOC_MAGIC, 4, size)
|
||||
self._FD628_IOC_POWER = ioctl.IOW(self._FD628_IOC_MAGIC, 5, size)
|
||||
self._FD628_IOC_GVER = ioctl.IOR(self._FD628_IOC_MAGIC, 6, size)
|
||||
self._FD628_IOC_STATUS_LED = ioctl.IOW(self._FD628_IOC_MAGIC, 7, size)
|
||||
self._FD628_IOC_GDISPLAY_TYPE = ioctl.IOR(self._FD628_IOC_MAGIC, 8, size)
|
||||
self._FD628_IOC_SDISPLAY_TYPE = ioctl.IOW(self._FD628_IOC_MAGIC, 9, size)
|
||||
self._FD628_IOC_SCHARS_ORDER = ioctl.IOW(self._FD628_IOC_MAGIC, 10, 7)
|
||||
self._FD628_IOC_USE_DTB_CONFIG = ioctl.IOW(self._FD628_IOC_MAGIC, 11, size)
|
||||
self._FD628_IOC_MAXNR = 12
|
||||
|
||||
def enableDisplay(self, value):
|
||||
self.__writeFD628(self._FD628_IOC_POWER, int(value))
|
||||
|
||||
def getBrightness(self):
|
||||
return self.__readFD628(self._FD628_IOC_GBRIGHT)
|
||||
|
||||
def setBrightness(self, value):
|
||||
self.__writeFD628(self._FD628_IOC_SBRIGHT, value)
|
||||
|
||||
def getDisplayType(self):
|
||||
return self.__readFD628(self._FD628_IOC_GDISPLAY_TYPE)
|
||||
|
||||
def setDisplayType(self, value):
|
||||
self.__writeFD628(self._FD628_IOC_SDISPLAY_TYPE, value)
|
||||
|
||||
def setCharacterOrder(self, value):
|
||||
pack = struct.pack('BBBBBBB', value[0], value[1], value[2], value[3], value[4], value[5], value[6])
|
||||
self.__writeFD628(self._FD628_IOC_SCHARS_ORDER, pack, True)
|
||||
|
||||
def useDtbConfig(self):
|
||||
self.__writeFD628(self._FD628_IOC_USE_DTB_CONFIG, 0)
|
||||
|
||||
def __readFD628(self, cmd, isBuf = False):
|
||||
import ioctl
|
||||
ret = None
|
||||
if (ioctl.DIR(cmd) == ioctl.READ and self.__writeFD628(cmd, 0)):
|
||||
with open(_led_cmd, "rb") as vfd:
|
||||
ret = vfd.read()
|
||||
if (ret == ''):
|
||||
ret = None
|
||||
if (not isBuf and ret != None):
|
||||
ret = int(ret, 0)
|
||||
kodiLog('fd628Dev.__readFD628: value = {0}'.format(str(ret)))
|
||||
return ret
|
||||
|
||||
def __writeFD628(self, cmd, value, isBuf = False):
|
||||
ret = False
|
||||
if (os.path.isfile(_led_cmd)):
|
||||
if isBuf:
|
||||
value = ''.join([struct.pack('I', cmd), value])
|
||||
else:
|
||||
value = struct.pack('Ii', cmd, value)
|
||||
kodiLog('fd628Dev.__writeFD628: value = {0}'.format(repr(value)))
|
||||
try:
|
||||
with open(_led_cmd, "wb") as vfd:
|
||||
vfd.write(value)
|
||||
ret = True
|
||||
except Exception as inst:
|
||||
kodiLogError(inst)
|
||||
return ret
|
||||
@@ -1,95 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
import xbmcaddon
|
||||
|
||||
addon = xbmcaddon.Addon(id='service.fd628')
|
||||
|
||||
def getSetting(id):
|
||||
return addon.getSetting(id)
|
||||
|
||||
def getSettingBool(id):
|
||||
value = getSetting(id).lower()
|
||||
if (value == 'true'):
|
||||
value = True
|
||||
else:
|
||||
value = False
|
||||
return value
|
||||
|
||||
def getSettingInt(id):
|
||||
return int(getSetting(id))
|
||||
|
||||
def getSettingNumber(id):
|
||||
return float(getSetting(id))
|
||||
|
||||
class fd628Settings:
|
||||
def __init__(self):
|
||||
self.readValues()
|
||||
|
||||
def isDisplayOn(self):
|
||||
return self._displayOn
|
||||
|
||||
def isAdvancedSettings(self):
|
||||
return self._displayAdvanced
|
||||
|
||||
def getBrightness(self):
|
||||
return self._displayBrightness
|
||||
|
||||
def getDisplayType(self):
|
||||
return self._displayType
|
||||
|
||||
def isCommonAnode(self):
|
||||
return self._commonAnode
|
||||
|
||||
def getDisplay(self):
|
||||
value = self.getDisplayType()
|
||||
if (self.isCommonAnode()):
|
||||
value = value + (1 << 16)
|
||||
return value
|
||||
|
||||
def getCharacterIndex(self, i):
|
||||
return self._characterIndexes[i]
|
||||
|
||||
def getCharacterIndexes(self):
|
||||
return self._characterIndexes
|
||||
|
||||
def isStorageIndicator(self):
|
||||
return self._storageIndicator
|
||||
|
||||
def getStorageIndicatorIcon(self):
|
||||
return self._storageIndicatorIcon
|
||||
|
||||
def isColonOn(self):
|
||||
return self._colonOn
|
||||
|
||||
def readValues(self):
|
||||
self._displayAdvanced = False
|
||||
self._displayOn = getSettingBool('display.on')
|
||||
if (self._displayOn):
|
||||
self._displayBrightness = getSettingInt('display.brightness')
|
||||
self._storageIndicator = getSettingBool('display.storage.indicator')
|
||||
self._storageIndicatorIcon = getSetting('display.storage.indicator.icon')
|
||||
self._colonOn = getSettingBool('display.colon.on')
|
||||
self._displayAdvanced = getSettingBool('display.advanced')
|
||||
if (self._displayAdvanced):
|
||||
self._displayType = getSettingInt('display.type')
|
||||
self._commonAnode = getSettingBool('display.common.anode')
|
||||
self._characterIndexes = []
|
||||
for i in range(7):
|
||||
self._characterIndexes.append(getSettingInt('display.char.index{0}'.format(i)))
|
||||
else:
|
||||
self.__initDefaultValues()
|
||||
else:
|
||||
self.__initDefaultValues()
|
||||
|
||||
def __initDefaultValues(self):
|
||||
if not (self._displayOn):
|
||||
self._displayBrightness = 7
|
||||
self._storageIndicator = False
|
||||
self._storageIndicatorIcon = ''
|
||||
self._colonOn = False
|
||||
self._displayAdvanced = False
|
||||
if not (self._displayAdvanced):
|
||||
self._displayType = 0
|
||||
self._commonAnode = False
|
||||
self._characterIndexes = range(0, 7)
|
||||
@@ -1,187 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
import xbmc
|
||||
import os
|
||||
from fd628utils import *
|
||||
|
||||
class fd628State(object):
|
||||
def __init__(self, ledName):
|
||||
self._value = False
|
||||
self._hasChanged = False
|
||||
self._ledName = ledName
|
||||
|
||||
def _getStr(self, className):
|
||||
return '{0} ({1})'.format(className, self._ledName)
|
||||
|
||||
def update(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def getValue(self):
|
||||
return self._value
|
||||
|
||||
def hasChanged(self):
|
||||
return self._hasChanged
|
||||
|
||||
def getLedName(self):
|
||||
return self._ledName
|
||||
|
||||
def _update(self, value):
|
||||
if (value != self._value):
|
||||
self._hasChanged = True
|
||||
self._value = value
|
||||
else:
|
||||
self._hasChanged = False
|
||||
|
||||
class fd628IconIndicator(fd628State):
|
||||
def __init__(self, on, ledName):
|
||||
super(fd628IconIndicator, self).__init__(ledName)
|
||||
self._on = on
|
||||
|
||||
def __str__(self):
|
||||
return self._getStr('fd628IconIndicator')
|
||||
|
||||
def turnOn(self):
|
||||
self._on = True
|
||||
|
||||
def turnOff(self):
|
||||
self._on = False
|
||||
|
||||
def toggle(self):
|
||||
self._on = not self._on
|
||||
|
||||
def update(self):
|
||||
self._update(self._on)
|
||||
|
||||
class fd628CondVisibility(fd628State):
|
||||
def __init__(self, ledName, cmd):
|
||||
super(fd628CondVisibility, self).__init__(ledName)
|
||||
self._cmd = cmd
|
||||
|
||||
def __str__(self):
|
||||
return self._getStr('fd628CondVisibility')
|
||||
|
||||
def update(self):
|
||||
value = xbmc.getCondVisibility(self._cmd)
|
||||
self._update(value)
|
||||
|
||||
class fd628FileContains(fd628State):
|
||||
def __init__(self, ledName, path, strings):
|
||||
super(fd628FileContains, self).__init__(ledName)
|
||||
self._path = path
|
||||
self._strings = strings
|
||||
|
||||
def __str__(self):
|
||||
return self._getStr('fd628FileContains')
|
||||
|
||||
def update(self):
|
||||
if (os.path.isfile(self._path)):
|
||||
with open(self._path, 'rb') as state:
|
||||
content = state.read()
|
||||
value = self.__checkContent(content)
|
||||
self._update(value)
|
||||
else:
|
||||
self._update(False)
|
||||
|
||||
def __checkContent(self, content):
|
||||
ret = False
|
||||
for s in self._strings:
|
||||
if (s in content):
|
||||
ret = True
|
||||
break
|
||||
return ret
|
||||
|
||||
class fd628WindowChecker(fd628State):
|
||||
def __init__(self, ledName, windows):
|
||||
super(fd628WindowChecker, self).__init__(ledName)
|
||||
self._windows = windows
|
||||
|
||||
def __str__(self):
|
||||
return self._getStr('fd628WindowChecker')
|
||||
|
||||
def update(self):
|
||||
value = False
|
||||
for id in self._windows:
|
||||
if (xbmc.getCondVisibility('Window.IsVisible({0})'.format(id))):
|
||||
value = True
|
||||
break
|
||||
self._update(value)
|
||||
|
||||
class fd628ExtStorageChecker(fd628State):
|
||||
def __init__(self, ledName, path):
|
||||
super(fd628ExtStorageChecker, self).__init__(ledName)
|
||||
self._path = path
|
||||
|
||||
def __str__(self):
|
||||
return self._getStr('fd628ExtStorageChecker')
|
||||
|
||||
def update(self):
|
||||
value = False
|
||||
for folder, subs, files in os.walk('/dev/disk/by-uuid'):
|
||||
for filename in files:
|
||||
path = os.path.realpath(os.path.join(folder, filename))
|
||||
if (path.startswith(self._path)):
|
||||
value = True
|
||||
break
|
||||
self._update(value)
|
||||
|
||||
class fd628ExtStorageCount(fd628State):
|
||||
def __init__(self, ledName, drives, type):
|
||||
super(fd628ExtStorageCount, self).__init__(ledName)
|
||||
if (drives == None): # Monitor all drives
|
||||
self._drives = None
|
||||
drives = self.__getAllDrives()
|
||||
else: # Monitor listed drives
|
||||
self._drives = drives
|
||||
drives = self.__getSelectedDrives()
|
||||
self._driveStats = {key: self.__readStatus(key) for key in drives}
|
||||
kodiLogNotice('fd628ExtStorageCount.__init__: Drive stats ' + str(self._driveStats))
|
||||
self._read = False
|
||||
self._write = False
|
||||
if (type == 'r'):
|
||||
self._read = True
|
||||
elif (type == 'w'):
|
||||
self._write = True
|
||||
elif (type == 'rw'):
|
||||
self._read = True
|
||||
self._write = True
|
||||
else:
|
||||
raise Exception('\'type\' must be \'r\', \'w\' or \'rw\'.')
|
||||
|
||||
def update(self):
|
||||
value = False
|
||||
if (self._drives == None):
|
||||
drives = self.__getAllDrives()
|
||||
else:
|
||||
drives = self.__getSelectedDrives()
|
||||
for drive in drives:
|
||||
if (not drive in self._driveStats):
|
||||
self._driveStats[drive] = None
|
||||
kodiLogNotice('fd628ExtStorageCount.update: New drive found \'{0}\''.format(drive))
|
||||
for path, stats in self._driveStats.iteritems():
|
||||
newStats = self.__readStatus(path)
|
||||
if (stats != None and newStats != None):
|
||||
if (self._read):
|
||||
value = value or stats[0] != newStats[0]
|
||||
if (self._write):
|
||||
value = value or stats[1] != newStats[1]
|
||||
self._driveStats[path] = newStats
|
||||
self._update(value)
|
||||
|
||||
def __readStatus(self, path):
|
||||
path = os.path.join('/sys/block', path, 'stat')
|
||||
if (os.path.isfile(path)):
|
||||
with open(path, 'rb') as status:
|
||||
values = status.read().split()
|
||||
return (values[2], values[6])
|
||||
else:
|
||||
return None
|
||||
|
||||
def __getAllDrives(self):
|
||||
drives = []
|
||||
for folder, subs, files in os.walk('/sys/block'):
|
||||
drives = [sub for sub in subs if (not sub.startswith('loop'))]
|
||||
return drives
|
||||
|
||||
def __getSelectedDrives(self):
|
||||
return [drive for drive in self.__getAllDrives() if ([d for d in self._drives if drive.startswith(d)])]
|
||||
@@ -1,19 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
|
||||
addonName = xbmcaddon.Addon(id='service.fd628').getAddonInfo('name')
|
||||
|
||||
def kodiLog(message, level = xbmc.LOGDEBUG):
|
||||
xbmc.log('{0} -> {1}'.format(addonName, str(message)), level)
|
||||
|
||||
def kodiLogError(message):
|
||||
kodiLog(message, xbmc.LOGERROR)
|
||||
|
||||
def kodiLogWarning(message):
|
||||
kodiLog(message, xbmc.LOGWARNING)
|
||||
|
||||
def kodiLogNotice(message):
|
||||
kodiLog(message, xbmc.LOGNOTICE)
|
||||
@@ -1,89 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
Author: SpliFF
|
||||
License: Public Domain
|
||||
|
||||
Python ioctl constants and functions module
|
||||
|
||||
Mostly follows specifications in asm-generic/ioctl.h from linux 2.5.36
|
||||
|
||||
Notable differences:
|
||||
* no architecture dependant stuff
|
||||
* size parameters are all passed as bytes, not types (ie pass 4, not int)
|
||||
|
||||
!! WARNING EXPERIMENTAL SOFTWARE !!
|
||||
Make sure the values returned by these functions are properly tested before using fcntl on anything remotely valuable!
|
||||
"""
|
||||
|
||||
NRBITS = 8
|
||||
TYPEBITS = 8
|
||||
|
||||
# may be arch dependent
|
||||
|
||||
SIZEBITS = 14
|
||||
DIRBITS = 2
|
||||
|
||||
NRMASK = (1 << NRBITS) - 1
|
||||
TYPEMASK = (1 << TYPEBITS) - 1
|
||||
SIZEMASK = (1 << SIZEBITS) - 1
|
||||
DIRMASK = (1 << DIRBITS) - 1
|
||||
|
||||
NRSHIFT = 0
|
||||
TYPESHIFT = NRSHIFT + NRBITS
|
||||
SIZESHIFT = TYPESHIFT + TYPEBITS
|
||||
DIRSHIFT = SIZESHIFT + SIZEBITS
|
||||
|
||||
# may be arch dependent
|
||||
|
||||
NONE = 0x0
|
||||
WRITE = 0x1
|
||||
READ = 0x2
|
||||
|
||||
# for the drivers/sound files...
|
||||
|
||||
IN = WRITE << DIRSHIFT
|
||||
OUT = READ << DIRSHIFT
|
||||
INOUT = (WRITE | READ) << DIRSHIFT
|
||||
IOCSIZE_MASK = SIZEMASK << SIZESHIFT
|
||||
IOCSIZE_SHIFT = SIZESHIFT
|
||||
|
||||
# used to create numbers ...
|
||||
|
||||
def IO( _type, nr):
|
||||
return IOC(NONE, _type, nr, 0)
|
||||
|
||||
def IOC(direction, _type, nr, size):
|
||||
return (direction << DIRSHIFT) | (_type << TYPESHIFT) | (nr << NRSHIFT) | (size << SIZESHIFT)
|
||||
|
||||
def IOR( _type, nr, size):
|
||||
return IOC(READ, _type, nr, size)
|
||||
|
||||
def IOW(_type, nr, size):
|
||||
return IOC(WRITE, _type, nr, size)
|
||||
|
||||
def IOWR(_type, nr, size):
|
||||
return IOC(READ|WRITE, _type, nr, size)
|
||||
|
||||
def IOR_BAD(_type, nr, size):
|
||||
return IOC(READ, _type, nr, size)
|
||||
|
||||
def IOW_BAD(_type, nr, size):
|
||||
return IOC(WRITE, _type, nr, size)
|
||||
|
||||
def IOWR_BAD(_type, nr, size):
|
||||
return IOC(READ|WRITE, _type, nr, size)
|
||||
|
||||
# used to decode ioctl numbers..
|
||||
|
||||
def DIR(nr):
|
||||
return (nr >> DIRSHIFT) & DIRMASK
|
||||
|
||||
def TYPE(nr):
|
||||
return (nr >> TYPESHIFT) & TYPEMASK
|
||||
|
||||
def NR(nr):
|
||||
return (nr >> NRSHIFT) & NRMASK
|
||||
|
||||
def SIZE(nr):
|
||||
return (nr >> SIZESHIFT) & SIZEMASK
|
||||
@@ -1,143 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
import xbmcaddon
|
||||
import threading
|
||||
import os
|
||||
import fd628states
|
||||
import fd628dev
|
||||
import fd628settings
|
||||
from fd628utils import *
|
||||
|
||||
addon = xbmcaddon.Addon(id='service.fd628')
|
||||
|
||||
class fd628Monitor(xbmc.Monitor):
|
||||
def __init__(self):
|
||||
super(fd628Monitor, self).__init__()
|
||||
self._settingsChangedCallback = None
|
||||
|
||||
def setSettingsChangedCallback(self, callbackObject):
|
||||
self._settingsChangedCallback = callbackObject
|
||||
|
||||
def onSettingsChanged(self):
|
||||
kodiLog('Enter fd628Monitor.onSettingsChanged')
|
||||
if (self._settingsChangedCallback != None):
|
||||
self._settingsChangedCallback.onSettingsChanged()
|
||||
|
||||
class fd628Addon():
|
||||
def __init__(self, monitor):
|
||||
self._fd628 = fd628dev.fd628Dev()
|
||||
self._states = []
|
||||
self._monitor = monitor
|
||||
self._monitor.setSettingsChangedCallback(self)
|
||||
self._settings = fd628settings.fd628Settings()
|
||||
self._vfdon = '/sys/class/leds/le-vfd/led_on'
|
||||
self._vfdoff = '/sys/class/leds/le-vfd/led_off'
|
||||
self._rlock = threading.RLock()
|
||||
|
||||
def run(self):
|
||||
firstLoop = True
|
||||
while not self._monitor.abortRequested():
|
||||
if self._monitor.waitForAbort(0.5):
|
||||
break
|
||||
if (not os.path.isfile(self._vfdon) or not os.path.isfile(self._vfdoff)):
|
||||
firstLoop = True
|
||||
continue
|
||||
if (firstLoop):
|
||||
self.onSettingsChanged()
|
||||
firstLoop = False
|
||||
self.__updateIndicators()
|
||||
self.__cleanUp()
|
||||
|
||||
def __updateIndicators(self):
|
||||
ledon = []
|
||||
ledoff = []
|
||||
if (self._rlock.acquire()):
|
||||
for state in self._states:
|
||||
state.update()
|
||||
if (state.hasChanged()):
|
||||
if (state.getValue()):
|
||||
ledon.append(state.getLedName())
|
||||
else:
|
||||
ledoff.append(state.getLedName())
|
||||
self.__writeFile(self._vfdon, ledon)
|
||||
self.__writeFile(self._vfdoff, ledoff)
|
||||
self._rlock.release()
|
||||
|
||||
def __cleanUp(self):
|
||||
self.__turnOffIndicators()
|
||||
self._monitor = None
|
||||
|
||||
def __turnOffIndicators(self):
|
||||
if (self._rlock.acquire()):
|
||||
ledoff = [state.getLedName() for state in self._states]
|
||||
self.__writeFile(self._vfdoff, ledoff)
|
||||
self._rlock.release()
|
||||
|
||||
def __writeFile(self, path, values):
|
||||
if (os.path.isfile(path)):
|
||||
with open(path, "wb") as vfd:
|
||||
for j in values:
|
||||
vfd.write(j)
|
||||
vfd.flush()
|
||||
|
||||
def onSettingsChanged(self):
|
||||
kodiLog('Enter fd628Addon.onSettingsChanged')
|
||||
self._settings.readValues()
|
||||
if (self._rlock.acquire()):
|
||||
self.__createStates()
|
||||
self._fd628.enableDisplay(self._settings.isDisplayOn())
|
||||
if (self._settings.isDisplayOn()):
|
||||
self._fd628.setBrightness(self._settings.getBrightness())
|
||||
if (self._settings.isAdvancedSettings()):
|
||||
self._fd628.setDisplayType(self._settings.getDisplay())
|
||||
self._fd628.setCharacterOrder(self._settings.getCharacterIndexes())
|
||||
else:
|
||||
self._fd628.useDtbConfig()
|
||||
if (self._colonIcon != None and self._settings.isColonOn()):
|
||||
self._colonIcon.turnOn()
|
||||
self.__updateIndicators()
|
||||
self._rlock.release()
|
||||
kodiLog('isDisplayOn = {0}'.format(self._settings.isDisplayOn()))
|
||||
kodiLog('getBrightness = {0}'.format(self._settings.getBrightness()))
|
||||
kodiLog('isAdvancedSettings = {0}'.format(self._settings.isAdvancedSettings()))
|
||||
kodiLog('getDisplayType = {0}'.format(self._settings.getDisplayType()))
|
||||
kodiLog('isCommonAnode = {0}'.format(self._settings.isCommonAnode()))
|
||||
kodiLog('getCharacterIndexex = {0}'.format(self._settings.getCharacterIndexes()))
|
||||
|
||||
def __createStates(self):
|
||||
settingsWindows = ['settings', 'systeminfo', 'systemsettings', 'servicesettings', 'pvrsettings', \
|
||||
'playersettings', 'mediasettings', 'interfacesettings', 'profiles', 'skinsettings', 'videossettings', \
|
||||
'musicsettings', 'appearancesettings', 'picturessettings', 'weathersettings', 'gamesettings', \
|
||||
'service-LibreELEC-Settings-mainWindow.xml', 'service-LibreELEC-Settings-wizard.xml', \
|
||||
'service-LibreELEC-Settings-getPasskey.xml']
|
||||
appsWindows = ['addonbrowser', 'addonsettings', 'addoninformation', 'addon', 'programs']
|
||||
states = []
|
||||
states.append(fd628states.fd628IconIndicator(True, 'power'))
|
||||
states.append(fd628states.fd628CondVisibility('play', 'Player.Playing'))
|
||||
states.append(fd628states.fd628CondVisibility('pause', 'Player.Paused'))
|
||||
states.append(fd628states.fd628FileContains('hdmi', '/sys/class/amhdmitx/amhdmitx0/hpd_state', ['1']))
|
||||
states.append(fd628states.fd628FileContains('cvbs', '/sys/class/display/mode', ['cvbs']))
|
||||
states.append(fd628states.fd628FileContains('eth', '/sys/class/net/eth0/operstate', ['up', 'unknown']))
|
||||
states.append(fd628states.fd628FileContains('wifi', '/sys/class/net/wlan0/operstate', ['up']))
|
||||
states.append(fd628states.fd628WindowChecker('setup', settingsWindows))
|
||||
states.append(fd628states.fd628WindowChecker('apps', appsWindows))
|
||||
states.append(fd628states.fd628ExtStorageChecker('usb', '/dev/sd'))
|
||||
states.append(fd628states.fd628ExtStorageChecker('sd', '/dev/mmcblk'))
|
||||
self._colonIcon = fd628states.fd628IconIndicator(False, 'colon')
|
||||
states.append(self._colonIcon)
|
||||
if (self._settings.isStorageIndicator()):
|
||||
for state in states:
|
||||
if (state.getLedName() == self._settings.getStorageIndicatorIcon()):
|
||||
states.remove(state)
|
||||
break
|
||||
states.append(fd628states.fd628ExtStorageCount(self._settings.getStorageIndicatorIcon(), None, 'rw'))
|
||||
kodiLog('Active states: ' + str([str(state) for state in states]))
|
||||
self.__turnOffIndicators()
|
||||
self._states = states
|
||||
|
||||
monitor = fd628Monitor()
|
||||
fd628 = fd628Addon(monitor)
|
||||
kodiLog('Service start.')
|
||||
fd628.run()
|
||||
kodiLog('Service stop.')
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<settings>
|
||||
<category label="30000">
|
||||
<setting label="30001" type="bool" id="display.on" default="true" />
|
||||
<setting label="30002" type="slider" id="display.brightness" default="7" range="0,7" option="int" visible="eq(-1,true)" />
|
||||
<setting label="30013" type="bool" id="display.storage.indicator" default="false" visible="eq(-2,true)" />
|
||||
<setting label="30014" type="labelenum" id="display.storage.indicator.icon" lvalues="30025|30015|30016|30017|30018|30019|30020|30021|30022|30023|30024|30027" default="30025" visible="eq(-3,true) + eq(-1,true)" subsetting="true" />
|
||||
<setting label="30028" type="bool" id="display.colon.on" default="false" visible="eq(-4,true)" />
|
||||
<setting label="30003" type="bool" id="display.advanced" default="false" visible="eq(-5,true)" />
|
||||
<setting label="30004" type="enum" id="display.type" values="0|1|2|3|4|5|6" default="1" visible="eq(-6,true) + eq(-1,true)" subsetting="true" />
|
||||
<setting label="30026" type="bool" id="display.common.anode" default="false" visible="eq(-7,true) + eq(-2,true)" subsetting="true" />
|
||||
<setting type="lsep" label="30012" visible="eq(-8,true) + eq(-3,true)" />
|
||||
<setting label="30005" type="enum" id="display.char.index0" values="0|1|2|3|4|5|6" default="0" visible="eq(-9 ,true) + eq(-4,true)" subsetting="true" />
|
||||
<setting label="30006" type="enum" id="display.char.index1" values="0|1|2|3|4|5|6" default="1" visible="eq(-10,true) + eq(-5,true)" subsetting="true" />
|
||||
<setting label="30007" type="enum" id="display.char.index2" values="0|1|2|3|4|5|6" default="2" visible="eq(-11,true) + eq(-6,true)" subsetting="true" />
|
||||
<setting label="30008" type="enum" id="display.char.index3" values="0|1|2|3|4|5|6" default="3" visible="eq(-12,true) + eq(-7,true)" subsetting="true" />
|
||||
<setting label="30009" type="enum" id="display.char.index4" values="0|1|2|3|4|5|6" default="4" visible="eq(-13,true) + eq(-8,true)" subsetting="true" />
|
||||
<setting label="30010" type="enum" id="display.char.index5" values="0|1|2|3|4|5|6" default="5" visible="false" subsetting="true" />
|
||||
<setting label="30011" type="enum" id="display.char.index6" values="0|1|2|3|4|5|6" default="6" visible="false" subsetting="true" />
|
||||
</category>
|
||||
</settings>
|
||||
@@ -1,3 +1,6 @@
|
||||
110
|
||||
- Fix RPi4 build to use dispmanx grabber
|
||||
|
||||
109
|
||||
- Update to version 2018-12-20
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ PKG_NAME="hyperion"
|
||||
PKG_VERSION="22f7be8df010fe8f0a51e3677fe0c8e709042622"
|
||||
PKG_SHA256="51cb6c5694d4bad67255ac4ae61a3c0aa481395c4868fb044a3ee19ca35bf19d"
|
||||
PKG_VERSION_DATE="2018-12-20"
|
||||
PKG_REV="109"
|
||||
PKG_REV="110"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_SITE="https://github.com/hyperion-project/hyperion"
|
||||
@@ -25,10 +25,7 @@ PKG_DISPMANX_SUPPORT="-DENABLE_DISPMANX=0"
|
||||
PKG_FB_SUPPORT="-DENABLE_FB=1"
|
||||
PKG_X11_SUPPORT="-DENABLE_X11=0"
|
||||
|
||||
if [ "$KODIPLAYER_DRIVER" = "libamcodec" ]; then
|
||||
PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET libamcodec"
|
||||
PKG_AMLOGIC_SUPPORT="-DENABLE_AMLOGIC=1"
|
||||
elif [ "$KODIPLAYER_DRIVER" = "bcm2835-driver" ]; then
|
||||
if [ "$PROJECT" = "RPi" ]; then
|
||||
PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET bcm2835-driver"
|
||||
PKG_DISPMANX_SUPPORT="-DENABLE_DISPMANX=1"
|
||||
PKG_FB_SUPPORT="-DENABLE_FB=0"
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
From 49f9c51f5519d48bae601c174914f82e8e71e093 Mon Sep 17 00:00:00 2001
|
||||
From: redpanther <redpanther@spooky-online.de>
|
||||
Date: Wed, 31 Aug 2016 14:39:14 +0200
|
||||
Subject: [PATCH] fix amlogic for newer kernels crosscompile stay on 32bit aml
|
||||
with kernel 3.10
|
||||
|
||||
backport 58a8e22 from hyperion.ng
|
||||
---
|
||||
libsrc/grabber/amlogic/AmlogicGrabber.cpp | 10 +++++++---
|
||||
libsrc/grabber/amlogic/CMakeLists.txt | 7 +++++++
|
||||
2 files changed, 14 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libsrc/grabber/amlogic/AmlogicGrabber.cpp b/libsrc/grabber/amlogic/AmlogicGrabber.cpp
|
||||
index 11cd280..5f39883 100644
|
||||
--- a/libsrc/grabber/amlogic/AmlogicGrabber.cpp
|
||||
+++ b/libsrc/grabber/amlogic/AmlogicGrabber.cpp
|
||||
@@ -20,9 +20,13 @@
|
||||
#define AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH _IOW(AMVIDEOCAP_IOC_MAGIC, 0x02, int)
|
||||
#define AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x03, int)
|
||||
|
||||
-// Flags copied from 'include/linux/amlogic/amports/amvstream.h' at https://github.com/codesnake/linux-amlogic
|
||||
-#define AMSTREAM_IOC_MAGIC 'S'
|
||||
-#define AMSTREAM_IOC_GET_VIDEO_DISABLE _IOR(AMSTREAM_IOC_MAGIC, 0x48, unsigned long)
|
||||
+#if HAVE_AML_HEADER
|
||||
+ #include <amcodec/amports/amstream.h>
|
||||
+#else
|
||||
+ // Flags copied from 'include/linux/amlogic/amports/amvstream.h' at https://github.com/codesnake/linux-amlogic
|
||||
+ #define AMSTREAM_IOC_MAGIC 'S'
|
||||
+ #define AMSTREAM_IOC_GET_VIDEO_DISABLE _IOR(AMSTREAM_IOC_MAGIC, 0x48, unsigned long)
|
||||
+#endif
|
||||
|
||||
AmlogicGrabber::AmlogicGrabber(const unsigned width, const unsigned height) :
|
||||
// Minimum required width or height is 160
|
||||
diff --git a/libsrc/grabber/amlogic/CMakeLists.txt b/libsrc/grabber/amlogic/CMakeLists.txt
|
||||
index cf8844b..326f7c7 100644
|
||||
--- a/libsrc/grabber/amlogic/CMakeLists.txt
|
||||
+++ b/libsrc/grabber/amlogic/CMakeLists.txt
|
||||
@@ -1,3 +1,4 @@
|
||||
+INCLUDE (CheckIncludeFiles)
|
||||
|
||||
# Define the current source locations
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
|
||||
@@ -21,6 +22,12 @@ else(ENABLE_QT5)
|
||||
QT4_WRAP_CPP(AmlogicHEADERS_MOC ${AmlogicQT_HEADERS})
|
||||
endif(ENABLE_QT5)
|
||||
|
||||
+CHECK_INCLUDE_FILES ("amcodec/amports/amstream.h" HAVE_AML_HEADER)
|
||||
+IF (${HAVE_AML_HEADER})
|
||||
+ ADD_DEFINITIONS( -DHAVE_AML_HEADER )
|
||||
+ENDIF()
|
||||
+
|
||||
+
|
||||
add_library(amlogic-grabber
|
||||
${AmlogicHEADERS}
|
||||
${AmlogicQT_HEADERS}
|
||||
--
|
||||
2.9.3
|
||||
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
117
|
||||
- Update to 51a634d (2019-07-23)
|
||||
- Set bit rate to 320 kpbs
|
||||
|
||||
116
|
||||
- Update to 4e3576b (2019-06-01)
|
||||
- Only use Kodi
|
||||
- Rework
|
||||
|
||||
115
|
||||
- Update to daeeeaa (22-02-2019)
|
||||
- Update to daeeeaa (2019-02-22)
|
||||
|
||||
114
|
||||
- Fix discovery mode setting
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2017 Shane Meagher (shanemeagher)
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="librespot"
|
||||
PKG_VERSION="daeeeaa122fc2d71edf11e562e23038db4210b39"
|
||||
PKG_SHA256="e9ebb8ca09c850598ae8c222bdab44e7d8321cb3c36017ba8e17a41db418c06e"
|
||||
PKG_VERSION_DATE="2019-02-22"
|
||||
PKG_REV="115"
|
||||
PKG_VERSION="51a634dc33233ca85a92db3e723d19550b548593"
|
||||
PKG_SHA256="581727e560c81cafbfeaf611b51f0a6987a48d348795785b3b6c0a304656a731"
|
||||
PKG_VERSION_DATE="2019-07-23"
|
||||
PKG_REV="117"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="MIT"
|
||||
PKG_SITE="https://github.com/librespot-org/librespot/"
|
||||
PKG_URL="https://github.com/librespot-org/librespot/archive/$PKG_VERSION.zip"
|
||||
PKG_DEPENDS_TARGET="toolchain avahi pulseaudio pyalsaaudio rust"
|
||||
PKG_DEPENDS_TARGET="toolchain avahi pulseaudio rust"
|
||||
PKG_SECTION="service"
|
||||
PKG_SHORTDESC="Librespot: play Spotify through LibreELEC using a Spotify app as a remote"
|
||||
PKG_LONGDESC="Librespot ($PKG_VERSION_DATE) plays Spotify through LibreELEC using the open source librespot library using a Spotify app as a remote."
|
||||
PKG_SHORTDESC="Librespot: play Spotify through Kodi using a Spotify app as a remote"
|
||||
PKG_LONGDESC="Librespot ($PKG_VERSION_DATE) lets you play Spotify through Kodi using a Spotify app as a remote."
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
PKG_IS_ADDON="yes"
|
||||
PKG_ADDON_NAME="Librespot"
|
||||
PKG_ADDON_TYPE="xbmc.service.library"
|
||||
PKG_ADDON_TYPE="xbmc.service"
|
||||
PKG_MAINTAINER="Anton Voyl (awiouy)"
|
||||
|
||||
configure_target() {
|
||||
@@ -29,21 +29,17 @@ configure_target() {
|
||||
|
||||
make_target() {
|
||||
cd src
|
||||
$CARGO_BUILD --no-default-features --features "alsa-backend pulseaudio-backend with-dns-sd"
|
||||
$CARGO_BUILD --no-default-features --features "pulseaudio-backend with-dns-sd"
|
||||
cd "$PKG_BUILD/.$TARGET_NAME"/*/release
|
||||
$STRIP librespot
|
||||
}
|
||||
|
||||
addon() {
|
||||
mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID"
|
||||
cp "$(get_build_dir pyalsaaudio)/.install_pkg/usr/lib/$PKG_PYTHON_VERSION/site-packages/alsaaudio.so" \
|
||||
"$ADDON_BUILD/$PKG_ADDON_ID"
|
||||
|
||||
mkdir -p "$ADDON_BUILD/$PKG_ADDON_ID/bin"
|
||||
cp "$PKG_BUILD/.$TARGET_NAME"/*/release/librespot \
|
||||
"$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"
|
||||
cp "$(get_build_dir avahi)/avahi-compat-libdns_sd/.libs/libdns_sd.so.1" \
|
||||
"$ADDON_BUILD/$PKG_ADDON_ID/lib"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
diff --git a/playback/src/config.rs b/playback/src/config.rs
|
||||
index 0f71110..931167d 100644
|
||||
--- a/playback/src/config.rs
|
||||
+++ b/playback/src/config.rs
|
||||
@@ -30,6 +30,7 @@ pub struct PlayerConfig {
|
||||
pub bitrate: Bitrate,
|
||||
pub normalisation: bool,
|
||||
pub normalisation_pregain: f32,
|
||||
+ pub notify_kodi: bool,
|
||||
}
|
||||
|
||||
impl Default for PlayerConfig {
|
||||
@@ -38,6 +39,7 @@ impl Default for PlayerConfig {
|
||||
bitrate: Bitrate::default(),
|
||||
normalisation: false,
|
||||
normalisation_pregain: 0.0,
|
||||
+ notify_kodi: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/playback/src/player.rs b/playback/src/player.rs
|
||||
index ab1a8ab..19d6394 100644
|
||||
--- a/playback/src/player.rs
|
||||
+++ b/playback/src/player.rs
|
||||
@@ -4,7 +4,8 @@ use futures::sync::oneshot;
|
||||
use futures::{future, Future};
|
||||
use std;
|
||||
use std::borrow::Cow;
|
||||
-use std::io::{Read, Result, Seek, SeekFrom};
|
||||
+use std::fs::OpenOptions;
|
||||
+use std::io::{Read, Result, Seek, SeekFrom, Write};
|
||||
use std::mem;
|
||||
use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError};
|
||||
use std::thread;
|
||||
@@ -394,6 +395,14 @@ impl PlayerInternal {
|
||||
}
|
||||
}
|
||||
|
||||
+ fn notify_kodi(&mut self, id: &str, track_id: &SpotifyId) {
|
||||
+ // println!("fifo = {} {}", id, track_id.to_base62());
|
||||
+ if self.config.notify_kodi {
|
||||
+ let mut file = OpenOptions::new().write(true).open("/tmp/librespot").unwrap();
|
||||
+ writeln!(&mut file, "{}\n{}", id, track_id.to_base62()).unwrap();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
fn handle_command(&mut self, cmd: PlayerCommand) {
|
||||
debug!("command={:?}", cmd);
|
||||
match cmd {
|
||||
@@ -413,11 +422,17 @@ impl PlayerInternal {
|
||||
| PlayerState::EndOfTrack {
|
||||
track_id: old_track_id,
|
||||
..
|
||||
- } => self.send_event(PlayerEvent::Changed {
|
||||
- old_track_id: old_track_id,
|
||||
- new_track_id: track_id,
|
||||
- }),
|
||||
- _ => self.send_event(PlayerEvent::Started { track_id }),
|
||||
+ } => {
|
||||
+ self.send_event(PlayerEvent::Changed {
|
||||
+ old_track_id: old_track_id,
|
||||
+ new_track_id: track_id,
|
||||
+ });
|
||||
+ self.notify_kodi("1", &track_id)
|
||||
+ }
|
||||
+ _ => {
|
||||
+ self.send_event(PlayerEvent::Started { track_id });
|
||||
+ self.notify_kodi("2", &track_id)
|
||||
+ }
|
||||
}
|
||||
|
||||
self.start_sink();
|
||||
@@ -443,13 +458,17 @@ impl PlayerInternal {
|
||||
| PlayerState::EndOfTrack {
|
||||
track_id: old_track_id,
|
||||
..
|
||||
- } => self.send_event(PlayerEvent::Changed {
|
||||
- old_track_id: old_track_id,
|
||||
- new_track_id: track_id,
|
||||
- }),
|
||||
+ } => {
|
||||
+ self.send_event(PlayerEvent::Changed {
|
||||
+ old_track_id: old_track_id,
|
||||
+ new_track_id: track_id,
|
||||
+ });
|
||||
+ self.notify_kodi("3", &track_id)
|
||||
+ }
|
||||
_ => (),
|
||||
}
|
||||
self.send_event(PlayerEvent::Stopped { track_id });
|
||||
+ self.notify_kodi("4", &track_id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,6 +495,7 @@ impl PlayerInternal {
|
||||
|
||||
self.send_event(PlayerEvent::Started { track_id });
|
||||
self.start_sink();
|
||||
+ self.notify_kodi("5", &track_id)
|
||||
} else {
|
||||
warn!("Player::play called from invalid state");
|
||||
}
|
||||
@@ -487,6 +507,7 @@ impl PlayerInternal {
|
||||
|
||||
self.stop_sink_if_running();
|
||||
self.send_event(PlayerEvent::Stopped { track_id });
|
||||
+ self.notify_kodi("6", &track_id)
|
||||
} else {
|
||||
warn!("Player::pause called from invalid state");
|
||||
}
|
||||
@@ -499,6 +520,7 @@ impl PlayerInternal {
|
||||
self.stop_sink_if_running();
|
||||
self.send_event(PlayerEvent::Stopped { track_id });
|
||||
self.state = PlayerState::Stopped;
|
||||
+ self.notify_kodi("7", &track_id)
|
||||
}
|
||||
PlayerState::Stopped => {
|
||||
warn!("Player::stop called from invalid state");
|
||||
diff --git a/src/main.rs b/src/main.rs
|
||||
index 36cd1b5..502cac8 100644
|
||||
--- a/src/main.rs
|
||||
+++ b/src/main.rs
|
||||
@@ -168,6 +168,11 @@ fn setup(args: &[String]) -> Setup {
|
||||
"Pregain (dB) applied by volume normalisation",
|
||||
"PREGAIN",
|
||||
)
|
||||
+ .optflag(
|
||||
+ "",
|
||||
+ "notify-kodi",
|
||||
+ "Notify Kodi",
|
||||
+ )
|
||||
.optflag(
|
||||
"",
|
||||
"linear-volume",
|
||||
@@ -248,6 +253,8 @@ fn setup(args: &[String]) -> Setup {
|
||||
)
|
||||
};
|
||||
|
||||
+ let notify_kodi = matches.opt_present("notify-kodi");
|
||||
+
|
||||
let session_config = {
|
||||
let device_id = device_id(&name);
|
||||
|
||||
@@ -291,6 +298,7 @@ fn setup(args: &[String]) -> Setup {
|
||||
.opt_str("normalisation-pregain")
|
||||
.map(|pregain| pregain.parse::<f32>().expect("Invalid pregain float value"))
|
||||
.unwrap_or(PlayerConfig::default().normalisation_pregain),
|
||||
+ notify_kodi: notify_kodi,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
From 109452968762175b255d3a46d2447bf103022a68 Mon Sep 17 00:00:00 2001
|
||||
From: awiouy <awiouy@gmail.com>
|
||||
Date: Wed, 7 Nov 2018 07:49:31 +0100
|
||||
Subject: [PATCH] libreelec: kodi hooks
|
||||
|
||||
---
|
||||
playback/src/player.rs | 44 ++++++++++++++++++++++++++-----------
|
||||
src/player_event_handler.rs | 8 +++++--
|
||||
2 files changed, 37 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/playback/src/player.rs b/playback/src/player.rs
|
||||
index ab1a8ab..0aa0630 100644
|
||||
--- a/playback/src/player.rs
|
||||
+++ b/playback/src/player.rs
|
||||
@@ -49,15 +49,18 @@ enum PlayerCommand {
|
||||
pub enum PlayerEvent {
|
||||
Started {
|
||||
track_id: SpotifyId,
|
||||
+ new_state: String,
|
||||
},
|
||||
|
||||
Changed {
|
||||
old_track_id: SpotifyId,
|
||||
new_track_id: SpotifyId,
|
||||
+ new_state: String,
|
||||
},
|
||||
|
||||
Stopped {
|
||||
track_id: SpotifyId,
|
||||
+ new_state: String,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -413,11 +416,18 @@ impl PlayerInternal {
|
||||
| PlayerState::EndOfTrack {
|
||||
track_id: old_track_id,
|
||||
..
|
||||
- } => self.send_event(PlayerEvent::Changed {
|
||||
- old_track_id: old_track_id,
|
||||
- new_track_id: track_id,
|
||||
- }),
|
||||
- _ => self.send_event(PlayerEvent::Started { track_id }),
|
||||
+ } => {
|
||||
+ let new_state = "play".to_string();
|
||||
+ self.send_event(PlayerEvent::Changed {
|
||||
+ old_track_id: old_track_id,
|
||||
+ new_track_id: track_id,
|
||||
+ new_state: new_state,
|
||||
+ });
|
||||
+ },
|
||||
+ _ => {
|
||||
+ let new_state = "play".to_string();
|
||||
+ self.send_event(PlayerEvent::Started { track_id, new_state });
|
||||
+ },
|
||||
}
|
||||
|
||||
self.start_sink();
|
||||
@@ -443,13 +453,18 @@ impl PlayerInternal {
|
||||
| PlayerState::EndOfTrack {
|
||||
track_id: old_track_id,
|
||||
..
|
||||
- } => self.send_event(PlayerEvent::Changed {
|
||||
- old_track_id: old_track_id,
|
||||
- new_track_id: track_id,
|
||||
- }),
|
||||
+ } => {
|
||||
+ let new_state = "pause".to_string();
|
||||
+ self.send_event(PlayerEvent::Changed {
|
||||
+ old_track_id: old_track_id,
|
||||
+ new_track_id: track_id,
|
||||
+ new_state: new_state,
|
||||
+ })
|
||||
+ },
|
||||
_ => (),
|
||||
}
|
||||
- self.send_event(PlayerEvent::Stopped { track_id });
|
||||
+ let new_state = "pause".to_string();
|
||||
+ self.send_event(PlayerEvent::Stopped { track_id, new_state });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,7 +489,8 @@ impl PlayerInternal {
|
||||
if let PlayerState::Paused { track_id, .. } = self.state {
|
||||
self.state.paused_to_playing();
|
||||
|
||||
- self.send_event(PlayerEvent::Started { track_id });
|
||||
+ let new_state = "play".to_string();
|
||||
+ self.send_event(PlayerEvent::Started { track_id, new_state });
|
||||
self.start_sink();
|
||||
} else {
|
||||
warn!("Player::play called from invalid state");
|
||||
@@ -486,7 +502,8 @@ impl PlayerInternal {
|
||||
self.state.playing_to_paused();
|
||||
|
||||
self.stop_sink_if_running();
|
||||
- self.send_event(PlayerEvent::Stopped { track_id });
|
||||
+ let new_state = "pause".to_string();
|
||||
+ self.send_event(PlayerEvent::Stopped { track_id, new_state });
|
||||
} else {
|
||||
warn!("Player::pause called from invalid state");
|
||||
}
|
||||
@@ -497,7 +514,8 @@ impl PlayerInternal {
|
||||
| PlayerState::Paused { track_id, .. }
|
||||
| PlayerState::EndOfTrack { track_id } => {
|
||||
self.stop_sink_if_running();
|
||||
- self.send_event(PlayerEvent::Stopped { track_id });
|
||||
+ let new_state = "stop".to_string();
|
||||
+ self.send_event(PlayerEvent::Stopped { track_id, new_state });
|
||||
self.state = PlayerState::Stopped;
|
||||
}
|
||||
PlayerState::Stopped => {
|
||||
diff --git a/src/player_event_handler.rs b/src/player_event_handler.rs
|
||||
index 1e682b9..3b478f1 100644
|
||||
--- a/src/player_event_handler.rs
|
||||
+++ b/src/player_event_handler.rs
|
||||
@@ -19,18 +19,22 @@ pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> io::Result<Ch
|
||||
PlayerEvent::Changed {
|
||||
old_track_id,
|
||||
new_track_id,
|
||||
+ new_state,
|
||||
} => {
|
||||
env_vars.insert("PLAYER_EVENT", "change".to_string());
|
||||
env_vars.insert("OLD_TRACK_ID", old_track_id.to_base62());
|
||||
env_vars.insert("TRACK_ID", new_track_id.to_base62());
|
||||
+ env_vars.insert("STATE", new_state.to_string());
|
||||
}
|
||||
- PlayerEvent::Started { track_id } => {
|
||||
+ PlayerEvent::Started { track_id, new_state } => {
|
||||
env_vars.insert("PLAYER_EVENT", "start".to_string());
|
||||
env_vars.insert("TRACK_ID", track_id.to_base62());
|
||||
+ env_vars.insert("STATE", new_state.to_string());
|
||||
}
|
||||
- PlayerEvent::Stopped { track_id } => {
|
||||
+ PlayerEvent::Stopped { track_id, new_state } => {
|
||||
env_vars.insert("PLAYER_EVENT", "stop".to_string());
|
||||
env_vars.insert("TRACK_ID", track_id.to_base62());
|
||||
+ env_vars.insert("STATE", new_state.to_string());
|
||||
}
|
||||
}
|
||||
run_program(onevent, env_vars)
|
||||
@@ -12,7 +12,7 @@ index 88f6280..4e7186b 100644
|
||||
--- a/playback/src/audio_backend/pulseaudio.rs
|
||||
+++ b/playback/src/audio_backend/pulseaudio.rs
|
||||
@@ -76,6 +76,7 @@ impl Open for PulseAudioSink {
|
||||
|
||||
|
||||
impl Sink for PulseAudioSink {
|
||||
fn start(&mut self) -> io::Result<()> {
|
||||
+ let sink = CString::new("librespot_sink").unwrap();
|
||||
@@ -24,7 +24,7 @@ index 88f6280..4e7186b 100644
|
||||
self.name.as_ptr(), // Our application's name.
|
||||
PA_STREAM_PLAYBACK,
|
||||
- null(), // Use the default device.
|
||||
+ sink.as_ptr(), // Our sink.
|
||||
+ sink.as_ptr(), // Our sink.
|
||||
self.desc.as_ptr(), // desc of our stream.
|
||||
&self.ss, // Our sample format.
|
||||
null(), // Use default channel map
|
||||
@@ -1,22 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
import alsaaudio
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
|
||||
|
||||
dialog = xbmcgui.Dialog()
|
||||
strings = xbmcaddon.Addon().getLocalizedString
|
||||
while True:
|
||||
pcms = alsaaudio.pcms()[1:]
|
||||
if len(pcms) == 0:
|
||||
dialog.ok(xbmcaddon.Addon().getAddonInfo('name'), strings(30210))
|
||||
break
|
||||
pcmx = dialog.select(strings(30115), pcms)
|
||||
if pcmx == -1:
|
||||
break
|
||||
pcm = pcms[pcmx]
|
||||
xbmcaddon.Addon().setSetting('ls_o', pcm)
|
||||
break
|
||||
del dialog
|
||||
@@ -1,2 +0,0 @@
|
||||
LS_PORT="6666"
|
||||
LS_SINK="librespot_sink"
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
echo -e "$STATE\n$TRACK_ID" > "$LS_FIFO"
|
||||
@@ -3,110 +3,35 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
f="/storage/.kodi/userdata/addon_data/service.librespot/settings.xml"
|
||||
[ -f "$f" ] && sed -i 's/ls_O/ls_m/g' "$f"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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"
|
||||
;;
|
||||
*)
|
||||
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\" \
|
||||
--onevent librespot.onevent"
|
||||
PORT="6666"
|
||||
SINK_NAME="librespot_sink"
|
||||
|
||||
if [ -n "$ls_b" -a "$ls_b" != "-" ]; then
|
||||
LIBRESPOT="$LIBRESPOT --bitrate $ls_b"
|
||||
if ! pactl list modules short | grep "sink_name=$SINK_NAME"; then
|
||||
pactl load-module module-null-sink sink_name="$SINK_NAME" > /dev/null
|
||||
fi
|
||||
if ! pactl list modules short | grep "source=$SINK_NAME"; then
|
||||
pactl load-module module-rtp-send source="$SINK_NAME.monitor" \
|
||||
destination_ip=127.0.0.1 port="$PORT" source_ip=127.0.0.1 > /dev/null
|
||||
fi
|
||||
pactl suspend-sink "$SINK_NAME" 1
|
||||
|
||||
LIBRESPOT="librespot \
|
||||
--backend pulseaudio \
|
||||
--bitrate 320 \
|
||||
--cache \"$ADDON_HOME/cache\" \
|
||||
--device-type TV \
|
||||
--disable-audio-cache \
|
||||
--name \"Kodi ($HOSTNAME)\" \
|
||||
--notify-kodi"
|
||||
|
||||
if [ "$ls_a" = "true" -a -n "$ls_p" -a -n "$ls_u" ]; then
|
||||
LIBRESPOT="$LIBRESPOT --disable-discovery \
|
||||
--password \"$ls_p\" \
|
||||
--username \"$ls_u\""
|
||||
LIBRESPOT="$LIBRESPOT \
|
||||
--disable-discovery \
|
||||
--password \"$ls_p\" \
|
||||
--username \"$ls_u\""
|
||||
fi
|
||||
|
||||
if [ "$ls_m" = "Kodi" ]; then
|
||||
LIBRESPOT="$LIBRESPOT --backend pulseaudio --device-type TV"
|
||||
else
|
||||
init_alsa
|
||||
if [ -n "$ls_o" ]; then
|
||||
LIBRESPOT="$LIBRESPOT --device \"$ls_o\""
|
||||
fi
|
||||
LIBRESPOT="$LIBRESPOT --device-type Speaker"
|
||||
fi
|
||||
|
||||
if [ -z "$(pactl list short modules | grep sink_name=$LS_SINK)" ]; then
|
||||
pactl load-module module-null-sink sink_name="$LS_SINK" > /dev/null
|
||||
fi
|
||||
pactl suspend-sink "$LS_SINK" 1
|
||||
if [ -z "$(pactl list short modules | grep source=$LS_SINK.monitor)" ]; then
|
||||
pactl load-module module-rtp-send source="$LS_SINK.monitor" \
|
||||
destination_ip=127.0.0.1 port="$LS_PORT" source_ip=127.0.0.1 > /dev/null
|
||||
fi
|
||||
|
||||
export LS_FIFO="/var/run/librespot"
|
||||
|
||||
eval $LIBRESPOT
|
||||
|
||||
@@ -1,13 +1,224 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
import urllib
|
||||
import urllib2
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'resources', 'lib'))
|
||||
ADDON = xbmcaddon.Addon()
|
||||
ADDON_ID = ADDON.getAddonInfo('id')
|
||||
ADDON_NAME = ADDON.getAddonInfo('name')
|
||||
FIFO = '/tmp/librespot'
|
||||
LOG_LEVEL = xbmc.LOGNOTICE
|
||||
LOG_MESSAGE = ADDON.getAddonInfo('name') + ': {}'
|
||||
SINK_NAME = "librespot_sink"
|
||||
SPOTIFY_ID = '169df5532dee47a59913f8528e83ae71'
|
||||
SPOTIFY_SECRET = '1f3d8b507bbe4f68beb3a4472e8ad411'
|
||||
STREAM_CODEC = 'pcm_s16be'
|
||||
STREAM_PORT = '6666'
|
||||
STREAM_URL = 'rtp://127.0.0.1:{}'.format(STREAM_PORT)
|
||||
|
||||
from ls_monitor import Monitor as Monitor
|
||||
|
||||
def log(message):
|
||||
xbmc.log(LOG_MESSAGE.format(message), LOG_LEVEL)
|
||||
|
||||
|
||||
class Monitor(xbmc.Monitor):
|
||||
|
||||
def __init__(self):
|
||||
log('monitor started')
|
||||
self.player = Player()
|
||||
|
||||
def onSettingsChanged(self):
|
||||
log('settings changed')
|
||||
self.player.update()
|
||||
|
||||
def waitForAbort(self):
|
||||
super(Monitor, self).waitForAbort()
|
||||
log('abort requested')
|
||||
self.player.abort()
|
||||
|
||||
|
||||
class Player(threading.Thread, xbmc.Player):
|
||||
|
||||
def __init__(self):
|
||||
log('player started')
|
||||
super(Player, self).__init__()
|
||||
self.isLibrespotStarted = True
|
||||
self.listitem = xbmcgui.ListItem()
|
||||
self.listitem.addStreamInfo('audio', {'codec': STREAM_CODEC})
|
||||
self.listitem.setPath(STREAM_URL)
|
||||
self.spotify = Spotify()
|
||||
if self.isPlaying():
|
||||
self.onAVStarted()
|
||||
else:
|
||||
self.playingFile = ''
|
||||
self.onPlayBackStopped()
|
||||
self.start()
|
||||
|
||||
def abort(self):
|
||||
log('aborting player')
|
||||
with open(FIFO, 'w') as fifo:
|
||||
fifo.close()
|
||||
self.join()
|
||||
|
||||
def onAVChange(self):
|
||||
self.onAVStarted()
|
||||
|
||||
def onAVStarted(self):
|
||||
log('playback started')
|
||||
self.playingFile = self.getPlayingFile()
|
||||
if self.isLibrespotStarted and (self.playingFile != STREAM_URL):
|
||||
self.isLibrespotStarted = False
|
||||
self.systemctl('stop')
|
||||
|
||||
def onPlayBackEnded(self):
|
||||
self.onPlayBackStopped()
|
||||
|
||||
def onPlayBackError(self):
|
||||
self.onPlayBackStopped()
|
||||
|
||||
def onPlayBackStopped(self):
|
||||
log('playback stopped')
|
||||
if self.playingFile == STREAM_URL:
|
||||
self.systemctl('restart')
|
||||
elif not self.isLibrespotStarted:
|
||||
self.systemctl('start')
|
||||
self.isLibrespotStarted = True
|
||||
|
||||
def pauseLibrespot(self):
|
||||
if self.isPlaying() and (self.getPlayingFile() == STREAM_URL):
|
||||
log('pausing librespot playback')
|
||||
self.pause()
|
||||
|
||||
def playLibrespot(self, track_id):
|
||||
track = self.spotify.getTrack(track_id)
|
||||
self.listitem.setArt(track.getArt())
|
||||
self.listitem.setInfo('music', track.getInfo())
|
||||
if not self.isPlaying():
|
||||
subprocess.call(['pactl', 'suspend-sink', SINK_NAME, '0'])
|
||||
log('starting librespot playback')
|
||||
self.play(STREAM_URL, self.listitem)
|
||||
elif self.getPlayingFile() == STREAM_URL:
|
||||
log('updating librespot playback')
|
||||
self.updateInfoTag(self.listitem)
|
||||
|
||||
def run(self):
|
||||
log('control pipe started')
|
||||
try:
|
||||
os.unlink(FIFO)
|
||||
except OSError:
|
||||
pass
|
||||
os.mkfifo(FIFO)
|
||||
while (os.path.exists(FIFO) and
|
||||
stat.S_ISFIFO(os.stat(FIFO).st_mode)):
|
||||
with open(FIFO, 'r') as fifo:
|
||||
command = fifo.read().splitlines()
|
||||
log('control pipe {}'.format(str(command)))
|
||||
if len(command) == 0:
|
||||
break
|
||||
elif command[0] in ['3', '5', '6']:
|
||||
self.pauseLibrespot()
|
||||
elif command[0] in ['1', '2', '4']:
|
||||
self.playLibrespot(command[1])
|
||||
elif command[0] in ['7']:
|
||||
self.stopLibrespot()
|
||||
try:
|
||||
os.unlink(FIFO)
|
||||
except OSError:
|
||||
pass
|
||||
log('control pipe stopped')
|
||||
|
||||
def stopLibrespot(self):
|
||||
if self.isPlaying() and (self.getPlayingFile() == STREAM_URL):
|
||||
log('stopping librespot playback')
|
||||
self.stop()
|
||||
|
||||
def systemctl(self, command):
|
||||
log('{} librespot'.format(command))
|
||||
subprocess.call(['systemctl', command, ADDON_ID])
|
||||
|
||||
def update(self):
|
||||
log('updating player')
|
||||
if self.isLibrespotStarted:
|
||||
self.systemctl('restart')
|
||||
|
||||
|
||||
class Spotify():
|
||||
|
||||
def __init__(self):
|
||||
self.headers = None
|
||||
self.expiration = time.time()
|
||||
self.request = [
|
||||
'https://accounts.spotify.com/api/token',
|
||||
urllib.urlencode({'grant_type': 'client_credentials'}),
|
||||
{'Authorization': 'Basic {}'.format(base64.b64encode(
|
||||
'{}:{}'.format(SPOTIFY_ID, SPOTIFY_SECRET)))}
|
||||
]
|
||||
|
||||
def getHeaders(self):
|
||||
if time.time() > self.expiration:
|
||||
log('token expired')
|
||||
token = json.loads(urllib2.urlopen(
|
||||
urllib2.Request(*self.request)).read())
|
||||
log('new token expires in {} seconds'.format(token['expires_in']))
|
||||
self.expiration = time.time() + float(token['expires_in']) - 60
|
||||
self.headers = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer {}'.format(token['access_token'])
|
||||
}
|
||||
|
||||
def getTrack(self, track_id):
|
||||
log('getting track')
|
||||
try:
|
||||
self.getHeaders()
|
||||
track = json.loads(urllib2.urlopen(urllib2.Request(
|
||||
'https://api.spotify.com/v1/tracks/{}'.format(track_id), None,
|
||||
self.headers)).read())
|
||||
except Exception as e:
|
||||
log('failed to get track from Spotify: {}'.format(e))
|
||||
track = dict()
|
||||
return Track(track)
|
||||
|
||||
|
||||
class Track():
|
||||
|
||||
def __init__(self, track):
|
||||
self.track = track
|
||||
|
||||
def get(self, default, *indices):
|
||||
tree = self.track
|
||||
try:
|
||||
for index in indices:
|
||||
tree = tree[index]
|
||||
except LookupError:
|
||||
tree = default
|
||||
return tree
|
||||
|
||||
def getArt(self):
|
||||
return {
|
||||
'thumb': self.get('', 'album', 'images', 0, 'url')
|
||||
}
|
||||
|
||||
def getInfo(self):
|
||||
return {
|
||||
'album': self.get('', 'album', 'name'),
|
||||
'artist': self.get('', 'artists', 0, 'name'),
|
||||
'title': self.get('', 'name'),
|
||||
}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
log('service started')
|
||||
Monitor().waitForAbort()
|
||||
log('service stopped')
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PORT="6666"
|
||||
SINK_NAME="librespot_sink"
|
||||
@@ -4,81 +4,17 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30100"
|
||||
msgid "Librespot"
|
||||
msgid "Configuration"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30102"
|
||||
msgid "Bit rate"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30103"
|
||||
msgid "-"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30104"
|
||||
msgid "96"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30105"
|
||||
msgid "160"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30106"
|
||||
msgid "320"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30107"
|
||||
msgid "Output mode"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30108"
|
||||
msgid "ALSA"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30109"
|
||||
msgid "Kodi"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30112"
|
||||
msgctxt "#30101"
|
||||
msgid "User mode"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "ALSA"
|
||||
msgctxt "#30102"
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Configuration wizard"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30115"
|
||||
msgid "Playback device"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Playback route"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30117"
|
||||
msgid "auto detect"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "headphone jack"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30119"
|
||||
msgid "HDMI"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "Could not find a playback device"
|
||||
msgctxt "#30103"
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user