Compare commits

...

310 Commits

Author SHA1 Message Date
SuperBFG7 297691ab5b move panel header to list panel 2022-08-10 17:30:46 +02:00
SuperBFG7 b41753220f don't show queue length when browsing 2022-08-10 17:30:24 +02:00
SuperBFG7 7a725e648d Revert "Fix handling of multiple client sessions (browsers)"
This reverts commit ac7ad51a0e.
2021-08-24 14:13:23 +02:00
SuperBFG7 ac7ad51a0e Fix handling of multiple client sessions (browsers) 2021-08-24 14:12:06 +02:00
SuperBFG7 3c70301789 Added authentication for webservice connection. 2021-08-23 17:23:48 +02:00
SuperBFG7 f5080c8419 linting 2021-07-29 11:57:55 +02:00
SuperBFG7 7b5496e06c fix handling of special characters in paths 2021-06-24 10:16:21 +02:00
SuperBFG7 4d30fff4bc hide volume controls when volume is not supported by the current output 2021-06-21 09:28:34 +02:00
SuperBFG7 2b461aafa2 Only show love button when either mpdas or mpdscribble channel is
present and use the correct channel to send the message of love
2021-06-17 20:50:15 +02:00
SuperBFG7 fd727cc20b linted 2021-06-17 11:43:45 +02:00
SuperBFG7 ebf5b3894d add mpdscribble support for love button 2021-06-17 10:07:52 +02:00
SuperBFG7 8669750a4b Browse: rename root to Library 2021-06-17 09:57:36 +02:00
SuperBFG7 28844275e6 Enable volume slider again
Add volume number
Move love button to song info box
2021-06-17 09:55:45 +02:00
SuperBFG7 86586fbcee Fix position only on big screens 2021-06-17 09:51:36 +02:00
SuperBFG7 886e390d09 Separate song info box and queue list
Fix position of song info box and control buttons (don't scroll out of screen)
2021-06-17 08:53:22 +02:00
SuperBFG7 d5294675c4 Removed standalone player 2021-06-16 17:27:12 +02:00
SuperBFG7 883ea7ca06 Added bash script to run linters to tools
Ran prettier on .clang-format
2021-06-16 17:18:25 +02:00
SuperBFG7 61e385a35d Merge branch 'tandell-linter' 2021-06-15 10:01:41 +02:00
Andrew Carr 9a0cf4a43b Configured and ran clang-format on src files 2021-05-23 04:09:25 +00:00
Andrew Carr b35e705066 Configured and ran Prettier on client files 2021-05-23 03:15:19 +00:00
SuperBFG7 9d1a3ccfb2 Merge branch 'tandell-remove-dirble-2' 2021-05-21 10:24:07 +02:00
Andrew Carr 3fe238b169 Dirble option and functionality removed
Dirble is no longer available and per the author/old-owner, will probably not
be coming back.

This commit removes the configuration option and the code used to access
dirble. Everything else still appears to be functional.

re: https://dev.to/confact/what-happened-with-dirble-k3g
2021-05-21 01:38:19 +00:00
SuperBFG7 d1416d8f34 Added option for automatic playback of mpd stream.
When activated in settings, ympd will atempt to play the mpd stream
(ogg/mp3) locally in the browser whenever mpd is playing.

This allows to run a headless instance on a PC with sound and start/stop
playback also from other instances or mpd clients.
e.g. run ympd with autoplay on your private PC with decent loudspeakers,
    but control it with another instance on your office laptop without
    the need to switch PCs.
2021-03-23 19:25:39 +01:00
SuperBFG7 5e6d090bd8 Merge branch 'dafanz-master' 2021-03-09 13:03:22 +01:00
SuperBFG7 bd95651d61 removed two obsolete lines 2021-03-09 13:03:04 +01:00
Dafan Zhai efa4d4443f Fixed invisible "Add all" button in browse page 2021-03-07 20:07:57 +01:00
Daniel Schregenberger df5a48f99f
Merge pull request #31 from SuperBFG7/compile
added forward declarations
2020-06-02 12:44:06 +02:00
SuperBFG7 2268e0f0f3 added forward declarations 2020-06-02 12:41:52 +02:00
Daniel Schregenberger 91700a2496
Merge pull request #29 from SuperBFG7/harden
Harden
2019-04-22 11:53:51 +02:00
Daniel Schregenberger e6e08d6159
Merge branch 'master' into harden 2019-04-22 11:53:24 +02:00
SuperBFG7 fff184dca2 moved default user definition to service file 2019-04-22 11:51:09 +02:00
SuperBFG7 aeceb91551 moved definition of default user to service file 2019-04-22 11:47:22 +02:00
Clément Pit-Claudel 0917b467e8
Harden ympd.service
This offers a measure of protection against potential ympd vulnerabilities.  See
https://www.freedesktop.org/software/systemd/man/systemd.exec.html for
documentation.
2019-03-10 16:43:39 +00:00
SuperBFG7 b9c268b847 fix layout 2018-06-03 12:11:26 +02:00
SuperBFG7 6340dcde72 Merge branch 'filter' 2018-06-03 12:06:07 +02:00
SuperBFG7 a3ae8cd802 fix filtering with pagination 2018-06-03 11:57:13 +02:00
SuperBFG7 f89c49e09c fix filtering of songs 2018-05-12 09:53:33 +02:00
Daniel Schregenberger 9bf518ed07
Merge pull request #25 from SuperBFG7/filter
make A-Z filters work also on songs and playlists
2018-05-11 21:12:39 +02:00
SuperBFG7 db72139490 make A-Z filters work also on songs and playlists 2018-05-11 21:10:22 +02:00
Daniel Schregenberger 2db7b711f7
Merge pull request #24 from SuperBFG7/filter
filtering on all levels and fix playlist filter
2018-05-11 17:19:57 +02:00
Daniel Schregenberger 5ffdc5e50a
Merge branch 'master' into filter 2018-05-11 17:19:50 +02:00
SuperBFG7 b0ec3be02f filtering on all levels and fix playlist filter 2018-05-11 17:18:17 +02:00
Daniel Schregenberger 93ec197f79
Merge pull request #23 from SuperBFG7/filter
add filtering on all levels and fix playlist filter
2018-05-11 16:59:55 +02:00
Daniel Schregenberger 3774a35f4c
Merge branch 'master' into filter 2018-05-11 16:59:07 +02:00
SuperBFG7 61ad51ffb7 add filtering on all levels and fix playlist filter 2018-05-11 16:49:12 +02:00
Daniel Schregenberger 1e96a921c5
Merge pull request #22 from SuperBFG7/revert-18-master
Revert "Typo error prevend webradio playlists to show."
2018-05-11 15:35:00 +02:00
Daniel Schregenberger 4be2db91e4
Revert "Typo error prevend webradio playlists to show." 2018-05-11 15:34:38 +02:00
Daniel Schregenberger 86a924cddd
Merge pull request #21 from SuperBFG7/revert-20-master
Revert "typo fix as per emilot commit"
2018-05-11 15:06:04 +02:00
Daniel Schregenberger 1588e21c08
Revert "typo fix as per emilot commit" 2018-05-11 15:05:31 +02:00
Daniel Schregenberger 2f4c737f09
Merge pull request #20 from archphile/master
typo fix as per emilot commit
2018-05-10 13:29:27 +02:00
Daniel Schregenberger 68cbe37a84
Merge pull request #19 from andreevskya/DisplayCurrentTrackInPageTitle
[Issue 128] Current track in page title
2018-05-10 12:03:04 +02:00
Daniel Schregenberger ffe1305c3c
Merge pull request #18 from Emilot/master
Typo error prevend webradio playlists to show.
2018-05-10 12:01:36 +02:00
Archphile 870da6f9a1
typo fix as per emilot commit
Please see: https://github.com/notandy/ympd/pull/175
2018-05-10 10:22:44 +03:00
Emilot b787c782d1
Typo error prevend webradio playlists to show. 2018-05-10 02:43:57 +03:00
andreevksya ac55e8a604 [Issue 128] Current track in page title 2018-05-09 20:27:33 +00:00
SuperBFG7 e1cb953e94 layout improvements 2018-04-23 13:38:58 +02:00
SuperBFG7 ebd357a24a fix layout 2018-04-22 20:48:18 +02:00
SuperBFG7 d08092b069 Merge remote-tracking branch 'eb041592/queue_nowrap' 2018-04-22 18:59:05 +02:00
SuperBFG7 265e5f76a1 Merge remote-tracking branch 'eb041592/queue_time' 2018-04-22 18:57:02 +02:00
SuperBFG7 63be6f0de0 Merge remote-tracking branch 'upstream/master' 2018-04-22 18:33:10 +02:00
eb041592 c9e200a3ef Prevent (almost) any wrapping to keep the interface "clean". 2018-04-10 21:18:35 +02:00
eb041592 2cb99de852 Revert some changes: There's no need to print the artist/album for each song while browsing. 2018-04-05 00:59:39 +02:00
eb041592 18417b9ed5 Reset #panel-heading-info on update of #panel-heading. 2018-04-04 23:06:19 +02:00
eb041592 c226026a51 Treat album while browsing the same way as in the queue. 2018-04-04 23:06:19 +02:00
eb041592 84b3ea71a4 Switch queue's line break before album from HTML to CSS. 2018-04-04 23:06:19 +02:00
eb041592 0faf70ad05 Add queue's total time to panel header. 2018-04-04 23:06:19 +02:00
eb041592 54e334a2a0 Added additional "totalTime" field to "obj" for the queue's total time. 2018-04-04 23:06:19 +02:00
Andy 612f8fc0b2
Merge pull request #158 from eb041592/master
Update FreeBSD RC script
2018-03-29 20:37:43 +02:00
Andy 17b97c8f6b
Merge pull request #159 from eb041592/unclutter_interface
Unclutter Interface
2018-03-29 20:36:25 +02:00
Andy a7d9bf85f5
Merge pull request #160 from eb041592/verbose_lists
Add artist and album to queue and search results
2018-03-29 20:36:03 +02:00
Andy 0e58a0d5c7
Merge pull request #162 from archphile/master
fixed a typo
2018-03-29 20:34:21 +02:00
Andy eea4a382a4
Merge pull request #163 from ffontaine/master
ympd is implemented only in C
2018-03-29 20:32:23 +02:00
SuperBFG7 2fa653711d fix defaults 2018-03-25 13:52:41 +02:00
SuperBFG7 26b2ca3408 add option "localport" to exclude ports from auth
usefull if ympd listens on two ports: one (local) for intranet usage and
one for internet usage
2018-03-25 13:45:16 +02:00
Daniel Schregenberger 5e834e56ff
Merge pull request #16 from ffontaine/master
ympd is implemented only in C
2018-03-12 17:51:19 +01:00
Fabrice Fontaine f53c0956d4 ympd is implemented only in C
By default, CMake assumes that the project is using both C and C++. By
explicitly passing 'C' as argument of the project() macro, we tell
CMake that only C is used, which prevents CMake from checking if a C++
compiler exists.

Patch applied to buildroot since 2014:
https://git.buildroot.net/buildroot/commit/package/ympd?id=40aa523af26963321443a2d96c64ce128577ca77

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2018-03-08 18:02:26 +01:00
Archphile d4865aca9d
fixed a typo
Replaced $DIRBLE_API_TOKE with $DIRBLE_API_TOKEN in order for the service to be functional.
2018-03-05 13:54:46 +02:00
eb041592 b4084034d0 Reverted some formatting; aligned CSS 2018-02-05 01:03:48 +01:00
eb041592 bd9775de8e Align the labels for the trash mode buttons with display:inline-block 2018-02-05 00:38:20 +01:00
eb041592 b3037d6117 Hide Dirble app, if no API token is given/available 2018-02-04 13:43:37 +01:00
eb041592 b091e47d2f Removed default for dirble_api_token from ympd.c 2018-02-04 01:50:28 +01:00
eb041592 037e7db1da Minor formatting 2018-02-04 01:11:41 +01:00
eb041592 2e9d477ee6 Hide output button(s) if there is only one configured output 2018-02-04 00:30:45 +01:00
eb041592 73a844eb71 Fixed error with "... added" notifications 2018-02-03 16:34:22 +01:00
eb041592 1b0484a285 Extended text field for stream url across entire width of dialog 2018-02-03 15:06:59 +01:00
eb041592 226e3b5999 Moved button for notifications to settings 2018-02-03 14:51:48 +01:00
SuperBFG7 17436bff40 fix browse for directories and playlists 2018-02-03 13:02:02 +01:00
SuperBFG7 7af873b793 remove password from service file 2018-02-03 12:51:20 +01:00
eb041592 fe0277bfbe Rearranged artist and album information in queue and search results. 2018-02-03 12:03:33 +01:00
eb041592 3fe7d9c44c Some more spelling 2018-02-02 02:40:40 +01:00
eb041592 cf572b705e Added artist and album to both queue and search results; minor spelling 2018-02-02 02:14:31 +01:00
eb041592 80834b989f Update FreeBSD RC script
- removed /usr/sbin/daemon's option "-t" (first appeared in FreeBSD 11, leading to an error in previous versions; since the [t]itle defaults to the daemonized invocation anyways, this shouldn't make a difference for FreeBSD 11+)
- removed /usr/sbin/daemon's option "-u" and the respective variable in the script (ympd has to be started as root to be able to bind to port 80)
- allow for additional arguments via ympd_flags="" in rc.conf (which would again allow to drop privileges after binding to the port)
2018-01-28 22:54:17 +01:00
SuperBFG7 fec13b6937 Revert "remove password since it breaks empty passwords"
This reverts commit 839b9aa9de.
2018-01-26 15:47:16 +01:00
Daniel Schregenberger 2a0e4fb22a
Merge pull request #15 from SuperBFG7/notandy-master
Notandy master
2018-01-26 15:43:58 +01:00
Daniel Schregenberger 7a31b441b6
Merge pull request #14 from notandy/master
fixed mpd connection with empty mpdpass introduced by #148
2018-01-26 15:42:49 +01:00
Andrew Karpow 88b2aa70c8 fixed mpd connection with empty mpdpass introduced by #148 2018-01-26 15:06:34 +01:00
SuperBFG7 839b9aa9de remove password since it breaks empty passwords 2018-01-26 14:22:50 +01:00
SuperBFG7 f1495ff712 fixed typo 2018-01-26 14:16:03 +01:00
SuperBFG7 94fed08434 Merge branch 'notandy-master' 2018-01-26 13:59:08 +01:00
SuperBFG7 1e93d2dc82 Merge branch 'master' into notandy-master 2018-01-26 13:51:20 +01:00
Daniel Schregenberger 3dac7ce3dc
Merge pull request #12 from notandy/master
Merge recent commits to notandy/ympd master
2018-01-26 13:23:23 +01:00
Andrew Karpow 8c1115dc63 Merge branch 'master' of github.com:notandy/ympd 2018-01-22 05:02:09 +01:00
Andrew Karpow d314ac08df Merge branch 'lesderid-master' 2018-01-22 05:01:40 +01:00
Andrew Karpow ceee8bd90a Merge branch 'master' of https://github.com/lesderid/ympd into lesderid-master 2018-01-22 04:58:17 +01:00
Andy 68429e39d5
Merge pull request #157 from florianheinemann/patch-1
Update README.md to highlight OpenSSL dependency
2018-01-22 04:55:07 +01:00
Andrew Karpow b0253a01ab Merge branch 'SuperBFG7-send-message' 2018-01-22 04:50:43 +01:00
Andrew Karpow ba4322c684 Merge branch 'send-message' of https://github.com/SuperBFG7/ympd into SuperBFG7-send-message 2018-01-22 04:50:22 +01:00
Andrew Karpow 95f8ccd7a4 update travis image 2018-01-22 04:45:59 +01:00
Andrew Karpow 265577c5ab Merge branch 'BenjaminHae-sortable' 2018-01-22 04:40:52 +01:00
Andy 91e3535891
Merge pull request #156 from znetstar/master
Adds a Dockerfile
2018-01-22 04:35:21 +01:00
Andy 393d6063da
Merge pull request #149 from SuperBFG7/delete
add ability to delete ranges of the playlist
2018-01-22 04:34:54 +01:00
Andy a99b0a5ddc
Merge pull request #134 from Kernald/fix-double-slashes
Fix double slashes in websocket URL
2018-01-22 04:33:54 +01:00
Andy e436fc93b5
Merge pull request #130 from govertbuijs/master
Added crude filtering for browsing db
2018-01-22 04:32:57 +01:00
Andy b21fccc240
Merge pull request #150 from azrdev/no-overwrite-cflags
Don't overwrite CFLAGS
2018-01-22 04:26:09 +01:00
Andy f7aade410d
Merge pull request #148 from unknownloner/master
Allow MPD Password to be configured in command line options
2018-01-22 04:23:51 +01:00
Andy e0050641df
Merge pull request #145 from felixjogris/master
added FreeBSD RC script
2018-01-22 04:22:36 +01:00
Florian Heinemann bba35bf682
Update README.md to highlight OpenSSL dependency 2018-01-21 22:06:40 +01:00
Zachary Boyd 02ab7df3c6 Adds a Dockerfile for building a lightweight Docker container based on alpine 2017-12-23 12:11:47 -08:00
SuperBFG7 5589013a95 shorter browse item in menu 2017-12-18 15:16:37 +01:00
SuperBFG7 06ded692a5 Revert "Merge branch 'lmanul-master'"
This reverts commit f118c53ecb, reversing
changes made to 604d54a0bb.
2017-12-18 15:10:21 +01:00
SuperBFG7 f118c53ecb Merge branch 'lmanul-master' 2017-12-18 15:00:56 +01:00
SuperBFG7 d9182dd2f4 merge branch lmanul-master 2017-12-18 15:00:28 +01:00
SuperBFG7 604d54a0bb fix player 2017-07-31 11:56:02 +02:00
azrdev c1f1adbc28 Don't overwrite CFLAGS
Preserve user/system-configured C_FLAGS.

