simple music player implementation using mpv
This commit is contained in:
commit
20685a8d2e
7 changed files with 190 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.cache/
|
||||||
|
builddir/
|
||||||
|
compile_commands.json
|
16
meson.build
Normal file
16
meson.build
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
project(
|
||||||
|
'waffle',
|
||||||
|
'cpp',
|
||||||
|
default_options : ['cpp_std=c++17']
|
||||||
|
)
|
||||||
|
|
||||||
|
raven_dep = dependency('raven')
|
||||||
|
mpv_dep = dependency('mpv')
|
||||||
|
|
||||||
|
executable(
|
||||||
|
'waffle',
|
||||||
|
'./src/MPVClient.cpp',
|
||||||
|
'./src/AppWidget.cpp',
|
||||||
|
'./src/main.cpp',
|
||||||
|
dependencies : [raven_dep, mpv_dep]
|
||||||
|
)
|
55
src/AppWidget.cpp
Normal file
55
src/AppWidget.cpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "AppWidget.hpp"
|
||||||
|
#include "raven/Styles.hpp"
|
||||||
|
#include "raven/Box.hpp"
|
||||||
|
#include "raven/TextInput.hpp"
|
||||||
|
#include "raven/Button.hpp"
|
||||||
|
#include "raven/ScrollContainer.hpp"
|
||||||
|
#include "raven/Widget.hpp"
|
||||||
|
#include "raven/ListLayout.hpp"
|
||||||
|
#include "raven/BoxLayout.hpp"
|
||||||
|
#include "raven/Label.hpp"
|
||||||
|
#include "raven/DocumentLayout.hpp"
|
||||||
|
#include "MPVClient.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
static void populate_song_list(std::filesystem::path songs_directory, std::shared_ptr<Raven::Widget> song_list_widget, MPVClient *mpv_client) {
|
||||||
|
song_list_widget->clear_children();
|
||||||
|
for (const auto &entry : std::filesystem::directory_iterator(songs_directory)) {
|
||||||
|
std::string filename = entry.path().filename();
|
||||||
|
std::string path_string = entry.path().string();
|
||||||
|
auto button = song_list_widget->add<Raven::Button>(filename);
|
||||||
|
button->on_click = [mpv_client, path_string]() {
|
||||||
|
const char *command[] = {
|
||||||
|
"loadfile",
|
||||||
|
path_string.c_str(),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
mpv_client->send_command_async(command);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppWidget::on_init() {
|
||||||
|
/* init */
|
||||||
|
{
|
||||||
|
auto layout = set_layout<Raven::BoxLayout>(Raven::Direction::Vertical);
|
||||||
|
layout->set_spacing(8);
|
||||||
|
layout->set_margin(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* song list */
|
||||||
|
{
|
||||||
|
m_song_list = add<Raven::ScrollContainer>();
|
||||||
|
m_song_list->set_grows(true);
|
||||||
|
auto target = m_song_list->make_target();
|
||||||
|
auto layout = target->set_layout<Raven::ListLayout>(Raven::Direction::Vertical);
|
||||||
|
layout->set_spacing(4.0);
|
||||||
|
layout->set_inherit_secondary_dimension(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
populate_song_list("/home/hippoz/music", m_song_list->target(), m_mpv_client);
|
||||||
|
|
||||||
|
reflow();
|
||||||
|
set_did_init(true);
|
||||||
|
}
|
19
src/AppWidget.hpp
Normal file
19
src/AppWidget.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "raven/ScrollContainer.hpp"
|
||||||
|
#include "raven/Widget.hpp"
|
||||||
|
#include "raven/TextInput.hpp"
|
||||||
|
#include "src/MPVClient.hpp"
|
||||||
|
|
||||||
|
class AppWidget : public Raven::Widget {
|
||||||
|
public:
|
||||||
|
AppWidget(MPVClient *mpv_client)
|
||||||
|
: Raven::Widget(),
|
||||||
|
m_mpv_client(mpv_client) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_init() override;
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Raven::ScrollContainer> m_song_list;
|
||||||
|
MPVClient *m_mpv_client { nullptr };
|
||||||
|
};
|
45
src/MPVClient.cpp
Normal file
45
src/MPVClient.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "MPVClient.hpp"
|
||||||
|
#include <mpv/client.h>
|
||||||
|
|
||||||
|
static void handle_mpv_wakeup_callback(void *mpv_client_ptr) {
|
||||||
|
MPVClient *mpv_client = static_cast<MPVClient*>(mpv_client_ptr);
|
||||||
|
mpv_client->raven_application()->queue_microtask([mpv_client]() {
|
||||||
|
mpv_client->handle_events();
|
||||||
|
});
|
||||||
|
mpv_client->raven_application()->wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPVClient::handle_events() {
|
||||||
|
while (1) {
|
||||||
|
mpv_event *event = mpv_wait_event(m_ctx, 0);
|
||||||
|
std::cout << "[MPV EVENT] " << mpv_event_name(event->event_id) << std::endl;
|
||||||
|
if (event->event_id == MPV_EVENT_NONE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPVClient::initialize() {
|
||||||
|
m_ctx = mpv_create();
|
||||||
|
if (!m_ctx) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpv_set_option_string(m_ctx, "vo", "null");
|
||||||
|
|
||||||
|
if (mpv_initialize(m_ctx) < 0) return -1;
|
||||||
|
|
||||||
|
mpv_set_wakeup_callback(m_ctx, handle_mpv_wakeup_callback, this);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPVClient::send_command_async(const char **command) {
|
||||||
|
mpv_command_async(m_ctx, 1, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPVClient::~MPVClient() {
|
||||||
|
if (m_ctx) {
|
||||||
|
mpv_terminate_destroy(m_ctx);
|
||||||
|
}
|
||||||
|
}
|
30
src/MPVClient.hpp
Normal file
30
src/MPVClient.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Application.hpp"
|
||||||
|
#include "Window.hpp"
|
||||||
|
#include <mpv/client.h>
|
||||||
|
|
||||||
|
|
||||||
|
class MPVClient {
|
||||||
|
public:
|
||||||
|
MPVClient(
|
||||||
|
Raven::Application *raven_application,
|
||||||
|
Raven::Window *raven_window
|
||||||
|
)
|
||||||
|
: m_raven_application(raven_application)
|
||||||
|
, m_raven_window(raven_window) {}
|
||||||
|
|
||||||
|
~MPVClient();
|
||||||
|
|
||||||
|
int initialize();
|
||||||
|
void handle_events();
|
||||||
|
|
||||||
|
void send_command_async(const char **command);
|
||||||
|
|
||||||
|
Raven::Application* raven_application() { return m_raven_application; }
|
||||||
|
Raven::Window* raven_window() { return m_raven_window; }
|
||||||
|
private:
|
||||||
|
mpv_handle *m_ctx { nullptr };
|
||||||
|
Raven::Application* m_raven_application { nullptr };
|
||||||
|
Raven::Window* m_raven_window { nullptr };
|
||||||
|
};
|
22
src/main.cpp
Normal file
22
src/main.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include "raven/Window.hpp"
|
||||||
|
#include "raven/Application.hpp"
|
||||||
|
#include "raven/Widget.hpp"
|
||||||
|
#include "raven/Button.hpp"
|
||||||
|
#include "AppWidget.hpp"
|
||||||
|
#include "MPVClient.hpp"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Raven::Application application(true);
|
||||||
|
auto window = application.add_window<Raven::Window>();
|
||||||
|
|
||||||
|
MPVClient client { &application, window.get() };
|
||||||
|
client.initialize();
|
||||||
|
|
||||||
|
window->spawn_window();
|
||||||
|
|
||||||
|
window->set_main_widget<AppWidget>(&client);
|
||||||
|
|
||||||
|
return application.run();
|
||||||
|
}
|
Loading…
Reference in a new issue