mirror of
https://github.com/Goldenkrew3000/OSSP_OpenSource.git
synced 2026-02-16 04:05:18 +10:00
Add OpenSubsonic /getInternetRadioStations endpoint
/getInternetRadioStations endpoint has been implemented and memory leak tested. It also has been added to the memory testing build. Sorry if there are any bugs, as I have not written memory heavy code in C in a while.
This commit is contained in:
@@ -24,6 +24,7 @@ add_executable(ossp MACOSX_BUNDLE
|
||||
main.c
|
||||
configHandler.c
|
||||
discordrpc.c
|
||||
localRadioDBHandler.c
|
||||
gui/gui_entry.cpp
|
||||
player/player.c
|
||||
player/playQueue.cpp
|
||||
@@ -44,6 +45,7 @@ add_executable(ossp MACOSX_BUNDLE
|
||||
libopensubsonic/endpoint_getStarred.c
|
||||
libopensubsonic/endpoint_ping.c
|
||||
libopensubsonic/endpoint_scrobble.c
|
||||
libopensubsonic/endpoint_getInternetRadioStations.c
|
||||
external/cJSON.c
|
||||
external/cJSON_Utils.c
|
||||
external/libcurl_uriescape.c
|
||||
@@ -55,6 +57,7 @@ add_executable(ossp MACOSX_BUNDLE
|
||||
external/imgui/imgui_demo.cpp
|
||||
external/imgui/backends/imgui_impl_sdl2.cpp
|
||||
external/imgui/backends/imgui_impl_opengl2.cpp
|
||||
external/sqlite3/sqlite3.c
|
||||
)
|
||||
|
||||
set_target_properties(ossp PROPERTIES
|
||||
|
||||
@@ -17,4 +17,5 @@ gcc runTests.c \
|
||||
libopensubsonic/endpoint_getAlbumList.c \
|
||||
libopensubsonic/endpoint_getStarred.c \
|
||||
libopensubsonic/endpoint_scrobble.c \
|
||||
libopensubsonic/endpoint_getInternetRadioStations.c \
|
||||
-o tests -lcurl
|
||||
|
||||
110
src/libopensubsonic/endpoint_getInternetRadioStations.c
Normal file
110
src/libopensubsonic/endpoint_getInternetRadioStations.c
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../external/cJSON.h"
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include "endpoint_getInternetRadioStations.h"
|
||||
|
||||
int opensubsonic_getInternetRadioStations_parse(char* data, opensubsonic_getInternetRadioStations_struct** getInternetRadioStationsStruct) {
|
||||
// Allocate and initialize struct
|
||||
*getInternetRadioStationsStruct = malloc(sizeof(opensubsonic_getInternetRadioStations_struct));
|
||||
(*getInternetRadioStationsStruct)->status = NULL;
|
||||
(*getInternetRadioStationsStruct)->errorCode = 0;
|
||||
(*getInternetRadioStationsStruct)->errorMessage = NULL;
|
||||
(*getInternetRadioStationsStruct)->radioStationCount = 0;
|
||||
(*getInternetRadioStationsStruct)->radioStations = NULL;
|
||||
|
||||
// Parse JSON
|
||||
cJSON* root = cJSON_Parse(data);
|
||||
if (root == NULL) {
|
||||
logger_log_error(__func__, "Error parsing JSON.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Make an object from subsonic-response
|
||||
cJSON* subsonic_root = cJSON_GetObjectItemCaseSensitive(root, "subsonic-response");
|
||||
if (subsonic_root == NULL) {
|
||||
logger_log_error(__func__, "Error handling JSON - subsonic-response does not exist.");
|
||||
cJSON_Delete(root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSS_Psoj(&(*getInternetRadioStationsStruct)->status, subsonic_root, "status");
|
||||
|
||||
// Check if API has returned an error
|
||||
if (strstr((*getInternetRadioStationsStruct)->status, "ok") == NULL) {
|
||||
// API has not returned 'ok' in status, fetch error, and return
|
||||
// Check if an error is present
|
||||
cJSON* subsonic_error = cJSON_GetObjectItemCaseSensitive(subsonic_root, "error");
|
||||
if (subsonic_error == NULL) {
|
||||
// Error not defined in JSON
|
||||
logger_log_error(__func__, "API has indicated failure through status, but error does not exist.");
|
||||
cJSON_Delete(root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSS_Pioj(&(*getInternetRadioStationsStruct)->errorCode, subsonic_error, "code");
|
||||
OSS_Psoj(&(*getInternetRadioStationsStruct)->errorMessage, subsonic_error, "message");
|
||||
|
||||
logger_log_error(__func__, "Error noted in JSON - Code %d: %s", (*getInternetRadioStationsStruct)->errorCode, (*getInternetRadioStationsStruct)->errorMessage);
|
||||
cJSON_Delete(root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Make an object from 'internetRadioStations'
|
||||
cJSON* internetRadioStations_root = cJSON_GetObjectItemCaseSensitive(subsonic_root, "internetRadioStations");
|
||||
if (internetRadioStations_root == NULL) {
|
||||
logger_log_error(__func__, "Error handling JSON - internetRadioStations does not exist.");
|
||||
cJSON_Delete(root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Make an object from 'internetRadioStation
|
||||
cJSON* internetRadioStation_root = cJSON_GetObjectItemCaseSensitive(internetRadioStations_root, "internetRadioStation");
|
||||
if (internetRadioStation_root == NULL) {
|
||||
logger_log_error(__func__, "Error handling JSON - internetRadioStation does not exist.");
|
||||
cJSON_Delete(root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get the amount of radio stiations, then allocate and initialize structs
|
||||
(*getInternetRadioStationsStruct)->radioStationCount = cJSON_GetArraySize(internetRadioStation_root);
|
||||
if ((*getInternetRadioStationsStruct)->radioStationCount != 0) {
|
||||
// If there are no radio stations, don't allocate anything, but let the program run through this.
|
||||
// Cleanup then happens at the same point, but the following allocation and fetching steps wont happen
|
||||
// Basically keeps the code cleaner for this edge case (Although this is probably present in other parts **TODO**)
|
||||
(*getInternetRadioStationsStruct)->radioStations = malloc((*getInternetRadioStationsStruct)->radioStationCount * sizeof(opensubsonic_getInternetRadioStations_radioStations_struct));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (*getInternetRadioStationsStruct)->radioStationCount; i++) {
|
||||
(*getInternetRadioStationsStruct)->radioStations[i].id = NULL;
|
||||
(*getInternetRadioStationsStruct)->radioStations[i].name = NULL;
|
||||
(*getInternetRadioStationsStruct)->radioStations[i].streamUrl = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (*getInternetRadioStationsStruct)->radioStationCount; i++) {
|
||||
cJSON* curr_idx_root = cJSON_GetArrayItem(internetRadioStation_root, i);
|
||||
if (curr_idx_root != NULL) {
|
||||
OSS_Psoj(&(*getInternetRadioStationsStruct)->radioStations[i].id, curr_idx_root, "id");
|
||||
OSS_Psoj(&(*getInternetRadioStationsStruct)->radioStations[i].name, curr_idx_root, "name");
|
||||
OSS_Psoj(&(*getInternetRadioStationsStruct)->radioStations[i].streamUrl, curr_idx_root, "streamUrl");
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void opensubsonic_getInternetRadioStations_struct_free(opensubsonic_getInternetRadioStations_struct** getInternetRadioStationsStruct) {
|
||||
logger_log_general(__func__, "Freeing /getInternetRadioStations endpoint heap objects.");
|
||||
if ((*getInternetRadioStationsStruct)->status != NULL) { free((*getInternetRadioStationsStruct)->status); }
|
||||
if ((*getInternetRadioStationsStruct)->errorMessage != NULL) { free((*getInternetRadioStationsStruct)->errorMessage); }
|
||||
for (int i = 0; i < (*getInternetRadioStationsStruct)->radioStationCount; i++) {
|
||||
if ((*getInternetRadioStationsStruct)->radioStations[i].id != NULL) { free((*getInternetRadioStationsStruct)->radioStations[i].id); }
|
||||
if ((*getInternetRadioStationsStruct)->radioStations[i].name != NULL) { free((*getInternetRadioStationsStruct)->radioStations[i].name); }
|
||||
if ((*getInternetRadioStationsStruct)->radioStations[i].streamUrl != NULL) { free((*getInternetRadioStationsStruct)->radioStations[i].streamUrl); }
|
||||
}
|
||||
if ((*getInternetRadioStationsStruct)->radioStations != NULL) { free((*getInternetRadioStationsStruct)->radioStations); }
|
||||
if (*getInternetRadioStationsStruct != NULL) { free(*getInternetRadioStationsStruct); }
|
||||
}
|
||||
29
src/libopensubsonic/endpoint_getInternetRadioStations.h
Normal file
29
src/libopensubsonic/endpoint_getInternetRadioStations.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef _ENDPOINT_GETINTERNETRADIOSTATIONS_H
|
||||
#define _ENDPOINT_GETINTERNETRADIOSTATIONS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct {
|
||||
char* id;
|
||||
char* name;
|
||||
char* streamUrl;
|
||||
} opensubsonic_getInternetRadioStations_radioStations_struct;
|
||||
|
||||
typedef struct {
|
||||
char* status;
|
||||
int errorCode;
|
||||
char* errorMessage;
|
||||
int radioStationCount;
|
||||
opensubsonic_getInternetRadioStations_radioStations_struct* radioStations;
|
||||
} opensubsonic_getInternetRadioStations_struct;
|
||||
|
||||
int opensubsonic_getInternetRadioStations_parse(char* data, opensubsonic_getInternetRadioStations_struct** getInternetRadioStationsStruct);
|
||||
void opensubsonic_getInternetRadioStations_struct_free(opensubsonic_getInternetRadioStations_struct** getInternetRadioStationsStruct);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // _ENDPOINT_GETINTERNETRADIOSTATIONS_H
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "endpoint_getAlbumList.h"
|
||||
#include "endpoint_getAlbum.h"
|
||||
#include "endpoint_scrobble.h"
|
||||
#include "endpoint_getInternetRadioStations.h"
|
||||
|
||||
static int rc = 0;
|
||||
extern configHandler_config_t* configObj;
|
||||
@@ -214,6 +215,12 @@ void opensubsonic_httpClient_formUrl(opensubsonic_httpClient_URL_t** urlObj) {
|
||||
(*urlObj)->id, submitString);
|
||||
free(submitString);
|
||||
break;
|
||||
case OPENSUBSONIC_ENDPOINT_GETINTERNETRADIOSTATIONS:
|
||||
rc = asprintf(&url, "%s://%s/rest/getInternetRadioStations?u=%s&t=%s&s=%s&f=json&v=%s&c=%s",
|
||||
configObj->opensubsonic_protocol, configObj->opensubsonic_server, configObj->opensubsonic_username,
|
||||
configObj->internal_opensubsonic_loginToken, configObj->internal_opensubsonic_loginSalt,
|
||||
configObj->internal_opensubsonic_version, configObj->internal_opensubsonic_clientName);
|
||||
break;
|
||||
default:
|
||||
logger_log_error(__func__, "Unknown endpoint requested.");
|
||||
break;
|
||||
@@ -270,6 +277,9 @@ void opensubsonic_httpClient_fetchResponse(opensubsonic_httpClient_URL_t** urlOb
|
||||
} else if ((*urlObj)->endpoint == OPENSUBSONIC_ENDPOINT_SCROBBLE) {
|
||||
opensubsonic_scrobble_struct** scrobbleStruct = (opensubsonic_scrobble_struct**)responseObj;
|
||||
opensubsonic_scrobble_parse(httpReq->responseMsg, scrobbleStruct);
|
||||
} else if ((*urlObj)->endpoint == OPENSUBSONIC_ENDPOINT_GETINTERNETRADIOSTATIONS) {
|
||||
opensubsonic_getInternetRadioStations_struct** getInternetRadioStationsStruct = (opensubsonic_getInternetRadioStations_struct**)responseObj;
|
||||
opensubsonic_getInternetRadioStations_parse(httpReq->responseMsg, getInternetRadioStationsStruct);
|
||||
} else {
|
||||
logger_log_error(__func__, "Unknown endpoint requested.");
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ extern "C" {
|
||||
#define OPENSUBSONIC_ENDPOINT_GETLYRICSBYSONGID 311
|
||||
#define OPENSUBSONIC_ENDPOINT_GETALBUMLIST 312
|
||||
#define OPENSUBSONIC_ENDPOINT_SCROBBLE 313
|
||||
#define OPENSUBSONIC_ENDPOINT_GETINTERNETRADIOSTATIONS 314
|
||||
#define OPENSUBSONIC_ENDPOINT_GETALBUMLIST_RANDOM 501
|
||||
#define OPENSUBSONIC_ENDPOINT_GETALBUMLIST_NEWEST 502
|
||||
#define OPENSUBSONIC_ENDPOINT_GETALBUMLIST_HIGHEST 503
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "libopensubsonic/endpoint_getAlbumList.h"
|
||||
#include "libopensubsonic/endpoint_getAlbum.h"
|
||||
#include "libopensubsonic/endpoint_getLyricsBySongId.h"
|
||||
#include "libopensubsonic/endpoint_getInternetRadioStations.h"
|
||||
|
||||
configHandler_config_t* configObj = NULL;
|
||||
|
||||
@@ -179,6 +180,21 @@ void test_libopensubsonic_endpoint_getLyricsBySongId(void) {
|
||||
opensubsonic_httpClient_URL_cleanup(&url);
|
||||
}
|
||||
|
||||
void test_libopensubsonic_endpoint_getInternetRadioStations(void) {
|
||||
logger_log_general(__func__, "Testing getInternetRadioStations endpoint.");
|
||||
|
||||
opensubsonic_httpClient_URL_t* url = malloc(sizeof(opensubsonic_httpClient_URL_t));
|
||||
opensubsonic_httpClient_URL_prepare(&url);
|
||||
url->endpoint = OPENSUBSONIC_ENDPOINT_GETINTERNETRADIOSTATIONS;
|
||||
opensubsonic_httpClient_formUrl(&url);
|
||||
|
||||
opensubsonic_getInternetRadioStations_struct* getInternetRadioStationsStruct;
|
||||
opensubsonic_httpClient_fetchResponse(&url, (void**)&getInternetRadioStationsStruct);
|
||||
|
||||
opensubsonic_getInternetRadioStations_struct_free(&getInternetRadioStationsStruct);
|
||||
opensubsonic_httpClient_URL_cleanup(&url);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int rc = 0;
|
||||
|
||||
@@ -200,6 +216,7 @@ int main(void) {
|
||||
test_libopensubsonic_endpoint_getAlbumList();
|
||||
test_libopensubsonic_endpoint_getAlbum();
|
||||
test_libopensubsonic_endpoint_getLyricsBySongId();
|
||||
test_libopensubsonic_endpoint_getInternetRadioStations();
|
||||
|
||||
// Free config file
|
||||
configHandler_Free(&configObj);
|
||||
|
||||
Reference in New Issue
Block a user