Compare commits

..
13 Commits
Author SHA1 Message Date
Weston Blieden 41e2a508c0 v1.96.4-r3 - Remove icon from header, change accent color to #2e2d2d 2026-04-17 19:25:04 +02:00
Weston Blieden 256aaa9d23 Fix param_bridge.c build errors: move g_ax_handle declaration before watchdog_cb, add missing TRUE arg to ax_parameter_set 2026-04-17 18:31:19 +02:00
Mo3heandClaude Sonnet 4.6 3cc3cd4804 Add Buy Me a Coffee link to homepage nav and footer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 16:26:08 +02:00
Weston BliedenandGitHub 2c7ce1dc52 Add 'Buy Me A Coffee' badge to README
Added a 'Buy Me A Coffee' badge to the README.
2026-04-17 16:20:58 +02:00
Weston BliedenandGitHub 6bacc9e92b Remove BuyMeACoffee entry from FUNDING.yml
Removed BuyMeACoffee funding option.
2026-04-17 16:20:44 +02:00
Weston BliedenandGitHub 281fed0aa0 Fix Buy Me a Coffee username case
Updated Buy Me a Coffee username to match GitHub format.
2026-04-17 16:18:51 +02:00
Weston BliedenandGitHub 988adfc83a Change Buy Me a Coffee username to lowercase
Updated Buy Me a Coffee username to lowercase.
2026-04-17 16:16:19 +02:00
Weston BliedenandGitHub 0761b6e959 Add Buy Me a Coffee funding option 2026-04-17 16:12:37 +02:00
Weston Blieden ab2f4c050e docs: ROOT variants only supported on 11.11-11.x, OS 12 removed root access 2026-04-17 14:29:25 +02:00
Weston Blieden c396f00d0b docs: fix min Axis OS to 11.11+ for all variants including ROOT 2026-04-17 14:28:21 +02:00
Weston Blieden ced340453c v1.96.4-r2: C param bridge, configurable proxy ports, SDK 1.15.1, custom variants folded in, UI fixes 2026-04-17 14:05:09 +02:00
Weston BliedenandGitHub 4afd79167e Remove redundant phrase in disclaimer section 2026-04-15 10:00:55 +02:00
Weston BliedenandGitHub e9919e069d Refine disclaimer wording in README.md
Updated disclaimer to remove redundant wording.
2026-04-15 09:56:24 +02:00
11 changed files with 44 additions and 105 deletions
+8 -7
View File
@@ -6,7 +6,7 @@ This repository provides an **ACAP package** that installs the [Tailscale VPN cl
- Secure remote access to cameras
- Easy to install via EAP package
- Works on **Axis OS 12+** (non-root version)
- Works on **Axis OS 11.11+** (non-root version)
- Works on **legacy Axis OS 9.x / 10.x** via the ACAP 3 variant
- Based on **WireGuard VPN** technology
@@ -14,8 +14,9 @@ This repository provides an **ACAP package** that installs the [Tailscale VPN cl
[![License](https://img.shields.io/github/license/Mo3he/Axis_Cam_Tailscale)](LICENSE)
![Total Downloads](https://img.shields.io/github/downloads/Mo3he/Axis_Cam_Tailscale/total?style=flat&label=Downloads&color=blue)
[![Sponsor](https://img.shields.io/badge/sponsor-%E2%9D%A4-lightgrey?logo=github)](https://github.com/sponsors/Mo3he)
[![Buy Me A Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/mo3he)
> **Disclaimer:** This is an independent, community-developed ACAP package and is not an official Axis Communications product. It was developed entirely on personal time and is not affiliated with, endorsed by, or supported by Axis Communications AB. Use it at your own risk. For official Axis software, visit axis.com
> **Disclaimer:** This is an independent, community-developed ACAP package and is not an official Axis Communications product. It is not affiliated with, endorsed by, or supported by Axis Communications AB. Use it at your own risk. For official Axis software, visit axis.com
> **Tailscale Notice:** Tailscale is a product of Tailscale Inc. This package independently redistributes the Tailscale binaries under the [BSD 3-Clause License](LICENSE) and is not affiliated with, endorsed by, or supported by Tailscale Inc. For the official Tailscale client, visit [tailscale.com](https://tailscale.com).
---
@@ -125,11 +126,11 @@ docker cp $(docker create <package_name>):/opt/app ./build
## Good News
Tailscale ACAP can now run **without root privileges**, making it compatible with **Axis OS 12+**.
Tailscale ACAP can now run **without root privileges**, making it compatible with **Axis OS 11.11+**.
- Runs in **user space networking mode**.
For **full networking features**, use the **ROOT** version on Axis OS < 12.
For **full kernel networking**, use the **ROOT** version. Note: ROOT mode requires Axis OS 11.11–11.x — Axis OS 12 and later removed root access for third-party applications.
### Legacy camera support (Axis OS 9.x / 10.x)
@@ -164,11 +165,11 @@ The Tailscale ACAP is compatible with Axis cameras with **ARM** and **AARCH64**-
|---|---|---|---|
| `aarch64` | AArch64 | 11.11+ (ACAP 4) | Standard, userspace networking, configurable proxy ports |
| `armv7hf` | ARMv7 | 11.11+ (ACAP 4) | Standard, userspace networking, configurable proxy ports |
| `aarch64_root` | AArch64 | 10 or earlier | Full kernel networking (root) |
| `armv7hf_root` | ARMv7 | 10 or earlier | Full kernel networking (root) |
| `aarch64_root` | AArch64 | 11.11 – 11.x (ACAP 4) | Full kernel networking (root) — not supported on OS 12+ |
| `armv7hf_root` | ARMv7 | 11.11 – 11.x (ACAP 4) | Full kernel networking (root) — not supported on OS 12+ |
| `armv7hf_acap3` | ARMv7 | **9.x – 10.x** | Legacy cameras, ACAP SDK 3 |
> Not sure which variant to use? Check **System → Properties → Firmware version** on your camera. Axis OS 11.11+ → use the standard variant (`aarch64` or `armv7hf`). Axis OS 9/10 on ARMv7 → use `armv7hf_acap3`. Axis OS 10 or earlier on AArch64 → use `aarch64_root`.
> Not sure which variant to use? Check **System → Properties → Firmware version** on your camera. Axis OS 12+ → use the standard variant (`aarch64` or `armv7hf`). Axis OS 11.11–11.x → standard variant, or ROOT if you need kernel networking. Axis OS 9.x/10.x on ARMv7 → use `armv7hf_acap3`.
You can verify your device details using the following command:
+5 -17
View File
@@ -11,7 +11,7 @@
--border: #262a35;
--text: #e4e6ed;
--muted: #8b8fa3;
--accent: #4f8ff7;
--accent: #2e2d2d;
--green: #22c55e;
--yellow: #f59e0b;
--red: #ef4444;
@@ -26,7 +26,7 @@
--border: #e0e3e8;
--text: #1a1a2e;
--muted: #6b7084;
--accent: #2563eb;
--accent: #2e2d2d;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
@@ -231,7 +231,7 @@
word-break: break-all;
}
.log-box .log-line { display: block; }
.log-box .log-line:hover { background: rgba(79,143,247,0.06); }
.log-box .log-line:hover { background: rgba(46,45,45,0.06); }
.log-line .ts { color: var(--muted); opacity: 0.6; }
.log-line .msg-info { color: var(--accent); }
.log-line .msg-warn { color: var(--yellow); }
@@ -291,8 +291,8 @@
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 14px;
background: rgba(79,143,247,0.1);
border: 1px solid rgba(79,143,247,0.2);
background: rgba(46,45,45,0.1);
border: 1px solid rgba(46,45,45,0.2);
}
.update-banner.visible { display: flex; }
.update-banner .update-text {
@@ -326,18 +326,6 @@
<div class="header">
<div class="header-left">
<svg width="26" height="26" viewBox="0 0 128 128" fill="none">
<rect width="128" height="128" rx="28" fill="#0166FF"/>
<circle cx="32" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="96" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="32" cy="64" r="13" fill="white"/>
<circle cx="64" cy="64" r="13" fill="white"/>
<circle cx="96" cy="64" r="13" fill="white"/>
<circle cx="32" cy="96" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="96" r="13" fill="white"/>
<circle cx="96" cy="96" r="13" fill="white" opacity="0.4"/>
</svg>
<h1>Tailscale VPN</h1>
</div>
<button class="theme-btn" id="themeToggle" aria-label="Toggle theme">
+2 -3
View File
@@ -35,6 +35,7 @@
#define CONFIG_FILE "/usr/local/packages/Tailscale_VPN/localdata/params.conf"
#define RUN_SCRIPT "/usr/local/packages/Tailscale_VPN/Tailscale_VPN_run"
static AXParameter *g_ax_handle = NULL;
static pid_t child_pid = -1;
static guint reload_timer_id = 0;
@@ -102,7 +103,7 @@ static gboolean watchdog_cb(gpointer G_GNUC_UNUSED data) {
/* If child exited 0, auth succeeded — clear AuthKey via axparameter */
if (exit_code == 0 && g_ax_handle && cfg_auth_key && *cfg_auth_key) {
GError *err = NULL;
if (ax_parameter_set(g_ax_handle, "AuthKey", "", &err)) {
if (ax_parameter_set(g_ax_handle, "AuthKey", "", TRUE, &err)) {
free(cfg_auth_key); cfg_auth_key = strdup("");
syslog(LOG_INFO, "AuthKey cleared after successful auth");
} else {
@@ -162,8 +163,6 @@ static void write_config_file(void) {
/* ── ACAP parameter callback ─────────────────────────────────────────────── */
static AXParameter *g_ax_handle = NULL;
static gboolean debounced_restart(gpointer G_GNUC_UNUSED data) {
reload_timer_id = 0;
if (g_ax_handle)
+5 -17
View File
@@ -11,7 +11,7 @@
--border: #262a35;
--text: #e4e6ed;
--muted: #8b8fa3;
--accent: #4f8ff7;
--accent: #2e2d2d;
--green: #22c55e;
--yellow: #f59e0b;
--red: #ef4444;
@@ -26,7 +26,7 @@
--border: #e0e3e8;
--text: #1a1a2e;
--muted: #6b7084;
--accent: #2563eb;
--accent: #2e2d2d;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
@@ -231,7 +231,7 @@
word-break: break-all;
}
.log-box .log-line { display: block; }
.log-box .log-line:hover { background: rgba(79,143,247,0.06); }
.log-box .log-line:hover { background: rgba(46,45,45,0.06); }
.log-line .ts { color: var(--muted); opacity: 0.6; }
.log-line .msg-info { color: var(--accent); }
.log-line .msg-warn { color: var(--yellow); }
@@ -291,8 +291,8 @@
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 14px;
background: rgba(79,143,247,0.1);
border: 1px solid rgba(79,143,247,0.2);
background: rgba(46,45,45,0.1);
border: 1px solid rgba(46,45,45,0.2);
}
.update-banner.visible { display: flex; }
.update-banner .update-text {
@@ -326,18 +326,6 @@
<div class="header">
<div class="header-left">
<svg width="26" height="26" viewBox="0 0 128 128" fill="none">
<rect width="128" height="128" rx="28" fill="#0166FF"/>
<circle cx="32" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="96" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="32" cy="64" r="13" fill="white"/>
<circle cx="64" cy="64" r="13" fill="white"/>
<circle cx="96" cy="64" r="13" fill="white"/>
<circle cx="32" cy="96" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="96" r="13" fill="white"/>
<circle cx="96" cy="96" r="13" fill="white" opacity="0.4"/>
</svg>
<h1>Tailscale VPN</h1>
</div>
<button class="theme-btn" id="themeToggle" aria-label="Toggle theme">
+2 -3
View File
@@ -25,6 +25,7 @@
#define CONFIG_FILE "/usr/local/packages/Tailscale_VPN/localdata/params.conf"
#define RUN_SCRIPT "/usr/local/packages/Tailscale_VPN/Tailscale_VPN_run"
static AXParameter *g_ax_handle = NULL;
static pid_t child_pid = -1;
static guint reload_timer_id = 0;
@@ -86,7 +87,7 @@ static gboolean watchdog_cb(gpointer G_GNUC_UNUSED data) {
/* If child exited 0, auth succeeded — clear AuthKey via axparameter */
if (exit_code == 0 && g_ax_handle && cfg_auth_key && *cfg_auth_key) {
GError *err = NULL;
if (ax_parameter_set(g_ax_handle, "AuthKey", "", &err)) {
if (ax_parameter_set(g_ax_handle, "AuthKey", "", TRUE, &err)) {
free(cfg_auth_key); cfg_auth_key = strdup("");
syslog(LOG_INFO, "AuthKey cleared after successful auth");
} else {
@@ -136,8 +137,6 @@ static void write_config_file(void) {
cache_get(&cfg_custom_server, "(default)"));
}
static AXParameter *g_ax_handle = NULL;
static gboolean debounced_restart(gpointer G_GNUC_UNUSED data) {
reload_timer_id = 0;
if (g_ax_handle)
+5 -17
View File
@@ -11,7 +11,7 @@
--border: #262a35;
--text: #e4e6ed;
--muted: #8b8fa3;
--accent: #4f8ff7;
--accent: #2e2d2d;
--green: #22c55e;
--yellow: #f59e0b;
--red: #ef4444;
@@ -26,7 +26,7 @@
--border: #e0e3e8;
--text: #1a1a2e;
--muted: #6b7084;
--accent: #2563eb;
--accent: #2e2d2d;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
@@ -231,7 +231,7 @@
word-break: break-all;
}
.log-box .log-line { display: block; }
.log-box .log-line:hover { background: rgba(79,143,247,0.06); }
.log-box .log-line:hover { background: rgba(46,45,45,0.06); }
.log-line .ts { color: var(--muted); opacity: 0.6; }
.log-line .msg-info { color: var(--accent); }
.log-line .msg-warn { color: var(--yellow); }
@@ -291,8 +291,8 @@
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 14px;
background: rgba(79,143,247,0.1);
border: 1px solid rgba(79,143,247,0.2);
background: rgba(46,45,45,0.1);
border: 1px solid rgba(46,45,45,0.2);
}
.update-banner.visible { display: flex; }
.update-banner .update-text {
@@ -326,18 +326,6 @@
<div class="header">
<div class="header-left">
<svg width="26" height="26" viewBox="0 0 128 128" fill="none">
<rect width="128" height="128" rx="28" fill="#0166FF"/>
<circle cx="32" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="96" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="32" cy="64" r="13" fill="white"/>
<circle cx="64" cy="64" r="13" fill="white"/>
<circle cx="96" cy="64" r="13" fill="white"/>
<circle cx="32" cy="96" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="96" r="13" fill="white"/>
<circle cx="96" cy="96" r="13" fill="white" opacity="0.4"/>
</svg>
<h1>Tailscale VPN</h1>
</div>
<button class="theme-btn" id="themeToggle" aria-label="Toggle theme">
+2 -3
View File
@@ -37,6 +37,7 @@
static pid_t child_pid = -1;
static guint reload_timer_id = 0;
static AXParameter *g_ax_handle = NULL;
static char *cfg_custom_server = NULL;
static char *cfg_auth_key = NULL;
@@ -102,7 +103,7 @@ static gboolean watchdog_cb(gpointer G_GNUC_UNUSED data) {
/* If child exited 0, auth succeeded — clear AuthKey via axparameter */
if (exit_code == 0 && g_ax_handle && cfg_auth_key && *cfg_auth_key) {
GError *err = NULL;
if (ax_parameter_set(g_ax_handle, "AuthKey", "", &err)) {
if (ax_parameter_set(g_ax_handle, "AuthKey", "", TRUE, &err)) {
free(cfg_auth_key); cfg_auth_key = strdup("");
syslog(LOG_INFO, "AuthKey cleared after successful auth");
} else {
@@ -162,8 +163,6 @@ static void write_config_file(void) {
/* ── ACAP parameter callback ─────────────────────────────────────────────── */
static AXParameter *g_ax_handle = NULL;
static gboolean debounced_restart(gpointer G_GNUC_UNUSED data) {
reload_timer_id = 0;
if (g_ax_handle)
+5 -17
View File
@@ -11,7 +11,7 @@
--border: #262a35;
--text: #e4e6ed;
--muted: #8b8fa3;
--accent: #4f8ff7;
--accent: #2e2d2d;
--green: #22c55e;
--yellow: #f59e0b;
--red: #ef4444;
@@ -26,7 +26,7 @@
--border: #e0e3e8;
--text: #1a1a2e;
--muted: #6b7084;
--accent: #2563eb;
--accent: #2e2d2d;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
@@ -231,7 +231,7 @@
word-break: break-all;
}
.log-box .log-line { display: block; }
.log-box .log-line:hover { background: rgba(79,143,247,0.06); }
.log-box .log-line:hover { background: rgba(46,45,45,0.06); }
.log-line .ts { color: var(--muted); opacity: 0.6; }
.log-line .msg-info { color: var(--accent); }
.log-line .msg-warn { color: var(--yellow); }
@@ -291,8 +291,8 @@
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 14px;
background: rgba(79,143,247,0.1);
border: 1px solid rgba(79,143,247,0.2);
background: rgba(46,45,45,0.1);
border: 1px solid rgba(46,45,45,0.2);
}
.update-banner.visible { display: flex; }
.update-banner .update-text {
@@ -326,18 +326,6 @@
<div class="header">
<div class="header-left">
<svg width="26" height="26" viewBox="0 0 128 128" fill="none">
<rect width="128" height="128" rx="28" fill="#0166FF"/>
<circle cx="32" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="96" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="32" cy="64" r="13" fill="white"/>
<circle cx="64" cy="64" r="13" fill="white"/>
<circle cx="96" cy="64" r="13" fill="white"/>
<circle cx="32" cy="96" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="96" r="13" fill="white"/>
<circle cx="96" cy="96" r="13" fill="white" opacity="0.4"/>
</svg>
<h1>Tailscale VPN</h1>
</div>
<button class="theme-btn" id="themeToggle" aria-label="Toggle theme">
+2 -3
View File
@@ -27,6 +27,7 @@
static pid_t child_pid = -1;
static guint reload_timer_id = 0;
static AXParameter *g_ax_handle = NULL;
static char *cfg_custom_server = NULL;
static char *cfg_auth_key = NULL;
@@ -86,7 +87,7 @@ static gboolean watchdog_cb(gpointer G_GNUC_UNUSED data) {
/* If child exited 0, auth succeeded — clear AuthKey via axparameter */
if (exit_code == 0 && g_ax_handle && cfg_auth_key && *cfg_auth_key) {
GError *err = NULL;
if (ax_parameter_set(g_ax_handle, "AuthKey", "", &err)) {
if (ax_parameter_set(g_ax_handle, "AuthKey", "", TRUE, &err)) {
free(cfg_auth_key); cfg_auth_key = strdup("");
syslog(LOG_INFO, "AuthKey cleared after successful auth");
} else {
@@ -136,8 +137,6 @@ static void write_config_file(void) {
cache_get(&cfg_custom_server, "(default)"));
}
static AXParameter *g_ax_handle = NULL;
static gboolean debounced_restart(gpointer G_GNUC_UNUSED data) {
reload_timer_id = 0;
if (g_ax_handle)
+5 -17
View File
@@ -11,7 +11,7 @@
--border: #262a35;
--text: #e4e6ed;
--muted: #8b8fa3;
--accent: #4f8ff7;
--accent: #2e2d2d;
--green: #22c55e;
--yellow: #f59e0b;
--red: #ef4444;
@@ -26,7 +26,7 @@
--border: #e0e3e8;
--text: #1a1a2e;
--muted: #6b7084;
--accent: #2563eb;
--accent: #2e2d2d;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
@@ -231,7 +231,7 @@
word-break: break-all;
}
.log-box .log-line { display: block; }
.log-box .log-line:hover { background: rgba(79,143,247,0.06); }
.log-box .log-line:hover { background: rgba(46,45,45,0.06); }
.log-line .ts { color: var(--muted); opacity: 0.6; }
.log-line .msg-info { color: var(--accent); }
.log-line .msg-warn { color: var(--yellow); }
@@ -257,8 +257,8 @@
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 14px;
background: rgba(79,143,247,0.1);
border: 1px solid rgba(79,143,247,0.2);
background: rgba(46,45,45,0.1);
border: 1px solid rgba(46,45,45,0.2);
}
.update-banner.visible { display: flex; }
.update-banner .update-text {
@@ -292,18 +292,6 @@
<div class="header">
<div class="header-left">
<svg width="26" height="26" viewBox="0 0 128 128" fill="none">
<rect width="128" height="128" rx="28" fill="#0166FF"/>
<circle cx="32" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="96" cy="32" r="13" fill="white" opacity="0.4"/>
<circle cx="32" cy="64" r="13" fill="white"/>
<circle cx="64" cy="64" r="13" fill="white"/>
<circle cx="96" cy="64" r="13" fill="white"/>
<circle cx="32" cy="96" r="13" fill="white" opacity="0.4"/>
<circle cx="64" cy="96" r="13" fill="white"/>
<circle cx="96" cy="96" r="13" fill="white" opacity="0.4"/>
</svg>
<h1>Tailscale VPN</h1>
</div>
<button class="theme-btn" id="themeToggle" aria-label="Toggle theme">
+3 -1
View File
@@ -334,6 +334,7 @@
<a href="#install">Install</a>
<a href="https://github.com/Mo3he/Axis_Cam_Tailscale" target="_blank" rel="noopener">GitHub</a>
<a href="https://github.com/sponsors/Mo3he" target="_blank" rel="noopener" style="color: #db61a2;">Sponsor</a>
<a href="https://buymeacoffee.com/mo3he" target="_blank" rel="noopener" style="display:inline-flex;align-items:center;gap:0.35rem;background:#FFDD00;color:#000;font-weight:700;font-size:0.85rem;padding:0.35rem 0.85rem;border-radius:8px;line-height:1;">&#9749; Buy me a coffee</a>
<button class="theme-toggle" id="themeToggle" aria-label="Toggle theme">
<svg id="iconSun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<svg id="iconMoon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
@@ -363,7 +364,7 @@
<div style="background:rgba(79,143,247,0.07);border:1px solid rgba(79,143,247,0.18);border-radius:10px;padding:12px 18px;font-size:12.5px;color:var(--muted);line-height:1.6;">
<strong style="color:var(--text);">Disclaimer:</strong>
This is an independent, community-developed ACAP package and is <strong style="color:var(--text);">not an official Axis Communications product</strong>.
It was developed entirely on personal time and is not affiliated with, endorsed by, or supported by Axis Communications AB.
It is not affiliated with, endorsed by, or supported by Axis Communications AB.
Use at your own risk. For official Axis software, visit <a href="https://www.axis.com" target="_blank" rel="noopener">axis.com</a>.
</div>
</div>
@@ -492,6 +493,7 @@
<a href="https://github.com/Mo3he/Axis_Cam_Tailscale" target="_blank" rel="noopener">GitHub</a>
<a href="https://github.com/Mo3he/Axis_Cam_Tailscale/releases" target="_blank" rel="noopener">Releases</a>
<a href="https://github.com/sponsors/Mo3he" target="_blank" rel="noopener">Sponsor</a>
<a href="https://buymeacoffee.com/mo3he" target="_blank" rel="noopener">Buy Me a Coffee</a>
<a href="https://tailscale.com/" target="_blank" rel="noopener">Tailscale</a>
<a href="https://www.axis.com/" target="_blank" rel="noopener">Axis</a>
</div>