mirror of
https://github.com/SuperBFG7/ympd
synced 2025-01-11 09:50:36 +00:00
Replaces jquery.cookie.js with version from https://github.com/js-cookie/js-cookie
Added streamport option to commandline Fixed description of options in manpage and help and README Removed mpd host options from settings menu Removed http stream options from settings menu
This commit is contained in:
parent
361882d5af
commit
f55fa51934
@ -11,7 +11,6 @@ else()
|
||||
set(ASSETS_PATH "${PROJECT_SOURCE_DIR}/htdocs")
|
||||
endif()
|
||||
|
||||
option(WITH_MPD_HOST_CHANGE "Let users of the web frontend change the MPD Host" ON)
|
||||
option(WITH_IPV6 "enable IPv6 support" ON)
|
||||
option(WITH_SSL "enable SSL support" ON)
|
||||
|
||||
@ -46,7 +45,7 @@ file(GLOB RESOURCES
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
src/ympd.c
|
||||
src/mympd.c
|
||||
src/mpd_client.c
|
||||
src/mongoose.c
|
||||
src/json_encode.c
|
||||
|
11
README.md
11
README.md
@ -14,6 +14,8 @@ UI Components
|
||||
- Bootstrap Slider: https://github.com/seiyria/bootstrap-slider
|
||||
- Material Design Icons: https://material.io/tools/icons/?style=baseline
|
||||
- Sammy.js: http://sammyjs.org/
|
||||
- jQuery: https://jquery.com/
|
||||
- js-cookie: https://github.com/js-cookie/js-cookie
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
@ -34,14 +36,17 @@ Unix Build Instructions
|
||||
Run flags
|
||||
---------
|
||||
```
|
||||
Usage: ./ympd [OPTION]...
|
||||
Usage: ./mympd [OPTION]...
|
||||
|
||||
-D, --digest <htdigest> path to htdigest file for authorization
|
||||
(realm ympd) [no authorization]
|
||||
(realm mympd) [no authorization]
|
||||
-h, --host <host> connect to mpd at host [localhost]
|
||||
-p, --port <port> connect to mpd at port [6600]
|
||||
-l, --localport <port> skip authorization for local port
|
||||
-w, --webport [ip:]<port> listen interface/port for webserver [8080]
|
||||
-s, --streamport <port> connect to mpd http stream at port [8000]
|
||||
-u, --user <username> drop priviliges to user after socket bind
|
||||
-m, --mpdpass <password> specifies the password to use when connecting to mpd
|
||||
-V, --version get version
|
||||
--help this help
|
||||
```
|
||||
@ -57,7 +62,7 @@ To run ympd with SSL support:
|
||||
```
|
||||
- tell ympd to use a webport using SSL and where to find the certificate:
|
||||
```
|
||||
# ./ympd -w "ssl://8081:/path/to/ssl.pem"
|
||||
# ./mympd -w "ssl://8081:/path/to/ssl.pem"
|
||||
```
|
||||
|
||||
Copyright
|
||||
|
@ -30,7 +30,7 @@
|
||||
</form>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a id="nav-addstream" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#addstream">Add Stream</a>
|
||||
<a id="nav-settings" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#settings" onclick="getHost();">Settings</a>
|
||||
<a id="nav-settings" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#settings">Settings</a>
|
||||
<a id="nav-updatedb" class="dropdown-item text-light bg-dark" href="#" onclick="updateDB();">Update Database</a>
|
||||
<a id="nav-localplayer" class="dropdown-item text-light bg-dark" href="#" data-toggle="dropdown" onclick="window.open('/player.html','LocalPlayer');">Local Player</a>
|
||||
</div>
|
||||
@ -283,47 +283,6 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<form role="form">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-9">
|
||||
<label class="control-label" for="mpdhost">MPD Host/IP</label>
|
||||
<input type="text" class="form-control" id="mpdhost" />
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<label class="control-label" for="mpdport">MPD Port</label>
|
||||
<input type="text" class="form-control" id="mpdport" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label class="control-label" for="mpd_pw">MPD Password</label>
|
||||
<input type="password" class="form-control" id="mpd_pw" placeholder="Password"/>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label class="control-label" for="mpd_pw_con">MPD Password (Confirmation)</label>
|
||||
<input type="password" class="form-control" id="mpd_pw_con" placeholder="Confirmation"
|
||||
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">
|
||||
<button type="button" class="close" aria-hidden="true">×</button>
|
||||
MPD Password is set
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-12">
|
||||
<label class="control-label" for="mpdstream">MPD Stream URL</label>
|
||||
<input type="text" class="form-control" id="mpdstream" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" onclick="confirmSettings();">Save</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
@ -385,7 +344,7 @@
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<script src="js/jquery-3.3.1.min.js"></script>
|
||||
<script src="js/jquery.cookie.js"></script>
|
||||
<script src="js/js.cookie.js"></script>
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<script src="js/bootstrap-slider.min.js"></script>
|
||||
<script src="js/bootstrap-notify.min.js"></script>
|
||||
|
5
htdocs/js/jquery-ui-sortable.min.js
vendored
5
htdocs/js/jquery-ui-sortable.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,114 +0,0 @@
|
||||
/*!
|
||||
* jQuery Cookie Plugin v1.4.0
|
||||
* https://github.com/carhartl/jquery-cookie
|
||||
*
|
||||
* Copyright 2013 Klaus Hartl
|
||||
* Released under the MIT license
|
||||
*/
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else {
|
||||
// Browser globals.
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
|
||||
var pluses = /\+/g;
|
||||
|
||||
function encode(s) {
|
||||
return config.raw ? s : encodeURIComponent(s);
|
||||
}
|
||||
|
||||
function decode(s) {
|
||||
return config.raw ? s : decodeURIComponent(s);
|
||||
}
|
||||
|
||||
function stringifyCookieValue(value) {
|
||||
return encode(config.json ? JSON.stringify(value) : String(value));
|
||||
}
|
||||
|
||||
function parseCookieValue(s) {
|
||||
if (s.indexOf('"') === 0) {
|
||||
// This is a quoted cookie as according to RFC2068, unescape...
|
||||
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
}
|
||||
|
||||
try {
|
||||
// Replace server-side written pluses with spaces.
|
||||
// If we can't decode the cookie, ignore it, it's unusable.
|
||||
// If we can't parse the cookie, ignore it, it's unusable.
|
||||
s = decodeURIComponent(s.replace(pluses, ' '));
|
||||
return config.json ? JSON.parse(s) : s;
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function read(s, converter) {
|
||||
var value = config.raw ? s : parseCookieValue(s);
|
||||
return $.isFunction(converter) ? converter(value) : value;
|
||||
}
|
||||
|
||||
var config = $.cookie = function (key, value, options) {
|
||||
|
||||
// Write
|
||||
|
||||
if (value !== undefined && !$.isFunction(value)) {
|
||||
options = $.extend({}, config.defaults, options);
|
||||
|
||||
if (typeof options.expires === 'number') {
|
||||
var days = options.expires, t = options.expires = new Date();
|
||||
t.setTime(+t + days * 864e+5);
|
||||
}
|
||||
|
||||
return (document.cookie = [
|
||||
encode(key), '=', stringifyCookieValue(value),
|
||||
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
||||
options.path ? '; path=' + options.path : '',
|
||||
options.domain ? '; domain=' + options.domain : '',
|
||||
options.secure ? '; secure' : ''
|
||||
].join(''));
|
||||
}
|
||||
|
||||
// Read
|
||||
|
||||
var result = key ? undefined : {};
|
||||
|
||||
// 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 $.cookie().
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
|
||||
for (var i = 0, l = cookies.length; i < l; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var name = decode(parts.shift());
|
||||
var cookie = parts.join('=');
|
||||
|
||||
if (key && key === name) {
|
||||
// If second argument (value) is a function it's a converter...
|
||||
result = read(cookie, value);
|
||||
break;
|
||||
}
|
||||
|
||||
// Prevent storing a cookie that we couldn't decode.
|
||||
if (!key && (cookie = read(cookie)) !== undefined) {
|
||||
result[name] = cookie;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
config.defaults = {};
|
||||
|
||||
$.removeCookie = function (key, options) {
|
||||
if ($.cookie(key) === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Must not alter options, thus extending a fresh object...
|
||||
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
|
||||
return !$.cookie(key);
|
||||
};
|
||||
|
||||
}));
|
165
htdocs/js/js.cookie.js
Normal file
165
htdocs/js/js.cookie.js
Normal file
@ -0,0 +1,165 @@
|
||||
/*!
|
||||
* 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 () {});
|
||||
}));
|
@ -162,10 +162,10 @@ $(document).ready(function(){
|
||||
if(!notificationsSupported())
|
||||
$('#btnnotifyWeb').addClass("disabled");
|
||||
else
|
||||
if ($.cookie("notificationWeb") === "true")
|
||||
if (Cookies.get('notificationWeb') === 'true')
|
||||
$('#btnnotifyWeb').removeClass('btn-secondary').addClass("btn-success")
|
||||
|
||||
if ($.cookie("notificationPage") === "true")
|
||||
if (Cookies.get('notificationPage') === 'true')
|
||||
$('#btnnotifyPage').removeClass('btn-secondary').addClass("btn-success")
|
||||
|
||||
add_filter();
|
||||
@ -186,6 +186,8 @@ function webSocketConnect() {
|
||||
app.run();
|
||||
/* emit initial request for output names */
|
||||
socket.send('MPD_API_GET_OUTPUTS');
|
||||
/* emit request for mympd options */
|
||||
socket.send('MPD_API_GET_OPTIONS');
|
||||
}
|
||||
|
||||
socket.onmessage = function got_packet(msg) {
|
||||
@ -517,15 +519,11 @@ function webSocketConnect() {
|
||||
socket.send('MPD_API_GET_QUEUE,'+pagination);
|
||||
}
|
||||
break;
|
||||
case "song_change":
|
||||
case "song_change":
|
||||
songChange(obj.data.title, obj.data.artist, obj.data.album, obj.data.uri);
|
||||
break;
|
||||
case 'mpdhost':
|
||||
$('#mpdhost').val(obj.data.host);
|
||||
setLocalStream(obj.data.host);
|
||||
$('#mpdport').val(obj.data.port);
|
||||
if(obj.data.passwort_set)
|
||||
$('#mpd_password_set').removeClass('hide');
|
||||
case 'mpdoptions':
|
||||
setLocalStream(obj.data.mpdhost,obj.data.streamport);
|
||||
break;
|
||||
case 'error':
|
||||
showNotification(obj.data,'','','danger');
|
||||
@ -614,22 +612,14 @@ function clickPlay() {
|
||||
socket.send('MPD_API_SET_PAUSE');
|
||||
}
|
||||
|
||||
function setLocalStream(mpdhost) {
|
||||
var mpdstream = $.cookie("mpdstream");
|
||||
|
||||
if ( !mpdstream ) {
|
||||
mpdstream = "http://";
|
||||
if ( mpdhost == "127.0.0.1" || mpdhost == "localhost")
|
||||
mpdstream += window.location.hostname;
|
||||
else
|
||||
mpdstream += mpdhost;
|
||||
mpdstream += ":8000/";
|
||||
|
||||
$.cookie("mpdstream", mpdstream, { expires: 424242 });
|
||||
}
|
||||
|
||||
$("#mpdstream").val(mpdstream);
|
||||
$("#mpdstream").change();
|
||||
function setLocalStream(mpdhost,streamport) {
|
||||
var mpdstream = 'http://';
|
||||
if ( mpdhost == '127.0.0.1' || mpdhost == 'localhost')
|
||||
mpdstream += window.location.hostname;
|
||||
else
|
||||
mpdstream += mpdhost;
|
||||
mpdstream += ':'+streamport+'/';
|
||||
Cookies.set('mpdstream', mpdstream, { expires: 424242 });
|
||||
}
|
||||
|
||||
function trash(tr) {
|
||||
@ -677,8 +667,8 @@ $('#trashmode').children("button").on('click', function(e) {
|
||||
});
|
||||
|
||||
$('#btnnotifyWeb').on('click', function (e) {
|
||||
if($.cookie('notificationWeb') === 'true') {
|
||||
$.cookie('notificationWeb', false);
|
||||
if(Cookies.get('notificationWeb') === 'true') {
|
||||
Cookies.set('notificationWeb', false, { expires: 424242 });
|
||||
$('#btnnotify').removeClass('btn-success').addClass('btn-secondary');
|
||||
} else {
|
||||
Notification.requestPermission(function (permission) {
|
||||
@ -687,7 +677,7 @@ $('#btnnotifyWeb').on('click', function (e) {
|
||||
}
|
||||
|
||||
if (permission === 'granted') {
|
||||
$.cookie('notificationWeb', true, { expires: 424242 });
|
||||
Cookies.set('notificationWeb', true, { expires: 424242 });
|
||||
$('#btnnotifyWeb').removeClass('btn-secondary').addClass('btn-success');
|
||||
}
|
||||
});
|
||||
@ -695,31 +685,15 @@ $('#btnnotifyWeb').on('click', function (e) {
|
||||
});
|
||||
|
||||
$('#btnnotifyPage').on('click', function (e) {
|
||||
if($.cookie("notificationPage") === 'true') {
|
||||
$.cookie("notificationPage", false);
|
||||
if(Cookies.get("notificationPage") === 'true') {
|
||||
Cookies.set("notificationPage", false, { expires: 424242 });
|
||||
$('#btnnotifyPage').removeClass('btn-success').addClass('btn-secondary');
|
||||
} else {
|
||||
$.cookie('notificationPage', true, { expires: 424242 });
|
||||
Cookies.set('notificationPage', true, { expires: 424242 });
|
||||
$('#btnnotifyPage').removeClass('btn-secondary').addClass('btn-success');
|
||||
}
|
||||
});
|
||||
|
||||
function getHost() {
|
||||
socket.send('MPD_API_GET_MPDHOST');
|
||||
|
||||
function onEnter(event) {
|
||||
if ( event.which == 13 ) {
|
||||
confirmSettings();
|
||||
}
|
||||
}
|
||||
|
||||
$('#mpdhost').keypress(onEnter);
|
||||
$('#mpdport').keypress(onEnter);
|
||||
$('#mpdstream').keypress(onEnter);
|
||||
$('#mpd_pw').keypress(onEnter);
|
||||
$('#mpd_pw_con').keypress(onEnter);
|
||||
}
|
||||
|
||||
$('#search > input').keypress(function (event) {
|
||||
if ( event.which == 13 ) {
|
||||
$('#mainMenu > a').dropdown('toggle');
|
||||
@ -770,38 +744,14 @@ function saveQueue() {
|
||||
$('#savequeue').modal('hide');
|
||||
}
|
||||
|
||||
function confirmSettings() {
|
||||
if($('#mpd_pw').val().length + $('#mpd_pw_con').val().length > 0) {
|
||||
if ($('#mpd_pw').val() !== $('#mpd_pw_con').val())
|
||||
{
|
||||
$('#mpd_pw_con').popover('show');
|
||||
setTimeout(function() {
|
||||
$('#mpd_pw_con').popover('hide');
|
||||
}, 2000);
|
||||
return;
|
||||
} else
|
||||
socket.send('MPD_API_SET_MPDPASS,'+$('#mpd_pw').val());
|
||||
}
|
||||
socket.send('MPD_API_SET_MPDHOST,'+$('#mpdport').val()+','+$('#mpdhost').val());
|
||||
$.cookie("mpdstream", $("#mpdstream").val(), { expires: 424242 });
|
||||
$('#settings').modal('hide');
|
||||
}
|
||||
|
||||
$('#mpd_password_set > button').on('click', function (e) {
|
||||
socket.send('MPD_API_SET_MPDPASS,');
|
||||
$('#mpd_pw').val("");
|
||||
$('#mpd_pw_con').val("");
|
||||
$('#mpd_password_set').addClass('hide');
|
||||
})
|
||||
|
||||
function showNotification(notificationTitle,notificationText,notificationHtml,notificationType) {
|
||||
if ($.cookie('notificationWeb') === 'true') {
|
||||
if (Cookies.get('notificationWeb') === 'true') {
|
||||
var notification = new Notification(notificationTitle, {icon: 'assets/favicon.ico', body: notificationText});
|
||||
setTimeout(function(notification) {
|
||||
notification.close();
|
||||
}, 3000, notification);
|
||||
}
|
||||
if ($.cookie('notificationPage') === 'true') {
|
||||
if (Cookies.get('notificationPage') === 'true') {
|
||||
$.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>' +
|
||||
|
@ -31,11 +31,11 @@
|
||||
</main>
|
||||
|
||||
<script src="js/jquery-3.3.1.min.js"></script>
|
||||
<script src="js/jquery.cookie.js"></script>
|
||||
<script src="js/js.cookie.js"></script>
|
||||
<script type="text/javascript">
|
||||
var mpdstream = $.cookie("mpdstream");
|
||||
var mpdstream = Cookies.get('mpdstream');
|
||||
player.src = mpdstream;
|
||||
console.log("playing mpd stream: " + player.src);
|
||||
console.log('playing mpd stream: ' + player.src);
|
||||
player.load();
|
||||
player.play();
|
||||
</script>
|
||||
|
6
mympd.1
6
mympd.1
@ -18,12 +18,18 @@ connect to mpd at host, defaults to localhost
|
||||
\fB\-p\fR, \fB\-\-port PORT\fR
|
||||
connect to mpd at port, defaults to 6600
|
||||
.TP
|
||||
\fB\-D\fR, \fB\-\-digest HTDIGEST\fR
|
||||
path to htdigest file for authorization
|
||||
.TP
|
||||
\fB\-l\fR, \fB\-\-localport PORT\fR
|
||||
skip authorization for local port
|
||||
.TP
|
||||
\fB\-w\fR, \fB\-\-webport PORT\fR
|
||||
specifies the port for the webserver to listen to, defaults to 8080
|
||||
.TP
|
||||
\fB-s\fR, \fB\-\-streamport PORT
|
||||
connect to mpd http stream at port [8000]
|
||||
.TP
|
||||
\fB\-u\fR, \fB\-\-user username\fR
|
||||
drop privileges to the provided username after socket binding
|
||||
.TP
|
||||
|
@ -1,4 +1,10 @@
|
||||
/* ympd
|
||||
/* myMPD
|
||||
(c) 2018 Juergen Mang <mail@jcgames.de>
|
||||
This project's homepage is: https://github.com/jcorporation/ympd
|
||||
|
||||
myMPD ist fork of:
|
||||
|
||||
ympd
|
||||
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
||||
This project's homepage is: http://www.ympd.org
|
||||
|
||||
@ -23,6 +29,4 @@
|
||||
#define YMPD_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR}
|
||||
#define YMPD_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH}
|
||||
#define SRC_PATH "${ASSETS_PATH}"
|
||||
#cmakedefine WITH_MPD_HOST_CHANGE
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,10 @@
|
||||
/* ympd
|
||||
/* myMPD
|
||||
(c) 2018 Juergen Mang <mail@jcgames.de>
|
||||
This project's homepage is: https://github.com/jcorporation/ympd
|
||||
|
||||
myMPD ist fork of:
|
||||
|
||||
ympd
|
||||
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
||||
This project's homepage is: http://www.ympd.org
|
||||
|
||||
|
@ -1,4 +1,10 @@
|
||||
/* ympd
|
||||
/* myMPD
|
||||
(c) 2018 Juergen Mang <mail@jcgames.de>
|
||||
This project's homepage is: https://github.com/jcorporation/ympd
|
||||
|
||||
myMPD ist fork of:
|
||||
|
||||
ympd
|
||||
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
||||
This project's homepage is: http://www.ympd.org
|
||||
|
||||
|
@ -1,4 +1,10 @@
|
||||
/* ympd
|
||||
/* myMPD
|
||||
(c) 2018 Juergen Mang <mail@jcgames.de>
|
||||
This project's homepage is: https://github.com/jcorporation/ympd
|
||||
|
||||
myMPD ist fork of:
|
||||
|
||||
ympd
|
||||
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
||||
This project's homepage is: http://www.ympd.org
|
||||
|
||||
@ -63,9 +69,9 @@ int callback_mpd(struct mg_connection *c)
|
||||
if(cmd_id == -1)
|
||||
return MG_TRUE;
|
||||
|
||||
if(mpd.conn_state != MPD_CONNECTED && cmd_id != MPD_API_SET_MPDHOST &&
|
||||
cmd_id != MPD_API_GET_MPDHOST && cmd_id != MPD_API_SET_MPDPASS)
|
||||
return MG_TRUE;
|
||||
// if(mpd.conn_state != MPD_CONNECTED && cmd_id != MPD_API_SET_MPDHOST &&
|
||||
// cmd_id != MPD_API_GET_MPDHOST && cmd_id != MPD_API_SET_MPDPASS)
|
||||
// return MG_TRUE;
|
||||
|
||||
switch(cmd_id)
|
||||
{
|
||||
@ -263,52 +269,11 @@ out_search:
|
||||
out_send_message:
|
||||
free(p_charbuf);
|
||||
break;
|
||||
#ifdef WITH_MPD_HOST_CHANGE
|
||||
/* Commands allowed when disconnected from MPD server */
|
||||
case MPD_API_SET_MPDHOST:
|
||||
int_buf = 0;
|
||||
p_charbuf = strdup(c->content);
|
||||
if(strcmp(strtok(p_charbuf, ","), "MPD_API_SET_MPDHOST"))
|
||||
goto out_host_change;
|
||||
|
||||
if((int_buf = strtol(strtok(NULL, ","), NULL, 10)) <= 0)
|
||||
goto out_host_change;
|
||||
|
||||
if((token = strtok(NULL, ",")) == NULL)
|
||||
goto out_host_change;
|
||||
|
||||
strncpy(mpd.host, token, sizeof(mpd.host));
|
||||
mpd.port = int_buf;
|
||||
mpd.conn_state = MPD_RECONNECT;
|
||||
free(p_charbuf);
|
||||
return MG_TRUE;
|
||||
out_host_change:
|
||||
free(p_charbuf);
|
||||
case MPD_API_GET_OPTIONS:
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\":\"mpdoptions\", \"data\": "
|
||||
"{\"mpdhost\" : \"%s\", \"mpdport\": \"%d\", \"passwort_set\": %s, \"streamport\": \"%d\"}"
|
||||
"}", mpd.host, mpd.port, mpd.password ? "true" : "false", streamport);
|
||||
break;
|
||||
case MPD_API_GET_MPDHOST:
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\":\"mpdhost\", \"data\": "
|
||||
"{\"host\" : \"%s\", \"port\": \"%d\", \"passwort_set\": %s}"
|
||||
"}", mpd.host, mpd.port, mpd.password ? "true" : "false");
|
||||
break;
|
||||
case MPD_API_SET_MPDPASS:
|
||||
p_charbuf = strdup(c->content);
|
||||
if(strcmp(strtok(p_charbuf, ","), "MPD_API_SET_MPDPASS"))
|
||||
goto out_set_pass;
|
||||
|
||||
if((token = strtok(NULL, ",")) == NULL)
|
||||
goto out_set_pass;
|
||||
|
||||
if(mpd.password)
|
||||
free(mpd.password);
|
||||
|
||||
mpd.password = strdup(token);
|
||||
mpd.conn_state = MPD_RECONNECT;
|
||||
free(p_charbuf);
|
||||
return MG_TRUE;
|
||||
out_set_pass:
|
||||
free(p_charbuf);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(mpd.conn_state == MPD_CONNECTED && mpd_connection_get_error(mpd.conn) != MPD_ERROR_SUCCESS)
|
||||
|
@ -1,4 +1,10 @@
|
||||
/* ympd
|
||||
/* myMPD
|
||||
(c) 2018 Juergen Mang <mail@jcgames.de>
|
||||
This project's homepage is: https://github.com/jcorporation/ympd
|
||||
|
||||
myMPD ist fork of:
|
||||
|
||||
ympd
|
||||
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
||||
This project's homepage is: http://www.ympd.org
|
||||
|
||||
@ -39,7 +45,6 @@
|
||||
#define MPD_CMDS(X) \
|
||||
X(MPD_API_GET_QUEUE) \
|
||||
X(MPD_API_GET_BROWSE) \
|
||||
X(MPD_API_GET_MPDHOST) \
|
||||
X(MPD_API_ADD_TRACK) \
|
||||
X(MPD_API_ADD_PLAY_TRACK) \
|
||||
X(MPD_API_ADD_PLAYLIST) \
|
||||
@ -58,8 +63,6 @@
|
||||
X(MPD_API_SET_SEEK) \
|
||||
X(MPD_API_SET_NEXT) \
|
||||
X(MPD_API_SET_PREV) \
|
||||
X(MPD_API_SET_MPDHOST) \
|
||||
X(MPD_API_SET_MPDPASS) \
|
||||
X(MPD_API_UPDATE_DB) \
|
||||
X(MPD_API_GET_OUTPUTS) \
|
||||
X(MPD_API_TOGGLE_OUTPUT) \
|
||||
@ -67,7 +70,8 @@
|
||||
X(MPD_API_TOGGLE_CONSUME) \
|
||||
X(MPD_API_TOGGLE_SINGLE) \
|
||||
X(MPD_API_TOGGLE_CROSSFADE) \
|
||||
X(MPD_API_TOGGLE_REPEAT)
|
||||
X(MPD_API_TOGGLE_REPEAT) \
|
||||
X(MPD_API_GET_OPTIONS)
|
||||
|
||||
enum mpd_cmd_ids {
|
||||
MPD_CMDS(GEN_ENUM)
|
||||
@ -99,6 +103,8 @@ struct t_mpd {
|
||||
unsigned queue_version;
|
||||
} mpd;
|
||||
|
||||
int streamport;
|
||||
|
||||
struct t_mpd_client_session {
|
||||
int song_id;
|
||||
unsigned queue_version;
|
||||
|
191
src/ympd.c
191
src/ympd.c
@ -1,191 +0,0 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "http_server.h"
|
||||
#include "mpd_client.h"
|
||||
#include "config.h"
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
int force_exit = 0;
|
||||
|
||||
void bye()
|
||||
{
|
||||
force_exit = 1;
|
||||
}
|
||||
|
||||
static int server_callback(struct mg_connection *c, enum mg_event ev) {
|
||||
int result = MG_FALSE;
|
||||
FILE *fp = NULL;
|
||||
|
||||
switch(ev) {
|
||||
case MG_CLOSE:
|
||||
mpd_close_handler(c);
|
||||
return MG_TRUE;
|
||||
case MG_REQUEST:
|
||||
if (c->is_websocket) {
|
||||
c->content[c->content_len] = '\0';
|
||||
if(c->content_len)
|
||||
return callback_mpd(c);
|
||||
else
|
||||
return MG_TRUE;
|
||||
} else
|
||||
return MG_FALSE;
|
||||
case MG_AUTH:
|
||||
// no auth for websockets since mobile safari does not support it
|
||||
if ( (mpd.gpass == NULL) || (c->is_websocket) || ((mpd.local_port > 0) && (c->local_port == mpd.local_port)) )
|
||||
return MG_TRUE;
|
||||
else {
|
||||
if ( (fp = fopen(mpd.gpass, "r")) != NULL ) {
|
||||
result = mg_authorize_digest(c, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
default:
|
||||
return MG_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n, option_index = 0;
|
||||
struct mg_server *server = mg_create_server(NULL, server_callback);
|
||||
unsigned int current_timer = 0, last_timer = 0;
|
||||
char *run_as_user = NULL;
|
||||
char const *error_msg = NULL;
|
||||
char *webport = "8080";
|
||||
|
||||
atexit(bye);
|
||||
mg_set_option(server, "document_root", SRC_PATH);
|
||||
|
||||
mg_set_option(server, "auth_domain", "mympd");
|
||||
mpd.port = 6600;
|
||||
mpd.local_port = 0;
|
||||
mpd.gpass = NULL;
|
||||
strcpy(mpd.host, "127.0.0.1");
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"digest", required_argument, 0, 'D'},
|
||||
{"host", required_argument, 0, 'h'},
|
||||
{"port", required_argument, 0, 'p'},
|
||||
{"localport", required_argument, 0, 'l'},
|
||||
{"webport", required_argument, 0, 'w'},
|
||||
{"user", required_argument, 0, 'u'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 0 },
|
||||
{"mpdpass", required_argument, 0, 'm'},
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
while((n = getopt_long(argc, argv, "D:h:p:l:w:u:d:v:m",
|
||||
long_options, &option_index)) != -1) {
|
||||
switch (n) {
|
||||
case 'D':
|
||||
mpd.gpass = strdup(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
strncpy(mpd.host, optarg, sizeof(mpd.host));
|
||||
break;
|
||||
case 'p':
|
||||
mpd.port = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
mpd.local_port = atoi(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
webport = strdup(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
run_as_user = strdup(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
if (strlen(optarg) > 0)
|
||||
mpd.password = strdup(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
fprintf(stdout, "ympd %d.%d.%d\n"
|
||||
"Copyright (C) 2014 Andrew Karpow <andy@ndyk.de>\n"
|
||||
"built " __DATE__ " "__TIME__ " ("__VERSION__")\n",
|
||||
YMPD_VERSION_MAJOR, YMPD_VERSION_MINOR, YMPD_VERSION_PATCH);
|
||||
return EXIT_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: %s [OPTION]...\n\n"
|
||||
" -D, --digest <htdigest>\tpath to htdigest file for authorization\n"
|
||||
" \t(realm ympd) [no authorization]\n"
|
||||
" -h, --host <host>\t\tconnect to mpd at host [localhost]\n"
|
||||
" -p, --port <port>\t\tconnect to mpd at port [6600]\n"
|
||||
" -l, --localport <port>\t\tskip authorization for local port\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"
|
||||
" -m, --mpdpass <password>\tspecifies the password to use when connecting to mpd\n"
|
||||
" --help\t\t\t\tthis help\n"
|
||||
, argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(error_msg)
|
||||
{
|
||||
fprintf(stderr, "Mongoose error: %s\n", error_msg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
error_msg = mg_set_option(server, "listening_port", webport);
|
||||
if(error_msg) {
|
||||
fprintf(stderr, "Mongoose error: %s\n", error_msg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* drop privilges at last to ensure proper port binding */
|
||||
if(run_as_user != NULL) {
|
||||
error_msg = mg_set_option(server, "run_as_user", run_as_user);
|
||||
free(run_as_user);
|
||||
if(error_msg)
|
||||
{
|
||||
fprintf(stderr, "Mongoose error: %s\n", error_msg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
while (!force_exit) {
|
||||
mg_poll_server(server, 200);
|
||||
current_timer = time(NULL);
|
||||
if(current_timer - last_timer)
|
||||
{
|
||||
last_timer = current_timer;
|
||||
mpd_poll(server);
|
||||
}
|
||||
}
|
||||
|
||||
mpd_disconnect();
|
||||
mg_destroy_server(&server);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue
Block a user