Added local music playback, cleaned macOS cmake support, and reworked gstreamer player logic
This commit is contained in:
+1
-1
@@ -69,7 +69,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIRS} /usr/X11R7/include /usr/pkg/include/ffmpeg8)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
message("--- Detected macOS ---")
|
||||
target_link_directories(ossp PRIVATE /opt/ossp/lib /opt/homebrew/lib)
|
||||
target_link_directories(ossp PRIVATE /opt/ossp/lib)
|
||||
pkg_check_modules(AVFORMAT REQUIRED libavformat)
|
||||
pkg_check_modules(AVUTIL REQUIRED libavutil)
|
||||
pkg_check_modules(BZ2 REQUIRED bzip2)
|
||||
|
||||
+7
-5
@@ -66,21 +66,23 @@ void discordrpc_update(discordrpc_data** discordrpc_struct) {
|
||||
if ((*discordrpc_struct)->state == DISCORDRPC_STATE_IDLE) {
|
||||
asprintf(&detailsString, "Idle");
|
||||
presence.details = detailsString;
|
||||
} else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_OPENSUBSONIC) {
|
||||
// Playing a song
|
||||
} else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_OPENSUBSONIC ||
|
||||
((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_LOCALFILE)) {
|
||||
// Playing a song from an OpenSubsonic server
|
||||
time_t currentTime = time(NULL);
|
||||
asprintf(&detailsString, "%s", (*discordrpc_struct)->songTitle);
|
||||
asprintf(&stateString, "by %s", (*discordrpc_struct)->songArtist);
|
||||
presence.details = detailsString;
|
||||
presence.state = stateString;
|
||||
presence.largeImageKey = (*discordrpc_struct)->coverArtUrl;
|
||||
if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_OPENSUBSONIC) {
|
||||
// TODO As of now, local file playback does NOT deal with cover art
|
||||
presence.largeImageKey = (*discordrpc_struct)->coverArtUrl;
|
||||
}
|
||||
presence.startTimestamp = (long)currentTime;
|
||||
presence.endTimestamp = (long)currentTime + (*discordrpc_struct)->songLength;
|
||||
if (configObj->discordrpc_showSysDetails) {
|
||||
presence.largeImageText = discordrpc_osString;
|
||||
}
|
||||
} else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_LOCALFILE) {
|
||||
//
|
||||
} else if ((*discordrpc_struct)->state == DISCORDRPC_STATE_PLAYING_INTERNETRADIO) {
|
||||
// Playing an internet radio station
|
||||
time_t currentTime = time(NULL);
|
||||
|
||||
+365
-4
@@ -5,6 +5,11 @@
|
||||
* Info: Debug / Prototype graphical interface
|
||||
*/
|
||||
|
||||
/*
|
||||
* THIS IS SPECIFICALLY THE DEVELOPMENT INTERFACE
|
||||
* IT IS HORRIFICIALLY UNOPTIMIZED BUT IT WORKS
|
||||
*/
|
||||
|
||||
#include "../external/imgui/imgui.h"
|
||||
#include "../external/imgui/backends/imgui_impl_sdl2.h"
|
||||
#include "../external/imgui/backends/imgui_impl_opengl2.h"
|
||||
@@ -15,15 +20,25 @@
|
||||
#include "../configHandler.h"
|
||||
#include "../libopensubsonic/httpclient.h"
|
||||
#include "../libopensubsonic/endpoint_getStarred.h"
|
||||
#include "../libopensubsonic/endpoint_getAlbum.h"
|
||||
#include "../player/player.h"
|
||||
#include "../libopensubsonic/endpoint_getInternetRadioStations.h"
|
||||
|
||||
extern configHandler_config_t* configObj;
|
||||
bool bLikedSongsShow = false;
|
||||
bool bAudioSettingsShow = false;
|
||||
bool bPlayQueueShow = false;
|
||||
bool bShowRadioStations = false;
|
||||
bool bShowNowPlaying = false;
|
||||
bool bShowLikedAlbums = false;
|
||||
bool bShowLocalSongs = false;
|
||||
void showLikedSongs();
|
||||
void showAudioSettings();
|
||||
void showPlayQueue();
|
||||
void showRadioStations();
|
||||
void showNowPlaying();
|
||||
void showLikedAlbums();
|
||||
void showLocalSongs();
|
||||
|
||||
int gui_entry() {
|
||||
// Initialize SDL
|
||||
@@ -112,6 +127,26 @@ int gui_entry() {
|
||||
bPlayQueueShow = true;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Radio")) {
|
||||
bShowRadioStations = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Now Playing")) {
|
||||
bShowNowPlaying = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Liked Albums")) {
|
||||
bShowLikedAlbums = true;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Local Songs")) {
|
||||
bShowLocalSongs = true;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -127,6 +162,22 @@ int gui_entry() {
|
||||
showPlayQueue();
|
||||
}
|
||||
|
||||
if (bShowRadioStations) {
|
||||
showRadioStations();
|
||||
}
|
||||
|
||||
if (bShowNowPlaying) {
|
||||
showNowPlaying();
|
||||
}
|
||||
|
||||
if (bShowLikedAlbums) {
|
||||
showLikedAlbums();
|
||||
}
|
||||
|
||||
if (bShowLocalSongs) {
|
||||
showLocalSongs();
|
||||
}
|
||||
|
||||
// Render
|
||||
ImGui::Render();
|
||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||
@@ -198,10 +249,30 @@ void showLikedSongs() {
|
||||
}
|
||||
|
||||
if (selectedSong != -1) {
|
||||
OSSPlayer_QueueAppend(starredStruct->songs[selectedSong].title,
|
||||
starredStruct->songs[selectedSong].artist,
|
||||
starredStruct->songs[selectedSong].id,
|
||||
starredStruct->songs[selectedSong].duration);
|
||||
// Form URL
|
||||
opensubsonic_httpClient_URL_t* song_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
|
||||
opensubsonic_httpClient_URL_prepare(&song_url);
|
||||
song_url->endpoint = OPENSUBSONIC_ENDPOINT_STREAM;
|
||||
song_url->id = strdup(starredStruct->songs[selectedSong].id);
|
||||
opensubsonic_httpClient_formUrl(&song_url);
|
||||
|
||||
opensubsonic_httpClient_URL_t* coverart_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
|
||||
opensubsonic_httpClient_URL_prepare(&coverart_url);
|
||||
coverart_url->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART;
|
||||
coverart_url->id = strdup(starredStruct->songs[selectedSong].coverArt);
|
||||
opensubsonic_httpClient_formUrl(&coverart_url);
|
||||
|
||||
OSSPQ_AppendToEnd(starredStruct->songs[selectedSong].title,
|
||||
starredStruct->songs[selectedSong].album,
|
||||
starredStruct->songs[selectedSong].artist,
|
||||
starredStruct->songs[selectedSong].id,
|
||||
song_url->formedUrl,
|
||||
coverart_url->formedUrl,
|
||||
starredStruct->songs[selectedSong].duration,
|
||||
OSSPQ_MODE_OPENSUBSONIC);
|
||||
|
||||
opensubsonic_httpClient_URL_cleanup(&song_url);
|
||||
opensubsonic_httpClient_URL_cleanup(&coverart_url);
|
||||
selectedSong = -1;
|
||||
}
|
||||
|
||||
@@ -242,6 +313,10 @@ void showAudioSettings() {
|
||||
OSSPlayer_GstECont_Pitch_Set(pitch_val * 100.0f); // Convert semitones to cents
|
||||
}
|
||||
|
||||
if(ImGui::Button("Skip")) {
|
||||
OSSPlayer_GstECont_Playbin3_Stop();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -263,3 +338,289 @@ void showPlayQueue() {
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool haveRadioStations = false;
|
||||
opensubsonic_getInternetRadioStations_struct* irsStruct;
|
||||
opensubsonic_httpClient_URL_t* radioUrl;
|
||||
|
||||
void getRadioStations() {
|
||||
radioUrl = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
|
||||
opensubsonic_httpClient_URL_prepare(&radioUrl);
|
||||
radioUrl->endpoint = OPENSUBSONIC_ENDPOINT_GETINTERNETRADIOSTATIONS;
|
||||
opensubsonic_httpClient_formUrl(&radioUrl);
|
||||
opensubsonic_httpClient_fetchResponse(&radioUrl, (void**)&irsStruct);
|
||||
|
||||
if (irsStruct->errorCode != 0) {
|
||||
// Error happened
|
||||
}
|
||||
|
||||
haveRadioStations = true;
|
||||
}
|
||||
|
||||
void showRadioStations() {
|
||||
if (!haveRadioStations) { getRadioStations(); }
|
||||
|
||||
ImGui::Begin("Radio Stations");
|
||||
|
||||
static int selectedSong = -1;
|
||||
if (haveRadioStations) {
|
||||
if (ImGui::BeginChild("Radio Stations", ImVec2(0, 200), ImGuiChildFlags_Border)) {
|
||||
for (int i = 0; i < irsStruct->radioStationCount; i++) {
|
||||
if (ImGui::Selectable(irsStruct->radioStations[i].name, selectedSong == i)) {
|
||||
selectedSong = i;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (selectedSong != -1) {
|
||||
//OSSPlayer_QueueAppend_Radio(irsStruct->radioStations[selectedSong].name,
|
||||
// irsStruct->radioStations[selectedSong].id,
|
||||
// irsStruct->radioStations[selectedSong].streamUrl);
|
||||
selectedSong = -1;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void showNowPlaying() {
|
||||
ImGui::Begin("Now Playing");
|
||||
|
||||
/*
|
||||
* Okay so I need:
|
||||
* - Current and final position of song
|
||||
* - Play, Pause, Next buttons (Needs DiscordRPC expansion)
|
||||
*/
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
void showAlbum(char* id);
|
||||
|
||||
int likedAlbumsSelectedSong = -1;
|
||||
void showLikedAlbums() {
|
||||
// /getStarred is all of the liked info, not just songs
|
||||
if (!haveLikedSongsInfo) { getLikedSongsInfo(); }
|
||||
|
||||
ImGui::Begin("Liked Albums");
|
||||
|
||||
ImGui::Text("Liked Albums");
|
||||
|
||||
if (ImGui::Button("Close")) {
|
||||
bShowLikedAlbums = false;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Refresh")) {
|
||||
opensubsonic_getStarred_struct_free(&starredStruct);
|
||||
opensubsonic_httpClient_URL_cleanup(&starredUrl);
|
||||
haveLikedSongsInfo = false;
|
||||
}
|
||||
|
||||
if (haveLikedSongsInfo) {
|
||||
if (ImGui::BeginChild("Liked Albums", ImVec2(0, 200), ImGuiChildFlags_Border)) {
|
||||
for (int i = 0; i < starredStruct->albumCount; i++) {
|
||||
if (ImGui::Selectable(starredStruct->albums[i].title, likedAlbumsSelectedSong == i)) {
|
||||
likedAlbumsSelectedSong = i;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
if (likedAlbumsSelectedSong != -1) {
|
||||
showAlbum(starredStruct->albums[likedAlbumsSelectedSong].id);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool hasAlbum = false;
|
||||
opensubsonic_getAlbum_struct* getAlbumStruct;
|
||||
void getAlbum(char* id) {
|
||||
opensubsonic_httpClient_URL_t* url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
|
||||
opensubsonic_httpClient_URL_prepare(&url);
|
||||
url->endpoint = OPENSUBSONIC_ENDPOINT_GETALBUM;
|
||||
url->id = strdup(id);
|
||||
opensubsonic_httpClient_formUrl(&url);
|
||||
|
||||
opensubsonic_httpClient_fetchResponse(&url, (void**)&getAlbumStruct);
|
||||
|
||||
//opensubsonic_getAlbum_struct_free(&getAlbumStruct);
|
||||
//opensubsonic_httpClient_URL_cleanup(&url);
|
||||
|
||||
hasAlbum = true;
|
||||
}
|
||||
|
||||
static int rand_int(int n) {
|
||||
int limit = RAND_MAX - RAND_MAX % n;
|
||||
int rnd;
|
||||
|
||||
do {
|
||||
rnd = rand();
|
||||
} while (rnd >= limit);
|
||||
return rnd % n;
|
||||
}
|
||||
|
||||
void shuffle(int *array, int n) {
|
||||
int i, j, tmp;
|
||||
|
||||
for (i = n - 1; i > 0; i--) {
|
||||
j = rand_int(i + 1);
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void shuffleAlbum() {
|
||||
int n = getAlbumStruct->songCount;
|
||||
|
||||
int arr[1] = { 0 };
|
||||
for (int i = 0; i < n; i++) {
|
||||
arr[i] = i;
|
||||
}
|
||||
|
||||
shuffle(arr, n);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
//OSSPlayer_QueueAppend_Song(getAlbumStruct->songs[arr[i]].title,
|
||||
// getAlbumStruct->songs[arr[i]].artist,
|
||||
// getAlbumStruct->songs[arr[i]].id,
|
||||
// getAlbumStruct->songs[arr[i]].duration);
|
||||
}
|
||||
}
|
||||
|
||||
#include <ctime>
|
||||
void showAlbum(char* id) {
|
||||
ImGui::Begin("Album");
|
||||
|
||||
if (!hasAlbum) { getAlbum(id); }
|
||||
|
||||
ImGui::Text("Album");
|
||||
|
||||
if (ImGui::Button("Close")) {
|
||||
likedAlbumsSelectedSong = -1;
|
||||
hasAlbum = false;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Play all")) {
|
||||
for (int i = 0; i < getAlbumStruct->songCount; i++) {
|
||||
/*
|
||||
// Form URL
|
||||
opensubsonic_getAlbum_struct*
|
||||
|
||||
opensubsonic_httpClient_URL_t* song_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
|
||||
opensubsonic_httpClient_URL_prepare(&song_url);
|
||||
song_url->endpoint = OPENSUBSONIC_ENDPOINT_STREAM;
|
||||
song_url->id = strdup(starredStruct->songs[selectedSong].id);
|
||||
opensubsonic_httpClient_formUrl(&song_url);
|
||||
|
||||
opensubsonic_httpClient_URL_t* coverart_url = (opensubsonic_httpClient_URL_t*)malloc(sizeof(opensubsonic_httpClient_URL_t));
|
||||
opensubsonic_httpClient_URL_prepare(&coverart_url);
|
||||
coverart_url->endpoint = OPENSUBSONIC_ENDPOINT_GETCOVERART;
|
||||
coverart_url->id = strdup(starredStruct->songs[selectedSong].coverArt);
|
||||
opensubsonic_httpClient_formUrl(&coverart_url);
|
||||
|
||||
OSSPQ_AppendToEnd(starredStruct->songs[selectedSong].title,
|
||||
starredStruct->songs[selectedSong].album,
|
||||
starredStruct->songs[selectedSong].artist,
|
||||
starredStruct->songs[selectedSong].id,
|
||||
song_url->formedUrl,
|
||||
coverart_url->formedUrl,
|
||||
starredStruct->songs[selectedSong].duration,
|
||||
OSSPQ_MODE_OPENSUBSONIC);
|
||||
|
||||
opensubsonic_httpClient_URL_cleanup(&song_url);
|
||||
opensubsonic_httpClient_URL_cleanup(&coverart_url);
|
||||
selectedSong = -1; getAlbumStruct->songs[i].duration);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Shuffle")) {
|
||||
srand(time(NULL));
|
||||
shuffleAlbum();
|
||||
}
|
||||
|
||||
static int selectedSong = -1;
|
||||
if (hasAlbum) {
|
||||
if (ImGui::BeginChild("Album", ImVec2(0, 200), ImGuiChildFlags_Border)) {
|
||||
for (int i = 0; i < getAlbumStruct->songCount; i++) {
|
||||
if (ImGui::Selectable(getAlbumStruct->songs[i].title, selectedSong == i)) {
|
||||
selectedSong = i;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "../localMusicHandler.hpp"
|
||||
|
||||
bool hasLocalSongs = false;
|
||||
localMusicHandler_songReq_t* songReq;
|
||||
|
||||
void getLocalSongs() {
|
||||
songReq = localMusicHandler_test();
|
||||
hasLocalSongs = true;
|
||||
}
|
||||
|
||||
void showLocalSongs() {
|
||||
|
||||
|
||||
ImGui::Begin("Local Songs");
|
||||
|
||||
if (!hasLocalSongs) { getLocalSongs(); }
|
||||
|
||||
ImGui::Text("Local Songs");
|
||||
|
||||
static int selectedSong = -1;
|
||||
if (hasLocalSongs) {
|
||||
if (ImGui::BeginChild("LocalSongs", ImVec2(0, 200), ImGuiChildFlags_Border)) {
|
||||
for (int i = 0; i < songReq->songCount; i++) {
|
||||
if (ImGui::Selectable(songReq->songs[i].title, selectedSong == i)) {
|
||||
selectedSong = i;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedSong != -1) {
|
||||
// Treat it as radio station for testing
|
||||
char* newPath = NULL;
|
||||
asprintf(&newPath, "file://%s", songReq->songs[selectedSong].path);
|
||||
|
||||
//OSSPlayer_QueueAppend_Radio(songReq->songs[selectedSong].title,
|
||||
// songReq->songs[selectedSong].uid,
|
||||
// newPath);
|
||||
OSSPQ_AppendToEnd(songReq->songs[selectedSong].title,
|
||||
NULL,
|
||||
NULL,
|
||||
songReq->songs[selectedSong].uid,
|
||||
newPath,
|
||||
NULL,
|
||||
0,
|
||||
OSSPQ_MODE_LOCALFILE);
|
||||
selectedSong = -1;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ void localMusicHandler_scan() {
|
||||
} else if (rc == 1) {
|
||||
// Table was already made, assume songs were loaded in before
|
||||
}
|
||||
|
||||
|
||||
//localMusicHandler_test();
|
||||
}
|
||||
|
||||
void localMusicHandler_scanDirectory(char* directory) {
|
||||
@@ -255,3 +258,65 @@ void localMusicHandler_moveSongsToDatabase(int idx) {
|
||||
|
||||
sqlite3_finalize(sqlite_stmt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// P.S. Sqlite searching directly is fucking useless
|
||||
// Have to use something on top, and just load base shit into memory completely I think
|
||||
// Plus how many fucking songs would it take to actually become an issue?
|
||||
std::deque<localMusicHandler_AudioObject> localMusicHandler_songReqDeque;
|
||||
localMusicHandler_songReq_t* localMusicHandler_test() {
|
||||
// Test
|
||||
sqlite3_stmt* sqlite_stmt;
|
||||
//const char* sqlQuery = "SELECT * FROM local_songs WHERE artistTitle LIKE ?;";
|
||||
const char* sqlQuery = "SELECT * FROM local_songs;";
|
||||
|
||||
if (sqlite3_prepare_v2(sqlite_db, sqlQuery, -1, &sqlite_stmt, NULL) != SQLITE_OK) {
|
||||
printf("fuck\n");
|
||||
//return;
|
||||
}
|
||||
//sqlite3_bind_text(sqlite_stmt, 1, "ch", -1, SQLITE_STATIC);
|
||||
|
||||
// %text% to prevent SQL injection --> %% for % with asprintf, %%%s%%. fucking ridiculous but its it
|
||||
// Also rename these fuckass fields. 'artistTitle' what am I high??
|
||||
|
||||
static int rc = 0;
|
||||
while ((rc = sqlite3_step(sqlite_stmt)) == SQLITE_ROW) {
|
||||
printf("here\n");
|
||||
localMusicHandler_AudioObject audioObject;
|
||||
// TODO THIS IS NOT SAFE HOLY FUCK TESTING ONLY LIKE MEGA ONLY
|
||||
// Could load directly into struct if I know how many songs there will be
|
||||
// Seems to be only able to do that by issuing yet another SQL request
|
||||
audioObject.path = (char*)sqlite3_column_text(sqlite_stmt, 6);
|
||||
audioObject.songTitle = (char*)sqlite3_column_text(sqlite_stmt, 1);
|
||||
audioObject.uid = (char*)sqlite3_column_text(sqlite_stmt, 0);
|
||||
localMusicHandler_songReqDeque.push_back(audioObject);
|
||||
}
|
||||
|
||||
if (sqlite3_step(sqlite_stmt) != SQLITE_DONE) {
|
||||
printf("[LocalMusicHandler] Execution error: %s\n", sqlite3_errmsg(sqlite_db));
|
||||
}
|
||||
|
||||
sqlite3_finalize(sqlite_stmt);
|
||||
|
||||
// Load into actual struct
|
||||
int songCount = localMusicHandler_songReqDeque.size();
|
||||
localMusicHandler_songReq_t* songReq = (localMusicHandler_songReq_t*)malloc(sizeof(localMusicHandler_songReq_t));
|
||||
songReq->songCount = songCount;
|
||||
songReq->songs = (localMusicHandler_songReq_songs_t*)malloc(sizeof(localMusicHandler_songReq_songs_t) * songCount);
|
||||
for (int i = 0; i < songCount; i++) {
|
||||
localMusicHandler_AudioObject audioObject;
|
||||
audioObject = localMusicHandler_songReqDeque.front();
|
||||
localMusicHandler_songReqDeque.pop_front();
|
||||
songReq->songs[i].uid = strdup(audioObject.uid.c_str());
|
||||
songReq->songs[i].title = strdup(audioObject.songTitle.c_str());
|
||||
songReq->songs[i].path = strdup(audioObject.path.c_str());
|
||||
}
|
||||
|
||||
return songReq;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,25 @@ void localMusicHandler_generateUid(int idx);
|
||||
int localMusicHandler_initDatabase();
|
||||
void localMusicHandler_moveSongsToDatabase(int idx);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
char* uid;
|
||||
char* title;
|
||||
char* album;
|
||||
char* artist;
|
||||
char* path;
|
||||
} localMusicHandler_songReq_songs_t;
|
||||
|
||||
typedef struct {
|
||||
int songCount;
|
||||
localMusicHandler_songReq_songs_t* songs;
|
||||
} localMusicHandler_songReq_t;
|
||||
|
||||
localMusicHandler_songReq_t* localMusicHandler_test();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* OpenSubsonicPlayer
|
||||
* Goldenkrew3000 2026
|
||||
* License: GNU General Public License 3.0
|
||||
* Info: Local (Not from OpenSubsonic server) Internet Radio Sqlite3 Database Handler
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "external/sqlite3/sqlite3.h"
|
||||
|
||||
#include "localRadioDBHandler.h"
|
||||
|
||||
static sqlite3* db = NULL;
|
||||
static int rc = 0;
|
||||
static char* errorMsg = NULL;
|
||||
|
||||
int localRadioDBHandler_CreateDB(char* dbPath);
|
||||
|
||||
int localRadioDBHandler_Init() {
|
||||
// Form path
|
||||
char* homePath = getenv("HOME");
|
||||
char* dbPath = NULL;
|
||||
rc = asprintf(&dbPath, "%s/.config/ossp/radio.db", homePath);
|
||||
if (rc == -1) { printf("asprintf() failed.\n"); return 1; }
|
||||
|
||||
// Check if file exists
|
||||
struct stat st;
|
||||
if (stat(dbPath, &st) == 0) {
|
||||
printf("[LocalRadio] Database found, is %ld bytes.\n", st.st_size);
|
||||
} else {
|
||||
printf("[LocalRadio] Database does not exist, creating.\n");
|
||||
localRadioDBHandler_CreateDB(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
int localRadioDBHandler_CreateDB(char* dbPath) {
|
||||
// Create database
|
||||
rc = sqlite3_open(dbPath, &db);
|
||||
if (rc) {
|
||||
printf("Could not create database: %s\n", sqlite3_errmsg(db));
|
||||
} else { printf("Created database.\n"); }
|
||||
|
||||
// Create table 'stations'
|
||||
char* sqlQuery = "CREATE TABLE stations(id INT, name TEXT, url TEXT)";
|
||||
rc = sqlite3_exec(db, sqlQuery, NULL, 0, &errorMsg);
|
||||
if (rc != SQLITE_OK) {
|
||||
printf("could not make table: %s\n", errorMsg);
|
||||
sqlite3_free(errorMsg);
|
||||
} else {
|
||||
printf("made table\n");
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
int localRadioDBHandler_AddStation(char* name, char* url) {
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _LOCAL_RADIO_DB_HANDLER_H
|
||||
#define _LOCAL_RADIO_DB_HANDLER_H
|
||||
|
||||
int localRadioDBHandler_Init();
|
||||
|
||||
#endif
|
||||
+11
@@ -17,12 +17,20 @@
|
||||
#include "player/player.h"
|
||||
#include "discordrpc.h"
|
||||
|
||||
#include "localRadioDBHandler.h"
|
||||
#include "libopensubsonic/endpoint_getInternetRadioStations.h"
|
||||
#include "libopensubsonic/httpclient.h"
|
||||
#include "socket.h"
|
||||
#include "localMusicHandler.hpp"
|
||||
|
||||
static int rc = 0;
|
||||
configHandler_config_t* configObj = NULL;
|
||||
int checkConfigFile();
|
||||
int validateConnection();
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
//localRadioDBHandler_Init();
|
||||
|
||||
// Read config file
|
||||
rc = configHandler_Read(&configObj);
|
||||
if (rc != 0) {
|
||||
@@ -67,8 +75,11 @@ int main(int argc, char** argv) {
|
||||
discordrpc_update(&discordrpc);
|
||||
discordrpc_struct_deinit(&discordrpc);
|
||||
|
||||
//localMusicHandler_scan();
|
||||
|
||||
// Launch QT frontend
|
||||
gui_entry();
|
||||
//socketHandler_init();
|
||||
|
||||
// Cleanup and exit
|
||||
configHandler_Free(&configObj);
|
||||
|
||||
+17
-2
@@ -44,7 +44,7 @@ static gboolean gst_bus_call(GstBus* bus, GstMessage* message, gpointer data) {
|
||||
case GST_MESSAGE_BUFFERING: {
|
||||
gint percent = 0;
|
||||
gst_message_parse_buffering(message, &percent);
|
||||
printf("Buffering (%d%%)...\n", (int)percent);
|
||||
//printf("Buffering (%d%%)...\n", (int)percent);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_ERROR: {
|
||||
@@ -57,7 +57,7 @@ static gboolean gst_bus_call(GstBus* bus, GstMessage* message, gpointer data) {
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_STATE_CHANGED:
|
||||
printf("State changed\n");
|
||||
//printf("State changed\n");
|
||||
break;
|
||||
case GST_MESSAGE_NEW_CLOCK:
|
||||
//
|
||||
@@ -361,6 +361,8 @@ int OSSPlayer_GstInit() {
|
||||
}
|
||||
|
||||
// Initialize reverb
|
||||
|
||||
|
||||
}
|
||||
|
||||
int OSSPlayer_GstDeInit() {
|
||||
@@ -432,6 +434,19 @@ void OSSPlayer_GstECont_Playbin3_Stop() {
|
||||
isPlaying = false; // Notify player thread to attempt to load next song
|
||||
}
|
||||
|
||||
void OSSPlayer_GstECont_Playbin3_PlayPause() {
|
||||
GstState state;
|
||||
gst_element_get_state (pipeline, &state, NULL, 0);
|
||||
|
||||
if (state == GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
g_print ("Paused\n");
|
||||
} else {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
g_print ("Playing\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility Functions
|
||||
*/
|
||||
|
||||
+6
-3
@@ -13,10 +13,11 @@ extern "C" {
|
||||
|
||||
#include "playQueue.hpp"
|
||||
|
||||
void* OSSPlayer_GMainLoop(void*);
|
||||
void* OSSPlayer_ThrdInit(void*);
|
||||
void* OSSPlayer_GMainLoop(void* arg);
|
||||
void* OSSPlayer_ThrdInit(void* arg);
|
||||
int OSSPlayer_GstInit();
|
||||
int OSSPlayer_QueueAppend(char* title, char* artist, char* id, long duration);
|
||||
int OSSPlayer_QueueAppend_Song(char* title, char* artist, char* id, long duration);
|
||||
int OSSPlayer_QueueAppend_Radio(char* name, char* id, char* radioUrl);
|
||||
OSSPQ_SongStruct* OSSPlayer_QueuePopFront();
|
||||
|
||||
float OSSPlayer_GstECont_InVolume_Get();
|
||||
@@ -25,6 +26,8 @@ float OSSPlayer_GstECont_OutVolume_Get();
|
||||
void OSSPlayer_GstECont_OutVolume_set(float val);
|
||||
float OSSPlayer_GstECont_Pitch_Get();
|
||||
void OSSPlayer_GstECont_Pitch_Set(float cents);
|
||||
void OSSPlayer_GstECont_Playbin3_Stop();
|
||||
void OSSPlayer_GstECont_Playbin3_PlayPause();
|
||||
|
||||
float OSSPlayer_DbLinMul(float db);
|
||||
float OSSPlayer_PitchFollow(float freq, float semitone);
|
||||
|
||||
Reference in New Issue
Block a user