improvements

This commit is contained in:
Mars 2024-06-07 04:23:11 -04:00
parent 41200459e5
commit 6868539069
Signed by: pupbrained
GPG key ID: 0FF5B8826803F895
16 changed files with 346 additions and 147 deletions

View file

@ -1,12 +1,14 @@
--- ---
Language: Cpp AlignConsecutiveAssignments: true
AllowShortLoopsOnASingleLine: true
BasedOnStyle: Chromium BasedOnStyle: Chromium
IndentAccessModifiers: false IndentAccessModifiers: false
IndentExternBlock: Indent
Language: Cpp
NamespaceIndentation: All NamespaceIndentation: All
SpaceBeforeCpp11BracedList: true SpaceBeforeCpp11BracedList: true
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
AlignConsecutiveAssignments: true
IndentExternBlock: Indent
IncludeBlocks: Regroup IncludeBlocks: Regroup
IncludeCategories: IncludeCategories:
- Regex: '".*"' - Regex: '".*"'

View file

@ -1,29 +1,22 @@
Checks: > Checks: >
bugprone-*, *,
clang-analyzer-*,
clang-diagnostic-*,
misc-const-correctness,
misc-definitions-in-headers,
modernize-*,
performance-*,
portability-*,
readability-*,
cppcoreguidelines-prefer-member-initializer,
modernize-use-designated-initializers,
-altera-*, -altera-*,
-bugprone-easily-swappable-parameters, -bugprone-easily-swappable-parameters,
-bugprone-implicit-widening-of-multiplication-result, -bugprone-implicit-widening-of-multiplication-result,
-concurrency-mt-unsafe, -concurrency-mt-unsafe,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-type-member-init,
-fuchsia-*, -fuchsia-*,
-google-*, -google-*,
-hicpp-*, -hicpp-*,
-llvm-include-order, -llvm-include-order,
-llvm-include-order, -llvm-include-order,
-llvmlibc-*, -llvmlibc-*,
-misc-non-private-member-variables-in-classes,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
-readability-braces-around-statements, -readability-braces-around-statements,
-readability-magic-numbers, -readability-implicit-bool-conversion,
-readability-implicit-bool-conversion -readability-magic-numbers
CheckOptions: CheckOptions:
readability-identifier-naming.ClassCase: CamelCase readability-identifier-naming.ClassCase: CamelCase
readability-identifier-naming.EnumCase: CamelCase readability-identifier-naming.EnumCase: CamelCase

View file

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1717430266, "lastModified": 1717646450,
"narHash": "sha256-EWy2Qbkl/HUwmO8KDBzgDQf+4rl+fLiPFvp3nUSWcxc=", "narHash": "sha256-KE+UmfSVk5PG8jdKdclPVcMrUB8yVZHbsjo7ZT1Bm3c=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d125f0e4d85f1517b639d4a8f848175da46fcd3e", "rev": "818dbe2f96df233d2041739d6079bb616d3e5597",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -58,21 +58,21 @@
); # TODO: Remove when fixed on darwin ); # TODO: Remove when fixed on darwin
[ [
coost curl
fmt fmt
glib glib
libcpr
tomlplusplus tomlplusplus
yyjson
]; ];
linuxPkgs = nixpkgs.lib.optionals stdenv.isLinux (with pkgs.llvmPackages_18; [ linuxPkgs = nixpkgs.lib.optionals stdenv.isLinux (with pkgs.llvmPackages_18; [
systemdLibs
sdbus-cpp sdbus-cpp
valgrind valgrind
]); ]);
darwinPkgs = nixpkgs.lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ darwinPkgs = nixpkgs.lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [
Foundation Foundation
MediaPlayer
]); ]);
in in
with pkgs; { with pkgs; {
@ -89,7 +89,6 @@
]; ];
propagatedBuildInputs = [ propagatedBuildInputs = [
libcpr
tomlplusplus tomlplusplus
]; ];

23
include/util/numtypes.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include <cstdint>
// Unsigned integers
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
// Signed integers
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
// Floating-points
using f32 = float;
using f64 = double;
// Size types
using usize = std::size_t;
using isize = std::ptrdiff_t;

108
include/util/result.h Normal file
View file

@ -0,0 +1,108 @@
#pragma once
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
// Define an error type
class Error {
public:
explicit Error(std::string message) : m_Message(std::move(message)) {}
[[nodiscard]] const std::string& message() const { return m_Message; }
private:
std::string m_Message;
};
// Primary template for Result with a default type of void
template <typename T = void>
class Result;
// Specialization for Result<void>
template <>
class Result<void> {
public:
// Constructors for success and error
Result() : m_Result(std::monostate {}) {}
Result(const Error& error) : m_Result(error) {}
Result(Error&& error) : m_Result(std::move(error)) {}
// Check if the result is an error
[[nodiscard]] bool isOk() const {
return std::holds_alternative<std::monostate>(m_Result);
}
[[nodiscard]] bool isErr() const {
return std::holds_alternative<Error>(m_Result);
}
// Throw an exception if it is an error
void value() const {
if (isErr()) {
throw std::logic_error("Attempted to access value of an error Result");
}
}
// Get the error or throw an exception if it is a value
[[nodiscard]] const Error& error() const {
if (isOk()) {
throw std::logic_error("Attempted to access error of an ok Result");
}
return std::get<Error>(m_Result);
}
private:
std::variant<std::monostate, Error> m_Result;
};
// Primary template for Result
template <typename T>
class Result {
public:
// Constructors for success and error
Result(const T& value) : m_Result(value) {}
Result(T&& value) : m_Result(std::move(value)) {}
Result(const Error& error) : m_Result(error) {}
Result(Error&& error) : m_Result(std::move(error)) {}
// Check if the result is an error
[[nodiscard]] bool isOk() const {
return std::holds_alternative<T>(m_Result);
}
[[nodiscard]] bool isErr() const {
return std::holds_alternative<Error>(m_Result);
}
// Get the value or throw an exception if it is an error
const T& value() const {
if (isErr()) {
throw std::logic_error("Attempted to access value of an error Result");
}
return std::get<T>(m_Result);
}
// Get the error or throw an exception if it is a value
[[nodiscard]] const Error& error() const {
if (isOk()) {
throw std::logic_error("Attempted to access error of an ok Result");
}
return std::get<Error>(m_Result);
}
// Optional: Get the value or provide a default
T valueOr(const T& defaultValue) const {
return isOk() ? std::get<T>(m_Result) : defaultValue;
}
private:
std::variant<T, Error> m_Result;
};
template <typename T>
auto Ok(T&& value) {
return Result<std::decay_t<T>>(std::forward<T>(value));
}
inline auto Ok() {
return Result<void>();
}

View file