This broke the rpm package build on fedora: They enable a hardened config (i.e. ASLR) by default, which adds -pie and -fPIC to linker and compiler flags. Overwriting C_FLAGS removed the compiler spec, but not the linker one, leading to an error like:

/bin/cc  -std=gnu99 -Wall -ggdb -pedantic  -specs=/usr/lib/rpm/redhat/redhat-hardened-ld CMakeFiles/mkdata.dir/tools/mkdata.c.o  -o mkdata -rdynamic 
bin/ld: CMakeFiles/mkdata.dir/tools/mkdata.c.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
CMakeFiles/mkdata.dir/tools/mkdata.c.o: error adding symbols: Bad value

With this fix, the error is gone:

/bin/cc  -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -std=gnu99 -Wall -g -ggdb -pedantic  -specs=/usr/lib/rpm/redhat/redhat-hardened-ld CMakeFiles/mkdata.dir/tools/mkdata.c.o  -o mkdata -rdynamic
2017-05-14 07:37:46 +02:00
SuperBFG7 fac60b18a1 Merge branch 'delete' 2017-04-08 11:31:41 +02:00
SuperBFG7 eb803d1da5 add ability to delete ranges of the playlist 2017-04-08 11:25:40 +02:00
Galen Alderson fa4cb48830 Fix segfault when using short password option (-m) 2017-03-29 12:17:01 -04:00
SuperBFG7 269c55b9c8 Merge remote-tracking branch 'origin/send-message' 2017-03-24 11:02:25 +01:00
SuperBFG7 dfb9adb78c added missing include 2017-03-24 11:01:24 +01:00
SuperBFG7 6727b8b0ad uncommented love button 2017-03-18 13:44:04 +01:00
SuperBFG7 4f64061286 Merge remote-tracking branch 'origin/send-message' 2017-03-18 13:41:32 +01:00
SuperBFG7 152defeaaa add a button to love tracks on last.fm using mpdas 2017-03-18 13:32:17 +01:00
SuperBFG7 07c6df23bc added API command to send messages to MPD channels 2017-03-18 13:31:26 +01:00
SuperBFG7 afab4e5653 Merge branch 'fix-double-slashes' 2017-03-18 10:39:25 +01:00
SuperBFG7 66ff05e8b5 Merge branch 'fix-double-slashes' of git://github.com/Kernald/ympd into fix-double-slashes 2017-03-18 10:38:46 +01:00
SuperBFG7 6c75d5bc6c Merge branch 'eolianoe-patch-1' 2017-03-18 10:35:24 +01:00
SuperBFG7 40c335cfca Merge branch 'patch-1' of git://github.com/eolianoe/ympd into eolianoe-patch-1 2017-03-18 10:34:57 +01:00
SuperBFG7 8abcee0049 fix README 2017-03-18 10:27:52 +01:00
unknownln e5a88b1ffe quote password 2017-02-18 12:05:24 -05:00
unknownln ec74ef463b config for system services 2017-02-18 12:00:28 -05:00
unknownln a6ba0d640c Update documentation for new option 2017-02-18 11:51:03 -05:00
unknownln f79dea44a2 Add option to set MPD password 2017-02-18 11:42:20 -05:00
Felix J. Ogris 40906e2bee added FreeBSD RC script 2017-02-06 20:19:09 +01:00
Les De Ridder d9ec70a9da
Make the Dirble API token configurable and use HTTPS
Fixes #140
2016-09-11 18:23:42 +02:00
Marc Plano-Lesay 15edcc645c Fix double slashes in websocket URL 2016-07-07 15:22:15 +02:00
Govert Buijs 306840fa1d Added crude filtering for browsing db 2016-06-08 23:20:27 +02:00
eolianoe d2d037fe97 Display the right short option for `--version` 2016-04-17 11:37:04 +02:00
SuperBFG7 f586db33d1 fix browsing of playlists 2016-02-16 12:03:50 +01:00
SuperBFG7 92d3806fca Merge branch 'notandt push origin mastery-master' 2016-02-14 12:34:13 +01:00
SuperBFG7 5d9a4831d4 Merge branch 'master' of git://github.com/notandy/ympd into notandy-master 2016-02-14 12:33:57 +01:00
SuperBFG7 ce689a26de sync with original repo 2016-02-14 12:30:14 +01:00
Daniel Schregenberger b367115850 Merge pull request #8 from BenjaminHae/master
moved Update-DB Button to settings
2016-02-14 12:16:07 +01:00
Daniel Schregenberger 08bc954917 Merge pull request #7 from BenjaminHae/playbutton
added functionality of play/pause button to queue header
2016-02-14 12:14:37 +01:00
Andy ec008a4995 Merge pull request #116 from SuperBFG7/comma
fix handling of commas in library item names
2016-02-13 22:01:52 +01:00
Andrew Karpow 0059a6dd41 removed minified files, minifing should be part of build process 2016-02-13 21:58:43 +01:00
Andy 9274480b2e Merge pull request #113 from BenjaminHae/playbutton
added functionality of play/pause symbol track-icon to queue header
2016-02-13 21:51:34 +01:00
Andy 126f247a08 Merge pull request #102 from SuperBFG7/browse
remember last folder in browser
2016-02-13 21:49:18 +01:00
Andy 597018542e Merge pull request #104 from SuperBFG7/touch
do not use mouseenter/leave on touch devices
2016-02-13 21:48:54 +01:00
Andy 2facf32896 Merge pull request #92 from BenjaminHae/master
moved Update-DB Button to settings
2016-02-13 21:46:57 +01:00
Andrew Karpow ba40ad4515 Merge branch 'sortable' of https://github.com/BenjaminHae/ympd into BenjaminHae-sortable 2016-02-13 21:31:23 +01:00
Andy 868f0f622a Merge pull request #97 from SuperBFG7/ssl
Compile mongoose with SSL support
2016-02-13 21:24:44 +01:00
Andy b041307637 Merge pull request #120 from notandy/fix-travis-ci
probably fix travis ci
2016-02-13 21:21:53 +01:00
Andrew Karpow 336d1e9097 probably fix travis ci 2016-02-13 18:09:27 +01:00
SuperBFG7 0591fadb20 Merge branch 'Nofre-dirble_fix' 2016-02-08 10:32:36 +01:00
SuperBFG7 ac47c67004 Merge branch 'dirble_fix' of git://github.com/Nofre/ympd into Nofre-dirble_fix 2016-02-08 10:32:08 +01:00
LordMyschkin f471c961e9 Update mpd.min.css
added overflow:hidden to button-class to prevent nasty overlaying of the outputs as adressed in issue #112
2016-02-07 22:28:29 +01:00
LordMyschkin aa49b1d352 Update mpd.css 2016-02-07 22:23:48 +01:00
Nofre 8ef9e58ab0 README.md updated 2016-02-03 18:51:44 +01:00
Nofre 0e47d5c4bc Dirble's token fix 2016-02-02 18:47:53 +01:00
SuperBFG7 97bdc9aa97 fix handling of commas in library item names 2016-01-25 13:29:28 +01:00
SuperBFG7 83dcb137fb fix handling of commas in library item names 2016-01-25 13:17:28 +01:00
Benjamin Häublein b047a900bc added functionality of play/pause button to queue header 2016-01-16 19:33:29 +01:00
SuperBFG7 2526a015f0 improve error handling for local player 2015-12-08 16:42:03 +01:00
SuperBFG7 d72c10cd8c simplify toolbar 2015-11-23 11:10:11 +01:00
SuperBFG7 fd50f3c4ed added digest option to contrib files 2015-11-13 15:07:54 +01:00
SuperBFG7 6f54187ea9 add digest option to contrib files 2015-11-13 15:07:07 +01:00
SuperBFG7 5090ca370e fix digest argument type 2015-11-13 10:33:32 +01:00
SuperBFG7 84ad2b06a7 fix digest argument type 2015-11-13 10:32:36 +01:00
SuperBFG7 b59c06b922 merge branch touch 2015-10-22 17:49:42 +02:00
SuperBFG7 2e74427778 do not use mouseenter/leave on touch devices 2015-10-22 17:48:42 +02:00
SuperBFG7 a8bcba7fe7 merge branch browse 2015-10-22 11:45:55 +02:00
SuperBFG7 f06885fab7 remember last folder in browser 2015-10-22 11:44:50 +02:00
SuperBFG7 8696216d6e Merge branch 'local_play' 2015-10-22 11:21:09 +02:00
SuperBFG7 4643f1cdcb use cookies to store streamurl and added minimal player 2015-10-21 19:24:38 +02:00
SuperBFG7 ff92b2718f add artist and title columns (by laclaro) 2015-10-16 18:51:25 +02:00
SuperBFG7 934fb63e1e merge local_play 2015-10-16 15:31:29 +02:00
SuperBFG7 264ce34ae9 fix toolbar layout 2015-10-16 15:28:04 +02:00
Daniel Schregenberger 03d02e815c Merge pull request #4 from BenjaminHae/sortable
Make playlist sortable
2015-10-16 14:24:54 +02:00
SuperBFG7 15c29c4b6b added wss+digest workaround for mobile safari 2015-10-15 16:09:47 +02:00
SuperBFG7 686eb4f5d2 skip authorization for websockets, since mobile safari does not support it 2015-10-15 15:46:28 +02:00
SuperBFG7 d87c762bb8 streamline design with original design 2015-10-09 12:12:31 +02:00
SuperBFG7 e0721fb6c9 optimized local playing of mpd stream 2015-10-09 12:06:41 +02:00
SuperBFG7 bde33d5aa7 added option for htdigest authentication 2015-10-06 20:17:28 +02:00
Daniel Schregenberger 2dc771b9c4 Merge pull request #3 from SuperBFG7/digest
added option for htdigest authentication
2015-10-06 19:59:36 +02:00
SuperBFG7 4ce5f736ad added option for htdigest authentication 2015-10-06 19:57:27 +02:00
Daniel Schregenberger 18ca9af342 Merge pull request #2 from SuperBFG7/ssl
added documentation for SSL usage
2015-10-06 19:40:54 +02:00
Daniel Schregenberger 64cdd920e7 added documentation for SSL usage 2015-10-06 18:53:14 +02:00
Daniel Schregenberger e051ebff9e Merge pull request #1 from SuperBFG7/ssl
compile mongoose with SSL support
2015-09-27 18:14:19 +02:00
SuperBFG7 cb82047228 removed filename to not depend on the format mpd is streaming
add load() before play() for mobile safari
2015-09-27 17:52:13 +02:00
SuperBFG7 0b2c69c281 Merge branch 'expire1' of github.com:parabelboi/ympd into local_play 2015-09-27 15:34:58 +02:00
SuperBFG7 00e58b0fe0 compile mongoose with SSL support 2015-09-27 14:33:37 +02:00
Benjamin Häublein 5234e97d5e check if element is sortable before removing sortable property 2015-09-26 14:32:14 +02:00
Benjamin Häublein 9d11aaf829 sortable queue
using jquery-ui-sortable standalone https://github.com/ryantbrown/jquery-ui-sortable
2015-09-26 13:51:56 +02:00
Benjamin Häublein ab9c9cf9e2 moved Update-DB Button to settings 2015-09-25 10:39:51 +02:00
Andrew Karpow 4295d15874 Merge branch 'Nofre-master' 2015-09-20 16:01:06 +02:00
Andrew Karpow 9f06699d3e Merge branch 'master' of https://github.com/Nofre/ympd into Nofre-master 2015-09-20 16:00:45 +02:00
Andy 30b0b812f6 Merge pull request #69 from kurt-vd/master
add support for output enable/disable
2015-09-20 15:56:10 +02:00
Andy b211543890 Merge pull request #82 from iwanders/improvement_stream_ui
Improve the add stream dialog user experience.
2015-09-20 15:55:19 +02:00
Andy 6dcb2ad758 Merge pull request #87 from BenjaminHae/master
Added the ability to save queue as playlist
2015-09-20 15:54:20 +02:00
Andy 84f3a78a42 Merge pull request #89 from dewyatt/master
Add arrow left/right and spacebar controls
2015-09-20 15:53:23 +02:00
Andy c1b52d819d Merge pull request #84 from hsoft/add-all-songs
Add "Add all" button in the Browse section
2015-09-20 15:52:52 +02:00
Daniel Wyatt 86d2d2ecb4 Add arrow left/right and spacebar controls 2015-09-13 04:38:18 -04:00
Benjamin Häublein 4f138c0986 Save Queue 2015-09-02 19:47:58 +02:00
Nofre 30bb8161b5 code cleared 2015-09-02 19:38:42 +02:00
Nofre 94869bba92 Added a tab to search radio stations from Dirble. Also fixes #85 2015-08-27 16:15:23 +02:00
Virgil Dupras 4e2f300643 Add "Add all" button in the Browse section
It adds all items in the directory. It's equivalent to clicking on "+"
on that same directory we decided to browse.
2015-08-17 17:01:47 -04:00
Ivor Wanders d3148056fc Improves the add stream dialog user experience.
When the dialog is opened, the text area is focused. When enter is
pressed (and the form is submit) the window now behaves as expected and
adds the stream to the playlist and closes. The text area is now also
cleared once the form is submit, previously the old stream was still
visible when the dialog was opened a second time.
2015-07-16 11:50:54 +02:00
Andy f2164b382a Merge pull request #81 from hsoft/fix-encoded-uri-addtrack
Fix broken add track action
2015-07-16 11:38:53 +02:00
Virgil Dupras 698f573a65 Fix broken add track action
Fix the bug I've introduced in my PR #78, breaking the add
track/playlist action. We have to decode URIs before sending them back
to our socket!

