diff --git a/tools/config-markdown.py b/tools/config-markdown.py index 4c01a6451..0301e8317 100755 --- a/tools/config-markdown.py +++ b/tools/config-markdown.py @@ -94,7 +94,7 @@ def insert_images_and_header(item): if image_file.is_file(): rel_path = f"tools/include/images/{item['id']}.{ext}" parts.append(f"\n") - parts.append(f"[![{item.get('short', item.get('description', ''))}](/images/{item['id']}.{ext})](#)") + parts.append(f"![{item.get('short', item.get('description', ''))}](/images/{item['id']}.{ext})") parts.append(f"\n") break @@ -216,6 +216,313 @@ def create_markdown_user(item, level=1, show_meta=True, force_title=False, skip_ return '\n'.join(md) +def slugify(text): + """netdata -> netdata, 'Uptime Kuma' -> uptime-kuma, NetAlertX -> netalertx.""" + return re.sub(r'[^a-z0-9]+', '-', (text or '').lower()).strip('-') + + +def yaml_quote(text): + """Double-quote a value for YAML front-matter. mkdocs parses front-matter as + YAML, where an unquoted scalar containing ': ' (colon-space) is read as a + nested mapping and the value is lost — so titles/descriptions MUST be quoted.""" + return '"' + str(text).replace('\\', '\\\\').replace('"', '\\"') + '"' + + +def _group_key(item): + """Identity that ties an app's install/remove/purge items together: the + module referenced by the item's command (e.g. `module_qbittorrent install` + -> module_qbittorrent). Grouping on the module (rather than an id prefix) + keeps distinct apps apart even if their ids share a prefix, while still + grouping an app's own actions. Falls back to the item id so unrelated + generic-command items never merge.""" + cmd = item.get('command') + cmd = (cmd[0] if isinstance(cmd, list) else cmd) or '' + m = re.search(r'module_[A-Za-z0-9_-]+', cmd) + return m.group(0) if m else item.get('id', '') + + +def group_software(sub_items): + """Split a category's flat `sub` list into per-software groups, one group per + app (keyed by its command module via _group_key). The name-bearing item + leads each group; its remove/purge actions follow. Returns a list of groups.""" + order, groups = [], {} + for it in sub_items: + key = _group_key(it) + if key not in groups: + groups[key] = [] + order.append(key) + groups[key].append(it) + result = [] + for key in order: + g = groups[key] + if not g[0].get('short'): # lead with the name-bearing (install) item + lead = next((i for i in g if i.get('short')), None) + if lead: + g = [lead] + [x for x in g if x is not lead] + if g[0].get('short'): + result.append(g) + return result + + +def _blurb(item_id): + """First real sentence of an app's header/footer markdown, for when the JSON + description is just the app name. Strips HTML comments and edit/meta lines.""" + for section in ('header', 'footer'): + f = MARKDOWN_DIR / f"{item_id}-{section}.md" + if not f.is_file(): + continue + text = re.sub(r'', '', f.read_text(), flags=re.DOTALL) + lines = [ln.strip() for ln in text.splitlines() + if ln.strip() and not ln.strip().startswith(('__', '#', '!', '['))] + if not lines: + continue + # first *declarative* sentence (skip a rhetorical "What is X?" lead-in) + for sentence in re.split(r'(?<=[.!?])\s', ' '.join(lines)): + sentence = sentence.strip() + if len(sentence) > 20 and not sentence.endswith('?'): + return sentence[:160].rstrip() + return None + + +def _page_image_path(item): + """Return the site-absolute path of the item's logo, or None.""" + for ext in ('png', 'webp'): + if (IMAGES_DIR / f"{item['id']}.{ext}").is_file(): + return f"/images/{item['id']}.{ext}" + return None + + +def render_software_page(group, category): + """One installable app -> a standalone page keyed by its slug, with SEO + front-matter (title + description + og image) pulled from the JSON entry + that already exists. The body reuses the normal per-software rendering.""" + install = group[0] + short = install.get('short') or install.get('description') or install['id'] + slug = slugify(short) + desc = (install.get('description') or short).strip().rstrip('.') + # drop a redundant leading app name ("Netdata - monitoring..." -> "monitoring...") + desc = re.sub(rf'^{re.escape(short)}\s*[-–:]\s*', '', desc, flags=re.IGNORECASE).strip() + # when the JSON description is just the app name, borrow the header/footer blurb + if not desc or desc.lower() == short.lower(): + desc = _blurb(install['id']) or short + + # Keyword-bearing description: the app name + what it is + the platform. + # People search "install arm64", not the category name. + meta_desc = f"Install and run {short} on Armbian — {desc.rstrip('.')}. Runs on ARM64 and x86 single-board computers." + + fm = ['---', f"title: {yaml_quote(short)}", f"description: {yaml_quote(meta_desc)}"] + img = _page_image_path(install) + if img: + fm.append(f"image: {img}") + # Category id ties the page to its section in the left nav (the docs repo + # groups app pages under their category from this field) and to the hub page. + fm.append(f"category: {yaml_quote(category['id'])}") + fm += ['comments: true', '---', ''] + + body = [f"# {short}\n"] + # Show one description: the fuller header blurb is rendered inside the group; + # only add the short JSON line when there is no header file (avoids the + # "monitoring real-time metrics" + full-paragraph duplication). + has_header = (MARKDOWN_DIR / f"{install['id']}-header.md").is_file() + if not has_header and desc and desc.lower() != short.lower(): + body.append(f"\n{desc}\n") + cat_short = re.sub(r'(?<=[a-z])(?=[A-Z])', ' ', category['id']) + menu_path = f"Software → {cat_short} → {short}" + body.append(render_software_group(group, level=1, with_title=False, menu_path=menu_path)) + + # Simple category back-link (plain text, no heading — so it doesn't add a + # TOC entry). The category's other apps are already in the left nav. + cat_name = category.get('description', category['id']) + body.append(f"\n---\n\n_Part of Armbian's [{cat_name}](/User-Guide_Armbian-Software/{category['id']}/) software._") + return slug, '\n'.join(fm) + '\n'.join(body) + '\n' + + +def render_category_index(category): + """A category page becomes an internal-linking hub: a short intro plus a + list that links out to each app's own page, instead of a wall of anchors.""" + cat_desc = category.get('description', category['id']) + # short label for the nav / ("HomeAutomation" -> "Home Automation"); + # the descriptive sentence stays as the page H1 below. + cat_short = re.sub(r'(?<=[a-z])(?=[A-Z])', ' ', category['id']) + groups = group_software(category.get('sub', [])) + meta_desc = f"{cat_desc} for Armbian on ARM64 and x86 single-board computers: " \ + + ", ".join(g[0]['short'] for g in groups) + "." + fm = ['---', f"title: {yaml_quote(cat_short)}", f"description: {yaml_quote(meta_desc[:180])}", 'comments: true', '---', ''] + md = [f"# {cat_desc}\n"] + md.extend(insert_images_and_header(category)) + md.append("\nInstall and configure these applications through " + "[`armbian-config`](/User-Guide_Armbian-Config/) or from the pages below:\n") + for g in groups: + short = g[0]['short'] + one_liner = (g[0].get('description') or short).strip().rstrip('.') + md.append(f"- [{short}](/software/{slugify(short)}/) — {one_liner}") + return '\n'.join(fm) + '\n'.join(md) + '\n' + + +def _footer_md(item_id): + """The included footer block for a command, or ''.""" + f = MARKDOWN_DIR / f"{item_id}-footer.md" + if not f.is_file(): + return "" + rel = f"tools/include/markdown/{item_id}-footer.md" + return f"\n<!--- footer START from {rel} --->\n{f.read_text()}\n<!--- footer STOP from {rel} --->\n" + + +def _image_md(item): + """Just the logo image (split out so a facts bar can sit under it), or ''.""" + for ext in ('png', 'webp'): + if (IMAGES_DIR / f"{item['id']}.{ext}").is_file(): + rel = f"tools/include/images/{item['id']}.{ext}" + alt = item.get('short', item.get('description', '')) + return (f"\n<!--- section image START from {rel} --->\n" + f"![{alt}](/images/{item['id']}.{ext})\n" + f"<!--- section image STOP from {rel} --->\n") + return "" + + +def _header_blurb_md(item): + """Just the header description block, or ''.""" + f = MARKDOWN_DIR / f"{item['id']}-header.md" + if not f.is_file(): + return "" + rel = f"tools/include/markdown/{item['id']}-header.md" + return f"\n<!--- header START from {rel} --->\n{f.read_text()}\n<!--- header STOP from {rel} --->\n" + + +def render_software_group(sub_items, level=1, with_title=True, menu_path=None): + """Render one app: logo + description, then an action-first layout — the + install command (with an armbian-config menu-path hint) comes first, the + Status/Architecture/Maintainer metadata sits below it, and remove/purge + follow. `with_title=False` skips the H1 (the page adds its own); `menu_path` + (e.g. "Software → Monitoring → Netdata") drives the hint line.""" + lead = sub_items[0] + md = [] + if with_title: + md.append(f"{'#' * level} {lead.get('short', lead.get('description', ''))}\n") + if lead.get('short') and lead.get('description') and lead.get('short') != lead.get('description'): + md.append(f"\n{lead.get('description')}\n") + + md.append(_image_md(lead)) # logo + + # Iconized one-line facts bar, directly under the logo. Only the facts that + # help someone decide/use: hardware it runs on, how it is packaged, where + # the docs are, and how to reach it. Each icon carries a hover title. + meta = [] + module = lead.get('module') + opts = module_options.get(module, {}) + if opts.get('arch'): + meta.append(f':material-cpu-64-bit:{{ title="Architecture" }} {format_arch_labels(opts["arch"])}') + badge = format_container_badge(lead) + if badge: + meta.append(badge) + if opts.get('doc_link'): + meta.append(f':material-book-open-variant:{{ title="Documentation" }} [Documentation]({opts["doc_link"]})') + ports = (opts.get('port') or '').split() + if ports: + scheme = opts.get('protocol', 'http') # http default; https / redis / postgresql / ... + # only the first port — the web / main protocol; extra ports (sync, + # discovery, ...) just clutter the one-line facts bar. + meta.append(f':material-lan-connect:{{ title="Access port" }} ' + f'`{scheme}://<your.IP>:{ports[0]}`') + if meta: + md.append('\n' + ' · '.join(meta) + '\n') + + md.append(_header_blurb_md(lead)) # description + + def api_cmd(item): + # Machine/API form: `armbian-config --api <helper>` runs the helper + # directly (e.g. "module_netdata install") — readable and scriptable, + # unlike the opaque menu id used by `--cmd`. + c = item['command'] + return (c[0] if isinstance(c, list) else c).strip() + + def action_label(item): + # Human label for the commands table. Prefer the item description; for + # the install action (a plain "install") just say "Install"; fall back + # to the command's action word (server/client/qrcode/...). + cmd = api_cmd(item) + arg = cmd.split(None, 1)[1].strip() if ' ' in cmd else '' + if arg == 'install': + return 'Install' + desc = (item.get('description') or '').strip() + short = item.get('short') or '' + if desc and desc.lower() != short.lower(): + return desc + return (arg or short).replace('_', ' ').strip().capitalize() or 'Run' + + cmd_items = [s for s in sub_items if s.get('command')] + + app_short = lead.get('short') or lead.get('description') or lead['id'] + + # install (first command) — with a friendly menu path, then the metadata + if cmd_items: + install = cmd_items[0] + iarg = api_cmd(install).split(None, 1)[1].strip() if ' ' in api_cmd(install) else '' + ititle = "CLI install" if iarg == 'install' else action_label(install) + if menu_path: + md.append(f"\nInstall from **[armbian-config](/User-Guide_Armbian-Config/) → {menu_path}**") + md.append(f"\n~~~ custombash title=\"{ititle}\"\narmbian-config --cmd {install['id']}\n~~~\n") + md.append(_footer_md(install['id'])) + + # The module's full command surface — read from its own `example` list + # (exactly what `armbian-config --api <module> help` prints), not just the + # menu's install/remove/purge subset. Label with the richer menu + # descriptions where we have them; fall back to the subcommand name. + module = lead.get('module') + opts = module_options.get(module, {}) + fn = opts.get('feature') or module + subcmds = opts.get('example', '').split() + menu_label = {} + for s in cmd_items: + parts = api_cmd(s).split(None, 1) + if len(parts) > 1: + menu_label[parts[1].strip()] = action_label(s) + if fn and subcmds: + md.append("\n**All `armbian-config` commands**\n") + md.append("| Action | Command |") + md.append("| --- | --- |") + for sub in subcmds: + label = menu_label.get(sub) or sub.capitalize() + md.append(f"| {label} | `armbian-config --api {fn} {sub}` |") + elif len(cmd_items) > 1: # module has no `example` list — use the menu items + md.append("\n**All `armbian-config` commands**\n") + md.append("| Action | Command |") + md.append("| --- | --- |") + for s in cmd_items: + md.append(f"| {action_label(s)} | `armbian-config --api {api_cmd(s)}` |") + + return '\n'.join(x for x in md if x) + + +# Top-level menu id whose sub-categories are public "software" (SEO) pages. +SOFTWARE_TOP_ID = "Software" + + +def write_software_section(top): + """Emit, for the Software section: a per-app page docs/software/<slug>.md + (SEO front-matter, own URL) for every installable app, plus each category + page rewritten as a link hub. Returns the app page count.""" + cat_dir = DOCS_DIR / top['id'] + cat_dir.mkdir(parents=True, exist_ok=True) + apps_dir = DOCS_DIR / 'software' + apps_dir.mkdir(parents=True, exist_ok=True) + # clear stale app pages so a renamed/removed slug does not linger as an orphan + for old in apps_dir.glob('*.md'): + old.unlink() + + # keep the section overview page as-is (still rsynced/linked) + (cat_dir / f"{top['id']}.md").write_text('---\ncomments: true\n---\n\n' + create_markdown_user(top)) + + count = 0 + for category in top.get('sub', []): + (cat_dir / f"{category['id']}.md").write_text(render_category_index(category)) + for group in group_software(category.get('sub', [])): + slug, page = render_software_page(group, category) + (apps_dir / f"{slug}.md").write_text(page) + count += 1 + return count + + def write_technical_markdown_files(data): DOCS_DIR.mkdir(exist_ok=True) for item in data['menu']: @@ -228,6 +535,13 @@ def write_technical_markdown_files(data): def write_user_markdown_files(data): DOCS_DIR.mkdir(exist_ok=True) for item in data['menu']: + # The Software section is published as per-app pages (own URL + SEO + # front-matter) with category pages as link hubs; everything else keeps + # the original single-page-per-category layout. + if item['id'] == SOFTWARE_TOP_ID: + n = write_software_section(item) + print(f"Software section: {n} per-app pages + {len(item.get('sub', []))} category hubs.") + continue item_dir = DOCS_DIR / item['id'] item_dir.mkdir(exist_ok=True) user_md = create_markdown_user(item) diff --git a/tools/include/images/DOW025.png b/tools/include/images/PRW001.png similarity index 100% rename from tools/include/images/DOW025.png rename to tools/include/images/PRW001.png diff --git a/tools/include/images/DOW001.png b/tools/include/images/QBT001.png similarity index 100% rename from tools/include/images/DOW001.png rename to tools/include/images/QBT001.png diff --git a/tools/include/markdown/ADG001-footer.md b/tools/include/markdown/ADG001-footer.md index 62a273aaf..afc95f71e 100644 --- a/tools/include/markdown/ADG001-footer.md +++ b/tools/include/markdown/ADG001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **3000**: - - - URL: `https://<your.IP>:3000` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/APT001-footer.md b/tools/include/markdown/APT001-footer.md index 7de1686af..0eaf38f44 100644 --- a/tools/include/markdown/APT001-footer.md +++ b/tools/include/markdown/APT001-footer.md @@ -1,10 +1,3 @@ -=== "Access to the service" - - The proxy listens on port **3142**: - - - URL: `http://<your.IP>:3142` - - Hit-rate report: `http://<your.IP>:3142/acng-report.html` - === "Client configuration" On each apt host on the LAN: diff --git a/tools/include/markdown/BAZ001-footer.md b/tools/include/markdown/BAZ001-footer.md index 5dc22e598..8843ed99c 100644 --- a/tools/include/markdown/BAZ001-footer.md +++ b/tools/include/markdown/BAZ001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **6767**: - - - URL: `https://<your.IP>:6767` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/COD001-footer.md b/tools/include/markdown/COD001-footer.md index 07846c7b7..784f902c8 100644 --- a/tools/include/markdown/COD001-footer.md +++ b/tools/include/markdown/COD001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8443**: - - - URL: `https://<your.IP>:8443` - Default Login: No password required by default (see optional variables below) **Note**: Code-server uses HTTPS with a self-signed certificate by default. Your browser may show a security warning - this is normal for self-signed certificates. diff --git a/tools/include/markdown/CPT001-footer.md b/tools/include/markdown/CPT001-footer.md index a4ad14593..ee4b7f734 100644 --- a/tools/include/markdown/CPT001-footer.md +++ b/tools/include/markdown/CPT001-footer.md @@ -1,11 +1,7 @@ === "Access to the web interface" - The web interface is accessible via port **9890**: - - - URL: `https://<your.IP>:9890` - Username/Password: your system login credentials === "Video instructions" - <iframe width="1200" height="676" src="https://www.youtube.com/embed/L9fMWCRcqIE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> diff --git a/tools/include/markdown/DAT005-footer.md b/tools/include/markdown/DAT005-footer.md index 7374532dd..93524cd9d 100644 --- a/tools/include/markdown/DAT005-footer.md +++ b/tools/include/markdown/DAT005-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8071**: - - - URL: `https://<your.IP>:8071` - Server: IP from server you are connecting to. If you have installed MariaDB via this tool, then this is `<your.IP>` - Username: defined at SQL server install (MariaDb) - Password: defined at SQL server install (MariaDb) diff --git a/tools/include/markdown/DEL001-footer.md b/tools/include/markdown/DEL001-footer.md index 9bf3cf70e..7efe2a576 100644 --- a/tools/include/markdown/DEL001-footer.md +++ b/tools/include/markdown/DEL001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8112**: - - - URL: `https://<your.IP>:8112` - Username/Password: default user/password of admin/deluge === "Directories" diff --git a/tools/include/markdown/DOM001-header.md b/tools/include/markdown/DOM001-header.md index 23bb0630b..552015e48 100644 --- a/tools/include/markdown/DOM001-header.md +++ b/tools/include/markdown/DOM001-header.md @@ -2,9 +2,6 @@ Domoticz is an open-source home automation platform that allows you to control a === "Access to the web interface" - The web interface is accessible via port **8780**: - - - URL: `https://<your.IP>:8780` - Username/Password: admin / domoticz === "Directories" diff --git a/tools/include/markdown/DOZ001-footer.md b/tools/include/markdown/DOZ001-footer.md index f32b8760d..721371255 100644 --- a/tools/include/markdown/DOZ001-footer.md +++ b/tools/include/markdown/DOZ001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **8888**: - - - URL: `http://<your.IP>:8888` - === "View logs" View real-time logs from the Dozzle container: @@ -27,4 +21,3 @@ - Ensure the Docker socket is properly mounted - Check that the container has logs available: `docker logs <container_name>` - Verify Dozzle container is running: `docker ps | grep dozzle` - diff --git a/tools/include/markdown/DPL001-footer.md b/tools/include/markdown/DPL001-footer.md index ee5fb7a60..56c8c6857 100644 --- a/tools/include/markdown/DPL001-footer.md +++ b/tools/include/markdown/DPL001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **8200**: - - - URL: `http://<your.IP>:8200` - === "Directories" - Install directory: `/armbian/duplicati` diff --git a/tools/include/markdown/EMB001-footer.md b/tools/include/markdown/EMB001-footer.md index 9cd61c62f..ccdd7f42a 100644 --- a/tools/include/markdown/EMB001-footer.md +++ b/tools/include/markdown/EMB001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **8091**: - - - URL: `https://<your.IP>:8091` - === "Directories" - Install directory: `/armbian/emby` diff --git a/tools/include/markdown/EVCC01-footer.md b/tools/include/markdown/EVCC01-footer.md index 5d3a9595d..f7053ef02 100644 --- a/tools/include/markdown/EVCC01-footer.md +++ b/tools/include/markdown/EVCC01-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **7070**: - - - URL: `https://<your.IP>:7070` - Admin password is generated at first web interface login === "Directories" diff --git a/tools/include/markdown/FIL001-footer.md b/tools/include/markdown/FIL001-footer.md index 887983edb..308985ee5 100644 --- a/tools/include/markdown/FIL001-footer.md +++ b/tools/include/markdown/FIL001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8095**: - - - URL: `http://<your.IP>:8095` - Username/Password: admin / admin === "Directories" diff --git a/tools/include/markdown/GCDN001-footer.md b/tools/include/markdown/GCDN001-footer.md index fb20dc439..4f5735bb2 100644 --- a/tools/include/markdown/GCDN001-footer.md +++ b/tools/include/markdown/GCDN001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the service" - - The proxy listens on port **8000**: - - - URL: `http://<your.IP>:8000` - === "Client configuration" On each git host on the LAN, redirect GitHub through the proxy: diff --git a/tools/include/markdown/GRA001-footer.md b/tools/include/markdown/GRA001-footer.md index 0856de141..7977b243d 100644 --- a/tools/include/markdown/GRA001-footer.md +++ b/tools/include/markdown/GRA001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **3022**: - - - URL: `https://<your.IP>:3022` - === "Directories" - Install directory: `/armbian/grafana` diff --git a/tools/include/markdown/HAB001-footer.md b/tools/include/markdown/HAB001-footer.md index 59b0deab0..d4087ee90 100644 --- a/tools/include/markdown/HAB001-footer.md +++ b/tools/include/markdown/HAB001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **2080**: - - - URL: `https://<your.IP>:2080` - Username/Password: Are set at first web interface login === "Directories" diff --git a/tools/include/markdown/HAS001-footer.md b/tools/include/markdown/HAS001-footer.md index 6330090ae..29cffa1ac 100644 --- a/tools/include/markdown/HAS001-footer.md +++ b/tools/include/markdown/HAS001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8123**: - - - URL: `https://<your.IP>:8123` - Username/Password: Are set at first web interface login === "Directories" diff --git a/tools/include/markdown/HPG001-footer.md b/tools/include/markdown/HPG001-footer.md index 3f5e8de4e..47d92b985 100644 --- a/tools/include/markdown/HPG001-footer.md +++ b/tools/include/markdown/HPG001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **3021**: - - - URL: `https://<your.IP>:3021` - Username/Password: none Configuration: Please reffer to official manual <https://gethomepage.dev/configs/> diff --git a/tools/include/markdown/IMM001-footer.md b/tools/include/markdown/IMM001-footer.md index 6c7bd9118..a3b85ff37 100644 --- a/tools/include/markdown/IMM001-footer.md +++ b/tools/include/markdown/IMM001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the service" - - Immich is accessible via HTTP on port **8077**: - - - URL: `http://<your.IP>:8077` - === "Default credentials" - Email: *(set during initial setup)* diff --git a/tools/include/markdown/JMS001-footer.md b/tools/include/markdown/JMS001-footer.md index 97de46860..3762d8be5 100644 --- a/tools/include/markdown/JMS001-footer.md +++ b/tools/include/markdown/JMS001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8096**: - - - URL: `http://<your.IP>:8096` - Username and password are set at first login === "Directories" diff --git a/tools/include/markdown/LID001-footer.md b/tools/include/markdown/LID001-footer.md index 02d7fbea3..bd3050b77 100644 --- a/tools/include/markdown/LID001-footer.md +++ b/tools/include/markdown/LID001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8686**: - - - URL: `https://<your.IP>:8686` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/MDS001-footer.md b/tools/include/markdown/MDS001-footer.md index 52d78f50a..b18c88924 100644 --- a/tools/include/markdown/MDS001-footer.md +++ b/tools/include/markdown/MDS001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **8081**: - - - URL: `https://<your.IP>:8081` - === "Directories" - Install directory: `/armbian/medusa` diff --git a/tools/include/markdown/NAX001-footer.md b/tools/include/markdown/NAX001-footer.md index b168ce594..2ab6da303 100644 --- a/tools/include/markdown/NAX001-footer.md +++ b/tools/include/markdown/NAX001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **20211**: - - - URL: `https://<your.IP>:20211` - === "Directories" - Config directory: `/armbian/netalertx/config` diff --git a/tools/include/markdown/NBOX01-footer.md b/tools/include/markdown/NBOX01-footer.md index 8a27dcb0b..d60be21cc 100644 --- a/tools/include/markdown/NBOX01-footer.md +++ b/tools/include/markdown/NBOX01-footer.md @@ -1,10 +1,3 @@ -=== "Access to the service" - - NetBox is accessible via HTTP on port **8222**: - - - URL: `http://<your.IP>:8222` - - API root: `http://<your.IP>:8222/api/` - === "Default credentials" - Username: `admin` diff --git a/tools/include/markdown/NCT001-footer.md b/tools/include/markdown/NCT001-footer.md index ed02356fb..5d5b8efea 100644 --- a/tools/include/markdown/NCT001-footer.md +++ b/tools/include/markdown/NCT001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **1443**: - - - URL: `https://<your.IP>:1443` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/OCT001-footer.md b/tools/include/markdown/OCT001-footer.md index c05654e6e..9dd1dfdaa 100644 --- a/tools/include/markdown/OCT001-footer.md +++ b/tools/include/markdown/OCT001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **7981**: - - - URL: `https://<your.IP>:7981` - === "Directories" - Install directory: `/armbian/octoprint` diff --git a/tools/include/markdown/OMV001-footer.md b/tools/include/markdown/OMV001-footer.md index b89de954d..5a1abf0c4 100644 --- a/tools/include/markdown/OMV001-footer.md +++ b/tools/include/markdown/OMV001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The OpenMediaVault web interface is accessible via the default HTTP port: - - - URL: `http://<your.IP>:80` - Username/Password: admin / openmediavault (change after first login) === "Directories" diff --git a/tools/include/markdown/OWC001-footer.md b/tools/include/markdown/OWC001-footer.md index 4e833bb5a..51fdc0bb6 100644 --- a/tools/include/markdown/OWC001-footer.md +++ b/tools/include/markdown/OWC001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **7787**: - - - URL: `http://<your.IP>:7787` - Username/Password: admin / admin === "Directories" diff --git a/tools/include/markdown/PGSQL1-footer.md b/tools/include/markdown/PGSQL1-footer.md index 59ca89c14..389b41122 100644 --- a/tools/include/markdown/PGSQL1-footer.md +++ b/tools/include/markdown/PGSQL1-footer.md @@ -1,8 +1,5 @@ === "Access to the database" - PostgreSQL is accessible via port **5432**: - - - Host: `postgresql://<your.IP>:5432` - Default user: `armbian` - Default password: `armbian` - Default database: `armbian` diff --git a/tools/include/markdown/PIH001-footer.md b/tools/include/markdown/PIH001-footer.md index 308b116c5..202a20af2 100644 --- a/tools/include/markdown/PIH001-footer.md +++ b/tools/include/markdown/PIH001-footer.md @@ -1,6 +1,3 @@ === "Access the web interface" - The web interface of Pi-hole can be accessed via: - - - URL = `http://<your.IP>:8811/admin` - - Password is set on install and can be adjusted from `armbian-config` \ No newline at end of file + - Password is set on install and can be adjusted from `armbian-config` diff --git a/tools/include/markdown/POR001-footer.md b/tools/include/markdown/POR001-footer.md index ad366313f..8b1378917 100644 --- a/tools/include/markdown/POR001-footer.md +++ b/tools/include/markdown/POR001-footer.md @@ -1,5 +1 @@ -=== "Access to the web interface" - The web interface is accessible via port **9002**: - - - URL = `http://<your.IP>:9002` diff --git a/tools/include/markdown/PRO001-footer.md b/tools/include/markdown/PRO001-footer.md index a98ea519d..48e5b9339 100644 --- a/tools/include/markdown/PRO001-footer.md +++ b/tools/include/markdown/PRO001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **9191**: - - - URL: `http://<your.IP>:9191` - === "Directories" - Config directory: `/armbian/prometheus` diff --git a/tools/include/markdown/DOW025-footer.md b/tools/include/markdown/PRW001-footer.md similarity index 76% rename from tools/include/markdown/DOW025-footer.md rename to tools/include/markdown/PRW001-footer.md index 816a9c6e2..d0ce59450 100644 --- a/tools/include/markdown/DOW025-footer.md +++ b/tools/include/markdown/PRW001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **9696**: - - - URL: `https://<your.IP>:9696` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/DOW025-header.md b/tools/include/markdown/PRW001-header.md similarity index 100% rename from tools/include/markdown/DOW025-header.md rename to tools/include/markdown/PRW001-header.md diff --git a/tools/include/markdown/PVE001-footer.md b/tools/include/markdown/PVE001-footer.md index 69df91074..8c90c41b4 100644 --- a/tools/include/markdown/PVE001-footer.md +++ b/tools/include/markdown/PVE001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8006**: - - - URL: `https://<your.IP>:8006` - Username: `root` (your system root password) Official documentation: <https://pve.proxmox.com/pve-docs/> diff --git a/tools/include/markdown/DOW001-footer.md b/tools/include/markdown/QBT001-footer.md similarity index 79% rename from tools/include/markdown/DOW001-footer.md rename to tools/include/markdown/QBT001-footer.md index 626e6c8a5..61f9e6c7d 100644 --- a/tools/include/markdown/DOW001-footer.md +++ b/tools/include/markdown/QBT001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8090**: - - - URL: `https://<your.IP>:8090` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/DOW001-header.md b/tools/include/markdown/QBT001-header.md similarity index 100% rename from tools/include/markdown/DOW001-header.md rename to tools/include/markdown/QBT001-header.md diff --git a/tools/include/markdown/RAD001-footer.md b/tools/include/markdown/RAD001-footer.md index ac3a76b95..c3fb38f6d 100644 --- a/tools/include/markdown/RAD001-footer.md +++ b/tools/include/markdown/RAD001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **7878**: - - - URL: `https://<your.IP>:7878` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/REDIS1-footer.md b/tools/include/markdown/REDIS1-footer.md index dae7a1ab4..697022dc5 100644 --- a/tools/include/markdown/REDIS1-footer.md +++ b/tools/include/markdown/REDIS1-footer.md @@ -1,9 +1,3 @@ -=== "Access to the service" - - Redis server is accessible on port **6379**: - - - Host: `redis://<your.IP>:6379` - === "Directories" - Data directory: `/armbian/redis/data` diff --git a/tools/include/markdown/SABN01-footer.md b/tools/include/markdown/SABN01-footer.md index fa6b4f514..e38bd515e 100644 --- a/tools/include/markdown/SABN01-footer.md +++ b/tools/include/markdown/SABN01-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8380**: - - - URL: `https://<your.IP>:8380` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/SON001-footer.md b/tools/include/markdown/SON001-footer.md index 5bebc6eac..b27aea560 100644 --- a/tools/include/markdown/SON001-footer.md +++ b/tools/include/markdown/SON001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **8989**: - - - URL: `https://<your.IP>:8989` - === "Directories" - Install directory: `/armbian/sonarr` diff --git a/tools/include/markdown/STC001-footer.md b/tools/include/markdown/STC001-footer.md index 6a67c9f4f..982315373 100644 --- a/tools/include/markdown/STC001-footer.md +++ b/tools/include/markdown/STC001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **8884**: - - - URL: `https://<your.IP>:8884` - Username/Password: There is none, but it is highly suggested setting a password for this container. To do this go to Actions -> Settings -> set user/password for the webUI. === "Directories" diff --git a/tools/include/markdown/STR001-footer.md b/tools/include/markdown/STR001-footer.md index bb59e3b8e..fa94f0ba5 100644 --- a/tools/include/markdown/STR001-footer.md +++ b/tools/include/markdown/STR001-footer.md @@ -1,9 +1,3 @@ -=== "Access to the web interface" - - The web interface is accessible via port **8075**: - - - URL: `https://<your.IP>:8075` - === "Directories" - Install directory: `/armbian/stirling` diff --git a/tools/include/markdown/TRA001-footer.md b/tools/include/markdown/TRA001-footer.md index 99c69c773..a49c78bfe 100644 --- a/tools/include/markdown/TRA001-footer.md +++ b/tools/include/markdown/TRA001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **9091**: - - - URL: `https://<your.IP>:9091` - Username/Password: admin / generate at first web interface login === "Directories" diff --git a/tools/include/markdown/UPK001-footer.md b/tools/include/markdown/UPK001-footer.md index d39199334..401d820ce 100644 --- a/tools/include/markdown/UPK001-footer.md +++ b/tools/include/markdown/UPK001-footer.md @@ -1,8 +1,5 @@ === "Access to the web interface" - The web interface is accessible via port **3001**: - - - URL: `https://<your.IP>:3001` - Username/Password: Are set at first web interface login === "Features" diff --git a/tools/include/markdown/WBM001-footer.md b/tools/include/markdown/WBM001-footer.md index 34e72a228..c563558de 100644 --- a/tools/include/markdown/WBM001-footer.md +++ b/tools/include/markdown/WBM001-footer.md @@ -1,7 +1,3 @@ === "Access to the web interface" - The web interface is accessible via port **10000**: - - - URL: `https://<your.IP>:10000` - Username/Password: your system login credentials - diff --git a/tools/include/markdown/WRG001-footer.md b/tools/include/markdown/WRG001-footer.md index 924f46152..83459b9db 100644 --- a/tools/include/markdown/WRG001-footer.md +++ b/tools/include/markdown/WRG001-footer.md @@ -1,6 +1,6 @@ === "Server" - 1. Launch `armbian-config --cmd WRG001`. + 1. Launch `armbian-config --api module_wireguard server`. 2. When prompted, enter a comma-separated list of peer names (e.g., laptop,phone,router). @@ -15,7 +15,7 @@ === "Client" - 1. Launch `armbian-config --cmd WRG002`. + 1. Launch `armbian-config --api module_wireguard client`. 2. You will be asked to edit or paste a valid WireGuard configuration. diff --git a/tools/json/config.software.json b/tools/json/config.software.json index 12add56e0..aaf64a788 100644 --- a/tools/json/config.software.json +++ b/tools/json/config.software.json @@ -552,26 +552,27 @@ "id": "GIT001", "description": "Install tools for cloning and managing repositories (git)", "short": "Git CLI", - "module": "module_generic", + "module": "module_git-cli", + "prompt": "This operation will install git.", "command": [ - "get_user_continue \"This operation will install git.\n\nDo you wish to continue?\" process_input", - "pkg_install git" + "module_git-cli install" ], "status": "Stable", "author": "@armbian", - "condition": "! pkg_installed git", + "condition": "! module_git-cli status", "help": "Command-line tool for version control and source code management" }, { "id": "GIT002", "description": "Remove tools for cloning and managing repositories (git)", + "module": "module_git-cli", + "prompt": "This operation will remove git.", "command": [ - "get_user_continue \"This operation will remove git.\n\nDo you wish to continue?\" process_input", - "pkg_remove git" + "module_git-cli remove" ], "status": "Stable", "author": "@armbian", - "condition": "pkg_installed git", + "condition": "module_git-cli status", "help": "Remove tools for cloning and managing repositories (git)" }, { @@ -699,7 +700,7 @@ "help": "Deluge purge with data folder" }, { - "id": "DOW001", + "id": "QBT001", "description": "qBittorrent BitTorrent client ", "short": "qBittorrent", "module": "module_qbittorrent", @@ -714,7 +715,7 @@ "help": "The Qbittorrent⁠ project aims to provide an open-source software alternative to µTorrent." }, { - "id": "DOW002", + "id": "QBT002", "description": "qBittorrent remove", "about": "This operation will remove qBittorrent BitTorrent client", "command": [ @@ -726,7 +727,7 @@ "help": "qBittorrent remove" }, { - "id": "DOW003", + "id": "QBT003", "description": "qBittorrent purge with data folder", "about": "This operation will remove qBittorrent BitTorrent data folder", "command": [ @@ -738,7 +739,7 @@ "help": "qBittorrent purge with data folder" }, { - "id": "DOW025", + "id": "PRW001", "description": "Prowlarr index manager and proxy for PVR", "short": "Prowlarr", "module": "module_prowlarr", @@ -753,7 +754,7 @@ "help": "Prowlarr is a indexer manager/proxy built on the popular arr." }, { - "id": "DOW026", + "id": "PRW002", "description": "Prowlarr remove", "about": "This operation will remove Prowlarr", "command": [ @@ -765,7 +766,7 @@ "help": "Prowlarr remove" }, { - "id": "DOW027", + "id": "PRW003", "description": "Prowlarr purge with data folder", "about": "This operation will purge Prowlarr with data folder", "command": [ diff --git a/tools/modules/runtime/config.runtime.sh b/tools/modules/runtime/config.runtime.sh index 90bd79e8b..cc7b0273b 100644 --- a/tools/modules/runtime/config.runtime.sh +++ b/tools/modules/runtime/config.runtime.sh @@ -159,7 +159,7 @@ update_sub_submenu_data "Software" "Management" "NBOX02" "http://$LOCALIPADD:${m update_sub_submenu_data "Software" "Management" "APT002" "http://$LOCALIPADD:${module_options["module_aptcacherng,port"]}/acng-report.html" # Downloaders -update_sub_submenu_data "Software" "Downloaders" "DOW002" "http://$LOCALIPADD:${module_options["module_qbittorrent,port"]%% *}" # removing second port from url +update_sub_submenu_data "Software" "Downloaders" "QBT002" "http://$LOCALIPADD:${module_options["module_qbittorrent,port"]%% *}" # removing second port from url update_sub_submenu_data "Software" "Downloaders" "DEL002" "http://$LOCALIPADD:${module_options["module_deluge,port"]%% *}" # removing second port from url update_sub_submenu_data "Software" "Downloaders" "TRA002" "http://$LOCALIPADD:${module_options["module_transmission,port"]%% *}" # removing second port from url update_sub_submenu_data "Software" "Downloaders" "SABN02" "http://$LOCALIPADD:${module_options["module_sabnzbd,port"]}" @@ -169,7 +169,7 @@ update_sub_submenu_data "Software" "Downloaders" "RAD002" "http://$LOCALIPADD:${ update_sub_submenu_data "Software" "Downloaders" "BAZ002" "http://$LOCALIPADD:${module_options["module_bazarr,port"]}" update_sub_submenu_data "Software" "Downloaders" "LID002" "http://$LOCALIPADD:${module_options["module_lidarr,port"]}" update_sub_submenu_data "Software" "Downloaders" "RDR002" "http://$LOCALIPADD:${module_options["module_readarr,port"]}" -update_sub_submenu_data "Software" "Downloaders" "DOW026" "http://$LOCALIPADD:${module_options["module_prowlarr,port"]}" +update_sub_submenu_data "Software" "Downloaders" "PRW002" "http://$LOCALIPADD:${module_options["module_prowlarr,port"]}" update_sub_submenu_data "Software" "Downloaders" "JEL002" "http://$LOCALIPADD:${module_options["module_jellyseerr,port"]}" # web diff --git a/tools/modules/software/module_cockpit.sh b/tools/modules/software/module_cockpit.sh index b2fc59ffb..417c3112b 100644 --- a/tools/modules/software/module_cockpit.sh +++ b/tools/modules/software/module_cockpit.sh @@ -8,6 +8,7 @@ module_options+=( ["module_cockpit,doc_link"]="https://cockpit-project.org/guide/latest/" ["module_cockpit,group"]="Management" ["module_cockpit,port"]="9890" + ["module_cockpit,protocol"]="https" ["module_cockpit,arch"]="x86-64 arm64 armhf" ) diff --git a/tools/modules/software/module_git-cli.sh b/tools/modules/software/module_git-cli.sh new file mode 100644 index 000000000..4fd5c1cbb --- /dev/null +++ b/tools/modules/software/module_git-cli.sh @@ -0,0 +1,58 @@ +module_options+=( + ["module_git-cli,author"]="@armbian" + ["module_git-cli,maintainer"]="@igorpecovnik" + ["module_git-cli,feature"]="module_git-cli" + ["module_git-cli,example"]="install remove status help" + ["module_git-cli,desc"]="Install git command-line tools" + ["module_git-cli,status"]="Stable" + ["module_git-cli,doc_link"]="https://git-scm.com/doc" + ["module_git-cli,group"]="DevTools" + ["module_git-cli,arch"]="x86-64 arm64 armhf riscv64" +) +# +# Module Git CLI +# +# Installs the git command-line tools (distributed version control) from the +# distribution repositories. Native package - no container. +# +function module_git-cli() { + local title="git" + + local commands + IFS=' ' read -r -a commands <<< "${module_options["module_git-cli,example"]}" + + case "$1" in + + "${commands[0]}") # install + pkg_update + pkg_install git + ;; + + "${commands[1]}") # remove + pkg_remove git + ;; + + "${commands[2]}") # status + if pkg_installed git; then + return 0 + else + return 1 + fi + ;; + + "${commands[3]}") # help + echo -e "\nUsage: ${module_options["module_git-cli,feature"]} <command>" + echo -e "Commands: ${module_options["module_git-cli,example"]}" + echo "Available commands:" + echo -e "\tinstall\t- Install $title." + echo -e "\tremove\t- Remove $title." + echo -e "\tstatus\t- Status $title." + echo + ;; + + *) + ${module_options["module_git-cli,feature"]} ${commands[3]} + ;; + + esac +} diff --git a/tools/modules/software/module_mariadb.sh b/tools/modules/software/module_mariadb.sh index 491f81200..bae4643ca 100644 --- a/tools/modules/software/module_mariadb.sh +++ b/tools/modules/software/module_mariadb.sh @@ -8,6 +8,7 @@ module_options+=( ["module_mariadb,doc_link"]="https://mariadb.org/documentation/" ["module_mariadb,group"]="Database" ["module_mariadb,port"]="3307" + ["module_mariadb,protocol"]="mariadb" ["module_mariadb,arch"]="x86-64 arm64" ["module_mariadb,dockerimage"]="lscr.io/linuxserver/mariadb:latest" ["module_mariadb,dockername"]="mariadb" diff --git a/tools/modules/software/module_mysql.sh b/tools/modules/software/module_mysql.sh index 91bb7f4d8..447e9296c 100644 --- a/tools/modules/software/module_mysql.sh +++ b/tools/modules/software/module_mysql.sh @@ -8,6 +8,7 @@ module_options+=( ["module_mysql,doc_link"]="https://hub.docker.com/_/mysql" ["module_mysql,group"]="Database" ["module_mysql,port"]="3306" + ["module_mysql,protocol"]="mysql" ["module_mysql,arch"]="x86-64 arm64" ["module_mysql,dockerimage"]="mysql:lts" ["module_mysql,dockername"]="mysql" diff --git a/tools/modules/software/module_postgres.sh b/tools/modules/software/module_postgres.sh index 33213c365..36404c00e 100644 --- a/tools/modules/software/module_postgres.sh +++ b/tools/modules/software/module_postgres.sh @@ -8,6 +8,7 @@ module_options+=( ["module_postgres,doc_link"]="https://www.postgresql.org/docs/" ["module_postgres,group"]="Database" ["module_postgres,port"]="5432" + ["module_postgres,protocol"]="postgresql" ["module_postgres,arch"]="x86-64 arm64" ["module_postgres,dockerimage"]="tensorchord/pgvecto-rs:pg14-v0.2.0" ["module_postgres,dockername"]="postgres" diff --git a/tools/modules/software/module_redis.sh b/tools/modules/software/module_redis.sh index fda79c465..e697d506a 100644 --- a/tools/modules/software/module_redis.sh +++ b/tools/modules/software/module_redis.sh @@ -8,6 +8,7 @@ module_options+=( ["module_redis,doc_link"]="https://redis.io/docs/" ["module_redis,group"]="Database" ["module_redis,port"]="6379" + ["module_redis,protocol"]="redis" ["module_redis,arch"]="x86-64 arm64" ["module_redis,dockerimage"]="redis:alpine" ["module_redis,dockername"]="redis" diff --git a/tools/modules/software/module_samba.sh b/tools/modules/software/module_samba.sh index c2f691c91..3a8a4336d 100644 --- a/tools/modules/software/module_samba.sh +++ b/tools/modules/software/module_samba.sh @@ -8,6 +8,7 @@ module_options+=( ["module_samba,doc_link"]="https://www.samba.org/samba/docs/" ["module_samba,group"]="Networking" ["module_samba,port"]="445" + ["module_samba,protocol"]="smb" ["module_samba,arch"]="x86-64 arm64 armhf" )