@ -25,6 +25,7 @@ if host_machine.system() == 'darwin'
'-Wno-c++20-compat', '-Wno-c++20-compat',
'-Wno-c++98-compat', '-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic', '-Wno-c++98-compat-pedantic',
'-Wno-disabled-macro-expansion',
'-Wno-missing-prototypes', '-Wno-missing-prototypes',
'-Wno-padded', '-Wno-padded',
'-Wno-pre-c++20-compat-pedantic', '-Wno-pre-c++20-compat-pedantic',
@ -40,6 +41,7 @@ add_project_arguments(
'-Wno-c++20-compat', '-Wno-c++20-compat',
'-Wno-c++98-compat', '-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic', '-Wno-c++98-compat-pedantic',
'-Wno-disabled-macro-expansion',
'-Wno-missing-prototypes', '-Wno-missing-prototypes',
'-Wno-padded', '-Wno-padded',
'-Wno-pre-c++20-compat-pedantic', '-Wno-pre-c++20-compat-pedantic',
@ -77,15 +79,13 @@ endforeach
deps = [] deps = []
deps += cpp.find_library('cpr')
deps += cpp.find_library('curl')
deps += cpp.find_library('tomlplusplus')
deps += dependency('coost')
deps += dependency('fmt') deps += dependency('fmt')
deps += dependency('libcurl')
deps += dependency('tomlplusplus')
deps += dependency('yyjson')
if host_machine.system() == 'darwin' if host_machine.system() == 'darwin'
deps += dependency('Foundation') deps += dependency('Foundation')
deps += dependency('MediaPlayer')
endif endif
if host_machine.system() == 'linux' if host_machine.system() == 'linux'

View file

@ -8,17 +8,15 @@
DEFINE_GETTER(Config, const General, General) DEFINE_GETTER(Config, const General, General)
DEFINE_GETTER(Config, const NowPlaying, NowPlaying) DEFINE_GETTER(Config, const NowPlaying, NowPlaying)
DEFINE_GETTER(Config, const Weather, Weather) DEFINE_GETTER(Config, const Weather, Weather)
DEFINE_GETTER(General, const string, Name) DEFINE_GETTER(General, const std::string, Name)
DEFINE_GETTER(NowPlaying, bool, Enabled) DEFINE_GETTER(NowPlaying, bool, Enabled)
DEFINE_GETTER(Weather, const Weather::Location, Location) DEFINE_GETTER(Weather, const Weather::Location, Location)
DEFINE_GETTER(Weather, const string, ApiKey) DEFINE_GETTER(Weather, const std::string, ApiKey)
DEFINE_GETTER(Weather, const string, Units) DEFINE_GETTER(Weather, const std::string, Units)
const Config& Config::getInstance() { const Config& Config::getInstance() {
static const auto* INSTANCE = static const auto* INSTANCE =
new Config(rfl::toml::load<Config>("./config.toml").value()); new Config(rfl::toml::load<Config>("./config.toml").value());
static std::once_flag Flag;
std::call_once(Flag, [] { std::atexit([] { delete INSTANCE; }); });
return *INSTANCE; return *INSTANCE;
} }
@ -27,11 +25,11 @@ Config::Config(General general, NowPlaying now_playing, Weather weather)
m_NowPlaying(now_playing), m_NowPlaying(now_playing),
m_Weather(std::move(weather)) {} m_Weather(std::move(weather)) {}
General::General(string name) : m_Name(std::move(name)) {} General::General(std::string name) : m_Name(std::move(name)) {}
NowPlaying::NowPlaying(bool enable) : m_Enabled(enable) {} NowPlaying::NowPlaying(bool enable) : m_Enabled(enable) {}
Weather::Weather(Location location, string api_key, string units) Weather::Weather(Location location, std::string api_key, std::string units)
: m_Location(std::move(location)), : m_Location(std::move(location)),
m_ApiKey(std::move(api_key)), m_ApiKey(std::move(api_key)),
m_Units(std::move(units)) {} m_Units(std::move(units)) {}

View file

@ -1,40 +1,102 @@
#include <co/json.h> #pragma once
#include <cpr/cpr.h>
#include <fmt/core.h> #include <fmt/core.h>
#include <rfl.hpp> #include <rfl.hpp>
#include <rfl/toml.hpp> #include <rfl/toml.hpp>
#include <string> #include <string>
#include <variant> #include <variant>
using std::string; #include "util/numtypes.h"
class Weather { class Weather {
public: public:
using percentage = rfl::Validator<i8, rfl::Minimum<0>, rfl::Maximum<100>>;
using degrees = rfl::Validator<u16, rfl::Minimum<0>, rfl::Maximum<360>>;
struct Condition {
usize id;
rfl::Rename<"main", std::string> group;
std::string description;
rfl::Rename<"icon", std::string> icon_id;
};
struct Main {
f64 temp;
f64 temp_max;
f64 temp_min;
f64 feels_like;
isize pressure;
std::optional<isize> sea_level;
std::optional<isize> grnd_level;
percentage humidity;
};
struct Wind {
f64 speed;
degrees deg;
std::optional<f64> gust;
};
struct Precipitation {
rfl::Rename<"1h", f64> one_hour;
rfl::Rename<"3h", f64> three_hours;
};
struct Sys {
std::string country;
usize id;
usize sunrise;
usize sunset;
usize type;
};
struct Clouds {
percentage all;
};
struct Coords { struct Coords {
double lat; double lat;
double lon; double lon;
}; };
using Location = std::variant<string, Coords>; struct WeatherOutput {
isize timezone;
isize visibility;
Main main;
Clouds clouds;
rfl::Rename<"coord", Coords> coords;
std::optional<Precipitation> rain;
std::optional<Precipitation> snow;
std::vector<Condition> weather;
std::string base;
std::string name;
Sys sys;
usize cod;
usize dt;
usize id;
Wind wind;
};
using Location = std::variant<std::string, Coords>;
private: private:
Location m_Location; Location m_Location;
string m_ApiKey; std::string m_ApiKey;
string m_Units; std::string m_Units;
public: public:
Weather(Location location, string api_key, string units); Weather(Location location, std::string api_key, std::string units);
[[nodiscard]] co::Json getWeatherInfo() const; [[nodiscard]] WeatherOutput getWeatherInfo() const;
[[nodiscard]] const Location getLocation() const; [[nodiscard]] const Location getLocation() const;
[[nodiscard]] const string getApiKey() const; [[nodiscard]] const std::string getApiKey() const;
[[nodiscard]] const string getUnits() const; [[nodiscard]] const std::string getUnits() const;
}; };
struct WeatherImpl { struct WeatherImpl {
Weather::Location location; Weather::Location location;
string api_key; std::string api_key;
string units; std::string units;
static WeatherImpl from_class(const Weather& weather) noexcept; static WeatherImpl from_class(const Weather& weather) noexcept;
@ -43,16 +105,16 @@ struct WeatherImpl {
class General { class General {
private: private:
string m_Name; std::string m_Name;
public: public:
General(string name); General(std::string name);
[[nodiscard]] const string getName() const; [[nodiscard]] const std::string getName() const;
}; };
struct GeneralImpl { struct GeneralImpl {
string name; std::string name;
static GeneralImpl from_class(const General& general) noexcept; static GeneralImpl from_class(const General& general) noexcept;

View file

@ -1,92 +1,113 @@
#include <curl/curl.h>
#include <rfl/json.hpp>
#include <rfl/json/load.hpp>
#include <util/result.h>
#include "config.h" #include "config.h"
using WeatherOutput = Weather::WeatherOutput;
// Function to read cache from file // Function to read cache from file
std::optional<std::pair<co::Json, std::chrono::system_clock::time_point>> Result<WeatherOutput> ReadCacheFromFile() {
ReadCacheFromFile() { const std::string cacheFile = "/tmp/weather_cache.json";
const string cacheFile = "/tmp/weather_cache.json";
std::ifstream ifs(cacheFile); std::ifstream ifs(cacheFile);
if (!ifs.is_open()) { if (!ifs.is_open())
fmt::println("Cache file not found."); return Error("Cache file not found.");
return std::nullopt;
}
fmt::println("Reading from cache file..."); fmt::println("Reading from cache file...");
co::Json val; WeatherOutput val;
std::chrono::system_clock::time_point timestamp;
try { try {
std::stringstream buf; std::stringstream buf;
buf << ifs.rdbuf(); buf << ifs.rdbuf();
val.parse_from(buf.str()); val = rfl::json::read<WeatherOutput>(buf.str()).value();
} catch (Error& e) {
string tsStr = val["timestamp"].as_string().c_str(); return e;
timestamp = std::chrono::system_clock::time_point(
std::chrono::milliseconds(stoll(tsStr)));
val.erase("timestamp");
} catch (...) {
fmt::println(stderr, "Failed to read from cache file.");
return std::nullopt;
} }
fmt::println("Successfully read from cache file."); fmt::println("Successfully read from cache file.");
return make_pair(val, timestamp);
return Ok(val);
} }
// Function to write cache to file // Function to write cache to file
void WriteCacheToFile(const co::Json& data) { Result<> WriteCacheToFile(const WeatherOutput& data) {
const string cacheFile = "/tmp/weather_cache.json"; const std::string cacheFile = "/tmp/weather_cache.json";
fmt::println("Writing to cache file..."); fmt::println("Writing to cache file...");
std::ofstream ofs(cacheFile); std::ofstream ofs(cacheFile);
if (!ofs.is_open()) { if (!ofs.is_open())
fmt::println(stderr, "Failed to open cache file for writing."); return Error("Failed to open cache file for writing.");
return;
}
data["timestamp"] = ofs << rfl::json::write(data);
std::to_string(duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
ofs << data.as_string();
fmt::println("Successfully wrote to cache file."); fmt::println("Successfully wrote to cache file.");
return Ok();
}
size_t WriteCallback(void* contents,
size_t size,
size_t nmemb,
std::string* buffer) {
size_t realsize = size * nmemb;
buffer->append(static_cast<char*>(contents), realsize);
return realsize;
} }
// Function to make API request // Function to make API request
co::Json MakeApiRequest(const string& url) { Result<WeatherOutput> MakeApiRequest(const std::string& url) {
using namespace cpr;
fmt::println("Making API request..."); fmt::println("Making API request...");
const Response res = Get(Url {url});
fmt::println("Received response from API.");
co::Json json = json::parse(res.text);
return json; CURL* curl = curl_easy_init();
std::string responseBuffer;
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuffer);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK)
return Error(fmt::format("Failed to perform cURL request: {}",
curl_easy_strerror(res)));
fmt::println("Received response from API.");
// Parse the JSON response
WeatherOutput output =
rfl::json::read<WeatherOutput>(responseBuffer).value();
return Ok(output);
}
return Error("Failed to initialize cURL.");
} }
// Core function to get weather information // Core function to get weather information
co::Json Weather::getWeatherInfo() const { WeatherOutput Weather::getWeatherInfo() const {
using namespace cpr; using namespace std::chrono;
const Location loc = m_Location; const Location loc = m_Location;
const string apiKey = m_ApiKey; const std::string apiKey = m_ApiKey;
const string units = m_Units; const std::string units = m_Units;
// Check if cache is valid // Check if cache is valid
if (auto cachedData = ReadCacheFromFile()) { if (Result<WeatherOutput> data = ReadCacheFromFile(); data.isOk()) {
auto& [data, timestamp] = *cachedData; WeatherOutput dataVal = data.value();
if (std::chrono::system_clock::now() - timestamp < if (system_clock::now() - system_clock::time_point(seconds(dataVal.dt)) <
std::chrono::minutes( minutes(10)) { // Assuming cache duration is always 10 minutes
10)) { // Assuming cache duration is always 10 minutes
fmt::println("Cache is valid. Returning cached data."); fmt::println("Cache is valid. Returning cached data.");
return data;
return dataVal;
} }
fmt::println("Cache is expired."); fmt::println("Cache is expired.");
@ -94,17 +115,17 @@ co::Json Weather::getWeatherInfo() const {
fmt::println("No valid cache found."); fmt::println("No valid cache found.");
} }
co::Json result; WeatherOutput result;
if (holds_alternative<string>(loc)) { if (holds_alternative<std::string>(loc)) {
const string city = get<string>(loc); const std::string city = get<std::string>(loc);
const char* location = curl_easy_escape(nullptr, city.c_str(), const char* location = curl_easy_escape(nullptr, city.c_str(),
static_cast<int>(city.length())); static_cast<int>(city.length()));
fmt::println("City: {}", location); fmt::println("City: {}", location);
const string apiUrl = format( const std::string apiUrl = fmt::format(
"https://api.openweathermap.org/data/2.5/" "https://api.openweathermap.org/data/2.5/"
"weather?q={}&appid={}&units={}", "weather?q={}&appid={}&units={}",
location, apiKey, units); location, apiKey, units);
@ -115,7 +136,7 @@ co::Json Weather::getWeatherInfo() const {
fmt::println("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon); fmt::println("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon);
const string apiUrl = format( const std::string apiUrl = fmt::format(
"https://api.openweathermap.org/data/2.5/" "https://api.openweathermap.org/data/2.5/"
"weather?lat={:.3f}&lon={:.3f}&appid={}&units={}", "weather?lat={:.3f}&lon={:.3f}&appid={}&units={}",
lat, lon, apiKey, units); lat, lon, apiKey, units);

View file

@ -1,16 +1,14 @@
#include <co/log.h>
#include <ctime> #include <ctime>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <fmt/core.h> #include <fmt/core.h>
#include "config/config.h" #include "config/config.h"
#include "os/macos/NowPlayingBridge.h"
#include "os/os.h" #include "os/os.h"
using std::string; using std::string;
struct BytesToGiB { struct BytesToGiB {
uint64_t value; u64 value;
}; };
template <> template <>
@ -42,9 +40,7 @@ DateNum ParseDate(string const& input) {
return Default; return Default;
} }
int main(int argc, char** argv) { int main() {
flag::parse(argc, argv);
const Config& config = Config::getInstance(); const Config& config = Config::getInstance();
if (config.getNowPlaying().getEnabled()) if (config.getNowPlaying().getEnabled())
@ -52,22 +48,17 @@ int main(int argc, char** argv) {
fmt::println("Hello {}!", config.getGeneral().getName()); fmt::println("Hello {}!", config.getGeneral().getName());
const uint64_t memInfo = GetMemInfo(); const u64 memInfo = GetMemInfo();
fmt::println("{:.2f}", BytesToGiB {memInfo}); fmt::println("{:.2f}", BytesToGiB {memInfo});
const std::tm localTime = fmt::localtime(time(nullptr)); const std::tm localTime = fmt::localtime(time(nullptr));
auto trimStart = [](std::string& str) {
auto start = str.begin();
while (start != str.end() && std::isspace(*start))
++start;
str.erase(str.begin(), start);
};
string date = fmt::format("{:%e}", localTime); string date = fmt::format("{:%e}", localTime);
trimStart(date); auto start = date.begin();
while (start != date.end() && std::isspace(*start)) ++start;
date.erase(date.begin(), start);
switch (ParseDate(date)) { switch (ParseDate(date)) {
case Ones: case Ones:
@ -89,11 +80,10 @@ int main(int argc, char** argv) {
fmt::println("{:%B} {}, {:%-I:%0M %p}", localTime, date, localTime); fmt::println("{:%B} {}, {:%-I:%0M %p}", localTime, date, localTime);
co::Json json = config.getWeather().getWeatherInfo(); Weather::WeatherOutput json = config.getWeather().getWeatherInfo();
const int temp = json.get("main", "temp").as_int(); const long temp = std::lround(json.main.temp);
const char* townName = const string townName = json.name;
json["name"].is_string() ? json["name"].as_string().c_str() : "Unknown";
fmt::println("It is {}°F in {}", temp, townName); fmt::println("It is {}°F in {}", temp, townName);

View file

@ -4,7 +4,6 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <sdbus-c++/sdbus-c++.h> #include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <vector> #include <vector>
#include "os.h" #include "os.h"
@ -18,44 +17,41 @@ static const char *DBUS_INTERFACE = "org.freedesktop.DBus",
*PLAYER_OBJECT_PATH = "/org/mpris/MediaPlayer2", *PLAYER_OBJECT_PATH = "/org/mpris/MediaPlayer2",
*PLAYER_INTERFACE_NAME = "org.mpris.MediaPlayer2.Player"; *PLAYER_INTERFACE_NAME = "org.mpris.MediaPlayer2.Player";
uint64_t ParseLineAsNumber(const string& input) { u64 ParseLineAsNumber(const string& input) {
// Find the first number // Find the first number
string::size_type start = 0; string::size_type start = 0;
// Skip leading non-numbers // Skip leading non-numbers
while (!isdigit(input[++start])) while (!isdigit(input[++start]));
;
// Start searching from the start of the number // Start searching from the start of the number
string::size_type end = start; string::size_type end = start;
// Increment to the end of the number // Increment to the end of the number
while (isdigit(input[++end])) while (isdigit(input[++end]));
;
// Return the substring containing the number // Return the substring containing the number
return std::stoul(input.substr(start, end - start)); return std::stoul(input.substr(start, end - start));
} }
uint64_t MeminfoParse(std::ifstream input) { u64 MeminfoParse(std::ifstream input) {
string line; string line;
// Skip every line before the one that starts with "MemTotal" // Skip every line before the one that starts with "MemTotal"
while (std::getline(input, line) && !line.starts_with("MemTotal")) while (std::getline(input, line) && !line.starts_with("MemTotal"));
;
// Parse the number from the line // Parse the number from the line
const uint64_t num = ParseLineAsNumber(line); const u64 num = ParseLineAsNumber(line);
return num; return num;
} }
uint64_t GetMemInfo() { u64 GetMemInfo() {
return MeminfoParse(std::ifstream("/proc/meminfo")) * 1024; return MeminfoParse(std::ifstream("/proc/meminfo")) * 1024;
} }
std::vector<std::string> GetMprisPlayers(sdbus::IConnection& connection) { std::vector<std::string> GetMprisPlayers(sdbus::IConnection& connection) {
auto dbusProxy = std::unique_ptr<sdbus::IProxy> dbusProxy =
sdbus::createProxy(connection, DBUS_INTERFACE, DBUS_OBJECT_PATH); sdbus::createProxy(connection, DBUS_INTERFACE, DBUS_OBJECT_PATH);
std::vector<std::string> names; std::vector<std::string> names;
@ -66,7 +62,7 @@ std::vector<std::string> GetMprisPlayers(sdbus::IConnection& connection) {
std::vector<std::string> mprisPlayers; std::vector<std::string> mprisPlayers;
for (const auto& name : names) for (const std::basic_string<char>& name : names)
if (name.find(MPRIS_INTERFACE_NAME) != std::string::npos) if (name.find(MPRIS_INTERFACE_NAME) != std::string::npos)
mprisPlayers.push_back(name); mprisPlayers.push_back(name);
@ -82,8 +78,10 @@ std::string GetActivePlayer(const std::vector<std::string>& mprisPlayers) {
std::string GetNowPlaying() { std::string GetNowPlaying() {
try { try {
auto connection = sdbus::createSessionBusConnection(); std::unique_ptr<sdbus::IConnection> connection =
auto mprisPlayers = GetMprisPlayers(*connection); sdbus::createSessionBusConnection();
std::vector<std::string> mprisPlayers = GetMprisPlayers(*connection);
if (mprisPlayers.empty()) if (mprisPlayers.empty())
return ""; return "";
@ -93,7 +91,7 @@ std::string GetNowPlaying() {
if (activePlayer.empty()) if (activePlayer.empty())
return ""; return "";
auto playerProxy = std::unique_ptr<sdbus::IProxy> playerProxy =
sdbus::createProxy(*connection, activePlayer, PLAYER_OBJECT_PATH); sdbus::createProxy(*connection, activePlayer, PLAYER_OBJECT_PATH);
std::map<std::string, sdbus::Variant> metadata = std::map<std::string, sdbus::Variant> metadata =

View file

@ -6,7 +6,7 @@
#include "macos/NowPlayingBridge.h" #include "macos/NowPlayingBridge.h"
#include "os.h" #include "os.h"
uint64_t GetMemInfo() { u64 GetMemInfo() {
uint64_t mem = 0; uint64_t mem = 0;
size_t size = sizeof(mem); size_t size = sizeof(mem);

View file

@ -1,5 +1,6 @@
// NowPlayingBridge.h #pragma once
#ifdef __APPLE__
#ifdef __OBJC__ #ifdef __OBJC__
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@ -12,3 +13,4 @@ extern "C" {
const char* GetCurrentPlayingArtist(); const char* GetCurrentPlayingArtist();
} }
#endif #endif
#endif

View file

@ -1,4 +1,4 @@
// NowPlayingBridge.mm #ifdef __APPLE__
#import "NowPlayingBridge.h" #import "NowPlayingBridge.h"
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@ -91,3 +91,5 @@ const char *GetCurrentPlayingArtist() {
return nullptr; return nullptr;
} }
} }
#endif

View file

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <cstdint>
#include <string> #include <string>
uint64_t GetMemInfo(); #include "util/numtypes.h"
u64 GetMemInfo();
std::string GetNowPlaying(); std::string GetNowPlaying();