From 0a07262b0f60dd0a1b87474610eba4b6306918a9 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Fri, 24 Jan 2025 11:27:49 +0100 Subject: [PATCH 1/6] lomiri.lomiri-music-app: init at 3.2.2 --- .../applications/lomiri-music-app/default.nix | 122 ++++++++++++++++++ pkgs/desktops/lomiri/default.nix | 1 + 2 files changed, 123 insertions(+) create mode 100644 pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix diff --git a/pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix b/pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix new file mode 100644 index 000000000000..23551fc2dc93 --- /dev/null +++ b/pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix @@ -0,0 +1,122 @@ +{ + stdenv, + lib, + fetchFromGitLab, + fetchpatch, + gitUpdater, + 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 = { + 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; + }; +}) diff --git a/pkgs/desktops/lomiri/default.nix b/pkgs/desktops/lomiri/default.nix index bd26af310969..483eacaeb58a 100644 --- a/pkgs/desktops/lomiri/default.nix +++ b/pkgs/desktops/lomiri/default.nix @@ -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 { }; From bc7133b8764d3ec0f4e34043bfcbbaff74149420 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sun, 15 Dec 2024 14:37:22 +0100 Subject: [PATCH 2/6] nixos/lomiri: Fix mediascanner2 service --- .../services/desktop-managers/lomiri.nix | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/nixos/modules/services/desktop-managers/lomiri.nix b/nixos/modules/services/desktop-managers/lomiri.nix index 8f04e33291ac..5c5cca1bc330 100644 --- a/nixos/modules/services/desktop-managers/lomiri.nix +++ b/nixos/modules/services/desktop-managers/lomiri.nix @@ -198,37 +198,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" = { From 6fd46df8a62f13d174ab39a86ee3f05383216fd8 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sun, 15 Dec 2024 14:37:52 +0100 Subject: [PATCH 3/6] nixos/lomiri: Add music app --- nixos/modules/services/desktop-managers/lomiri.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixos/modules/services/desktop-managers/lomiri.nix b/nixos/modules/services/desktop-managers/lomiri.nix index 5c5cca1bc330..638c1ef9bfcc 100644 --- a/nixos/modules/services/desktop-managers/lomiri.nix +++ b/nixos/modules/services/desktop-managers/lomiri.nix @@ -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 From 4b3bdd486aac8dd3494dd4ff8736fcf7f6e56e12 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Mon, 16 Dec 2024 22:50:04 +0100 Subject: [PATCH 4/6] lomiri.lomiri-session: Force xdg-user-dirs-update to be run mediascanner2 expects xdg-user-dirs to be set up properly, otherwise its g_get_user_special_dir() calls fail. Lomiri, by itself, doesn't seem to ensure this by default, so hack in a call of this. --- pkgs/desktops/lomiri/data/lomiri-session/default.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkgs/desktops/lomiri/data/lomiri-session/default.nix b/pkgs/desktops/lomiri/data/lomiri-session/default.nix index 960fb2794c84..fdc7b90ad875 100644 --- a/pkgs/desktops/lomiri/data/lomiri-session/default.nix +++ b/pkgs/desktops/lomiri/data/lomiri-session/default.nix @@ -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 = [ From c4c8c1181fdab6ece6f74dfeccf6f65a3a95d829 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sun, 9 Feb 2025 15:39:44 +0100 Subject: [PATCH 5/6] nixosTests.lomiri-music-app: init --- nixos/tests/all-tests.nix | 1 + nixos/tests/lomiri-music-app.nix | 193 ++++++++++++++++++ .../applications/lomiri-music-app/default.nix | 2 + .../services/lomiri-thumbnailer/default.nix | 6 +- .../lomiri/services/mediascanner2/default.nix | 8 +- 5 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 nixos/tests/lomiri-music-app.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index cb7f599eb6ea..24d6e0725f2a 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -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 {}; diff --git a/nixos/tests/lomiri-music-app.nix b/nixos/tests/lomiri-music-app.nix new file mode 100644 index 000000000000..93a3889c9127 --- /dev/null +++ b/nixos/tests/lomiri-music-app.nix @@ -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") + ''; +} diff --git a/pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix b/pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix index 23551fc2dc93..f3688b33d9e3 100644 --- a/pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix +++ b/pkgs/desktops/lomiri/applications/lomiri-music-app/default.nix @@ -4,6 +4,7 @@ fetchFromGitLab, fetchpatch, gitUpdater, + nixosTests, cmake, gettext, gst_all_1, @@ -105,6 +106,7 @@ stdenv.mkDerivation (finalAttrs: { ''; passthru = { + tests.vm = nixosTests.lomiri-music-app; updateScript = gitUpdater { }; }; diff --git a/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix b/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix index 925f5592c34d..a9cb0b7da1d9 100644 --- a/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix +++ b/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix @@ -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 { }; diff --git a/pkgs/desktops/lomiri/services/mediascanner2/default.nix b/pkgs/desktops/lomiri/services/mediascanner2/default.nix index 0401e42ca78a..a6dafcc45fd1 100644 --- a/pkgs/desktops/lomiri/services/mediascanner2/default.nix +++ b/pkgs/desktops/lomiri/services/mediascanner2/default.nix @@ -3,6 +3,7 @@ lib, fetchFromGitLab, gitUpdater, + nixosTests, testers, # dbus-cpp not compatible with Boost 1.87 # https://gitlab.com/ubports/development/core/lib-cpp/dbus-cpp/-/issues/8 @@ -101,7 +102,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 { }; }; From fe7d0cd8a81956527332e09cdd0cecee4cf63b1f Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sun, 9 Feb 2025 17:45:30 +0100 Subject: [PATCH 6/6] lomiri.mediascanner2: Apply patch for desktop-independance --- pkgs/desktops/lomiri/services/mediascanner2/default.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkgs/desktops/lomiri/services/mediascanner2/default.nix b/pkgs/desktops/lomiri/services/mediascanner2/default.nix index a6dafcc45fd1..86172e2774c6 100644 --- a/pkgs/desktops/lomiri/services/mediascanner2/default.nix +++ b/pkgs/desktops/lomiri/services/mediascanner2/default.nix @@ -2,6 +2,7 @@ stdenv, lib, fetchFromGitLab, + fetchpatch, gitUpdater, nixosTests, testers, @@ -45,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}"