Configured and ran Prettier on client files
authorAndrew Carr <andrew.carr@tandell.com>
Sun, 23 May 2021 03:15:19 +0000 (03:15 +0000)
committerAndrew Carr <andrew.carr@tandell.com>
Sun, 23 May 2021 03:15:19 +0000 (03:15 +0000)
.prettierignore [new file with mode: 0644]
.prettierrc.json [new file with mode: 0644]
.travis.yml
DEVELOPMENT.md [new file with mode: 0644]
README.md
htdocs/css/mpd.css
htdocs/index.html
htdocs/js/mpd.js
htdocs/player.html

diff --git a/.prettierignore b/.prettierignore
new file mode 100644 (file)
index 0000000..435a6f0
--- /dev/null
@@ -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*
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644 (file)
index 0000000..f27022b
--- /dev/null
@@ -0,0 +1,20 @@
+{
+    "trailingComma": "es5",
+    "tabWidth": 4,
+    "semi": true,
+    "singleQuote": true,
+    "overrides": [
+        {
+            "files": ["*.html"],
+            "options": {
+                "tabWidth": 2
+            }
+        },
+        {
+            "files": ["*.css"],
+            "options": {
+                "tabWidth": 2
+            }
+        }
+    ]
+}
index 4b2afb9..b4d35ab 100644 (file)
@@ -3,16 +3,15 @@ language: c
 sudo: required
 dist: trusty
 
-compiler: 
-  - gcc
-  - clang
+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 ..
+    - 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
-
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
new file mode 100644 (file)
index 0000000..3dce54e
--- /dev/null
@@ -0,0 +1,13 @@
+# 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`.
index 1d7fb81..4f9a3c3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -4,28 +4,26 @@ ympd
 
 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
-------------
- - libmpdclient 2: http://www.musicpd.org/libs/libmpdclient/
- - cmake 2.6: http://cmake.org/
- - OpenSSL: https://www.openssl.org/
+## Dependencies
+
+-   libmpdclient 2: http://www.musicpd.org/libs/libmpdclient/
+-   cmake 2.6: http://cmake.org/
+-   OpenSSL: https://www.openssl.org/
 
-Unix Build Instructions
------------------------
+## Unix Build Instructions
 
 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```
+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
 
-Run flags
----------
 ```
 Usage: ./ympd [OPTION]...
 