fixes #80
2015-07-13 14:31:56 -04:00
Andy 7b05dc1010 Merge pull request #78 from hsoft/master
Fix browsing for non-ascii entity URI under Safari
2015-06-24 20:17:05 +02:00
Virgil Dupras fe44fca184 Fix browsing for non-ascii entity URI under Safari
Previously, browsing entities with non-ascii characters in their URI
under Safari wouldn't work. Directories would be empty, songs wouldn't
be added. I haven't tried it, but this behavior seems to be common to
Webkit-based browsers, so Chrome would be affected too.

This turned out to be because Safari normalizes all unicode strings to
NFC, breaking the link with MPD-spewed URIs, which are in NFD.

An obvious fix would have been to normalize all URIs to NFD, but
unfortunately, Safari doesn't have `str.normalize()`. Adding
normalization capabilities to our JS side would have involved
introductiing libraries such as `unorm`, which is rather big.

We could have done it on the C side, but it involves introducing `icu`,
which is far from trivial too.

After much fussing around, I stumbled on a simple solution: URI-encode
our URI when creating our browser table row. This magically prevents
Safari from trying to mess with our unicode form before we get the
chance to send it back to our server.
2015-06-20 22:39:42 -04:00
Kurt Van Dijck 3b72651d7e outputs: fix typo 2015-05-25 18:11:22 +02:00
Andy 51c371bbc3 Merge pull request #73 from jpleau/fix_init
fix webport using the wrong variable in init scripts
2015-05-03 02:20:04 +02:00
Kurt Van Dijck d125f0a1d3 outputs: show MPD error message on stderr 2015-05-02 14:36:02 +02:00
Jason Pleau c7f19755bd fix webport using the wrong variable in init scripts 2015-05-01 20:57:58 -04:00
Andrew Karpow 770c32a370 replaced deprecated drone.yml with travis-ci 2015-05-02 01:49:48 +02:00
Andy 8c916e2b74 Merge pull request #72 from jpleau/various_patches
various patches: manpage, remove external js, init scripts
2015-05-02 01:11:05 +02:00
Kurt Van Dijck c3ddc8318b outputs: clear possible error 2015-05-02 00:07:37 +02:00
Kurt Van Dijck 0c3ded1cf3 outputs: reduce duplicate code 2015-05-02 00:04:04 +02:00
Kurt Van Dijck 66ed2518a2 mpd_client: fix allocation of outputs 2015-05-01 23:33:07 +02:00
Jason Pleau 5abfdfda7b update init script and systemd service file
init script: depend on $remote_fs instead of $local_fs. Reason: /usr can
be mounted a remote filesystem. Also depend on mpd (instead of $mpd,
which doesn't seem to exist.. at least on my system)

Also provide a default config (which should be installed as
/etc/default/ympd)

This commit makes the systemd unit file as well as the init script load
values from this configuration file so the user can change ympd settings
easily when running it as a service.
2015-05-01 17:14:21 -04:00
Jason Pleau 3ef53f3cc2 webpage: remove respond.js
Calling outside resources is a breach of privacy, and prevents the page
from loading correctly if offline.
2015-05-01 17:06:57 -04:00
Jason Pleau 1035264d66 manpage: set section to 1 and update version 2015-05-01 17:06:09 -04:00
Andrew Karpow ade4ee3808 apply mg_set listening_port only once, fixes #71 2015-05-01 21:05:15 +02:00
Kurt Van Dijck d344ec05a9 add support for output enable/disable 2015-04-28 11:08:21 +02:00
Andrew Karpow caddebcec0 fixed memleak in mpd_set_password 2015-04-25 00:39:16 +02:00
Andrew Karpow 4ba3e0b70f removed %m formatstring, works now with openbsd, fixes #68 2015-04-25 00:35:01 +02:00
Andrew Karpow 3701a8510b add libmpdclient header location to gcc-search path, fixes openbsd builds 2015-04-24 23:38:39 +02:00
Andy 2e350f4a65 Merge pull request #67 from jpleau/update_mongoos_56
Update mongoos 56
2015-04-24 21:41:31 +02:00
Jason Pleau 19c6d7eb88 replace mg_iterate_over_connections with a loop with mg_next 2015-04-20 23:11:03 -04:00
Jason Pleau 7061015486 update mongoose to 5.6 2015-04-20 23:05:23 -04:00
Andy 3df5b36b97 Merge pull request #56 from warhog/master
Added ability to add streams
2015-03-19 23:08:15 +01:00
warhog 4d4ff2bdc2 changed order of menu entries 2015-03-06 12:41:26 +01:00
warhog 1c4e89def8 added ability to add streams 2015-03-06 12:40:14 +01:00
Andy ca40c44dd5 Merge pull request #52 from ajs124/master
Add crossfade support. Not sure about the icon/glyph though
2015-03-03 21:50:49 +01:00
Andy 1268cab3b3 Merge pull request #40 from iwanders/master
Change websocket URL to allow easy incorporation of different backends.
2015-03-03 21:49:46 +01:00
ajs124 3eb12e6ecd Add crossfade support. Not sure about the icon/glyph though 2015-02-17 15:45:26 +01:00
LaClaro df3ba1c04c Added more columns also to the search 2014-11-20 20:17:16 +01:00
Andrew Karpow e6e93a08c7 release build now installs assets to prefix
if build with dynamic assets
2014-11-11 21:13:11 +01:00
LaClaro 8b29d44496 Patched files to include more columns in browsing and queue mode 2014-11-11 18:52:05 +01:00
LaClaro f3aef08a7a Patched files to include more columns in browsing and queue mode 2014-11-11 18:50:21 +01:00
LaClaro 838237d854 Patched files to include more columns in browsing and queue mode 2014-11-11 18:41:39 +01:00
Ivor Wanders a5a4ac9461 Changes URL used for the websocket.
This change allows easier implementation of different backends because the websocket URL isn't identical to the webpage URL. This does not affect the functionality of the default C backend.
2014-11-03 20:01:05 +01:00
Andy aeaac3ecc3 Merge pull request #38 from jpleau/jquery
add jquery source file
2014-11-03 19:07:33 +01:00
Andy b9411a7134 Merge pull request #26 from KAMiKAZOW/patch-1
Create ympd.spec
2014-11-03 03:22:05 +01:00
Andy 9728aae69c Merge pull request #37 from jpleau/fix_mpd_port_argument
ympd.c: add a break statement for the mpd port argument
2014-11-02 13:13:04 +01:00
Jason Pleau 07b6ac7473 add jquery source file
This is to comply with the Debian Free Software Guidelines:
https://www.debian.org/social_contract#guidelines

ympd can still use the minified file, however we need the source files
to be included in the source package.
2014-10-29 18:25:07 -04:00
Jason Pleau 59d971dc1b ympd.c: add a break statement for the mpd port argument
Otherwise, passing -p tried to also bind the http server to MPD's port
(which was already in use by MPD...)
2014-10-28 22:48:08 -04:00
KAMiKAZOW d4f45558e9 Rename ympd.spec to contrib/ympd.spec 2014-10-29 03:08:59 +01:00
Andy 8b29371e4e Merge pull request #36 from jpleau/init_script
init.debian: correct typo in shebang and adjust default webport
2014-10-29 02:38:04 +01:00
Jason Pleau d8610584d4 init.debian: correct typo in shebang and adjust default webport
The default webport in the systemd unit is 8080, but the one in the init
script was 80.
2014-10-28 20:11:38 -04:00
Andrew Karpow dc15e3b0d7 add WITH_DYNAMIC_SERVING for theme developing 2014-10-27 22:12:10 +01:00
Andrew Karpow 2b5a4c6fa0 added mkdata.pl generator for cross-compiling, fixes #31 2014-10-19 22:58:03 +02:00
Andrew Karpow 912140c96c prepare for 1.2.3 release 2014-10-19 20:29:30 +02:00
Andrew Karpow 60d2392022 set mpd timeout only after connect, fixes #32 2014-10-19 20:27:11 +02:00
Andrew Karpow aa60cb8991 upgraded to mongoose 5.4, introducing ipv6 support 2014-10-19 19:52:23 +02:00
Andrew Karpow 87fdd34f87 make mkdata more portable, fixes #35 2014-10-19 16:45:49 +02:00
Andrew Karpow 5fd723c1db fixed CMake warning CMP0026 2014-10-19 16:35:16 +02:00
KAMiKAZOW 8b77500850 Create ympd.spec
Spec file to create RPM packages. Works under Fedora 19 and 20:
https://build.opensuse.org/package/show/home:KAMiKAZOW:Fedora/ympd
2014-07-30 06:34:54 +02:00
Christian Krafft 379a5ffce3 save some characters 2014-06-30 21:25:26 +02:00
Christian Krafft 718ac3024e make local playback controls better distinguishable from mpd controls by
reordering and grouping them. also clean up markup by removing
autoplay="false" which is not correct html5 

Signed-off-by: Christian Krafft <parabelboi@gmail.com>
2014-06-30 17:34:38 +02:00
Christian Krafft 645161bc8a add http-stream support, URL is hardcoded for now 2014-05-24 18:23:45 +02:00
Andy a98d760ddd Merge pull request #19 from ajs124/master
remove webkit prefix from notifications
2014-05-24 15:25:47 +02:00
ajs124 9f001aa264 change notification cookie from session to "permanent" 2014-05-24 03:12:51 +02:00
ajs124 0730673851 remove webkit prefix from Notifications, now working with firefox!
+ probably fix bug with undefined artist or album
2014-05-24 02:57:30 +02:00
Andrew Karpow a70d87f7c7 bumped version to 1.2.2 2014-05-09 14:10:14 +02:00
Andy 1e3dea473c Merge pull request #14 from phmongeau/master
make service environment file optional
2014-04-23 17:31:05 +02:00
Philippe Mongeau 5659a1a86d make service environment file optional 2014-04-23 10:47:25 -04:00
Andrew Karpow 25d54f68d6 drop privliges after port binding, fixes #12 2014-04-23 12:22:31 +02:00
Andy fd140e210e Merge pull request #13 from kingcody/hotfix/prev-next-swap
fix prev and next buttons
2014-04-23 12:03:17 +02:00
Cody Mize 11e3dbefb0 fix prev and next buttons; was swapped 2014-04-23 03:13:07 -04:00
Andy acc5855e17 Merge pull request #11 from Nighoo/typo-1
fix some typos
2014-04-15 20:59:50 +02:00
Nico Suhl 712b3dc251 fix some typos 2014-04-15 19:16:04 +02:00
Andy 4ad51d11f3 Merge pull request #9 from TheReverend403/patch-1
fixed typo in index.html
2014-04-15 14:32:52 +02:00
Lee Watson e516ddb882 Ermahgerd! Werbserver!
Yeah, typo.
2014-04-15 12:41:48 +01:00
Andy 237de050ba Merge pull request #8 from Kernald/systemd-unit-config
Allow the sytemd unit to read a configuration file
2014-04-13 22:37:43 +02:00
Marc Plano-Lesay bf96db2ba3 Allow the sytemd unit to read a configuration file 2014-04-12 19:45:40 +02:00
Andrew Karpow 3751c6ad98 release 1.2.1 2014-03-31 17:55:40 +02:00
engine d5f4394a40 increased mpd timeout to 10 seconds
Signed-off-by: Andrew Karpow <andy@ndyk.de>
2014-03-31 16:19:47 +02:00
othmar52 dcb489d764 bugfix timeout when using the searchfield
Signed-off-by: Andrew Karpow <andy@ndyk.de>
2014-03-31 16:19:39 +02:00
Andrew Karpow 409150933d added mkdata dependency properly, fixes #7 2014-03-18 04:01:39 +01:00
Andrew Karpow fd3a4e183a Readme adaptions for 1.2.0 release 2014-03-18 01:45:58 +01:00
Andrew Karpow 14e807850c Merge branch 'mongoose' 2014-03-18 01:30:01 +01:00
Andrew Karpow 1edb663071 add badge 2014-03-11 21:08:21 +01:00
Andrew Karpow 5ccb6fe21e updated readme.md 2014-03-08 21:14:02 +01:00
Andrew Karpow 75e4d6a22e updated initscript 2014-03-08 20:38:14 +01:00
Andrew Karpow d4728248f0 updated manpage 2014-03-08 20:37:03 +01:00
Andrew Karpow 6bf4379eb8 fixed password remove 2014-03-08 20:33:22 +01:00
Andrew Karpow b75dadf7a9 removed perl generator, added c generator 2014-03-08 20:32:54 +01:00
Andrew Karpow 35ab38d0e2 fixed osx scanf behaviour, notifications 2014-03-08 12:31:22 +01:00
Andrew Karpow b9a4d83130 better json generator, various fixups 2014-03-08 12:30:49 +01:00
Andrew Karpow 38b4544542 replaces libwebsockets with mongoose, changed licese to gpl
add search support
add playlist support
various fixups
C Cleanup
2014-03-08 12:30:49 +01:00
Andrew Karpow 160386b357 added drone.yml for ci build 2014-03-08 12:30:49 +01:00
Andrew Karpow 79e38e7edd initial mongoose checkin 2014-03-08 12:30:48 +01:00
Andrew Karpow 5920d9f1bf fix settings modal hiding on keypress 2014-03-08 12:30:48 +01:00
Andrew Karpow 6b6622988d updated bootstrap to 3.1 2014-03-08 12:30:48 +01:00
Andrew Karpow 8c49b2a877 add settings modal dialog 2014-03-08 12:30:48 +01:00
Philippe Mongeau 6f8d5ef732 mpd_get_title: call basename only when using path
Otherwise, traks like "Morning Bell/Amnesiac" get trimmed to "Amnesiac"
2014-03-08 12:30:48 +01:00
Philippe Mongeau dcc4823bc3 add systemd service file 2014-03-08 12:30:48 +01:00
Andrew Karpow a9c907d6b1 remove installation of debian-specific init.d script 2014-03-08 12:30:48 +01:00
39 changed files with 19469 additions and 1525 deletions

168
.clang-format Normal file
View File

@ -0,0 +1,168 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: true
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
- Regex: '^<.*'
Priority: 2
SortPriority: 0
- Regex: '.*'
Priority: 3
SortPriority: 0
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
---

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Build Artifacts
build/

13
.prettierignore Normal file
View File

@ -0,0 +1,13 @@
# Used by Prettier to ignore certain files and folders completely.
# See https://prettier.io/docs/en/ignore.html for details.
# Ignore build and system artifacts
build/
cmake/
contrib/
# Ignore all 3rd party libraries
**/bootstrap*
**/jquery*
**/modernizr*
**/sammy*

20
.prettierrc.json Normal file
View File

@ -0,0 +1,20 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": true,
"singleQuote": true,
"overrides": [
{
"files": ["*.html"],
"options": {
"tabWidth": 2
}
},
{
"files": ["*.css"],
"options": {
"tabWidth": 2
}
}
]
}

