mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-02-02 15:07:36 -05:00
191 lines
4.4 KiB
C
191 lines
4.4 KiB
C
/* Icecast
|
|
*
|
|
* This program is distributed under the GNU General Public License, version 2.
|
|
* A copy of this license is included with this source.
|
|
*
|
|
* Copyright 2015, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <libxml/xmlmemory.h>
|
|
#include <libxml/parser.h>
|
|
#include <libxml/tree.h>
|
|
|
|
/* for free() and strdup() */
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "playlist.h"
|
|
|
|
/* for XMLSTR() */
|
|
#include "cfgfile.h"
|
|
|
|
#include "logging.h"
|
|
#define CATMODULE "playlist"
|
|
|
|
typedef struct playlist_track_tag playlist_track_t;
|
|
|
|
struct playlist_tag {
|
|
size_t refc;
|
|
ssize_t max_tracks;
|
|
playlist_track_t *first;
|
|
};
|
|
|
|
struct playlist_track_tag {
|
|
char *title;
|
|
char *creator;
|
|
char *album;
|
|
char *trackNum;
|
|
playlist_track_t *next;
|
|
};
|
|
|
|
static void __free_track(playlist_track_t *track)
|
|
{
|
|
if (track->title)
|
|
free(track->title);
|
|
if (track->creator)
|
|
free(track->creator);
|
|
if (track->album)
|
|
free(track->album);
|
|
if (track->trackNum)
|
|
free(track->trackNum);
|
|
free(track);
|
|
}
|
|
|
|
static char * __query_vc(vorbis_comment *vc, const char *key)
|
|
{
|
|
char *value = vorbis_comment_query(vc, key, 0);
|
|
if (!value)
|
|
return NULL;
|
|
return strdup(value);
|
|
}
|
|
|
|
playlist_t * playlist_new(ssize_t max_tracks)
|
|
{
|
|
playlist_t *playlist = calloc(1, sizeof(playlist_t));
|
|
|
|
if (!playlist)
|
|
return NULL;
|
|
|
|
playlist->refc = 1;
|
|
playlist->max_tracks = max_tracks;
|
|
|
|
return playlist;
|
|
}
|
|
|
|
int playlist_ref(playlist_t *playlist)
|
|
{
|
|
if (!playlist)
|
|
return -1;
|
|
playlist->refc++;
|
|
return 0;
|
|
}
|
|
|
|
int playlist_release(playlist_t *playlist)
|
|
{
|
|
playlist_track_t *track;
|
|
|
|
if (!playlist)
|
|
return -1;
|
|
playlist->refc--;
|
|
if (playlist->refc)
|
|
return 0;
|
|
|
|
while ((track = playlist->first)) {
|
|
playlist->first = track->next;
|
|
__free_track(track);
|
|
}
|
|
|
|
free(playlist);
|
|
return 0;
|
|
}
|
|
|
|
int playlist_set_max_tracks(playlist_t *playlist, ssize_t max_tracks)
|
|
{
|
|
if (!playlist)
|
|
return -1;
|
|
playlist->max_tracks = max_tracks;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int playlist_push_track(playlist_t *playlist, vorbis_comment *vc)
|
|
{
|
|
playlist_track_t *track, **cur;
|
|
ssize_t num = 0;
|
|
|
|
if (!playlist)
|
|
return -1;
|
|
|
|
track = calloc(1, sizeof(playlist_track_t));
|
|
if (!track)
|
|
return -1;
|
|
|
|
cur = &playlist->first;
|
|
while (*cur) {
|
|
cur = &(*cur)->next;
|
|
num++;
|
|
}
|
|
*cur = track;
|
|
|
|
num++; /* the extra track we just inserted */
|
|
|
|
while (playlist->max_tracks > 0 && num > playlist->max_tracks) {
|
|
playlist_track_t *to_free = playlist->first;
|
|
playlist->first = to_free->next;
|
|
__free_track(to_free);
|
|
num--;
|
|
}
|
|
|
|
if (vc) {
|
|
track->title = __query_vc(vc, "TITLE");
|
|
track->creator = __query_vc(vc, "ARTIST");
|
|
track->album = __query_vc(vc, "ALBUM");
|
|
track->trackNum = __query_vc(vc, "TRACKNUMBER");
|
|
|
|
if (!track->title && !track->creator && !track->album && !track->trackNum) {
|
|
/* no useful meta data has been found. try ICY style meta data */
|
|
track->title = __query_vc(vc, "X_ICY_TITLE");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
xmlNodePtr playlist_render_xspf(playlist_t *playlist)
|
|
{
|
|
xmlNodePtr rootnode, tracklist, tracknode;
|
|
playlist_track_t *track;
|
|
|
|
if (!playlist)
|
|
return NULL;
|
|
|
|
rootnode = xmlNewNode(NULL, XMLSTR("playlist"));
|
|
xmlSetProp(rootnode, XMLSTR("version"), XMLSTR("1"));
|
|
xmlSetProp(rootnode, XMLSTR("xmlns"), XMLSTR("http://xspf.org/ns/0/"));
|
|
|
|
tracklist = xmlNewNode(NULL, XMLSTR("trackList"));
|
|
xmlAddChild(rootnode, tracklist);
|
|
|
|
track = playlist->first;
|
|
while (track) {
|
|
tracknode = xmlNewNode(NULL, XMLSTR("track"));
|
|
xmlAddChild(tracklist, tracknode);
|
|
/* TODO: Handle meta data */
|
|
if (track->title)
|
|
xmlNewTextChild(tracknode, NULL, XMLSTR("title"), XMLSTR(track->title));
|
|
if (track->creator)
|
|
xmlNewTextChild(tracknode, NULL, XMLSTR("creator"), XMLSTR(track->creator));
|
|
if (track->album)
|
|
xmlNewTextChild(tracknode, NULL, XMLSTR("album"), XMLSTR(track->album));
|
|
if (track->trackNum)
|
|
xmlNewTextChild(tracknode, NULL, XMLSTR("trackNum"), XMLSTR(track->trackNum));
|
|
track = track->next;
|
|
}
|
|
|
|
return rootnode;
|
|
}
|