static void parse_artist(ezxml_t top, struct artist *a) { xmlstrncpy(a->name, sizeof a->name, top, "name", -1); xmlstrncpy(a->id, sizeof a->id, top, "id", -1); xmlstrncpy(a->portrait_id, sizeof a->portrait_id, top, "portrait", 0, "id", -1); xmlatof(&a->popularity, top, "popularity", -1); }
static void parse_browse_album(ezxml_t top, struct album_browse* a) { xmlstrncpy(a->name, sizeof a->name, top, "name", -1); xmlstrncpy(a->id, sizeof a->id, top, "id", -1); xmlstrncpy(a->cover_id, sizeof a->cover_id, top, "cover", -1); xmlatoi(&a->year, top, "year", -1); xmlatof(&a->popularity, top, "popularity", -1); xmlstrncpy(a->artist, sizeof a->artist, top, "artist", -1); xmlstrncpy(a->artist_id, sizeof a->artist_id, top, "artist-id", -1); ezxml_t x = ezxml_get(top, "review",-1); if (x) { int len = strlen(x->txt); a->review = malloc(len + 1); memcpy(a->review, x->txt, len+1); } /* TODO: support multiple discs per album */ a->tracks = calloc(1, sizeof(struct track)); ezxml_t disc = ezxml_get(top, "discs",0,"disc", -1); a->num_tracks = parse_tracks(disc, a->tracks, false); /* Copy missing metadata from album to tracks */ int count = 0; for (struct track *t = a->tracks; t; t = t->next) { DSFYstrncpy(t->album, a->name, sizeof t->album); DSFYstrncpy(t->album_id, a->id, sizeof t->album_id); DSFYstrncpy(t->cover_id, a->cover_id, sizeof t->cover_id); t->year = a->year; count++; } }
static void parse_album(ezxml_t top, struct album* a) { xmlstrncpy(a->name, sizeof a->name, top, "name", -1); xmlstrncpy(a->id, sizeof a->id, top, "id", -1); xmlstrncpy(a->artist, sizeof a->artist, top, "artist-name", -1); xmlstrncpy(a->artist_id, sizeof a->artist_id, top, "artist-id", -1); xmlstrncpy(a->cover_id, sizeof a->cover_id, top, "cover", -1); xmlatof(&a->popularity, top, "popularity", -1); }
bool xml_parse_browse_artist(struct artist_browse* a, unsigned char* xml, int len, bool high_bitrate) { ezxml_t top = ezxml_parse_str(xml, len); xmlstrncpy(a->name, sizeof a->name, top, "name", -1); xmlstrncpy(a->genres, sizeof a->genres, top, "genres", -1); xmlstrncpy(a->years_active, sizeof a->years_active, top, "years-active",-1); xmlstrncpy(a->id, sizeof a->id, top, "id", -1); xmlstrncpy(a->portrait_id, sizeof a->portrait_id, top, "portrait", 0, "id", -1); xmlatof(&a->popularity, top, "popularity", -1); ezxml_t x = ezxml_get(top, "bios",0,"bio",0,"text",-1); if (x) { int len = strlen(x->txt); a->text = malloc(len + 1); memcpy(a->text, x->txt, len+1); } /* traverse albums */ x = ezxml_get(top, "albums",-1); struct album_browse* prev = NULL; struct album_browse* album = calloc(1, sizeof(struct album_browse)); a->albums = album; int album_count = 0; ezxml_t xalb; for (xalb = ezxml_get(x, "album", -1); xalb; xalb = xalb->next) { if (prev) { album = calloc(1, sizeof(struct album)); prev->next = album; } parse_browse_album(xalb, album, high_bitrate); prev = album; album_count++; } a->num_albums = album_count; ezxml_free(top); return true; }
void xml_parse_prodinfo(struct user_info* u, unsigned char* xml, int len) { ezxml_t top = ezxml_parse_str(xml, len); xmlstrncpy(u->type, sizeof u->type, top, "product", 0, "type", -1); unsigned int expiry; xmlatoi(&expiry, top, "product", 0, "expiry", -1); u->expiry = expiry; ezxml_free(top); }
static void parse_browse_album(ezxml_t top, struct album_browse* a, bool high_bitrate) { xmlstrncpy(a->name, sizeof a->name, top, "name", -1); xmlstrncpy(a->id, sizeof a->id, top, "id", -1); xmlstrncpy(a->artist, sizeof a->artist, top, "artist", -1); xmlstrncpy(a->artist_id, sizeof a->artist_id, top, "artist-id", -1); xmlstrncpy(a->cover_id, sizeof a->cover_id, top, "cover", -1); xmlatoi(&a->year, top, "year", -1); xmlatof(&a->popularity, top, "popularity", -1); a->tracks = calloc(1, sizeof(struct track)); ezxml_t disc = ezxml_get(top, "discs",0,"disc", -1); a->num_tracks = parse_tracks(disc, a->tracks, false, high_bitrate); /* Append extra discs to album */ struct track *last = a->tracks; while (last->next) last = last->next; while ((disc = disc->next)) { int offset = last->tracknumber; last->next = calloc(1, sizeof(struct track)); a->num_tracks += parse_tracks(disc, last->next, false, high_bitrate); do { last = last->next; last->tracknumber += offset; } while (last->next); } /* Copy missing metadata from album to tracks */ int count = 0; for (struct track *t = a->tracks; t; t = t->next) { DSFYstrncpy(t->album, a->name, sizeof t->album); DSFYstrncpy(t->album_id, a->id, sizeof t->album_id); DSFYstrncpy(t->cover_id, a->cover_id, sizeof t->cover_id); t->year = a->year; count++; } }
static void parse_browse_album(ezxml_t top, struct album_browse* a, bool high_bitrate) { xmlstrncpy(a->name, sizeof a->name, top, "name", -1); xmlstrncpy(a->id, sizeof a->id, top, "id", -1); xmlstrncpy(a->cover_id, sizeof a->cover_id, top, "cover", -1); xmlatoi(&a->year, top, "year", -1); xmlatof(&a->popularity, top, "popularity", -1); /* TODO: support multiple discs per album */ a->tracks = calloc(1, sizeof(struct track)); ezxml_t disc = ezxml_get(top, "discs",0,"disc", -1); a->num_tracks = parse_tracks(disc, a->tracks, false, high_bitrate); /* Copy missing metadata from album to tracks */ int count = 0; for (struct track *t = a->tracks; t; t = t->next) { DSFYstrncpy(t->album, a->name, sizeof t->album); DSFYstrncpy(t->album_id, a->id, sizeof t->album_id); DSFYstrncpy(t->cover_id, a->cover_id, sizeof t->cover_id); t->year = a->year; count++; } }
int xml_parse_search(struct search_result* search, struct track* firsttrack, unsigned char* xml, int len, bool high_bitrate) { ezxml_t top = ezxml_parse_str(xml, len); xmlstrncpy(search->suggestion, sizeof search->suggestion, top, "did-you-mean", -1); xmlatoi(&search->total_artists, top, "total-artists", -1); xmlatoi(&search->total_albums, top, "total-albums", -1); xmlatoi(&search->total_tracks, top, "total-tracks", -1); ezxml_t artists = ezxml_get(top, "artists",-1); struct artist *prev = NULL; struct artist *artist = calloc(1, sizeof(struct artist)); search->artists = artist; ezxml_t xa; for (xa = ezxml_get(artists, "artist", -1); xa; xa = xa->next) { if(prev) { artist = calloc(1, sizeof(struct artist)); prev->next = artist; } parse_artist(xa, artist); prev = artist; } ezxml_t albums = ezxml_get(top, "albums",-1); struct album *aprev = NULL; struct album *album = calloc(1, sizeof(struct album)); search->albums = album; for (xa = ezxml_get(albums, "album", -1); xa; xa = xa->next) { if(aprev) { album = calloc(1, sizeof(struct album)); aprev->next = album; } parse_album(xa, album); aprev = album; } ezxml_t tracks = ezxml_get(top, "tracks",-1); int num_tracks = parse_tracks(tracks, firsttrack, false, high_bitrate); ezxml_free(top); return num_tracks; }
struct playlist* xml_parse_playlist(struct playlist* pl, unsigned char* xml, int len, bool list_of_lists) { ezxml_t top = ezxml_parse_str(xml, len); ezxml_t tmpx = ezxml_get(top, "next-change",0, "change", 0, "ops", 0, "add", 0, "items", -1); char* items = NULL; if (tmpx) items = tmpx->txt; while (items && *items && isspace(*items)) items++; if (list_of_lists) { /* create list of playlists */ struct playlist* prev = NULL; struct playlist* p = pl; for (char* id = strtok(items, ",\n"); id; id = strtok(NULL, ",\n")) { if (prev) { p = calloc(1, sizeof(struct playlist)); prev->next = p; } DSFYstrncpy(p->playlist_id, id, sizeof p->playlist_id); prev = p; } } else { /* create list of tracks */ struct track* prev = NULL; struct track* root = NULL; struct track* t = NULL; int track_count = 0; for (char* id = strtok(items, ",\n"); id; id = strtok(NULL, ",\n")) { t = calloc(1, sizeof(struct track)); if (prev) prev->next = t; else root = t; DSFYstrncpy(t->track_id, id, sizeof t->track_id); prev = t; track_count++; } pl->tracks = root; pl->num_tracks = track_count; // FIXME: <version> parsing overwrites track_count } xmlstrncpy(pl->author, sizeof pl->author, top, "next-change",0, "change", 0, "user", -1); xmlstrncpy(pl->name, sizeof pl->name, top, "next-change",0, "change", 0, "ops",0, "name", -1); xml_parse_version(pl, top, "next-change", 0, "version", -1); ezxml_free(top); return pl; }
static int parse_tracks(ezxml_t xml, struct track* t, bool ordered, bool high_bitrate) { int track_count = 0; struct track* prev = NULL; struct track* root = t; for (ezxml_t track = ezxml_get(xml, "track",-1); track; track = track->next) { /* is this an ordered list? in that case we have to find the right track struct for every track id */ if (ordered) { char tid[33]; xmlstrncpy(tid, sizeof tid, track, "id", -1); struct track* tt; for (tt = root; tt; tt = tt->next) if (!tt->has_meta_data && !strncmp(tt->track_id, tid, sizeof tt->track_id)) break; /* if we didn't find the id, check if an old, redirected id is used */ if (!tt) { char rid[33]; for (ezxml_t re = ezxml_child(track, "redirect"); re; re = re->next) { strncpy(rid, re->txt, sizeof rid); for (tt = root; tt; tt = tt->next) { /* update to new id */ /* FIXME: This invalidates the playlist checksum */ if (!tt->has_meta_data && !strncmp(tt->track_id, rid, sizeof tt->track_id)) { memcpy (tt->track_id, tid, sizeof tt->track_id); break; } } if (tt) break; } /* we've wasted enough cpu cycles on this track now */ if (!tt) { DSFYDEBUG("!!! error: track id not found: %s\n", tid); continue; } } t = tt; } else if (!t) { t = calloc(1, sizeof(struct track)); prev->next = t; } xmlstrncpy(t->title, sizeof t->title, track, "title", -1); xmlstrncpy(t->album, sizeof t->album, track, "album", -1); xmlstrncpy(t->track_id, sizeof t->track_id, track, "id", -1); xmlstrncpy(t->cover_id, sizeof t->cover_id, track, "cover", -1); xmlstrncpy(t->album_id, sizeof t->album_id, track, "album-id", -1); /* create list of artists */ struct artist* preva = NULL; struct artist* artist = calloc(1, sizeof(struct artist)); t->artist = artist; ezxml_t xid = ezxml_get(track, "artist-id", -1); for (ezxml_t xa = ezxml_get(track, "artist", -1); xa; xa = xa->next) { if (preva) { artist = calloc(1, sizeof(struct artist)); preva->next = artist; } DSFYstrncpy(artist->name, xa->txt, sizeof artist->name); if (xid) { DSFYstrncpy(artist->id, xid->txt, sizeof artist->id); xid = xid->next; } preva = artist; } for ( ezxml_t file = ezxml_get(track, "files",0, "file",-1); file; file = file->next) { char* fmt = (char*)ezxml_attr(file, "format"); if (fmt) { unsigned int bitrate; if (sscanf(fmt,"Ogg Vorbis,%u,", &bitrate)) { if (bitrate > t->file_bitrate) { if (high_bitrate || t->file_bitrate == 0) t->file_bitrate = bitrate; else continue; } } char* id = (char*)ezxml_attr(file, "id"); if (id) { DSFYstrncpy(t->file_id, id, sizeof t->file_id); t->playable = true; } } } for ( ezxml_t restriction = ezxml_get(track, "restrictions", 0, "restriction", -1); restriction; restriction = restriction->next) { char *catalogues = (char*)ezxml_attr(restriction, "catalogues"); if(catalogues && strstr(catalogues, "premium") != NULL) { char* allowed = (char*)ezxml_attr(restriction, "allowed"); if(allowed) { t->allowed = calloc(strlen(allowed)+1, sizeof(char)); DSFYstrncpy(t->allowed, allowed, strlen(allowed)+1); } else { t->allowed = NULL; } char* forbidden = (char*)ezxml_attr(restriction, "forbidden"); if(forbidden) { t->forbidden = calloc(strlen(forbidden)+1, sizeof(char)); DSFYstrncpy(t->forbidden, forbidden, strlen(forbidden)+1); } else { t->forbidden = NULL; } } } xmlatoi(&t->year, track, "year", -1); xmlatoi(&t->length, track, "length", -1); xmlatoi(&t->tracknumber, track, "track-number", -1); xmlatof(&t->popularity, track, "popularity", -1); t->has_meta_data = true; prev = t; t = t->next; track_count++; } return track_count; }
static int parse_tracks(ezxml_t xml, struct track* t, bool ordered) { int track_count = 0; struct track* prev = NULL; struct track* root = t; for (ezxml_t track = ezxml_get(xml, "track",-1); track; track = track->next) { /* is this an ordered list? in that case we have to find the right track struct for every track id */ if (ordered) { char tid[33]; xmlstrncpy(tid, sizeof tid, track, "id", -1); struct track* tt; for (tt = root; tt; tt = tt->next) if (!tt->has_meta_data && !strncmp(tt->track_id, tid, sizeof tt->track_id)) break; /* if we didn't find the id, check if an old, redirected id is used */ if (!tt) { char rid[33]; for (ezxml_t re = ezxml_child(track, "redirect"); re; re = re->next) { strncpy(rid, re->txt, sizeof rid); for (tt = root; tt; tt = tt->next) { /* update to new id */ /* FIXME: This invalidates the playlist checksum */ if (!tt->has_meta_data && !strncmp(tt->track_id, rid, sizeof tt->track_id)) { memcpy (tt->track_id, tid, sizeof tt->track_id); break; } } if (tt) break; } /* we've wasted enough cpu cycles on this track now */ if (!tt) { DSFYDEBUG("!!! error: track id not found: %s\n", tid); continue; } } t = tt; } else if (!t) { t = calloc(1, sizeof(struct track)); prev->next = t; } xmlstrncpy(t->title, sizeof t->title, track, "title", -1); xmlstrncpy(t->album, sizeof t->album, track, "album", -1); xmlstrncpy(t->track_id, sizeof t->track_id, track, "id", -1); xmlstrncpy(t->cover_id, sizeof t->cover_id, track, "cover", -1); xmlstrncpy(t->album_id, sizeof t->album_id, track, "album-id", -1); /* create list of artists */ struct artist* preva = NULL; struct artist* artist = calloc(1, sizeof(struct artist)); t->artist = artist; ezxml_t xid = ezxml_get(track, "artist-id", -1); for (ezxml_t xa = ezxml_get(track, "artist", -1); xa; xa = xa->next) { if (preva) { artist = calloc(1, sizeof(struct artist)); preva->next = artist; } DSFYstrncpy(artist->name, xa->txt, sizeof artist->name); if (xid) { DSFYstrncpy(artist->id, xid->txt, sizeof artist->id); xid = xid->next; } preva = artist; } ezxml_t file = ezxml_get(track, "files",0, "file",-1); if (file) { char* id = (char*)ezxml_attr(file, "id"); if (id) { DSFYstrncpy(t->file_id, id, sizeof t->file_id); t->playable = true; } } xmlatoi(&t->year, track, "year", -1); xmlatoi(&t->length, track, "length", -1); xmlatoi(&t->tracknumber, track, "track-number", -1); xmlatof(&t->popularity, track, "popularity", -1); t->has_meta_data = true; prev = t; t = t->next; track_count++; } return track_count; }