lomiri.lomiri-music-app: init at 3.2.2 (#364958)

This commit is contained in:
Cosima Neidahl
2025-02-11 11:31:39 +01:00
committed by GitHub
8 changed files with 386 additions and 25 deletions
@@ -95,6 +95,7 @@ in
lomiri-gallery-app
lomiri-history-service
lomiri-mediaplayer-app
lomiri-music-app
lomiri-polkit-agent
lomiri-schemas # exposes some required dbus interfaces
lomiri-session # wrappers to properly launch the session
@@ -198,37 +199,54 @@ in
"/share/sounds"
];
systemd.user.services = {
# Unconditionally run service that collects system-installed URL handlers before LUD
# TODO also run user-installed one?
"lomiri-url-dispatcher-update-system-dir" = {
description = "Lomiri URL dispatcher system directory updater";
wantedBy = [ "lomiri-url-dispatcher.service" ];
before = [ "lomiri-url-dispatcher.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.lomiri.lomiri-url-dispatcher}/libexec/lomiri-url-dispatcher/lomiri-update-directory /run/current-system/sw/share/lomiri-url-dispatcher/urls/";
};
};
"lomiri-polkit-agent" = rec {
description = "Lomiri Polkit agent";
wantedBy = [
systemd.user.services =
let
lomiriServiceNames = [
"lomiri.service"
"lomiri-full-greeter.service"
"lomiri-full-shell.service"
"lomiri-greeter.service"
"lomiri-shell.service"
];
after = [ "graphical-session.target" ];
partOf = wantedBy;
serviceConfig = {
Type = "simple";
Restart = "always";
ExecStart = "${pkgs.lomiri.lomiri-polkit-agent}/libexec/lomiri-polkit-agent/policykit-agent";
in
{
# Unconditionally run service that collects system-installed URL handlers before LUD
# TODO also run user-installed one?
"lomiri-url-dispatcher-update-system-dir" = {
description = "Lomiri URL dispatcher system directory updater";
wantedBy = [ "lomiri-url-dispatcher.service" ];
before = [ "lomiri-url-dispatcher.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.lomiri.lomiri-url-dispatcher}/libexec/lomiri-url-dispatcher/lomiri-update-directory /run/current-system/sw/share/lomiri-url-dispatcher/urls/";
};
};
"lomiri-polkit-agent" = {
description = "Lomiri Polkit agent";
wantedBy = lomiriServiceNames;
after = [ "graphical-session.target" ];
partOf = lomiriServiceNames;
serviceConfig = {
Type = "simple";
Restart = "always";
ExecStart = "${pkgs.lomiri.lomiri-polkit-agent}/libexec/lomiri-polkit-agent/policykit-agent";
};
};
"mediascanner-2.0" = {
description = "Media Scanner";
wantedBy = lomiriServiceNames;
before = lomiriServiceNames;
partOf = lomiriServiceNames;
serviceConfig = {
Type = "dbus";
BusName = "com.lomiri.MediaScanner2.Daemon";
Restart = "on-failure";
ExecStart = "${lib.getExe pkgs.lomiri.mediascanner2}";
};
};
};
};
systemd.services = {
"dbus-com.lomiri.UserMetrics" = {
+1
View File
@@ -569,6 +569,7 @@ in {
lomiri-docviewer-app = runTest ./lomiri-docviewer-app.nix;
lomiri-filemanager-app = runTest ./lomiri-filemanager-app.nix;
lomiri-mediaplayer-app = runTest ./lomiri-mediaplayer-app.nix;
lomiri-music-app = runTest ./lomiri-music-app.nix;
lomiri-gallery-app = runTest ./lomiri-gallery-app.nix;
lomiri-system-settings = handleTest ./lomiri-system-settings.nix {};
lorri = handleTest ./lorri/default.nix {};
+193
View File
@@ -0,0 +1,193 @@
{ lib, ... }:
let
ocrContent = "Music Test";
musicFile = "test.mp3";
ocrPauseColor = "#FF00FF";
ocrStartColor = "#00FFFF";
in
{
name = "lomiri-music-app-standalone";
meta = {
maintainers = lib.teams.lomiri.members;
# This needs a Linux VM
platforms = lib.platforms.linux;
};
nodes.machine =
{ config, pkgs, ... }:
{
imports = [
./common/auto.nix
./common/user-account.nix
./common/x11.nix
];
services.xserver.enable = true;
environment = {
# Setup video
etc."${musicFile}".source =
pkgs.runCommand musicFile
{
nativeBuildInputs = with pkgs; [
ffmpeg # produce music
(imagemagick.override { ghostscriptSupport = true; }) # produce OCR-able cover image
];
}
''
magick -size 400x400 canvas:white -pointsize 40 -fill black -annotate +100+100 '${ocrContent}' output.png
ffmpeg -re \
-f lavfi -i anullsrc=channel_layout=mono:sample_rate=44100 \
-i output.png \
-map 0:0 -map 1:0 \
-id3v2_version 3 \
-metadata:s:v title="Album cover" \
-metadata:s:v comment="Cover (front)" \
-t 120 \
$out -loglevel fatal
'';
systemPackages =
with pkgs;
[
xdg-user-dirs # generate XDG dirs
xdotool # mouse movement
]
++ (with pkgs.lomiri; [
mediascanner2
lomiri-music-app
lomiri-thumbnailer
# To check if playback actually works, or is broken due to missing codecs, we need to make the app's icons more OCR-able
(lib.meta.hiPrio (
suru-icon-theme.overrideAttrs (oa: {
# Colour the background in special colours, which we can OCR for
postPatch =
(oa.postPatch or "")
+ ''
substituteInPlace suru/actions/scalable/media-playback-pause.svg \
--replace-fail 'fill:none' 'fill:${ocrPauseColor}'
substituteInPlace suru/actions/scalable/media-playback-start.svg \
--replace-fail 'fill:none' 'fill:${ocrStartColor}'
'';
})
))
]);
variables = {
UITK_ICON_THEME = "suru";
};
};
# Get mediascanner-2.0.service
services.desktopManager.lomiri.enable = lib.mkForce true;
# ...but stick with icewm
services.displayManager.defaultSession = lib.mkForce "none+icewm";
systemd.tmpfiles.settings = {
"10-lomiri-music-app-test-setup" = {
"/root/Music".d = {
mode = "0755";
user = "root";
group = "root";
};
"/root/Music/${musicFile}"."C+".argument = "/etc/${musicFile}";
};
};
i18n.supportedLocales = [ "all" ];
};
enableOCR = true;
testScript = ''
from collections.abc import Callable
import tempfile
import subprocess
pauseColor: str = "${ocrPauseColor}"
startColor: str = "${ocrStartColor}"
# Based on terminal-emulators.nix' check_for_pink
def check_for_color(color: str) -> Callable[[bool], bool]:
def check_for_color_retry(final=False) -> bool:
with tempfile.NamedTemporaryFile() as tmpin:
machine.send_monitor_command("screendump {}".format(tmpin.name))
cmd = 'convert {} -define histogram:unique-colors=true -format "%c" histogram:info:'.format(
tmpin.name
)
ret = subprocess.run(cmd, shell=True, capture_output=True)
if ret.returncode != 0:
raise Exception(
"image analysis failed with exit code {}".format(ret.returncode)
)
text = ret.stdout.decode("utf-8")
return color in text
return check_for_color_retry
machine.wait_for_x()
# mediascanner2 needs XDG dirs to exist
machine.succeed("xdg-user-dirs-update")
# mediascanner2 needs to have run, is only started automatically by Lomiri
machine.systemctl("start mediascanner-2.0.service", "root")
with subtest("lomiri music launches"):
machine.succeed("lomiri-music-app >&2 &")
machine.wait_for_text("favorite music")
machine.send_key("alt-f10")
machine.screenshot("lomiri-music")
with subtest("lomiri music plays music"):
machine.succeed("xdotool mousemove 30 720 click 1") # Skip intro
machine.wait_for_text("Albums")
machine.succeed("xdotool mousemove 25 45 click 1") # Open categories
machine.wait_for_text("Tracks")
machine.succeed("xdotool mousemove 25 240 click 1") # Switch to Tracks category
machine.wait_for_text("test") # the test file
machine.screenshot("lomiri-music_listing")
# Ensure pause colours isn't present already
assert (
check_for_color(pauseColor)(True) == False
), "pauseColor {} was present on the screen before we selected anything!".format(pauseColor)
machine.succeed("xdotool mousemove 25 120 click 1") # Select the track
# Waiting for pause icon to be displayed
with machine.nested("Waiting for the screen to have pauseColor {} on it:".format(pauseColor)):
retry(check_for_color(pauseColor))
machine.screenshot("lomiri-music_playback")
# Ensure play colours isn't present already
assert (
check_for_color(startColor)(True) == False
), "startColor {} was present on the screen before we were expecting it to be!".format(startColor)
machine.succeed("xdotool mousemove 860 480 click 1") # Pause track (only works if app can actually decode the file)
# Waiting for play icon to be displayed
with machine.nested("Waiting for the screen to have startColor {} on it:".format(startColor)):
retry(check_for_color(startColor))
machine.screenshot("lomiri-music_paused")
# Lastly, check if generated cover image got extracted properly
# if not, indicates an issue with mediascanner / lomiri-thumbnailer
machine.wait_for_text("${ocrContent}")
machine.succeed("pkill -f lomiri-music-app")
with subtest("lomiri music localisation works"):
machine.succeed("env LANG=de_DE.UTF-8 lomiri-music-app .mp4 >&2 &")
machine.wait_for_text("Titel")
machine.screenshot("lomiri-music_localised")
'';
}
@@ -0,0 +1,124 @@
{
stdenv,
lib,
fetchFromGitLab,
fetchpatch,
gitUpdater,
nixosTests,
cmake,
gettext,
gst_all_1,
libusermetrics,
lomiri-content-hub,
lomiri-thumbnailer,
lomiri-ui-toolkit,
qtbase,
qtdeclarative,
qtmultimedia,
qtsystems,
wrapGAppsHook3,
wrapQtAppsHook,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "lomiri-music-app";
version = "3.2.2";
src = fetchFromGitLab {
owner = "ubports";
repo = "development/apps/lomiri-music-app";
rev = "refs/tags/v${finalAttrs.version}";
hash = "sha256-tHCbZF+7i/gYs8WqM5jDBhhKmM4ZeUbG3DYBdQAiUT8=";
};
patches = [
# Remove when version > 3.2.2
(fetchpatch {
name = "0001-lomiri-music-app-Fix-GNUInstallDirs-usage.patch";
url = "https://gitlab.com/ubports/development/apps/lomiri-music-app/-/commit/32591f2332aa204b9ee2857992e50594db0e6ff2.patch";
hash = "sha256-SXn+7jItzi1Q0xK0iK57+W3SpEdSCx1dKSfeghOCePg=";
})
# Remove when version > 3.2.2
(fetchpatch {
name = "0002-lomiri-music-app-bindtextdomain.patch";
url = "https://gitlab.com/ubports/development/apps/lomiri-music-app/-/commit/4e950521a67e201f3d02b3b71c6bb1ddce8ef2b2.patch";
hash = "sha256-HgGKk44FU+IXRVx2NK3iGSo/wPJce1T2k/vP8nZtewQ=";
})
];
postPatch = ''
# We don't want absolute paths in desktop files
substituteInPlace CMakeLists.txt \
--replace-fail 'ICON ''${DATA_DIR}/''${ICON_FILE}' 'ICON lomiri-music-app' \
--replace-fail 'SPLASH ''${DATA_DIR}/''${SPLASH_FILE}' 'SPLASH lomiri-app-launch/splash/lomiri-music-app.svg'
'';
strictDeps = true;
nativeBuildInputs = [
cmake
gettext
wrapGAppsHook3
wrapQtAppsHook
];
buildInputs =
[
qtbase
qtdeclarative
# QML
libusermetrics
lomiri-content-hub
lomiri-thumbnailer
lomiri-ui-toolkit
qtmultimedia
qtsystems
]
# QtMultimedia playback support
++ (with gst_all_1; [
gstreamer
gst-plugins-base
gst-plugins-good
gst-plugins-bad
]);
dontWrapGApps = true;
cmakeFlags = [
(lib.cmakeBool "CLICK_MODE" false)
(lib.cmakeBool "INSTALL_TESTS" false)
];
# Only autopilot tests
doCheck = false;
postInstall = ''
mkdir -p $out/share/{icons/hicolor/scalable/apps,lomiri-app-launch/splash}
ln -s $out/share/{lomiri-music-app/app/graphics/music-app.svg,icons/hicolor/scalable/apps/lomiri-music-app.svg}
ln -s $out/share/{lomiri-music-app/app/graphics/music-app-splash.svg,lomiri-app-launch/splash/lomiri-music-app.svg}
'';
preFixup = ''
qtWrapperArgs+=("''${gappsWrapperArgs[@]}")
'';
passthru = {
tests.vm = nixosTests.lomiri-music-app;
updateScript = gitUpdater { };
};
meta = {
description = "Default Music application for Ubuntu devices";
homepage = "https://gitlab.com/ubports/development/apps/lomiri-music-app";
changelog = "https://gitlab.com/ubports/development/apps/lomiri-music-app/-/blob/v${finalAttrs.version}/ChangeLog";
license = with lib.licenses; [
gpl3Only
];
mainProgram = "lomiri-music-app";
maintainers = lib.teams.lomiri.members;
platforms = lib.platforms.linux;
};
})
@@ -13,6 +13,7 @@
makeWrapper,
pkg-config,
systemd,
xdg-user-dirs,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
@@ -34,6 +35,10 @@ stdenvNoCC.mkDerivation (finalAttrs: {
substituteInPlace systemd/CMakeLists.txt \
--replace-fail 'pkg_get_variable(SYSTEMD_USER_DIR systemd systemduserunitdir)' 'pkg_get_variable(SYSTEMD_USER_DIR systemd systemduserunitdir DEFINE_VARIABLES prefix=''${CMAKE_INSTALL_PREFIX})'
# Inject a call to xdg-user-dirs-update, so when mediascanner2 launches, it can actually scan for files
substituteInPlace desktop/dm-lomiri-session.in \
--replace-fail '@CMAKE_INSTALL_FULL_LIBEXECDIR@/lomiri-session/run-systemd-session' '${lib.getExe' xdg-user-dirs "xdg-user-dirs-update"} && @CMAKE_INSTALL_FULL_LIBEXECDIR@/lomiri-session/run-systemd-session'
'';
nativeBuildInputs = [
+1
View File
@@ -21,6 +21,7 @@ let
lomiri-filemanager-app = callPackage ./applications/lomiri-filemanager-app { };
lomiri-gallery-app = callPackage ./applications/lomiri-gallery-app { };
lomiri-mediaplayer-app = callPackage ./applications/lomiri-mediaplayer-app { };
lomiri-music-app = callPackage ./applications/lomiri-music-app { };
lomiri-system-settings-unwrapped = callPackage ./applications/lomiri-system-settings { };
lomiri-system-settings = callPackage ./applications/lomiri-system-settings/wrapper.nix { };
lomiri-terminal-app = callPackage ./applications/lomiri-terminal-app { };
@@ -176,7 +176,11 @@ stdenv.mkDerivation (finalAttrs: {
passthru = {
tests = {
# gallery app delegates to thumbnailer, tests various formats
vm = nixosTests.lomiri-gallery-app;
gallery-app = nixosTests.lomiri-gallery-app;
# music app relies on thumbnailer to extract embedded cover art
music-app = nixosTests.lomiri-music-app;
pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
};
updateScript = gitUpdater { };
@@ -2,7 +2,9 @@
stdenv,
lib,
fetchFromGitLab,
fetchpatch,
gitUpdater,
nixosTests,
testers,
# dbus-cpp not compatible with Boost 1.87
# https://gitlab.com/ubports/development/core/lib-cpp/dbus-cpp/-/issues/8
@@ -44,6 +46,14 @@ stdenv.mkDerivation (finalAttrs: {
"dev"
];
patches = [
(fetchpatch {
name = "0001-mediascanner2-scannerdaemon-Drop-desktop-and-MEDIASCANNER_RUN-check.patch";
url = "https://gitlab.com/ubports/development/core/mediascanner2/-/commit/1e65b32e32a0536b9e2f283ba563fa78b6ef6d61.patch";
hash = "sha256-Xhm5+/E/pP+mn+4enqdsor1oRqfYTzabg1ODVfIhra4=";
})
];
postPatch = ''
substituteInPlace src/qml/MediaScanner.*/CMakeLists.txt \
--replace-fail "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
@@ -101,7 +111,12 @@ stdenv.mkDerivation (finalAttrs: {
'';
passthru = {
tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
tests = {
# music app needs mediascanner to work properly, so it can find files
music-app = nixosTests.lomiri-music-app;
pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
};
updateScript = gitUpdater { };
};