17
.travis.yml Normal file
View File

@ -0,0 +1,17 @@
language: c
sudo: required
dist: trusty
compiler:
- gcc
- clang
before_install:
- sudo apt-get -qq update
- sudo apt-get install -y libmpdclient-dev cmake
- mkdir build
- cd build
- cmake -D CMAKE_BUILD_TYPE=DEBUG ..
script: make

View File

@ -1,57 +1,80 @@
cmake_minimum_required(VERSION 2.6)
project (ympd)
project (ympd C)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
set(CPACK_PACKAGE_VERSION_MAJOR "1")
set(CPACK_PACKAGE_VERSION_MINOR "0")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_GENERATOR "DEB;RPM;TGZ")
set(CPACK_SOURCE_GENERATOR "TBZ2")
set(DEBIAN_PACKAGE_SECTION "web")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MPD web client based on Websockets and Bootstrap")
set(CPACK_PACKAGE_CONTACT "Andrew Karpow <andy@ympd.org>")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "andy@ndyk.de")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libssl1.0.0,libmpdclient2")
option(WITH_STATIC_WEBSOCKETS "Build with static libwebsockets library" ON)
option(WITH_MPD_HOST_CHANGE "Let users of the web frontend change the MPD Host" ON)
find_package(LibMPDClient REQUIRED)
find_package(LibWebSockets REQUIRED)
if(WITH_STATIC_WEBSOCKETS)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
set(CPACK_PACKAGE_VERSION_MINOR "2")
set(CPACK_PACKAGE_VERSION_PATCH "3")
if(CMAKE_BUILD_TYPE MATCHES RELEASE)
set(ASSETS_PATH "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/htdocs")
else()
set(ASSETS_PATH "${PROJECT_SOURCE_DIR}/htdocs")
endif()
configure_file(${PROJECT_SOURCE_DIR}/src/config.h.in
${PROJECT_BINARY_DIR}/config.h)
include_directories(${PROJECT_BINARY_DIR} ${LIBWEBSOCKETS_INCLUDE_DIR})
option(WITH_MPD_HOST_CHANGE "Let users of the web frontend change the MPD Host" ON)
option(WITH_DYNAMIC_ASSETS "Serve assets dynamically (e.g for development/packaging)" OFF)
option(WITH_IPV6 "enable IPv6 support" ON)
option(WITH_SSL "enable SSL support" ON)
find_package(LibMPDClient REQUIRED)
find_package(Threads REQUIRED)
configure_file(src/config.h.in ${PROJECT_BINARY_DIR}/config.h)
include_directories(${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${LIBMPDCLIENT_INCLUDE_DIR})
include(CheckCSourceCompiles)
include(CPack)
set(CMAKE_C_FLAGS "-std=gnu99 -Wall")
set(CMAKE_C_FLAGS_DEBUG "-ggdb -pedantic")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -pedantic")
if(WITH_IPV6)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS NS_ENABLE_IPV6)
endif()
if(WITH_SSL)
find_package(OpenSSL REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIR})
# list(APPEND LIB_LIST ${OPENSSL_LIBRARIES})
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS NS_ENABLE_SSL)
endif()
file(GLOB RESOURCES
RELATIVE ${PROJECT_SOURCE_DIR}
htdocs/js/*
htdocs/assets/*
htdocs/css/*.css
htdocs/fonts/*
htdocs/index.html
htdocs/player.html
)
set(SOURCES
src/ympd.c
src/http_server.c
src/mpd_client.c
src/mongoose.c
src/json_encode.c
)
add_executable(ympd ${SOURCES})
if(NOT WITH_DYNAMIC_ASSETS)
if(CMAKE_CROSSCOMPILING)
set(MKDATA_EXE ${PROJECT_SOURCE_DIR}/tools/mkdata.pl)
else()
set(MKDATA_EXE $<TARGET_FILE:mkdata>)
set(MKDATA_TARGET mkdata)
add_executable(mkdata tools/mkdata.c)
endif()
# TODO: use generator expressions introduced to CMake 2.8.12, too fresh yet
if(WITH_STATIC_WEBSOCKETS)
find_library(LIBWEBSOCKETS_LIBRARY_STATIC libwebsockets.a)
target_link_libraries(ympd ${LIBMPDCLIENT_LIBRARY}
${LIBWEBSOCKETS_LIBRARY_STATIC} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES})
else()
target_link_libraries(ympd ${LIBMPDCLIENT_LIBRARY}
${LIBWEBSOCKETS_LIBRARIES})
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/assets.c
COMMAND ${MKDATA_EXE} ${RESOURCES} > ${PROJECT_BINARY_DIR}/assets.c
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS ${RESOURCES} ${MKDATA_TARGET}
)
list(APPEND SOURCES src/http_server.c assets.c)
endif()
add_executable(ympd ${SOURCES})
target_link_libraries(ympd ${LIBMPDCLIENT_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES})
install(TARGETS ympd DESTINATION bin)
install(FILES ympd.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1)
install(DIRECTORY htdocs DESTINATION share/${PROJECT_NAME})
if(WITH_DYNAMIC_ASSETS)
install(DIRECTORY htdocs DESTINATION share/${PROJECT_NAME})
endif()

32
DEVELOPMENT.md Normal file
View File

@ -0,0 +1,32 @@
# Development Notes
## Code Formatting
The project has been formatted with [prettier.io](https://prettier.io/) for the HTML, JavaScript, CSS, and Markdown files. See the configuration file [.prettierrc.json](./.prettierrc.json) and the ignore file [.prettierignore](./.prettierignore) for details. If `prettier` is installed globally, there's no need to provide the various `npm`-type dependencies in the project. Various editors may provide plugins that can use this configuration without having to install `npm` and `prettier` manually.
Manual Usage:
```bash
> npx prettier --write .
```
The C source and header files have been formatted with `clang-format`. There's no easy way to manually execute the formatter on all of the C files at the same time. The clang format is based off of the 'Google' style with ajdustments to make the changes not as disruptive. See [.clang-format](./.clang-format) file for the formatting rules. Various editors should be able to automatically format the source on save.
The only files formatted are the non-third party library files.
Manual Usage:
```bash
> clang-format -i -style=file <filename>
```
Manually formatted files:
- http_server.c
- http_server.h
- json_encode.h
- mpd_client.c
- mpd_client.h
- ympd.c
For help with the rules, see [Clang Format Configurator](https://zed0.co.uk/clang-format-configurator/) for an interactive tool and [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) for the rules reference.

13
Dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM alpine:3.5
WORKDIR /app/build
COPY . /app
RUN apk add --no-cache g++ make cmake libmpdclient-dev openssl-dev
RUN cmake ..
RUN make
FROM alpine:3.5
RUN apk add --no-cache libmpdclient openssl
EXPOSE 8080
COPY --from=0 /app/build/ympd /usr/bin/ympd
COPY --from=0 /app/build/mkdata /usr/bin/mkdata
CMD ympd

356
LICENSE
View File

@ -1,22 +1,340 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Preamble
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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; either version 2 of the License, or
(at your option) any later version.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,3 +1,4 @@
[![Build Status](https://travis-ci.org/notandy/ympd.svg)](https://travis-ci.org/notandy/ympd)
ympd
====
@ -5,24 +6,54 @@ Standalone MPD Web GUI written in C, utilizing Websockets and Bootstrap/JS
http://www.ympd.org
![ScreenShot](http://www.ympd.org/assets/ympd_github.png)
Dependencies
------------
- libwebsockets master branch: http://git.libwebsockets.org/cgi-bin/cgit/libwebsockets
- libmpdclient 2: http://www.musicpd.org/libs/libmpdclient/
- cmake 2.6: http://cmake.org/
- Optional: OpenSSL for SSL support in libwebsockets webserver
## Dependencies
Unix Build Instructions
-----------------------
- libmpdclient 2: http://www.musicpd.org/libs/libmpdclient/
- cmake 2.6: http://cmake.org/
- OpenSSL: https://www.openssl.org/
1. Install Dependencies, cmake, openssl and libmpdclient are available from all major distributions.
2. create build directory ```cd /path/to/src; mkdir build; cd build```
3. create makefile ```cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr```
4. build ```make```
5. install ```sudo make install``` or build debian package ```cpack -G DEB; sudo dpkg -i ympd*.deb```
## Unix Build Instructions
Copyright
---------
1. install dependencies. cmake, libmpdclient (dev), and OpenSSL (dev) are available from all major distributions.
2. create build directory `cd /path/to/src; mkdir build; cd build`
3. create makefile `cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr`
4. build `make`
5. install `sudo make install` or just run with `./ympd`
## Run flags
```
Usage: ./ympd [OPTION]...
-D, --digest <htdigest> path to htdigest file for authorization
(realm ympd) [no authorization]
-h, --host <host> connect to mpd at host [localhost]
-p, --port <port> connect to mpd at port [6600]
-w, --webport [ip:]<port> listen interface/port for webserver [8080]
-u, --user <username> drop priviliges to user after socket bind
-V, --version get version
--help this help
```
## SSL Support
To run ympd with SSL support:
- create a certificate (key and cert in the same file), example:
```
# openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 1000 -nodes
# cat key.pem cert.pem > ssl.pem
```
- tell ympd to use a webport using SSL and where to find the certificate:
```
# ./ympd -w "ssl://8081:/path/to/ssl.pem"
```
## Copyright
2013-2014 <andy@ndyk.de>

View File

@ -1,35 +0,0 @@
# This module tries to find libWebsockets library and include files
#
# LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets
# LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h
# LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so
# LIBWEBSOCKETS_LIBRARIES, the library to link against
#
# This currently works probably only for Linux
find_package(PkgConfig)
pkg_check_modules(PC_LIBWEBSOCKETS QUIET libwebsockets)
set(LIBWEBSOCKETS_DEFINITIONS ${PC_LIBWEBSOCKETS_CFLAGS_OTHER})
find_path(LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h
HINTS ${PC_LIBWEBSOCKETS_INCLUDEDIR} ${PC_LIBWEBSOCKETS_INCLUDE_DIRS}
)
find_library(LIBWEBSOCKETS_LIBRARY websockets
HINTS ${PC_LIBWEBSOCKETS_LIBDIR} ${PC_LIBWEBSOCKETS_LIBRARY_DIRS}
)
set(LIBWEBSOCKETS_LIBRARIES ${LIBWEBSOCKETS_LIBRARY})
set(LIBWEBSOCKETS_INCLUDE_DIRS ${LIBWEBSOCKETS_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBWEBSOCKETS_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(LibWebSockets DEFAULT_MSG
LIBWEBSOCKETS_LIBRARY LIBWEBSOCKETS_INCLUDE_DIR
)
mark_as_advanced(
LIBWEBSOCKETS_LIBRARY
LIBWEBSOCKETS_INCLUDE_DIR
)

View File

@ -1,8 +1,8 @@
#/bin/sh
#!/bin/sh
### BEGIN INIT INFO
# Provides: ympd
# Required-Start: $local_fs $mpd
# Required-Stop: $local_fs $mpd
# Required-Start: $remote_fs mpd
# Required-Stop: $remote_fs mpd
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Daemonized version of ympd.
@ -20,9 +20,13 @@ PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
LOG_OUT=/var/log/$NAME.out
LOG_ERR=/var/log/$NAME.err
YMPD_USER=mpd
YMPD_GROUP=mpd
DAEMON_OPT="--uid $YMPD_USER --gid $YMPD_GROUP --webport 80"
YMPD_USER=nobody
MPD_HOST=localhost
MPD_PORT=6600
WEB_PORT=8080
#DIGEST=--digest /path/to/htdigest
#LOCALPORT=8080
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
@ -33,6 +37,8 @@ DAEMON_OPT="--uid $YMPD_USER --gid $YMPD_GROUP --webport 80"
# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS
DAEMON_OPT="--user $YMPD_USER --mpdpass '$MPD_PASSWORD' --webport $WEB_PORT --host $MPD_HOST --port $MPD_PORT $DIGEST $LOCALPORT"
do_start()
{
start-stop-daemon --start --background --quiet --pidfile $PIDFILE --make-pidfile \

6
contrib/ympd.default Normal file
View File

@ -0,0 +1,6 @@
MPD_HOST=localhost
MPD_PORT=6600
MPD_PASSWORD=
WEB_PORT=8080
#DIGEST=--digest /path/to/htdigest
#LOCALPORT=--localport 8080

28
contrib/ympd.freebsd Executable file
View File

@ -0,0 +1,28 @@
#!/bin/sh
# PROVIDE: ympd
# REQUIRE: DAEMON musicpd
# KEYWORD: shutdown
# Add the following line to /etc/rc.conf to enable ympd:
#
# ympd_enable="YES"
. /etc/rc.subr
name="ympd"
rcvar="${name}_enable"
command="/usr/local/bin/${name}"
pidfile="/var/run/${name}.pid"
start_cmd="ympd_start"
load_rc_config "${name}"
: ${ympd_enable:="NO"}
ympd_start()
{
check_startmsgs && echo "Starting ${name}."
/usr/sbin/daemon -f -p "${pidfile}" "${command}" "${rc_flags}"
}
run_rc_command "$1"

View File

@ -3,7 +3,35 @@ Description=ympd server daemon
Requires=network.target local-fs.target
[Service]
ExecStart=/usr/bin/ympd
User=nobody
DynamicUser=yes
MountAPIVFS=yes
RemoveIPC=yes
CapabilityBoundingSet=
LockPersonality=yes
PrivateUsers=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
NoNewPrivileges=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
ProtectHome=yes
Environment=MPD_HOST=localhost
Environment=MPD_PORT=6600
Environment=MPD_PASSWORD=
Environment=WEB_PORT=8080
Environment=YMPD_USER=nobody
Environment=DIGEST=
Environment=LOCALPORT=
EnvironmentFile=/etc/default/ympd
ExecStart=/usr/bin/ympd --user $USER --webport $WEB_PORT --host $MPD_HOST --port $MPD_PORT $DIGEST $LOCALPORT
Type=simple
[Install]

71
contrib/ympd.spec Normal file
View File

@ -0,0 +1,71 @@
#
# spec file for package ympd
#
# Copyright (c) 2014 Markus S. <kamikazow@web.de>
#
# This file 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, either version 2 of the License, or
# (at your option) any later version.
#
# 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, see <http://www.gnu.org/licenses/>.
Name: ympd
Version: 1.2.2
Release: 0%{?dist}
Summary: ympd is a lightweight MPD (Music Player Daemon) web client
Group: Applications/Multimedia
License: GPL
URL: http://www.ympd.org/
# For this spec file to work, the ympd sources must be located in a directory
# named ympd-1.2.2 (with "1.2.2" being the version number defined above).
# If the sources are compressed in another format than ZIP, change the
# file extension accordingly.
Source0: %{name}-%{version}.zip
# Package names only verified with Fedora.
# Should the packages in your distro be named dirrerently,
# see http://en.opensuse.org/openSUSE:Build_Service_cross_distribution_howto
# %if 0%{?fedora}
BuildRequires: cmake
BuildRequires: unzip
BuildRequires: libmpdclient-devel
Requires: libmpdclient
# %endif
%description
ympd is a lightweight MPD (Music Player Daemon) web client that runs without
a dedicated webserver or interpreters like PHP, NodeJS or Ruby.
It's tuned for minimal resource usage and requires only very litte dependencies.
%prep
%setup -q
%build
mkdir build
pushd build
%cmake .. -DCMAKE_INSTALL_PREFIX_PATH=%{_prefix}
make PREFIX=%{_prefix} %{?_smp_mflags}
popd
%install
pushd build
%{make_install}
popd
%files
%defattr(-,root,root,-)
%doc LICENSE README.md
%{_bindir}/%{name}
%{_mandir}/man[^3]/*
%changelog

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,27 +9,60 @@ body {
#volumeslider {
width: 150px;
float: left;
}
#volumeslider .progress {
margin-bottom: 0;
}
button {
overflow: hidden;
}
#volume-icon {
float: left;
margin-right: 10px;
margin-top: 2px;
}
#volume-number {
float: right;
margin-top: 2px;
margin-left: 10px;
}
#love {
float: right;
}
#love > button > span {
color: red;
}
#breadcrump {
display: block;
overflow: auto;
white-space: nowrap;
}
#breadcrump > li > a {
cursor: pointer;
}
#counter {
font-size: 24px;
margin-top: -6px;
margin-left: 10px;
min-width: 50px;
font-size: 24px;
margin-top: -6px;
margin-left: 10px;
min-width: 50px;
}
#search {
margin-right: -10px;
}
.btn-group-hover {
opacity: 20%;
opacity: 20%;
}
.btn:active,
@ -37,29 +70,77 @@ body {
background-image: none;
outline: 0;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
color: #428bca;
background-color: #fdfdfd;
border-color: #adadad;
}
@media (max-width: 1199px) {
#btn-responsive-block > .btn {
padding: 6px 12px;
font-size: 14px;
border-radius: 4px;
#btn-responsive-block > .btn {
padding: 6px 12px;
font-size: 14px;
border-radius: 4px;
}
}
#salamisandwich td:nth-child(3), th:nth-child(3) {
h1 {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
td:nth-child(4),
th:nth-child(4) {
/* This *has* to be placed before
any t[dh]:nth-last-child(2) for
the override to work. */
min-width: 50%;
}
td:nth-last-child(2),
th:nth-last-child(2) {
text-align: right;
width: 4em;
}
#salamisandwich td:nth-child(4) span {
font-size: 90%;
display: block;
}
td:nth-child(2),
td:nth-child(3) {
min-width: 25%;
max-width: 10em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media only screen and (max-width: 600px) {
td:nth-child(2),
td:nth-child(3) {
min-width: 0;
max-width: 0;
}
td:nth-child(4),
th:nth-child(4) {
min-width: 10%;
white-space: normal;
}
}
tbody {
cursor: pointer;
}
td:last-child, td:first-child {
td:last-child,
td:first-child {
width: 30px;
}
@ -68,7 +149,7 @@ td:last-child, td:first-child {
z-index: 9999;
}
/* Positioning */
/* Positioning */
.notifications.top-right {
right: 10px;
top: 60px;
@ -79,4 +160,30 @@ td:last-child, td:first-child {
position: relative;
z-index: 9999;
margin: 5px 0px;
}
}
button {
overflow: hidden;
}
#trashmode span:last-child {
display: inline-block;
text-align: left;
width: 2.8em;
}
#filter > a.active {
font-weight: bold;
pointer-events: none;
cursor: default;
text-decoration: none;
color: black;
}
@media screen and (min-width: 992px) {
.sticky {
position: sticky;
top: 55px;
z-index: 99;
}
}

