diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..cdb379e --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +Diagnostics: + Suppress: -Wmissing-template-arg-list-after-template-kw \ No newline at end of file diff --git a/meson.build b/meson.build index f56662b..f1948c9 100644 --- a/meson.build +++ b/meson.build @@ -63,6 +63,8 @@ source_file_names = [ if host_machine.system() == 'linux' source_file_names += ['src/os/linux.cpp'] +elif host_machine.system() == 'freebsd' + source_file_names += ['src/os/freebsd.cpp'] elif host_machine.system() == 'darwin' source_file_names += [ 'src/os/macos.cpp', @@ -90,7 +92,7 @@ if host_machine.system() == 'darwin' deps += dependency('MediaPlayer') deps += dependency('SystemConfiguration') deps += dependency('iconv') -elif host_machine.system() == 'linux' +elif host_machine.system() == 'linux' or host_machine.system() == 'freebsd' deps += dependency('sdbus-c++') deps += dependency('x11') endif diff --git a/src/main.cpp b/src/main.cpp index 9c4b302..501dd15 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -80,8 +80,12 @@ fn main() -> i32 { if (weather.enabled) fmt::println("It is {}°F in {}", std::lround(weatherInfo.main.temp), weatherInfo.name); - if (nowPlayingEnabled) - fmt::println("{}", GetNowPlaying()); + if (nowPlayingEnabled) { + const string nowPlaying = GetNowPlaying(); + if (!nowPlaying.empty()) + fmt::println("{}", nowPlaying); + else fmt::println("No song playing"); + } return 0; } diff --git a/src/os/freebsd.cpp b/src/os/freebsd.cpp new file mode 100644 index 0000000..099e393 --- /dev/null +++ b/src/os/freebsd.cpp @@ -0,0 +1,116 @@ +#ifdef __FreeBSD__ + +#include +#include +#include +#include +#include +#include "os.h" + +fn GetMemInfo() -> u64 { + u64 mem = 0; + usize size = sizeof(mem); + + sysctlbyname("hw.physmem", &mem, &size, nullptr, 0); + + return mem; +} + +fn GetOSVersion() -> string { + std::ifstream file("/etc/os-release"); + + if (!file.is_open()) { + std::cerr << "Failed to open /etc/os-release" << std::endl; + return ""; // Return empty string indicating failure + } + + string line; + const string prefix = "PRETTY_NAME="; + + while (std::getline(file, line)) { + if (line.find(prefix) == 0) { + string prettyName = line.substr(prefix.size()); + + // Remove surrounding quotes if present + if (!prettyName.empty() && prettyName.front() == '"' && prettyName.back() == '"') + prettyName = prettyName.substr(1, prettyName.size() - 2); + + return prettyName; + } + } + + return ""; // Return empty string if PRETTY_NAME= line not found +} + +fn GetMprisPlayers(sdbus::IConnection& connection) -> std::vector { + const sdbus::ServiceName dbusInterface = sdbus::ServiceName("org.freedesktop.DBus"); + const sdbus::ObjectPath dbusObjectPath = sdbus::ObjectPath("/org/freedesktop/DBus"); + const char* dbusMethodListNames = "ListNames"; + + const std::unique_ptr dbusProxy = + createProxy(connection, dbusInterface, dbusObjectPath); + + std::vector names; + + dbusProxy->callMethod(dbusMethodListNames).onInterface(dbusInterface).storeResultsTo(names); + + std::vector mprisPlayers; + + for (const std::basic_string& name : names) + if (const char* mprisInterfaceName = "org.mpris.MediaPlayer2"; + name.find(mprisInterfaceName) != std::string::npos) + mprisPlayers.push_back(name); + + return mprisPlayers; +} + +fn GetActivePlayer(const std::vector& mprisPlayers) -> string { + if (!mprisPlayers.empty()) + return mprisPlayers.front(); + + return ""; +} + +fn GetNowPlaying() -> string { + try { + const char *playerObjectPath = "/org/mpris/MediaPlayer2", + *playerInterfaceName = "org.mpris.MediaPlayer2.Player"; + + std::unique_ptr connection = sdbus::createSessionBusConnection(); + + std::vector mprisPlayers = GetMprisPlayers(*connection); + + if (mprisPlayers.empty()) + return ""; + + string activePlayer = GetActivePlayer(mprisPlayers); + + if (activePlayer.empty()) + return ""; + + auto playerProxy = sdbus::createProxy( + *connection, sdbus::ServiceName(activePlayer), sdbus::ObjectPath(playerObjectPath) + ); + + sdbus::Variant metadataVariant = + playerProxy->getProperty("Metadata").onInterface(playerInterfaceName); + + if (metadataVariant.containsValueOfType>()) { + const auto& metadata = metadataVariant.get>(); + + auto iter = metadata.find("xesam:title"); + + if (iter != metadata.end() && iter->second.containsValueOfType()) + return iter->second.get(); + } + } catch (const sdbus::Error& e) { + if (e.getName() != "com.github.altdesktop.playerctld.NoActivePlayer") + return fmt::format("Error: {}", e.what()); + + return "No active player"; + } + + return ""; +} + +#endif