mirror of
https://github.com/SuperBFG7/ympd
synced 2025-04-18 08:43:15 +00:00
Save myMPD settings in state file, not in cookies
This commit is contained in:
parent
b790a687a3
commit
c11bfa0d1a
@ -687,7 +687,6 @@
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<script src="js/jquery-3.3.1.min.js"></script>
|
||||
<script src="js/js.cookie-2.2.0.min.js"></script>
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/bootstrap-slider.min.js"></script>
|
||||
<script src="js/bootstrap-notify.min.js"></script>
|
||||
|
@ -1,165 +0,0 @@
|
||||
/*!
|
||||
* JavaScript Cookie v2.2.0
|
||||
* https://github.com/js-cookie/js-cookie
|
||||
*
|
||||
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
|
||||
* Released under the MIT license
|
||||
*/
|
||||
;(function (factory) {
|
||||
var registeredInModuleLoader = false;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(factory);
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (!registeredInModuleLoader) {
|
||||
var OldCookies = window.Cookies;
|
||||
var api = window.Cookies = factory();
|
||||
api.noConflict = function () {
|
||||
window.Cookies = OldCookies;
|
||||
return api;
|
||||
};
|
||||
}
|
||||
}(function () {
|
||||
function extend () {
|
||||
var i = 0;
|
||||
var result = {};
|
||||
for (; i < arguments.length; i++) {
|
||||
var attributes = arguments[ i ];
|
||||
for (var key in attributes) {
|
||||
result[key] = attributes[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function init (converter) {
|
||||
function api (key, value, attributes) {
|
||||
var result;
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Write
|
||||
|
||||
if (arguments.length > 1) {
|
||||
attributes = extend({
|
||||
path: '/'
|
||||
}, api.defaults, attributes);
|
||||
|
||||
if (typeof attributes.expires === 'number') {
|
||||
var expires = new Date();
|
||||
expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
|
||||
attributes.expires = expires;
|
||||
}
|
||||
|
||||
// We're using "expires" because "max-age" is not supported by IE
|
||||
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
|
||||
|
||||
try {
|
||||
result = JSON.stringify(value);
|
||||
if (/^[\{\[]/.test(result)) {
|
||||
value = result;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (!converter.write) {
|
||||
value = encodeURIComponent(String(value))
|
||||
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
|
||||
} else {
|
||||
value = converter.write(value, key);
|
||||
}
|
||||
|
||||
key = encodeURIComponent(String(key));
|
||||
key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
|
||||
key = key.replace(/[\(\)]/g, escape);
|
||||
|
||||
var stringifiedAttributes = '';
|
||||
|
||||
for (var attributeName in attributes) {
|
||||
if (!attributes[attributeName]) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '; ' + attributeName;
|
||||
if (attributes[attributeName] === true) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '=' + attributes[attributeName];
|
||||
}
|
||||
return (document.cookie = key + '=' + value + stringifiedAttributes);
|
||||
}
|
||||
|
||||
// Read
|
||||
|
||||
if (!key) {
|
||||
result = {};
|
||||
}
|
||||
|
||||
// To prevent the for loop in the first place assign an empty array
|
||||
// in case there are no cookies at all. Also prevents odd result when
|
||||
// calling "get()"
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
var rdecode = /(%[0-9A-Z]{2})+/g;
|
||||
var i = 0;
|
||||
|
||||
for (; i < cookies.length; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var cookie = parts.slice(1).join('=');
|
||||
|
||||
if (!this.json && cookie.charAt(0) === '"') {
|
||||
cookie = cookie.slice(1, -1);
|
||||
}
|
||||
|
||||
try {
|
||||
var name = parts[0].replace(rdecode, decodeURIComponent);
|
||||
cookie = converter.read ?
|
||||
converter.read(cookie, name) : converter(cookie, name) ||
|
||||
cookie.replace(rdecode, decodeURIComponent);
|
||||
|
||||
if (this.json) {
|
||||
try {
|
||||
cookie = JSON.parse(cookie);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (key === name) {
|
||||
result = cookie;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
result[name] = cookie;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
api.set = api;
|
||||
api.get = function (key) {
|
||||
return api.call(api, key);
|
||||
};
|
||||
api.getJSON = function () {
|
||||
return api.apply({
|
||||
json: true
|
||||
}, [].slice.call(arguments));
|
||||
};
|
||||
api.defaults = {};
|
||||
|
||||
api.remove = function (key, attributes) {
|
||||
api(key, '', extend(attributes, {
|
||||
expires: -1
|
||||
}));
|
||||
};
|
||||
|
||||
api.withConverter = init;
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
return init(function () {});
|
||||
}));
|
3
htdocs/js/js.cookie-2.2.0.min.js
vendored
3
htdocs/js/js.cookie-2.2.0.min.js
vendored
@ -1,3 +0,0 @@
|
||||
/*! js-cookie v2.2.0 | MIT */
|
||||
|
||||
!function(e){var n=!1;if("function"==typeof define&&define.amd&&(define(e),n=!0),"object"==typeof exports&&(module.exports=e(),n=!0),!n){var o=window.Cookies,t=window.Cookies=e();t.noConflict=function(){return window.Cookies=o,t}}}(function(){function e(){for(var e=0,n={};e<arguments.length;e++){var o=arguments[e];for(var t in o)n[t]=o[t]}return n}function n(o){function t(n,r,i){var c;if("undefined"!=typeof document){if(arguments.length>1){if("number"==typeof(i=e({path:"/"},t.defaults,i)).expires){var a=new Date;a.setMilliseconds(a.getMilliseconds()+864e5*i.expires),i.expires=a}i.expires=i.expires?i.expires.toUTCString():"";try{c=JSON.stringify(r),/^[\{\[]/.test(c)&&(r=c)}catch(e){}r=o.write?o.write(r,n):encodeURIComponent(r+"").replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),n=(n=(n=encodeURIComponent(n+"")).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent)).replace(/[\(\)]/g,escape);var s="";for(var f in i)i[f]&&(s+="; "+f,!0!==i[f]&&(s+="="+i[f]));return document.cookie=n+"="+r+s}n||(c={});for(var p=document.cookie?document.cookie.split("; "):[],d=/(%[0-9A-Z]{2})+/g,u=0;u<p.length;u++){var l=p[u].split("="),C=l.slice(1).join("=");this.json||'"'!==C.charAt(0)||(C=C.slice(1,-1));try{var m=l[0].replace(d,decodeURIComponent);if(C=o.read?o.read(C,m):o(C,m)||C.replace(d,decodeURIComponent),this.json)try{C=JSON.parse(C)}catch(e){}if(n===m){c=C;break}n||(c[m]=C)}catch(e){}}return c}}return t.set=t,t.get=function(e){return t.call(t,e)},t.getJSON=function(){return t.apply({json:!0},[].slice.call(arguments))},t.defaults={},t.remove=function(n,o){t(n,"",e(o,{expires:-1}))},t.withConverter=n,t}return n(function(){})});
|
188
htdocs/js/mpd.js
188
htdocs/js/mpd.js
@ -27,13 +27,12 @@ var last_song = '';
|
||||
var last_state;
|
||||
var last_outputs;
|
||||
var current_song = new Object();
|
||||
var MAX_ELEMENTS_PER_PAGE = 100;
|
||||
var isTouch = Modernizr.touch ? 1 : 0;
|
||||
var playstate = '';
|
||||
var progressBar;
|
||||
var volumeBar;
|
||||
var coverImageFile = '';
|
||||
var settings = { "notifyPage":1, "notifyWeb": 0, "mpdstream":"" };
|
||||
var settings = {};
|
||||
|
||||
var app = {};
|
||||
|
||||
@ -214,8 +213,7 @@ app.route=function() {
|
||||
};
|
||||
|
||||
$(document).ready(function(){
|
||||
sendAPI({"cmd":"MPD_API_GET_MPD_SETTINGS"},parseSettings);
|
||||
sendAPI({"cmd":"MPD_API_GET_MYMPD_SETTINGS"},parseMympdSettings);
|
||||
sendAPI({"cmd":"MPD_API_GET_SETTINGS"},parseSettings);
|
||||
sendAPI({"cmd":"MPD_API_GET_OUTPUTNAMES"},parseOutputnames);
|
||||
|
||||
webSocketConnect();
|
||||
@ -257,14 +255,9 @@ $(document).ready(function(){
|
||||
$('#search > input').focus();
|
||||
});
|
||||
|
||||
if(!notificationsSupported())
|
||||
$('#btnnotifyWeb').addClass("disabled");
|
||||
else
|
||||
if (Cookies.get('notificationWeb') === 'true')
|
||||
$('#btnnotifyWeb').removeClass('btn-secondary').addClass("btn-success")
|
||||
|
||||
if (Cookies.get('notificationPage') === 'true')
|
||||
$('#btnnotifyPage').removeClass('btn-secondary').addClass("btn-success")
|
||||
|
||||
|
||||
|
||||
|
||||
add_filter('#BrowseFilesystemFilterLetters');
|
||||
add_filter('#BrowseDatabaseFilterLetters');
|
||||
@ -311,9 +304,6 @@ function webSocketConnect() {
|
||||
case "song_change":
|
||||
songChange(obj);
|
||||
break;
|
||||
case 'settings':
|
||||
parseSettings(obj);
|
||||
break;
|
||||
case 'error':
|
||||
showNotification(obj.data,'','','danger');
|
||||
default:
|
||||
@ -373,55 +363,73 @@ function parseStats(obj) {
|
||||
$('#mpdVersion').text(obj.data.mpd_version);
|
||||
}
|
||||
|
||||
function parseMympdSettings(obj) {
|
||||
settings.notifyPage=obj.data.notifyPage;
|
||||
settings.notifyWeb=obj.data.notifyWeb;
|
||||
//try to set web notification
|
||||
}
|
||||
|
||||
function parseSettings(obj) {
|
||||
if (!isNaN(obj.data.max_elements_per_page))
|
||||
MAX_ELEMENTS_PER_PAGE=obj.data.max_elements_per_page;
|
||||
|
||||
if(obj.data.random)
|
||||
$('#btnrandom').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnrandom').removeClass("btn-success").addClass("btn-secondary");
|
||||
if (obj.data.random)
|
||||
$('#btnrandom').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnrandom').removeClass("btn-success").addClass("btn-secondary");
|
||||
|
||||
if(obj.data.consume)
|
||||
$('#btnconsume').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnconsume').removeClass("btn-success").addClass("btn-secondary");
|
||||
if (obj.data.consume)
|
||||
$('#btnconsume').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnconsume').removeClass("btn-success").addClass("btn-secondary");
|
||||
|
||||
if(obj.data.single)
|
||||
$('#btnsingle').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnsingle').removeClass("btn-success").addClass("btn-secondary");
|
||||
if (obj.data.single)
|
||||
$('#btnsingle').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnsingle').removeClass("btn-success").addClass("btn-secondary");
|
||||
|
||||
if(obj.data.crossfade != undefined)
|
||||
$('#inputCrossfade').removeAttr('disabled').val(obj.data.crossfade);
|
||||
else
|
||||
$('#inputCrossfade').attr('disabled', 'disabled');
|
||||
if (obj.data.crossfade != undefined)
|
||||
$('#inputCrossfade').removeAttr('disabled').val(obj.data.crossfade);
|
||||
else
|
||||
$('#inputCrossfade').attr('disabled', 'disabled');
|
||||
|
||||
if(obj.data.mixrampdb != undefined)
|
||||
$('#inputMixrampdb').removeAttr('disabled').val(obj.data.mixrampdb);
|
||||
else
|
||||
$('#inputMixrampdb').attr('disabled', 'disabled');
|
||||
if (obj.data.mixrampdb != undefined)
|
||||
$('#inputMixrampdb').removeAttr('disabled').val(obj.data.mixrampdb);
|
||||
else
|
||||
$('#inputMixrampdb').attr('disabled', 'disabled');
|
||||
|
||||
if(obj.data.mixrampdelay != undefined)
|
||||
$('#inputMixrampdelay').removeAttr('disabled').val(obj.data.mixrampdelay);
|
||||
else
|
||||
$('#inputMixrampdb').attr('disabled', 'disabled');
|
||||
if (obj.data.mixrampdelay != undefined)
|
||||
$('#inputMixrampdelay').removeAttr('disabled').val(obj.data.mixrampdelay);
|
||||
else
|
||||
$('#inputMixrampdb').attr('disabled', 'disabled');
|
||||
|
||||
if(obj.data.repeat)
|
||||
$('#btnrepeat').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnrepeat').removeClass("btn-success").addClass("btn-secondary");
|
||||
if (obj.data.repeat)
|
||||
$('#btnrepeat').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnrepeat').removeClass("btn-success").addClass("btn-secondary");
|
||||
|
||||
$("#selectReplaygain").val(obj.data.replaygain);
|
||||
$("#selectReplaygain").val(obj.data.replaygain);
|
||||
|
||||
if (notificationsSupported()) {
|
||||
if (obj.data.notificationWeb) {
|
||||
$('#btnnotifyWeb').removeClass('btn-secondary').addClass("btn-success")
|
||||
|
||||
Notification.requestPermission(function (permission) {
|
||||
if(!('permission' in Notification))
|
||||
Notification.permission = permission;
|
||||
if (permission === 'granted') {
|
||||
$('#btnnotifyWeb').removeClass('btn-secondary').addClass('btn-success');
|
||||
} else {
|
||||
$('#btnnotifyWeb').addClass('btn-secondary').removeClass('btn-success');
|
||||
obj.data.notificationWeb=0;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
$('#btnnotifyWeb').addClass('btn-secondary').removeClass("btn-success");
|
||||
} else {
|
||||
$('#btnnotifyWeb').addClass("disabled");
|
||||
$('#btnnotifyWeb').addClass('btn-secondary').removeClass("btn-success");
|
||||
}
|
||||
|
||||
if (obj.data.notificationPage)
|
||||
$('#btnnotifyPage').removeClass('btn-secondary').addClass("btn-success")
|
||||
else
|
||||
$('#btnnotifyPage').addClass('btn-secondary').removeClass("btn-success");
|
||||
|
||||
settings=obj.data;
|
||||
setLocalStream(obj.data.mpdhost,obj.data.streamport);
|
||||
coverImageFile=obj.data.coverimage;
|
||||
}
|
||||
|
||||
function parseOutputnames(obj) {
|
||||
@ -824,7 +832,7 @@ function parseListDBtags(obj) {
|
||||
function parseListTitles(obj) {
|
||||
if(app.current.app !== 'Browse' && app.current.tab !== 'Database' && app.current.view !== 'Album') return;
|
||||
var album=$('#'+genId(obj.album)+' > div > table > tbody');
|
||||
$('#'+genId(obj.album)+' > img').attr('src','/library/'+obj.data[0].uri.replace(/\/[^\/]+$/,'\/')+coverImageFile);
|
||||
$('#'+genId(obj.album)+' > img').attr('src','/library/'+obj.data[0].uri.replace(/\/[^\/]+$/,'\/')+settings.coverimage);
|
||||
$('#'+genId(obj.album)+' > img').attr('uri',obj.data[0].uri.replace(/\/[^\/]+$/,''));
|
||||
$('#'+genId(obj.album)+' > img').attr('data-album',encodeURI(obj.album));
|
||||
var titleList='';
|
||||
@ -850,26 +858,26 @@ function parseListTitles(obj) {
|
||||
}
|
||||
|
||||
function setPagination(number) {
|
||||
var totalPages=Math.ceil(number / MAX_ELEMENTS_PER_PAGE);
|
||||
var totalPages=Math.ceil(number / settings.max_elements_per_page);
|
||||
var cat=app.current.app+(app.current.tab==undefined ? '': app.current.tab);
|
||||
if (totalPages==0) { totalPages=1; }
|
||||
$('#'+cat+'PaginationTopPage').text('Page '+(app.current.page / MAX_ELEMENTS_PER_PAGE + 1)+' / '+totalPages);
|
||||
$('#'+cat+'PaginationBottomPage').text('Page '+(app.current.page / MAX_ELEMENTS_PER_PAGE + 1)+' / '+totalPages);
|
||||
$('#'+cat+'PaginationTopPage').text('Page '+(app.current.page / settings.max_elements_per_page + 1)+' / '+totalPages);
|
||||
$('#'+cat+'PaginationBottomPage').text('Page '+(app.current.page / settings.max_elements_per_page + 1)+' / '+totalPages);
|
||||
if (totalPages > 1) {
|
||||
$('#'+cat+'PaginationTopPage').removeClass('disabled').removeAttr('disabled');
|
||||
$('#'+cat+'PaginationBottomPage').removeClass('disabled').removeAttr('disabled');
|
||||
$('#'+cat+'PaginationTopPages').empty();
|
||||
$('#'+cat+'PaginationBottomPages').empty();
|
||||
for (var i=0;i<totalPages;i++) {
|
||||
$('#'+cat+'PaginationTopPages').append('<button onclick="gotoPage('+(i * MAX_ELEMENTS_PER_PAGE)+',this,event)" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+(i+1)+'</button>');
|
||||
$('#'+cat+'PaginationBottomPages').append('<button onclick="gotoPage('+(i * MAX_ELEMENTS_PER_PAGE)+',this,event)" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+(i+1)+'</button>');
|
||||
$('#'+cat+'PaginationTopPages').append('<button onclick="gotoPage('+(i * settings.max_elements_per_page)+',this,event)" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+(i+1)+'</button>');
|
||||
$('#'+cat+'PaginationBottomPages').append('<button onclick="gotoPage('+(i * settings.max_elements_per_page)+',this,event)" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+(i+1)+'</button>');
|
||||
}
|
||||
} else {
|
||||
$('#'+cat+'PaginationTopPage').addClass('disabled').attr('disabled','disabled');
|
||||
$('#'+cat+'PaginationBottomPage').addClass('disabled').attr('disabled','disabled');
|
||||
}
|
||||
|
||||
if(number > app.current.page + MAX_ELEMENTS_PER_PAGE) {
|
||||
if(number > app.current.page + settings.max_elements_per_page) {
|
||||
$('#'+cat+'PaginationTopNext').removeClass('disabled').removeAttr('disabled');
|
||||
$('#'+cat+'PaginationBottomNext').removeClass('disabled').removeAttr('disabled');
|
||||
$('#'+cat+'ButtonsBottom').removeClass('hide');
|
||||
@ -1013,10 +1021,16 @@ $('#btnconsume').on('click', function (e) {
|
||||
$('#btnsingle').on('click', function (e) {
|
||||
toggleBtn(this);
|
||||
});
|
||||
|
||||
$('#btnrepeat').on('click', function (e) {
|
||||
toggleBtn(this);
|
||||
});
|
||||
$('#btnnotifyPage').on('click', function (e) {
|
||||
toggleBtn(this);
|
||||
});
|
||||
$('#btnnotifyWeb').on('click', function (e) {
|
||||
toggleBtn(this);
|
||||
});
|
||||
|
||||
|
||||
$('#cardBrowseNavFilesystem').on('click', function (e) {
|
||||
app.goto('Browse','Filesystem');
|
||||
@ -1100,7 +1114,7 @@ function confirmSettings() {
|
||||
}
|
||||
}
|
||||
if (formOK == true) {
|
||||
sendAPI({"cmd":"MPD_API_SET_MPD_SETTINGS", "data": {
|
||||
sendAPI({"cmd":"MPD_API_SET_SETTINGS", "data": {
|
||||
"consume": ($('#btnconsume').hasClass('btn-success') ? 1 : 0),
|
||||
"random": ($('#btnrandom').hasClass('btn-success') ? 1 : 0),
|
||||
"single": ($('#btnsingle').hasClass('btn-success') ? 1 : 0),
|
||||
@ -1108,11 +1122,9 @@ function confirmSettings() {
|
||||
"replaygain": $('#selectReplaygain').val(),
|
||||
"crossfade": $('#inputCrossfade').val(),
|
||||
"mixrampdb": $('#inputMixrampdb').val(),
|
||||
"mixrampdelay": $('#inputMixrampdelay').val()
|
||||
}});
|
||||
sendAPI({"cmd":"MPD_API_SET_MYMPD_SETTINGS","data": {
|
||||
"notificationsWeb": ($('#btnnotifyWeb').hasClass('btn-success') ? 1 : 0),
|
||||
"notificationsPage": ($('#btnnotifyPage').hasClass('btn-success') ? 1 : 0)
|
||||
"mixrampdelay": $('#inputMixrampdelay').val(),
|
||||
"notificationWeb": ($('#btnnotifyWeb').hasClass('btn-success') ? 1 : 0),
|
||||
"notificationPage": ($('#btnnotifyPage').hasClass('btn-success') ? 1 : 0)
|
||||
}});
|
||||
$('#settings').modal('hide');
|
||||
}
|
||||
@ -1127,33 +1139,7 @@ $('#trashmodebtns > button').on('click', function(e) {
|
||||
$(this).removeClass("btn-secondary").addClass("btn-success");
|
||||
});
|
||||
|
||||
$('#btnnotifyWeb').on('click', function (e) {
|
||||
if(Cookies.get('notificationWeb') === 'true') {
|
||||
Cookies.set('notificationWeb', false, { expires: 424242 });
|
||||
$('#btnnotifyWeb').removeClass('btn-success').addClass('btn-secondary');
|
||||
} else {
|
||||
Notification.requestPermission(function (permission) {
|
||||
if(!('permission' in Notification)) {
|
||||
Notification.permission = permission;
|
||||
}
|
||||
|
||||
if (permission === 'granted') {
|
||||
Cookies.set('notificationWeb', true, { expires: 424242 });
|
||||
$('#btnnotifyWeb').removeClass('btn-secondary').addClass('btn-success');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#btnnotifyPage').on('click', function (e) {
|
||||
if(Cookies.get("notificationPage") === 'true') {
|
||||
Cookies.set("notificationPage", false, { expires: 424242 });
|
||||
$('#btnnotifyPage').removeClass('btn-success').addClass('btn-secondary');
|
||||
} else {
|
||||
Cookies.set('notificationPage', true, { expires: 424242 });
|
||||
$('#btnnotifyPage').removeClass('btn-secondary').addClass('btn-success');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#search > input').keypress(function (event) {
|
||||
if ( event.which == 13 ) {
|
||||
@ -1221,10 +1207,10 @@ function scrollToTop() {
|
||||
function gotoPage(x,element,event) {
|
||||
switch (x) {
|
||||
case "next":
|
||||
app.current.page += MAX_ELEMENTS_PER_PAGE;
|
||||
app.current.page += settings.max_elements_per_page;
|
||||
break;
|
||||
case "prev":
|
||||
app.current.page -= MAX_ELEMENTS_PER_PAGE;
|
||||
app.current.page -= settings.max_elements_per_page;
|
||||
if(app.current.page <= 0)
|
||||
app.current.page = 0;
|
||||
break;
|
||||
@ -1251,13 +1237,13 @@ function saveQueue() {
|
||||
}
|
||||
|
||||
function showNotification(notificationTitle,notificationText,notificationHtml,notificationType) {
|
||||
if (Cookies.get('notificationWeb') === 'true') {
|
||||
if (settings.notificationWeb == 1) {
|
||||
var notification = new Notification(notificationTitle, {icon: 'assets/favicon.ico', body: notificationText});
|
||||
setTimeout(function(notification) {
|
||||
notification.close();
|
||||
}, 3000, notification);
|
||||
}
|
||||
if (Cookies.get('notificationPage') === 'true') {
|
||||
if (settings.notificationPage == 1) {
|
||||
$.notify({ title: notificationTitle, message: notificationHtml},{ type: notificationType, offset: { y: 60, x:20 },
|
||||
template: '<div data-notify="container" class="col-xs-11 col-sm-3 alert alert-{0}" role="alert">' +
|
||||
'<button type="button" aria-hidden="true" class="close" data-notify="dismiss">×</button>' +
|
||||
@ -1285,8 +1271,8 @@ function songChange(obj) {
|
||||
var coverImg='';
|
||||
if (obj.data.uri.indexOf('http://') == 0 || obj.data.uri.indexOf('https://') == 0 ) {
|
||||
coverImg='/assets/coverimage-httpstream.png';
|
||||
} else if (coverImageFile != '') {
|
||||
coverImg='/library/'+obj.data.uri.replace(/\/[^\/]+$/,'\/'+coverImageFile);
|
||||
} else if (settings.coverimage != '') {
|
||||
coverImg='/library/'+obj.data.uri.replace(/\/[^\/]+$/,'\/'+settings.coverimage);
|
||||
} else {
|
||||
coverImg='/assets/coverimage-notavailable.png';
|
||||
}
|
||||
|
@ -29,8 +29,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script type="text/javascript" src="js/js.cookie-2.2.0.min.js"></script>
|
||||
<script type="text/javascript" src="js/player.js"></script>
|
||||
<script type="text/javascript" src="js/player.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,20 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
||||
* Copyright (c) 2013 Cesanta Software Limited
|
||||
* Copyright (c) 2018 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/>.
|
||||
* Licensed under the Apache License, Version 2.0 (the ""License"");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Alternatively, you can license this library under a commercial
|
||||
* license, as set out in <http://cesanta.com/products.html>.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an ""AS IS"" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */
|
||||
@ -35,6 +34,8 @@
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef snprintf
|
||||
#undef vsnprintf
|
||||
#define snprintf cs_win_snprintf
|
||||
#define vsnprintf cs_win_vsnprintf
|
||||
int cs_win_snprintf(char *str, size_t size, const char *format, ...);
|
||||
@ -47,33 +48,27 @@ typedef unsigned _int64 uint64_t;
|
||||
#endif
|
||||
#define PRId64 "I64d"
|
||||
#define PRIu64 "I64u"
|
||||
#if !defined(SIZE_T_FMT)
|
||||
#if _MSC_VER >= 1310
|
||||
#define SIZE_T_FMT "Iu"
|
||||
#else
|
||||
#define SIZE_T_FMT "u"
|
||||
#endif
|
||||
#endif
|
||||
#else /* _WIN32 */
|
||||
/* <inttypes.h> wants this for C++ */
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#if !defined(SIZE_T_FMT)
|
||||
#define SIZE_T_FMT "zu"
|
||||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifndef INT64_FMT
|
||||
#define INT64_FMT PRId64
|
||||
#endif
|
||||
#ifndef UINT64_FMT
|
||||
#define UINT64_FMT PRIu64
|
||||
#endif
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(x, y) x = y
|
||||
#endif
|
||||
|
||||
#ifndef JSON_MAX_PATH_LEN
|
||||
#define JSON_MAX_PATH_LEN 60
|
||||
#define JSON_MAX_PATH_LEN 256
|
||||
#endif
|
||||
|
||||
struct frozen {
|
||||
@ -85,14 +80,14 @@ struct frozen {
|
||||
|
||||
/* For callback API */
|
||||
char path[JSON_MAX_PATH_LEN];
|
||||
int path_len;
|
||||
size_t path_len;
|
||||
void *callback_data;
|
||||
json_walk_callback_t callback;
|
||||
};
|
||||
|
||||
struct fstate {
|
||||
const char *ptr;
|
||||
int path_len;
|
||||
size_t path_len;
|
||||
};
|
||||
|
||||
#define SET_STATE(fr, ptr, str, len) \
|
||||
@ -117,14 +112,15 @@ struct fstate {
|
||||
|
||||
static int append_to_path(struct frozen *f, const char *str, int size) {
|
||||
int n = f->path_len;
|
||||
f->path_len +=
|
||||
snprintf(f->path + f->path_len, sizeof(f->path) - (f->path_len + 1),
|
||||
"%.*s", size, str);
|
||||
|
||||
int left = sizeof(f->path) - n - 1;
|
||||
if (size > left) size = left;
|
||||
memcpy(f->path + n, str, size);
|
||||
f->path[n + size] = '\0';
|
||||
f->path_len += size;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void truncate_path(struct frozen *f, int len) {
|
||||
static void truncate_path(struct frozen *f, size_t len) {
|
||||
f->path_len = len;
|
||||
f->path[len] = '\0';
|
||||
}
|
||||
@ -242,7 +238,7 @@ static int parse_string(struct frozen *f) {
|
||||
ch = *(unsigned char *) f->cur;
|
||||
len = get_utf8_char_len((unsigned char) ch);
|
||||
EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
|
||||
EXPECT(len < left(f), JSON_STRING_INCOMPLETE);
|
||||
EXPECT(len <= left(f), JSON_STRING_INCOMPLETE);
|
||||
if (ch == '\\') {
|
||||
EXPECT((n = get_escape_len(f->cur + 1, left(f))) > 0, n);
|
||||
len += n;
|
||||
@ -288,9 +284,9 @@ static int parse_number(struct frozen *f) {
|
||||
static int parse_array(struct frozen *f) {
|
||||
int i = 0, current_path_len;
|
||||
char buf[20];
|
||||
CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0);
|
||||
TRY(test_and_skip(f, '['));
|
||||
{
|
||||
CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0);
|
||||
{
|
||||
SET_STATE(f, f->cur - 1, "", 0);
|
||||
while (cur(f) != ']') {
|
||||
@ -374,9 +370,6 @@ static int parse_value(struct frozen *f) {
|
||||
/* key = identifier | string */
|
||||
static int parse_key(struct frozen *f) {
|
||||
int ch = cur(f);
|
||||
#if 0
|
||||
printf("%s [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur);
|
||||
#endif
|
||||
if (is_alpha(ch)) {
|
||||
TRY(parse_identifier(f));
|
||||
} else if (ch == '"') {
|
||||
@ -407,19 +400,17 @@ static int parse_pair(struct frozen *f) {
|
||||
|
||||
/* object = '{' pair { ',' pair } '}' */
|
||||
static int parse_object(struct frozen *f) {
|
||||
CALL_BACK(f, JSON_TYPE_OBJECT_START, NULL, 0);
|
||||
TRY(test_and_skip(f, '{'));
|
||||
{
|
||||
CALL_BACK(f, JSON_TYPE_OBJECT_START, NULL, 0);
|
||||
{
|
||||
SET_STATE(f, f->cur - 1, ".", 1);
|
||||
while (cur(f) != '}') {
|
||||
TRY(parse_pair(f));
|
||||
if (cur(f) == ',') f->cur++;
|
||||
}
|
||||
TRY(test_and_skip(f, '}'));
|
||||
truncate_path(f, fstate.path_len);
|
||||
CALL_BACK(f, JSON_TYPE_OBJECT_END, fstate.ptr, f->cur - fstate.ptr);
|
||||
SET_STATE(f, f->cur - 1, ".", 1);
|
||||
while (cur(f) != '}') {
|
||||
TRY(parse_pair(f));
|
||||
if (cur(f) == ',') f->cur++;
|
||||
}
|
||||
TRY(test_and_skip(f, '}'));
|
||||
truncate_path(f, fstate.path_len);
|
||||
CALL_BACK(f, JSON_TYPE_OBJECT_END, fstate.ptr, f->cur - fstate.ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -430,7 +421,8 @@ static int doit(struct frozen *f) {
|
||||
return parse_value(f);
|
||||
}
|
||||
|
||||
static int json_encode_string(struct json_out *out, const char *p, size_t len) {
|
||||
int json_escape(struct json_out *out, const char *p, size_t len) WEAK;
|
||||
int json_escape(struct json_out *out, const char *p, size_t len) {
|
||||
size_t i, cl, n = 0;
|
||||
const char *hex_digits = "0123456789abcdef";
|
||||
const char *specials = "btnvfr";
|
||||
@ -505,7 +497,7 @@ static int b64rev(int c) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t hexdec(const char *s) {
|
||||
static unsigned char hexdec(const char *s) {
|
||||
#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
|
||||
int a = tolower(*(const unsigned char *) s);
|
||||
int b = tolower(*(const unsigned char *) (s + 1));
|
||||
@ -569,7 +561,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) {
|
||||
skip += 2;
|
||||
} else if (fmt[1] == 'z' && fmt[2] == 'u') {
|
||||
size_t val = va_arg(ap, size_t);
|
||||
snprintf(buf, sizeof(buf), "%" SIZE_T_FMT, val);
|
||||
snprintf(buf, sizeof(buf), "%lu", (unsigned long) val);
|
||||
len += out->printer(out, buf, strlen(buf));
|
||||
skip += 1;
|
||||
} else if (fmt[1] == 'M') {
|
||||
@ -613,7 +605,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) {
|
||||
l = strlen(p);
|
||||
}
|
||||
len += out->printer(out, quote, 1);
|
||||
len += json_encode_string(out, p, l);
|
||||
len += json_escape(out, p, l);
|
||||
len += out->printer(out, quote, 1);
|
||||
}
|
||||
} else {
|
||||
@ -628,30 +620,48 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) {
|
||||
* TODO(dfrank): reimplement %s and %.*s in order to avoid that.
|
||||
*/
|
||||
|
||||
const char *end_of_format_specifier = "sdfFgGlhuI.*-0123456789";
|
||||
size_t n = strspn(fmt + 1, end_of_format_specifier);
|
||||
const char *end_of_format_specifier = "sdfFgGlhuIcx.*-0123456789";
|
||||
int n = strspn(fmt + 1, end_of_format_specifier);
|
||||
char *pbuf = buf;
|
||||
size_t need_len;
|
||||
int need_len, size = sizeof(buf);
|
||||
char fmt2[20];
|
||||
va_list sub_ap;
|
||||
strncpy(fmt2, fmt, n + 1 > sizeof(fmt2) ? sizeof(fmt2) : n + 1);
|
||||
va_list ap_copy;
|
||||
strncpy(fmt2, fmt,
|
||||
n + 1 > (int) sizeof(fmt2) ? sizeof(fmt2) : (size_t) n + 1);
|
||||
fmt2[n + 1] = '\0';
|
||||
|
||||
va_copy(sub_ap, ap);
|
||||
need_len =
|
||||
vsnprintf(buf, sizeof(buf), fmt2, sub_ap) + 1 /* null-term */;
|
||||
/*
|
||||
* TODO(lsm): Fix windows & eCos code path here. Their vsnprintf
|
||||
* implementation returns -1 on overflow rather needed size.
|
||||
*/
|
||||
if (need_len > sizeof(buf)) {
|
||||
va_copy(ap_copy, ap);
|
||||
need_len = vsnprintf(pbuf, size, fmt2, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if (need_len < 0) {
|
||||
/*
|
||||
* Windows & eCos vsnprintf implementation return -1 on overflow
|
||||
* instead of needed size.
|
||||
*/
|
||||
pbuf = NULL;
|
||||
while (need_len < 0) {
|
||||
free(pbuf);
|
||||
size *= 2;
|
||||
if ((pbuf = (char *) malloc(size)) == NULL) break;
|
||||
va_copy(ap_copy, ap);
|
||||
need_len = vsnprintf(pbuf, size, fmt2, ap_copy);
|
||||
va_end(ap_copy);
|
||||
}
|
||||
} else if (need_len >= (int) sizeof(buf)) {
|
||||
/*
|
||||
* resulting string doesn't fit into a stack-allocated buffer `buf`,
|
||||
* so we need to allocate a new buffer from heap and use it
|
||||
*/
|
||||
pbuf = (char *) malloc(need_len);
|
||||
va_copy(sub_ap, ap);
|
||||
vsnprintf(pbuf, need_len, fmt2, sub_ap);
|
||||
if ((pbuf = (char *) malloc(need_len + 1)) != NULL) {
|
||||
va_copy(ap_copy, ap);
|
||||
vsnprintf(pbuf, need_len + 1, fmt2, ap_copy);
|
||||
va_end(ap_copy);
|
||||
}
|
||||
}
|
||||
if (pbuf == NULL) {
|
||||
buf[0] = '\0';
|
||||
pbuf = buf;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -663,7 +673,6 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) {
|
||||
if ((n + 1 == strlen("%" PRId64) && strcmp(fmt2, "%" PRId64) == 0) ||
|
||||
(n + 1 == strlen("%" PRIu64) && strcmp(fmt2, "%" PRIu64) == 0)) {
|
||||
(void) va_arg(ap, int64_t);
|
||||
skip += strlen(PRIu64) - 1;
|
||||
} else if (strcmp(fmt2, "%.*s") == 0) {
|
||||
(void) va_arg(ap, int);
|
||||
(void) va_arg(ap, char *);
|
||||
@ -704,6 +713,7 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) {
|
||||
}
|
||||
len += out->printer(out, quote, 1);
|
||||
} else {
|
||||
len += out->printer(out, fmt, 1);
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
@ -749,7 +759,8 @@ int json_printf_array(struct json_out *out, va_list *ap) {
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap) WEAK;
|
||||
int cs_win_vsnprintf(char *str, size_t size, const char *format,
|
||||
va_list ap) WEAK;
|
||||
int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
|
||||
int res = _vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
@ -788,6 +799,7 @@ int json_walk(const char *json_string, int json_string_length,
|
||||
}
|
||||
|
||||
struct scan_array_info {
|
||||
int found;
|
||||
char path[JSON_MAX_PATH_LEN];
|
||||
struct json_token *token;
|
||||
};
|
||||
@ -802,6 +814,7 @@ static void json_scanf_array_elem_cb(void *callback_data, const char *name,
|
||||
|
||||
if (strcmp(path, info->path) == 0) {
|
||||
*info->token = *token;
|
||||
info->found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -811,10 +824,11 @@ int json_scanf_array_elem(const char *s, int len, const char *path, int idx,
|
||||
struct json_token *token) {
|
||||
struct scan_array_info info;
|
||||
info.token = token;
|
||||
info.found = 0;
|
||||
memset(token, 0, sizeof(*token));
|
||||
snprintf(info.path, sizeof(info.path), "%s[%d]", path, idx);
|
||||
json_walk(s, len, json_scanf_array_elem_cb, &info);
|
||||
return token->len;
|
||||
return info.found ? token->len : -1;
|
||||
}
|
||||
|
||||
struct json_scanf_info {
|
||||
@ -856,6 +870,7 @@ static void json_scanf_cb(void *callback_data, const char *name,
|
||||
size_t name_len, const char *path,
|
||||
const struct json_token *token) {
|
||||
struct json_scanf_info *info = (struct json_scanf_info *) callback_data;
|
||||
char buf[32]; /* Must be enough to hold numbers */
|
||||
|
||||
(void) name;
|
||||
(void) name_len;
|
||||
@ -876,7 +891,17 @@ static void json_scanf_cb(void *callback_data, const char *name,
|
||||
switch (info->type) {
|
||||
case 'B':
|
||||
info->num_conversions++;
|
||||
*(int *) info->target = (token->type == JSON_TYPE_TRUE ? 1 : 0);
|
||||
switch (sizeof(bool)) {
|
||||
case sizeof(char):
|
||||
*(char *) info->target = (token->type == JSON_TYPE_TRUE ? 1 : 0);
|
||||
break;
|
||||
case sizeof(int):
|
||||
*(int *) info->target = (token->type == JSON_TYPE_TRUE ? 1 : 0);
|
||||
break;
|
||||
default:
|
||||
/* should never be here */
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 'M': {
|
||||
union {
|
||||
@ -889,12 +914,21 @@ static void json_scanf_cb(void *callback_data, const char *name,
|
||||
}
|
||||
case 'Q': {
|
||||
char **dst = (char **) info->target;
|
||||
int unescaped_len = json_unescape(token->ptr, token->len, NULL, 0);
|
||||
if (unescaped_len >= 0 &&
|
||||
(*dst = (char *) malloc(unescaped_len + 1)) != NULL) {
|
||||
info->num_conversions++;
|
||||
json_unescape(token->ptr, token->len, *dst, unescaped_len);
|
||||
(*dst)[unescaped_len] = '\0';
|
||||
if (token->type == JSON_TYPE_NULL) {
|
||||
*dst = NULL;
|
||||
} else {
|
||||
int unescaped_len = json_unescape(token->ptr, token->len, NULL, 0);
|
||||
if (unescaped_len >= 0 &&
|
||||
(*dst = (char *) malloc(unescaped_len + 1)) != NULL) {
|
||||
info->num_conversions++;
|
||||
if (json_unescape(token->ptr, token->len, *dst, unescaped_len) ==
|
||||
unescaped_len) {
|
||||
(*dst)[unescaped_len] = '\0';
|
||||
} else {
|
||||
free(*dst);
|
||||
*dst = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -927,7 +961,12 @@ static void json_scanf_cb(void *callback_data, const char *name,
|
||||
*(struct json_token *) info->target = *token;
|
||||
break;
|
||||
default:
|
||||
info->num_conversions += sscanf(token->ptr, info->fmt, info->target);
|
||||
/* Before scanf, copy into tmp buffer in order to 0-terminate it */
|
||||
if (token->len < (int) sizeof(buf)) {
|
||||
memcpy(buf, token->ptr, token->len);
|
||||
buf[token->len] = '\0';
|
||||
info->num_conversions += sscanf(buf, info->fmt, info->target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -992,3 +1031,380 @@ int json_scanf(const char *str, int len, const char *fmt, ...) {
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
int json_vfprintf(const char *file_name, const char *fmt, va_list ap) WEAK;
|
||||
int json_vfprintf(const char *file_name, const char *fmt, va_list ap) {
|
||||
int res = -1;
|
||||
FILE *fp = fopen(file_name, "wb");
|
||||
if (fp != NULL) {
|
||||
struct json_out out = JSON_OUT_FILE(fp);
|
||||
res = json_vprintf(&out, fmt, ap);
|
||||
fputc('\n', fp);
|
||||
fclose(fp);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int json_fprintf(const char *file_name, const char *fmt, ...) WEAK;
|
||||
int json_fprintf(const char *file_name, const char *fmt, ...) {
|
||||
int result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
result = json_vfprintf(file_name, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *json_fread(const char *path) WEAK;
|
||||
char *json_fread(const char *path) {
|
||||
FILE *fp;
|
||||
char *data = NULL;
|
||||
if ((fp = fopen(path, "rb")) == NULL) {
|
||||
} else if (fseek(fp, 0, SEEK_END) != 0) {
|
||||
fclose(fp);
|
||||
} else {
|
||||
long size = ftell(fp);
|
||||
if (size > 0 && (data = (char *) malloc(size + 1)) != NULL) {
|
||||
fseek(fp, 0, SEEK_SET); /* Some platforms might not have rewind(), Oo */
|
||||
if (fread(data, 1, size, fp) != (size_t) size) {
|
||||
free(data);
|
||||
data = NULL;
|
||||
} else {
|
||||
data[size] = '\0';
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
struct json_setf_data {
|
||||
const char *json_path;
|
||||
const char *base; /* Pointer to the source JSON string */
|
||||
int matched; /* Matched part of json_path */
|
||||
int pos; /* Offset of the mutated value begin */
|
||||
int end; /* Offset of the mutated value end */
|
||||
int prev; /* Offset of the previous token end */
|
||||
};
|
||||
|
||||
static int get_matched_prefix_len(const char *s1, const char *s2) {
|
||||
int i = 0;
|
||||
while (s1[i] && s2[i] && s1[i] == s2[i]) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static void json_vsetf_cb(void *userdata, const char *name, size_t name_len,
|
||||
const char *path, const struct json_token *t) {
|
||||
struct json_setf_data *data = (struct json_setf_data *) userdata;
|
||||
int off, len = get_matched_prefix_len(path, data->json_path);
|
||||
if (t->ptr == NULL) return;
|
||||
off = t->ptr - data->base;
|
||||
// printf("--%d %s %d\n", t->type, path, off);
|
||||
if (len > data->matched) data->matched = len;
|
||||
|
||||
/*
|
||||
* If there is no exact path match, set the mutation position to tbe end
|
||||
* of the object or array
|
||||
*/
|
||||
if (len < data->matched && data->pos == 0 &&
|
||||
(t->type == JSON_TYPE_OBJECT_END || t->type == JSON_TYPE_ARRAY_END)) {
|
||||
data->pos = data->end = data->prev;
|
||||
}
|
||||
|
||||
/* Exact path match. Set mutation position to the value of this token */
|
||||
if (strcmp(path, data->json_path) == 0 && t->type != JSON_TYPE_OBJECT_START &&
|
||||
t->type != JSON_TYPE_ARRAY_START) {
|
||||
data->pos = off;
|
||||
data->end = off + t->len;
|
||||
}
|
||||
|
||||
/*
|
||||
* For deletion, we need to know where the previous value ends, because
|
||||
* we don't know where matched value key starts.
|
||||
* When the mutation position is not yet set, remember each value end.
|
||||
* When the mutation position is already set, but it is at the beginning
|
||||
* of the object/array, we catch the end of the object/array and see
|
||||
* whether the object/array start is closer then previously stored prev.
|
||||
*/
|
||||
if (data->pos == 0) {
|
||||
data->prev = off + t->len; /* pos is not yet set */
|
||||
} else if ((t->ptr[0] == '[' || t->ptr[0] == '{') && off + 1 < data->pos &&
|
||||
off + 1 > data->prev) {
|
||||
data->prev = off + 1;
|
||||
}
|
||||
(void) name;
|
||||
(void) name_len;
|
||||
}
|
||||
|
||||
int json_vsetf(const char *s, int len, struct json_out *out,
|
||||
const char *json_path, const char *json_fmt, va_list ap) WEAK;
|
||||
int json_vsetf(const char *s, int len, struct json_out *out,
|
||||
const char *json_path, const char *json_fmt, va_list ap) {
|
||||
struct json_setf_data data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.json_path = json_path;
|
||||
data.base = s;
|
||||
data.end = len;
|
||||
// printf("S:[%.*s] %s %p\n", len, s, json_path, json_fmt);
|
||||
json_walk(s, len, json_vsetf_cb, &data);
|
||||
// printf("-> %d %d %d\n", data.prev, data.pos, data.end);
|
||||
if (json_fmt == NULL) {
|
||||
/* Deletion codepath */
|
||||
json_printf(out, "%.*s", data.prev, s);
|
||||
/* Trim comma after the value that begins at object/array start */
|
||||
if (s[data.prev - 1] == '{' || s[data.prev - 1] == '[') {
|
||||
int i = data.end;
|
||||
while (i < len && is_space(s[i])) i++;
|
||||
if (s[i] == ',') data.end = i + 1; /* Point after comma */
|
||||
}
|
||||
json_printf(out, "%.*s", len - data.end, s + data.end);
|
||||
} else {
|
||||
/* Modification codepath */
|
||||
int n, off = data.matched, depth = 0;
|
||||
|
||||
/* Print the unchanged beginning */
|
||||
json_printf(out, "%.*s", data.pos, s);
|
||||
|
||||
/* Add missing keys */
|
||||
while ((n = strcspn(&json_path[off], ".[")) > 0) {
|
||||
if (s[data.prev - 1] != '{' && s[data.prev - 1] != '[' && depth == 0) {
|
||||
json_printf(out, ",");
|
||||
}
|
||||
if (off > 0 && json_path[off - 1] != '.') break;
|
||||
json_printf(out, "%.*Q:", 1, json_path + off);
|
||||
off += n;
|
||||
if (json_path[off] != '\0') {
|
||||
json_printf(out, "%c", json_path[off] == '.' ? '{' : '[');
|
||||
depth++;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
/* Print the new value */
|
||||
json_vprintf(out, json_fmt, ap);
|
||||
|
||||
/* Close brackets/braces of the added missing keys */
|
||||
for (; off > data.matched; off--) {
|
||||
int ch = json_path[off];
|
||||
const char *p = ch == '.' ? "}" : ch == '[' ? "]" : "";
|
||||
json_printf(out, "%s", p);
|
||||
}
|
||||
|
||||
/* Print the rest of the unchanged string */
|
||||
json_printf(out, "%.*s", len - data.end, s + data.end);
|
||||
}
|
||||
return data.end > data.pos ? 1 : 0;
|
||||
}
|
||||
|
||||
int json_setf(const char *s, int len, struct json_out *out,
|
||||
const char *json_path, const char *json_fmt, ...) WEAK;
|
||||
int json_setf(const char *s, int len, struct json_out *out,
|
||||
const char *json_path, const char *json_fmt, ...) {
|
||||
int result;
|
||||
va_list ap;
|
||||
va_start(ap, json_fmt);
|
||||
result = json_vsetf(s, len, out, json_path, json_fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct prettify_data {
|
||||
struct json_out *out;
|
||||
int level;
|
||||
int last_token;
|
||||
};
|
||||
|
||||
static void indent(struct json_out *out, int level) {
|
||||
while (level-- > 0) out->printer(out, " ", 2);
|
||||
}
|
||||
|
||||
static void print_key(struct prettify_data *pd, const char *path,
|
||||
const char *name, int name_len) {
|
||||
if (pd->last_token != JSON_TYPE_INVALID &&
|
||||
pd->last_token != JSON_TYPE_ARRAY_START &&
|
||||
pd->last_token != JSON_TYPE_OBJECT_START) {
|
||||
pd->out->printer(pd->out, ",", 1);
|
||||
}
|
||||
if (path[0] != '\0') pd->out->printer(pd->out, "\n", 1);
|
||||
indent(pd->out, pd->level);
|
||||
if (path[0] != '\0' && path[strlen(path) - 1] != ']') {
|
||||
pd->out->printer(pd->out, "\"", 1);
|
||||
pd->out->printer(pd->out, name, (int) name_len);
|
||||
pd->out->printer(pd->out, "\"", 1);
|
||||
pd->out->printer(pd->out, ": ", 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void prettify_cb(void *userdata, const char *name, size_t name_len,
|
||||
const char *path, const struct json_token *t) {
|
||||
struct prettify_data *pd = (struct prettify_data *) userdata;
|
||||
switch (t->type) {
|
||||
case JSON_TYPE_OBJECT_START:
|
||||
case JSON_TYPE_ARRAY_START:
|
||||
print_key(pd, path, name, name_len);
|
||||
pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_START ? "[" : "{",
|
||||
1);
|
||||
pd->level++;
|
||||
break;
|
||||
case JSON_TYPE_OBJECT_END:
|
||||
case JSON_TYPE_ARRAY_END:
|
||||
pd->level--;
|
||||
if (pd->last_token != JSON_TYPE_INVALID &&
|
||||
pd->last_token != JSON_TYPE_ARRAY_START &&
|
||||
pd->last_token != JSON_TYPE_OBJECT_START) {
|
||||
pd->out->printer(pd->out, "\n", 1);
|
||||
indent(pd->out, pd->level);
|
||||
}
|
||||
pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_END ? "]" : "}", 1);
|
||||
break;
|
||||
case JSON_TYPE_NUMBER:
|
||||
case JSON_TYPE_NULL:
|
||||
case JSON_TYPE_TRUE:
|
||||
case JSON_TYPE_FALSE:
|
||||
case JSON_TYPE_STRING:
|
||||
print_key(pd, path, name, name_len);
|
||||
if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1);
|
||||
pd->out->printer(pd->out, t->ptr, t->len);
|
||||
if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pd->last_token = t->type;
|
||||
}
|
||||
|
||||
int json_prettify(const char *s, int len, struct json_out *out) WEAK;
|
||||
int json_prettify(const char *s, int len, struct json_out *out) {
|
||||
struct prettify_data pd = {out, 0, JSON_TYPE_INVALID};
|
||||
return json_walk(s, len, prettify_cb, &pd);
|
||||
}
|
||||
|
||||
int json_prettify_file(const char *file_name) WEAK;
|
||||
int json_prettify_file(const char *file_name) {
|
||||
int res = -1;
|
||||
char *s = json_fread(file_name);
|
||||
FILE *fp;
|
||||
if (s != NULL && (fp = fopen(file_name, "wb")) != NULL) {
|
||||
struct json_out out = JSON_OUT_FILE(fp);
|
||||
res = json_prettify(s, strlen(s), &out);
|
||||
if (res < 0) {
|
||||
/* On error, restore the old content */
|
||||
fclose(fp);
|
||||
fp = fopen(file_name, "wb");
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fwrite(s, 1, strlen(s), fp);
|
||||
} else {
|
||||
fputc('\n', fp);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
free(s);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct next_data {
|
||||
void *handle; // Passed handle. Changed if a next entry is found
|
||||
const char *path; // Path to the iterated object/array
|
||||
int path_len; // Path length - optimisation
|
||||
int found; // Non-0 if found the next entry
|
||||
struct json_token *key; // Object's key
|
||||
struct json_token *val; // Object's value
|
||||
int *idx; // Array index
|
||||
};
|
||||
|
||||
static void next_set_key(struct next_data *d, const char *name, int name_len,
|
||||
int is_array) {
|
||||
if (is_array) {
|
||||
/* Array. Set index and reset key */
|
||||
if (d->key != NULL) {
|
||||
d->key->len = 0;
|
||||
d->key->ptr = NULL;
|
||||
}
|
||||
if (d->idx != NULL) *d->idx = atoi(name);
|
||||
} else {
|
||||
/* Object. Set key and make index -1 */
|
||||
if (d->key != NULL) {
|
||||
d->key->ptr = name;
|
||||
d->key->len = name_len;
|
||||
}
|
||||
if (d->idx != NULL) *d->idx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void next_cb(void *userdata, const char *name, size_t name_len,
|
||||
const char *path, const struct json_token *t) {
|
||||
struct next_data *d = (struct next_data *) userdata;
|
||||
const char *p = path + d->path_len;
|
||||
if (d->found) return;
|
||||
if (d->path_len >= (int) strlen(path)) return;
|
||||
if (strncmp(d->path, path, d->path_len) != 0) return;
|
||||
if (strchr(p + 1, '.') != NULL) return; /* More nested objects - skip */
|
||||
if (strchr(p + 1, '[') != NULL) return; /* Ditto for arrays */
|
||||
// {OBJECT,ARRAY}_END types do not pass name, _START does. Save key.
|
||||
if (t->type == JSON_TYPE_OBJECT_START || t->type == JSON_TYPE_ARRAY_START) {
|
||||
// printf("SAV %s %d %p\n", path, t->type, t->ptr);
|
||||
next_set_key(d, name, name_len, p[0] == '[');
|
||||
} else if (d->handle == NULL || d->handle < (void *) t->ptr) {
|
||||
// printf("END %s %d %p\n", path, t->type, t->ptr);
|
||||
if (t->type != JSON_TYPE_OBJECT_END && t->type != JSON_TYPE_ARRAY_END) {
|
||||
next_set_key(d, name, name_len, p[0] == '[');
|
||||
}
|
||||
if (d->val != NULL) *d->val = *t;
|
||||
d->handle = (void *) t->ptr;
|
||||
d->found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void *json_next(const char *s, int len, void *handle, const char *path,
|
||||
struct json_token *key, struct json_token *val, int *i) {
|
||||
struct json_token tmpval, *v = val == NULL ? &tmpval : val;
|
||||
struct json_token tmpkey, *k = key == NULL ? &tmpkey : key;
|
||||
int tmpidx, *pidx = i == NULL ? &tmpidx : i;
|
||||
struct next_data data = {handle, path, strlen(path), 0, k, v, pidx};
|
||||
json_walk(s, len, next_cb, &data);
|
||||
return data.found ? data.handle : NULL;
|
||||
}
|
||||
|
||||
void *json_next_key(const char *s, int len, void *handle, const char *path,
|
||||
struct json_token *key, struct json_token *val) WEAK;
|
||||
void *json_next_key(const char *s, int len, void *handle, const char *path,
|
||||
struct json_token *key, struct json_token *val) {
|
||||
return json_next(s, len, handle, path, key, val, NULL);
|
||||
}
|
||||
|
||||
void *json_next_elem(const char *s, int len, void *handle, const char *path,
|
||||
int *idx, struct json_token *val) WEAK;
|
||||
void *json_next_elem(const char *s, int len, void *handle, const char *path,
|
||||
int *idx, struct json_token *val) {
|
||||
return json_next(s, len, handle, path, NULL, val, idx);
|
||||
}
|
||||
|
||||
static int json_sprinter(struct json_out *out, const char *str, size_t len) {
|
||||
size_t old_len = out->u.buf.buf == NULL ? 0 : strlen(out->u.buf.buf);
|
||||
size_t new_len = len + old_len;
|
||||
char *p = (char *) realloc(out->u.buf.buf, new_len + 1);
|
||||
if (p != NULL) {
|
||||
memcpy(p + old_len, str, len);
|
||||
p[new_len] = '\0';
|
||||
out->u.buf.buf = p;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
char *json_vasprintf(const char *fmt, va_list ap) WEAK;
|
||||
char *json_vasprintf(const char *fmt, va_list ap) {
|
||||
struct json_out out;
|
||||
memset(&out, 0, sizeof(out));
|
||||
out.printer = json_sprinter;
|
||||
json_vprintf(&out, fmt, ap);
|
||||
return out.u.buf.buf;
|
||||
}
|
||||
|
||||
char *json_asprintf(const char *fmt, ...) WEAK;
|
||||
char *json_asprintf(const char *fmt, ...) {
|
||||
char *result = NULL;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
result = json_vasprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
@ -1,20 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
|
||||
* Copyright (c) 2013 Cesanta Software Limited
|
||||
* Copyright (c) 2018 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/>.
|
||||
* Licensed under the Apache License, Version 2.0 (the ""License"");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Alternatively, you can license this library under a commercial
|
||||
* license, as set out in <http://cesanta.com/products.html>.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an ""AS IS"" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CS_FROZEN_FROZEN_H_
|
||||
@ -28,6 +27,13 @@ extern "C" {
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_WIN32) && _MSC_VER < 1700
|
||||
typedef int bool;
|
||||
enum { false = 0, true = 1 };
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
/* JSON token type */
|
||||
enum json_token_type {
|
||||
JSON_TYPE_INVALID = 0, /* memsetting to 0 should create INVALID value */
|
||||
@ -94,6 +100,7 @@ typedef void (*json_walk_callback_t)(void *callback_data, const char *name,
|
||||
/*
|
||||
* Parse `json_string`, invoking `callback` in a way similar to SAX parsers;
|
||||
* see `json_walk_callback_t`.
|
||||
* Return number of processed bytes, or a negative error code.
|
||||
*/
|
||||
int json_walk(const char *json_string, int json_string_length,
|
||||
json_walk_callback_t callback, void *callback_data);
|
||||
@ -127,7 +134,7 @@ extern int json_printer_file(struct json_out *, const char *, size_t);
|
||||
#define JSON_OUT_FILE(fp) \
|
||||
{ \
|
||||
json_printer_file, { \
|
||||
{ (void *) fp, 0, 0 } \
|
||||
{ (char *) fp, 0, 0 } \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -144,13 +151,34 @@ typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap);
|
||||
* - `%M` invokes a json_printf_callback_t function. That callback function
|
||||
* can consume more parameters.
|
||||
*
|
||||
* Return number of bytes printed. If the return value is bigger then the
|
||||
* Return number of bytes printed. If the return value is bigger than the
|
||||
* supplied buffer, that is an indicator of overflow. In the overflow case,
|
||||
* overflown bytes are not printed.
|
||||
*/
|
||||
int json_printf(struct json_out *, const char *fmt, ...);
|
||||
int json_vprintf(struct json_out *, const char *fmt, va_list ap);
|
||||
|
||||
/*
|
||||
* Same as json_printf, but prints to a file.
|
||||
* File is created if does not exist. File is truncated if already exists.
|
||||
*/
|
||||
int json_fprintf(const char *file_name, const char *fmt, ...);
|
||||
int json_vfprintf(const char *file_name, const char *fmt, va_list ap);
|
||||
|
||||
/*
|
||||
* Print JSON into an allocated 0-terminated string.
|
||||
* Return allocated string, or NULL on error.
|
||||
* Example:
|
||||
*
|
||||
* ```c
|
||||
* char *str = json_asprintf("{a:%H}", 3, "abc");
|
||||
* printf("%s\n", str); // Prints "616263"
|
||||
* free(str);
|
||||
* ```
|
||||
*/
|
||||
char *json_asprintf(const char *fmt, ...);
|
||||
char *json_vasprintf(const char *fmt, va_list ap);
|
||||
|
||||
/*
|
||||
* Helper %M callback that prints contiguous C arrays.
|
||||
* Consumes void *array_ptr, size_t array_size, size_t elem_size, char *fmt
|
||||
@ -165,7 +193,8 @@ int json_printf_array(struct json_out *, va_list *ap);
|
||||
* 1. Object keys in the format string may be not quoted, e.g. "{key: %d}"
|
||||
* 2. Order of keys in an object is irrelevant.
|
||||
* 3. Several extra format specifiers are supported:
|
||||
* - %B: consumes `int *`, expects boolean `true` or `false`.
|
||||
* - %B: consumes `int *` (or `char *`, if `sizeof(bool) == sizeof(char)`),
|
||||
* expects boolean `true` or `false`.
|
||||
* - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned
|
||||
* string is malloc-ed, caller must free() the string.
|
||||
* - %V: consumes `char **`, `int *`. Expects base64-encoded string.
|
||||
@ -193,7 +222,7 @@ typedef void (*json_scanner_t)(const char *str, int len, void *user_data);
|
||||
/*
|
||||
* Helper function to scan array item with given path and index.
|
||||
* Fills `token` with the matched JSON token.
|
||||
* Return 0 if no array element found, otherwise non-0.
|
||||
* Return -1 if no array element found, otherwise non-negative token length.
|
||||
*/
|
||||
int json_scanf_array_elem(const char *s, int len, const char *path, int index,
|
||||
struct json_token *token);
|
||||
@ -207,6 +236,76 @@ int json_scanf_array_elem(const char *s, int len, const char *path, int index,
|
||||
*/
|
||||
int json_unescape(const char *src, int slen, char *dst, int dlen);
|
||||
|
||||
/*
|
||||
* Escape a string `str`, `str_len` into the printer `out`.
|
||||
* Return the number of bytes printed.
|
||||
*/
|
||||
int json_escape(struct json_out *out, const char *str, size_t str_len);
|
||||
|
||||
/*
|
||||
* Read the whole file in memory.
|
||||
* Return malloc-ed file content, or NULL on error. The caller must free().
|
||||
*/
|
||||
char *json_fread(const char *file_name);
|
||||
|
||||
/*
|
||||
* Update given JSON string `s,len` by changing the value at given `json_path`.
|
||||
* The result is saved to `out`. If `json_fmt` == NULL, that deletes the key.
|
||||
* If path is not present, missing keys are added. Array path without an
|
||||
* index pushes a value to the end of an array.
|
||||
* Return 1 if the string was changed, 0 otherwise.
|
||||
*
|
||||
* Example: s is a JSON string { "a": 1, "b": [ 2 ] }
|
||||
* json_setf(s, len, out, ".a", "7"); // { "a": 7, "b": [ 2 ] }
|
||||
* json_setf(s, len, out, ".b", "7"); // { "a": 1, "b": 7 }
|
||||
* json_setf(s, len, out, ".b[]", "7"); // { "a": 1, "b": [ 2,7 ] }
|
||||
* json_setf(s, len, out, ".b", NULL); // { "a": 1 }
|
||||
*/
|
||||
int json_setf(const char *s, int len, struct json_out *out,
|
||||
const char *json_path, const char *json_fmt, ...);
|
||||
|
||||
int json_vsetf(const char *s, int len, struct json_out *out,
|
||||
const char *json_path, const char *json_fmt, va_list ap);
|
||||
|
||||
/*
|
||||
* Pretty-print JSON string `s,len` into `out`.
|
||||
* Return number of processed bytes in `s`.
|
||||
*/
|
||||
int json_prettify(const char *s, int len, struct json_out *out);
|
||||
|
||||
/*
|
||||
* Prettify JSON file `file_name`.
|
||||
* Return number of processed bytes, or negative number of error.
|
||||
* On error, file content is not modified.
|
||||
*/
|
||||
int json_prettify_file(const char *file_name);
|
||||
|
||||
/*
|
||||
* Iterate over an object at given JSON `path`.
|
||||
* On each iteration, fill the `key` and `val` tokens. It is OK to pass NULL
|
||||
* for `key`, or `val`, in which case they won't be populated.
|
||||
* Return an opaque value suitable for the next iteration, or NULL when done.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```c
|
||||
* void *h = NULL;
|
||||
* struct json_token key, val;
|
||||
* while ((h = json_next_key(s, len, h, ".foo", &key, &val)) != NULL) {
|
||||
* printf("[%.*s] -> [%.*s]\n", key.len, key.ptr, val.len, val.ptr);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
void *json_next_key(const char *s, int len, void *handle, const char *path,
|
||||
struct json_token *key, struct json_token *val);
|
||||
|
||||
/*
|
||||
* Iterate over an array at given JSON `path`.
|
||||
* Similar to `json_next_key`, but fills array index `idx` instead of `key`.
|
||||
*/
|
||||
void *json_next_elem(const char *s, int len, void *handle, const char *path,
|
||||
int *idx, struct json_token *val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
@ -59,8 +59,8 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
|
||||
int je, int_buf;
|
||||
float float_buf;
|
||||
char *p_charbuf1, *p_charbuf2;
|
||||
FILE *fp;
|
||||
|
||||
struct mympd_state { int a; int b; } state = { .a = 0, .b = 0 };
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout,"Got request: %s\n",msg.p);
|
||||
#endif
|
||||
@ -72,24 +72,10 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
|
||||
return;
|
||||
|
||||
switch(cmd_id) {
|
||||
case MPD_API_SET_MYMPD_SETTINGS:
|
||||
fp = fopen(mpd.statefile,"w");
|
||||
if(fp != NULL) {
|
||||
fprintf(fp,"%.*s",msg.len,msg.p);
|
||||
fclose(fp);
|
||||
} else {
|
||||
fprintf(stderr,"Cant write state file\n");
|
||||
}
|
||||
break;
|
||||
case MPD_API_GET_MYMPD_SETTINGS:
|
||||
fp = fopen(mpd.statefile,"r");
|
||||
if(fp != NULL) {
|
||||
fgets(mpd.buf, MAX_SIZE, fp);
|
||||
fclose(fp);
|
||||
n=strlen(mpd.buf);
|
||||
}
|
||||
break;
|
||||
case MPD_API_SET_MPD_SETTINGS:
|
||||
case MPD_API_SET_SETTINGS:
|
||||
json_scanf(msg.p, msg.len, "{ data: { notificationWeb: %d, notificationPage: %d} }", &state.a, &state.b);
|
||||
json_fprintf(mpd.statefile, "{ notificationWeb: %d, notificationPage: %d}", state.a, state.b);
|
||||
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { random:%u } }", &uint_buf1);
|
||||
if (je == 1)
|
||||
mpd_run_random(mpd.conn, uint_buf1);
|
||||
@ -305,7 +291,7 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
|
||||
mpd_run_rm(mpd.conn, p_charbuf1);
|
||||
free(p_charbuf1);
|
||||
break;
|
||||
case MPD_API_GET_MPD_SETTINGS:
|
||||
case MPD_API_GET_SETTINGS:
|
||||
n = mympd_put_settings(mpd.buf);
|
||||
break;
|
||||
case MPD_API_GET_STATS:
|
||||
@ -630,6 +616,14 @@ int mympd_put_settings(char *buffer)
|
||||
char *replaygain;
|
||||
int len;
|
||||
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
|
||||
struct mympd_state { int a; int b; } state = { .a = 0, .b = 0 };
|
||||
if( access( mpd.statefile, F_OK ) != -1 ) {
|
||||
char *content = json_fread(mpd.statefile);
|
||||
json_scanf(content, strlen(content), "{notificationWeb: %d, notificationPage: %d}", &state.a, &state.b);
|
||||
} else {
|
||||
state.a=0;
|
||||
state.b=0;
|
||||
}
|
||||
|
||||
status = mpd_run_status(mpd.conn);
|
||||
if (!status) {
|
||||
@ -644,12 +638,13 @@ int mympd_put_settings(char *buffer)
|
||||
replaygain=strdup(pair->value);
|
||||
mpd_return_pair(mpd.conn, pair);
|
||||
}
|
||||
|
||||
|
||||
len = json_printf(&out,
|
||||
"{type:settings, data:{"
|
||||
"repeat:%d, single:%d, crossfade:%d, consume:%d, random:%d, "
|
||||
"mixrampdb: %f, mixrampdelay: %f, mpdhost : %Q, mpdport: %d, passwort_set: %B, "
|
||||
"streamport: %d, coverimage: %Q, max_elements_per_page: %d, replaygain: %Q"
|
||||
"streamport: %d, coverimage: %Q, max_elements_per_page: %d, replaygain: %Q,"
|
||||
"notificationWeb: %d, notificationPage: %d"
|
||||
"}}",
|
||||
mpd_status_get_repeat(status),
|
||||
mpd_status_get_single(status),
|
||||
@ -662,7 +657,9 @@ int mympd_put_settings(char *buffer)
|
||||
mpd.password ? "true" : "false",
|
||||
streamport, coverimage,
|
||||
MAX_ELEMENTS_PER_PAGE,
|
||||
replaygain
|
||||
replaygain,
|
||||
state.a,
|
||||
state.b
|
||||
);
|
||||
mpd_status_free(status);
|
||||
|
||||
|
@ -78,10 +78,8 @@
|
||||
X(MPD_API_GET_ARTISTS) \
|
||||
X(MPD_API_GET_CURRENT_SONG) \
|
||||
X(MPD_API_WELCOME) \
|
||||
X(MPD_API_GET_MPD_SETTINGS) \
|
||||
X(MPD_API_SET_MPD_SETTINGS) \
|
||||
X(MPD_API_SET_MYMPD_SETTINGS) \
|
||||
X(MPD_API_GET_MYMPD_SETTINGS)
|
||||
X(MPD_API_GET_SETTINGS) \
|
||||
X(MPD_API_SET_SETTINGS)
|
||||
|
||||
enum mpd_cmd_ids {
|
||||
MPD_CMDS(GEN_ENUM)
|
||||
|
Loading…
x
Reference in New Issue
Block a user