luci-app-minidlna: convert to client side rendering
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
0d68d0ad7b
commit
9ae591b38f
9 changed files with 180 additions and 246 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
});
|
|
@ -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
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
<%+minidlna_status%>
|
|
@ -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>
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"admin/services/minidlna": {
|
||||
"title": "miniDLNA",
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "minidlna"
|
||||
},
|
||||
"depends": {
|
||||
"uci": { "minidlna": true }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue