🛸 Sync 2022-11-10 20:30:59
@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=forked-daapd
|
||||
PKG_VERSION:=27.4
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
|
||||
PKG_SOURCE_URL:=https://github.com/ejurgensen/$(PKG_NAME)/releases/download/$(PKG_VERSION)/
|
||||
|
@ -1,414 +0,0 @@
|
||||
# A quick guide to configuring forked-daapd:
|
||||
#
|
||||
# For regular use, the most important setting to configure is "directories",
|
||||
# which should be the location of your media. Whatever user you have set as
|
||||
# "uid" must have read access to this location. If the location is a network
|
||||
# mount, please see the README.
|
||||
#
|
||||
# In all likelihood, that's all you need to do!
|
||||
|
||||
general {
|
||||
# Username
|
||||
# Make sure the user has read access to the library directories you set
|
||||
# below, and full access to the databases, log and local audio
|
||||
uid = "daapd"
|
||||
|
||||
# Database location
|
||||
# db_path = "/var/cache/forked-daapd/songs3.db"
|
||||
|
||||
# Log file and level
|
||||
# Available levels: fatal, log, warning, info, debug, spam
|
||||
logfile = "/var/log/forked-daapd.log"
|
||||
loglevel = log
|
||||
|
||||
# Admin password for the web interface
|
||||
# Note that access to the web interface from computers in
|
||||
# "trusted_network" (see below) does not require password
|
||||
# admin_password = ""
|
||||
|
||||
# Websocket port for the web interface.
|
||||
# websocket_port = 3688
|
||||
|
||||
# Sets who is allowed to connect without authorisation. This applies to
|
||||
# client types like Remotes, DAAP clients (iTunes) and to the web
|
||||
# interface. Options are "any", "localhost" or the prefix to one or
|
||||
# more ipv4/6 networks. The default is { "localhost", "192.168", "fd" }
|
||||
# trusted_networks = { "localhost", "192.168", "fd" }
|
||||
|
||||
# Enable/disable IPv6
|
||||
ipv6 = no
|
||||
|
||||
# Location of cache database
|
||||
# cache_path = "/var/cache/forked-daapd/cache.db"
|
||||
|
||||
# DAAP requests that take longer than this threshold (in msec) get their
|
||||
# replies cached for next time. Set to 0 to disable caching.
|
||||
# cache_daap_threshold = 1000
|
||||
|
||||
# When starting playback, autoselect speaker (if none of the previously
|
||||
# selected speakers/outputs are available)
|
||||
# speaker_autoselect = no
|
||||
|
||||
# Most modern systems have a high-resolution clock, but if you are on an
|
||||
# unusual platform and experience audio drop-outs, you can try changing
|
||||
# this option
|
||||
# high_resolution_clock = yes
|
||||
}
|
||||
|
||||
# Library configuration
|
||||
library {
|
||||
# Name of the library as displayed by the clients (%h: hostname). If you
|
||||
# change the name after pairing with Remote you may have to re-pair.
|
||||
name = "My Music on %h"
|
||||
|
||||
# TCP port to listen on. Default port is 3689 (daap)
|
||||
port = 3689
|
||||
|
||||
# Password for the library. Optional.
|
||||
# password = ""
|
||||
|
||||
# Directories to index
|
||||
directories = { "/srv/music" }
|
||||
|
||||
# Follow symlinks. Default: true.
|
||||
# follow_symlinks = true
|
||||
|
||||
# Directories containing podcasts
|
||||
# For each directory that is indexed the path is matched against these
|
||||
# names. If there is a match all items in the directory are marked as
|
||||
# podcasts. Eg. if you index /srv/music, and your podcasts are in
|
||||
# /srv/music/Podcasts, you can set this to "/Podcasts".
|
||||
# (changing this setting only takes effect after rescan, see the README)
|
||||
podcasts = { "/Podcasts" }
|
||||
|
||||
# Directories containing audiobooks
|
||||
# For each directory that is indexed the path is matched against these
|
||||
# names. If there is a match all items in the directory are marked as
|
||||
# audiobooks.
|
||||
# (changing this setting only takes effect after rescan, see the README)
|
||||
audiobooks = { "/Audiobooks" }
|
||||
|
||||
# Directories containing compilations (eg soundtracks)
|
||||
# For each directory that is indexed the path is matched against these
|
||||
# names. If there is a match all items in the directory are marked as
|
||||
# compilations.
|
||||
# (changing this setting only takes effect after rescan, see the README)
|
||||
compilations = { "/Compilations" }
|
||||
|
||||
# Compilations usually have many artists, and sometimes no album artist.
|
||||
# If you don't want every artist to be listed in artist views, you can
|
||||
# set a single name which will be used for all compilation tracks
|
||||
# without an album artist, and for all tracks in the compilation
|
||||
# directories.
|
||||
# (changing this setting only takes effect after rescan, see the README)
|
||||
compilation_artist = "Various Artists"
|
||||
|
||||
# If your album and artist lists are cluttered, you can choose to hide
|
||||
# albums and artists with only one track. The tracks will still be
|
||||
# visible in other lists, e.g. songs and playlists. This setting
|
||||
# currently only works in some remotes.
|
||||
# hide_singles = false
|
||||
|
||||
# Internet streams in your playlists will by default be shown in the
|
||||
# "Radio" library, like iTunes does. However, some clients (like
|
||||
# TunesRemote+) won't show the "Radio" library. If you would also like
|
||||
# to have them shown like normal playlists, you can enable this option.
|
||||
# radio_playlists = false
|
||||
|
||||
# These are the default playlists. If you want them to have other names,
|
||||
# you can set it here.
|
||||
# name_library = "Library"
|
||||
# name_music = "Music"
|
||||
# name_movies = "Movies"
|
||||
# name_tvshows = "TV Shows"
|
||||
# name_podcasts = "Podcasts"
|
||||
# name_audiobooks = "Audiobooks"
|
||||
# name_radio = "Radio"
|
||||
|
||||
# Artwork file names (without file type extension)
|
||||
# forked-daapd will look for jpg and png files with these base names
|
||||
# artwork_basenames = { "artwork", "cover", "Folder" }
|
||||
|
||||
# Enable searching for artwork corresponding to each individual media
|
||||
# file instead of only looking for album artwork. This is disabled by
|
||||
# default to reduce cache size.
|
||||
# artwork_individual = false
|
||||
|
||||
# File types the scanner should ignore
|
||||
# Non-audio files will never be added to the database, but here you
|
||||
# can prevent the scanner from even probing them. This might improve
|
||||
# scan time. By default .db, .ini, .db-journal, .pdf and .metadata are
|
||||
# ignored.
|
||||
# filetypes_ignore = { ".db", ".ini", ".db-journal", ".pdf", ".metadata" }
|
||||
|
||||
# File paths the scanner should ignore
|
||||
# If you want to exclude files on a more advanced basis you can enter
|
||||
# one or more POSIX regular expressions, and any file with a matching
|
||||
# path will be ignored.
|
||||
# filepath_ignore = { "myregex" }
|
||||
|
||||
# Disable startup file scanning
|
||||
# When forked-daapd starts it will do an initial file scan of your
|
||||
# library (and then watch it for changes). If you are sure your library
|
||||
# never changes while forked-daapd is not running, you can disable the
|
||||
# initial file scan and save some system ressources. Disabling this scan
|
||||
# may lead to forked-daapd's database coming out of sync with the
|
||||
# library. If that happens read the instructions in the README on how
|
||||
# to trigger a rescan.
|
||||
# filescan_disable = false
|
||||
|
||||
# Should metadata from m3u playlists, e.g. artist and title in EXTINF,
|
||||
# override the metadata we get from radio streams?
|
||||
# m3u_overrides = false
|
||||
|
||||
# Should iTunes metadata override ours?
|
||||
# itunes_overrides = false
|
||||
|
||||
# Should we import the content of iTunes smart playlists?
|
||||
# itunes_smartpl = false
|
||||
|
||||
# Decoding options for DAAP clients
|
||||
# Since iTunes has native support for mpeg, mp4a, mp4v, alac and wav,
|
||||
# such files will be sent as they are. Any other formats will be decoded
|
||||
# to raw wav. If forked-daapd detects a non-iTunes DAAP client, it is
|
||||
# assumed to only support mpeg and wav, other formats will be decoded.
|
||||
# Here you can change when to decode. Note that these settings have no
|
||||
# effect on AirPlay.
|
||||
# Formats: mp4a, mp4v, mpeg, alac, flac, mpc, ogg, wma, wmal, wmav, aif, wav
|
||||
# Formats that should never be decoded
|
||||
# no_decode = { "format", "format" }
|
||||
# Formats that should always be decoded
|
||||
# force_decode = { "format", "format" }
|
||||
|
||||
# Watch named pipes in the library for data and autostart playback when
|
||||
# there is data to be read. To exclude specific pipes from watching,
|
||||
# consider using the above _ignore options.
|
||||
# pipe_autostart = true
|
||||
|
||||
# Enable automatic rating updates
|
||||
# If enabled, rating is automatically updated after a song has either been
|
||||
# played or skipped (only skipping to the next song is taken into account).
|
||||
# The calculation is taken from the beets plugin "mpdstats" (see
|
||||
# https://beets.readthedocs.io/en/latest/plugins/mpdstats.html).
|
||||
# It consist of calculating a stable rating based only on the play- and
|
||||
# skipcount and a rolling rating based on the current rating and the action
|
||||
# (played or skipped). Both results are combined with a mix-factor of 0.75:
|
||||
# new rating = 0.75 * stable rating + 0.25 * rolling rating)
|
||||
# rating_updates = false
|
||||
|
||||
# Allows creating, deleting and modifying m3u playlists in the library directories.
|
||||
# Only supported by the player web interface and some mpd clients
|
||||
# Defaults to being disabled.
|
||||
# allow_modifying_stored_playlists = false
|
||||
|
||||
# A directory in one of the library directories that will be used as the default
|
||||
# playlist directory. forked-dapd creates new playlists in this directory if only
|
||||
# a playlist name is provided (requires "allow_modify_stored_playlists" set to true).
|
||||
# default_playlist_directory = ""
|
||||
}
|
||||
|
||||
# Local audio output
|
||||
audio {
|
||||
# Name - used in the speaker list in Remote
|
||||
nickname = "Computer"
|
||||
|
||||
# Type of the output (alsa, pulseaudio, dummy or disabled)
|
||||
# type = "alsa"
|
||||
|
||||
# For pulseaudio output, an optional server hostname or IP can be
|
||||
# specified (e.g. "localhost"). If not set, connection is made via local
|
||||
# socket.
|
||||
# server = ""
|
||||
|
||||
# Audio PCM device name for local audio output - ALSA only
|
||||
# card = "default"
|
||||
|
||||
# Mixer channel to use for volume control - ALSA only
|
||||
# If not set, PCM will be used if available, otherwise Master.
|
||||
# mixer = ""
|
||||
|
||||
# Mixer device to use for volume control - ALSA only
|
||||
# If not set, the value for "card" will be used.
|
||||
# mixer_device = ""
|
||||
|
||||
# Enable or disable audio resampling to keep local audio in sync with
|
||||
# e.g. Airplay. This feature relies on accurate ALSA measurements of
|
||||
# delay, and some devices don't provide that. If that is the case you
|
||||
# are better off disabling the feature.
|
||||
# sync_disable = false
|
||||
|
||||
# Here you can adjust when local audio is started relative to other
|
||||
# speakers, e.g. Airplay. Negative values correspond to moving local
|
||||
# audio ahead, positive correspond to delaying it. The unit is
|
||||
# milliseconds. The offset must be between -1000 and 1000 (+/- 1 sec).
|
||||
# offset_ms = 0
|
||||
|
||||
# To calculate what and if resampling is required, local audio delay is
|
||||
# measured each second. After a period the collected measurements are
|
||||
# used to estimate drift and latency, which determines if corrections
|
||||
# are required. This setting sets the length of that period in seconds.
|
||||
# adjust_period_seconds = 100
|
||||
}
|
||||
|
||||
# ALSA device settings
|
||||
# If you have multiple ALSA devices you can configure them individually via
|
||||
# sections like the below. Make sure to set the "card name" correctly. See the
|
||||
# README about ALSA for details. Note that these settings will override the ALSA
|
||||
# settings in the "audio" section above.
|
||||
#alsa "card name" {
|
||||
# Name - used in the speaker list in Remote
|
||||
# If not set, the card name will be used
|
||||
# nickname = "Computer"
|
||||
|
||||
# Mixer channel to use for volume control
|
||||
# If not set, PCM will be used if available, otherwise Master
|
||||
# mixer = ""
|
||||
|
||||
# Mixer device to use for volume control
|
||||
# If not set, the card name will be used
|
||||
# mixer_device = ""
|
||||
#}
|
||||
|
||||
# Pipe output
|
||||
# Allows forked-daapd to output audio data to a named pipe
|
||||
#fifo {
|
||||
# nickname = "fifo"
|
||||
# path = "/path/to/fifo"
|
||||
#}
|
||||
|
||||
# AirPlay settings common to all devices
|
||||
#airplay_shared {
|
||||
# UDP ports used when airplay devices make connections back to forked-daapd
|
||||
# (choosing specific ports may be helpful when running forked-daapd behind a firewall)
|
||||
# control_port = 0
|
||||
# timing_port = 0
|
||||
#}
|
||||
|
||||
# AirPlay per device settings
|
||||
# (make sure you get the capitalization of the device name right)
|
||||
#airplay "My AirPlay device" {
|
||||
# forked-daapd's volume goes to 11! If that's more than you can handle
|
||||
# you can set a lower value here
|
||||
# max_volume = 11
|
||||
|
||||
# Enable this option to exclude a particular AirPlay device from the
|
||||
# speaker list
|
||||
# exclude = false
|
||||
|
||||
# Enable this option to keep a particular AirPlay device in the speaker
|
||||
# list and thus ignore mdns notifications about it no longer being
|
||||
# present. The speaker will remain until restart of forked-daapd.
|
||||
# permanent = false
|
||||
|
||||
# Some devices spuriously disconnect during playback, and based on the
|
||||
# device type forked-daapd may attempt to reconnect. Setting this option
|
||||
# overrides this so reconnecting is either always enabled or disabled.
|
||||
# reconnect = false
|
||||
|
||||
# AirPlay password
|
||||
# password = "s1kr3t"
|
||||
#}
|
||||
|
||||
# Chromecast settings
|
||||
# (make sure you get the capitalization of the device name right)
|
||||
#chromecast "My Chromecast device" {
|
||||
# Enable this option to exclude a particular device from the speaker
|
||||
# list
|
||||
# exclude = false
|
||||
#}
|
||||
|
||||
# Spotify settings (only have effect if Spotify enabled - see README/INSTALL)
|
||||
spotify {
|
||||
# Directory where user settings should be stored (credentials)
|
||||
# settings_dir = "/var/cache/forked-daapd/libspotify"
|
||||
|
||||
# Cache directory
|
||||
# cache_dir = "/tmp"
|
||||
|
||||
# Set preferred bitrate for music streaming
|
||||
# 0: No preference (default), 1: 96kbps, 2: 160kbps, 3: 320kbps
|
||||
# bitrate = 0
|
||||
|
||||
# Your Spotify playlists will by default be put in a "Spotify" playlist
|
||||
# folder. If you would rather have them together with your other
|
||||
# playlists you can set this option to true.
|
||||
# base_playlist_disable = false
|
||||
|
||||
# Spotify playlists usually have many artist, and if you don't want
|
||||
# every artist to be listed when artist browsing in Remote, you can set
|
||||
# the artist_override flag to true. This will use the compilation_artist
|
||||
# as album artist for Spotify items.
|
||||
# artist_override = false
|
||||
|
||||
# Similar to the different artists in Spotify playlists, the playlist
|
||||
# items belong to different albums, and if you do not want every album
|
||||
# to be listed when browsing in Remote, you can set the album_override
|
||||
# flag to true. This will use the playlist name as album name for
|
||||
# Spotify items. Notice that if an item is in more than one playlist,
|
||||
# it will only appear in one album when browsing (in which album is
|
||||
# random).
|
||||
# album_override = false
|
||||
}
|
||||
|
||||
# MPD configuration (only have effect if MPD enabled - see README/INSTALL)
|
||||
mpd {
|
||||
# TCP port to listen on for MPD client requests.
|
||||
# Default port is 6600, set to 0 to disable MPD support.
|
||||
# port = 6600
|
||||
|
||||
# HTTP port to listen for artwork requests (only supported by some MPD
|
||||
# clients and will need additional configuration in the MPD client to
|
||||
# work). Set to 0 to disable serving artwork over http.
|
||||
# http_port = 0
|
||||
|
||||
# By default forked-daapd will - like iTunes - clear the playqueue if
|
||||
# playback stops. Setting clear_queue_on_stop_disable to true will keep
|
||||
# the playlist like MPD does. Note that some dacp clients do not show
|
||||
# the playqueue if playback is stopped.
|
||||
# clear_queue_on_stop_disable = false
|
||||
}
|
||||
|
||||
# SQLite configuration (allows to modify the operation of the SQLite databases)
|
||||
# Make sure to read the SQLite documentation for the corresponding PRAGMA
|
||||
# statements as changing them from the defaults may increase the possibility of
|
||||
# database corruptions! By default the SQLite default values are used.
|
||||
sqlite {
|
||||
# Cache size in number of db pages for the library database
|
||||
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
|
||||
# pragma_cache_size_library = 2000
|
||||
|
||||
# Cache size in number of db pages for the daap cache database
|
||||
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
|
||||
# pragma_cache_size_cache = 2000
|
||||
|
||||
# Sets the journal mode for the database
|
||||
# DELETE (default), TRUNCATE, PERSIST, MEMORY, WAL, OFF
|
||||
# pragma_journal_mode = DELETE
|
||||
|
||||
# Change the setting of the "synchronous" flag
|
||||
# 0: OFF, 1: NORMAL, 2: FULL (default)
|
||||
# pragma_synchronous = 2
|
||||
|
||||
# Number of bytes set aside for memory-mapped I/O for the library database
|
||||
# (requires sqlite 3.7.17 or later)
|
||||
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
|
||||
# pragma_mmap_size_library = 0
|
||||
|
||||
# Number of bytes set aside for memory-mapped I/O for the cache database
|
||||
# (requires sqlite 3.7.17 or later)
|
||||
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
|
||||
# pragma_mmap_size_cache = 0
|
||||
|
||||
# Should the database be vacuumed on startup? (increases startup time,
|
||||
# but may reduce database size). Default is yes.
|
||||
# vacuum = yes
|
||||
}
|
||||
|
||||
# Streaming audio settings for remote connections (ie stream.mp3)
|
||||
streaming {
|
||||
# Sample rate, typically 44100 or 48000
|
||||
# sample_rate = 44100
|
||||
|
||||
# Set the MP3 streaming bit rate (in kbps), valid options: 64 / 96 / 128 / 192 / 320
|
||||
# bit_rate = 192
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2014 OpenWrt.org
|
||||
|
||||
START=99
|
||||
BIN=/usr/sbin/forked-daapd
|
||||
PID=/var/run/forked-daapd.pid
|
||||
SSD=start-stop-daemon
|
||||
|
||||
start() {
|
||||
$SSD -p $PID -S -x $BIN -- -P $PID
|
||||
}
|
||||
|
||||
stop() {
|
||||
$SSD -p $PID -K -s SIGINT
|
||||
}
|
16
luci-app-chinesesubfinder/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
|
||||
LUCI_TITLE:=LuCI support for ChineseSubFinder
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+docker +luci-lib-taskd
|
||||
|
||||
define Package/luci-app-chinesesubfinder/conffiles
|
||||
/etc/config/chinesesubfinder
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
7
luci-app-chinesesubfinder/luasrc/controller/chinesesubfinder.lua
Executable file
@ -0,0 +1,7 @@
|
||||
|
||||
module("luci.controller.chinesesubfinder", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "chinesesubfinder"}, alias("admin", "services", "chinesesubfinder", "config"), _("ChineseSubFinder"), 30).dependent = true
|
||||
entry({"admin", "services", "chinesesubfinder", "config"}, cbi("chinesesubfinder"))
|
||||
end
|
@ -0,0 +1,54 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local chinesesubfinder_model = require "luci.model.chinesesubfinder"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("chinesesubfinder", "chinesesubfinder", "/usr/libexec/istorec/chinesesubfinder.sh",
|
||||
translate("ChineseSubFinder"),
|
||||
translate("ChineseSubFinder brings together your personal videos, music, photos, and live television.")
|
||||
.. translate("Official website:") .. ' <a href=\"https://chinesesubfinder.media/\" target=\"_blank\">https://chinesesubfinder.media/</a>')
|
||||
|
||||
s = m:section(SimpleSection, translate("Service Status"), translate("ChineseSubFinder status:"))
|
||||
s:append(Template("chinesesubfinder/status"))
|
||||
|
||||
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
|
||||
s.addremove=false
|
||||
s.anonymous=true
|
||||
|
||||
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.default = "19035"
|
||||
o.datatype = "string"
|
||||
|
||||
o = s:option(Value, "web_port", "WEB Port<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.default = "19037"
|
||||
o.datatype = "string"
|
||||
|
||||
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
o:value("allanpk716/chinesesubfinder:latest-lite", "allanpk716/chinesesubfinder:latest-lite")
|
||||
o:value("allanpk716/chinesesubfinder:v0.43.1-lite", "allanpk716/chinesesubfinder:v0.43.1-lite")
|
||||
o.default = "allanpk716/chinesesubfinder:latest-lite"
|
||||
|
||||
local blocks = chinesesubfinder_model.blocks()
|
||||
local home = chinesesubfinder_model.home()
|
||||
|
||||
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
|
||||
local paths, default_path = chinesesubfinder_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
|
||||
o.datatype = "string"
|
||||
|
||||
return m
|
54
luci-app-chinesesubfinder/luasrc/model/chinesesubfinder.lua
Normal file
@ -0,0 +1,54 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local chinesesubfinder = {}
|
||||
|
||||
chinesesubfinder.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj["blockdevices"]) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
-- fsize > 1G
|
||||
vals[#vals+1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
chinesesubfinder.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
chinesesubfinder.find_paths = function(blocks, home_dirs, path_name)
|
||||
local default_path = ''
|
||||
local configs = {}
|
||||
|
||||
default_path = home_dirs[path_name] .. "/ChineseSubFinder"
|
||||
if #blocks == 0 then
|
||||
table.insert(configs, default_path)
|
||||
else
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(configs, val .. "/" .. path_name .. "/ChineseSubFinder")
|
||||
end
|
||||
local without_conf_dir = "/root/" .. path_name .. "/ChineseSubFinder"
|
||||
if default_path == without_conf_dir then
|
||||
default_path = configs[1]
|
||||
end
|
||||
end
|
||||
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return chinesesubfinder
|
@ -0,0 +1,31 @@
|
||||
<%
|
||||
local util = require "luci.util"
|
||||
local container_status = util.trim(util.exec("/usr/libexec/istorec/chinesesubfinder.sh status"))
|
||||
local container_install = (string.len(container_status) > 0)
|
||||
local container_running = container_status == "running"
|
||||
-%>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:Status%></label>
|
||||
<div class="cbi-value-field">
|
||||
<% if container_running then %>
|
||||
<button class="cbi-button cbi-button-success" disabled="true"><%:ChineseSubFinder is running%></button>
|
||||
<% else %>
|
||||
<button class="cbi-button cbi-button-negative" disabled="true"><%:ChineseSubFinder is not running%></button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
if container_running then
|
||||
local port=util.trim(util.exec("/usr/libexec/istorec/chinesesubfinder.sh port"))
|
||||
if port == "" then
|
||||
port="19035"
|
||||
end
|
||||
-%>
|
||||
<div class="cbi-value cbi-value-last">
|
||||
<label class="cbi-value-title"> </label>
|
||||
<div class="cbi-value-field">
|
||||
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open ChineseSubFinder%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
41
luci-app-chinesesubfinder/po/zh-cn/chinesesubfinder.po
Normal file
@ -0,0 +1,41 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Official website:"
|
||||
msgstr "官方网站:"
|
||||
|
||||
msgid "ChineseSubFinder brings together your personal videos, music, photos, and live television."
|
||||
msgstr "ChineseSubFinder 是一个多媒体串流平台。"
|
||||
|
||||
msgid "Config path"
|
||||
msgstr "配置文件路径"
|
||||
|
||||
msgid "HTTP Port"
|
||||
msgstr "HTTP 端口"
|
||||
|
||||
msgid "Service Status"
|
||||
msgstr "服务状态"
|
||||
|
||||
msgid "ChineseSubFinder status:"
|
||||
msgstr "ChineseSubFinder 的状态信息如下:"
|
||||
|
||||
msgid "Setup"
|
||||
msgstr "安装配置"
|
||||
|
||||
msgid "The following parameters will only take effect during installation or upgrade:"
|
||||
msgstr "以下参数只在安装或者升级时才会生效:"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "ChineseSubFinder is running"
|
||||
msgstr "ChineseSubFinder 运行中"
|
||||
|
||||
msgid "ChineseSubFinder is not running"
|
||||
msgstr "ChineseSubFinder 未运行"
|
||||
|
||||
msgid "Open ChineseSubFinder"
|
||||
msgstr "打开 ChineseSubFinder"
|
||||
|
||||
msgid "Not required, all disk is mounted in"
|
||||
msgstr "可不填,所有硬盘都在"
|
1
luci-app-chinesesubfinder/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
@ -0,0 +1,6 @@
|
||||
config main
|
||||
option 'http_port' '19035'
|
||||
option 'web_port' '19037'
|
||||
option 'image_name' 'allanpk716/chinesesubfinder:latest-lite'
|
||||
option 'config_path' ''
|
||||
|
79
luci-app-chinesesubfinder/root/usr/libexec/istorec/chinesesubfinder.sh
Executable file
@ -0,0 +1,79 @@
|
||||
#!/bin/sh
|
||||
# Author Xiaobao(xiaobao@linkease.com)
|
||||
|
||||
ACTION=${1}
|
||||
shift 1
|
||||
|
||||
do_install() {
|
||||
local http_port=`uci get chinesesubfinder.@main[0].http_port 2>/dev/null`
|
||||
local web_port=`uci get chinesesubfinder.@main[0].web_port 2>/dev/null`
|
||||
local image_name=`uci get chinesesubfinder.@main[0].image_name 2>/dev/null`
|
||||
local config=`uci get chinesesubfinder.@main[0].config_path 2>/dev/null`
|
||||
local media=`uci get chinesesubfinder.@main[0].media_path 2>/dev/null`
|
||||
|
||||
[ -z "$image_name" ] && image_name="allanpk716/chinesesubfinder:latest-lite"
|
||||
echo "docker pull ${image_name}"
|
||||
docker pull ${image_name}
|
||||
docker rm -f chinesesubfinder
|
||||
|
||||
if [ -z "$config" ]; then
|
||||
echo "config path is empty!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -z "$http_port" ] && http_port=19035
|
||||
[ -z "$web_port" ] && web_port=19037
|
||||
|
||||
local cmd="docker run --restart=unless-stopped -d -v \"$config:/config\" --dns=172.17.0.1 -p $http_port:19035 -p $web_port:19037 \
|
||||
--hostname chinesesubfinder \
|
||||
--log-driver \"json-file\" \
|
||||
--log-opt \"max-size=100m\" "
|
||||
|
||||
local tz="`cat /tmp/TZ`"
|
||||
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
|
||||
|
||||
[ -z "$media" ] || cmd="$cmd -v \"$media:/media\""
|
||||
|
||||
cmd="$cmd -v /mnt:/mnt"
|
||||
mountpoint -q /mnt && cmd="$cmd:rslave"
|
||||
cmd="$cmd --name chinesesubfinder \"$image_name\""
|
||||
|
||||
echo "$cmd"
|
||||
eval "$cmd"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 sub-command"
|
||||
echo "where sub-command is one of:"
|
||||
echo " install Install the chinesesubfinder"
|
||||
echo " upgrade Upgrade the chinesesubfinder"
|
||||
echo " rm/start/stop/restart Remove/Start/Stop/Restart the chinesesubfinder"
|
||||
echo " status ChineseSubFinder status"
|
||||
echo " port ChineseSubFinder port"
|
||||
}
|
||||
|
||||
case ${ACTION} in
|
||||
"install")
|
||||
do_install
|
||||
;;
|
||||
"upgrade")
|
||||
do_install
|
||||
;;
|
||||
"rm")
|
||||
docker rm -f chinesesubfinder
|
||||
;;
|
||||
"start" | "stop" | "restart")
|
||||
docker ${ACTION} chinesesubfinder
|
||||
;;
|
||||
"status")
|
||||
docker ps --all -f 'name=chinesesubfinder' --format '{{.State}}'
|
||||
;;
|
||||
"port")
|
||||
local http_port=`uci get chinesesubfinder.@main[0].http_port 2>/dev/null`
|
||||
echo $http_port
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-chinesesubfinder": {
|
||||
"description": "Grant UCI access for luci-app-chinesesubfinder",
|
||||
"read": {
|
||||
"uci": [ "chinesesubfinder" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "chinesesubfinder" ]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
|
||||
config settings 'cpufreq'
|
||||
|
||||
config settings 'global'
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci_write_config() {
|
||||
uci -q set cpufreq.cpufreq.governor$1="$2"
|
||||
uci -q set cpufreq.cpufreq.minfreq$1="$3"
|
||||
uci -q set cpufreq.cpufreq.maxfreq$1="$4"
|
||||
[ -n "$5" ] && uci -q set cpufreq.cpufreq.sdfactor$1="$5"
|
||||
[ -n "$6" ] && uci -q set cpufreq.cpufreq.upthreshold$1="$6"
|
||||
uci -q set "cpufreq.cpufreq.governor$1"="$2"
|
||||
uci -q set "cpufreq.cpufreq.minfreq$1"="$3"
|
||||
uci -q set "cpufreq.cpufreq.maxfreq$1"="$4"
|
||||
[ -n "$5" ] && uci -q set "cpufreq.cpufreq.sdfactor$1"="$5"
|
||||
[ -n "$6" ] && uci -q set "cpufreq.cpufreq.upthreshold$1"="$6"
|
||||
uci -q set cpufreq.global.set=1
|
||||
uci -q commit cpufreq
|
||||
}
|
||||
|
||||
[ "$(uci -q get cpufreq.global.set)" -eq "1" ] && exit 0
|
||||
|
||||
CPU_FREQS="$(cat '/sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies')"
|
||||
CPU_POLICYS="$(find '/sys/devices/system/cpu/cpufreq/policy'* -maxdepth 0 | grep -Eo '[0-9]+')"
|
||||
source "/etc/openwrt_release"
|
||||
@ -30,7 +33,7 @@ case "$DISTRIB_TARGET" in
|
||||
# IPQ6000
|
||||
CPU_MAX_FREQ="1200000"
|
||||
fi
|
||||
uci_write_config 0 ondemand 864000 $CPU_MAX_FREQ 10 50
|
||||
uci_write_config 0 ondemand 864000 "$CPU_MAX_FREQ" 10 50
|
||||
;;
|
||||
"ipq806x/generic")
|
||||
if echo "$CPU_FREQS" | grep -q "1725000"; then
|
||||
@ -43,7 +46,7 @@ case "$DISTRIB_TARGET" in
|
||||
# IPQ8062
|
||||
CPU_MAX_FREQ="1000000"
|
||||
fi
|
||||
uci_write_config 0 ondemand 600000 $CPU_MAX_FREQ 10 50
|
||||
uci_write_config 0 ondemand 600000 "$CPU_MAX_FREQ" 10 50
|
||||
# IPQ8064/5
|
||||
echo "$CPU_POLICYS" | grep -q "1" && uci_write_config 1 ondemand 600000 1200000 10 50
|
||||
;;
|
||||
@ -52,10 +55,10 @@ case "$DISTRIB_TARGET" in
|
||||
# IPQ8072/4/6/8A
|
||||
CPU_MAX_FREQ="2208000"
|
||||
else
|
||||
# IPQ8071A
|
||||
# IPQ8070/1A
|
||||
CPU_MAX_FREQ="1382400"
|
||||
fi
|
||||
uci_write_config 0 schedutil 1017600 $CPU_MAX_FREQ
|
||||
uci_write_config 0 schedutil 1017600 "$CPU_MAX_FREQ"
|
||||
;;
|
||||
"mediatek/mt7622")
|
||||
uci_write_config 0 ondemand 600000 1350000 10 50
|
||||
@ -75,7 +78,7 @@ case "$DISTRIB_TARGET" in
|
||||
# RK3328
|
||||
CPU_MAX_FREQ="1512000"
|
||||
fi
|
||||
uci_write_config 0 schedutil 816000 $CPU_MAX_FREQ
|
||||
uci_write_config 0 schedutil 816000 "$CPU_MAX_FREQ"
|
||||
fi
|
||||
;;
|
||||
"sunxi/cortexa53")
|
||||
|
16
luci-app-emby/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
|
||||
LUCI_TITLE:=LuCI support for Emby
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+docker +luci-lib-taskd
|
||||
|
||||
define Package/luci-app-emby/conffiles
|
||||
/etc/config/emby
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
7
luci-app-emby/luasrc/controller/emby.lua
Executable file
@ -0,0 +1,7 @@
|
||||
|
||||
module("luci.controller.emby", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "emby"}, alias("admin", "services", "emby", "config"), _("Emby"), 30).dependent = true
|
||||
entry({"admin", "services", "emby", "config"}, cbi("emby"))
|
||||
end
|
63
luci-app-emby/luasrc/model/cbi/emby.lua
Normal file
@ -0,0 +1,63 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local emby_model = require "luci.model.emby"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("emby", "emby", "/usr/libexec/istorec/emby.sh",
|
||||
translate("Emby"),
|
||||
translate("Emby brings together your personal videos, music, photos, and live television.")
|
||||
.. translate("Official website:") .. ' <a href=\"https://emby.media/\" target=\"_blank\">https://emby.media/</a>')
|
||||
|
||||
s = m:section(SimpleSection, translate("Service Status"), translate("Emby status:"))
|
||||
s:append(Template("emby/status"))
|
||||
|
||||
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
|
||||
s.addremove=false
|
||||
s.anonymous=true
|
||||
|
||||
o = s:option(Flag, "hostnet", translate("Host network"), translate("Emby running in host network, for DLNA application, port is always 8096 if enabled"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.default = "8096"
|
||||
o.datatype = "string"
|
||||
o:depends("hostnet", 0)
|
||||
|
||||
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
o:value("emby/embyserver", "emby/embyserver")
|
||||
o:value("emby/embyserver_arm32v7", "emby/embyserver_arm32v7")
|
||||
o:value("emby/embyserver_arm64v8", "emby/embyserver_arm64v8")
|
||||
o.default = "emby/embyserver"
|
||||
|
||||
local blocks = emby_model.blocks()
|
||||
local home = emby_model.home()
|
||||
|
||||
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
|
||||
local paths, default_path = emby_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
|
||||
o.datatype = "string"
|
||||
|
||||
o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space"))
|
||||
o.datatype = "string"
|
||||
local paths, default_path = emby_model.find_paths(blocks, home, "Caches")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
return m
|
54
luci-app-emby/luasrc/model/emby.lua
Normal file
@ -0,0 +1,54 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local emby = {}
|
||||
|
||||
emby.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj["blockdevices"]) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
-- fsize > 1G
|
||||
vals[#vals+1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
emby.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
emby.find_paths = function(blocks, home_dirs, path_name)
|
||||
local default_path = ''
|
||||
local configs = {}
|
||||
|
||||
default_path = home_dirs[path_name] .. "/Emby"
|
||||
if #blocks == 0 then
|
||||
table.insert(configs, default_path)
|
||||
else
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(configs, val .. "/" .. path_name .. "/Emby")
|
||||
end
|
||||
local without_conf_dir = "/root/" .. path_name .. "/Emby"
|
||||
if default_path == without_conf_dir then
|
||||
default_path = configs[1]
|
||||
end
|
||||
end
|
||||
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return emby
|
31
luci-app-emby/luasrc/view/emby/status.htm
Normal file
@ -0,0 +1,31 @@
|
||||
<%
|
||||
local util = require "luci.util"
|
||||
local container_status = util.trim(util.exec("/usr/libexec/istorec/emby.sh status"))
|
||||
local container_install = (string.len(container_status) > 0)
|
||||
local container_running = container_status == "running"
|
||||
-%>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:Status%></label>
|
||||
<div class="cbi-value-field">
|
||||
<% if container_running then %>
|
||||
<button class="cbi-button cbi-button-success" disabled="true"><%:Emby is running%></button>
|
||||
<% else %>
|
||||
<button class="cbi-button cbi-button-negative" disabled="true"><%:Emby is not running%></button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
if container_running then
|
||||
local port=util.trim(util.exec("/usr/libexec/istorec/emby.sh port"))
|
||||
if port == "" then
|
||||
port="8096"
|
||||
end
|
||||
-%>
|
||||
<div class="cbi-value cbi-value-last">
|
||||
<label class="cbi-value-title"> </label>
|
||||
<div class="cbi-value-field">
|
||||
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open Emby%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
41
luci-app-emby/po/zh-cn/emby.po
Normal file
@ -0,0 +1,41 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Official website:"
|
||||
msgstr "官方网站:"
|
||||
|
||||
msgid "Emby brings together your personal videos, music, photos, and live television."
|
||||
msgstr "Emby 是一个多媒体串流平台。"
|
||||
|
||||
msgid "Config path"
|
||||
msgstr "配置文件路径"
|
||||
|
||||
msgid "HTTP Port"
|
||||
msgstr "HTTP 端口"
|
||||
|
||||
msgid "Service Status"
|
||||
msgstr "服务状态"
|
||||
|
||||
msgid "Emby status:"
|
||||
msgstr "Emby 的状态信息如下:"
|
||||
|
||||
msgid "Setup"
|
||||
msgstr "安装配置"
|
||||
|
||||
msgid "The following parameters will only take effect during installation or upgrade:"
|
||||
msgstr "以下参数只在安装或者升级时才会生效:"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Emby is running"
|
||||
msgstr "Emby 运行中"
|
||||
|
||||
msgid "Emby is not running"
|
||||
msgstr "Emby 未运行"
|
||||
|
||||
msgid "Open Emby"
|
||||
msgstr "打开 Emby"
|
||||
|
||||
msgid "Not required, all disk is mounted in"
|
||||
msgstr "可不填,所有硬盘都在"
|
1
luci-app-emby/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
6
luci-app-emby/root/etc/config/emby
Normal file
@ -0,0 +1,6 @@
|
||||
config main
|
||||
option 'hostnet' '0'
|
||||
option 'http_port' '8096'
|
||||
option 'image_name' 'emby/embyserver'
|
||||
option 'config_path' ''
|
||||
|
92
luci-app-emby/root/usr/libexec/istorec/emby.sh
Executable file
@ -0,0 +1,92 @@
|
||||
#!/bin/sh
|
||||
# Author Xiaobao(xiaobao@linkease.com)
|
||||
|
||||
ACTION=${1}
|
||||
shift 1
|
||||
|
||||
do_install() {
|
||||
local hostnet=`uci get emby.@main[0].hostnet 2>/dev/null`
|
||||
local http_port=`uci get emby.@main[0].http_port 2>/dev/null`
|
||||
local image_name=`uci get emby.@main[0].image_name 2>/dev/null`
|
||||
local config=`uci get emby.@main[0].config_path 2>/dev/null`
|
||||
local media=`uci get emby.@main[0].media_path 2>/dev/null`
|
||||
local cache=`uci get emby.@main[0].cache_path 2>/dev/null`
|
||||
|
||||
[ -z "$image_name" ] && image_name="emby/embyserver"
|
||||
echo "docker pull ${image_name}"
|
||||
docker pull ${image_name}
|
||||
docker rm -f emby
|
||||
|
||||
if [ -z "$config" ]; then
|
||||
echo "config path is empty!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -z "$http_port" ] && http_port=8096
|
||||
|
||||
local cmd="docker run --restart=unless-stopped -d -v \"$config:/config\" "
|
||||
|
||||
if [ -d /dev/dri ]; then
|
||||
cmd="$cmd\
|
||||
--device /dev/dri:/dev/dri \
|
||||
--privileged "
|
||||
fi
|
||||
|
||||
if [ "$hostnet" = 1 ]; then
|
||||
cmd="$cmd\
|
||||
--dns=127.0.0.1 \
|
||||
--network=host "
|
||||
else
|
||||
cmd="$cmd\
|
||||
--dns=172.17.0.1 \
|
||||
-p $http_port:8096 "
|
||||
fi
|
||||
|
||||
local tz="`cat /tmp/TZ`"
|
||||
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
|
||||
|
||||
[ -z "$cache" ] || cmd="$cmd -v \"$cache:/config/cache\""
|
||||
[ -z "$media" ] || cmd="$cmd -v \"$media:/data\""
|
||||
|
||||
cmd="$cmd -v /mnt:/mnt"
|
||||
mountpoint -q /mnt && cmd="$cmd:rslave"
|
||||
cmd="$cmd --name emby \"$image_name\""
|
||||
|
||||
echo "$cmd"
|
||||
eval "$cmd"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 sub-command"
|
||||
echo "where sub-command is one of:"
|
||||
echo " install Install the emby"
|
||||
echo " upgrade Upgrade the emby"
|
||||
echo " rm/start/stop/restart Remove/Start/Stop/Restart the emby"
|
||||
echo " status Emby status"
|
||||
echo " port Emby port"
|
||||
}
|
||||
|
||||
case ${ACTION} in
|
||||
"install")
|
||||
do_install
|
||||
;;
|
||||
"upgrade")
|
||||
do_install
|
||||
;;
|
||||
"rm")
|
||||
docker rm -f emby
|
||||
;;
|
||||
"start" | "stop" | "restart")
|
||||
docker ${ACTION} emby
|
||||
;;
|
||||
"status")
|
||||
docker ps --all -f 'name=emby' --format '{{.State}}'
|
||||
;;
|
||||
"port")
|
||||
docker ps --all -f 'name=emby' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*' | sed 's/0.0.0.0://'
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
11
luci-app-emby/root/usr/share/rpcd/acl.d/luci-app-emby.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-emby": {
|
||||
"description": "Grant UCI access for luci-app-emby",
|
||||
"read": {
|
||||
"uci": [ "emby" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "emby" ]
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local jellyfin_model = require "luci.model.jellyfin"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("jellyfin", "jellyfin", "/usr/share/jellyfin/install.sh",
|
||||
@ -26,14 +27,28 @@ o.default = "8096"
|
||||
o.datatype = "port"
|
||||
o:depends("hostnet", 0)
|
||||
|
||||
o = s:option(Value, "media_path", translate("Media path"))
|
||||
o.datatype = "string"
|
||||
local blocks = jellyfin_model.blocks()
|
||||
local home = jellyfin_model.home()
|
||||
|
||||
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
|
||||
o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space"))
|
||||
local paths, default_path = jellyfin_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
|
||||
o.datatype = "string"
|
||||
|
||||
o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space"))
|
||||
o.datatype = "string"
|
||||
local paths, default_path = jellyfin_model.find_paths(blocks, home, "Caches")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
return m
|
||||
|
54
luci-app-jellyfin/luasrc/model/jellyfin.lua
Normal file
@ -0,0 +1,54 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local jellyfin = {}
|
||||
|
||||
jellyfin.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj["blockdevices"]) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
-- fsize > 1G
|
||||
vals[#vals+1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
jellyfin.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
jellyfin.find_paths = function(blocks, home_dirs, path_name)
|
||||
local default_path = ''
|
||||
local configs = {}
|
||||
|
||||
default_path = home_dirs[path_name] .. "/Jellyfin"
|
||||
if #blocks == 0 then
|
||||
table.insert(configs, default_path)
|
||||
else
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(configs, val .. "/" .. path_name .. "/Jellyfin")
|
||||
end
|
||||
local without_conf_dir = "/root/" .. path_name .. "/Jellyfin"
|
||||
if default_path == without_conf_dir then
|
||||
default_path = configs[1]
|
||||
end
|
||||
end
|
||||
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return jellyfin
|
@ -51,3 +51,6 @@ msgstr "Jellyfin 未运行"
|
||||
|
||||
msgid "Open Jellyfin"
|
||||
msgstr "打开 Jellyfin"
|
||||
|
||||
msgid "Not required, all disk is mounted in"
|
||||
msgstr "可不填,所有硬盘都在"
|
||||
|
@ -3,5 +3,5 @@ config jellyfin
|
||||
option 'port' '8096'
|
||||
option 'image' 'default'
|
||||
option 'media_path' ''
|
||||
option 'config_path' '/root/jellyfin/config'
|
||||
option 'config_path' ''
|
||||
option 'cache_path' ''
|
||||
|
16
luci-app-lanraragi/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
|
||||
LUCI_TITLE:=LuCI support for LANraragi
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+docker +luci-lib-taskd
|
||||
|
||||
define Package/luci-app-lanraragi/conffiles
|
||||
/etc/config/lanraragi
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
7
luci-app-lanraragi/luasrc/controller/lanraragi.lua
Executable file
@ -0,0 +1,7 @@
|
||||
|
||||
module("luci.controller.lanraragi", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "lanraragi"}, alias("admin", "services", "lanraragi", "config"), _("LANraragi"), 30).dependent = true
|
||||
entry({"admin", "services", "lanraragi", "config"}, cbi("lanraragi"))
|
||||
end
|
54
luci-app-lanraragi/luasrc/model/cbi/lanraragi.lua
Normal file
@ -0,0 +1,54 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local lanraragi_model = require "luci.model.lanraragi"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("lanraragi", "lanraragi", "/usr/libexec/istorec/lanraragi.sh",
|
||||
translate("LANraragi"),
|
||||
translate("LANraragi is Open source server for archival of comics/manga.")
|
||||
.. translate("Official website:") .. ' <a href=\"https://github.com/Difegue/LANraragi\" target=\"_blank\">https://github.com/Difegue/LANraragi</a>')
|
||||
|
||||
s = m:section(SimpleSection, translate("Service Status"), translate("LANraragi status:"))
|
||||
s:append(Template("lanraragi/status"))
|
||||
|
||||
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
|
||||
s.addremove=false
|
||||
s.anonymous=true
|
||||
|
||||
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.default = "3000"
|
||||
o.datatype = "string"
|
||||
|
||||
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
o:value("difegue/lanraragi", "difegue/lanraragi")
|
||||
o.default = "difegue/lanraragi"
|
||||
|
||||
local blocks = lanraragi_model.blocks()
|
||||
local home = lanraragi_model.home()
|
||||
|
||||
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
|
||||
local paths, default_path = lanraragi_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
o = s:option(Value, "content_path", translate("Content path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
local paths, default_path = lanraragi_model.find_paths(blocks, home, "Downloads")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
return m
|
54
luci-app-lanraragi/luasrc/model/lanraragi.lua
Normal file
@ -0,0 +1,54 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local lanraragi = {}
|
||||
|
||||
lanraragi.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj["blockdevices"]) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
-- fsize > 1G
|
||||
vals[#vals+1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
lanraragi.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
lanraragi.find_paths = function(blocks, home_dirs, path_name)
|
||||
local appname = '/LANraragi'
|
||||
local default_path = ''
|
||||
local configs = {}
|
||||
|
||||
if #blocks == 0 then
|
||||
return
|
||||
else
|
||||
if path_name == "Downloads" then
|
||||
appname = "/Music"
|
||||
end
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(configs, val .. "/" .. path_name .. appname)
|
||||
end
|
||||
default_path = configs[1]
|
||||
end
|
||||
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return lanraragi
|
31
luci-app-lanraragi/luasrc/view/lanraragi/status.htm
Normal file
@ -0,0 +1,31 @@
|
||||
<%
|
||||
local util = require "luci.util"
|
||||
local container_status = util.trim(util.exec("/usr/libexec/istorec/lanraragi.sh status"))
|
||||
local container_install = (string.len(container_status) > 0)
|
||||
local container_running = container_status == "running"
|
||||
-%>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:Status%></label>
|
||||
<div class="cbi-value-field">
|
||||
<% if container_running then %>
|
||||
<button class="cbi-button cbi-button-success" disabled="true"><%:LANraragi is running%></button>
|
||||
<% else %>
|
||||
<button class="cbi-button cbi-button-negative" disabled="true"><%:LANraragi is not running%></button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
if container_running then
|
||||
local port=util.trim(util.exec("/usr/libexec/istorec/lanraragi.sh port"))
|
||||
if port == "" then
|
||||
port="3000"
|
||||
end
|
||||
-%>
|
||||
<div class="cbi-value cbi-value-last">
|
||||
<label class="cbi-value-title"> </label>
|
||||
<div class="cbi-value-field">
|
||||
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open LANraragi%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
41
luci-app-lanraragi/po/zh-cn/lanraragi.po
Normal file
@ -0,0 +1,41 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Official website:"
|
||||
msgstr "官方网站:"
|
||||
|
||||
msgid "LANraragi is Open source server for archival of comics/manga."
|
||||
msgstr "LANraragi 是一个开源的电子书、漫画管理平台。"
|
||||
|
||||
msgid "Config path"
|
||||
msgstr "配置文件路径"
|
||||
|
||||
msgid "Content path"
|
||||
msgstr "资源路径"
|
||||
|
||||
msgid "HTTP Port"
|
||||
msgstr "HTTP 端口"
|
||||
|
||||
msgid "Service Status"
|
||||
msgstr "服务状态"
|
||||
|
||||
msgid "LANraragi status:"
|
||||
msgstr "LANraragi 的状态信息如下:"
|
||||
|
||||
msgid "Setup"
|
||||
msgstr "安装配置"
|
||||
|
||||
msgid "The following parameters will only take effect during installation or upgrade:"
|
||||
msgstr "以下参数只在安装或者升级时才会生效:"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "LANraragi is running"
|
||||
msgstr "LANraragi 运行中"
|
||||
|
||||
msgid "LANraragi is not running"
|
||||
msgstr "LANraragi 未运行"
|
||||
|
||||
msgid "Open LANraragi"
|
||||
msgstr "打开 LANraragi"
|
1
luci-app-lanraragi/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
6
luci-app-lanraragi/root/etc/config/lanraragi
Normal file
@ -0,0 +1,6 @@
|
||||
config main
|
||||
option 'http_port' '3000'
|
||||
option 'image_name' 'difegue/lanraragi'
|
||||
option 'config_path' ''
|
||||
option 'content_path' ''
|
||||
|
75
luci-app-lanraragi/root/usr/libexec/istorec/lanraragi.sh
Executable file
@ -0,0 +1,75 @@
|
||||
#!/bin/sh
|
||||
# Author Xiaobao(xiaobao@linkease.com)
|
||||
|
||||
ACTION=${1}
|
||||
shift 1
|
||||
|
||||
do_install() {
|
||||
local http_port=`uci get lanraragi.@main[0].http_port 2>/dev/null`
|
||||
local image_name=`uci get lanraragi.@main[0].image_name 2>/dev/null`
|
||||
local config=`uci get lanraragi.@main[0].config_path 2>/dev/null`
|
||||
local content=`uci get lanraragi.@main[0].content_path 2>/dev/null`
|
||||
|
||||
[ -z "$image_name" ] && image_name="difegue/lanraragi"
|
||||
echo "docker pull ${image_name}"
|
||||
docker pull ${image_name}
|
||||
docker rm -f lanraragi
|
||||
|
||||
if [ -z "$config" ]; then
|
||||
echo "config path is empty!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -z "$http_port" ] && http_port=3000
|
||||
|
||||
local cmd="docker run --restart=unless-stopped -d \
|
||||
-v \"$config:/home/koyomi/lanraragi/database\" \
|
||||
-v \"$content:/home/koyomi/lanraragi/content\" \
|
||||
--dns=172.17.0.1 \
|
||||
-p $http_port:3000 "
|
||||
|
||||
local tz="`cat /tmp/TZ`"
|
||||
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
|
||||
|
||||
cmd="$cmd -v /mnt:/mnt"
|
||||
mountpoint -q /mnt && cmd="$cmd:rslave"
|
||||
cmd="$cmd --name lanraragi \"$image_name\""
|
||||
|
||||
echo "$cmd"
|
||||
eval "$cmd"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 sub-command"
|
||||
echo "where sub-command is one of:"
|
||||
echo " install Install the lanraragi"
|
||||
echo " upgrade Upgrade the lanraragi"
|
||||
echo " rm/start/stop/restart Remove/Start/Stop/Restart the lanraragi"
|
||||
echo " status LANraragi status"
|
||||
echo " port LANraragi port"
|
||||
}
|
||||
|
||||
case ${ACTION} in
|
||||
"install")
|
||||
do_install
|
||||
;;
|
||||
"upgrade")
|
||||
do_install
|
||||
;;
|
||||
"rm")
|
||||
docker rm -f lanraragi
|
||||
;;
|
||||
"start" | "stop" | "restart")
|
||||
docker ${ACTION} lanraragi
|
||||
;;
|
||||
"status")
|
||||
docker ps --all -f 'name=lanraragi' --format '{{.State}}'
|
||||
;;
|
||||
"port")
|
||||
docker ps --all -f 'name=lanraragi' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*' | sed 's/0.0.0.0://'
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-lanraragi": {
|
||||
"description": "Grant UCI access for luci-app-lanraragi",
|
||||
"read": {
|
||||
"uci": [ "lanraragi" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "lanraragi" ]
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@ include $(TOPDIR)/rules.mk
|
||||
LUCI_TITLE:=LuCI support for linkease
|
||||
LUCI_DEPENDS:=+linkease
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_MINIFY_LUA:=0
|
||||
LUCI_MINIFY_CSS:=0
|
||||
LUCI_MINIFY_JS:=0
|
||||
|
||||
|
@ -1,22 +1,20 @@
|
||||
<%
|
||||
local ver = require "luci.version"
|
||||
-%>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0" /> -->
|
||||
<meta name="viewport" content="width=1380" />
|
||||
<title>易有云文件管理</title>
|
||||
<script>
|
||||
(function () {
|
||||
var pathe_prefix = "<%=prefix%>"
|
||||
window.path_base = pathe_prefix
|
||||
window.ver = "<%=ver.luciversion%>"
|
||||
window.ver = "<%# PKG_VERSION %>"
|
||||
})();
|
||||
</script>
|
||||
<script type="module" crossorigin src="/luci-static/linkeasefile/index.js?v=<%=ver.luciversion%>"></script>
|
||||
<link rel="stylesheet" href="/luci-static/linkeasefile/style.css?v=<%=ver.luciversion%>">
|
||||
<script type="module" crossorigin src="/luci-static/linkeasefile/index.js<%# ?v=PKG_VERSION %>"></script>
|
||||
<link rel="stylesheet" href="/luci-static/linkeasefile/style.css<%# ?v=PKG_VERSION %>">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
13
luci-app-mymind/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_MAINTAINER:=xiaobao <xiaobao@linkease.com>
|
||||
|
||||
LUCI_TITLE:=LuCI support for mymind
|
||||
LUCI_DESCRIPTION:=all
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
7
luci-app-mymind/luasrc/controller/mymind.lua
Executable file
@ -0,0 +1,7 @@
|
||||
|
||||
module("luci.controller.mymind", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "mymind"}, alias("admin", "services", "mymind", "config"), _("MyMind"), 30).dependent = true
|
||||
entry({"admin", "services", "mymind", "config"}, cbi("mymind"))
|
||||
end
|
16
luci-app-mymind/luasrc/model/cbi/mymind.lua
Normal file
@ -0,0 +1,16 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local m, s
|
||||
|
||||
m = Map("mymind",
|
||||
translate("MyMind"),
|
||||
translate("MyMind is mind editor.")
|
||||
.. translate("Official website:") .. ' <a href=\"https://github.com/ondras/my-mind\" target=\"_blank\">https://github.com/ondras/my-mind</a>')
|
||||
|
||||
s = m:section(SimpleSection, translate("MyMind Web"), translate("MyMind Web:"))
|
||||
s:append(Template("mymind/status"))
|
||||
|
||||
return m
|
7
luci-app-mymind/luasrc/view/mymind/status.htm
Normal file
@ -0,0 +1,7 @@
|
||||
<div class="cbi-value cbi-value-last">
|
||||
<label class="cbi-value-title"> </label>
|
||||
<div class="cbi-value-field">
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open MyMind%>" onclick="window.open('http://'+location.hostname+'/luci-static/mymind/', '_blank')" />
|
||||
</div>
|
||||
</div>
|
||||
|
14
luci-app-mymind/po/zh-cn/mymind.po
Normal file
@ -0,0 +1,14 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Official website:"
|
||||
msgstr "官方网站:"
|
||||
|
||||
msgid "MyMind is mind editor."
|
||||
msgstr "MyMind 是一个在线思维导图编辑器。"
|
||||
|
||||
msgid "Open MyMind"
|
||||
msgstr "打开 MyMind"
|
||||
|
||||
msgid "MyMind Web"
|
||||
msgstr "MyMind 网页"
|
1
luci-app-mymind/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
20
luci-app-mymind/root/www/luci-static/mymind/LICENSE.txt
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2019 Ondrej Zara
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
8
luci-app-mymind/root/www/luci-static/mymind/PRIVACY.txt
Normal file
@ -0,0 +1,8 @@
|
||||
Privacy Policy
|
||||
==============
|
||||
|
||||
This application can be configured to use Google Drive as a storage option for Mind Map design files. If you decide to do so, please note that My Mind will have a theoretical access to all your Google Drive files.
|
||||
|
||||
This application, however, only saves/loads those files that are explicitely requested by the user via My Mind's User Interface.
|
||||
|
||||
This application is not accessing, reading, writing, modifying or deleting other kinds of data. In particular, user data and metadata (information about the user logged into the Google ecosystem) is never accessed.
|
37
luci-app-mymind/root/www/luci-static/mymind/README.md
Normal file
@ -0,0 +1,37 @@
|
||||
# My Mind
|
||||
|
||||
![Screenshot](screenshot.png)
|
||||
|
||||
My Mind is a web application for creating and managing Mind maps. It is free to use and you can fork its source code. It is distributed under the terms of the MIT license.
|
||||
|
||||
New to Mind maps? They are useful, aesthetic and cool! Read more about these special diagrams in [the Wikipedia article](http://en.wikipedia.org/wiki/Mind_map).
|
||||
|
||||
* [Official web page](http://my-mind.github.io/)
|
||||
* [Sample mind map](http://my-mind.github.io/?map=examples/features.mymind) showcasing many features
|
||||
* [News / Changelog](https://github.com/ondras/my-mind/wiki/News)
|
||||
* [Documentation](https://github.com/ondras/my-mind/wiki)
|
||||
* <a target="_blank" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3340079"><img src="https://www.paypal.com/en_GB/i/btn/btn_donate_LG.gif" alt="Donate" title="Donate to support further development" /></a>
|
||||
|
||||
## Installation
|
||||
Note: there is also an online version, which can be found at [my-mind.github.io](http://my-mind.github.io/)
|
||||
|
||||
* Download the zip by clicking [here](archive/master.zip) and extract the archive, or clone the repository using git
|
||||
* Open index.html in your webbrowser
|
||||
* Done! If need be, you can find the manual [here](https://github.com/ondras/my-mind/wiki)
|
||||
|
||||
## Contributing
|
||||
|
||||
Do you want to participate?
|
||||
|
||||
* Found a bug? [Open an issue.](https://github.com/ondras/my-mind/issues)
|
||||
* Not sure how to do stuff? [Check the docs.](https://github.com/ondras/my-mind/wiki)
|
||||
* Have a feature request? [Open an issue.](https://github.com/ondras/my-mind/issues)
|
||||
* Have an improvement? [Submit a pull request.](https://github.com/ondras/my-mind/pulls)
|
||||
|
||||
## License
|
||||
[MIT](LICENSE.txt)
|
||||
|
||||
## Links
|
||||
|
||||
* [cdnjs](https://nobige.cn/post/20191116-qian_duan_cdn_zheng_li_he_ji/)
|
||||
|
6
luci-app-mymind/root/www/luci-static/mymind/css/font.css
Normal file
121
luci-app-mymind/root/www/luci-static/mymind/css/item.css
Normal file
@ -0,0 +1,121 @@
|
||||
.item {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.item.cut {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.item.collapsed .children {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content > * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.text {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
min-width: 0.5em;
|
||||
min-height: 1.3em;
|
||||
line-height: 1.3em;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.value, .status {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
.text ~ .value, .text ~ .status {
|
||||
margin-left: 0.2em;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.value {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.value:not(:empty):before {
|
||||
content: "(";
|
||||
}
|
||||
|
||||
.value:not(:empty):after {
|
||||
content: ")";
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 150%;
|
||||
line-height: 0.8;
|
||||
}
|
||||
|
||||
.status.yes:after {
|
||||
content: "✔";
|
||||
color: #0f0;
|
||||
}
|
||||
|
||||
.status.no:after {
|
||||
content: "✘";
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.notes-indicator {
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
background: url("../icons/notes-indicator.png") right center no-repeat;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: 0;
|
||||
opacity: 0.4;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.notes-indicator-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
line-height: 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #00f;
|
||||
background-color: #88f;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-family: sans-serif;
|
||||
color: #fff;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.toggle:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toggle:before {
|
||||
content: "−";
|
||||
}
|
||||
|
||||
.collapsed > .toggle:before {
|
||||
content: "+";
|
||||
}
|
||||
|
||||
:not(.current):not(.collapsed) > .toggle {
|
||||
/* NOT display:none - we need to have non-zero dimensions for layouting */
|
||||
visibility: hidden;
|
||||
}
|
33
luci-app-mymind/root/www/luci-static/mymind/css/menu.css
Normal file
@ -0,0 +1,33 @@
|
||||
#menu {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
border: 1px solid #666;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 2px 1px #666;
|
||||
}
|
||||
|
||||
#menu button {
|
||||
display: block;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 3px 6px;
|
||||
font-size: 15px;
|
||||
width: 130px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#menu button:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#menu span {
|
||||
display: block;
|
||||
border-top: 1px solid #666;
|
||||
margin-top: 4px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
#menu .ui select.fa-select, .ui select.fa-select option {
|
||||
font-size: 13px;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
.ui, #toggle, #tip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#port > .item {
|
||||
position: static;
|
||||
}
|
43
luci-app-mymind/root/www/luci-static/mymind/css/shape.css
Normal file
@ -0,0 +1,43 @@
|
||||
.shape-box > .content {
|
||||
padding: 0.15em 0.4em;
|
||||
background-color: #fff;
|
||||
border: 1px solid #666;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.shape-ellipse > .content {
|
||||
background-color: #fff;
|
||||
border: 1px solid #666;
|
||||
border-radius: 50%;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
/* current */
|
||||
|
||||
.current > .content {
|
||||
background-color: rgba(255, 255, 187, 0.9);
|
||||
}
|
||||
|
||||
/* root */
|
||||
|
||||
#port > .item > .content {
|
||||
font-weight: bold;
|
||||
border-width: 2px;
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
#port > .item > .toggle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 1st children */
|
||||
|
||||
#port > .item > .children > .item > .content {
|
||||
border-width: 2px;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.item .icon {
|
||||
margin: 0 0.5em 0 0;
|
||||
font-size: x-large;
|
||||
}
|
73
luci-app-mymind/root/www/luci-static/mymind/css/style.css
Normal file
@ -0,0 +1,73 @@
|
||||
@import url(ui.css);
|
||||
@import url(item.css);
|
||||
@import url(shape.css);
|
||||
@import url(menu.css);
|
||||
|
||||
* {
|
||||
font-family: source sans pro, sans-serif;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
background-color: #eed;
|
||||
-webkit-user-select: none; /* no magnifier on hold */
|
||||
}
|
||||
|
||||
[contenteditable] { /* allow for editable items */
|
||||
-webkit-user-select: auto;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#port {
|
||||
overflow: hidden;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#throbber {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: -60px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-image: url(throbber.gif);
|
||||
}
|
||||
|
||||
#throbber:not(.visible) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.ghost {
|
||||
position: absolute !important; /* to prevent collision with .content */
|
||||
opacity: 0.5;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#tip {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
left: 10px;
|
||||
bottom: 5px;
|
||||
transition: all 500ms;
|
||||
font-size: 1rem; /* do not scale with map zoom */
|
||||
}
|
||||
|
||||
#tip:before {
|
||||
content: "Tip: ";
|
||||
}
|
||||
|
||||
#tip code {
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
#tip.hidden {
|
||||
opacity: 0;
|
||||
}
|
BIN
luci-app-mymind/root/www/luci-static/mymind/css/throbber.gif
Normal file
After Width: | Height: | Size: 13 KiB |
226
luci-app-mymind/root/www/luci-static/mymind/css/ui.css
Normal file
@ -0,0 +1,226 @@
|
||||
button:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ui {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
width: 200px;
|
||||
max-width: 600px;
|
||||
box-shadow: 0 0 2px 2px #666;
|
||||
-webkit-transition: -webkit-transform 500ms;
|
||||
transition: transform 500ms;
|
||||
}
|
||||
|
||||
.ui:not(.visible) {
|
||||
-webkit-transform: translate(100%, 0);
|
||||
transform: translate(100%, 0);
|
||||
}
|
||||
|
||||
.ui h3 {
|
||||
background-color: #34495e;
|
||||
color: #fff;
|
||||
padding: 0.2em 0;
|
||||
margin: 0;
|
||||
text-transform: capitalize;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ui select, .ui input {
|
||||
background-color: transparent;
|
||||
border: 1px solid rgba(50, 70, 90, 0.5);
|
||||
font-size: 13px;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
transition: all 250ms linear;
|
||||
}
|
||||
|
||||
.ui select:hover, .ui input:hover, .ui select:focus, .ui input:focus {
|
||||
border-color: rgba(50, 70, 90, 1);
|
||||
}
|
||||
|
||||
.ui select, .ui input, .ui #color {
|
||||
width: 168px;
|
||||
}
|
||||
|
||||
.ui .go {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ui p {
|
||||
margin: 8px 16px;
|
||||
}
|
||||
|
||||
.ui p.desc {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ui:not([id]) button {
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0 4px;
|
||||
background-color: transparent;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.ui button:first-child {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.ui button:last-child {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.ui button[data-command=Help] {
|
||||
position: absolute;
|
||||
left: -50px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.ui button[data-command=Notes] {
|
||||
position: absolute;
|
||||
left: -90px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.ui table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.ui table td:first-child {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.ui table td:last-child {
|
||||
text-align: right;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.ui span {
|
||||
text-transform: uppercase;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.ui #color {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ui #color::after {
|
||||
clear: both;
|
||||
content: "";
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ui [data-color] {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 3px;
|
||||
margin-right: 2px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.ui [data-color]:hover, .ui [data-color]:first-child {
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
#notes {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#notes-editor {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pell-content {
|
||||
height: calc(100% - 60px);
|
||||
}
|
||||
|
||||
.ui #github {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
bottom: 6px;
|
||||
}
|
||||
|
||||
.ui #github img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ui #privacy {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
bottom: 6px;
|
||||
}
|
||||
|
||||
.ui #toggle {
|
||||
z-index: 999;
|
||||
position: absolute;
|
||||
left: -23px;
|
||||
top: 48%;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
padding: 0 0 0 2px;
|
||||
text-align: left;
|
||||
|
||||
border: none;
|
||||
background-color: #fff;
|
||||
box-shadow: -3px 0 2px 0px #666;
|
||||
|
||||
line-height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.ui #toggle:after {
|
||||
content: "←";
|
||||
font-weight: bold;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.ui.visible #toggle:after {
|
||||
content: "→";
|
||||
}
|
||||
|
||||
.ui#help {
|
||||
overflow-y: auto;
|
||||
right: auto;
|
||||
left: 0;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.ui#help:not(.visible) {
|
||||
-webkit-transform: translate(-100%, 0);
|
||||
transform: translate(-100%, 0);
|
||||
}
|
||||
|
||||
.ui#help table {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.ui#io button {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.ui#io button:nth-child(odd) {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.ui#io button:nth-child(even) {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.ui select.fa-select ,
|
||||
.ui select.fa-select option {
|
||||
font-family: fontAwesome;
|
||||
font-size: x-large;
|
||||
}
|
91
luci-app-mymind/root/www/luci-static/mymind/editor.html
Normal file
@ -0,0 +1,91 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0" />
|
||||
<title></title>
|
||||
<link rel="stylesheet" type="text/css" href="https://npm.elemecdn.com/pell/dist/pell.min.css">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="notes-content"></div>
|
||||
<script>
|
||||
|
||||
var sendMessage = function(action, value) {
|
||||
window.parent.postMessage({
|
||||
action: action,
|
||||
value: value
|
||||
}, '*');
|
||||
};
|
||||
|
||||
window.addEventListener("message", function(e) {
|
||||
if (e.data && e.data.action) {
|
||||
switch (e.data.action) {
|
||||
case "setContent":
|
||||
window.editor.content.innerHTML = e.data.value;
|
||||
break;
|
||||
|
||||
case "getContent":
|
||||
sendMessage('setContent', window.editor.content.innerHTML);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
window.onload = function() {
|
||||
|
||||
window.editor = window.pell.init({
|
||||
element: document.getElementById('notes-content'),
|
||||
onChange: function(html) {
|
||||
sendMessage('setContent', html);
|
||||
},
|
||||
defaultParagraphSeparator: 'div',
|
||||
styleWithCSS: false,
|
||||
actions: [
|
||||
'bold',
|
||||
'italic',
|
||||
'underline',
|
||||
'strikethrough',
|
||||
'heading1',
|
||||
'heading2',
|
||||
'paragraph',
|
||||
'quote',
|
||||
'olist',
|
||||
'ulist',
|
||||
'code',
|
||||
'line',
|
||||
{
|
||||
name: 'link',
|
||||
result: function() {
|
||||
const url = window.prompt('Enter the link URL');
|
||||
if (url) {
|
||||
window.pell.exec('createLink', url);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'close',
|
||||
icon: 'Close',
|
||||
title: 'Close Notes',
|
||||
result: function() {
|
||||
sendMessage('closeEditor', true);
|
||||
}
|
||||
}
|
||||
],
|
||||
classes: {
|
||||
actionbar: 'pell-actionbar',
|
||||
button: 'pell-button',
|
||||
content: 'pell-content',
|
||||
selected: 'pell-button-selected'
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<script src="http://npm.elemecdn.com/pell"></script>
|
||||
</body>
|
||||
</html>
|
BIN
luci-app-mymind/root/www/luci-static/mymind/favicon.ico
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/github.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/icons/help.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/icons/new.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 790 B |
BIN
luci-app-mymind/root/www/luci-static/mymind/icons/notes.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/icons/open.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/icons/save-as.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/icons/save.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
1053
luci-app-mymind/root/www/luci-static/mymind/index.html
Normal file
365
luci-app-mymind/root/www/luci-static/mymind/logo/logo.svg
Normal file
@ -0,0 +1,365 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="100.5"
|
||||
height="100.5"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="logo.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient3950">
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3952" />
|
||||
<stop
|
||||
id="stop3958"
|
||||
offset="0.5"
|
||||
style="stop-color:#eeeeec;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3954" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3934">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3936" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3938" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3926">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3928" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3930" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3811"
|
||||
osb:paint="gradient">
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3813" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:0.24705882;"
|
||||
offset="0.10769231"
|
||||
id="stop3821" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3815" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3957">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3959" />
|
||||
<stop
|
||||
id="stop3973"
|
||||
offset="0.83076924"
|
||||
style="stop-color:#729fcf;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3961" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3861">
|
||||
<stop
|
||||
style="stop-color:#555753;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3863" />
|
||||
<stop
|
||||
style="stop-color:#555753;stop-opacity:0.24705882;"
|
||||
offset="0.95384616"
|
||||
id="stop3879" />
|
||||
<stop
|
||||
style="stop-color:#555753;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3865" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3853">
|
||||
<stop
|
||||
style="stop-color:#2e3436;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3855" />
|
||||
<stop
|
||||
style="stop-color:#2e3436;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3857" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3833">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3835" />
|
||||
<stop
|
||||
id="stop3841"
|
||||
offset="0.40000001"
|
||||
style="stop-color:#729fcf;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3837" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3797">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3799" />
|
||||
<stop
|
||||
id="stop3805"
|
||||
offset="0.73846155"
|
||||
style="stop-color:#729fcf;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3801" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3833"
|
||||
id="linearGradient3839"
|
||||
x1="35.992271"
|
||||
y1="971.09375"
|
||||
x2="64.009659"
|
||||
y2="971.09375"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3853"
|
||||
id="radialGradient3859"
|
||||
cx="51.42564"
|
||||
cy="1038.7981"
|
||||
fx="51.42564"
|
||||
fy="1038.7981"
|
||||
r="25.491026"
|
||||
gradientTransform="matrix(1,0,0,0.1069758,0,927.67183)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3926"
|
||||
id="linearGradient3932"
|
||||
x1="41.919182"
|
||||
y1="967.81268"
|
||||
x2="57.638966"
|
||||
y2="967.81268"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3934"
|
||||
id="linearGradient3940"
|
||||
x1="47.370735"
|
||||
y1="983.86664"
|
||||
x2="52.938766"
|
||||
y2="983.86664"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3797"
|
||||
id="linearGradient3046"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="20.875662"
|
||||
y1="1004.267"
|
||||
x2="76.027336"
|
||||
y2="1004.267" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.6568542"
|
||||
inkscape:cx="27.022189"
|
||||
inkscape:cy="65.253162"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-951.86218)">
|
||||
<g
|
||||
id="g3965"
|
||||
transform="matrix(0.87335401,0,0,0.87335401,4.7729708,129.21159)">
|
||||
<rect
|
||||
transform="matrix(0,-1,1,0,0,0)"
|
||||
ry="10"
|
||||
rx="10"
|
||||
y="0.25"
|
||||
x="-1052.1122"
|
||||
height="100"
|
||||
width="100"
|
||||
id="rect3039"
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#204a87;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<rect
|
||||
style="fill:none;stroke:#729fcf;stroke-width:0.49659538;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3041"
|
||||
width="99.319077"
|
||||
height="99.319077"
|
||||
x="0.59046113"
|
||||
y="952.45264"
|
||||
rx="9.9319077"
|
||||
ry="9.9319077" />
|
||||
</g>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:url(#radialGradient3859);fill-opacity:1;stroke:none"
|
||||
id="path3843"
|
||||
sodipodi:cx="51.42564"
|
||||
sodipodi:cy="1038.7981"
|
||||
sodipodi:rx="25.241026"
|
||||
sodipodi:ry="2.476923"
|
||||
d="m 76.666666,1038.7981 c 0,1.368 -11.300792,2.4769 -25.241026,2.4769 -13.940234,0 -25.241026,-1.1089 -25.241026,-2.4769 0,-1.368 11.300792,-2.4769 25.241026,-2.4769 13.940234,0 25.241026,1.1089 25.241026,2.4769 z"
|
||||
transform="translate(-2.8307692,2.7902882)" />
|
||||
<g
|
||||
id="g3041"
|
||||
transform="translate(-0.87536919,-2)">
|
||||
<g
|
||||
transform="matrix(1.1570738,0,0,0.73672744,-7.7805549,273.73097)"
|
||||
id="g3035">
|
||||
<path
|
||||
transform="matrix(0.35495108,-0.88493004,0.77120246,0.40729496,-742.15673,650.73834)"
|
||||
d="m 75.527338,1004.267 c 0,14.9536 -12.122266,27.0759 -27.075838,27.0759 -14.953573,0 -27.075838,-12.1223 -27.075838,-27.0759 0,-14.95354 12.122265,-27.07581 27.075838,-27.07581 14.953572,0 27.075838,12.12227 27.075838,27.07581 z"
|
||||
sodipodi:ry="27.075838"
|
||||
sodipodi:rx="27.075838"
|
||||
sodipodi:cy="1004.267"
|
||||
sodipodi:cx="48.4515"
|
||||
id="path3785"
|
||||
style="fill:url(#linearGradient3046);fill-opacity:1;stroke:#729fcf;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:none;stroke:#204a87;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path3759"
|
||||
sodipodi:cx="48.4515"
|
||||
sodipodi:cy="1004.267"
|
||||
sodipodi:rx="27.075838"
|
||||
sodipodi:ry="27.075838"
|
||||
d="m 75.527338,1004.267 c 0,14.9536 -12.122266,27.0759 -27.075838,27.0759 -14.953573,0 -27.075838,-12.1223 -27.075838,-27.0759 0,-14.95354 12.122265,-27.07581 27.075838,-27.07581 14.953572,0 27.075838,12.12227 27.075838,27.07581 z"
|
||||
transform="matrix(0.8714841,0,0,1,7.3096687,12.628031)" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#204a87;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path3755"
|
||||
sodipodi:cx="34.55732"
|
||||
sodipodi:cy="993.93536"
|
||||
sodipodi:rx="8.1940031"
|
||||
sodipodi:ry="8.1940031"
|
||||
d="m 42.751323,993.93536 c 0,4.52543 -3.66858,8.19404 -8.194003,8.19404 -4.525423,0 -8.194003,-3.66861 -8.194003,-8.19404 0,-4.52542 3.66858,-8.194 8.194003,-8.194 4.525423,0 8.194003,3.66858 8.194003,8.194 z"
|
||||
transform="matrix(-0.84657206,0.48875732,-0.48875732,-0.84657205,554.39803,1840.7315)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#eeeeec;fill-opacity:1;stroke:#204a87;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path3757"
|
||||
sodipodi:cx="59.139328"
|
||||
sodipodi:cy="998.38861"
|
||||
sodipodi:rx="4.2751322"
|
||||
sodipodi:ry="4.4532628"
|
||||
d="m 63.41446,998.38861 c 0,2.45949 -1.914042,4.45329 -4.275132,4.45329 -2.36109,0 -4.275132,-1.9938 -4.275132,-4.45329 0,-2.45947 1.914042,-4.45326 4.275132,-4.45326 2.36109,0 4.275132,1.99379 4.275132,4.45326 z"
|
||||
transform="matrix(-0.74348535,0.70960306,-0.71090476,-0.742124,817.9943,1719.2735)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#555753;fill-opacity:1;stroke:#729fcf;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path3761"
|
||||
sodipodi:cx="34.022926"
|
||||
sodipodi:cy="994.11353"
|
||||
sodipodi:rx="3.0282187"
|
||||
sodipodi:ry="3.0282187"
|
||||
d="m 37.051145,994.11353 c 0,1.67243 -1.35578,3.02821 -3.028219,3.02821 -1.672439,0 -3.028218,-1.35578 -3.028218,-3.02821 0,-1.67244 1.355779,-3.02822 3.028218,-3.02822 1.672439,0 3.028219,1.35578 3.028219,3.02822 z"
|
||||
transform="matrix(0.64658836,0,0,0.64658836,17.189883,373.56249)" />
|
||||
<path
|
||||
transform="matrix(0.64658836,0,0,0.64658836,42.128155,377.83762)"
|
||||
d="m 37.051145,994.11353 c 0,1.67243 -1.35578,3.02821 -3.028219,3.02821 -1.672439,0 -3.028218,-1.35578 -3.028218,-3.02821 0,-1.67244 1.355779,-3.02822 3.028218,-3.02822 1.672439,0 3.028219,1.35578 3.028219,3.02822 z"
|
||||
sodipodi:ry="3.0282187"
|
||||
sodipodi:rx="3.0282187"
|
||||
sodipodi:cy="994.11353"
|
||||
sodipodi:cx="34.022926"
|
||||
id="path3767"
|
||||
style="fill:#555753;fill-opacity:1;stroke:#729fcf;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
<g
|
||||
style="font-size:43.07986069px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:none;stroke:#204a87;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Bold"
|
||||
id="text3856"
|
||||
transform="translate(-0.9476607,10)">
|
||||
<path
|
||||
style="stroke:#204a87;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Bold"
|
||||
d="m 50.174617,981.06107 c 0.37862,0 0.750239,0.0771 1.114859,0.23139 0.378619,0.15426 0.722192,0.36461 1.03072,0.63105 0.308501,0.26645 0.55391,0.58197 0.736228,0.94658 0.196313,0.36461 0.294477,0.75726 0.294491,1.17796 -1.4e-5,0.37864 -0.08416,0.74324 -0.252421,1.09383 -0.168295,0.35058 -0.39968,0.6591 -0.694158,0.92554 -0.280481,0.26644 -0.617042,0.4768 -1.009684,0.63105 -0.378644,0.15426 -0.785322,0.23139 -1.220035,0.23139 -0.44876,0 -0.869461,-0.0771 -1.262105,-0.23139 -0.392665,-0.15425 -0.736238,-0.36461 -1.03072,-0.63105 -0.2945,-0.26644 -0.525886,-0.57496 -0.694158,-0.92554 -0.168289,-0.35059 -0.252429,-0.71519 -0.252421,-1.09383 -8e-6,-0.39265 0.08413,-0.77128 0.252421,-1.13589 0.168272,-0.36461 0.399658,-0.68013 0.694158,-0.94658 0.294482,-0.28047 0.638055,-0.49783 1.03072,-0.65209 0.392644,-0.16828 0.813345,-0.25242 1.262105,-0.25242"
|
||||
id="path3900"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="stroke:#204a87;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Bold"
|
||||
d="m 42.917511,960.23633 c 0.645072,-0.617 1.339229,-1.13587 2.082474,-1.55659 0.757256,-0.4347 1.549577,-0.76425 2.376965,-0.98865 0.841394,-0.23837 1.710844,-0.35757 2.608351,-0.3576 1.234046,3e-5 2.348905,0.21038 3.344579,0.63105 0.995645,0.40671 1.837048,0.96764 2.524211,1.68281 0.687128,0.71522 1.213005,1.5426 1.577631,2.48214 0.378613,0.93959 0.567928,1.93525 0.567948,2.98698 -2e-5,0.81338 -0.112207,1.54259 -0.336562,2.18765 -0.210369,0.63107 -0.511872,1.22005 -0.904509,1.76695 -0.378649,0.54693 -0.84142,1.0728 -1.388315,1.57763 -0.532905,0.50486 -1.121887,1.01671 -1.766948,1.53556 -0.322552,0.25244 -0.581985,0.51888 -0.778298,0.79934 -0.182318,0.28048 -0.322552,0.57497 -0.420702,0.88347 -0.08415,0.2945 -0.140247,0.61704 -0.168281,0.96761 -0.02806,0.33658 -0.04208,0.70118 -0.04207,1.09383 l 0,2.37696 -4.270123,0 0,-2.37696 c -9e-6,-0.603 0.02103,-1.14991 0.06311,-1.64074 0.04206,-0.49081 0.154248,-0.98162 0.336561,-1.47246 0.196318,-0.50482 0.490809,-1.02369 0.883474,-1.55659 0.392644,-0.5469 0.939556,-1.17094 1.640737,-1.87212 0.869437,-0.86944 1.472442,-1.65475 1.809017,-2.35593 0.350571,-0.71518 0.525863,-1.42336 0.525877,-2.12455 -1.4e-5,-0.51884 -0.08415,-1.00265 -0.252421,-1.45142 -0.168294,-0.46275 -0.406692,-0.86241 -0.715193,-1.199 -0.294504,-0.33654 -0.6521,-0.60298 -1.072789,-0.79933 -0.40669,-0.19631 -0.848427,-0.29447 -1.325211,-0.29449 -0.532899,2e-5 -1.044752,0.1052 -1.535561,0.31552 -0.476804,0.19635 -0.939576,0.47682 -1.388316,0.84141 -0.448756,0.36463 -0.883481,0.80636 -1.304175,1.32521 -0.406685,0.50486 -0.792328,1.07281 -1.15693,1.70384 l -3.218371,-3.07112 c 0.504837,-0.75724 1.072784,-1.43738 1.70384,-2.04041 z"
|
||||
id="path3883"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="stroke:#204a87;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Bold"
|
||||
d="m 50.174617,981.06107 c 0.37862,0 0.750239,0.0771 1.114859,0.23139 0.378619,0.15426 0.722192,0.36461 1.03072,0.63105 0.308501,0.26645 0.55391,0.58197 0.736228,0.94658 0.196313,0.36461 0.294477,0.75726 0.294491,1.17796 -1.4e-5,0.37864 -0.08416,0.74324 -0.252421,1.09383 -0.168295,0.35058 -0.39968,0.6591 -0.694158,0.92554 -0.280481,0.26644 -0.617042,0.4768 -1.009684,0.63105 -0.378644,0.15426 -0.785322,0.23139 -1.220035,0.23139 -0.44876,0 -0.869461,-0.0771 -1.262105,-0.23139 -0.392665,-0.15425 -0.736238,-0.36461 -1.03072,-0.63105 -0.2945,-0.26644 -0.525886,-0.57496 -0.694158,-0.92554 -0.168289,-0.35059 -0.252429,-0.71519 -0.252421,-1.09383 -8e-6,-0.39265 0.08413,-0.77128 0.252421,-1.13589 0.168272,-0.36461 0.399658,-0.68013 0.694158,-0.94658 0.294482,-0.28047 0.638055,-0.49783 1.03072,-0.65209 0.392644,-0.16828 0.813345,-0.25242 1.262105,-0.25242"
|
||||
id="path3904"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3932);fill-opacity:1;stroke:#729fcf;stroke-width:0.88508385;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Bold"
|
||||
d="m 51.246743,958.3551 c 1.437972,0.22537 2.200404,0.49227 3.327809,1.34453 1.168747,0.88351 2.444631,2.67088 2.606656,5.04155 0.162024,2.65195 -1.19831,3.91824 -1.994644,4.79227 -0.796334,0.87404 -2.645573,2.04052 -3.508717,4.02771 -0.271033,0.23534 -0.300558,4.06254 -0.300558,4.06254 l -2.673891,0 c 0,0 0.02209,-1.93923 0.04418,-3.20959 0.02209,-1.27036 1.625341,-3.53769 2.695703,-4.52738 1.070363,-0.98968 2.943847,-2.60748 2.55883,-5.71811 -0.241938,-1.95465 -1.712887,-3.89799 -4.396978,-3.90988 -2.350107,-0.0104 -5.038402,3.11733 -5.344768,3.70563 l -1.898642,-1.84649 c 1.16321,-1.34857 2.397371,-2.40231 4.075683,-3.16481 1.668287,-0.75794 3.326802,-0.83034 4.809337,-0.59797 z"
|
||||
id="path3906"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ssccccczzssccss" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3940);fill-opacity:1;stroke:#729fcf;stroke-width:0.75084299;font-family:Inconsolata;-inkscape-font-specification:Inconsolata Bold"
|
||||
d="m 50.178442,981.66337 c 0.284285,0 0.563312,0.0579 0.837085,0.17374 0.284283,0.11582 0.542252,0.27376 0.773909,0.47382 0.231635,0.20006 0.415899,0.43696 0.552791,0.71073 0.1474,0.27377 0.221106,0.56858 0.221117,0.88447 -1.1e-5,0.28429 -0.06319,0.55805 -0.189529,0.82129 -0.126363,0.26323 -0.300097,0.49488 -0.521203,0.69493 -0.210598,0.20006 -0.463303,0.35801 -0.758115,0.47382 -0.284302,0.11583 -0.589653,0.17374 -0.916055,0.17374 -0.336948,0 -0.652829,-0.0579 -0.947643,-0.17374 -0.294829,-0.11581 -0.552799,-0.27376 -0.773908,-0.47382 -0.221124,-0.20005 -0.394858,-0.4317 -0.521204,-0.69493 -0.126359,-0.26324 -0.189535,-0.537 -0.189529,-0.82129 -6e-6,-0.29482 0.06317,-0.57911 0.189529,-0.85288 0.126346,-0.27377 0.30008,-0.51067 0.521204,-0.71074 0.221109,-0.21058 0.479079,-0.37379 0.773908,-0.48961 0.294814,-0.12635 0.610695,-0.18953 0.947643,-0.18953"
|
||||
id="path3908"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 18 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/logo/logo128.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/logo/logo16.png
Normal file
After Width: | Height: | Size: 314 B |
BIN
luci-app-mymind/root/www/luci-static/mymind/logo/logo256.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/logo/logo32.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
luci-app-mymind/root/www/luci-static/mymind/logo/logo64.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
5412
luci-app-mymind/root/www/luci-static/mymind/my-mind.js
Normal file
BIN
luci-app-mymind/root/www/luci-static/mymind/screenshot.png
Normal file
After Width: | Height: | Size: 90 KiB |
1
luci-app-mymind/root/www/luci-static/mymind/vendor/pell/css/pell.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.pell{border:1px solid hsla(0,0%,4%,.1)}.pell,.pell-content{box-sizing:border-box}.pell-content{height:300px;outline:0;overflow-y:auto;padding:10px}.pell-actionbar{background-color:#fff;border-bottom:1px solid hsla(0,0%,4%,.1)}.pell-button{background-color:transparent;border:none;cursor:pointer;height:30px;outline:0;width:30px;vertical-align:bottom}.pell-button-selected{background-color:#f0f0f0}
|
1
luci-app-mymind/root/www/luci-static/mymind/vendor/pell/src/pell.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.pell={})}(this,function(t){"use strict";var e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t},c="defaultParagraphSeparator",l="formatBlock",a=function(t,e,n){return t.addEventListener(e,n)},s=function(t,e){return t.appendChild(e)},d=function(t){return document.createElement(t)},n=function(t){return document.queryCommandState(t)},f=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null;return document.execCommand(t,!1,e)},p={bold:{icon:"<b>B</b>",title:"Bold",state:function(){return n("bold")},result:function(){return f("bold")}},italic:{icon:"<i>I</i>",title:"Italic",state:function(){return n("italic")},result:function(){return f("italic")}},underline:{icon:"<u>U</u>",title:"Underline",state:function(){return n("underline")},result:function(){return f("underline")}},strikethrough:{icon:"<strike>S</strike>",title:"Strike-through",state:function(){return n("strikeThrough")},result:function(){return f("strikeThrough")}},heading1:{icon:"<b>H<sub>1</sub></b>",title:"Heading 1",result:function(){return f(l,"<h1>")}},heading2:{icon:"<b>H<sub>2</sub></b>",title:"Heading 2",result:function(){return f(l,"<h2>")}},paragraph:{icon:"¶",title:"Paragraph",result:function(){return f(l,"<p>")}},quote:{icon:"“ ”",title:"Quote",result:function(){return f(l,"<blockquote>")}},olist:{icon:"#",title:"Ordered List",result:function(){return f("insertOrderedList")}},ulist:{icon:"•",title:"Unordered List",result:function(){return f("insertUnorderedList")}},code:{icon:"</>",title:"Code",result:function(){return f(l,"<pre>")}},line:{icon:"―",title:"Horizontal Line",result:function(){return f("insertHorizontalRule")}},link:{icon:"🔗",title:"Link",result:function(){var t=window.prompt("Enter the link URL");t&&f("createLink",t)}},image:{icon:"📷",title:"Image",result:function(){var t=window.prompt("Enter the image URL");t&&f("insertImage",t)}}},m={actionbar:"pell-actionbar",button:"pell-button",content:"pell-content",selected:"pell-button-selected"},r=function(n){var t=n.actions?n.actions.map(function(t){return"string"==typeof t?p[t]:p[t.name]?e({},p[t.name],t):t}):Object.keys(p).map(function(t){return p[t]}),r=e({},m,n.classes),i=n[c]||"div",o=d("div");o.className=r.actionbar,s(n.element,o);var u=n.element.content=d("div");return u.contentEditable=!0,u.className=r.content,u.oninput=function(t){var e=t.target.firstChild;e&&3===e.nodeType?f(l,"<"+i+">"):"<br>"===u.innerHTML&&(u.innerHTML=""),n.onChange(u.innerHTML)},u.onkeydown=function(t){var e;"Enter"===t.key&&"blockquote"===(e=l,document.queryCommandValue(e))&&setTimeout(function(){return f(l,"<"+i+">")},0)},s(n.element,u),t.forEach(function(t){var e=d("button");if(e.className=r.button,e.innerHTML=t.icon,e.title=t.title,e.setAttribute("type","button"),e.onclick=function(){return t.result()&&u.focus()},t.state){var n=function(){return e.classList[t.state()?"add":"remove"](r.selected)};a(u,"keyup",n),a(u,"mouseup",n),a(e,"click",n)}s(o,e)}),n.styleWithCSS&&f("styleWithCSS"),f(c,i),n.element},i={exec:f,init:r};t.exec=f,t.init=r,t.default=i,Object.defineProperty(t,"__esModule",{value:!0})});
|
@ -3,6 +3,7 @@ LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local nastools_model = require "luci.model.nastools"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("nastools", "nastools", "/usr/libexec/istorec/nastools.sh",
|
||||
@ -22,10 +23,19 @@ o.rmempty = false
|
||||
o.default = "3003"
|
||||
o.datatype = "port"
|
||||
|
||||
local blocks = nastools_model.blocks()
|
||||
local home = nastools_model.home()
|
||||
|
||||
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
|
||||
local paths, default_path = nastools_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
o = s:option(Flag, "auto_upgrade", translate("Auto update"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
54
luci-app-nastools/luasrc/model/nastools.lua
Normal file
@ -0,0 +1,54 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local nastools = {}
|
||||
|
||||
nastools.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj["blockdevices"]) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
-- fsize > 1G
|
||||
vals[#vals+1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
nastools.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
nastools.find_paths = function(blocks, home_dirs, path_name)
|
||||
local default_path = ''
|
||||
local configs = {}
|
||||
|
||||
default_path = home_dirs[path_name] .. "/NasTools"
|
||||
if #blocks == 0 then
|
||||
table.insert(configs, default_path)
|
||||
else
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(configs, val .. "/" .. path_name .. "/NasTools")
|
||||
end
|
||||
local without_conf_dir = "/root/" .. path_name .. "/NasTools"
|
||||
if default_path == without_conf_dir then
|
||||
default_path = configs[1]
|
||||
end
|
||||
end
|
||||
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return nastools
|
@ -1,4 +1,4 @@
|
||||
config nastools
|
||||
option 'config_path' '/root/nastools/config'
|
||||
option 'config_path' ''
|
||||
option 'http_port' '3003'
|
||||
option 'auto_upgrade' '0'
|
||||
|
16
luci-app-navidrome/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
|
||||
LUCI_TITLE:=LuCI support for Navidrome
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+docker +luci-lib-taskd
|
||||
|
||||
define Package/luci-app-navidrome/conffiles
|
||||
/etc/config/navidrome
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
7
luci-app-navidrome/luasrc/controller/navidrome.lua
Executable file
@ -0,0 +1,7 @@
|
||||
|
||||
module("luci.controller.navidrome", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "navidrome"}, alias("admin", "services", "navidrome", "config"), _("Navidrome"), 30).dependent = true
|
||||
entry({"admin", "services", "navidrome", "config"}, cbi("navidrome"))
|
||||
end
|
54
luci-app-navidrome/luasrc/model/cbi/navidrome.lua
Normal file
@ -0,0 +1,54 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local navidrome_model = require "luci.model.navidrome"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("navidrome", "navidrome", "/usr/libexec/istorec/navidrome.sh",
|
||||
translate("Navidrome"),
|
||||
translate("Navidrome is Open source server for archival of comics/manga.")
|
||||
.. translate("Official website:") .. ' <a href=\"https://github.com/Difegue/Navidrome\" target=\"_blank\">https://github.com/Difegue/Navidrome</a>')
|
||||
|
||||
s = m:section(SimpleSection, translate("Service Status"), translate("Navidrome status:"))
|
||||
s:append(Template("navidrome/status"))
|
||||
|
||||
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
|
||||
s.addremove=false
|
||||
s.anonymous=true
|
||||
|
||||
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.default = "3000"
|
||||
o.datatype = "string"
|
||||
|
||||
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
o:value("difegue/navidrome", "difegue/navidrome")
|
||||
o.default = "difegue/navidrome"
|
||||
|
||||
local blocks = navidrome_model.blocks()
|
||||
local home = navidrome_model.home()
|
||||
|
||||
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
|
||||
local paths, default_path = navidrome_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
o = s:option(Value, "music_path", translate("Music path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
local paths, default_path = navidrome_model.find_paths(blocks, home, "Downloads")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
return m
|
54
luci-app-navidrome/luasrc/model/navidrome.lua
Normal file
@ -0,0 +1,54 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local navidrome = {}
|
||||
|
||||
navidrome.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj["blockdevices"]) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
-- fsize > 1G
|
||||
vals[#vals+1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
navidrome.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
navidrome.find_paths = function(blocks, home_dirs, path_name)
|
||||
local appname = '/Navidrome'
|
||||
local default_path = ''
|
||||
local configs = {}
|
||||
|
||||
if #blocks == 0 then
|
||||
return
|
||||
else
|
||||
if path_name == "Downloads" then
|
||||
appname = "/Music"
|
||||
end
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(configs, val .. "/" .. path_name .. appname)
|
||||
end
|
||||
default_path = configs[1]
|
||||
end
|
||||
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return navidrome
|
31
luci-app-navidrome/luasrc/view/navidrome/status.htm
Normal file
@ -0,0 +1,31 @@
|
||||
<%
|
||||
local util = require "luci.util"
|
||||
local container_status = util.trim(util.exec("/usr/libexec/istorec/navidrome.sh status"))
|
||||
local container_install = (string.len(container_status) > 0)
|
||||
local container_running = container_status == "running"
|
||||
-%>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:Status%></label>
|
||||
<div class="cbi-value-field">
|
||||
<% if container_running then %>
|
||||
<button class="cbi-button cbi-button-success" disabled="true"><%:Navidrome is running%></button>
|
||||
<% else %>
|
||||
<button class="cbi-button cbi-button-negative" disabled="true"><%:Navidrome is not running%></button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
if container_running then
|
||||
local port=util.trim(util.exec("/usr/libexec/istorec/navidrome.sh port"))
|
||||
if port == "" then
|
||||
port="4533"
|
||||
end
|
||||
-%>
|
||||
<div class="cbi-value cbi-value-last">
|
||||
<label class="cbi-value-title"> </label>
|
||||
<div class="cbi-value-field">
|
||||
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open Navidrome%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
41
luci-app-navidrome/po/zh-cn/navidrome.po
Normal file
@ -0,0 +1,41 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Official website:"
|
||||
msgstr "官方网站:"
|
||||
|
||||
msgid "Navidrome is an open source web-based music collection server and streamer. "
|
||||
msgstr "Navidrome 是一个开源的在线音乐播放软件。"
|
||||
|
||||
msgid "Config path"
|
||||
msgstr "配置文件路径"
|
||||
|
||||
msgid "Music path"
|
||||
msgstr "音乐路径"
|
||||
|
||||
msgid "HTTP Port"
|
||||
msgstr "HTTP 端口"
|
||||
|
||||
msgid "Service Status"
|
||||
msgstr "服务状态"
|
||||
|
||||
msgid "Navidrome status:"
|
||||
msgstr "Navidrome 的状态信息如下:"
|
||||
|
||||
msgid "Setup"
|
||||
msgstr "安装配置"
|
||||
|
||||
msgid "The following parameters will only take effect during installation or upgrade:"
|
||||
msgstr "以下参数只在安装或者升级时才会生效:"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Navidrome is running"
|
||||
msgstr "Navidrome 运行中"
|
||||
|
||||
msgid "Navidrome is not running"
|
||||
msgstr "Navidrome 未运行"
|
||||
|
||||
msgid "Open Navidrome"
|
||||
msgstr "打开 Navidrome"
|
1
luci-app-navidrome/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
6
luci-app-navidrome/root/etc/config/navidrome
Normal file
@ -0,0 +1,6 @@
|
||||
config main
|
||||
option 'http_port' '4533'
|
||||
option 'image_name' 'deluan/navidrome:latest'
|
||||
option 'config_path' ''
|
||||
option 'music_path' ''
|
||||
|
75
luci-app-navidrome/root/usr/libexec/istorec/navidrome.sh
Executable file
@ -0,0 +1,75 @@
|
||||
#!/bin/sh
|
||||
# Author Xiaobao(xiaobao@linkease.com)
|
||||
|
||||
ACTION=${1}
|
||||
shift 1
|
||||
|
||||
do_install() {
|
||||
local http_port=`uci get navidrome.@main[0].http_port 2>/dev/null`
|
||||
local image_name=`uci get navidrome.@main[0].image_name 2>/dev/null`
|
||||
local config=`uci get navidrome.@main[0].config_path 2>/dev/null`
|
||||
local content=`uci get navidrome.@main[0].music_path 2>/dev/null`
|
||||
|
||||
[ -z "$image_name" ] && image_name="difegue/navidrome"
|
||||
echo "docker pull ${image_name}"
|
||||
docker pull ${image_name}
|
||||
docker rm -f navidrome
|
||||
|
||||
if [ -z "$config" ]; then
|
||||
echo "config path is empty!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -z "$http_port" ] && http_port=4533
|
||||
|
||||
local cmd="docker run --restart=unless-stopped -d \
|
||||
-v \"$config:/data\" \
|
||||
-v \"$content:/music:ro\" \
|
||||
--dns=172.17.0.1 \
|
||||
-p $http_port:4533 "
|
||||
|
||||
local tz="`cat /tmp/TZ`"
|
||||
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
|
||||
|
||||
cmd="$cmd -v /mnt:/mnt"
|
||||
mountpoint -q /mnt && cmd="$cmd:rslave"
|
||||
cmd="$cmd --name navidrome \"$image_name\""
|
||||
|
||||
echo "$cmd"
|
||||
eval "$cmd"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 sub-command"
|
||||
echo "where sub-command is one of:"
|
||||
echo " install Install the navidrome"
|
||||
echo " upgrade Upgrade the navidrome"
|
||||
echo " rm/start/stop/restart Remove/Start/Stop/Restart the navidrome"
|
||||
echo " status Navidrome status"
|
||||
echo " port Navidrome port"
|
||||
}
|
||||
|
||||
case ${ACTION} in
|
||||
"install")
|
||||
do_install
|
||||
;;
|
||||
"upgrade")
|
||||
do_install
|
||||
;;
|
||||
"rm")
|
||||
docker rm -f navidrome
|
||||
;;
|
||||
"start" | "stop" | "restart")
|
||||
docker ${ACTION} navidrome
|
||||
;;
|
||||
"status")
|
||||
docker ps --all -f 'name=navidrome' --format '{{.State}}'
|
||||
;;
|
||||
"port")
|
||||
docker ps --all -f 'name=navidrome' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*' | sed 's/0.0.0.0://'
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-navidrome": {
|
||||
"description": "Grant UCI access for luci-app-navidrome",
|
||||
"read": {
|
||||
"uci": [ "navidrome" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "navidrome" ]
|
||||
}
|
||||
}
|
||||
}
|
16
luci-app-photoprism/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
|
||||
LUCI_TITLE:=LuCI support for PhotoPrism
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+docker +luci-lib-taskd
|
||||
|
||||
define Package/luci-app-photoprism/conffiles
|
||||
/etc/config/photoprism
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
7
luci-app-photoprism/luasrc/controller/photoprism.lua
Executable file
@ -0,0 +1,7 @@
|
||||
|
||||
module("luci.controller.photoprism", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "photoprism"}, alias("admin", "services", "photoprism", "config"), _("PhotoPrism"), 30).dependent = true
|
||||
entry({"admin", "services", "photoprism", "config"}, cbi("photoprism"))
|
||||
end
|
50
luci-app-photoprism/luasrc/model/cbi/photoprism.lua
Normal file
@ -0,0 +1,50 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local photoprism_model = require "luci.model.photoprism"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("photoprism", "photoprism", "/usr/libexec/istorec/photoprism.sh",
|
||||
translate("PhotoPrism"),
|
||||
translate("PhotoPrism® is an AI-Powered Photos App for the Decentralized Web.")
|
||||
.. translate("Official website:") .. ' <a href=\"https://photoprism.app/\" target=\"_blank\">https://photoprism.app/</a>')
|
||||
|
||||
s = m:section(SimpleSection, translate("Service Status"), translate("PhotoPrism status:"))
|
||||
s:append(Template("photoprism/status"))
|
||||
|
||||
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
|
||||
s.addremove=false
|
||||
s.anonymous=true
|
||||
|
||||
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.default = "2342"
|
||||
o.datatype = "string"
|
||||
o:depends("hostnet", 0)
|
||||
|
||||
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
o:value("photoprism/photoprism:latest", "photoprism/photoprism:latest")
|
||||
o:value("photoprism/photoprism:221105-armv7", "photoprism/photoprism:221105-armv7")
|
||||
o.default = "photoprism/photoprism:latest"
|
||||
|
||||
local blocks = photoprism_model.blocks()
|
||||
local home = photoprism_model.home()
|
||||
|
||||
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
|
||||
local paths, default_path = photoprism_model.find_paths(blocks, home, "Configs")
|
||||
for _, val in pairs(paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = default_path
|
||||
|
||||
o = s:option(Value, "picture_path", translate("Picture path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
|
||||
o.datatype = "string"
|
||||
|
||||
return m
|
54
luci-app-photoprism/luasrc/model/photoprism.lua
Normal file
@ -0,0 +1,54 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local photoprism = {}
|
||||
|
||||
photoprism.blocks = function()
|
||||
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
|
||||
local vals = {}
|
||||
if f then
|
||||
local ret = f:read("*all")
|
||||
f:close()
|
||||
local obj = jsonc.parse(ret)
|
||||
for _, val in pairs(obj["blockdevices"]) do
|
||||
local fsize = val["fssize"]
|
||||
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
|
||||
-- fsize > 1G
|
||||
vals[#vals+1] = val["mountpoint"]
|
||||
end
|
||||
end
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
photoprism.home = function()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local home_dirs = {}
|
||||
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
|
||||
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
|
||||
home_dirs["Downloads"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Downloads")
|
||||
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
|
||||
return home_dirs
|
||||
end
|
||||
|
||||
photoprism.find_paths = function(blocks, home_dirs, path_name)
|
||||
local default_path = ''
|
||||
local configs = {}
|
||||
|
||||
default_path = home_dirs[path_name] .. "/PhotoPrism"
|
||||
if #blocks == 0 then
|
||||
table.insert(configs, default_path)
|
||||
else
|
||||
for _, val in pairs(blocks) do
|
||||
table.insert(configs, val .. "/" .. path_name .. "/PhotoPrism")
|
||||
end
|
||||
local without_conf_dir = "/root/" .. path_name .. "/PhotoPrism"
|
||||
if default_path == without_conf_dir then
|
||||
default_path = configs[1]
|
||||
end
|
||||
end
|
||||
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return photoprism
|
31
luci-app-photoprism/luasrc/view/photoprism/status.htm
Normal file
@ -0,0 +1,31 @@
|
||||
<%
|
||||
local util = require "luci.util"
|
||||
local container_status = util.trim(util.exec("/usr/libexec/istorec/photoprism.sh status"))
|
||||
local container_install = (string.len(container_status) > 0)
|
||||
local container_running = container_status == "running"
|
||||
-%>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:Status%></label>
|
||||
<div class="cbi-value-field">
|
||||
<% if container_running then %>
|
||||
<button class="cbi-button cbi-button-success" disabled="true"><%:PhotoPrism is running%></button>
|
||||
<% else %>
|
||||
<button class="cbi-button cbi-button-negative" disabled="true"><%:PhotoPrism is not running%></button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
if container_running then
|
||||
local port=util.trim(util.exec("/usr/libexec/istorec/photoprism.sh port"))
|
||||
if port == "" then
|
||||
port="2342"
|
||||
end
|
||||
-%>
|
||||
<div class="cbi-value cbi-value-last">
|
||||
<label class="cbi-value-title"> </label>
|
||||
<div class="cbi-value-field">
|
||||
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open PhotoPrism%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
44
luci-app-photoprism/po/zh-cn/photoprism.po
Normal file
@ -0,0 +1,44 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Official website:"
|
||||
msgstr "官方网站:"
|
||||
|
||||
msgid "PhotoPrism® is an AI-Powered Photos App for the Decentralized Web."
|
||||
msgstr "PhotoPrism® PhotoPrism 是一个 AI 驱动的相册管理应用。"
|
||||
|
||||
msgid "Config path"
|
||||
msgstr "配置文件路径"
|
||||
|
||||
msgid "HTTP Port"
|
||||
msgstr "HTTP 端口"
|
||||
|
||||
msgid "Service Status"
|
||||
msgstr "服务状态"
|
||||
|
||||
msgid "Photoprism status:"
|
||||
msgstr "Photoprism 的状态信息如下:"
|
||||
|
||||
msgid "Setup"
|
||||
msgstr "安装配置"
|
||||
|
||||
msgid "The following parameters will only take effect during installation or upgrade:"
|
||||
msgstr "以下参数只在安装或者升级时才会生效:"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Photoprism is running"
|
||||
msgstr "Photoprism 运行中"
|
||||
|
||||
msgid "Photoprism is not running"
|
||||
msgstr "Photoprism 未运行"
|
||||
|
||||
msgid "Open Photoprism"
|
||||
msgstr "打开 Photoprism"
|
||||
|
||||
msgid "Not required, all disk is mounted in"
|
||||
msgstr "可不填,所有硬盘都在"
|
||||
|
||||
msgid "Picture path"
|
||||
msgstr "图片路径"
|
1
luci-app-photoprism/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
5
luci-app-photoprism/root/etc/config/photoprism
Normal file
@ -0,0 +1,5 @@
|
||||
config main
|
||||
option 'http_port' '2342'
|
||||
option 'image_name' 'photoprism/photoprism'
|
||||
option 'config_path' ''
|
||||
|