image: gcc4.8
script:
- sudo apt-get install -y libmpdclient-dev &> /dev/null
- - cmake . -DCMAKE_INSTALL_PREFIX:PATH=/usr
- - make
- - cpack -D CPACK_DEBIAN_PACKAGE_MAINTAINER="ympd Team" -G DEB
+ - cmake . -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_BUILD_TYPE=Debug
+ - make VERBOSE=1
notify:
email:
recipients:
- andy@ndyk.de
+ irc:
+ server: irc.freenode.org
+ nick: droneBot
+ channel: '#nicotest'
+ on_started: true
+ on_success: true
+ on_failure: true
+
project (ympd)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
set(CPACK_PACKAGE_VERSION_MAJOR "1")
-set(CPACK_PACKAGE_VERSION_MINOR "0")
+set(CPACK_PACKAGE_VERSION_MINOR "2")
set(CPACK_PACKAGE_VERSION_PATCH "0")
option(WITH_MPD_HOST_CHANGE "Let users of the web frontend change the MPD Host" ON)
src/http_server.c
src/mpd_client.c
src/mongoose.c
+ src/json_encode.c
)
add_executable(ympd ${SOURCES} ${PROJECT_BINARY_DIR}/http_files.h)
<ul id="nav_links" class="nav navbar-nav">
<li id="queue"><a href="#/">Queue</a></li>
- <li id="browse"><a href="#/browse/">Browse database</a></li>
+ <li id="browse"><a href="#/browse/0/">Browse database</a></li>
<li><a href="#" data-toggle="modal" data-target="#settings" onclick="getHost();">Settings</a></li>
</ul>
<div class="panel panel-primary">
<!-- Default panel contents -->
- <div id="panel-heading" class="panel-heading">Queue</div>
+ <div class="panel-heading"><b id="panel-heading">Queue</b></div>
<div class="panel-body">
<h1>
<span id="track-icon" class="glyphicon glyphicon-play"></span>
</tbody>
</table>
</div><!-- /.panel -->
+ <ul class="pager">
+ <li id="prev" class="page-btn hide"><a href="">Previous</a></li>
+ <li id="next" class="page-btn"><a href="">Next</a></li>
+ </ul>
</div><!-- /.col-md-10 -->
<div class="col-md-2 col-xs-12" >
data-placement="right" data-toggle="popover" data-content="Password does not match!"
data-trigger="manual" />
</div>
+ <div class="form-group col-md-12">
+ <div id="mpd_password_set" class="hide alert alert-info">MPD Password is set</div>
+ </div>
+
</div>
</form>
</div>
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
+ <div class="modal fade bs-example-modal-sm" id="wait" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h1>Searching...</h1>
+ </div>
+ <div class="modal-body">
+ <div class="progress progress-striped active">
+ <div class="progress-bar" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 100%">
+ <span class="sr-only">Please Wait</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
<!-- Bootstrap core JavaScript
var socket;
var last_state;
var current_app;
+var pagination = 0;
+var browsepath;
var lastSongTitle = "";
var current_song = new Object();
+var MAX_ELEMENTS_PER_PAGE = 512;
var app = $.sammy(function() {
- this.before('/', function(e, data) {
- $('#nav_links > li').removeClass('active');
- });
- this.get('#/', function() {
+ function runBrowse() {
current_app = 'queue';
+
$('#breadcrump').addClass('hide');
$('#salamisandwich').find("tr:gt(0)").remove();
- socket.send('MPD_API_GET_QUEUE');
+ socket.send('MPD_API_GET_QUEUE,'+pagination);
$('#panel-heading').text("Queue");
$('#queue').addClass('active');
+ }
+
+ function prepare() {
+ $('#nav_links > li').removeClass('active');
+ $('.page-btn').addClass('hide');
+ pagination = 0;
+ browsepath = '';
+ }
+
+ this.get(/\#\/(\d+)/, function() {
+ prepare();
+ pagination = parseInt(this.params['splat'][0]);
+ runBrowse();
});
- this.get(/\#\/browse\/(.*)/, function() {
+ this.get(/\#\/browse\/(\d+)\/(.*)/, function() {
+ prepare();
+ browsepath = this.params['splat'][1];
+ pagination = parseInt(this.params['splat'][0]);
current_app = 'browse';
- $('#breadcrump').removeClass('hide').empty().append("<li><a href=\"#/browse/\">root</a></li>");
+ $('#breadcrump').removeClass('hide').empty().append("<li><a href=\"#/browse/0/\">root</a></li>");
$('#salamisandwich').find("tr:gt(0)").remove();
- var path = this.params['splat'][0];
-
- socket.send('MPD_API_GET_BROWSE,' + path);
+ socket.send('MPD_API_GET_BROWSE,'+pagination+','+(browsepath ? browsepath : "/"));
- $('#panel-heading').text("Browse database: "+path);
- var path_array = path.split('/');
+ $('#panel-heading').text("Browse database: "+browsepath);
+ var path_array = browsepath.split('/');
var full_path = "";
$.each(path_array, function(index, chunk) {
if(path_array.length - 1 == index) {
}
full_path = full_path + chunk;
- $('#breadcrump').append("<li><a href=\"#/browse/" + full_path + "\">"+chunk+"</a></li>");
+ $('#breadcrump').append("<li><a href=\"#/browse/0/" + full_path + "\">"+chunk+"</a></li>");
full_path += "/";
});
$('#browse').addClass('active');
});
this.get("/", function(context) {
- context.redirect("#/");
+ context.redirect("#/0");
});
});
app.run();
}
- socket.onmessage =function got_packet(msg) {
- if(msg.data === last_state)
+ socket.onmessage = function got_packet(msg) {
+ if(msg.data === last_state || msg.data.length == 0)
return;
var obj = JSON.parse(msg.data);
"</td><td></td></tr>");
}
+ if(obj.data[obj.data.length-1].id >= pagination + MAX_ELEMENTS_PER_PAGE)
+ $('#next').removeClass('hide');
+ if(pagination > 0)
+ $('#prev').removeClass('hide');
+
$('#salamisandwich > tbody > tr').on({
mouseover: function(){
if($(this).children().last().has("a").length == 0)
});
break;
case "search":
+ $('#wait').modal('hide');
case "browse":
if(current_app !== 'browse' && current_app !== 'search')
break;
"</td><td></td></tr>"
);
break;
+ case "wrap":
+ if(current_app == 'browse') {
+ $('#next').removeClass('hide');
+ } else {
+ $('#salamisandwich > tbody').append(
+ "<tr><td><span class=\"glyphicon glyphicon-remove\"></span></td>" +
+ "<td>Too many results, please refine your search!</td>" +
+ "<td></td><td></td></tr>"
+ );
+ }
+ break;
}
+
+ if(pagination > 0)
+ $('#prev').removeClass('hide');
+
}
function appendClickableIcon(appendTo, onClickAction, glyphicon) {
appendClickableIcon($(this), 'MPD_API_ADD_PLAY_TRACK', 'play');
},
click: function() {
- if($(this).is(".dir"))
- app.setLocation("#/browse/"+$(this).attr("uri"));
- else {
- if($(this).is(".song"))
+ switch($(this).attr('class')) {
+ case 'dir':
+ app.setLocation("#/browse/0/"+$(this).attr("uri"));
+ break;
+ case 'song':
socket.send("MPD_API_ADD_TRACK," + $(this).attr("uri"));
- else
+ $('.top-right').notify({
+ message:{
+ text: $('td:nth-child(2)', this).text() + " added"
+ }
+ }).show();
+ break;
+ case 'plist':
socket.send("MPD_API_ADD_PLAYLIST," + $(this).attr("uri"));
-
- $('.top-right').notify({
- message:{
- text: $('td:nth-child(2)', this).text() + " added"
- }
- }).show();
+ $('.top-right').notify({
+ message:{
+ text: "Playlist " + $('td:nth-child(2)', this).text() + " added"
+ }
+ }).show();
+ break;
}
-
},
mouseleave: function(){
$(this).children().last().find("a").stop().remove();
break;
case "update_queue":
if(current_app === 'queue')
- socket.send('MPD_API_GET_QUEUE');
+ socket.send('MPD_API_GET_QUEUE,'+pagination);
break;
case "song_change":
$('#currenttrack').text(" " + obj.data.title);
case "mpdhost":
$('#mpdhost').val(obj.data.host);
$('#mpdport').val(obj.data.port);
- if(obj.data.passwort_set) {
- $('#mpd_pw').attr('placeholder', '*******');
- $('#mpd_pw_con').attr('placeholder', '*******');
- }
+ if(obj.data.passwort_set)
+ $('#mpd_password_set').removeClass('hide');
break;
case "error":
$('.top-right').notify({
}
$('#search').submit(function () {
-
app.setLocation("#/search/"+$('#search > div > input').val());
+ $('#wait').modal('show');
+ setTimeout(function() {
+ $('#wait').modal('hide');
+ }, 10000);
return false;
});
+$('.page-btn').on('click', function (e) {
+
+ switch ($(this).text()) {
+ case "Next":
+ pagination += MAX_ELEMENTS_PER_PAGE;
+ break;
+ case "Previous":
+ pagination -= MAX_ELEMENTS_PER_PAGE;
+ if(pagination <= 0)
+ pagination = 0;
+ break;
+ }
+
+ switch(current_app) {
+ case "queue":
+ app.setLocation('#/'+pagination);
+ break;
+ case "browse":
+ app.setLocation('#/browse/'+pagination+'/'+browsepath);
+ break;
+ }
+ e.preventDefault();
+});
+
function confirmSettings() {
if($('#mpd_pw').val().length + $('#mpd_pw_con').val().length > 0) {
if ($('#mpd_pw').val() !== $('#mpd_pw_con').val())
}
function songNotify(artist, title) {
- if (!notificationsSupported())
- return;
-
- if (window.webkitNotifications.checkPermission() == 0) {
- var notification = window.webkitNotifications.createNotification("assets/favicon.ico", artist, title);
- notification.show();
- setTimeout(function(notification) {
- notification.cancel();
- }, 3000, notification);
- } else {
- window.webkitNotifications.requestPermission();
- }
+ var notification = window.webkitNotifications.createNotification("assets/favicon.ico", artist, title);
+ notification.show();
+ setTimeout(function(notification) {
+ notification.cancel();
+ }, 3000, notification);
}
--- /dev/null
+// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
+// Copyright (c) 2013 Cesanta Software Limited
+// All rights reserved
+//
+// This library is dual-licensed: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation. For the terms of this
+// license, see <http://www.gnu.org/licenses/>.
+//
+// You are free to use this library under the terms of the GNU General
+// Public License, but WITHOUT ANY WARRANTY; without even the implied
+// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// Alternatively, you can license this library under a commercial
+// license, as set out in <http://cesanta.com/products.html>.
+
+// json encoder 'frozen' from https://github.com/cesanta/frozen
+
+#include <stdio.h>
+
+#include "json_encode.h"
+
+int json_emit_int(char *buf, int buf_len, long int value) {
+ return buf_len <= 0 ? 0 : snprintf(buf, buf_len, "%ld", value);
+}
+
+int json_emit_double(char *buf, int buf_len, double value) {
+ return buf_len <= 0 ? 0 : snprintf(buf, buf_len, "%g", value);
+}
+
+int json_emit_quoted_str(char *buf, int buf_len, const char *str) {
+ int i = 0, j = 0, ch;
+
+#define EMIT(x) do { if (j < buf_len) buf[j++] = x; } while (0)
+
+ EMIT('"');
+ while ((ch = str[i++]) != '\0' && j < buf_len) {
+ switch (ch) {
+ case '"': EMIT('\\'); EMIT('"'); break;
+ case '\\': EMIT('\\'); EMIT('\\'); break;
+ case '\b': EMIT('\\'); EMIT('b'); break;
+ case '\f': EMIT('\\'); EMIT('f'); break;
+ case '\n': EMIT('\\'); EMIT('n'); break;
+ case '\r': EMIT('\\'); EMIT('r'); break;
+ case '\t': EMIT('\\'); EMIT('t'); break;
+ default: EMIT(ch);
+ }
+ }
+ EMIT('"');
+ EMIT(0);
+
+ return j == 0 ? 0 : j - 1;
+}
+
+int json_emit_raw_str(char *buf, int buf_len, const char *str) {
+ return buf_len <= 0 ? 0 : snprintf(buf, buf_len, "%s", str);
+}
\ No newline at end of file
--- /dev/null
+/* ympd
+ (c) 2013-2014 Andrew Karpow <andy@ndyk.de>
+ This project's homepage is: http://www.ympd.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef __JSON_ENCODE_H__
+#define __JSON_ENCODE_H__
+
+int json_emit_int(char *buf, int buf_len, long int value);
+int json_emit_double(char *buf, int buf_len, double value);
+int json_emit_quoted_str(char *buf, int buf_len, const char *str);
+int json_emit_raw_str(char *buf, int buf_len, const char *str);
+
+#endif
\ No newline at end of file
#include "mpd_client.h"
#include "config.h"
+#include "json_encode.h"
const char * mpd_cmd_strs[] = {
MPD_CMDS(GEN_STR)
case MPD_API_RM_ALL:
mpd_run_clear(mpd.conn);
break;
- case MPD_API_GET_QUEUE:
- n = mpd_put_queue(mpd.buf);
- break;
case MPD_API_RM_TRACK:
if(sscanf(c->content, "MPD_API_RM_TRACK,%u", &uint_buf))
mpd_run_delete_id(mpd.conn, uint_buf);
if(sscanf(c->content, "MPD_API_SET_SEEK,%u,%u", &uint_buf, &uint_buf_2))
mpd_run_seek_id(mpd.conn, uint_buf, uint_buf_2);
break;
+ case MPD_API_GET_QUEUE:
+ if(sscanf(c->content, "MPD_API_GET_QUEUE,%u", &uint_buf))
+ n = mpd_put_queue(mpd.buf, uint_buf);
+ break;
case MPD_API_GET_BROWSE:
- if(sscanf(c->content, "MPD_API_GET_BROWSE,%m[^\t\n]", &p_charbuf) && p_charbuf != NULL)
- n = mpd_put_browse(mpd.buf, p_charbuf);
- else
- n = mpd_put_browse(mpd.buf, "/");
- free(p_charbuf);
+ if(sscanf(c->content, "MPD_API_GET_BROWSE,%u,%m[^\t\n]", &uint_buf, &p_charbuf) && p_charbuf != NULL)
+ {
+ n = mpd_put_browse(mpd.buf, p_charbuf, uint_buf);
+ free(p_charbuf);
+ }
break;
case MPD_API_ADD_TRACK:
if(sscanf(c->content, "MPD_API_ADD_TRACK,%m[^\t\n]", &p_charbuf) && p_charbuf != NULL)
mpd.password = p_charbuf;
mpd.conn_state = MPD_RECONNECT;
- printf("Got mpd pw %s\n", mpd.password);
return MG_CLIENT_CONTINUE;
}
break;
char* mpd_get_title(struct mpd_song const *song)
{
- char *str, *ptr;
+ char *str;
str = (char *)mpd_song_get_tag(song, MPD_TAG_TITLE, 0);
if(str == NULL){
str = basename((char *)mpd_song_get_uri(song));
}
- if(str == NULL)
- return NULL;
-
- ptr = str;
- while(*ptr++ != '\0')
- if(*ptr=='"')
- *ptr='\'';
-
return str;
}
if(song == NULL)
return 0;
- cur += snprintf(cur, end - cur, "{\"type\": \"song_change\", \"data\":"
- "{\"pos\":%d, \"title\":\"%s\"",
- mpd_song_get_pos(song),
- mpd_get_title(song));
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\": \"song_change\", \"data\":{\"pos\":");
+ cur += json_emit_int(cur, end - cur, mpd_song_get_pos(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"title\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_get_title(song));
+
if(mpd_song_get_tag(song, MPD_TAG_ARTIST, 0) != NULL)
- cur += snprintf(cur, end - cur, ", \"artist\":\"%s\"",
- mpd_song_get_tag(song, MPD_TAG_ARTIST, 0));
+ {
+ cur += json_emit_raw_str(cur, end - cur, ",\"artist\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_song_get_tag(song, MPD_TAG_ARTIST, 0));
+ }
+
if(mpd_song_get_tag(song, MPD_TAG_ALBUM, 0) != NULL)
- cur += snprintf(cur, end - cur, ", \"album\":\"%s\"",
- mpd_song_get_tag(song, MPD_TAG_ALBUM, 0));
+ {
+ cur += json_emit_raw_str(cur, end - cur, ",\"album\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_song_get_tag(song, MPD_TAG_ALBUM, 0));
+ }
- cur += snprintf(cur, end - cur, "}}");
+ cur += json_emit_raw_str(cur, end - cur, "}}");
mpd_song_free(song);
mpd_response_finish(mpd.conn);
return cur - buffer;
}
-int mpd_put_queue(char *buffer)
+int mpd_put_queue(char *buffer, unsigned int offset)
{
char *cur = buffer;
const char *end = buffer + MAX_SIZE;
struct mpd_entity *entity;
- if (!mpd_send_list_queue_meta(mpd.conn))
+ if (!mpd_send_list_queue_range_meta(mpd.conn, offset, offset+MAX_ELEMENTS_PER_PAGE))
RETURN_ERROR_AND_RECOVER("mpd_send_list_queue_meta");
- cur += snprintf(cur, end - cur, "{\"type\": \"queue\", \"data\": [ ");
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"queue\",\"data\":[ ");
while((entity = mpd_recv_entity(mpd.conn)) != NULL) {
const struct mpd_song *song;
if(mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
song = mpd_entity_get_song(entity);
- cur += snprintf(cur, end - cur,
- "{\"id\":%d, \"pos\":%d, \"duration\":%d, \"title\":\"%s\"},",
- mpd_song_get_id(song),
- mpd_song_get_pos(song),
- mpd_song_get_duration(song),
- mpd_get_title(song)
- );
+
+ cur += json_emit_raw_str(cur, end - cur, "{\"id\":");
+ cur += json_emit_int(cur, end - cur, mpd_song_get_id(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"pos\":");
+ cur += json_emit_int(cur, end - cur, mpd_song_get_pos(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"duration\":");
+ cur += json_emit_int(cur, end - cur, mpd_song_get_duration(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"title\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_get_title(song));
+ cur += json_emit_raw_str(cur, end - cur, "},");
}
mpd_entity_free(entity);
}
/* remove last ',' */
cur--;
- cur += snprintf(cur, end - cur, "] }");
+
+ cur += json_emit_raw_str(cur, end - cur, "]}");
return cur - buffer;
}
-int mpd_put_browse(char *buffer, char *path)
+int mpd_put_browse(char *buffer, char *path, unsigned int offset)
{
char *cur = buffer;
const char *end = buffer + MAX_SIZE;
struct mpd_entity *entity;
-
+ unsigned int entity_count = 0;
if (!mpd_send_list_meta(mpd.conn, path))
RETURN_ERROR_AND_RECOVER("mpd_send_list_meta");
- cur += snprintf(cur, end - cur, "{\"type\":\"browse\",\"data\":[ ");
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"browse\",\"data\":[ ");
while((entity = mpd_recv_entity(mpd.conn)) != NULL) {
const struct mpd_song *song;
const struct mpd_directory *dir;
const struct mpd_playlist *pl;
+ if(offset > entity_count)
+ {
+ mpd_entity_free(entity);
+ entity_count++;
+ continue;
+ }
+ else if(offset + MAX_ELEMENTS_PER_PAGE - 1 < entity_count)
+ {
+ mpd_entity_free(entity);
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"wrap\",\"count\":");
+ cur += json_emit_int(cur, end - cur, entity_count);
+ cur += json_emit_raw_str(cur, end - cur, "} ");
+ break;
+ }
+
switch (mpd_entity_get_type(entity)) {
case MPD_ENTITY_TYPE_UNKNOWN:
break;
case MPD_ENTITY_TYPE_SONG:
song = mpd_entity_get_song(entity);
- cur += snprintf(cur, end - cur,
- "{\"type\":\"song\",\"uri\":\"%s\",\"duration\":%d,\"title\":\"%s\"},",
- mpd_song_get_uri(song),
- mpd_song_get_duration(song),
- mpd_get_title(song)
- );
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"song\",\"uri\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_song_get_uri(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"duration\":");
+ cur += json_emit_int(cur, end - cur, mpd_song_get_duration(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"title\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_get_title(song));
+ cur += json_emit_raw_str(cur, end - cur, "},");
break;
case MPD_ENTITY_TYPE_DIRECTORY:
dir = mpd_entity_get_directory(entity);
- cur += snprintf(cur, end - cur,
- "{\"type\":\"directory\",\"dir\":\"%s\", \"basename\":\"%s\"},",
- mpd_directory_get_path(dir),
- basename((char *)mpd_directory_get_path(dir))
- );
+
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"directory\",\"dir\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_directory_get_path(dir));
+ cur += json_emit_raw_str(cur, end - cur, "},");
break;
case MPD_ENTITY_TYPE_PLAYLIST:
pl = mpd_entity_get_playlist(entity);
- cur += snprintf(cur, end - cur,
- "{\"type\":\"playlist\",\"plist\":\"%s\"},",
- mpd_playlist_get_path(pl)
- );
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"playlist\",\"plist\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_playlist_get_path(pl));
+ cur += json_emit_raw_str(cur, end - cur, "},");
break;
}
mpd_entity_free(entity);
+ entity_count++;
}
if (mpd_connection_get_error(mpd.conn) != MPD_ERROR_SUCCESS || !mpd_response_finish(mpd.conn)) {
/* remove last ',' */
cur--;
- cur += snprintf(cur, end - cur, "] }");
+
+ cur += json_emit_raw_str(cur, end - cur, "]}");
return cur - buffer;
}
int mpd_search(char *buffer, char *searchstr)
{
+ int i = 0;
char *cur = buffer;
const char *end = buffer + MAX_SIZE;
struct mpd_song *song;
else if(mpd_search_commit(mpd.conn) == false)
RETURN_ERROR_AND_RECOVER("mpd_search_commit");
else {
- cur += snprintf(cur, end - cur, "{\"type\": \"search\", \"data\": [ ");
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"search\",\"data\":[ ");
while((song = mpd_recv_song(mpd.conn)) != NULL) {
- cur += snprintf(cur, end - cur,
- "{\"type\":\"song\",\"uri\":\"%s\",\"duration\":%d,\"title\":\"%s\"},",
- mpd_song_get_uri(song),
- mpd_song_get_duration(song),
- mpd_get_title(song)
- );
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"song\",\"uri\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_song_get_uri(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"duration\":");
+ cur += json_emit_int(cur, end - cur, mpd_song_get_duration(song));
+ cur += json_emit_raw_str(cur, end - cur, ",\"title\":");
+ cur += json_emit_quoted_str(cur, end - cur, mpd_get_title(song));
+ cur += json_emit_raw_str(cur, end - cur, "},");
mpd_song_free(song);
+
+ /* Maximum results */
+ if(i++ >= 300)
+ {
+ cur += json_emit_raw_str(cur, end - cur, "{\"type\":\"wrap\"},");
+ break;
+ }
}
/* remove last ',' */
cur--;
- cur += snprintf(cur, end - cur, "] }");
+
+ cur += json_emit_raw_str(cur, end - cur, "]}");
}
return cur - buffer;
}
#define MAX_SIZE 1024 * 100
+#define MAX_ELEMENTS_PER_PAGE 512
+
#define GEN_ENUM(X) X,
#define GEN_STR(X) #X,
#define MPD_CMDS(X) \
int mpd_close_handler(struct mg_connection *c);
int mpd_put_state(char *buffer, int *current_song_id, unsigned *queue_version);
int mpd_put_current_song(char *buffer);
-int mpd_put_queue(char *buffer);
-int mpd_put_browse(char *buffer, char *path);
+int mpd_put_queue(char *buffer, unsigned int offset);
+int mpd_put_browse(char *buffer, char *path, unsigned int offset);
int mpd_search(char *buffer, char *searchstr);
void mpd_disconnect();
#endif
{"port", required_argument, 0, 'p'},
{"webport", required_argument, 0, 'w'},
{"user", required_argument, 0, 'u'},
- {"version", no_argument, 0, 'V'},
+ {"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 0 },
{0, 0, 0, 0 }
};
- while((n = getopt_long(argc, argv, "h:p:w:u::V",
+ while((n = getopt_long(argc, argv, "h:p:w:u:v",
long_options, &option_index)) != -1) {
switch (n) {
case 'h':
mg_set_option(server, "listening_port", optarg);
break;
case 'u':
+ printf("Strarg is %s\n", optarg);
mg_set_option(server, "run_as_user", optarg);
break;
- case 'V':
+ case 'v':
fprintf(stdout, "ympd %d.%d.%d\n"
"Copyright (C) 2014 Andrew Karpow <andy@ndyk.de>\n"
"built " __DATE__ " "__TIME__ " ("__VERSION__")\n",
break;
default:
fprintf(stderr, "Usage: %s [OPTION]...\n\n"
- "\t-h, --host <host>\t\tconnect to mpd at host [localhost]\n"
- "\t-p, --port <port>\t\tconnect to mpd at port [6600]\n"
- "\t-w, --webport [ip:]<port>\t\tlisten interface/port for webserver [8080]\n"
- "\t-u, --user <username>\t\t\tdrop priviliges to user after socket bind\n"
- "\t-V, --version\t\t\tget version\n"
- "\t--help\t\t\t\tthis help\n"
+ " -h, --host <host>\t\tconnect to mpd at host [localhost]\n"
+ " -p, --port <port>\t\tconnect to mpd at port [6600]\n"
+ " -w, --webport [ip:]<port>\tlisten interface/port for webserver [8080]\n"
+ " -u, --user <username>\t\tdrop priviliges to user after socket bind\n"
+ " -V, --version\t\t\tget version\n"
+ " --help\t\t\t\tthis help\n"
, argv[0]);
return EXIT_FAILURE;
}