View File

@ -1,223 +1,597 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="ympd - fast and lightweight MPD webclient">
<meta name="author" content="andy@ndyk.de">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="ympd - fast and lightweight MPD webclient"
/>
<meta name="author" content="andy@ndyk.de" />
<title>ympd</title>
<title>ympd</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.css" rel="stylesheet">
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.css" rel="stylesheet" />
<link href="css/bootstrap-theme.css" rel="stylesheet" />
<!-- Custom styles for this template -->
<link href="css/mpd.css" rel="stylesheet">
<link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
<!-- Custom styles for this template -->
<link href="css/mpd.css" rel="stylesheet" />
<link
href="assets/favicon.ico"
rel="shortcut icon"
type="image/vnd.microsoft.icon"
/>
<script src="js/modernizr-custom.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button
type="button"
class="navbar-toggle"
data-toggle="collapse"
data-target=".navbar-collapse"
>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"
><span class="glyphicon glyphicon-play-circle"></span> ympd</a
>
</div>
<div class="collapse navbar-collapse">
<ul id="nav_links" class="nav navbar-nav">
<li id="queue"><a href="#/">Queue</a></li>
<li id="browse"><a href="#/browse/0/">Browse</a></li>
<li>
<a href="#" data-toggle="modal" data-target="#addstream"
>Add Stream</a
>
</li>
<li>
<a
href="#"
data-toggle="modal"
data-target="#settings"
onclick="getHost();"
>Settings</a
>
</li>
</ul>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"><span class="glyphicon glyphicon-play-circle"></span> ympd</a>
</div>
<div class="collapse navbar-collapse">
<ul id="nav_links" class="nav navbar-nav">
<li id="playlist"><a href="#/">Playlist</a></li>
<li id="browse"><a href="#/browse/">Browse database</a></li>
<li><a href="#" data-toggle="modal" data-target="#about" onclick="getVersion();">About</a></li>
<li><a href="#" data-toggle="modal" data-target="#settings" onclick="getHost();">Settings</a></li>
</ul>
<div class="btn-toolbar navbar-btn navbar-right" role="toolbar">
<div class="btn-group">
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_NEXT');">
<span class="glyphicon glyphicon-backward"></span>
</button>
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_STOP');">
<span id="stop-icon" class="glyphicon glyphicon-stop"></span>
</button>
<button type="button" class="btn btn-default" onclick="clickPlay();">
<span id="play-icon" class="glyphicon glyphicon-pause"></span>
</button>
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_PREV');">
<span class="glyphicon glyphicon-forward"></span>
</button>
</div>
<div class="btn-group">
<div class="btn btn-toolbar btn-default">
<span id="volume-icon" class="glyphicon glyphicon-volume-up"></span>
<div id="volumeslider"></div>
<div class="btn-toolbar navbar-btn navbar-right" role="toolbar">
<div class="btn-group">
<button
type="button"
class="btn btn-default"
onclick="socket.send('MPD_API_SET_PREV');"
>
<span class="glyphicon glyphicon-backward"></span>
</button>
<button
type="button"
class="btn btn-default"
onclick="socket.send('MPD_API_SET_STOP');"
>
<span id="stop-icon" class="glyphicon glyphicon-stop"></span>
</button>
<button
type="button"
class="btn btn-default"
onclick="clickPlay();"
>
<span id="play-icon" class="glyphicon glyphicon-pause"></span>
</button>
<button
type="button"
class="btn btn-default"
onclick="socket.send('MPD_API_SET_NEXT');"
>
<span class="glyphicon glyphicon-forward"></span>
</button>
</div>
<div class="btn-group" role="group">
<button
type="button"
class="btn btn-default"
onclick="clickLocalPlay()"
>
<audio id="player" preload="none"></audio>
<span
id="localplay-icon"
class="glyphicon glyphicon-play"
></span>
</button>
</div>
<div class="btn-group" role="group" id="volume-group">
<div class="btn btn-toolbar btn-default">
<span
id="volume-icon"
class="glyphicon glyphicon-volume-up"
></span>
<div id="volumeslider"></div>
<span id="volume-number"></span>
</div>
</div>
</div>
</div>
</div><!--/.nav-collapse -->
</div>
</div>
<div class="container starter-template">
<div class="row">
<div class="col-md-10 col-xs-12">
<div class="notifications top-right"></div>
<div class="panel panel-primary">
<!-- Default panel contents -->
<div id="panel-heading" class="panel-heading">Playlist</div>
<div class="panel-body">
<h1>
<span id="track-icon" class="glyphicon glyphicon-play"></span>
<span id="currenttrack"></span>
</h1>
<h4>
<span id="album" class="text"></span>
<span id="artist" class="text pull-right"></span>
</h4>
<p id="counter" class="text pull-right">&nbsp;&nbsp;</p>
<div id="progressbar"></div>
</div><!-- /.panel-body -->
<ol id="breadcrump" class="breadcrumb">
</ol>
<!-- Table -->
<table id="salamisandwich" class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Duration</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div><!-- /.panel -->
</div><!-- /.col-md-10 -->
<div class="col-md-2 col-xs-12" >
<div class="btn-toolbar">
<div class="btn-group-vertical btn-block btn-group-lg" data-toggle="buttons">
<button id="btnrandom" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-random"></span> Random
</button>
<button id="btnconsume" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-fire"></span> Consume
</button>
<button id="btnsingle" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-star"></span> Single
</button>
<button id="btnrepeat" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-repeat"></span> Repeat
</button>
</div>
<div id="btn-responsive-block" class="btn-group-vertical btn-block btn-group-lg">
<button type="button" class="btn btn-default" onclick="updateDB();">
<span class="glyphicon glyphicon-refresh"></span> Update DB
</button>
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_RM_ALL');">
<span class="glyphicon glyphicon-trash"></span> Clear queue
</button>
</div>
<div id="btn-responsive-block" class="btn-group-vertical btn-block btn-group-lg" data-toggle="buttons">
<button type="button" class="btn btn-default" id="btnnotify">
<span class="glyphicon glyphicon-comment"></span> Notifications
</button>
</div>
</div>
</div><!-- /.col-md-2 -->
</div><!-- /.row -->
</div><!-- /.container -->
<!-- Modal -->
<div class="modal fade" id="about" tabindex="-1" role="dialog" aria-labelledby="aboutLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h2 class="modal-title" id="aboutLabel">About</h2>
</div>
<div class="modal-body">
<h4><a href="http://www.ympd.org"><span class="glyphicon glyphicon-play-circle"></span> ympd</a>&nbsp;&nbsp;&nbsp;<small>MPD Web GUI - written in C, utilizing Websockets and Bootstrap/JS</small></h4>
<p>
ympd is a lightweight MPD (Music Player Daemon) web client that runs without a dedicated werbserver or interpreters like PHP, NodeJS or Ruby. It's tuned for minimal resource usage and requires only very litte dependencies.</p>
<p class="text-muted">
ympd <span id="ympd_version"></span><br/>
libmpdclient <span id="mpd_version"></span><br/>
</p>
<h5>ympd uses following excellent software:</h5>
<h6><a href="http://libwebsockets.org">libWebSockets</a> <small>LGPL2.1 + static link exception</small></h6>
<h6><a href="http://www.musicpd.org/libs/libmpdclient/">libMPDClient</a> <small>BSD License</small></h6>
<br/>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- Modal -->
<div class="modal fade" id="settings" tabindex="-1" role="dialog" aria-labelledby="settingsLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h2 class="modal-title" id="settingsLabel"><span class="glyphicon glyphicon-wrench"></span> Settings</h2>
</div>
<div class="modal-body">
<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>
<form id="search" class="navbar-form navbar-right" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" />
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="setHost();">Save</button>
<!--/.nav-collapse -->
</div>
</div>
<div class="container starter-template">
<div class="row">
<div class="col-md-10 col-xs-12">
<div class="notifications top-right"></div>
<div class="panel panel-primary sticky">
<!-- Default panel contents -->
<div class="panel-body">
<h1>
<span
id="track-icon"
onclick="clickPlay();"
class="glyphicon glyphicon-play"
></span>
<span id="currenttrack"></span>
<span id="love">
<button
id="btnlove"
type="button"
class="btn btn-default"
onclick="clickLove();"
>
<span class="glyphicon glyphicon-heart"></span></button
></span>
</h1>
<h4>
<span id="artist" class="text"></span>
<span id="album" class="text pull-right"></span>
</h4>
<p id="counter" class="text pull-right">&nbsp;&nbsp;</p>
<div id="progressbar"></div>
</div>
</div>
<!-- /.panel -->
<!-- /.panel-body -->
<div class="panel panel-primary">
<div class="panel-heading">
<b id="panel-heading">Queue</b>
<b id="panel-heading-info" class="text pull-right"></b>
</div>
<ol id="breadcrump" class="breadcrumb"></ol>
<div class="col-md-12" id="filter"></div>
<!-- Table -->
<table id="salamisandwich" class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Artist</th>
<th>Album</th>
<th>Title</th>
<th>Length</th>
<th><div style="width: 15px"></div></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<!-- /.panel -->
<ul class="pager">
<li id="prev" class="page-btn hide"><a href="">Previous</a></li>
<li id="next" class="page-btn"><a href="">Next</a></li>
</ul>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<!-- /.col-md-10 -->
<div class="col-md-2 col-xs-12 sticky">
<div class="btn-toolbar">
<div
class="btn-group-vertical btn-block btn-group-lg"
data-toggle="buttons"
>
<button id="btnrandom" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-random"></span> Random
</button>
<button id="btnconsume" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-fire"></span> Consume
</button>
<button id="btnsingle" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-star"></span> Single
</button>
<button id="btncrossfade" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-link"></span> Crossfade
</button>
<button id="btnrepeat" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-repeat"></span> Repeat
</button>
</div>
<div
id="btn-outputs-block"
class="btn-group-vertical btn-block btn-group-lg"
></div>
<div
id="trashmode"
class="btn-group-vertical btn-block btn-group-lg"
data-toggle="radio"
>
<button id="btntrashmodeup" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-chevron-up"></span>
<span class="glyphicon glyphicon-trash"></span> <span>Up</span>
</button>
<button
id="btntrashmodesingle"
type="button"
class="btn btn-default active"
>
<span class="glyphicon glyphicon-star-empty"></span>
<span class="glyphicon glyphicon-trash"></span>
<span>Single</span>
</button>
<button
id="btntrashmodedown"
type="button"
class="btn btn-default"
>
<span class="glyphicon glyphicon-chevron-down"></span>
<span class="glyphicon glyphicon-trash"></span>
<span>Down</span>
</button>
</div>
<!-- Bootstrap core JavaScript
<div
id="btn-responsive-block"
class="btn-group-vertical btn-block btn-group-lg"
>
<button
type="button"
class="btn btn-default"
onclick="socket.send('MPD_API_RM_ALL');"
>
<span class="glyphicon glyphicon-trash"></span> Clear Queue
</button>
<a
href="#"
data-toggle="modal"
data-target="#savequeue"
class="btn btn-default"
>
<span class="glyphicon glyphicon-save"></span> Save Queue
</a>
</div>
</div>
</div>
<!-- /.col-md-2 -->
</div>
<!-- /.row -->
</div>
<!-- /.container -->
<!-- Modal -->
<div
class="modal fade"
id="settings"
tabindex="-1"
role="dialog"
aria-labelledby="settingsLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-hidden="true"
>
&times;
</button>
<h2 class="modal-title" id="settingsLabel">
<span class="glyphicon glyphicon-wrench"></span> Settings
</h2>
</div>
<div class="modal-body">
<h4>
<a href="http://www.ympd.org"
><span class="glyphicon glyphicon-play-circle"></span> ympd</a
>&nbsp;&nbsp;&nbsp;<small
>MPD Web GUI - written in C, utilizing Websockets and
Bootstrap/JS</small
>
</h4>
<p>
ympd is a lightweight MPD (Music Player Daemon) web client that
runs without a dedicated webserver or interpreters like PHP,
NodeJS or Ruby. It's tuned for minimal resource usage and requires
only very litte dependencies.
</p>
<h5>ympd uses following excellent software:</h5>
<h6>
<a href="http://cesanta.com/docs.html">Mongoose</a>
<small>GPLv2</small>
</h6>
<h6>
<a href="http://www.musicpd.org/libs/libmpdclient/"
>libMPDClient</a
>
<small>BSD License</small>
</h6>
<hr />
<div class="row">
<div class="form-group col-md-6">
<button
type="button"
class="btn btn-default btn-block"
onclick="updateDB();"
>
<span class="glyphicon glyphicon-refresh"></span> Update
Database
</button>
</div>
<div class="form-group col-md-6" data-toggle="buttons">
<button
type="button"
class="btn btn-default btn-block"
id="btnnotify"
>
<span class="glyphicon glyphicon-comment"></span> Enable
Notifications
</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">
&times;
</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 class="row">
<div class="form-group col-md-12" data-toggle="buttons">
<button
type="button"
class="btn btn-default btn-block"
id="btnautoplay"
>
<span class="glyphicon glyphicon-play"></span> Autoplay stream
in this browser when mpd is playing
</button>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
<button
type="button"
class="btn btn-default"
onclick="confirmSettings();"
>
Save
</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<!-- Modal -->
<div
class="modal fade"
id="addstream"
tabindex="-1"
role="dialog"
aria-labelledby="addstreamLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-hidden="true"
>
&times;
</button>
<h2 class="modal-title" id="addstreamLabel">
<span class="glyphicon glyphicon-wrench"></span> Add Stream
</h2>
</div>
<div class="modal-body">
<form role="form">
<div class="row">
<div class="form-group col-md-12">
<label class="control-label" for="streamurl"
>Stream URL</label
>
<input type="text" class="form-control" id="streamurl" />
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
<button
type="button"
class="btn btn-default"
onclick="addStream();"
>
Add Stream
</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<div
class="modal fade"
id="savequeue"
tabindex="-1"
role="dialog"
aria-labelledby="savequeueLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-hidden="true"
>
&times;
</button>
<h2 class="modal-title" id="savequeueLabel">
<span class="glyphicon glyphicon-wrench"></span> Save Queue
</h2>
</div>
<div class="modal-body">
<form role="form">
<div class="row">
<div class="form-group col-md-9">
<label class="control-label" for="playlistname"
>Playlist Name</label
>
<input type="text" class="form-control" id="playlistname" />
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
<button
type="button"
class="btn btn-default"
onclick="saveQueue();"
>
Save Queue
</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<div
class="modal fade bs-example-modal-sm"
id="wait"
tabindex="-1"
role="dialog"
data-backdrop="static"
data-keyboard="false"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1>Searching...</h1>
</div>
<div class="modal-body">
<div class="progress progress-striped active">
<div
class="progress-bar"
role="progressbar"
aria-valuenow="45"
aria-valuemin="0"
aria-valuemax="100"
style="width: 100%"
>
<span class="sr-only">Please Wait</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="js/jquery-1.10.2.min.js"></script>
<script src="js/jquery.cookie.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/bootstrap-notify.js"></script>
<script src="js/bootstrap-slider.js"></script>
<script src="js/sammy.js"></script>
<script src="js/mpd.js"></script>
</body>
<!-- Placed at the end of the document so the pages load faster -->
<script src="js/jquery-1.10.2.min.js"></script>
<script src="js/jquery.cookie.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/bootstrap-notify.js"></script>
<script src="js/bootstrap-slider.js"></script>
<script src="js/sammy.js"></script>
<script src="js/jquery-ui-sortable.min.js"></script>
<script src="js/mpd.js"></script>
</body>
</html>

