add song library abstraction

This commit is contained in:
hippoz 2022-11-13 23:17:35 +02:00
parent af5fd74a2d
commit 95a67c626d
No known key found for this signature in database
GPG key ID: 7C52899193467641
6 changed files with 171 additions and 16 deletions

View file

@ -11,6 +11,7 @@ alsa_dep = dependency('alsa')
executable(
'hyperpop',
'./src/player/SongLibrary.cpp',
'./src/player/OpusFile.cpp',
'./src/player/ALSAOutput.cpp',
'./src/player/Player.cpp',

View file

@ -5,12 +5,16 @@
#include "raven/Widget.hpp"
#include "raven/Button.hpp"
#include "src/player/Player.hpp"
#include "src/player/SongLibrary.hpp"
#include "ui/AppWidget.hpp"
#include "player/ALSAOutput.hpp"
#include "player/OpusFile.hpp"
int main()
{
SongLibrary *library = new SongLibrary();
library->populate_from("/home/hippoz/music");
Player player;
Raven::Application application(true);
@ -18,7 +22,11 @@ int main()
window->spawn_window();
window->set_main_widget<AppWidget>(&player);
window->set_main_widget<AppWidget>(&player, library);
return application.run();
application.run();
delete library;
return 0;
}

View file

@ -0,0 +1,41 @@
#include "SongLibrary.hpp"
#include <opusfile.h>
#include <iostream>
#include <memory>
void SongLibrary::populate_from(std::filesystem::path directory) {
m_all_songs.clear();
m_songs_by_artist.clear();
for (const auto &entry : std::filesystem::directory_iterator(directory)) {
OggOpusFile *file = op_open_file(entry.path().c_str(), NULL);
if (file == NULL) {
continue;
}
const OpusTags *tags = op_tags(file, -1);
if (tags == NULL) {
continue;
}
const char *artist_value = opus_tags_query(tags, "artist", 0);
const char *title_value = opus_tags_query(tags, "title", 0);
const char *album_value = opus_tags_query(tags, "album", 0);
if (artist_value == NULL || title_value == NULL || album_value == NULL) {
continue;
}
std::shared_ptr<SongEntry> song_entry = std::make_shared<SongEntry>();
song_entry->artist = artist_value;
song_entry->title = title_value;
song_entry->album = album_value;
song_entry->absolute_path = entry.path().c_str();
song_entry->length_ms = op_pcm_total(file, -1);
m_all_songs.push_back(song_entry);
m_songs_by_artist[song_entry->artist].push_back(song_entry);
op_free(file);
}
}

View file

@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <vector>
#include <map>
#include <filesystem>
class SongLibrary {
public:
struct SongEntry {
std::string artist;
std::string album;
std::string title;
std::string absolute_path;
size_t length_ms;
};
SongLibrary() {}
void populate_from(std::filesystem::path directory);
const std::vector<std::shared_ptr<SongEntry>> &all_songs() { return m_all_songs; }
const std::map<std::string, std::vector<std::shared_ptr<SongEntry>>> &songs_by_artist() { return m_songs_by_artist; }
private:
std::vector<std::shared_ptr<SongEntry>> m_all_songs;
std::map<std::string, std::vector<std::shared_ptr<SongEntry>>> m_songs_by_artist;
};

View file

@ -1,4 +1,5 @@
#include "AppWidget.hpp"
#include "GenericStyle.hpp"
#include "raven/Styles.hpp"
#include "raven/Box.hpp"
#include "raven/TextInput.hpp"
@ -11,17 +12,65 @@
#include "raven/DocumentLayout.hpp"
#include "src/player/OpusFile.hpp"
#include "src/player/Player.hpp"
#include "src/player/SongLibrary.hpp"
#include <filesystem>
static void populate_song_list(std::filesystem::path songs_directory, std::shared_ptr<Raven::Widget> song_list_widget, Player *player) {
Raven::RGB accent_color = { 0xF7A99E };
Raven::RGB background_color = { 0xfff9f4 };
Raven::GenericStyle background_color_style {
NULL,
Raven::unused,
accent_color,
Raven::unused,
Raven::unused,
0.0,
true,
false
};
Raven::GenericStyle main_view_style {
NULL,
Raven::unused,
background_color,
Raven::unused,
Raven::unused,
12.0,
true,
false
};
Raven::GenericStyle song_button_style {
pango_font_description_from_string("sans-serif"),
Raven::black1,
background_color,
accent_color.factor(1.1),
accent_color.factor(1.2),
6.0,
true,
true
};
Raven::GenericStyle artist_button_style {
pango_font_description_from_string("sans-serif"),
Raven::black1,
accent_color,
accent_color.factor(1.1),
accent_color.factor(1.2),
6.0,
true,
true
};
static void populate_song_list(std::shared_ptr<Raven::Widget> song_list_widget, Player *player, SongLibrary *song_library, std::string target_artist) {
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 = [player, path_string]() {
for (const auto &entry : song_library->songs_by_artist().at(target_artist)) {
auto button = song_list_widget->add<Raven::Button>(entry->title);
button->set_style(&song_button_style);
button->on_click = [player, entry]() {
auto file = std::make_shared<OpusFile>();
file->open(path_string);
file->open(entry->absolute_path);
player->set_file(file);
};
}
@ -30,23 +79,47 @@ static void populate_song_list(std::filesystem::path songs_directory, std::share
void AppWidget::on_init() {
/* init */
{
auto layout = set_layout<Raven::BoxLayout>(Raven::Direction::Vertical);
auto layout = set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
layout->set_spacing(8);
layout->set_margin(12);
layout->set_margin(16);
set_style(&background_color_style);
}
/* sidebar */
{
m_sidebar = add<Raven::ScrollContainer>();
m_sidebar->set_style(&background_color_style);
m_sidebar->rect().set_min_width(250.0);
auto target = m_sidebar->make_target();
target->set_style(&background_color_style);
auto layout = target->set_layout<Raven::ListLayout>(Raven::Direction::Vertical);
layout->set_spacing(6.0);
layout->set_inherit_secondary_dimension(true);
}
/* song list */
{
m_song_list = add<Raven::ScrollContainer>();
m_song_list->set_grows(true);
m_song_list->set_style(&main_view_style);
auto target = m_song_list->make_target();
auto layout = target->set_layout<Raven::ListLayout>(Raven::Direction::Vertical);
layout->set_spacing(4.0);
layout->set_spacing(6.0);
layout->set_margin(10.0);
layout->set_inherit_secondary_dimension(true);
}
populate_song_list("/home/hippoz/music", m_song_list->target(), m_player);
populate_song_list(m_song_list->target(), m_player, m_song_library, "EDEN");
for (const auto &it : m_song_library->songs_by_artist()) {
auto button = m_sidebar->target()->add<Raven::Button>(it.first);
button->set_style(&artist_button_style);
button->on_click = [this, it]() {
populate_song_list(m_song_list->target(), m_player, m_song_library, it.first);
};
}
reflow();
set_did_init(true);
}

View file

@ -4,16 +4,20 @@
#include "raven/Widget.hpp"
#include "raven/TextInput.hpp"
#include "src/player/Player.hpp"
#include "src/player/SongLibrary.hpp"
class AppWidget : public Raven::Widget {
public:
AppWidget(Player *player)
AppWidget(Player *player, SongLibrary *library)
: Raven::Widget()
, m_player(player) {}
, m_player(player)
, m_song_library(library) {}
protected:
void on_init() override;
private:
std::shared_ptr<Raven::ScrollContainer> m_song_list;
std::shared_ptr<Raven::ScrollContainer> m_sidebar;
Player *m_player;
SongLibrary *m_song_library;
};