luci-app-minidlna: convert to client side rendering
authorJo-Philipp Wich <jo@mein.io>
Sun, 1 Mar 2020 19:21:14 +0000 (20:21 +0100)
committerJo-Philipp Wich <jo@mein.io>
Sun, 1 Mar 2020 19:21:14 +0000 (20:21 +0100)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
applications/luci-app-minidlna/Makefile
applications/luci-app-minidlna/htdocs/luci-static/resources/view/minidlna.js [new file with mode: 0644]
applications/luci-app-minidlna/htdocs/luci-static/resources/view/status/include/80_minidlna.js [new file with mode: 0644]
applications/luci-app-minidlna/luasrc/controller/minidlna.lua [deleted file]
applications/luci-app-minidlna/luasrc/model/cbi/minidlna.lua [deleted file]
applications/luci-app-minidlna/luasrc/view/admin_status/index/minidlna.htm [deleted file]
applications/luci-app-minidlna/luasrc/view/minidlna_status.htm [deleted file]
applications/luci-app-minidlna/root/usr/share/luci/menu.d/luci-app-minidlna.json [new file with mode: 0644]
applications/luci-app-minidlna/root/usr/share/rpcd/acl.d/luci-app-minidlna.json [new file with mode: 0644]

index 3d3ec4d52eebf431e7673d405cf7fa2fd2cd7e8f..4790aa32ced30fa14cbd216bc09879e9554006e7 100644 (file)
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=LuCI Support for miniDLNA
-LUCI_DEPENDS:=+luci-compat +minidlna
+LUCI_DEPENDS:=+minidlna
 
 include ../../luci.mk
 