9789
htdocs/js/jquery-1.10.2.js vendored Normal file

File diff suppressed because it is too large Load Diff

5
htdocs/js/jquery-ui-sortable.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,19 @@
/* ympd
(c) 2013-2014 Andrew Karpow <andy@ympd.org>
(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.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
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.
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __CONFIG_H__
@ -32,8 +22,8 @@
#define YMPD_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR}
#define YMPD_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR}
#define YMPD_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH}
#define DATADIR "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}"
#define LOCAL_RESOURCE_PATH DATADIR"/htdocs"
#define SRC_PATH "${ASSETS_PATH}"
#cmakedefine WITH_MPD_HOST_CHANGE
#cmakedefine WITH_DYNAMIC_ASSETS
#endif

View File

@ -1,184 +1,60 @@
/* ympd
(c) 2013-2014 Andrew Karpow <andy@ympd.org>
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
This project's homepage is: http://www.ympd.org
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
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.
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
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.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 <libwebsockets.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <mpd/client.h>
#include "http_server.h"
#include <openssl/rand.h>
#include <string.h>
#include "mpd_client.h"
#include "config.h"
char *resource_path = LOCAL_RESOURCE_PATH;
extern enum mpd_conn_states mpd_conn_state;
int callback_http(struct mg_connection *c) {
const struct embedded_file *req_file;
struct serveable {
const char *urlpath;
const char *mimetype;
};
if (!strcmp(c->uri, "/"))
req_file = find_embedded_file("/index.html");
else
req_file = find_embedded_file(c->uri);
static const struct serveable whitelist[] = {
{ "/css/bootstrap.css", "text/css" },
{ "/css/mpd.css", "text/css" },
if (req_file) {
mg_send_header(c, "Content-Type", req_file->mimetype);
mg_send_data(c, req_file->data, req_file->size);
{ "/js/bootstrap.min.js", "text/javascript" },
{ "/js/mpd.js", "text/javascript" },
{ "/js/jquery-1.10.2.min.js", "text/javascript" },
{ "/js/jquery.cookie.js", "text/javascript" },
{ "/js/bootstrap-slider.js", "text/javascript" },
{ "/js/bootstrap-notify.js", "text/javascript" },
{ "/js/sammy.js", "text/javascript" },
{ "/fonts/glyphicons-halflings-regular.woff", "application/x-font-woff"},
{ "/fonts/glyphicons-halflings-regular.svg", "image/svg+xml"},
{ "/fonts/glyphicons-halflings-regular.ttf", "application/x-font-ttf"},
{ "/fonts/glyphicons-halflings-regular.eot", "application/vnd.ms-fontobject"},
{ "/assets/favicon.ico", "image/vnd.microsoft.icon" },
/* last one is the default served if no match */
{ "/index.html", "text/html" },
};
static const char http_header[] = "HTTP/1.0 200 OK\x0d\x0a"
"Server: libwebsockets\x0d\x0a"
"Content-Type: application/json\x0d\x0a"
"Content-Length: 000000\x0d\x0a\x0d\x0a";
/* Converts a hex character to its integer value */
char from_hex(char ch) {
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}
/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
char *url_decode(char *str) {
char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
while (*pstr) {
if (*pstr == '%') {
if (pstr[1] && pstr[2]) {
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
pstr += 2;
}
} else if (*pstr == '+') {
*pbuf++ = ' ';
} else {
*pbuf++ = *pstr;
}
pstr++;
}
*pbuf = '\0';
return buf;
}
int callback_http(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len)
{
char *response_buffer, *p;
char buf[64];
size_t n, response_size = 0;
switch (reason) {
case LWS_CALLBACK_HTTP:
if(in && strncmp((const char *)in, "/api/", 5) == 0)
{
p = (char *)malloc(MAX_SIZE + 100);
memcpy(p, http_header, sizeof(http_header) - 1);
response_buffer = p + sizeof(http_header) - 1;
/* put content length and payload to buffer */
if(mpd_conn_state != MPD_CONNECTED) {}
else if(strncmp((const char *)in, "/api/get_browse", 15) == 0)
{
char *url;
if(sscanf(in, "/api/get_browse/%m[^\t\n]", &url) == 1)
{
char *url_decoded = url_decode(url);
response_size = mpd_put_browse(response_buffer, url_decoded);
free(url_decoded);
free(url);
}
else
response_size = mpd_put_browse(response_buffer, "/");
}
else if(strncmp((const char *)in, "/api/get_playlist", 17) == 0)
response_size = mpd_put_playlist(response_buffer);
else if(strncmp((const char *)in, "/api/get_version", 16) == 0)
response_size = snprintf(response_buffer, MAX_SIZE,
"{\"type\":\"version\",\"data\":{"
"\"ympd_version\":\"%d.%d.%d\","
"\"mpd_version\":\"%d.%d.%d\""
"}}",
YMPD_VERSION_MAJOR, YMPD_VERSION_MINOR, YMPD_VERSION_PATCH,
LIBMPDCLIENT_MAJOR_VERSION, LIBMPDCLIENT_MINOR_VERSION,
LIBMPDCLIENT_PATCH_VERSION);
/* Copy size to content-length field */
sprintf(buf, "%6zu", response_size);
memcpy(p + sizeof(http_header) - 11, buf, 6);
n = libwebsocket_write(wsi, (unsigned char *)p,
sizeof(http_header) - 1 + response_size, LWS_WRITE_HTTP);
free(p);
/*
* book us a LWS_CALLBACK_HTTP_WRITEABLE callback
*/
libwebsocket_callback_on_writable(context, wsi);
}
else
{
for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
if (in && strcmp((const char *)in, whitelist[n].urlpath) == 0)
break;
sprintf(buf, "%s%s", resource_path, whitelist[n].urlpath);
if (libwebsockets_serve_http_file(context, wsi, buf, whitelist[n].mimetype, NULL))
return -1; /* through completion or error, close the socket */
}
break;
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
/* kill the connection after we sent one file */
return -1;
default:
break;
return MG_TRUE;
}
return 0;
if (!strcmp(c->uri, "/wss-auth")) {
unsigned char salt[WSS_AUTH_TOKEN_SIZE + 1];
RAND_bytes(salt, WSS_AUTH_TOKEN_SIZE);
for (int i = 0; i <= WSS_AUTH_TOKEN_SIZE; i++) salt[i] = salt[i] % 26 + 65;
salt[WSS_AUTH_TOKEN_SIZE] = 0;
if (mpd.wss_auth_token)
free(mpd.wss_auth_token);
mpd.wss_auth_token = strdup((char *)salt);
mg_send_header(c, "Content-Type", "text/plain");
mg_send_data(c, salt, WSS_AUTH_TOKEN_SIZE);
return MG_TRUE;
}
mg_send_status(c, 404);
mg_printf_data(c, "Not Found");
return MG_TRUE;
}