@@ -39,21 +37,23 @@ Usage: ./ympd [OPTION]...
  --help                        this help
 ```
 
-SSL Support
------------
+## SSL Support
+
 To run ympd with SSL support:
 
-- create a certificate (key and cert in the same file), example:
+-   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: 
+
+-   tell ympd to use a webport using SSL and where to find the certificate:
+
 ```
 # ./ympd -w "ssl://8081:/path/to/ssl.pem"
 ```
 
-Copyright
----------
+## Copyright
 
 2013-2014 <andy@ndyk.de>
index a5c6acc..c1e9d46 100644 (file)
@@ -15,12 +15,10 @@ body {
   margin-bottom: 0;
 }
 
-
 button {
   overflow: hidden;
 }
 
-
 #volume-icon {
   float: left;
   margin-right: 10px;
@@ -34,7 +32,7 @@ button {
   white-space: nowrap;
 }
 
-#breadcrump > li > a{
+#breadcrump > li > a {
   cursor: pointer;
 }
 
@@ -58,17 +56,17 @@ button {
   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;
   }
 }
 
@@ -80,14 +78,16 @@ h1 {
   white-space: nowrap;
 }
 
-td:nth-child(4), th:nth-child(4) {
+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) {
+td:nth-last-child(2),
+th:nth-last-child(2) {
   text-align: right;
   width: 4em;
 }
@@ -98,7 +98,8 @@ td:nth-last-child(2), th:nth-last-child(2) {
   display: block;
 }
 
-td:nth-child(2), td:nth-child(3) {
+td:nth-child(2),
+td:nth-child(3) {
   min-width: 25%;
   max-width: 10em;
 
@@ -108,21 +109,24 @@ td:nth-child(2), td:nth-child(3) {
 }
 
 @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;
-       }
+  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;
 }
 
@@ -149,9 +153,9 @@ button {
 }
 
 #trashmode span:last-child {
-  display:inline-block;
-  text-align:left;
-  width:2.8em;
+  display: inline-block;
+  text-align: left;
+  width: 2.8em;
 }
 
 #filter > a.active {
index 1cf62cf..e8e7e04 100644 (file)
 <!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">
-  <link href="css/bootstrap-theme.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">
-  <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>
+    <!-- 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>
 
-        <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">
-            <button id="btnlove" type="button" class="btn btn-default" onclick="clickLove();">
-              <span class="glyphicon glyphicon-heart"></span>
-            </button>
-          </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">
+              <button
+                id="btnlove"
+                type="button"
+                class="btn btn-default"
+                onclick="clickLove();"
+              >
+                <span class="glyphicon glyphicon-heart"></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>
           </div>
 -->
-           <div class="btn-group" role="group">
-            <audio id="player" preload="none"></audio>
-            <button type="button" class="btn btn-default" onclick="clickLocalPlay()">
-              <span id="localplay-icon" class="glyphicon glyphicon-play"></span>
-            </button>
-            <button type="button" class="btn btn-default" onclick="window.open('/player.html');">
-              <span id="localplay-icon" class="glyphicon glyphicon-new-window"></span>
-            </button>
-          </div>
-       </div>
-          
-        <form id="search" class="navbar-form navbar-right" role="search">
-          <div class="form-group">
-            <input type="text" class="form-control" placeholder="Search">
+            <div class="btn-group" role="group">
+              <audio id="player" preload="none"></audio>
+              <button
+                type="button"
+                class="btn btn-default"
+                onclick="clickLocalPlay()"
+              >
+                <span
+                  id="localplay-icon"
+                  class="glyphicon glyphicon-play"
+                ></span>
+              </button>
+              <button
+                type="button"
+                class="btn btn-default"
+                onclick="window.open('/player.html');"
+              >
+                <span
+                  id="localplay-icon"
+                  class="glyphicon glyphicon-new-window"
+                ></span>
+              </button>
+            </div>
           </div>
-        </form>
-      </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 class="panel-heading"><b id="panel-heading">Queue</b>
-                                     <b id="panel-heading-info" class="text pull-right"></b></div>
-          <div class="panel-body">
-            <h1>
-              <span id="track-icon" onclick="clickPlay();" class="glyphicon glyphicon-play"></span>
-              <span id="currenttrack"></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><!-- /.panel-body -->
-
-          <ol id="breadcrump" class="breadcrumb">
-          </ol>
-
-          <div class="col-md-12" id="filter">
-          </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>
+        <!--/.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>
 
-          <!-- 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></th>
-              </tr>
-            </thead>
-            <tbody>
-            </tbody>
-          </table>
+          <div class="panel panel-primary">
+            <!-- Default panel contents -->
+            <div class="panel-heading">
+              <b id="panel-heading">Queue</b>
+              <b id="panel-heading-info" class="text pull-right"></b>
+            </div>
+            <div class="panel-body">
+              <h1>
+                <span
+                  id="track-icon"
+                  onclick="clickPlay();"
+                  class="glyphicon glyphicon-play"
+                ></span>
+                <span id="currenttrack"></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><!-- /.panel -->
-        <ul class="pager">
-          <li id="prev" class="page-btn hide"><a href="">Previous</a></li>
-          <li id="next" class="page-btn"><a href="">Next</a></li>
-        </ul>
-      </div><!-- /.col-md-10 -->
+              <div id="progressbar"></div>
+            </div>
+            <!-- /.panel-body -->
 
-      <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="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>
+            <ol id="breadcrump" class="breadcrumb"></ol>
 
-          <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>
+            <div class="col-md-12" id="filter"></div>
 
-          <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>
+            <!-- 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></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><!-- /.col-md-2 -->
-    </div><!-- /.row -->
-  </div><!-- /.container -->
+        <!-- /.col-md-10 -->
 
-  <!-- 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
+        <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="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 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
+            <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>
+
+            <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>
-          <hr />
-          <form role="form">
+        </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-9">
-                <label class="control-label" for="mpdhost">MPD Host/IP</label>
-                <input type="text" class="form-control" id="mpdhost" />
+              <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-3">
-                <label class="control-label" for="mpdport">MPD Port</label>
-                <input type="text" class="form-control" id="mpdport" />
+              <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>
-            <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"/>
+            <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="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 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="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 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>
-            </div>
+            </form>
             <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 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>
-          </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 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>
-        <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-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" />
+    <!-- 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>
-            </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>
+            </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>
-      </div><!-- /.modal-content -->
-    </div><!-- /.modal-dialog -->
-  </div><!-- /.modal -->
+        <!-- /.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
+      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>
-            </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>
+            </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>
-      </div><!-- /.modal-content -->
-    </div><!-- /.modal-dialog -->
-  </div><!-- /.modal -->
+        <!-- /.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
+      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>
-  </div>
-
 
-  <!-- Bootstrap core JavaScript
+    <!-- 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/jquery-ui-sortable.min.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>
index f82e866..83c5374 100644 (file)
    Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-var TOKEN = "";
+var TOKEN = '';
 
 var socket;
 var last_state;
 var last_outputs;
 var current_app;
 var pagination = 0;
-var browsepath = "";
-var lastSongTitle = "";
+var browsepath = '';
+var lastSongTitle = '';
 var current_song = new Object();
 var MAX_ELEMENTS_PER_PAGE = 512;
 var isTouch = Modernizr.touch ? 1 : 0;
-var filter = "";
-
-var app = $.sammy(function() {
+var filter = '';
 
+var app = $.sammy(function () {
     function runBrowse() {
         current_app = 'queue';
 
         $('#breadcrump').addClass('hide');
         $('#filter').addClass('hide');
-        $('#salamisandwich').removeClass('hide').find("tr:gt(0)").remove();
-        socket.send('MPD_API_GET_QUEUE,'+pagination);
+        $('#salamisandwich').removeClass('hide').find('tr:gt(0)').remove();
+        socket.send('MPD_API_GET_QUEUE,' + pagination);
 
-        $('#panel-heading').text("Queue");
+        $('#panel-heading').text('Queue');
         $('#panel-heading-info').empty();
 
         $('#queue').addClass('active');
@@ -54,192 +53,246 @@ var app = $.sammy(function() {
         browsepath = '';
     }
 
-    this.get(/\#\/(\d+)/, function() {
+    this.get(/\#\/(\d+)/, function () {
         prepare();
         pagination = parseInt(this.params['splat'][0]);
         runBrowse();
     });
 
-    this.get(/\#\/browse\/(\d+)\/(.*)/, function() {
+    this.get(/\#\/browse\/(\d+)\/(.*)/, function () {
         prepare();
         browsepath = this.params['splat'][1];
         pagination = parseInt(this.params['splat'][0]);
         current_app = 'browse';
-        $('#breadcrump').removeClass('hide').empty().append("<li><a uri=\"\" onclick=\"set_filter('')\">root</a></li>");
-               add_filter();
-        $('#salamisandwich').removeClass('hide').find("tr:gt(0)").remove();
-        socket.send('MPD_API_GET_BROWSE,'+pagination+','+(browsepath ? browsepath : "/"));
+        $('#breadcrump')
+            .removeClass('hide')
+            .empty()
+            .append('<li><a uri="" onclick="set_filter(\'\')">root</a></li>');
+        add_filter();
+        $('#salamisandwich').removeClass('hide').find('tr:gt(0)').remove();
+        socket.send(
+            'MPD_API_GET_BROWSE,' +
+                pagination +
+                ',' +
+                (browsepath ? browsepath : '/')
+        );
         // Don't add all songs from root
         if (browsepath) {
-            $('#filter').append('<button id="add-all-songs" class="btn btn-primary pull-right">Add all</button>');
+            $('#filter').append(
+                '<button id="add-all-songs" class="btn btn-primary pull-right">Add all</button>'
+            );
             var add_all_songs = $('#add-all-songs');
-            add_all_songs.on('click', function() {
-                socket.send('MPD_API_ADD_TRACK,'+browsepath);
+            add_all_songs.on('click', function () {
+                socket.send('MPD_API_ADD_TRACK,' + browsepath);
             });
         }
 
-        $('#panel-heading').text("Browse database: "+browsepath);
+        $('#panel-heading').text('Browse database: ' + browsepath);
         var path_array = browsepath.split('/');
-        var full_path = "";
-        $.each(path_array, function(index, chunk) {
-            if(path_array.length - 1 == index) {
-                $('#breadcrump').append("<li class=\"active\">"+ chunk + "</li>");
+        var full_path = '';
+        $.each(path_array, function (index, chunk) {
+            if (path_array.length - 1 == index) {
+                $('#breadcrump').append(
+                    '<li class="active">' + chunk + '</li>'
+                );
                 return;
             }
 
             full_path = full_path + chunk;
-            $('#breadcrump').append("<li><a uri=\"" + full_path + "\">"+chunk+"</a></li>");
-            full_path += "/";
+            $('#breadcrump').append(
+                '<li><a uri="' + full_path + '">' + chunk + '</a></li>'
+            );
+            full_path += '/';
         });
         $('#browse').addClass('active');
     });
 
-    this.get(/\#\/search\/(.*)/, function() {
+    this.get(/\#\/search\/(.*)/, function () {
         current_app = 'search';
-        $('#salamisandwich').find("tr:gt(0)").remove();
+        $('#salamisandwich').find('tr:gt(0)').remove();
         var searchstr = this.params['splat'][0];
 
         $('#search > div > input').val(searchstr);
         socket.send('MPD_API_SEARCH,' + searchstr);
 
-        $('#panel-heading').text("Search: "+searchstr);
+        $('#panel-heading').text('Search: ' + searchstr);
     });
 
-    this.get("/", function(context) {
-        context.redirect("#/0");
+    this.get('/', function (context) {
+        context.redirect('#/0');
     });
 });
 
-$(document).ready(function(){
+$(document).ready(function () {
     webSocketConnect();
-    $("#volumeslider").slider(0);
-    $("#volumeslider").on('slider.newValue', function(evt,data){
-        socket.send("MPD_API_SET_VOLUME,"+data.val);
+    $('#volumeslider').slider(0);
+    $('#volumeslider').on('slider.newValue', function (evt, data) {
+        socket.send('MPD_API_SET_VOLUME,' + data.val);
     });
     $('#progressbar').slider(0);
-    $("#progressbar").on('slider.newValue', function(evt,data){
-        if(current_song && current_song.currentSongId >= 0) {
-            var seekVal = Math.ceil(current_song.totalTime*(data.val/100));
-            socket.send("MPD_API_SET_SEEK,"+current_song.currentSongId+","+seekVal);
+    $('#progressbar').on('slider.newValue', function (evt, data) {
+        if (current_song && current_song.currentSongId >= 0) {
+            var seekVal = Math.ceil(current_song.totalTime * (data.val / 100));
+            socket.send(
+                'MPD_API_SET_SEEK,' + current_song.currentSongId + ',' + seekVal
+            );
         }
     });
 
     $('#addstream').on('shown.bs.modal', function () {
         $('#streamurl').focus();
-     })
+    });
     $('#addstream form').on('submit', function (e) {
         addStream();
     });
 
-    if(!notificationsSupported())
-        $('#btnnotify').addClass("disabled");
-    else
-        if ($.cookie("notification") === "true")
-            $('#btnnotify').addClass("active")
-
-    if ($.cookie("autoplay") === "true")
-        $('#btnautoplay').addClass("active")
-
-    document.getElementById('player').addEventListener('stalled', function() {
-                                               if ( !document.getElementById('player').paused ) {
-                                                       this.pause();
-                                                       clickLocalPlay();
-                                                       $('.top-right').notify({
-                                                               message:{text:"music stream stalled - trying to recover..."},
-                                                               type: "danger",
-                                                               fadeOut: { enabled: true, delay: 1000 },
-                                                       }).show();
-                                               }
+    if (!notificationsSupported()) $('#btnnotify').addClass('disabled');
+    else if ($.cookie('notification') === 'true')
+        $('#btnnotify').addClass('active');
+
+    if ($.cookie('autoplay') === 'true') $('#btnautoplay').addClass('active');
+
+    document.getElementById('player').addEventListener('stalled', function () {
+        if (!document.getElementById('player').paused) {
+            this.pause();
+            clickLocalPlay();
+            $('.top-right')
+                .notify({
+                    message: {
+                        text: 'music stream stalled - trying to recover...',
+                    },
+                    type: 'danger',
+                    fadeOut: { enabled: true, delay: 1000 },
+                })
+                .show();
+        }
     });
 
-    document.getElementById('player').addEventListener('pause', function() {
-        this.src='';
-        this.removeAttribute("src");
-       $("#localplay-icon").removeClass("glyphicon-pause").addClass("glyphicon-play");
+    document.getElementById('player').addEventListener('pause', function () {
+        this.src = '';
+        this.removeAttribute('src');
+        $('#localplay-icon')
+            .removeClass('glyphicon-pause')
+            .addClass('glyphicon-play');
     });
 
-       document.getElementById('player').addEventListener('error', function failed(e) {
-               this.pause();
-               switch (e.target.error.code) {
-                       case e.target.error.MEDIA_ERR_ABORTED:
-                               $('.top-right').notify({
-                                       message:{text:"Audio playback aborted by user."},
-                                       type: "info",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       case e.target.error.MEDIA_ERR_NETWORK:
-                               $('.top-right').notify({
-                                       message:{text:"Network error while playing audio."},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       case e.target.error.MEDIA_ERR_DECODE:
-                               $('.top-right').notify({
-                                       message:{text:"Audio playback aborted. Did you unplug your headphones?"},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
-                               $('.top-right').notify({
-                                       message:{text:"Error while loading audio (server, network or format error)."},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       default:
-                               $('.top-right').notify({
-                                       message:{text:"Unknown error while playing audio."},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-               }
-       }, true);
+    document.getElementById('player').addEventListener(
+        'error',
+        function failed(e) {
+            this.pause();
+            switch (e.target.error.code) {
+                case e.target.error.MEDIA_ERR_ABORTED:
+                    $('.top-right')
+                        .notify({
+                            message: {
+                                text: 'Audio playback aborted by user.',
+                            },
+                            type: 'info',
+                            fadeOut: { enabled: true, delay: 1000 },
+                        })
+                        .show();
+                    break;
+                case e.target.error.MEDIA_ERR_NETWORK:
+                    $('.top-right')
+                        .notify({
+                            message: {
+                                text: 'Network error while playing audio.',
+                            },
+                            type: 'danger',
+                            fadeOut: { enabled: true, delay: 1000 },
+                        })
+                        .show();
+                    break;
+                case e.target.error.MEDIA_ERR_DECODE:
+                    $('.top-right')
+                        .notify({
+                            message: {
+                                text: 'Audio playback aborted. Did you unplug your headphones?',
+                            },
+                            type: 'danger',
+                            fadeOut: { enabled: true, delay: 1000 },
+                        })
+                        .show();
+                    break;
+                case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
+                    $('.top-right')
+                        .notify({
+                            message: {
+                                text: 'Error while loading audio (server, network or format error).',
+                            },
+                            type: 'danger',
+                            fadeOut: { enabled: true, delay: 1000 },
+                        })
+                        .show();
+                    break;
+                default:
+                    $('.top-right')
+                        .notify({
+                            message: {
+                                text: 'Unknown error while playing audio.',
+                            },
+                            type: 'danger',
+                            fadeOut: { enabled: true, delay: 1000 },
+                        })
+                        .show();
+                    break;
+            }
+        },
+        true
+    );
 });
 
 function webSocketConnect() {
-    if (typeof MozWebSocket != "undefined") {
+    if (typeof MozWebSocket != 'undefined') {
         socket = new MozWebSocket(get_appropriate_ws_url());
     } else {
         socket = new WebSocket(get_appropriate_ws_url());
     }
 
     try {
-        socket.onopen = function() {
-            console.log("connected");
-            $('.top-right').notify({
-                message:{text:"Connected to ympd"},
-                fadeOut: { enabled: true, delay: 500 }
-            }).show();
+        socket.onopen = function () {
+            console.log('connected');
+            $('.top-right')
+                .notify({
+                    message: { text: 'Connected to ympd' },
+                    fadeOut: { enabled: true, delay: 500 },
+                })
+                .show();
 
             app.run();
             /* emit initial request for output names */
             socket.send('MPD_API_GET_OUTPUTS');
-        }
+        };
 
         socket.onmessage = function got_packet(msg) {
-            if(msg.data === last_state || msg.data.length == 0)
-                return;
+            if (msg.data === last_state || msg.data.length == 0) return;
 
             var obj = JSON.parse(msg.data);
-            
 
             switch (obj.type) {
                 case 'queue':
-                    if(current_app !== 'queue')
-                        break;
+                    if (current_app !== 'queue') break;
 
                     if (obj.totalTime > 0) {
                         var hours = Math.floor(obj.totalTime / 3600);
-                        var minutes = Math.floor(obj.totalTime / 60) - hours * 60;
-                        var seconds = obj.totalTime - hours * 3600 - minutes * 60;
-
-                        $('#panel-heading-info').text('Total: ' +
-                            (hours > 0 ? hours + '\u2009h ' + (minutes < 10 ? '0' : '') : '') +
-                            minutes + '\u2009m ' + (seconds < 10 ? '0' : '') + seconds + '\u2009s');
+                        var minutes =
+                            Math.floor(obj.totalTime / 60) - hours * 60;
+                        var seconds =
+                            obj.totalTime - hours * 3600 - minutes * 60;
+
+                        $('#panel-heading-info').text(
+                            'Total: ' +
+                                (hours > 0
+                                    ? hours +
+                                      '\u2009h ' +
+                                      (minutes < 10 ? '0' : '')
+                                    : '') +
+                                minutes +
+                                '\u2009m ' +
+                                (seconds < 10 ? '0' : '') +
+                                seconds +
+                                '\u2009s'
+                        );
                     } else {
                         $('#panel-heading-info').empty();
                     }
@@ -250,79 +303,138 @@ function webSocketConnect() {
                         var seconds = obj.data[song].duration - minutes * 60;
 
                         $('#salamisandwich > tbody').append(
-                            "<tr trackid=\"" + obj.data[song].id + "\"><td>" + (obj.data[song].pos + 1) + "</td>" +
-                                "<td>"+ obj.data[song].artist +"</td>" + 
-                                "<td>"+ obj.data[song].album +"</td>" +
-                                "<td>"+ obj.data[song].title +"</td>" +
-                                "<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +
-                        "</td><td></td></tr>");
+                            '<tr trackid="' +
+                                obj.data[song].id +
+                                '"><td>' +
+                                (obj.data[song].pos + 1) +
+                                '</td>' +
+                                '<td>' +
+                                obj.data[song].artist +
+                                '</td>' +
+                                '<td>' +
+                                obj.data[song].album +
+                                '</td>' +
+                                '<td>' +
+                                obj.data[song].title +
+                                '</td>' +
+                                '<td>' +
+                                minutes +
+                                ':' +
+                                (seconds < 10 ? '0' : '') +
+                                seconds +
+                                '</td><td></td></tr>'
+                        );
                     }
 
-                    if(obj.data.length && obj.data[obj.data.length-1].pos + 1 >= pagination + MAX_ELEMENTS_PER_PAGE)
+                    if (
+                        obj.data.length &&
+                        obj.data[obj.data.length - 1].pos + 1 >=
+                            pagination + MAX_ELEMENTS_PER_PAGE
+                    )
                         $('#next').removeClass('hide');
-                    if(pagination > 0)
-                        $('#prev').removeClass('hide');
-                    if ( isTouch ) {
-                        $('#salamisandwich > tbody > tr > td:last-child').append(
-                                    "<a class=\"pull-right btn-group-hover\" href=\"#/\" " +
-                                        "onclick=\"trash($(this).parents('tr'));\">" +
-                                "<span class=\"glyphicon glyphicon-trash\"></span></a>");
+                    if (pagination > 0) $('#prev').removeClass('hide');
+                    if (isTouch) {
+                        $(
+                            '#salamisandwich > tbody > tr > td:last-child'
+                        ).append(
+                            '<a class="pull-right btn-group-hover" href="#/" ' +
+                                'onclick="trash($(this).parents(\'tr\'));">' +
+                                '<span class="glyphicon glyphicon-trash"></span></a>'
+                        );
                     } else {
                         $('#salamisandwich > tbody > tr').on({
-                            mouseover: function(){
+                            mouseover: function () {
                                 var doomed = $(this);
-                                if ( $('#btntrashmodeup').hasClass('active') )
-                                    doomed = $("#salamisandwich > tbody > tr:lt(" + ($(this).index() + 1) + ")");
-                                if ( $('#btntrashmodedown').hasClass('active') )
-                                    doomed = $("#salamisandwich > tbody > tr:gt(" + ($(this).index() - 1) + ")");
-                                $.each(doomed, function(){
-                                if($(this).children().last().has("a").length == 0)
-                                    $(this).children().last().append(
-                                        "<a class=\"pull-right btn-group-hover\" href=\"#/\" " +
-                                            "onclick=\"trash($(this).parents('tr'));\">" +
-                                    "<span class=\"glyphicon glyphicon-trash\"></span></a>")
-                                .find('a').fadeTo('fast',1);
+                                if ($('#btntrashmodeup').hasClass('active'))
+                                    doomed = $(
+                                        '#salamisandwich > tbody > tr:lt(' +
+                                            ($(this).index() + 1) +
+                                            ')'
+                                    );
+                                if ($('#btntrashmodedown').hasClass('active'))
+                                    doomed = $(
+                                        '#salamisandwich > tbody > tr:gt(' +
+                                            ($(this).index() - 1) +
+                                            ')'
+                                    );
+                                $.each(doomed, function () {
+                                    if (
+                                        $(this).children().last().has('a')
+                                            .length == 0
+                                    )
+                                        $(this)
+                                            .children()
+                                            .last()
+                                            .append(
+                                                '<a class="pull-right btn-group-hover" href="#/" ' +
+                                                    'onclick="trash($(this).parents(\'tr\'));">' +
+                                                    '<span class="glyphicon glyphicon-trash"></span></a>'
+                                            )
+                                            .find('a')
+                                            .fadeTo('fast', 1);
                                 });
                             },
-                            mouseleave: function(){
+                            mouseleave: function () {
                                 var doomed = $(this);
-                                if ( $('#btntrashmodeup').hasClass('active') )
-                                    doomed = $("#salamisandwich > tbody > tr:lt(" + ($(this).index() + 1) + ")");
-                                if ( $('#btntrashmodedown').hasClass('active') )
-                                    doomed = $("#salamisandwich > tbody > tr:gt(" + ($(this).index() - 1) + ")");
-                                $.each(doomed, function(){$(this).children().last().find("a").stop().remove();});
-                            }
+                                if ($('#btntrashmodeup').hasClass('active'))
+                                    doomed = $(
+                                        '#salamisandwich > tbody > tr:lt(' +
+                                            ($(this).index() + 1) +
+                                            ')'
+                                    );
+                                if ($('#btntrashmodedown').hasClass('active'))
+                                    doomed = $(
+                                        '#salamisandwich > tbody > tr:gt(' +
+                                            ($(this).index() - 1) +
+                                            ')'
+                                    );
+                                $.each(doomed, function () {
+                                    $(this)
+                                        .children()
+                                        .last()
+                                        .find('a')
+                                        .stop()
+                                        .remove();
+                                });
+                            },
                         });
-                    };
+                    }
 
                     $('#salamisandwich > tbody > tr').on({
-                        click: function() {
-                            $('#salamisandwich > tbody > tr').removeClass('active');
-                            socket.send('MPD_API_PLAY_TRACK,'+$(this).attr('trackid'));
+                        click: function () {
+                            $('#salamisandwich > tbody > tr').removeClass(
+                                'active'
+                            );
+                            socket.send(
+                                'MPD_API_PLAY_TRACK,' + $(this).attr('trackid')
+                            );
                             $(this).addClass('active');
                         },
                     });
                     //Helper function to keep table row from collapsing when being sorted
-                    var fixHelperModified = function(e, tr) {
-                      var $originals = tr.children();
-                      var $helper = tr.clone();
-                      $helper.children().each(function(index)
-                      {
-                        $(this).width($originals.eq(index).width())
-                      });
-                      return $helper;
+                    var fixHelperModified = function (e, tr) {
+                        var $originals = tr.children();
+                        var $helper = tr.clone();
+                        $helper.children().each(function (index) {
+                            $(this).width($originals.eq(index).width());
+                        });
+                        return $helper;
                     };
-                    
+
                     //Make queue table sortable
-                    $('#salamisandwich > tbody').sortable({
-                      helper: fixHelperModified,
-                      stop: function(event,ui) {renumber_table('#salamisandwich',ui.item)}
-                    }).disableSelection();
+                    $('#salamisandwich > tbody')
+                        .sortable({
+                            helper: fixHelperModified,
+                            stop: function (event, ui) {
+                                renumber_table('#salamisandwich', ui.item);
+                            },
+                        })
+                        .disableSelection();
                     break;
                 case 'search':
                     $('#wait').modal('hide');
                 case 'browse':
-                    if(current_app !== 'browse' && current_app !== 'search')
+                    if (current_app !== 'browse' && current_app !== 'search')
                         break;
 
                     /* The use of encodeURI() below might seem useless, but it's not. It prevents
@@ -333,304 +445,463 @@ function webSocketConnect() {
                         $('#salamisandwich > tbody').sortable('destroy');
                     }
                     for (var item in obj.data) {
-                        switch(obj.data[item].type) {
+                        switch (obj.data[item].type) {
                             case 'directory':
                                 var clazz = 'dir';
-                                if (filter !== "") {
+                                if (filter !== '') {
                                     var first = basename(obj.data[item].dir)[0];
-                                    if (filter === "num" && isNaN(first)) {
+                                    if (filter === 'num' && isNaN(first)) {
                                         clazz += ' hide';
-                                    } else if (filter >= "A" && filter <= "Z" && first.toUpperCase() !== filter) {
+                                    } else if (
+                                        filter >= 'A' &&
+                                        filter <= 'Z' &&
+                                        first.toUpperCase() !== filter
+                                    ) {
                                         clazz += ' hide';
-                                    } else if (filter === "plist") {
+                                    } else if (filter === 'plist') {
                                         clazz += ' hide';
                                     }
                                 }
                                 $('#salamisandwich > tbody').append(
-                                    "<tr uri=\"" + encodeURI(obj.data[item].dir) + "\" class=\"" + clazz + "\">" +
-                                    "<td><span class=\"glyphicon glyphicon-folder-open\"></span></td>" +
-                                    "<td colspan=\"3\"><a>" + basename(obj.data[item].dir) + "</a></td>" +
-                                    "<td></td><td></td></tr>"
+                                    '<tr uri="' +
+                                        encodeURI(obj.data[item].dir) +
+                                        '" class="' +
+                                        clazz +
+                                        '">' +
+                                        '<td><span class="glyphicon glyphicon-folder-open"></span></td>' +
+                                        '<td colspan="3"><a>' +
+                                        basename(obj.data[item].dir) +
+                                        '</a></td>' +
+                                        '<td></td><td></td></tr>'
                                 );
                                 break;
                             case 'playlist':
                                 var clazz = 'plist';
-                                if ( (filter !== "") && (filter !== "plist") ) {
+                                if (filter !== '' && filter !== 'plist') {
                                     clazz += ' hide';
                                 }
                                 $('#salamisandwich > tbody').append(
-                                    "<tr uri=\"" + encodeURI(obj.data[item].plist) + "\" class=\"" + clazz + "\">" +
-                                    "<td><span class=\"glyphicon glyphicon-list\"></span></td>" +
-                                    "<td colspan=\"3\"><a>" + basename(obj.data[item].plist) + "</a></td>" +
-                                    "<td></td><td></td></tr>"
+                                    '<tr uri="' +
+                                        encodeURI(obj.data[item].plist) +
+                                        '" class="' +
+                                        clazz +
+                                        '">' +
+                                        '<td><span class="glyphicon glyphicon-list"></span></td>' +
+                                        '<td colspan="3"><a>' +
+                                        basename(obj.data[item].plist) +
+                                        '</a></td>' +
+                                        '<td></td><td></td></tr>'
                                 );
                                 break;
                             case 'song':
-                                var minutes = Math.floor(obj.data[item].duration / 60);
-                                var seconds = obj.data[item].duration - minutes * 60;
+                                var minutes = Math.floor(
+                                    obj.data[item].duration / 60
+                                );
+                                var seconds =
+                                    obj.data[item].duration - minutes * 60;
 
                                 if (obj.data[item].artist == null) {
-                                    var artist = "<td colspan=\"2\">";
+                                    var artist = '<td colspan="2">';
                                 } else {
-                                    var artist = "<td>" + obj.data[item].artist +
-                                                     "<span>" + obj.data[item].album + "</span></td><td>";
+                                    var artist =
+                                        '<td>' +
+                                        obj.data[item].artist +
+                                        '<span>' +
+                                        obj.data[item].album +
+                                        '</span></td><td>';
                                 }
 
                                 $('#salamisandwich > tbody').append(
-                                    "<tr uri=\"" + encodeURI(obj.data[item].uri) + "\" class=\"song\">" +
-                                    "<td><span class=\"glyphicon glyphicon-music\"></span></td>" + 
-                                    "<td>" + obj.data[item].artist + "</td>" + 
-                                    "<td>" + obj.data[item].album  + "</td>" +
-                                    "<td>" + obj.data[item].title  + "</td>" +
-                                    "<td>" + minutes + ":" + (seconds < 10 ? '0' : '') + seconds +
-                                    "</td><td></td></tr>"
+                                    '<tr uri="' +
+                                        encodeURI(obj.data[item].uri) +
+                                        '" class="song">' +
+                                        '<td><span class="glyphicon glyphicon-music"></span></td>' +
+                                        '<td>' +
+                                        obj.data[item].artist +
+                                        '</td>' +
+                                        '<td>' +
+                                        obj.data[item].album +
+                                        '</td>' +
+                                        '<td>' +
+                                        obj.data[item].title +
+                                        '</td>' +
+                                        '<td>' +
+                                        minutes +
+                                        ':' +
+                                        (seconds < 10 ? '0' : '') +
+                                        seconds +
+                                        '</td><td></td></tr>'
                                 );
                                 break;
                             case 'wrap':
-                                if(current_app == 'browse') {
+                                if (current_app == 'browse') {
                                     $('#next').removeClass('hide');
                                 } else {
                                     $('#salamisandwich > tbody').append(
-                                        "<tr><td><span class=\"glyphicon glyphicon-remove\"></span></td>" +
-                                        "<td colspan=\"3\">Too many results, please refine your search!</td>" +
-                                        "<td></td><td></td></tr>"
+                                        '<tr><td><span class="glyphicon glyphicon-remove"></span></td>' +
+                                            '<td colspan="3">Too many results, please refine your search!</td>' +
+                                            '<td></td><td></td></tr>'
                                     );
                                 }
                                 break;
                         }
 
-                        if(pagination > 0)
-                            $('#prev').removeClass('hide');
-
+                        if (pagination > 0) $('#prev').removeClass('hide');
                     }
 
-                    function appendClickableIcon(appendTo, onClickAction, glyphicon) {
-                        $(appendTo).append(
-                            "<a role=\"button\" class=\"pull-right btn-group-hover\">" +
-                            "<span class=\"glyphicon glyphicon-" + glyphicon + "\"></span></a>")
-                            .find('a').click(function(e) {
+                    function appendClickableIcon(
+                        appendTo,
+                        onClickAction,
+                        glyphicon
+                    ) {
+                        $(appendTo)
+                            .append(
+                                '<a role="button" class="pull-right btn-group-hover">' +
+                                    '<span class="glyphicon glyphicon-' +
+                                    glyphicon +
+                                    '"></span></a>'
+                            )
+                            .find('a')
+                            .click(function (e) {
                                 e.stopPropagation();
-                                socket.send(onClickAction + "," + decodeURI($(this).parents("tr").attr("uri")));
-                            $('.top-right').notify({
-                                message:{
-                                    text: "\"" + $('td:nth-last-child(3)', $(this).parents("tr")).text() + "\" added"
-                                } }).show();
-                            }).fadeTo('fast',1);
+                                socket.send(
+                                    onClickAction +
+                                        ',' +
+                                        decodeURI(
+                                            $(this).parents('tr').attr('uri')
+                                        )
+                                );
+                                $('.top-right')
+                                    .notify({
+                                        message: {
+                                            text:
+                                                '"' +
+                                                $(
+                                                    'td:nth-last-child(3)',
+                                                    $(this).parents('tr')
+                                                ).text() +
+                                                '" added',
+                                        },
+                                    })
+                                    .show();
+                            })
+                            .fadeTo('fast', 1);
                     }
 
-                    if ( isTouch ) {
-                        appendClickableIcon($("#salamisandwich > tbody > tr.dir > td:last-child"), 'MPD_API_ADD_TRACK', 'plus');
-                        appendClickableIcon($("#salamisandwich > tbody > tr.song > td:last-child"), 'MPD_API_ADD_TRACK', 'play');
+                    if (isTouch) {
+                        appendClickableIcon(
+                            $(
+                                '#salamisandwich > tbody > tr.dir > td:last-child'
+                            ),
+                            'MPD_API_ADD_TRACK',
+                            'plus'
+                        );
+                        appendClickableIcon(
+                            $(
+                                '#salamisandwich > tbody > tr.song > td:last-child'
+                            ),
+                            'MPD_API_ADD_TRACK',
+                            'play'
+                        );
                     } else {
                         $('#salamisandwich > tbody > tr').on({
-                            mouseenter: function() {
-                                if($(this).is(".dir")) 
-                                    appendClickableIcon($(this).children().last(), 'MPD_API_ADD_TRACK', 'plus');
-                                else if($(this).is(".song"))
-                                    appendClickableIcon($(this).children().last(), 'MPD_API_ADD_PLAY_TRACK', 'play');
+                            mouseenter: function () {
+                                if ($(this).is('.dir'))
+                                    appendClickableIcon(
+                                        $(this).children().last(),
+                                        'MPD_API_ADD_TRACK',
+                                        'plus'
+                                    );
+                                else if ($(this).is('.song'))
+                                    appendClickableIcon(
+                                        $(this).children().last(),
+                                        'MPD_API_ADD_PLAY_TRACK',
+                                        'play'
+                                    );
+                            },
+                            mouseleave: function () {
+                                $(this)
+                                    .children()
+                                    .last()
+                                    .find('a')
+                                    .stop()
+                                    .remove();
                             },
-                            mouseleave: function(){
-                                $(this).children().last().find("a").stop().remove();
-                            }
                         });
-                    };
+                    }
                     $('#salamisandwich > tbody > tr').on({
-                        click: function() {
-                            switch($(this).attr('class')) {
+                        click: function () {
+                            switch ($(this).attr('class')) {
                                 case 'dir':
                                     pagination = 0;
-                                    browsepath = $(this).attr("uri");
-                                    $("#browse > a").attr("href", '#/browse/'+pagination+'/'+browsepath);
-                                                                       $('#filter > a').attr("href", '#/browse/'+pagination+'/'+browsepath);
-                                    app.setLocation('#/browse/'+pagination+'/'+browsepath);
-                                                                       set_filter('');
+                                    browsepath = $(this).attr('uri');
+                                    $('#browse > a').attr(
+                                        'href',
+                                        '#/browse/' +
+                                            pagination +
+                                            '/' +
+                                            browsepath
+                                    );
+                                    $('#filter > a').attr(
+                                        'href',
+                                        '#/browse/' +
+                                            pagination +
+                                            '/' +
+                                            browsepath
+                                    );
+                                    app.setLocation(
+                                        '#/browse/' +
+                                            pagination +
+                                            '/' +
+                                            browsepath
+                                    );
+                                    set_filter('');
                                     break;
                                 case 'song':
-                                    socket.send("MPD_API_ADD_TRACK," + decodeURI($(this).attr("uri")));
-                                    $('.top-right').notify({
-                                        message:{
-                                            text: "\"" + $('td:nth-last-child(3)', this).text() + "\" added"
-                                        }
-                                    }).show();
+                                    socket.send(
+                                        'MPD_API_ADD_TRACK,' +
+                                            decodeURI($(this).attr('uri'))
+                                    );
+                                    $('.top-right')
+                                        .notify({
+                                            message: {
+                                                text:
+                                                    '"' +
+                                                    $(
+                                                        'td:nth-last-child(3)',
+                                                        this
+                                                    ).text() +
+                                                    '" added',
+                                            },
+                                        })
+                                        .show();
                                     break;
                                 case 'plist':
-                                    socket.send("MPD_API_ADD_PLAYLIST," + decodeURI($(this).attr("uri")));
-                                    $('.top-right').notify({
-                                        message:{
-                                            text: "\"" + $('td:nth-last-child(3)', this).text() + "\" added"
-                                        }
-                                    }).show();
+                                    socket.send(
+                                        'MPD_API_ADD_PLAYLIST,' +
+                                            decodeURI($(this).attr('uri'))
+                                    );
+                                    $('.top-right')
+                                        .notify({
+                                            message: {
+                                                text:
+                                                    '"' +
+                                                    $(
+                                                        'td:nth-last-child(3)',
+                                                        this
+                                                    ).text() +
+                                                    '" added',
+                                            },
+                                        })
+                                        .show();
                                     break;
                             }
-                        }
+                        },
                     });
 
-                                       $('#breadcrump > li > a').on({
-                                               click: function() {
-                                                       pagination = 0;
-                                                       browsepath = $(this).attr("uri");
-                                                       $("#browse > a").attr("href", '#/browse/'+pagination+'/'+browsepath);
-                                                       $('#filter > a').attr("href", '#/browse/'+pagination+'/'+browsepath);
-                                                       app.setLocation('#/browse/'+pagination+'/'+browsepath);
-                                                       set_filter('');
-                                               }
-                                       });
+                    $('#breadcrump > li > a').on({
+                        click: function () {
+                            pagination = 0;
+                            browsepath = $(this).attr('uri');
+                            $('#browse > a').attr(
+                                'href',
+                                '#/browse/' + pagination + '/' + browsepath
+                            );
+                            $('#filter > a').attr(
+                                'href',
+                                '#/browse/' + pagination + '/' + browsepath
+                            );
+                            app.setLocation(
+                                '#/browse/' + pagination + '/' + browsepath
+                            );
+                            set_filter('');
+                        },
+                    });
 
                     break;
                 case 'state':
                     updatePlayIcon(obj.data.state);
                     updateVolumeIcon(obj.data.volume);
 
-                    if(JSON.stringify(obj) === JSON.stringify(last_state))
+                    if (JSON.stringify(obj) === JSON.stringify(last_state))
                         break;
 
-                    current_song.totalTime  = obj.data.totalTime;
+                    current_song.totalTime = obj.data.totalTime;
                     current_song.currentSongId = obj.data.currentsongid;
                     var total_minutes = Math.floor(obj.data.totalTime / 60);
                     var total_seconds = obj.data.totalTime - total_minutes * 60;
 
                     var elapsed_minutes = Math.floor(obj.data.elapsedTime / 60);
-                    var elapsed_seconds = obj.data.elapsedTime - elapsed_minutes * 60;
+                    var elapsed_seconds =
+                        obj.data.elapsedTime - elapsed_minutes * 60;
 
                     $('#volumeslider').slider(obj.data.volume);
-                    var progress = Math.floor(100*obj.data.elapsedTime/obj.data.totalTime);
+                    var progress = Math.floor(
+                        (100 * obj.data.elapsedTime) / obj.data.totalTime
+                    );
                     $('#progressbar').slider(progress);
 
-                    $('#counter')
-                    .text(elapsed_minutes + ":" + 
-                        (elapsed_seconds < 10 ? '0' : '') + elapsed_seconds + " / " +
-                        total_minutes + ":" + (total_seconds < 10 ? '0' : '') + total_seconds);
-
-                    $('#salamisandwich > tbody > tr').removeClass('active').css("font-weight", "");
-                    $('#salamisandwich > tbody > tr[trackid='+obj.data.currentsongid+']').addClass('active').css("font-weight", "bold");
-
-                    if(obj.data.random)
-                        $('#btnrandom').addClass("active")
-                    else
-                        $('#btnrandom').removeClass("active");
-
-                    if(obj.data.consume)
-                        $('#btnconsume').addClass("active")
-                    else
-                        $('#btnconsume').removeClass("active");
-
-                    if(obj.data.single)
-                        $('#btnsingle').addClass("active")
-                    else
-                        $('#btnsingle').removeClass("active");
-
-                    if(obj.data.crossfade)
-                        $('#btncrossfade').addClass("active")
-                    else
-                        $('#btncrossfade').removeClass("active");
-
-                    if(obj.data.repeat)
-                        $('#btnrepeat').addClass("active")
-                    else
-                        $('#btnrepeat').removeClass("active");
+                    $('#counter').text(
+                        elapsed_minutes +
+                            ':' +
+                            (elapsed_seconds < 10 ? '0' : '') +
+                            elapsed_seconds +
+                            ' / ' +
+                            total_minutes +
+                            ':' +
+                            (total_seconds < 10 ? '0' : '') +
+                            total_seconds
+                    );
+
+                    $('#salamisandwich > tbody > tr')
+                        .removeClass('active')
+                        .css('font-weight', '');
+                    $(
+                        '#salamisandwich > tbody > tr[trackid=' +
+                            obj.data.currentsongid +
+                            ']'
+                    )
+                        .addClass('active')
+                        .css('font-weight', 'bold');
+
+                    if (obj.data.random) $('#btnrandom').addClass('active');
+                    else $('#btnrandom').removeClass('active');
+
+                    if (obj.data.consume) $('#btnconsume').addClass('active');
+                    else $('#btnconsume').removeClass('active');
+
+                    if (obj.data.single) $('#btnsingle').addClass('active');
+                    else $('#btnsingle').removeClass('active');
+
+                    if (obj.data.crossfade)
+                        $('#btncrossfade').addClass('active');
+                    else $('#btncrossfade').removeClass('active');
+
+                    if (obj.data.repeat) $('#btnrepeat').addClass('active');
+                    else $('#btnrepeat').removeClass('active');
 
                     last_state = obj;
                     break;
                 case 'outputnames':
                     $('#btn-outputs-block button').remove();
-                    if ( Object.keys(obj.data).length ) {
-                       $.each(obj.data, function(id, name){
-                            var btn = $('<button id="btnoutput'+id+'" class="btn btn-default" onclick="toggleoutput(this, '+id+')"><span class="glyphicon glyphicon-volume-up"></span> '+name+'</button>');
+                    if (Object.keys(obj.data).length) {
+                        $.each(obj.data, function (id, name) {
+                            var btn = $(
+                                '<button id="btnoutput' +
+                                    id +
+                                    '" class="btn btn-default" onclick="toggleoutput(this, ' +
+                                    id +
+                                    ')"><span class="glyphicon glyphicon-volume-up"></span> ' +
+                                    name +
+                                    '</button>'
+                            );
                             btn.appendTo($('#btn-outputs-block'));
                         });
-                   } else {
+                    } else {
                         $('#btn-outputs-block').addClass('hide');
-                   }
+                    }
                     /* remove cache, since the buttons have been recreated */
                     last_outputs = '';
                     break;
                 case 'outputs':
-                    if(JSON.stringify(obj) === JSON.stringify(last_outputs))
+                    if (JSON.stringify(obj) === JSON.stringify(last_outputs))
                         break;
-                    $.each(obj.data, function(id, enabled){
-                        if (enabled)
-                        $('#btnoutput'+id).addClass("active");
-                        else
-                        $('#btnoutput'+id).removeClass("active");
+                    $.each(obj.data, function (id, enabled) {
+                        if (enabled) $('#btnoutput' + id).addClass('active');
+                        else $('#btnoutput' + id).removeClass('active');
                     });
                     last_outputs = obj;
                     break;
                 case 'disconnected':
-                    if($('.top-right').has('div').length == 0)
-                        $('.top-right').notify({
-                            message:{text:"ympd lost connection to MPD "},
-                            type: "danger",
-                            fadeOut: { enabled: true, delay: 1000 },
-                        }).show();
+                    if ($('.top-right').has('div').length == 0)
+                        $('.top-right')
+                            .notify({
+                                message: {
+                                    text: 'ympd lost connection to MPD ',
+                                },
+                                type: 'danger',
+                                fadeOut: { enabled: true, delay: 1000 },
+                            })
+                            .show();
                     break;
                 case 'update_queue':
-                    if(current_app === 'queue')
-                        socket.send('MPD_API_GET_QUEUE,'+pagination);
+                    if (current_app === 'queue')
+                        socket.send('MPD_API_GET_QUEUE,' + pagination);
                     break;
                 case 'song_change':
                     updatePageTitle(obj.data);
-                    $('#album').text("");
-                    $('#artist').text("");
+                    $('#album').text('');
+                    $('#artist').text('');
 
-                                       $('#btnlove').removeClass("active");
+                    $('#btnlove').removeClass('active');
 
-                    $('#currenttrack').text(" " + obj.data.title);
-                    var notification = "<strong><h4>" + obj.data.title + "</h4></strong>";
+                    $('#currenttrack').text(' ' + obj.data.title);
+                    var notification =
+                        '<strong><h4>' + obj.data.title + '</h4></strong>';
 
-                    if(obj.data.artist) {
+                    if (obj.data.artist) {
                         $('#artist').text(obj.data.artist);
-                        notification += obj.data.artist + "<br />";
+                        notification += obj.data.artist + '<br />';
                     }
-                    if(obj.data.album) {
+                    if (obj.data.album) {
                         $('#album').text(obj.data.album);
-                        notification += obj.data.album + "<br />";
+                        notification += obj.data.album + '<br />';
                     }
 
-                    if ($.cookie("notification") === "true")
-                        songNotify(obj.data.title, obj.data.artist, obj.data.album );
+                    if ($.cookie('notification') === 'true')
+                        songNotify(
+                            obj.data.title,
+                            obj.data.artist,
+                            obj.data.album
+                        );
                     else
-                        $('.top-right').notify({
-                            message:{html: notification},
-                            type: "info",
-                        }).show();        
+                        $('.top-right')
+                            .notify({
+                                message: { html: notification },
+                                type: 'info',
+                            })
+                            .show();
                     break;
                 case 'mpdhost':
                     $('#mpdhost').val(obj.data.host);
                     setLocalStream(obj.data.host);
                     $('#mpdport').val(obj.data.port);
-                    if(obj.data.passwort_set)
+                    if (obj.data.passwort_set)
                         $('#mpd_password_set').removeClass('hide');
                     break;
-                
+
                 case 'error':
-                    $('.top-right').notify({
-                        message:{text: obj.data},
-                        type: "danger",
-                    }).show();
+                    $('.top-right')
+                        .notify({
+                            message: { text: obj.data },
+                            type: 'danger',
+                        })
+                        .show();
                 default:
                     break;
             }
-        }
-
-        socket.onclose = function(){
-            console.log("disconnected");
-            $('.top-right').notify({
-                message:{text:"Connection to ympd lost, retrying in 3 seconds "},
-                type: "danger", 
-                onClose: function () {
-                    webSocketConnect();
-                }
-            }).show();
-        }
-
-    } catch(exception) {
+        };
+
+        socket.onclose = function () {
+            console.log('disconnected');
+            $('.top-right')
+                .notify({
+                    message: {
+                        text: 'Connection to ympd lost, retrying in 3 seconds ',
+                    },
+                    type: 'danger',
+                    onClose: function () {
+                        webSocketConnect();
+                    },
+                })
+                .show();
+        };
+    } catch (exception) {
         alert('<p>Error' + exception);
     }
-
 }
 
-function get_appropriate_ws_url()
-{
+function get_appropriate_ws_url() {
     var pcol;
     var u = document.URL;
     var separator;
@@ -640,115 +911,122 @@ function get_appropriate_ws_url()
     /* https:// url itself, otherwise unencrypted
     /*/
 
-    if (u.substring(0, 5) == "https") {
-        pcol = "wss://";
+    if (u.substring(0, 5) == 'https') {
+        pcol = 'wss://';
         u = u.substr(8);
     } else {
-        pcol = "ws://";
-        if (u.substring(0, 4) == "http")
-            u = u.substr(7);
+        pcol = 'ws://';
+        if (u.substring(0, 4) == 'http') u = u.substr(7);
     }
 
     u = u.split('#');
 
     if (/\/$/.test(u[0])) {
-        separator = "";
+        separator = '';
     } else {
-        separator = "/";
+        separator = '/';
     }
 
-    return pcol + u[0] + separator + "ws";
+    return pcol + u[0] + separator + 'ws';
 }
 
-var updateVolumeIcon = function(volume)
-{
-    $("#volume-icon").removeClass("glyphicon-volume-off");
-    $("#volume-icon").removeClass("glyphicon-volume-up");
-    $("#volume-icon").removeClass("glyphicon-volume-down");
+var updateVolumeIcon = function (volume) {
+    $('#volume-icon').removeClass('glyphicon-volume-off');
+    $('#volume-icon').removeClass('glyphicon-volume-up');
+    $('#volume-icon').removeClass('glyphicon-volume-down');
 
-    if(volume == 0) {
-        $("#volume-icon").addClass("glyphicon-volume-off");
+    if (volume == 0) {
+        $('#volume-icon').addClass('glyphicon-volume-off');
     } else if (volume < 50) {
-        $("#volume-icon").addClass("glyphicon-volume-down");
+        $('#volume-icon').addClass('glyphicon-volume-down');
     } else {
-        $("#volume-icon").addClass("glyphicon-volume-up");
+        $('#volume-icon').addClass('glyphicon-volume-up');
     }
-}
-
-var updatePlayIcon = function(state)
-{
-    $("#play-icon").removeClass("glyphicon-play")
-    .removeClass("glyphicon-pause");
-    $('#track-icon').removeClass("glyphicon-play")
-    .removeClass("glyphicon-pause")
-    .removeClass("glyphicon-stop");
-
-    if(state == 1) { // stop
-        $("#play-icon").addClass("glyphicon-play");
-        $('#track-icon').addClass("glyphicon-stop");
-               document.getElementById('player').pause();
-    } else if(state == 2) { // play
-        $("#play-icon").addClass("glyphicon-pause");
-        $('#track-icon').addClass("glyphicon-play");
-        if ( ($.cookie("autoplay") === "true") && (player.paused) ) {
-                       clickLocalPlay();
-               }
-    } else { // pause
-        $("#play-icon").addClass("glyphicon-play");
-        $('#track-icon').addClass("glyphicon-pause");
-               document.getElementById('player').pause();
+};
+
+var updatePlayIcon = function (state) {
+    $('#play-icon')
+        .removeClass('glyphicon-play')
+        .removeClass('glyphicon-pause');
+    $('#track-icon')
+        .removeClass('glyphicon-play')
+        .removeClass('glyphicon-pause')
+        .removeClass('glyphicon-stop');
+
+    if (state == 1) {
+        // stop
+        $('#play-icon').addClass('glyphicon-play');
+        $('#track-icon').addClass('glyphicon-stop');
+        document.getElementById('player').pause();
+    } else if (state == 2) {
+        // play
+        $('#play-icon').addClass('glyphicon-pause');
+        $('#track-icon').addClass('glyphicon-play');
+        if ($.cookie('autoplay') === 'true' && player.paused) {
+            clickLocalPlay();
+        }
+    } else {
+        // pause
+        $('#play-icon').addClass('glyphicon-play');
+        $('#track-icon').addClass('glyphicon-pause');
+        document.getElementById('player').pause();
     }
-}
+};
 
-var updatePageTitle = function(songInfo) {
-    if(!songInfo || (!songInfo.artist && !songInfo.title)) {
+var updatePageTitle = function (songInfo) {
+    if (!songInfo || (!songInfo.artist && !songInfo.title)) {
         document.title = 'ympd';
         return;
     }
-    if(songInfo.artist) {
-        if(songInfo.title) {
+    if (songInfo.artist) {
+        if (songInfo.title) {
             document.title = songInfo.artist + ' - ' + songInfo.title;
         }
     } else {
         document.title = songInfo.title;
     }
-}
+};
 
 function updateDB() {
     socket.send('MPD_API_UPDATE_DB');
-    $('.top-right').notify({
-        message:{text:"Updating MPD Database... "}
-    }).show();
+    $('.top-right')
+        .notify({
+            message: { text: 'Updating MPD Database... ' },
+        })
+        .show();
 }
 
 function clickPlay() {
-    if($('#track-icon').hasClass('glyphicon-stop'))
+    if ($('#track-icon').hasClass('glyphicon-stop'))
         socket.send('MPD_API_SET_PLAY');
-    else
-        socket.send('MPD_API_SET_PAUSE');
+    else socket.send('MPD_API_SET_PAUSE');
 }
 
 function clickLocalPlay() {
     var player = document.getElementById('player');
-    $("#localplay-icon").removeClass("glyphicon-play").removeClass("glyphicon-pause");
-       
+    $('#localplay-icon')
+        .removeClass('glyphicon-play')
+        .removeClass('glyphicon-pause');
 
-    if ( !$('#track-icon').hasClass('glyphicon-play') ) {
-               clickPlay();
-       }
+    if (!$('#track-icon').hasClass('glyphicon-play')) {
+        clickPlay();
+    }
 
-    if ( player.paused ) {
-        var mpdstream = $.cookie("mpdstream");
+    if (player.paused) {
+        var mpdstream = $.cookie('mpdstream');
 
-        if ( mpdstream ) {
+        if (mpdstream) {
             player.src = mpdstream;
-            console.log("playing mpd stream: " + player.src);
+            console.log('playing mpd stream: ' + player.src);
             player.load();
             player.play();
-            $("#localplay-icon").addClass("glyphicon-pause");
+            $('#localplay-icon').addClass('glyphicon-pause');
         } else {
-            $("#mpdstream").change(function(){ clickLocalPlay(); $(this).unbind("change"); });
-            $("#localplay-icon").addClass("glyphicon-play");
+            $('#mpdstream').change(function () {
+                clickLocalPlay();
+                $(this).unbind('change');
+            });
+            $('#localplay-icon').addClass('glyphicon-play');
             getHost();
         }
     } else {
@@ -757,43 +1035,41 @@ function clickLocalPlay() {
 }
 
 function setLocalStream(mpdhost) {
-    var mpdstream = $.cookie("mpdstream");
+    var mpdstream = $.cookie('mpdstream');
 
-    if ( !mpdstream ) {
-        mpdstream = "http://";
-        if ( mpdhost == "127.0.0.1" )
-            mpdstream += window.location.hostname;
-        else
-            mpdstream += mpdhost;
-        mpdstream += ":8000/";
+    if (!mpdstream) {
+        mpdstream = 'http://';
+        if (mpdhost == '127.0.0.1') mpdstream += window.location.hostname;
+        else mpdstream += mpdhost;
+        mpdstream += ':8000/';
 
-        $.cookie("mpdstream", mpdstream, { expires: 424242 });
+        $.cookie('mpdstream', mpdstream, { expires: 424242 });
     }
 
-    $("#mpdstream").val(mpdstream);
-    $("#mpdstream").change();
+    $('#mpdstream').val(mpdstream);
+    $('#mpdstream').change();
 }
 
 function trash(tr) {
-    if ( $('#btntrashmodeup').hasClass('active') ) {
+    if ($('#btntrashmodeup').hasClass('active')) {
         socket.send('MPD_API_RM_RANGE,0,' + (tr.index() + 1));
         tr.remove();
-    } else if ( $('#btntrashmodesingle').hasClass('active') ) {
+    } else if ($('#btntrashmodesingle').hasClass('active')) {
         socket.send('MPD_API_RM_TRACK,' + tr.attr('trackid'));
         tr.remove();
-    } else if ( $('#btntrashmodedown').hasClass('active') ) {
+    } else if ($('#btntrashmodedown').hasClass('active')) {
         socket.send('MPD_API_RM_RANGE,' + tr.index() + ',-1');
         tr.remove();
-    };
+    }
 }
 
-function renumber_table(tableID,item) {
-    was = item.children("td").first().text();//Check if first item exists!
-    is = item.index() + 1;//maybe add pagination
+function renumber_table(tableID, item) {
+    was = item.children('td').first().text(); //Check if first item exists!
+    is = item.index() + 1; //maybe add pagination
 
     if (was != is) {
-        socket.send("MPD_API_MOVE_TRACK," + was + "," + is);
-        socket.send('MPD_API_GET_QUEUE,'+pagination);
+        socket.send('MPD_API_MOVE_TRACK,' + was + ',' + is);
+        socket.send('MPD_API_GET_QUEUE,' + pagination);
     }
 }
 
@@ -802,63 +1078,79 @@ function basename(path) {
 }
 
 function clickLove() {
-    socket.send("MPD_API_SEND_MESSAGE,mpdas," + ($('#btnlove').hasClass('active') ? "unlove" : "love"));
-       if ( $('#btnlove').hasClass('active') )
-               $('#btnlove').removeClass("active");
-       else
-               $('#btnlove').addClass("active");
+    socket.send(
+        'MPD_API_SEND_MESSAGE,mpdas,' +
+            ($('#btnlove').hasClass('active') ? 'unlove' : 'love')
+    );
+    if ($('#btnlove').hasClass('active')) $('#btnlove').removeClass('active');
+    else $('#btnlove').addClass('active');
 }
 
 $('#btnrandom').on('click', function (e) {
-    socket.send("MPD_API_TOGGLE_RANDOM," + ($(this).hasClass('active') ? 0 : 1));
-
+    socket.send(
+        'MPD_API_TOGGLE_RANDOM,' + ($(this).hasClass('active') ? 0 : 1)
+    );
 });
 $('#btnconsume').on('click', function (e) {
-    socket.send("MPD_API_TOGGLE_CONSUME," + ($(this).hasClass('active') ? 0 : 1));
-
+    socket.send(
+        'MPD_API_TOGGLE_CONSUME,' + ($(this).hasClass('active') ? 0 : 1)
+    );
 });
 $('#btnsingle').on('click', function (e) {
-    socket.send("MPD_API_TOGGLE_SINGLE," + ($(this).hasClass('active') ? 0 : 1));
+    socket.send(
+        'MPD_API_TOGGLE_SINGLE,' + ($(this).hasClass('active') ? 0 : 1)
+    );
 });
-$('#btncrossfade').on('click', function(e) {
-    socket.send("MPD_API_TOGGLE_CROSSFADE," + ($(this).hasClass('active') ? 0 : 1));
+$('#btncrossfade').on('click', function (e) {
+    socket.send(
+        'MPD_API_TOGGLE_CROSSFADE,' + ($(this).hasClass('active') ? 0 : 1)
+    );
 });
 $('#btnrepeat').on('click', function (e) {
-    socket.send("MPD_API_TOGGLE_REPEAT," + ($(this).hasClass('active') ? 0 : 1));
+    socket.send(
+        'MPD_API_TOGGLE_REPEAT,' + ($(this).hasClass('active') ? 0 : 1)
+    );
 });
 
 function toggleoutput(button, id) {
-    socket.send("MPD_API_TOGGLE_OUTPUT,"+id+"," + ($(button).hasClass('active') ? 0 : 1));
+    socket.send(
+        'MPD_API_TOGGLE_OUTPUT,' +
+            id +
+            ',' +
+            ($(button).hasClass('active') ? 0 : 1)
+    );
 }
 
-$('#trashmode').children("button").on('click', function(e) {
-    $('#trashmode').children("button").removeClass("active");
-    $(this).addClass("active");
-});
+$('#trashmode')
+    .children('button')
+    .on('click', function (e) {
+        $('#trashmode').children('button').removeClass('active');
+        $(this).addClass('active');
+    });
 
 $('#btnnotify').on('click', function (e) {
-    if($.cookie("notification") === "true") {
-        $.cookie("notification", false);
+    if ($.cookie('notification') === 'true') {
+        $.cookie('notification', false);
     } else {
         Notification.requestPermission(function (permission) {
-            if(!('permission' in Notification)) {
+            if (!('permission' in Notification)) {
                 Notification.permission = permission;
             }
 
-            if (permission === "granted") {
-                $.cookie("notification", true, { expires: 424242 });
-                $('btnnotify').addClass("active");
+            if (permission === 'granted') {
+                $.cookie('notification', true, { expires: 424242 });
+                $('btnnotify').addClass('active');
             }
         });
     }
 });
 
 $('#btnautoplay').on('click', function (e) {
-    if($.cookie("autoplay") === "true") {
-        $.cookie("autoplay", false);
+    if ($.cookie('autoplay') === 'true') {
+        $.cookie('autoplay', false);
     } else {
-        $.cookie("autoplay", true, { expires: 424242 });
-        $('#btnautoplay').addClass("active");
+        $.cookie('autoplay', true, { expires: 424242 });
+        $('#btnautoplay').addClass('active');
     }
 });
 
@@ -866,9 +1158,9 @@ function getHost() {
     socket.send('MPD_API_GET_MPDHOST');
 
     function onEnter(event) {
-      if ( event.which == 13 ) {
-        confirmSettings();
-      }
+        if (event.which == 13) {
+            confirmSettings();
+        }
     }
 
     $('#mpdhost').keypress(onEnter);
@@ -879,79 +1171,77 @@ function getHost() {
 }
 
 $('#search').submit(function () {
-    app.setLocation("#/search/"+$('#search > div > input').val());
+    app.setLocation('#/search/' + $('#search > div > input').val());
     $('#wait').modal('show');
-    setTimeout(function() {
+    setTimeout(function () {
         $('#wait').modal('hide');
     }, 10000);
     return false;
 });
 
 $('.page-btn').on('click', function (e) {
-
     switch ($(this).text()) {
-        case "Next":
+        case 'Next':
             pagination += MAX_ELEMENTS_PER_PAGE;
             break;
-        case "Previous":
+        case 'Previous':
             pagination -= MAX_ELEMENTS_PER_PAGE;
-            if(pagination <= 0)
-                pagination = 0;
+            if (pagination <= 0) pagination = 0;
             break;
     }
 
-    switch(current_app) {
-        case "queue":
-            app.setLocation('#/'+pagination);
+    switch (current_app) {
+        case 'queue':
+            app.setLocation('#/' + pagination);
             break;
-        case "browse":
-            app.setLocation('#/browse/'+pagination+'/'+browsepath);
+        case 'browse':
+            app.setLocation('#/browse/' + pagination + '/' + browsepath);
             break;
     }
     e.preventDefault();
 });
 
 function addStream() {
-    if($('#streamurl').val().length > 0) {
-        socket.send('MPD_API_ADD_TRACK,'+$('#streamurl').val());
+    if ($('#streamurl').val().length > 0) {
+        socket.send('MPD_API_ADD_TRACK,' + $('#streamurl').val());
     }
-    $('#streamurl').val("");
+    $('#streamurl').val('');
     $('#addstream').modal('hide');
 }
 
 function saveQueue() {
-    if($('#playlistname').val().length > 0) {
-        socket.send('MPD_API_SAVE_QUEUE,'+$('#playlistname').val());
+    if ($('#playlistname').val().length > 0) {
+        socket.send('MPD_API_SAVE_QUEUE,' + $('#playlistname').val());
     }
     $('#savequeue').modal('hide');
 }
 
 function confirmSettings() {
-    if($('#mpd_pw').val().length + $('#mpd_pw_con').val().length > 0) {
-        if ($('#mpd_pw').val() !== $('#mpd_pw_con').val())
-        {
+    if ($('#mpd_pw').val().length + $('#mpd_pw_con').val().length > 0) {
+        if ($('#mpd_pw').val() !== $('#mpd_pw_con').val()) {
             $('#mpd_pw_con').popover('show');
-            setTimeout(function() {
+            setTimeout(function () {
                 $('#mpd_pw_con').popover('hide');
             }, 2000);
             return;
-        } else
-            socket.send('MPD_API_SET_MPDPASS,'+$('#mpd_pw').val());
+        } else socket.send('MPD_API_SET_MPDPASS,' + $('#mpd_pw').val());
     }
-    socket.send('MPD_API_SET_MPDHOST,'+$('#mpdport').val()+','+$('#mpdhost').val());
-    $.cookie("mpdstream", $("#mpdstream").val(), { expires: 424242 });
+    socket.send(
+        'MPD_API_SET_MPDHOST,' + $('#mpdport').val() + ',' + $('#mpdhost').val()
+    );
+    $.cookie('mpdstream', $('#mpdstream').val(), { expires: 424242 });
     $('#settings').modal('hide');
 }
 
 $('#mpd_password_set > button').on('click', function (e) {
     socket.send('MPD_API_SET_MPDPASS,');
-    $('#mpd_pw').val("");
-    $('#mpd_pw_con').val("");
+    $('#mpd_pw').val('');
+    $('#mpd_pw_con').val('');
     $('#mpd_password_set').addClass('hide');
-})
+});
 
 function notificationsSupported() {
-    return "Notification" in window;
+    return 'Notification' in window;
 }
 
 function songNotify(title, artist, album) {
@@ -968,19 +1258,26 @@ function songNotify(title, artist, album) {
 */
     //chrome.notifications.create(id, options, creationCallback);
 
-    var textNotification = "";
-    if(typeof artist != 'undefined' && artist.length > 0)
-        textNotification += " " + artist;
-    if(typeof album != 'undefined' && album.length > 0)
-        textNotification += "\n " + album;
+    var textNotification = '';
+    if (typeof artist != 'undefined' && artist.length > 0)
+        textNotification += ' ' + artist;
+    if (typeof album != 'undefined' && album.length > 0)
+        textNotification += '\n ' + album;
 
-    var notification = new Notification(title, {icon: 'assets/favicon.ico', body: textNotification});
-    setTimeout(function(notification) {
-        notification.close();
-    }, 3000, notification);
+    var notification = new Notification(title, {
+        icon: 'assets/favicon.ico',
+        body: textNotification,
+    });
+    setTimeout(
+        function (notification) {
+            notification.close();
+        },
+        3000,
+        notification
+    );
 }
 
-$(document).keydown(function(e){
+$(document).keydown(function (e) {
     if (e.target.tagName == 'INPUT') {
         return;
     }
@@ -1000,52 +1297,82 @@ $(document).keydown(function(e){
     e.preventDefault();
 });
 
-function set_filter (c) {
+function set_filter(c) {
     filter = c;
-       $('#filter > a').removeClass('active');
-       $('#f' + c).addClass('active');
-
-    if (filter === "") {
-       $('#salamisandwich > tbody > tr').removeClass('hide');
-       } else if (filter === "plist") {
-       $('#salamisandwich > tbody > tr.dir').addClass('hide');
-       $('#salamisandwich > tbody > tr.song').addClass('hide');
-       $('#salamisandwich > tbody > tr.plist').removeClass('hide');
+    $('#filter > a').removeClass('active');
+    $('#f' + c).addClass('active');
+
+    if (filter === '') {
+        $('#salamisandwich > tbody > tr').removeClass('hide');
+    } else if (filter === 'plist') {
+        $('#salamisandwich > tbody > tr.dir').addClass('hide');
+        $('#salamisandwich > tbody > tr.song').addClass('hide');
+        $('#salamisandwich > tbody > tr.plist').removeClass('hide');
     } else {
-               $.each($('#salamisandwich > tbody > tr'), function(i, line) {
-                       var first = basename($(line).attr('uri'))[0];
-                       if ( $(line).hasClass('song') ) {
-                               first = $(line).children().eq(3).text()[0];
-                       }
-
-                       if (filter === "num") {
-                               if (!isNaN(first)) {
-                                       $(line).removeClass('hide');
-                               } else {
-                                       $(line).addClass('hide');
-                               }
-                       } else if (filter >= "A" && filter <= "Z") {
-                               if (first.toUpperCase() === filter) {
-                                       $(line).removeClass('hide');
-                               } else {
-                                       $(line).addClass('hide');
-                               }
-                       }
-               });
-       }
+        $.each($('#salamisandwich > tbody > tr'), function (i, line) {
+            var first = basename($(line).attr('uri'))[0];
+            if ($(line).hasClass('song')) {
+                first = $(line).children().eq(3).text()[0];
+            }
+
+            if (filter === 'num') {
+                if (!isNaN(first)) {
+                    $(line).removeClass('hide');
+                } else {
+                    $(line).addClass('hide');
+                }
+            } else if (filter >= 'A' && filter <= 'Z') {
+                if (first.toUpperCase() === filter) {
+                    $(line).removeClass('hide');
+                } else {
+                    $(line).addClass('hide');
+                }
+            }
+        });
+    }
 }
 
-function add_filter () {
-       $('#filter').empty();
-    $('#filter').append('&nbsp;<a onclick="set_filter(\'\')" href="#/browse/'+pagination+'/'+browsepath+'">All</a>');
-    $('#filter').append('&nbsp;<a id="fnum" onclick="set_filter(\'num\')" href="#/browse/'+pagination+'/'+browsepath+'">#</a>');
+function add_filter() {
+    $('#filter').empty();
+    $('#filter').append(
+        '&nbsp;<a onclick="set_filter(\'\')" href="#/browse/' +
+            pagination +
+            '/' +
+            browsepath +
+            '">All</a>'
+    );
+    $('#filter').append(
+        '&nbsp;<a id="fnum" onclick="set_filter(\'num\')" href="#/browse/' +
+            pagination +
+            '/' +
+            browsepath +
+            '">#</a>'
+    );
 
     for (i = 65; i <= 90; i++) {
         var c = String.fromCharCode(i);
-        $('#filter').append('&nbsp;<a id="f' + c + '" onclick="set_filter(\'' + c + '\');" href="#/browse/' + pagination + '/' + browsepath + '">' + c + '</a>');
+        $('#filter').append(
+            '&nbsp;<a id="f' +
+                c +
+                '" onclick="set_filter(\'' +
+                c +
+                '\');" href="#/browse/' +
+                pagination +
+                '/' +
+                browsepath +
+                '">' +
+                c +
+                '</a>'
+        );
     }
 
-    $('#filter').append('&nbsp;<a id="fplist" onclick="set_filter(\'plist\')" href="#/browse/'+pagination+'/'+browsepath+'" class="glyphicon glyphicon-list"></a>');
-       $('#f' + filter).addClass('active');
+    $('#filter').append(
+        '&nbsp;<a id="fplist" onclick="set_filter(\'plist\')" href="#/browse/' +
+            pagination +
+            '/' +
+            browsepath +
+            '" class="glyphicon glyphicon-list"></a>'
+    );
+    $('#f' + filter).addClass('active');
     $('#filter').removeClass('hide');
 }
index c93360f..9f35359 100644 (file)
 <!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="viewport" content="width=320">
-  <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="viewport" content="width=320" />
+    <meta
+      name="description"
+      content="ympd - fast and lightweight MPD webclient"
+    />
+    <meta name="author" content="andy@ndyk.de" />
 
-  <title>ympd player</title>
+    <title>ympd player</title>
 
-  <!-- Bootstrap core CSS -->
-  <link href="css/bootstrap.css" rel="stylesheet">
-  <link href="css/bootstrap-theme.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">
-  <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 type="text/javascript">
-function clickLocalPlay() {
-    var player = document.getElementById('player');
-    $("#localplay-icon").removeClass("glyphicon-play").removeClass("glyphicon-pause");
+    <!-- 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/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 type="text/javascript">
+      function clickLocalPlay() {
+        var player = document.getElementById('player');
+        $('#localplay-icon')
+          .removeClass('glyphicon-play')
+          .removeClass('glyphicon-pause');
 
+        if (player.paused) {
+          var mpdstream = $.cookie('mpdstream');
+          player.src = mpdstream;
+          console.log('playing mpd stream: ' + player.src);
+          player.load();
+          player.play();
+          $('#localplay-icon').addClass('glyphicon-pause');
+        } else {
+          player.pause();
+          player.src = '';
+          player.removeAttribute('src');
+          $('#localplay-icon').addClass('glyphicon-play');
+        }
+      }
 
-    if ( player.paused ) {
-        var mpdstream = $.cookie("mpdstream");
-        player.src = mpdstream;
-        console.log("playing mpd stream: " + player.src);
-        player.load();
-        player.play();
-        $("#localplay-icon").addClass("glyphicon-pause");
-    } else {
-        player.pause();
-        player.src='';
-        player.removeAttribute("src");
-        $("#localplay-icon").addClass("glyphicon-play");
-    }
-}
+      $(document).ready(function () {
+        document
+          .getElementById('player')
+          .addEventListener('stalled', function () {
+            if (!document.getElementById('player').paused) {
+              this.pause();
+              clickLocalPlay();
+              $('.top-right')
+                .notify({
+                  message: {
+                    text: 'music stream stalled - trying to recover...',
+                  },
+                  type: 'danger',
+                  fadeOut: { enabled: true, delay: 1000 },
+                })
+                .show();
+            }
+          });
 
-$(document).ready(function(){
-       document.getElementById('player').addEventListener('stalled', function() {
-                                               if ( !document.getElementById('player').paused ) {
-                                                       this.pause();
-                                                       clickLocalPlay();
-                                                       $('.top-right').notify({
-                                                               message:{text:"music stream stalled - trying to recover..."},
-                                                               type: "danger",
-                                                               fadeOut: { enabled: true, delay: 1000 },
-                                                       }).show();
-                                               }
-       });
+        document
+          .getElementById('player')
+          .addEventListener('pause', function () {
+            this.src = '';
+            this.removeAttribute('src');
+            $('#localplay-icon')
+              .removeClass('glyphicon-pause')
+              .addClass('glyphicon-play');
+          });
 
-       document.getElementById('player').addEventListener('pause', function() {
-               this.src='';
-               this.removeAttribute("src");
-               $("#localplay-icon").removeClass("glyphicon-pause").addClass("glyphicon-play");
-       });
-
-       document.getElementById('player').addEventListener('error', function failed(e) {
-               this.pause();
-               switch (e.target.error.code) {
-                       case e.target.error.MEDIA_ERR_ABORTED:
-                               $('.top-right').notify({
-                                       message:{text:"Audio playback aborted by user."},
-                                       type: "info",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       case e.target.error.MEDIA_ERR_NETWORK:
-                               $('.top-right').notify({
-                                       message:{text:"Network error while playing audio."},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       case e.target.error.MEDIA_ERR_DECODE:
-                               $('.top-right').notify({
-                                       message:{text:"Audio playback aborted. Did you unplug your headphones?"},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
-                               $('.top-right').notify({
-                                       message:{text:"Error while loading audio (server, network or format error)."},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-                       default:
-                               $('.top-right').notify({
-                                       message:{text:"Unknown error while playing audio."},
-                                       type: "danger",
-                                       fadeOut: { enabled: true, delay: 1000 },
-                               }).show();
-                               break;
-               }
-       }, true);
-});
-</script>
-</head>
-<body>
-  <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
-    <div class="container">
-        <a class="navbar-brand" href="/" target="_blank"><span class="glyphicon glyphicon-play-circle"></span> ympd</a>
+        document.getElementById('player').addEventListener(
+          'error',
+          function failed(e) {
+            this.pause();
+            switch (e.target.error.code) {
+              case e.target.error.MEDIA_ERR_ABORTED:
+                $('.top-right')
+                  .notify({
+                    message: { text: 'Audio playback aborted by user.' },
+                    type: 'info',
+                    fadeOut: { enabled: true, delay: 1000 },
+                  })
+                  .show();
+                break;
+              case e.target.error.MEDIA_ERR_NETWORK:
+                $('.top-right')
+                  .notify({
+                    message: { text: 'Network error while playing audio.' },
+                    type: 'danger',
+                    fadeOut: { enabled: true, delay: 1000 },
+                  })
+                  .show();
+                break;
+              case e.target.error.MEDIA_ERR_DECODE:
+                $('.top-right')
+                  .notify({
+                    message: {
+                      text: 'Audio playback aborted. Did you unplug your headphones?',
+                    },
+                    type: 'danger',
+                    fadeOut: { enabled: true, delay: 1000 },
+                  })
+                  .show();
+                break;
+              case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
+                $('.top-right')
+                  .notify({
+                    message: {
+                      text: 'Error while loading audio (server, network or format error).',
+                    },
+                    type: 'danger',
+                    fadeOut: { enabled: true, delay: 1000 },
+                  })
+                  .show();
+                break;
+              default:
+                $('.top-right')
+                  .notify({
+                    message: { text: 'Unknown error while playing audio.' },
+                    type: 'danger',
+                    fadeOut: { enabled: true, delay: 1000 },
+                  })
+                  .show();
+                break;
+            }
+          },
+          true
+        );
+      });
+    </script>
+  </head>
+  <body>
+    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
+      <div class="container">
+        <a class="navbar-brand" href="/" target="_blank"
+          ><span class="glyphicon glyphicon-play-circle"></span> ympd</a
+        >
+      </div>
     </div>
-  </div>
 
-  <div class="container starter-template">
-    <div class="row">
-      <div class="col-md-10 col-xs-12">
-            <audio id="player" preload="none"></audio>
-            <button type="button" class="btn btn-default btn-lg center-block" onclick="clickLocalPlay()">
-              <span id="localplay-icon" class="glyphicon glyphicon-play"></span>
-            </button>
-        <div class="notifications top-right"></div>
+    <div class="container starter-template">
+      <div class="row">
+        <div class="col-md-10 col-xs-12">
+          <audio id="player" preload="none"></audio>
+          <button
+            type="button"
+            class="btn btn-default btn-lg center-block"
+            onclick="clickLocalPlay()"
+          >
+            <span id="localplay-icon" class="glyphicon glyphicon-play"></span>
+          </button>
+          <div class="notifications top-right"></div>
+        </div>
       </div>
     </div>
-  </div>
-</body>
+  </body>
 </html>