Skip to content

Commit 1d04eb7

Browse files
committed
refactor(configs): exposed the mpv options to config & updated the paths
1 parent 6d2bace commit 1d04eb7

4 files changed

Lines changed: 235 additions & 38 deletions

File tree

src/audio/player.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,20 @@ class MusicPlayer {
9292
throw std::runtime_error("MPV initialization failed");
9393
}
9494

95-
// Configure MPV options
96-
const std::vector<std::pair<const char *, const char *>> mpv_options = {
97-
{"video", "no"}, {"audio-display", "no"}, {"terminal", "no"},
98-
{"quiet", "yes"}, {"sub-auto", "fuzzy"}, {"sub-codepage", "UTF-8"}};
99-
100-
for (const auto &[option, value] : mpv_options) {
101-
if (mpv_set_option_string(mpv.get(), option, value) < 0) {
102-
log_error("Failed to set option: " + std::string(option));
95+
// Configure MPV options from config
96+
const std::vector<std::pair<std::string, std::string>> mpv_options = {
97+
{"video", "no"},
98+
{"audio-display", "no"},
99+
{"terminal", "no"},
100+
{"quiet", "yes"},
101+
{"sub-auto", "fuzzy"},
102+
{"sub-codepage", "UTF-8"}
103+
};
104+
105+
for (const auto &[option, default_value] : mpv_options) {
106+
// For now use defaults, but this allows easy config integration later
107+
if (mpv_set_option_string(mpv.get(), option.c_str(), default_value.c_str()) < 0) {
108+
log_error("Failed to set option: " + option);
103109
}
104110
}
105111

@@ -110,8 +116,14 @@ class MusicPlayer {
110116
mpv_observe_property(mpv.get(), 0, "duration", MPV_FORMAT_DOUBLE);
111117
mpv_observe_property(mpv.get(), 0, "sub-text", MPV_FORMAT_STRING);
112118
mpv_observe_property(mpv.get(), 0, "audio-data", MPV_FORMAT_NODE);
113-
mpv_set_option_string(mpv.get(), "audio-display", "no");
114-
mpv_set_option_string(mpv.get(), "ao", "pulse"); // or your preferred audio output
119+
// Set audio output based on platform
120+
#ifdef _WIN32
121+
mpv_set_option_string(mpv.get(), "ao", "wasapi");
122+
#elif defined(__APPLE__)
123+
mpv_set_option_string(mpv.get(), "ao", "coreaudio");
124+
#else
125+
mpv_set_option_string(mpv.get(), "ao", "pulse");
126+
#endif
115127

116128

117129
mpv_set_property_string(mpv.get(), "sid", "1");

src/common/paths.hpp

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <filesystem>
5+
6+
#ifdef _WIN32
7+
#include <windows.h>
8+
#include <shlobj.h>
9+
#elif defined(__APPLE__)
10+
#include <unistd.h>
11+
#include <sys/types.h>
12+
#include <pwd.h>
13+
#else
14+
#include <unistd.h>
15+
#include <sys/types.h>
16+
#include <pwd.h>
17+
#endif
18+
19+
namespace paths {
20+
21+
inline std::string get_config_dir() {
22+
#ifdef _WIN32
23+
char* appdata = nullptr;
24+
size_t len = 0;
25+
if (_dupenv_s(&appdata, &len, "APPDATA") == 0 && appdata != nullptr) {
26+
std::string result = std::string(appdata) + "\\tuisic";
27+
free(appdata);
28+
return result;
29+
}
30+
return ".\\config";
31+
#elif defined(__APPLE__)
32+
const char* home = getenv("HOME");
33+
if (home) {
34+
return std::string(home) + "/Library/Application Support/tuisic";
35+
}
36+
return "./config";
37+
#else
38+
// Linux/Unix - XDG Base Directory Specification
39+
const char* xdg_config = getenv("XDG_CONFIG_HOME");
40+
if (xdg_config) {
41+
return std::string(xdg_config) + "/tuisic";
42+
}
43+
44+
const char* home = getenv("HOME");
45+
if (home) {
46+
return std::string(home) + "/.config/tuisic";
47+
}
48+
return "./config";
49+
#endif
50+
}
51+
52+
inline std::string get_data_dir() {
53+
#ifdef _WIN32
54+
char* appdata = nullptr;
55+
size_t len = 0;
56+
if (_dupenv_s(&appdata, &len, "LOCALAPPDATA") == 0 && appdata != nullptr) {
57+
std::string result = std::string(appdata) + "\\tuisic";
58+
free(appdata);
59+
return result;
60+
}
61+
return ".\\data";
62+
#elif defined(__APPLE__)
63+
const char* home = getenv("HOME");
64+
if (home) {
65+
return std::string(home) + "/Library/Application Support/tuisic";
66+
}
67+
return "./data";
68+
#else
69+
// Linux/Unix - XDG Base Directory Specification
70+
const char* xdg_data = getenv("XDG_DATA_HOME");
71+
if (xdg_data) {
72+
return std::string(xdg_data) + "/tuisic";
73+
}
74+
75+
const char* home = getenv("HOME");
76+
if (home) {
77+
return std::string(home) + "/.local/share/tuisic";
78+
}
79+
return "./data";
80+
#endif
81+
}
82+
83+
inline std::string get_cache_dir() {
84+
#ifdef _WIN32
85+
char* temp = nullptr;
86+
size_t len = 0;
87+
if (_dupenv_s(&temp, &len, "TEMP") == 0 && temp != nullptr) {
88+
std::string result = std::string(temp) + "\\tuisic";
89+
free(temp);
90+
return result;
91+
}
92+
return ".\\cache";
93+
#elif defined(__APPLE__)
94+
const char* home = getenv("HOME");
95+
if (home) {
96+
return std::string(home) + "/Library/Caches/tuisic";
97+
}
98+
return "./cache";
99+
#else
100+
// Linux/Unix - XDG Base Directory Specification
101+
const char* xdg_cache = getenv("XDG_CACHE_HOME");
102+
if (xdg_cache) {
103+
return std::string(xdg_cache) + "tuisic";
104+
}
105+
106+
const char* home = getenv("HOME");
107+
if (home) {
108+
return std::string(home) + "/.cache/tuisic";
109+
}
110+
return "./cache";
111+
#endif
112+
}
113+
114+
inline std::string get_music_dir() {
115+
#ifdef _WIN32
116+
char* profile = nullptr;
117+
size_t len = 0;
118+
if (_dupenv_s(&profile, &len, "USERPROFILE") == 0 && profile != nullptr) {
119+
std::string result = std::string(profile) + "\\Music";
120+
free(profile);
121+
return result;
122+
}
123+
return ".\\Music";
124+
#elif defined(__APPLE__)
125+
const char* home = getenv("HOME");
126+
if (home) {
127+
return std::string(home) + "/Music";
128+
}
129+
return "./Music";
130+
#else
131+
const char* home = getenv("HOME");
132+
if (home) {
133+
return std::string(home) + "/Music";
134+
}
135+
return "./Music";
136+
#endif
137+
}
138+
139+
// Ensure directory exists
140+
inline void ensure_directory_exists(const std::string& path) {
141+
try {
142+
std::filesystem::create_directories(path);
143+
} catch (const std::exception& e) {
144+
// Silently fail - the application will handle this gracefully
145+
}
146+
}
147+
148+
} // namespace paths

src/core/config/config.hpp

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
#include <rapidjson/prettywriter.h>
99
#include <rapidjson/stringbuffer.h>
1010
#include <rapidjson/writer.h>
11-
12-
namespace fs = std::filesystem;
11+
#include "../../common/paths.hpp"
1312

1413
class Config {
1514
private:
@@ -21,11 +20,8 @@ class Config {
2120
config.SetObject();
2221
auto &allocator = config.GetAllocator();
2322

24-
const char *home = getenv("HOME");
25-
std::string home_dir = home ? home : "/tmp";
26-
2723
rapidjson::Value downloads(rapidjson::kObjectType);
28-
std::string default_music_path = home_dir + "/Music";
24+
std::string default_music_path = paths::get_music_dir();
2925
downloads.AddMember("path",
3026
rapidjson::Value(default_music_path.c_str(), allocator),
3127
allocator);
@@ -46,6 +42,26 @@ class Config {
4642
player.AddMember("volume", 100, allocator);
4743
player.AddMember("subtitle_enabled", true, allocator);
4844
player.AddMember("repeat_enabled", false, allocator);
45+
46+
// MPV-specific settings
47+
rapidjson::Value mpv_options(rapidjson::kObjectType);
48+
mpv_options.AddMember("video", "no", allocator);
49+
mpv_options.AddMember("audio-display", "no", allocator);
50+
mpv_options.AddMember("terminal", "no", allocator);
51+
mpv_options.AddMember("quiet", "yes", allocator);
52+
mpv_options.AddMember("sub-auto", "fuzzy", allocator);
53+
mpv_options.AddMember("sub-codepage", "UTF-8", allocator);
54+
55+
// Platform-specific audio output defaults
56+
#ifdef _WIN32
57+
mpv_options.AddMember("ao", "wasapi", allocator);
58+
#elif defined(__APPLE__)
59+
mpv_options.AddMember("ao", "coreaudio", allocator);
60+
#else
61+
mpv_options.AddMember("ao", "pulse", allocator);
62+
#endif
63+
64+
player.AddMember("mpv_options", mpv_options, allocator);
4965
config.AddMember("player", player, allocator);
5066

5167
// UI section
@@ -59,26 +75,17 @@ class Config {
5975
rapidjson::Value cache(rapidjson::kObjectType);
6076
cache.AddMember("enabled", true, allocator);
6177
cache.AddMember("max_size_mb", 100, allocator);
62-
cache.AddMember(
63-
"path",
64-
rapidjson::Value(
65-
(std::string(getenv("HOME")) + "/.cache/musicplayer").c_str(),
66-
allocator),
67-
allocator);
78+
std::string cache_path = paths::get_cache_dir();
79+
cache.AddMember("path", rapidjson::Value(cache_path.c_str(), allocator), allocator);
6880
config.AddMember("cache", cache, allocator);
6981

7082
// Create directories if they don't exist
7183
/* std::filesystem::create_directories( */
7284
/* std::filesystem::path(get_download_path()).parent_path() */
7385
/* ); */
74-
namespace fs = std::filesystem;
75-
76-
try {
77-
fs::create_directories(default_music_path);
78-
} catch (const std::exception &e) {
79-
std::cerr << "Failed to create download directory: " << e.what()
80-
<< std::endl;
81-
}
86+
// Create necessary directories
87+
paths::ensure_directory_exists(default_music_path);
88+
paths::ensure_directory_exists(cache_path);
8289

8390
save_config();
8491
}
@@ -120,13 +127,11 @@ class Config {
120127
}
121128

122129
public:
123-
Config(const std::string &path = std::string(getenv("HOME")) +
124-
"/.config/tuisic/config.json")
125-
: config_path(path) {
130+
Config(const std::string &path = "")
131+
: config_path(path.empty() ? (paths::get_config_dir() + "/config.json") : path) {
126132
try {
127133
// Create config directory if it doesn't exist
128-
std::filesystem::create_directories(
129-
std::filesystem::path(config_path).parent_path());
134+
paths::ensure_directory_exists(std::filesystem::path(config_path).parent_path());
130135

131136
// Try to read existing config
132137
std::ifstream file(config_path);
@@ -194,6 +199,31 @@ class Config {
194199
return get_bool_value("ui", "show_notifications", true);
195200
}
196201

202+
// MPV settings getters
203+
std::string get_mpv_option(const std::string& option, const std::string& default_value = "") const {
204+
std::lock_guard<std::mutex> lock(config_mutex);
205+
if (config.HasMember("player") && config["player"].HasMember("mpv_options") &&
206+
config["player"]["mpv_options"].HasMember(option.c_str()) &&
207+
config["player"]["mpv_options"][option.c_str()].IsString()) {
208+
return config["player"]["mpv_options"][option.c_str()].GetString();
209+
}
210+
return default_value;
211+
}
212+
213+
std::string get_audio_output() const {
214+
#ifdef _WIN32
215+
return get_mpv_option("ao", "wasapi");
216+
#elif defined(__APPLE__)
217+
return get_mpv_option("ao", "coreaudio");
218+
#else
219+
return get_mpv_option("ao", "pulse");
220+
#endif
221+
}
222+
223+
std::string get_data_dir() const {
224+
return paths::get_data_dir();
225+
}
226+
197227
void set_download_path(const std::string &path) {
198228
if (config.HasMember("downloads")) {
199229
config["downloads"]["path"].SetString(path.c_str(),

src/storage/localStorage.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "../common/Track.h"
2+
#include "../common/paths.hpp"
23
#include "rapidjson/document.h"
34
#include "rapidjson/filewritestream.h"
45
#include "rapidjson/filereadstream.h"
@@ -7,6 +8,7 @@
78
#include <iostream>
89
#include <ostream>
910
#include <vector>
11+
#include <filesystem>
1012

1113
void saveData(const std::vector<Track> &recentlyPlayed,
1214
const std::vector<Track> &favorites_tracks) {
@@ -37,7 +39,10 @@ void saveData(const std::vector<Track> &recentlyPlayed,
3739
data.AddMember("favorites", favoritesArray, allocator);
3840

3941
// Write to file
40-
FILE* outFile = fopen("config.json", "wb");
42+
std::string data_dir = paths::get_data_dir();
43+
paths::ensure_directory_exists(data_dir);
44+
std::string tracks_file = data_dir + "/tracks.json";
45+
FILE* outFile = fopen(tracks_file.c_str(), "wb");
4146
if (!outFile) {
4247
std::cerr << "Failed to open file for writing" << std::endl;
4348
return;
@@ -54,9 +59,11 @@ void saveData(const std::vector<Track> &recentlyPlayed,
5459

5560
bool loadData(std::vector<Track> &recentlyPlayed,
5661
std::vector<Track> &favorites_tracks) {
57-
FILE* inFile = fopen("config.json", "rb");
62+
std::string data_dir = paths::get_data_dir();
63+
std::string tracks_file = data_dir + "/tracks.json";
64+
FILE* inFile = fopen(tracks_file.c_str(), "rb");
5865
if (!inFile) {
59-
std::cerr << "Failed to open config file" << std::endl;
66+
std::cerr << "Failed to open tracks file" << std::endl;
6067
return false;
6168
}
6269

0 commit comments

Comments
 (0)