diff --git a/applications/luci-app-minidlna/htdocs/luci-static/resources/view/minidlna.js b/applications/luci-app-minidlna/htdocs/luci-static/resources/view/minidlna.js
new file mode 100644 (file)
index 0000000..ff3cae1
--- /dev/null
@@ -0,0 +1,118 @@
+'use strict';
+'require fs';
+'require uci';
+'require form';
+'require tools.widgets as widgets';
+
+var CBIMiniDLNAStatus = form.DummyValue.extend({
+       load: function() {
+               var port = +uci.get_first('minidlna', 'minidlna', 'port');
+
+               if (isNaN(port) || port < 0 || port > 65535)
+                       port = 8200;
+
+               return L.resolveDefault(fs.exec_direct('/usr/bin/wget', [ '-q', 'http://127.0.0.1:%d/'.format(port), '-O', '-' ]), null)
+                       .then(L.bind(function(html) {
+                               if (html == null) {
+                                       this.default = E('em', {}, [ _('The miniDLNA service is not running.') ]);
+                               }
+                               else {
+                                       var audio = html.match(/Audio files<\/td><td>(\d+)/),
+                                           video = html.match(/Video files<\/td><td>(\d+)/),
+                                           image = html.match(/Image files<\/td><td>(\d+)/);
+
+                                       this.default = _('The miniDLNA service is active, serving %d audio, %d video and %d image files.')
+                                               .format(audio ? +audio[1] : 0, video ? +video[1] : 0, image ? +image[1] : 0);
+                               }
+                       }, this));
+       }
+});
+
+return L.view.extend({
+       render: function() {
+               var m, s, o;
+
+               m = new form.Map('minidlna', _('miniDLNA'), _('MiniDLNA is server software with the aim of being fully compliant with DLNA/UPnP-AV clients.'));
+
+               s = m.section(form.TypedSection);
+               s.title = _('Status');
+               s.anonymous = true;
+               s.cfgsections = function() { return [ '_status' ] };
+
+               o = s.option(CBIMiniDLNAStatus);
+
+
+               s = m.section(form.TypedSection, 'minidlna', 'miniDLNA Settings');
+               s.anonymous = true;
+               s.addremove = false;
+
+               s.tab('general', _('General Settings'));
+               s.tab('advanced', _('Advanced Settings'));
+
+               o = s.taboption('general', form.Flag, 'enabled', _('Enable'));
+
+               o = s.taboption('general', form.Value, 'port', _('Port'),
+                       _('Port for HTTP (descriptions, SOAP, media transfer) traffic.'));
+               o.default = '8200';
+
+               o = s.taboption('general', widgets.DeviceSelect, 'interface', _('Interfaces'), _('Network interfaces to serve.'));
+               o.multiple = true;
+               o.noaliases = true;
+               o.cfgvalue = function(section_id) {
+                       return L.toArray(uci.get('minidlna', section_id, 'interface')).join(',').split(/[ \t,]+/);
+               };
+               o.write = function(section_id, value) {
+                       return uci.set('minidlna', section_id, 'interface', L.toArray(value).join(','));
+               };
+
+               o = s.taboption('general', form.Value, 'friendly_name', _('Friendly name'), _('Set this if you want to customize the name that shows up on your clients.'));
+
+               o = s.taboption('general', form.ListValue, 'root_container', _('Root container'));
+               o.value('.', _('Standard container'));
+               o.value('B', _('Browse directory'));
+               o.value('M', _('Music'));
+               o.value('V', _('Video'));
+               o.value('P', _('Pictures'));
+
+               o = s.taboption('general', form.DynamicList, 'media_dir', _('Media directories'), _('Set this to the directory you want scanned. If you want to restrict the directory to a specific content type, you can prepend the type (\'A\' for audio, \'V\' for video, \'P\' for images), followed by a comma, to the directory (eg. A,/mnt/media/Music). Multiple directories can be specified.'));
+
+               o = s.taboption('general', form.DynamicList, 'album_art_names', _('Album art names'), _('This is a list of file names to check for when searching for album art.'));
+               o.cfgvalue = function(section_id) {
+                       return L.toArray(uci.get('minidlna', section_id, 'album_art_names')).join('/').split(/\//);
+               };
+               o.write = function(section_id, value) {
+                       return uci.set('minidlna', section_id, 'album_art_names', L.toArray(value).join('/'));
+               };
+
+               o = s.taboption('advanced', form.Value, 'db_dir', _('Database directory'), _('Set this if you would like to specify the directory where you want MiniDLNA to store its database and album art cache.'));
+
+               o = s.taboption('advanced', form.Value, 'log_dir', _('Log directory'), _('Set this if you would like to specify the directory where you want MiniDLNA to store its log file.'));
+
+               o = s.taboption('advanced', form.Flag, 'inotify', _('Enable inotify'), _('Set this to enable inotify monitoring to automatically discover new files.'));
+               o.default = o.enabled;
+
+               o = s.taboption('advanced', form.Flag, 'enable_tivo', _('Enable TIVO'), _('Set this to enable support for streaming .jpg and .mp3 files to a TiVo supporting HMO.'));
+
+               o = s.taboption('advanced', form.Flag, 'wide_links', _('Allow wide links'), _('Set this to allow serving content outside the media root (via symlinks).'));
+
+               o = s.taboption('advanced', form.Flag, 'strict_dlna', _('Strict to DLNA standard'), _('Set this to strictly adhere to DLNA standards. This will allow server-side downscaling of very large JPEG images, which may hurt JPEG serving performance on (at least) Sony DLNA products.'));
+
+               o = s.taboption('advanced', form.Value, 'presentation_url', _('Presentation URL'));
+
+               o = s.taboption('advanced', form.Value, 'notify_interval', _('Notify interval'), _('Notify interval in seconds.'));
+               o.placeholder = '900';
+
+               o = s.taboption('advanced', form.Value, 'serial', _('Announced serial number'), _('Serial number the miniDLNA daemon will report to clients in its XML description.'));
+               o.placeholder = '12345678';
+
+               o = s.taboption('advanced', form.Value, 'uuid', _('Announced UUID'));
+               o.placeholder = '019f9a56-ff60-44c0-9edc-eae88d09fa05';
+
+               o = s.taboption('advanced', form.Value, 'model_number', _('Announced model number'), _('Model number the miniDLNA daemon will report to clients in its XML description.'));
+               o.placeholder = '1';
+
+               o = s.taboption('advanced', form.Value, 'minissdpsocket', _('miniSSDP socket'), _('Specify the path to the MiniSSDPd socket.'));
+
+               return m.render();
+       }
+});
diff --git a/applications/luci-app-minidlna/htdocs/luci-static/resources/view/status/include/80_minidlna.js b/applications/luci-app-minidlna/htdocs/luci-static/resources/view/status/include/80_minidlna.js
new file mode 100644 (file)
index 0000000..f67e5f8
--- /dev/null
@@ -0,0 +1,30 @@
+'use strict';
+'require fs';
+'require uci';
+
+return L.Class.extend({
+       title: _('miniDLNA Status'),
+
+       load: function() {
+               return uci.load('minidlna').then(function() {
+                       var port = +uci.get_first('minidlna', 'minidlna', 'port');
+
+                       if (isNaN(port) || port < 0 || port > 65535)
+                               port = 8200;
+
+                       return L.resolveDefault(fs.exec_direct('/usr/bin/wget', [ '-q', 'http://127.0.0.1:%d/'.format(port), '-O', '-' ]), null);
+               });
+       },
+
+       render: function(html) {
+               if (html == null)
+                       return E('em', {}, [ _('The miniDLNA service is not running.') ]);
+
+               var audio = html.match(/Audio files<\/td><td>(\d+)/),
+                   video = html.match(/Video files<\/td><td>(\d+)/),
+                   image = html.match(/Image files<\/td><td>(\d+)/);
+
+               return _('The miniDLNA service is active, serving %d audio, %d video and %d image files.')
+                       .format(audio ? +audio[1] : 0, video ? +video[1] : 0, image ? +image[1] : 0);
+       }
+});
diff --git a/applications/luci-app-minidlna/luasrc/controller/minidlna.lua b/applications/luci-app-minidlna/luasrc/controller/minidlna.lua
deleted file mode 100644 (file)
index 3420f30..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
--- Copyright 2012 Gabor Juhos <juhosg@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
-module("luci.controller.minidlna", package.seeall)
-
-function index()
-       if not nixio.fs.access("/etc/config/minidlna") then
-               return
-       end
-
-       local page
-
-       page = entry({"admin", "services", "minidlna"}, cbi("minidlna"), _("miniDLNA"))
-       page.dependent = true
-
-       entry({"admin", "services", "minidlna_status"}, call("minidlna_status"))
-end
-
-function minidlna_status()
-       local sys  = require "luci.sys"
-       local uci  = require "luci.model.uci".cursor()
-       local port = tonumber(uci:get_first("minidlna", "minidlna", "port"))
-
-       local status = {
-               running = (sys.call("pidof minidlnad >/dev/null") == 0),
-               audio   = 0,
-               video   = 0,
-               image   = 0
-       }
-
-       if status.running then
-               local fd = sys.httpget("http://127.0.0.1:%d/" % (port or 8200), true)
-               if fd then
-                       local html = fd:read("*a")
-                       if html then
-                               status.audio = (tonumber(html:match("Audio files</td><td>(%d+)")) or 0)
-                               status.video = (tonumber(html:match("Video files</td><td>(%d+)")) or 0)
-                               status.image = (tonumber(html:match("Image files</td><td>(%d+)")) or 0)
-                       end
-                       fd:close()
-               end
-       end
-
-       luci.http.prepare_content("application/json")
-       luci.http.write_json(status)
-end
diff --git a/applications/luci-app-minidlna/luasrc/model/cbi/minidlna.lua b/applications/luci-app-minidlna/luasrc/model/cbi/minidlna.lua
deleted file mode 100644 (file)
index 9dcc527..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
--- Copyright 2012 Gabor Juhos <juhosg@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
-local m, s, o
-
-m = Map("minidlna", translate("miniDLNA"),
-       translate("MiniDLNA is server software with the aim of being fully compliant with DLNA/UPnP-AV clients."))
-
-m:section(SimpleSection).template  = "minidlna_status"
-
-s = m:section(TypedSection, "minidlna", "miniDLNA Settings")
-s.addremove = false
-s.anonymous = true
-
-s:tab("general", translate("General Settings"))
-s:tab("advanced", translate("Advanced Settings"))
-
-o = s:taboption("general", Flag, "enabled", translate("Enable"))
-o.rmempty = false
-
-function o.cfgvalue(self, section)
-       return luci.sys.init.enabled("minidlna") and self.enabled or self.disabled
-end
-
-function o.write(self, section, value)
-       if value == "1" then
-               luci.sys.init.enable("minidlna")
-               luci.sys.call("/etc/init.d/minidlna start >/dev/null")
-       else
-               luci.sys.call("/etc/init.d/minidlna stop >/dev/null")
-               luci.sys.init.disable("minidlna")
-       end
-
-       return Flag.write(self, section, value)
-end
-
-o = s:taboption("general", Value, "port", translate("Port"),
-       translate("Port for HTTP (descriptions, SOAP, media transfer) traffic."))
-o.datatype = "port"
-o.default = 8200
-
-
-o = s:taboption("general", Value, "interface", translate("Interfaces"),
-       translate("Network interfaces to serve."))
-
-o.template = "cbi/network_ifacelist"
-o.widget   = "checkbox"
-o.nocreate = true
-
-function o.cfgvalue(self, section)
-       local rv = { }
-       local val = Value.cfgvalue(self, section)
-       if val then
-               local ifc
-               for ifc in val:gmatch("[^,%s]+") do
-                       rv[#rv+1] = ifc
-               end
-       end
-       return rv
-end
-
-function o.write(self, section, value)
-       local rv = { }
-       local ifc
-       for ifc in luci.util.imatch(value) do
-               rv[#rv+1] = ifc
-       end
-       Value.write(self, section, table.concat(rv, ","))
-end
-
-
-o = s:taboption("general", Value, "friendly_name", translate("Friendly name"),
-       translate("Set this if you want to customize the name that shows up on your clients."))
-o.rmempty = true
-o.placeholder = "OpenWrt DLNA Server"
-
-o = s:taboption("advanced", Value, "db_dir", translate("Database directory"),
-       translate("Set this if you would like to specify the directory where you want MiniDLNA to store its database and album art cache."))
-o.rmempty = true
-o.placeholder = "/var/cache/minidlna"
-
-o = s:taboption("advanced", Value, "log_dir", translate("Log directory"),
-       translate("Set this if you would like to specify the directory where you want MiniDLNA to store its log file."))
-o.rmempty = true
-o.placeholder = "/var/log"
-
-s:taboption("advanced", Flag, "inotify", translate("Enable inotify"),
-       translate("Set this to enable inotify monitoring to automatically discover new files."))
-
-s:taboption("advanced", Flag, "enable_tivo", translate("Enable TIVO"),
-       translate("Set this to enable support for streaming .jpg and .mp3 files to a TiVo supporting HMO."))
-o.rmempty = true
-
-s:taboption("advanced", Flag, "wide_links", translate("Allow wide links"),
-       translate("Set this to allow serving content outside the media root (via symlinks)."))
-o.rmempty = true
-
-o = s:taboption("advanced", Flag, "strict_dlna", translate("Strict to DLNA standard"),
-       translate("Set this to strictly adhere to DLNA standards. This will allow server-side downscaling of very large JPEG images, which may hurt JPEG serving performance on (at least) Sony DLNA products."))
-o.rmempty = true
-
-o = s:taboption("advanced", Value, "presentation_url", translate("Presentation URL"))
-o.rmempty = true
-o.placeholder = "http://192.168.1.1/"
-
-o = s:taboption("advanced", Value, "notify_interval", translate("Notify interval"),
-       translate("Notify interval in seconds."))
-o.datatype = "uinteger"
-o.placeholder = 900
-
-o = s:taboption("advanced", Value, "serial", translate("Announced serial number"),
-       translate("Serial number the miniDLNA daemon will report to clients in its XML description."))
-o.placeholder = "12345678"
-
-s:taboption("advanced", Value, "model_number", translate("Announced model number"),
-       translate("Model number the miniDLNA daemon will report to clients in its XML description."))
-o.placholder = "1"
-
-o = s:taboption("advanced", Value, "minissdpsocket", translate("miniSSDP socket"),
-       translate("Specify the path to the MiniSSDPd socket."))
-o.rmempty = true
-o.placeholder = "/var/run/minissdpd.sock"
-
-o = s:taboption("general", ListValue, "root_container", translate("Root container"))
-o:value(".", translate("Standard container"))
-o:value("B", translate("Browse directory"))
-o:value("M", translate("Music"))
-o:value("V", translate("Video"))
-o:value("P", translate("Pictures"))
-
-
-s:taboption("general", DynamicList, "media_dir", translate("Media directories"),
-       translate("Set this to the directory you want scanned. If you want to restrict the directory to a specific content type, you can prepend the type ('A' for audio, 'V' for video, 'P' for images), followed by a comma, to the directory (eg. A,/mnt/media/Music). Multiple directories can be specified."))
-
-
-o = s:taboption("general", DynamicList, "album_art_names", translate("Album art names"),
-       translate("This is a list of file names to check for when searching for album art."))
-o.rmempty = true
-o.placeholder = "Cover.jpg"
-
-function o.cfgvalue(self, section)
-       local rv = { }
-
-       local val = Value.cfgvalue(self, section)
-       if type(val) == "table" then
-               val = table.concat(val, "/")
-       elseif not val then
-               val = ""
-       end
-
-       local file
-       for file in val:gmatch("[^/%s]+") do
-               rv[#rv+1] = file
-       end
-
-       return rv
-end
-
-function o.write(self, section, value)
-       local rv = { }
-       local file
-       for file in luci.util.imatch(value) do
-               rv[#rv+1] = file
-       end
-       Value.write(self, section, table.concat(rv, "/"))
-end
-
-
-return m
diff --git a/applications/luci-app-minidlna/luasrc/view/admin_status/index/minidlna.htm b/applications/luci-app-minidlna/luasrc/view/admin_status/index/minidlna.htm
deleted file mode 100644 (file)
index b2feeb2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<%+minidlna_status%>
diff --git a/applications/luci-app-minidlna/luasrc/view/minidlna_status.htm b/applications/luci-app-minidlna/luasrc/view/minidlna_status.htm
deleted file mode 100644 (file)
index eaf3721..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<script type="text/javascript">//<![CDATA[
-       XHR.poll(-1, '<%=url("admin/services/minidlna_status")%>', null,
-               function(x, st)
-               {
-                       var tb = document.getElementById('minidlna_status');
-                       if (st && tb)
-                       {
-                               if (st.running)
-                               {
-                                       tb.innerHTML = String.format(
-                                               '<%:The miniDLNA service is active, serving %d audio, %d video and %d image files.%>',
-                                                       st.audio, st.video, st.image
-                                       );
-                               }
-                               else
-                               {
-                                       tb.innerHTML = '<em><%:The miniDLNA service is not running.%></em>';
-                               }
-                       }
-               }
-       );
-//]]></script>
-
-<fieldset class="cbi-section">
-       <legend><%:miniDLNA Status%></legend>
-       <p id="minidlna_status">
-               <em><%:Collecting data...%></em>
-       </p>
-</fieldset>
diff --git a/applications/luci-app-minidlna/root/usr/share/luci/menu.d/luci-app-minidlna.json b/applications/luci-app-minidlna/root/usr/share/luci/menu.d/luci-app-minidlna.json
new file mode 100644 (file)
index 0000000..ddb4129
--- /dev/null
@@ -0,0 +1,12 @@
+{
+       "admin/services/minidlna": {
+               "title": "miniDLNA",
+               "action": {
+                       "type": "view",
+                       "path": "minidlna"
+               },
+               "depends": {
+                       "uci": { "minidlna": true }
+               }
+       }
+}
diff --git a/applications/luci-app-minidlna/root/usr/share/rpcd/acl.d/luci-app-minidlna.json b/applications/luci-app-minidlna/root/usr/share/rpcd/acl.d/luci-app-minidlna.json
new file mode 100644 (file)
index 0000000..a49d2f1
--- /dev/null
@@ -0,0 +1,19 @@
+{
+       "luci-app-minidlna": {
+               "description": "Grant access to minidlna status and configuration",
+               "read": {
+                       "cgi-io": [ "exec" ],
+                       "file": {
+                               "/usr/bin/wget -q http://127.0.0.1:[0-9]*/ -O -": [ "exec" ]
+                       },
+                       "uci": [
+                               "minidlna"
+                       ]
+               },
+               "write": {
+                       "uci": [
+                               "minidlna"
+                       ]
+               }
+       }
+}