View File

@ -1,43 +1,34 @@
/* ympd
(c) 2013-2014 Andrew Karpow <andy@ympd.org>
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
This project's homepage is: http://www.ympd.org
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
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.
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
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.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __HTTP_SERVER_H__
#define __HTTP_SERVER_H__
#include <libwebsockets.h>
#include "mongoose.h"
struct per_session_data__http {
int fd;
struct embedded_file {
const char *name;
const unsigned char *data;
const char *mimetype;
size_t size;
};
int callback_http(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len);
const struct embedded_file *find_embedded_file(const char *name);
int callback_http(struct mg_connection *c);
#endif

58
src/json_encode.c Normal file
View File

@ -0,0 +1,58 @@
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
// Copyright (c) 2013 Cesanta Software Limited
// All rights reserved
//
// This library is dual-licensed: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation. For the terms of this
// license, see <http://www.gnu.org/licenses/>.
//
// You are free to use this library under the terms of the GNU General
// Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/products.html>.
// json encoder 'frozen' from https://github.com/cesanta/frozen
#include <stdio.h>
#include "json_encode.h"
int json_emit_int(char *buf, int buf_len, long int value) {
return buf_len <= 0 ? 0 : snprintf(buf, buf_len, "%ld", value);
}
int json_emit_double(char *buf, int buf_len, double value) {
return buf_len <= 0 ? 0 : snprintf(buf, buf_len, "%g", value);
}
int json_emit_quoted_str(char *buf, int buf_len, const char *str) {
int i = 0, j = 0, ch;
#define EMIT(x) do { if (j < buf_len) buf[j++] = x; } while (0)
EMIT('"');
while ((ch = str[i++]) != '\0' && j < buf_len) {
switch (ch) {
case '"': EMIT('\\'); EMIT('"'); break;
case '\\': EMIT('\\'); EMIT('\\'); break;
case '\b': EMIT('\\'); EMIT('b'); break;
case '\f': EMIT('\\'); EMIT('f'); break;
case '\n': EMIT('\\'); EMIT('n'); break;
case '\r': EMIT('\\'); EMIT('r'); break;
case '\t': EMIT('\\'); EMIT('t'); break;
default: EMIT(ch);
}
}
EMIT('"');
EMIT(0);
return j == 0 ? 0 : j - 1;
}
int json_emit_raw_str(char *buf, int buf_len, const char *str) {
return buf_len <= 0 ? 0 : snprintf(buf, buf_len, "%s", str);
}

27
src/json_encode.h Normal file
View File

@ -0,0 +1,27 @@
/* ympd
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
This project's homepage is: http://www.ympd.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __JSON_ENCODE_H__
#define __JSON_ENCODE_H__
int json_emit_int(char *buf, int buf_len, long int value);
int json_emit_double(char *buf, int buf_len, double value);
int json_emit_quoted_str(char *buf, int buf_len, const char *str);
int json_emit_raw_str(char *buf, int buf_len, const char *str);
#endif

5404
src/mongoose.c Normal file

File diff suppressed because it is too large Load Diff

152
src/mongoose.h Normal file
View File

@ -0,0 +1,152 @@
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
// Copyright (c) 2013-2014 Cesanta Software Limited
// All rights reserved
//
// This software is dual-licensed: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation. For the terms of this
// license, see <http://www.gnu.org/licenses/>.
//
// You are free to use this software under the terms of the GNU General
// Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/>.
#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_VERSION "5.6"
#include <stdio.h> // required for FILE
#include <stddef.h> // required for size_t
#include <sys/types.h> // required for time_t
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// This structure contains information about HTTP request.
struct mg_connection {
const char *request_method; // "GET", "POST", etc
const char *uri; // URL-decoded URI
const char *http_version; // E.g. "1.0", "1.1"
const char *query_string; // URL part after '?', not including '?', or NULL
char remote_ip[48]; // Max IPv6 string length is 45 characters
char local_ip[48]; // Local IP address
unsigned short remote_port; // Client's port
unsigned short local_port; // Local port number
int num_headers; // Number of HTTP headers
struct mg_header {
const char *name; // HTTP header name
const char *value; // HTTP header value
} http_headers[30];
char *content; // POST (or websocket message) data, or NULL
size_t content_len; // Data length
int is_websocket; // Connection is a websocket connection
int status_code; // HTTP status code for HTTP error handler
int wsbits; // First byte of the websocket frame
void *server_param; // Parameter passed to mg_create_server()
void *connection_param; // Placeholder for connection-specific data
void *callback_param;
};
struct mg_server; // Opaque structure describing server instance
enum mg_result { MG_FALSE, MG_TRUE, MG_MORE };
enum mg_event {
MG_POLL = 100, // Callback return value is ignored
MG_CONNECT, // If callback returns MG_FALSE, connect fails
MG_AUTH, // If callback returns MG_FALSE, authentication fails
MG_REQUEST, // If callback returns MG_FALSE, Mongoose continues with req
MG_REPLY, // If callback returns MG_FALSE, Mongoose closes connection
MG_RECV, // Mongoose has received POST data chunk.
// Callback should return a number of bytes to discard from
// the receive buffer, or -1 to close the connection.
MG_CLOSE, // Connection is closed, callback return value is ignored
MG_WS_HANDSHAKE, // New websocket connection, handshake request
MG_WS_CONNECT, // New websocket connection established
MG_HTTP_ERROR // If callback returns MG_FALSE, Mongoose continues with err
};
typedef int (*mg_handler_t)(struct mg_connection *, enum mg_event);
// Websocket opcodes, from http://tools.ietf.org/html/rfc6455
enum {
WEBSOCKET_OPCODE_CONTINUATION = 0x0,
WEBSOCKET_OPCODE_TEXT = 0x1,
WEBSOCKET_OPCODE_BINARY = 0x2,
WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
WEBSOCKET_OPCODE_PING = 0x9,
WEBSOCKET_OPCODE_PONG = 0xa
};
// Server management functions
struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
void mg_destroy_server(struct mg_server **);
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
time_t mg_poll_server(struct mg_server *, int milliseconds);
const char **mg_get_valid_option_names(void);
const char *mg_get_option(const struct mg_server *server, const char *name);
void mg_copy_listeners(struct mg_server *from, struct mg_server *to);
struct mg_connection *mg_next(struct mg_server *, struct mg_connection *);
void mg_wakeup_server(struct mg_server *);
void mg_wakeup_server_ex(struct mg_server *, mg_handler_t, const char *, ...);
struct mg_connection *mg_connect(struct mg_server *, const char *);
// Connection management functions
void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name, const char *val);
size_t mg_send_data(struct mg_connection *, const void *data, int data_len);
size_t mg_printf_data(struct mg_connection *, const char *format, ...);
size_t mg_write(struct mg_connection *, const void *buf, size_t len);
size_t mg_printf(struct mg_connection *conn, const char *fmt, ...);
size_t mg_websocket_write(struct mg_connection *, int opcode,
const char *data, size_t data_len);
size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
const char *fmt, ...);
void mg_send_file(struct mg_connection *, const char *path, const char *);
void mg_send_file_data(struct mg_connection *, int fd);
const char *mg_get_header(const struct mg_connection *, const char *name);
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len);
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
int mg_parse_multipart(const char *buf, int buf_len,
char *var_name, int var_name_len,
char *file_name, int file_name_len,
const char **data, int *data_len);
// Utility functions
void *mg_start_thread(void *(*func)(void *), void *param);
char *mg_md5(char buf[33], ...);
int mg_authorize_digest(struct mg_connection *c, FILE *fp);
size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int);
int mg_terminate_ssl(struct mg_connection *c, const char *cert);
int mg_forward(struct mg_connection *c, const char *addr);
void *mg_mmap(FILE *fp, size_t size);
void mg_munmap(void *p, size_t size);
// Templates support
struct mg_expansion {
const char *keyword;
void (*handler)(struct mg_connection *);
};
void mg_template(struct mg_connection *, const char *text,
struct mg_expansion *expansions);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // MONGOOSE_HEADER_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -1,96 +1,125 @@
/* ympd
(c) 2013-2014 Andrew Karpow <andy@ympd.org>
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
This project's homepage is: http://www.ympd.org
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
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.
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
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.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __MPD_CLIENT_H__
#define __MPD_CLIENT_H__
#include <libwebsockets.h>
#include "mongoose.h"
#define RETURN_ERROR_AND_RECOVER(X) \
do { \
fprintf(stderr, "MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \
cur += snprintf(cur, end - cur, "{\"type\":\"error\",\"data\":\"%s\"}", \
mpd_connection_get_error_message(mpd.conn)); \
if (!mpd_connection_clear_error(mpd.conn)) \
mpd.conn_state = MPD_FAILURE; \
return cur - buffer; \
} while (0)
#define MAX_SIZE 1024 * 100
#define MAX_ELEMENTS_PER_PAGE 512
#define DO_SEND_STATE (1 << 0)
#define DO_SEND_PLAYLIST (1 << 1)
#define DO_SEND_TRACK_INFO (1 << 2)
#define DO_SEND_BROWSE (1 << 3)
#define DO_SEND_ERROR (1 << 4)
#define DO_SEND_MPDHOST (1 << 5)
#define WSS_AUTH_TOKEN_SIZE 50
#define MPD_API_GET_SEEK "MPD_API_GET_SEEK"
#define MPD_API_GET_PLAYLIST "MPD_API_GET_PLAYLIST"
#define MPD_API_GET_TRACK_INFO "MPD_API_GET_TRACK_INFO"
#define MPD_API_GET_BROWSE "MPD_API_GET_BROWSE"
#define MPD_API_GET_MPDHOST "MPD_API_GET_MPDHOST"
#define MPD_API_ADD_TRACK "MPD_API_ADD_TRACK"
#define MPD_API_ADD_PLAY_TRACK "MPD_API_ADD_PLAY_TRACK"
#define MPD_API_PLAY_TRACK "MPD_API_PLAY_TRACK"
#define MPD_API_RM_TRACK "MPD_API_RM_TRACK"
#define MPD_API_RM_ALL "MPD_API_RM_ALL"
#define MPD_API_SET_VOLUME "MPD_API_SET_VOLUME"
#define MPD_API_SET_PAUSE "MPD_API_SET_PAUSE"
#define MPD_API_SET_PLAY "MPD_API_SET_PLAY"
#define MPD_API_SET_STOP "MPD_API_SET_STOP"
#define MPD_API_SET_SEEK "MPD_API_SET_SEEK"
#define MPD_API_SET_NEXT "MPD_API_SET_PREV"
#define MPD_API_SET_PREV "MPD_API_SET_NEXT"
#define MPD_API_SET_MPDHOST "MPD_API_SET_MPDHOST"
#define MPD_API_UPDATE_DB "MPD_API_UPDATE_DB"
#define MPD_API_TOGGLE_RANDOM "MPD_API_TOGGLE_RANDOM"
#define MPD_API_TOGGLE_CONSUME "MPD_API_TOGGLE_CONSUME"
#define MPD_API_TOGGLE_SINGLE "MPD_API_TOGGLE_SINGLE"
#define MPD_API_TOGGLE_REPEAT "MPD_API_TOGGLE_REPEAT"
#define GEN_ENUM(X) X,
#define GEN_STR(X) #X,
#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) \
X(MPD_API_PLAY_TRACK) \
X(MPD_API_SAVE_QUEUE) \
X(MPD_API_RM_TRACK) \
X(MPD_API_RM_RANGE) \
X(MPD_API_RM_ALL) \
X(MPD_API_MOVE_TRACK) \
X(MPD_API_SEARCH) \
X(MPD_API_GET_CHANNELS) \
X(MPD_API_SEND_MESSAGE) \
X(MPD_API_SET_VOLUME) \
X(MPD_API_SET_PAUSE) \
X(MPD_API_SET_PLAY) \
X(MPD_API_SET_STOP) \
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) \
X(MPD_API_TOGGLE_RANDOM) \
X(MPD_API_TOGGLE_CONSUME) \
X(MPD_API_TOGGLE_SINGLE) \
X(MPD_API_TOGGLE_CROSSFADE) \
X(MPD_API_TOGGLE_REPEAT) \
X(MPD_API_AUTHORIZE)
struct per_session_data__ympd {
int do_send;
unsigned queue_version;
int current_song_id;
char *browse_path;
};
enum mpd_cmd_ids { MPD_CMDS(GEN_ENUM) };
enum mpd_conn_states {
MPD_FAILURE,
MPD_DISCONNECTED,
MPD_FAILURE,
MPD_CONNECTED,
MPD_RECONNECT
MPD_RECONNECT,
MPD_DISCONNECT
};
void *mpd_idle_connection(void *_data);
int callback_ympd(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len);
void mpd_loop();
struct t_mpd {
int port;
int local_port;
char host[128];
char *password;
char *gpass;
char *wss_auth_token;
struct mpd_connection *conn;
enum mpd_conn_states conn_state;
/* Reponse Buffer */
char buf[MAX_SIZE];
size_t buf_size;
int song_id;
unsigned queue_version;
};
extern struct t_mpd mpd;
struct t_mpd_client_session {
int song_id;
unsigned queue_version;
int authorized;
char *auth_token;
};
void mpd_poll(struct mg_server *s);
int callback_mpd(struct mg_connection *c);
int mpd_close_handler(struct mg_connection *c);
int mpd_put_state(char *buffer, int *current_song_id, unsigned *queue_version);
int mpd_put_outputs(char *buffer, int putnames);
int mpd_put_channels(char *buffer);
int mpd_put_current_song(char *buffer);
int mpd_put_playlist(char *buffer);
int mpd_put_browse(char *buffer, char *path);
int mpd_port;
char mpd_host[255];
int mpd_put_queue(char *buffer, unsigned int offset);
int mpd_put_browse(char *buffer, char *path, unsigned int offset);
int mpd_search(char *buffer, char *searchstr);
void mpd_disconnect();
#endif

View File

@ -1,40 +0,0 @@
/*
from http://www.geekhideout.com/urlcode.shtml
public domain
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
/* Converts a hex character to its integer value */
char from_hex(char ch) {
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}
/* Converts an integer value to its hex character*/
char to_hex(char code) {
static char hex[] = "0123456789abcdef";
return hex[code & 15];
}
/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
char *url_decode(char *str) {
char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
while (*pstr) {
if (*pstr == '%') {
if (pstr[1] && pstr[2]) {
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
pstr += 2;
}
} else if (*pstr == '+') {
*pbuf++ = ' ';
} else {
*pbuf++ = *pstr;
}
pstr++;
}
*pbuf = '\0';
return buf;
}

View File

@ -1,215 +1,200 @@
/* ympd
(c) 2013-2014 Andrew Karpow <andy@ympd.org>
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
This project's homepage is: http://www.ympd.org
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
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.
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
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.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 <libwebsockets.h>
#include <getopt.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/time.h>
#include <unistd.h>
#include "http_server.h"
#include "mpd_client.h"
#include "config.h"
#include "http_server.h"
#include "mongoose.h"
#include "mpd_client.h"
extern char *optarg;
extern char *resource_path;
struct libwebsocket_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{
"http-only", /* name */
callback_http, /* callback */
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
},
{
"ympd-client",
callback_ympd,
sizeof(struct per_session_data__ympd),
255,
0,
},
{ NULL, NULL, 0, 0, 0 } /* terminator */
};
int force_exit = 0;
void bye()
{
void bye() {
force_exit = 1;
}
int main(int argc, char **argv)
{
int n, gid = -1, uid = -1;
int option_index = 0;
unsigned int oldus = 0;
struct libwebsocket_context *context;
struct lws_context_creation_info info;
const char *cert_filepath = NULL;
const char *private_key_filepath = NULL;
const char *iface = NULL;
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
#ifdef WITH_DYNAMIC_ASSETS
return MG_FALSE;
#else
return callback_http(c);
#endif
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);
memset(&info, 0, sizeof info);
info.port = 8080;
strcpy(mpd_host, "127.0.0.1");
mpd_port = 6600;
lws_set_log_level(LLL_ERR | LLL_WARN, NULL);
#ifdef WITH_DYNAMIC_ASSETS
mg_set_option(server, "document_root", SRC_PATH);
#endif
mg_set_option(server, "auth_domain", "ympd");
mpd.port = 6600;
mpd.local_port = 0;
mpd.gpass = NULL;
strcpy(mpd.host, "127.0.0.1");
/* clang-format off */
static struct option long_options[] = {
{"digest", required_argument, 0, 'D'},
{"host", required_argument, 0, 'h'},
{"port", required_argument, 0, 'p'},
{"interface", required_argument, 0, 'i'},
{"localport", required_argument, 0, 'l'},
{"webport", required_argument, 0, 'w'},
{"resourcepath", required_argument, 0, 'r'},
{"ssl_cert", required_argument, 0, 'c'},
{"ssl_key", required_argument, 0, 'k'},
{"gid", required_argument, 0, 'g'},
{"uid", required_argument, 0, 'u'},
{"verbose", optional_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"user", required_argument, 0, 'u'},
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 0 },
{"mpdpass", required_argument, 0, 'm'},
{0, 0, 0, 0 }
};
/* clang-format on */
while((n = getopt_long(argc, argv, "h:p:i:w:r:c:k:g:u:v::V",
long_options, &option_index)) != -1) {
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));
strncpy(mpd.host, optarg, sizeof(mpd.host));
break;
case 'p':
mpd_port = atoi(optarg);
case 'i':
iface = optarg;
mpd.port = atoi(optarg);
break;
case 'l':
mpd.local_port = atoi(optarg);
break;
case 'w':
info.port = atoi(optarg);
break;
case 'r':
resource_path = optarg;
break;
case 'c':
cert_filepath = optarg;
break;
case 'k':
private_key_filepath = optarg;
break;
case 'g':
gid = atoi(optarg);
webport = strdup(optarg);
break;
case 'u':
uid = atoi(optarg);
run_as_user = strdup(optarg);
break;
case 'm':
if (strlen(optarg) > 0)
mpd.password = strdup(optarg);
break;
case 'v':
if(optarg)
lws_set_log_level(strtol(optarg, NULL, 10), NULL);
else
lws_set_log_level(LLL_ERR | LLL_WARN |
LLL_NOTICE | LLL_INFO, NULL);
break;
case 'V':
fprintf(stdout, "ympd %d.%d.%d\n"
"Copyright (C) 2014 Andrew Karpow <andy@ympd.org>\n"
"Resource Path: "LOCAL_RESOURCE_PATH"\n"
"built " __DATE__ " "__TIME__ " ("__VERSION__")\n",
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"
"\t-h, --host <host>\t\tconnect to mpd at host [localhost]\n"
"\t-p, --port <port>\t\tconnect to mpd at port [6600]\n"
"\t-i, --interface <interface>\tlisten interface for webserver [all]\n"
"\t-w, --webport <port>\t\tlisten port for webserver [8080]\n"
"\t-r, --resourcepath <path>\tresourcepath for webserver [" LOCAL_RESOURCE_PATH "]\n"
"\t-c, --ssl_cert <filepath>\tssl certificate ssl_private_key_filepath\n"
"\t-k, --ssl_key <filepath>\tssl private key filepath\n"
"\t-u, --uid <id>\t\t\tuser-id after socket bind\n"
"\t-g, --gid <id>\t\t\tgroup-id after socket bind\n"
"\t-v, --verbose[<level>]\t\tverbosity level\n"
"\t-V, --version\t\t\tget version\n"
"\t--help\t\t\t\tthis help\n"
, argv[0]);
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(cert_filepath != NULL && private_key_filepath == NULL) {
lwsl_err("private key filepath needed\n");
return EXIT_FAILURE;
}
if(private_key_filepath != NULL && cert_filepath == NULL) {
lwsl_err("public cert filepath needed\n");
return EXIT_FAILURE;
}
info.ssl_cert_filepath = cert_filepath;
info.ssl_private_key_filepath = private_key_filepath;
info.iface = iface;
info.protocols = protocols;
info.extensions = libwebsocket_get_internal_extensions();
info.gid = gid;
info.uid = uid;
info.options = 0;
context = libwebsocket_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
return EXIT_FAILURE;
}
n = 0;
while (n >= 0 && !force_exit) {
struct timeval tv;
gettimeofday(&tv, NULL);
/*
* This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
* live websocket connection using the DUMB_INCREMENT protocol,
* as soon as it can take more packets (usually immediately)
*/
if (((unsigned int)tv.tv_usec - oldus) > 1000 * 500) {
mpd_loop();
libwebsocket_callback_on_writable_all_protocol(&protocols[1]);
oldus = tv.tv_usec;
if (error_msg) {
fprintf(stderr, "Mongoose error: %s\n", error_msg);
return EXIT_FAILURE;
}
n = libwebsocket_service(context, 50);
}
libwebsocket_context_destroy(context);
return 0;
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;
}

10
tools/lint.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
repo="$(git rev-parse --show-toplevel)"
pushd "$repo"
prettier --write .
for i in http_server.c http_server.h json_encode.h mpd_client.c mpd_client.h ympd.c; do
clang-format -i -style=file "src/$i"
done
popd

94
tools/mkdata.c Normal file
View File

@ -0,0 +1,94 @@
/* This program is used to embed arbitrary data into a C binary. It takes
* a list of files as an input, and produces a .c data file that contains
* contents of all these files as collection of char arrays.
*
* Usage: ./mkdata <this_file> <file1> [file2, ...] > embedded_data.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <errno.h>
#include <string.h>
const char* header =
"#include <stddef.h>\n"
"#include <string.h>\n"
"#include <sys/types.h>\n"
"#include \"src/http_server.h\"\n"
"\n"
"static const struct embedded_file embedded_files[] = {\n";
const char* footer =
" {NULL, NULL, NULL, 0}\n"
"};\n"
"\n"
"const struct embedded_file *find_embedded_file(const char *name) {\n"
" const struct embedded_file *p;\n"
" for (p = embedded_files; p->name != NULL; p++)\n"
" if (!strcmp(p->name, name))\n"
" return p;\n"
" return NULL;\n"
"}\n";
static const char* get_mime(char* filename)
{
const char *extension = strrchr(filename, '.');
if(!strcmp(extension, ".js"))
return "application/javascript";
if(!strcmp(extension, ".css"))
return "text/css";
if(!strcmp(extension, ".ico"))
return "image/vnd.microsoft.icon";
if(!strcmp(extension, ".woff"))
return "application/font-woff";
if(!strcmp(extension, ".ttf"))
return "application/x-font-ttf";
if(!strcmp(extension, ".eot"))
return "application/octet-stream";
if(!strcmp(extension, ".svg"))
return "image/svg+xml";
if(!strcmp(extension, ".html"))
return "text/html";
return "text/plain";
}
int main(int argc, char *argv[])
{
int i, j, buf;
FILE *fd;
if(argc <= 1)
err(EXIT_FAILURE, "Usage: ./%s <this_file> <file1> [file2, ...] > embedded_data.c", argv[0]);
for(i = 1; i < argc; i++)
{
fd = fopen(argv[i], "r");
if(!fd)
err(EXIT_FAILURE, "%s", argv[i]);
printf("static const unsigned char v%d[] = {", i);
j = 0;
while((buf = fgetc(fd)) != EOF)
{
if(!(j % 12))
putchar('\n');
printf(" %#04x, ", buf);
j++;
}
printf(" 0x00\n};\n\n");
fclose(fd);
}
fputs(header, stdout);
for(i = 1; i < argc; i++)
{
printf(" {\"%s\", v%d, \"%s\", sizeof(v%d) - 1}, \n",
argv[i]+6, i, get_mime(argv[i]), i);
}
fputs(footer, stdout);
return EXIT_SUCCESS;
}

65
tools/mkdata.pl Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/perl
# This program is used to embed arbitrary data into a C binary. It takes
# a list of files as an input, and produces a .c data file that contains
# contents of all these files as collection of char arrays.
#
# Usage: perl <this_file> <file1> [file2, ...] > embedded_data.c
use File::Basename;
%mimetypes = (
js => 'application/javascript',
css => 'text/css',
ico => 'image/vnd.microsoft.icon',
woff => 'application/font-woff',
ttf => 'application/x-font-ttf',
eot => 'application/octet-stream',
svg => 'image/svg+xml',
html => 'text/html'
);
foreach my $i (0 .. $#ARGV) {
open FD, '<:raw', $ARGV[$i] or die "Cannot open $ARGV[$i]: $!\n";
printf("static const unsigned char v%d[] = {", $i);
my $byte;
my $j = 0;
while (read(FD, $byte, 1)) {
if (($j % 12) == 0) {
print "\n";
}
printf ' %#04x,', ord($byte);
$j++;
}
print " 0x00\n};\n";
close FD;
}
print <<EOS;
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include "src/http_server.h"
static const struct embedded_file embedded_files[] = {
EOS
foreach my $i (0 .. $#ARGV) {
my ($ext) = $ARGV[$i] =~ /([^.]+)$/;
my $mime = $mimetypes{$ext};
$ARGV[$i] =~ s/htdocs//;
print " {\"$ARGV[$i]\", v$i, \"$mime\", sizeof(v$i) - 1},\n";
}
print <<EOS;
{NULL, NULL, NULL, 0}
};
const struct embedded_file *find_embedded_file(const char *name) {
const struct embedded_file *p;
for (p = embedded_files; p->name != NULL; p++)
if (!strcmp(p->name, name))
return p;
return NULL;
}
EOS

33
ympd.1
View File

@ -1,14 +1,14 @@
.\" Manpage for ympd.
.\" Contact andy@ympd.org to correct errors or typos.
.TH man 8 "17 Jan 2014" "1.0" "ympd man page"
.TH man 1 "19 Oct 2014" "1.2.3" "ympd man page"
.SH NAME
ympd \- Standalone MPD Web GUI written in C, utilizing Websockets and Bootstrap/JS
.SH SYNOPSIS
ympd [OPTION]...
.SH DESCRIPTION
ympd is a lightweight MPD (Music Player Daemon) web client that runs without a dedicated werbserver or interpreters like PHP, NodeJS or Ruby. It's tuned for minimal resource usage and requires only very litte dependencies.
ympd is a lightweight MPD (Music Player Daemon) web client that runs without a dedicated webserver or interpreters like PHP, NodeJS or Ruby. It's tuned for minimal resource usage and requires only very litte dependencies.
ympd is based in part on the work of the libwebsockets project (http://libwebsockets.org)
ympd is based in part on the work of the mongoose http server (https://github.com/cesanta/mongoose)
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-host HOST\fR
@ -17,29 +17,14 @@ 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\-i\fR, \fB\-\-interface INTERFACE\fR
specifies the interface to listen to
.TP
\fB\-w\fR, \fB\-\-webport PORT\fR
specifies the port for the webserver to listen to, defaults to 8080
.TP
\fB\-r\fR, \fB\-\-resourcepath PATH\fR
resource path to htdocs directory, defaults to the supplied htdocs directory
\fB\-u\fR, \fB\-\-user username\fR
drop privileges to the provided username after socket binding
.TP
\fB\-c\fR, \fB\-\-ssl_cert PATH\fR
path the the ssl certificate
.TP
\fB\-k\fR, \fB\-\-ssl_key PATH\fR
path the the private ssl key
.TP
\fB\-u\fR, \fB\-\-uid UID\fR
drop privileges to the provided uid after socket binding
.TP
\fB\-g\fR, \fB\-\-gid GID\fR
drop privileges to the provided gid after socket binding
.TP
\fB\-v\fR, \fB\-\-verbose [LEVEL]\fR
sets the verbository level
\fB\-m\fR, \fB\-\-mpdpass password\fR
specifies the password to use when connecting to mpd
.TP
\fB\-V\fR, \fB\-\-version\fR
print version and exit
@ -49,6 +34,6 @@ print all valid options and exits
.SH BUGS
No known bugs.
.SH AUTHOR
Andrew Karpow (andy@ympd.org)
Andrew Karpow (andy@ndyk.de)
http://ympd.org
http://www.ympd.org