+
会员价格 · 按 applicationId / 包名 下发。Spark GET /api/client/spark/prices;FullStoryNovel GET /api/client/novel-reader/prices(下发包名 wf.wyrs.com,iOS Bundle com.wyrs.fullstorynovel);StepsWith GET /api/client/runsteps/prices(com.wyrs.runsteps)。Header X-Wyrs-Package · 有精确包名价则用之,否则回退该 App 的空包名默认。行首胶囊即 enabled:开=启用下发,关=停用不下发。
+
筛选包名
-
+
全部
仅默认兜底
- ${pkgOptions.map((p) => `${esc(p)} `).join('')}
+ ${pkgOptions.map((p) => `${esc(pkgOptionLabel(p))} `).join('')}
共 ${esc(list.length)} / ${esc(all.length)} 条
刷新
-
`;
+ let editing = null;
+ const setEditMode = (on, id) => {
+ $('pfSave').textContent = on ? '保存修改' : '新增价格';
+ $('pfCancel').style.display = on ? '' : 'none';
+ $('pfEditHint').style.display = on ? '' : 'none';
+ $('pfEditHint').textContent = on ? ('正在修改 #' + id) : '';
+ };
+ const clearPriceForm = () => {
+ editing = null;
+ $('pfPkg').value = '';
+ $('pfPkgCustom').value = '';
+ $('pfName').value = '';
+ $('pfBilling').value = 'subscription';
+ $('pfPrice').value = '';
+ $('pfOrig').value = '';
+ $('pfDays').value = '';
+ $('pfEnabled').checked = true;
+ CHANNELS.forEach((k) => { const el = $('pfSku_' + k); if (el) el.value = ''; });
+ setEditMode(false);
+ };
$('pfPkgFilter').onchange = () => { window.__pricePkgFilter = $('pfPkgFilter').value; pages.prices(); };
$('pfReload').onclick = () => pages.prices();
+ $('pfCancel').onclick = clearPriceForm;
$('pfSave').onclick = async () => {
const channelProductCodes = {};
CHANNELS.forEach((k) => { const v = $('pfSku_' + k)?.value?.trim(); if (v) channelProductCodes[k] = v; });
const custom = ($('pfPkgCustom')?.value || '').trim();
const packageName = custom || ($('pfPkg')?.value || '').trim();
- await api('/prices', {
- method: 'POST',
- body: JSON.stringify({
- appCode: APP,
- packageName,
- name: $('pfName').value,
- billingType: $('pfBilling').value,
- price: $('pfPrice').value,
- originalPrice: $('pfOrig').value,
- durationDays: parseInt($('pfDays').value, 10) || 0,
- channelProductCodes,
- enabled: true,
- }),
- });
+ const name = ($('pfName').value || '').trim();
+ if (!name) return alert('请填写套餐名称');
+ const priceNum = Number($('pfPrice').value);
+ if (!Number.isFinite(priceNum)) return alert('请填写有效价格');
+ const origRaw = ($('pfOrig').value || '').trim();
+ const origNum = origRaw === '' ? null : Number(origRaw);
+ if (origRaw !== '' && !Number.isFinite(origNum)) return alert('原价格式无效');
+ const body = {
+ appCode: appCodeForPackage(packageName, editing),
+ packageName,
+ name,
+ billingType: $('pfBilling').value,
+ price: priceNum,
+ originalPrice: origNum,
+ durationDays: parseInt($('pfDays').value, 10) || 0,
+ channelProductCodes,
+ enabled: !!$('pfEnabled').checked,
+ };
+ if (editing && editing.id != null) {
+ body.id = editing.id;
+ if (editing.productId) body.productId = editing.productId;
+ if (editing.createdAt) body.createdAt = editing.createdAt;
+ }
+ try {
+ await api('/prices', { method: 'POST', body: JSON.stringify(body) });
+ } catch (e) {
+ alert((editing ? '修改失败:' : '新增失败:') + e.message);
+ return;
+ }
pages.prices();
};
+ $('content').querySelectorAll('[data-pedit]').forEach((btn) => {
+ btn.onclick = () => {
+ const row = all.find((p) => String(p.id) === String(btn.dataset.pedit));
+ if (!row) return alert('价格不存在');
+ editing = row;
+ const pkg = (row.packageName || '').trim();
+ const known = [...$('pfPkg').options].some((o) => o.value === pkg);
+ if (pkg && known) {
+ $('pfPkg').value = pkg;
+ $('pfPkgCustom').value = '';
+ } else {
+ $('pfPkg').value = '';
+ $('pfPkgCustom').value = pkg;
+ }
+ $('pfName').value = row.name || '';
+ $('pfBilling').value = row.billingType === 'one_time' ? 'one_time' : 'subscription';
+ $('pfPrice').value = row.price ?? '';
+ $('pfOrig').value = row.originalPrice ?? '';
+ $('pfDays').value = row.durationDays ?? '';
+ $('pfEnabled').checked = row.enabled !== false;
+ CHANNELS.forEach((k) => {
+ const el = $('pfSku_' + k);
+ if (el) el.value = (row.channelProductCodes && row.channelProductCodes[k]) || '';
+ });
+ setEditMode(true, row.id);
+ $('pfName').focus();
+ };
+ });
+ $('content').querySelectorAll('[data-penable]').forEach((btn) => {
+ btn.onclick = async () => {
+ if (btn.disabled) return;
+ const row = all.find((p) => String(p.id) === String(btn.dataset.penable));
+ if (!row) return alert('价格不存在');
+ const prev = btn.getAttribute('aria-checked') === 'true';
+ const next = !prev;
+ btn.disabled = true;
+ btn.setAttribute('aria-checked', next ? 'true' : 'false');
+ btn.setAttribute('aria-label', (next ? '停用下发 ' : '启用下发 ') + (row.name || ''));
+ const body = {
+ id: row.id,
+ appCode: row.appCode || appCodeForPackage(row.packageName || '', row),
+ packageName: row.packageName || '',
+ name: row.name,
+ billingType: row.billingType || 'subscription',
+ price: row.price,
+ originalPrice: row.originalPrice,
+ durationDays: row.durationDays,
+ channelProductCodes: row.channelProductCodes || {},
+ enabled: next,
+ };
+ if (row.productId) body.productId = row.productId;
+ if (row.createdAt) body.createdAt = row.createdAt;
+ try {
+ await api('/prices', { method: 'POST', body: JSON.stringify(body) });
+ } catch (e) {
+ btn.setAttribute('aria-checked', prev ? 'true' : 'false');
+ btn.setAttribute('aria-label', (prev ? '停用下发 ' : '启用下发 ') + (row.name || ''));
+ btn.disabled = false;
+ alert('修改失败:' + e.message);
+ return;
+ }
+ pages.prices();
+ };
+ });
$('content').querySelectorAll('[data-pdel]').forEach((btn) => {
btn.onclick = async () => {
if (!confirm('确认删除?')) return;
diff --git a/docs/daily/2026-10-11-change-list.md b/docs/daily/2026-10-11-change-list.md
new file mode 100644
index 0000000..8c5f28d
--- /dev/null
+++ b/docs/daily/2026-10-11-change-list.md
@@ -0,0 +1,182 @@
+# 每日变动 2026-10-11
+
+## 16:06 — 官网导航增加协议、注销与关于入口
+
+### 概要
+
+- 官网顶栏在「能力」「下载」旁增加「隐私协议」「用户协议」「注销」「关于」,桌面并排,窄屏折行。
+- 隐私协议、用户协议链到已有页面;新建注销与关于页,子页面可回首页,当前页高亮。
+
+### 变更范围
+
+| 类型 | 说明 |
+|------|------|
+| 功能 | 官网主导航与两个子页面 |
+| 配置 | 官网 nginx 为隐私、用户协议、注销、关于提供独立路径,避免落到首页 |
+
+### 主要文件
+
+- `website/index.html` — 顶栏四个站内入口
+- `website/assets/styles.css` — 导航折行、当前页高亮、子页面版式
+- `website/about/index.html` — 关于页,复用官网介绍
+- `website/delete/index.html` — 注销说明(App 内邮箱验证码;找不到入口时走意见反馈)
+- `website/legal/legal.html` — 协议页补同一导航、当前项与返回首页
+- `deploy/nginx/host/sparkmessenger.conf` — `/privacy`、`/terms` 改指向现有页面,并增加 `/delete`、`/about`
+
+### 验证
+
+- `make test`: 未跑(只改官网静态页与 nginx,未改 Go)
+- 本地静态服务打开首页,点过四个入口:隐私协议、用户协议、注销、关于均可打开;关于页「返回首页」回到首页。桌面 1280 导航同一行且不重叠;320 宽折行后仍可点。
+
+### 关联
+
+- 线上站点 sparkmessenger.wyrs365.com / sparkmsg.wyrs365.com
+
+## 16:07 — 会员价格补 FullStoryNovel / StepsWith 包名,行首胶囊开关下发
+
+### 概要
+
+- 会员价格页的包名下拉与筛选补上 FullStoryNovel、StepsWith。保存时按包名写入对应 appCode,客户端按 appCode + `X-Wyrs-Package` 命中精确价,否则回退该 App 的空包名默认。
+- 每条价格行最左侧改为胶囊开关,对应字段 `enabled`。点击即 `POST /api/admin/prices` 保存;开=启用下发,关=停用不下发。请求中禁止连点,失败回滚并 alert。
+
+### 变更范围
+
+| 类型 | 说明 |
+|------|------|
+| 功能 | popadmin 会员价格分包名与单条启用下发 |
+
+### 主要文件
+
+- `deploy/popadmin/popadmin.js` — 包名选项与 appCode 映射;行首 `enabled` 胶囊开关
+
+### 验证
+
+- `make test`: 未跑(只改 popadmin 静态前端,未改 Go / SQL)
+- 本地页面演练:下拉含 `wf.wyrs.com`、`com.wyrs.fullstorynovel`、`com.wyrs.runsteps`;保存分别落到 `novel-reader` / `runsteps`。胶囊开为绿、滑块在右,关为灰、滑块在左。点击关闭会 POST `enabled:false` 并在刷新后保持关闭;接口失败时开关回到原状态并提示「修改失败」。
+
+### 关联
+
+- 线上页 popadmin.wyrs365.com/popadmin/index.html「会员价格」
+- FullStoryNovel 客户端下发包名 `wf.wyrs.com`(iOS Bundle `com.wyrs.fullstorynovel`);StepsWith `com.wyrs.runsteps`
+
+## 19:50 — FullStoryNovel 官网页脚增加隐私政策、用户协议、注销
+
+### 概要
+
+- 在新加坡服务器的 fullstorynovel.com 首页页脚增加三个站内入口,并上线对应中文页面。
+- 本地留了一份不含密钥的副本。Spark 官网和 popadmin 公网已是新版本,这次没有覆盖。
+
+### 变更范围
+
+| 类型 | 说明 |
+|------|------|
+| 功能 | FullStoryNovel 官网页脚与三个子页面 |
+| 配置 | 只增量改该站点 nginx:首页壳、`/privacy`、`/terms`、`/delete`、`site.js` |
+
+### 主要文件
+
+- `fullstorynovel-web/public-index.html` — 页脚三个入口;点击时不走站内单页路由
+- `fullstorynovel-web/privacy/index.html` — 隐私政策
+- `fullstorynovel-web/terms/index.html` — 用户协议
+- `fullstorynovel-web/delete/index.html` — 注销说明
+- `fullstorynovel-web/assets/js/site.js` — 这三个路径改为整页打开
+- `fullstorynovel-web/nginx-legal.snippet` — 与线上增量配置对应的片段
+
+### 验证
+
+- `make test`: 未跑(只新增静态页副本,未改 Go、迁移、OpenAPI 或 i18n)
+- 公网 curl:首页含三个入口;`/privacy`、`/terms`、`/delete` 均为 200
+- 浏览器点过三个入口并回到首页。桌面不重叠;390 宽页脚折行且不溢出
+
+### 关联
+
+- 服务器站点目录 `/opt/fullstorynovel/static-override`
+- nginx `/etc/nginx/conf.d/fullstorynovel.conf`(已 `nginx -t` 并 reload,未重启整机)
+
+## 19:55 — FullStoryNovel 协议对齐 wyrs365,去掉管理入口
+
+### 概要
+
+- 隐私政策和用户协议改为与 wyrs365.com 上 FullStoryNovel(novel-reader)政策同一套条款结构和表述,产品名保持 Full Story Novel / FullStoryNovel。
+- 首页页脚不再放管理入口;隐私政策、用户协议、注销三个入口保留。注销页仍写 iOS 应用里的真实注销流程。
+
+### 变更范围
+
+| 类型 | 说明 |
+|------|------|
+| 文案 | `/privacy`、`/terms` 按 wyrs365 的 novel-reader 政策重写 |
+| 页面 | 首页去掉管理入口;三个法律入口仍在页脚 |
+
+### 主要文件
+
+- `fullstorynovel-web/privacy/index.html` — 软件隐私权政策
+- `fullstorynovel-web/terms/index.html` — 软件用户服务协议
+- `fullstorynovel-web/public-index.html` — 页脚无管理入口
+- 服务器 `/opt/fullstorynovel/static-override` 同步上述三个文件
+
+### 验证
+
+- `make test`: 未跑(只改静态页,未改 Go、迁移、OpenAPI 或 i18n)
+- 公网:首页 200,无管理入口,含三个页脚链接;`/privacy`、`/terms`、`/delete` 均为 200。隐私政策含公司名、友盟披露和公开邮箱;用户协议含小说阅读服务条款。
+
+### 关联
+
+- 参考 https://www.wyrs365.com/ 、`/novel-reader-privacy`、`/novel-reader-agreement`
+- 未改 nginx、未重启整机、未提交 git
+
+## 20:40 — Spark 协议正文对齐 wyrs365.com
+
+### 概要
+
+- 官网 `/privacy`、`/terms` 仍进原有协议页。正文从四段短说明改为与 wyrs365.com 各 App 协议同一套条款:引言到联系方式共九部分,用户协议为导言到附则共八部分。
+- 产品名保持 Spark Messenger(火花)。公司名与公开邮箱沿用 wyrs365.com 已公开信息。简体、繁体为全文,其余语言显示英文全文。顶栏未改。
+
+### 变更范围
+
+| 类型 | 说明 |
+|------|------|
+| 文案 | 协议正文对齐 wyrs365.com 的条款范围 |
+
+### 主要文件
+
+- `website/legal/legal.html` — 隐私政策与用户协议正文
+
+### 验证
+
+- `make test`: 未跑(只改官网静态协议页,未改 Go、迁移、OpenAPI 或 i18n)
+- 本地打开隐私政策与英文用户协议,条款标题和联系邮箱可见。
+- 公网 `https://sparkmsg.wyrs365.com/legal/legal.html?doc=privacy` 含「Spark Messenger(火花)软件隐私权政策」和「九、如何联系我们」。
+
+### 关联
+
+- 参考 https://www.wyrs365.com/runsteps-privacy 、https://www.wyrs365.com/runsteps-agreement
+- 未改 nginx、未动 FullStoryNovel、未提交 git
+
+## 21:35 — Sleep Heart 官网 health.wyrs365.com
+
+### 概要
+
+- 阿里云 DNS 为 `health.wyrs365.com` 新增 A 记录到新加坡 `47.236.66.9`。
+- 新加坡机新增静态站与只含该域名的证书,首页及下载、注销、隐私协议、用户协议可访问。
+
+### 变更范围
+
+| 类型 | 说明 |
+|------|------|
+| 配置 | 仅该主机名的 DNS、Nginx 与证书 |
+| 功能 | Sleep Heart 官网五页 |
+
+### 主要文件
+
+- `health-web/` — 不含密钥的官网源码,已同步到 `/var/www/health.wyrs365.com`
+- `health-web/nginx/health.wyrs365.com.conf` — 对应服务器 `/etc/nginx/conf.d/health-wyrs365.conf`
+
+### 验证
+
+- `make test`: 未跑(只增加静态官网,未改 Go、迁移、OpenAPI 或 i18n)
+- 直连公网 IP:首页、`/download`、`/delete`、`/privacy`、`/terms` 均为 200
+- 浏览器点过四个入口并回到首页;约 390px 宽无横向溢出
+
+### 关联
+
+- 未提交 git,未重启整机,未改安全组,未改其他站点文件
diff --git a/fullstorynovel-web/assets/js/site.js b/fullstorynovel-web/assets/js/site.js
new file mode 100644
index 0000000..ea42b76
--- /dev/null
+++ b/fullstorynovel-web/assets/js/site.js
@@ -0,0 +1,1084 @@
+/* Full Story Novel — public site: i18n + theme + SPA */
+const LANG_KEY = "fsn_lang";
+const THEME_KEY = "fsn_theme";
+const DEFAULT_LANG = "en";
+const RTL_LANGS = new Set(["ar", "ur"]);
+
+const LANGS = [
+ { code: "en", label: "English" },
+ { code: "zh-CN", label: "简体中文" },
+ { code: "zh-TW", label: "繁體中文" },
+ { code: "hi", label: "हिन्दी" },
+ { code: "es", label: "Español" },
+ { code: "ar", label: "العربية" },
+ { code: "bn", label: "বাংলা" },
+ { code: "pt", label: "Português" },
+ { code: "ru", label: "Русский" },
+ { code: "ur", label: "اردو" },
+ { code: "ja", label: "日本語" },
+ { code: "ko", label: "한국어" },
+ { code: "fr", label: "Français" },
+ { code: "de", label: "Deutsch" },
+ { code: "it", label: "Italiano" },
+];
+
+const I18N = {
+ en: {
+ "nav.home": "Home", "nav.novels": "Novels", "nav.genres": "Genres", "nav.download": "Download App",
+ "search.placeholder": "Search novels...", "search.button": "Search",
+ "prefs.language": "Language", "prefs.theme": "Theme", "prefs.themeLight": "Light", "prefs.themeDark": "Dark",
+ "footer.tagline": "Serialized fantasy reading inspired by classic web-novel platforms.",
+ "footer.browse": "Browse", "footer.admin": "Admin",
+ "common.loading": "Loading…", "common.unknown": "Unknown", "common.any": "Any",
+ "common.viewAll": "View all", "common.chapters": "chapters", "common.views": "views",
+ "common.failed": "Failed to load", "common.previous": "Previous", "common.next": "Next",
+ "common.by": "by", "common.total": "total", "common.series": "series",
+ "home.featured": "Featured Series", "home.readNow": "Read Now", "home.browse": "Browse Library",
+ "home.welcome": "Welcome to Full Story Novel", "home.emptyHint": "Add novels from the admin panel to get started.",
+ "home.popularGenres": "Popular Genres", "home.noGenres": "No genres yet",
+ "home.popular": "Popular This Week", "home.new": "New Releases", "home.updated": "Recently Updated",
+ "home.nothing": "Nothing here yet.",
+ "novels.title": "Novels", "novels.search": "Search", "novels.genre": "Category",
+ "novels.tag": "Tag", "novels.allTags": "All tags",
+ "novels.status": "Status", "novels.language": "Language", "novels.sort": "Sort",
+ "novels.placeholder": "Title or author", "novels.empty": "No novels matched.",
+ "status.ONGOING": "Ongoing", "status.COMPLETED": "Completed", "status.HIATUS": "Hiatus",
+ "lang.ENGLISH": "English", "lang.CHINESE": "Chinese", "lang.KOREAN": "Korean",
+ "sort.popular": "Popular", "sort.rating": "Rating", "sort.newest": "New",
+ "sort.updated": "Updated", "sort.name": "Name", "sort.chapters": "Chapters",
+ "genres.title": "Genres", "genres.explore": "Explore this genre.",
+ "genres.tags": "Tags",
+ "novel.start": "Start Reading", "novel.noChapters": "No chapters yet",
+ "novel.back": "Back to Library", "novel.chapters": "Chapters", "novel.chapter": "Chapter",
+ "novel.nonePublished": "No chapters published.",
+ "read.prev": "← Previous", "read.next": "Next →", "read.chapters": "Chapters",
+ "download.title": "Read anywhere",
+ "download.lead": "Offline bookshelf, PDF/TXT import, and cloud picks — crafted for Android.",
+ "download.android": "Get Android APK",
+ "download.resolving": "Preparing the latest build…",
+ "download.ready": "Build ready — tap to install.",
+ "download.unavailable": "Package temporarily unavailable. Please try again shortly.",
+ "download.hint1": "Android only for now. Allow installs from this browser if prompted.",
+ "download.hint2": "Package name: wf.wyrs.com",
+ "download.hint3": "Signed release build mirrored on this site for a direct install.",
+ "download.feature1": "Offline bookshelf",
+ "download.feature2": "PDF / TXT import",
+ "download.feature3": "Cloud recommendations",
+ "download.platform": "Android",
+ },
+ "zh-CN": {
+ "nav.home": "首页", "nav.novels": "书库", "nav.genres": "类型", "nav.download": "App下载",
+ "search.placeholder": "搜索小说…", "search.button": "搜索",
+ "prefs.language": "语言", "prefs.theme": "主题", "prefs.themeLight": "日间", "prefs.themeDark": "暗黑",
+ "footer.tagline": "连载奇幻阅读,致敬经典网文平台。",
+ "footer.browse": "浏览", "footer.admin": "管理",
+ "common.loading": "加载中…", "common.unknown": "未知", "common.any": "全部",
+ "common.viewAll": "查看全部", "common.chapters": "章", "common.views": "阅读",
+ "common.failed": "加载失败", "common.previous": "上一页", "common.next": "下一页",
+ "common.by": "作者", "common.total": "共", "common.series": "部作品",
+ "home.featured": "精选推荐", "home.readNow": "立即阅读", "home.browse": "浏览书库",
+ "home.welcome": "欢迎来到 Full Story Novel", "home.emptyHint": "请先在管理后台添加小说。",
+ "home.popularGenres": "热门类型", "home.noGenres": "暂无类型",
+ "home.popular": "本周热门", "home.new": "新书上架", "home.updated": "最近更新",
+ "home.nothing": "暂无内容。",
+ "novels.title": "书库", "novels.search": "搜索", "novels.genre": "一级分类",
+ "novels.tag": "二级标签", "novels.allTags": "全部标签",
+ "novels.status": "状态", "novels.language": "语言", "novels.sort": "排序",
+ "novels.placeholder": "书名或作者", "novels.empty": "没有匹配的小说。",
+ "status.ONGOING": "连载中", "status.COMPLETED": "已完结", "status.HIATUS": "暂停",
+ "lang.ENGLISH": "英语", "lang.CHINESE": "中文", "lang.KOREAN": "韩语",
+ "sort.popular": "热门", "sort.rating": "评分", "sort.newest": "最新",
+ "sort.updated": "更新", "sort.name": "名称", "sort.chapters": "章节数",
+ "genres.title": "类型", "genres.explore": "探索该类型。",
+ "genres.tags": "二级标签",
+ "novel.start": "开始阅读", "novel.noChapters": "暂无章节",
+ "novel.back": "返回书库", "novel.chapters": "章节列表", "novel.chapter": "第",
+ "novel.nonePublished": "暂无已发布章节。",
+ "read.prev": "← 上一章", "read.next": "下一章 →", "read.chapters": "目录",
+ "download.title": "随时开读",
+ "download.lead": "本地书架、PDF/TXT 导入与云端推荐 — 专为 Android 打造。",
+ "download.android": "获取 Android 安装包",
+ "download.resolving": "正在准备最新构建…",
+ "download.ready": "构建已就绪,点击即可安装。",
+ "download.unavailable": "安装包暂不可用,请稍后再试。",
+ "download.hint1": "目前仅提供 Android。若系统提示,请允许从此浏览器安装。",
+ "download.hint2": "包名:wf.wyrs.com",
+ "download.hint3": "本站提供已签名正式版,可直接安装。",
+ "download.feature1": "离线书架",
+ "download.feature2": "PDF / TXT 导入",
+ "download.feature3": "云端推荐",
+ "download.platform": "Android",
+ },
+ "zh-TW": {
+ "nav.home": "首頁", "nav.novels": "書庫", "nav.genres": "類型", "nav.download": "App下載",
+ "search.placeholder": "搜尋小說…", "search.button": "搜尋",
+ "prefs.language": "語言", "prefs.theme": "主題", "prefs.themeLight": "日間", "prefs.themeDark": "暗黑",
+ "footer.tagline": "連載奇幻閱讀,致敬經典網文平台。",
+ "footer.browse": "瀏覽", "footer.admin": "管理",
+ "common.loading": "載入中…", "common.unknown": "未知", "common.any": "全部",
+ "common.viewAll": "查看全部", "common.chapters": "章", "common.views": "閱讀",
+ "common.failed": "載入失敗", "common.previous": "上一頁", "common.next": "下一頁",
+ "common.by": "作者", "common.total": "共", "common.series": "部作品",
+ "home.featured": "精選推薦", "home.readNow": "立即閱讀", "home.browse": "瀏覽書庫",
+ "home.welcome": "歡迎來到 Full Story Novel", "home.emptyHint": "請先在管理後台新增小說。",
+ "home.popularGenres": "熱門類型", "home.noGenres": "暫無類型",
+ "home.popular": "本週熱門", "home.new": "新書上架", "home.updated": "最近更新",
+ "home.nothing": "暫無內容。",
+ "novels.title": "書庫", "novels.search": "搜尋", "novels.genre": "一級分類",
+ "novels.tag": "二級標籤", "novels.allTags": "全部標籤",
+ "novels.status": "狀態", "novels.language": "語言", "novels.sort": "排序",
+ "novels.placeholder": "書名或作者", "novels.empty": "沒有符合的小說。",
+ "status.ONGOING": "連載中", "status.COMPLETED": "已完結", "status.HIATUS": "暫停",
+ "lang.ENGLISH": "英語", "lang.CHINESE": "中文", "lang.KOREAN": "韓語",
+ "sort.popular": "熱門", "sort.rating": "評分", "sort.newest": "最新",
+ "sort.updated": "更新", "sort.name": "名稱", "sort.chapters": "章節數",
+ "genres.title": "類型", "genres.explore": "探索此類型。",
+ "genres.tags": "二級標籤",
+ "novel.start": "開始閱讀", "novel.noChapters": "暫無章節",
+ "novel.back": "返回書庫", "novel.chapters": "章節列表", "novel.chapter": "第",
+ "novel.nonePublished": "暫無已發佈章節。",
+ "read.prev": "← 上一章", "read.next": "下一章 →", "read.chapters": "目錄",
+ "download.title": "隨時開讀",
+ "download.lead": "本地書架、PDF/TXT 匯入與雲端推薦 — 專為 Android 打造。",
+ "download.android": "取得 Android 安裝包",
+ "download.resolving": "正在準備最新建置…",
+ "download.ready": "建置已就緒,點擊即可安裝。",
+ "download.unavailable": "安裝包暫不可用,請稍後再試。",
+ "download.hint1": "目前僅提供 Android。若系統提示,請允許從此瀏覽器安裝。",
+ "download.hint2": "包名:wf.wyrs.com",
+ "download.hint3": "本站提供已簽名正式版,可直接安裝。",
+ "download.feature1": "離線書架",
+ "download.feature2": "PDF / TXT 匯入",
+ "download.feature3": "雲端推薦",
+ "download.platform": "Android",
+ },
+ hi: {
+ "nav.home": "होम", "nav.novels": "उपन्यास", "nav.genres": "विधाएँ",
+ "search.placeholder": "उपन्यास खोजें...", "search.button": "खोजें",
+ "prefs.language": "भाषा", "prefs.theme": "थीम", "prefs.themeLight": "दिन", "prefs.themeDark": "रात",
+ "footer.tagline": "क्लासिक वेब-उपन्यास शैली में धारावाहिक फंतासी पठन।",
+ "footer.browse": "ब्राउज़", "footer.admin": "एडमिन",
+ "common.loading": "लोड हो रहा है…", "common.unknown": "अज्ञात", "common.any": "कोई भी",
+ "common.viewAll": "सभी देखें", "common.chapters": "अध्याय", "common.views": "दृश्य",
+ "common.failed": "लोड विफल", "common.previous": "पिछला", "common.next": "अगला",
+ "common.by": "द्वारा", "common.total": "कुल", "common.series": "श्रृंखला",
+ "home.featured": "विशेष श्रृंखला", "home.readNow": "अभी पढ़ें", "home.browse": "लाइब्रेरी देखें",
+ "home.welcome": "Full Story Novel में आपका स्वागत है", "home.emptyHint": "शुरू करने के लिए एडमिन से उपन्यास जोड़ें।",
+ "home.popularGenres": "लोकप्रिय विधाएँ", "home.noGenres": "अभी कोई विधा नहीं",
+ "home.popular": "इस सप्ताह लोकप्रिय", "home.new": "नई रिलीज़", "home.updated": "हाल ही में अपडेट",
+ "home.nothing": "अभी कुछ नहीं।",
+ "novels.title": "उपन्यास", "novels.search": "खोज", "novels.genre": "विधा",
+ "novels.status": "स्थिति", "novels.language": "भाषा", "novels.sort": "क्रम",
+ "novels.placeholder": "शीर्षक या लेखक", "novels.empty": "कोई उपन्यास नहीं मिला।",
+ "status.ONGOING": "चालू", "status.COMPLETED": "पूर्ण", "status.HIATUS": "विराम",
+ "lang.ENGLISH": "अंग्रेज़ी", "lang.CHINESE": "चीनी", "lang.KOREAN": "कोरियाई",
+ "sort.popular": "लोकप्रिय", "sort.rating": "रेटिंग", "sort.newest": "नया",
+ "sort.updated": "अपडेट", "sort.name": "नाम", "sort.chapters": "अध्याय",
+ "genres.title": "विधाएँ", "genres.explore": "इस विधा को देखें।",
+ "novel.start": "पढ़ना शुरू करें", "novel.noChapters": "अभी अध्याय नहीं",
+ "novel.back": "लाइब्रेरी पर वापस", "novel.chapters": "अध्याय", "novel.chapter": "अध्याय",
+ "novel.nonePublished": "कोई अध्याय प्रकाशित नहीं।",
+ "read.prev": "← पिछला", "read.next": "अगला →", "read.chapters": "अध्याय",
+ },
+ es: {
+ "nav.home": "Inicio", "nav.novels": "Novelas", "nav.genres": "Géneros",
+ "search.placeholder": "Buscar novelas...", "search.button": "Buscar",
+ "prefs.language": "Idioma", "prefs.theme": "Tema", "prefs.themeLight": "Claro", "prefs.themeDark": "Oscuro",
+ "footer.tagline": "Lectura fantástica por entregas inspirada en novelas web clásicas.",
+ "footer.browse": "Explorar", "footer.admin": "Admin",
+ "common.loading": "Cargando…", "common.unknown": "Desconocido", "common.any": "Cualquiera",
+ "common.viewAll": "Ver todo", "common.chapters": "capítulos", "common.views": "vistas",
+ "common.failed": "Error al cargar", "common.previous": "Anterior", "common.next": "Siguiente",
+ "common.by": "por", "common.total": "total", "common.series": "series",
+ "home.featured": "Serie destacada", "home.readNow": "Leer ahora", "home.browse": "Explorar biblioteca",
+ "home.welcome": "Bienvenido a Full Story Novel", "home.emptyHint": "Añade novelas desde el panel de administración.",
+ "home.popularGenres": "Géneros populares", "home.noGenres": "Sin géneros aún",
+ "home.popular": "Popular esta semana", "home.new": "Novedades", "home.updated": "Actualizado recientemente",
+ "home.nothing": "Nada aquí todavía.",
+ "novels.title": "Novelas", "novels.search": "Buscar", "novels.genre": "Género",
+ "novels.status": "Estado", "novels.language": "Idioma", "novels.sort": "Orden",
+ "novels.placeholder": "Título o autor", "novels.empty": "Ninguna novela coincide.",
+ "status.ONGOING": "En curso", "status.COMPLETED": "Completada", "status.HIATUS": "Pausa",
+ "lang.ENGLISH": "Inglés", "lang.CHINESE": "Chino", "lang.KOREAN": "Coreano",
+ "sort.popular": "Popular", "sort.rating": "Valoración", "sort.newest": "Nuevo",
+ "sort.updated": "Actualizado", "sort.name": "Nombre", "sort.chapters": "Capítulos",
+ "genres.title": "Géneros", "genres.explore": "Explora este género.",
+ "novel.start": "Empezar a leer", "novel.noChapters": "Sin capítulos aún",
+ "novel.back": "Volver a la biblioteca", "novel.chapters": "Capítulos", "novel.chapter": "Capítulo",
+ "novel.nonePublished": "No hay capítulos publicados.",
+ "read.prev": "← Anterior", "read.next": "Siguiente →", "read.chapters": "Capítulos",
+ },
+ ar: {
+ "nav.home": "الرئيسية", "nav.novels": "الروايات", "nav.genres": "الأنواع",
+ "search.placeholder": "ابحث عن روايات...", "search.button": "بحث",
+ "prefs.language": "اللغة", "prefs.theme": "المظهر", "prefs.themeLight": "نهاري", "prefs.themeDark": "داكن",
+ "footer.tagline": "قراءة خيالية متسلسلة مستوحاة من منصات الروايات الكلاسيكية.",
+ "footer.browse": "تصفح", "footer.admin": "الإدارة",
+ "common.loading": "جارٍ التحميل…", "common.unknown": "غير معروف", "common.any": "الكل",
+ "common.viewAll": "عرض الكل", "common.chapters": "فصول", "common.views": "مشاهدات",
+ "common.failed": "فشل التحميل", "common.previous": "السابق", "common.next": "التالي",
+ "common.by": "بقلم", "common.total": "الإجمالي", "common.series": "سلسلة",
+ "home.featured": "سلسلة مميزة", "home.readNow": "اقرأ الآن", "home.browse": "تصفح المكتبة",
+ "home.welcome": "مرحبًا بك في Full Story Novel", "home.emptyHint": "أضف روايات من لوحة الإدارة للبدء.",
+ "home.popularGenres": "أنواع شائعة", "home.noGenres": "لا أنواع بعد",
+ "home.popular": "الأكثر شعبية هذا الأسبوع", "home.new": "إصدارات جديدة", "home.updated": "حديث التحديث",
+ "home.nothing": "لا شيء هنا بعد.",
+ "novels.title": "الروايات", "novels.search": "بحث", "novels.genre": "النوع",
+ "novels.status": "الحالة", "novels.language": "اللغة", "novels.sort": "ترتيب",
+ "novels.placeholder": "العنوان أو المؤلف", "novels.empty": "لا روايات مطابقة.",
+ "status.ONGOING": "مستمرة", "status.COMPLETED": "مكتملة", "status.HIATUS": "متوقفة",
+ "lang.ENGLISH": "الإنجليزية", "lang.CHINESE": "الصينية", "lang.KOREAN": "الكورية",
+ "sort.popular": "شائع", "sort.rating": "التقييم", "sort.newest": "الأحدث",
+ "sort.updated": "محدث", "sort.name": "الاسم", "sort.chapters": "الفصول",
+ "genres.title": "الأنواع", "genres.explore": "استكشف هذا النوع.",
+ "novel.start": "ابدأ القراءة", "novel.noChapters": "لا فصول بعد",
+ "novel.back": "العودة للمكتبة", "novel.chapters": "الفصول", "novel.chapter": "فصل",
+ "novel.nonePublished": "لا فصول منشورة.",
+ "read.prev": "→ السابق", "read.next": "التالي ←", "read.chapters": "الفصول",
+ },
+ bn: {
+ "nav.home": "হোম", "nav.novels": "উপন্যাস", "nav.genres": "ধরন",
+ "search.placeholder": "উপন্যাস খুঁজুন...", "search.button": "অনুসন্ধান",
+ "prefs.language": "ভাষা", "prefs.theme": "থিম", "prefs.themeLight": "দিন", "prefs.themeDark": "রাত",
+ "footer.tagline": "ক্লাসিক ওয়েব-উপন্যাস প্ল্যাটফর্ম থেকে অনুপ্রাণিত ধারাবাহিক ফ্যান্টাসি পাঠ।",
+ "footer.browse": "ব্রাউজ", "footer.admin": "অ্যাডমিন",
+ "common.loading": "লোড হচ্ছে…", "common.unknown": "অজানা", "common.any": "যেকোনো",
+ "common.viewAll": "সব দেখুন", "common.chapters": "অধ্যায়", "common.views": "দেখা",
+ "common.failed": "লোড ব্যর্থ", "common.previous": "পূর্ববর্তী", "common.next": "পরবর্তী",
+ "common.by": "লেখক", "common.total": "মোট", "common.series": "সিরিজ",
+ "home.featured": "বিশেষ সিরিজ", "home.readNow": "এখনই পড়ুন", "home.browse": "লাইব্রেরি দেখুন",
+ "home.welcome": "Full Story Novel-এ স্বাগতম", "home.emptyHint": "শুরু করতে অ্যাডমিন থেকে উপন্যাস যোগ করুন।",
+ "home.popularGenres": "জনপ্রিয় ধরন", "home.noGenres": "এখনো কোনো ধরন নেই",
+ "home.popular": "এই সপ্তাহের জনপ্রিয়", "home.new": "নতুন প্রকাশ", "home.updated": "সম্প্রতি আপডেট",
+ "home.nothing": "এখনো কিছু নেই।",
+ "novels.title": "উপন্যাস", "novels.search": "অনুসন্ধান", "novels.genre": "ধরন",
+ "novels.status": "অবস্থা", "novels.language": "ভাষা", "novels.sort": "সাজানো",
+ "novels.placeholder": "শিরোনাম বা লেখক", "novels.empty": "কোনো উপন্যাস মেলেনি।",
+ "status.ONGOING": "চলমান", "status.COMPLETED": "সম্পূর্ণ", "status.HIATUS": "বিরতি",
+ "lang.ENGLISH": "ইংরেজি", "lang.CHINESE": "চীনা", "lang.KOREAN": "কোরিয়ান",
+ "sort.popular": "জনপ্রিয়", "sort.rating": "রেটিং", "sort.newest": "নতুন",
+ "sort.updated": "আপডেট", "sort.name": "নাম", "sort.chapters": "অধ্যায়",
+ "genres.title": "ধরন", "genres.explore": "এই ধরন অন্বেষণ করুন।",
+ "novel.start": "পড়া শুরু করুন", "novel.noChapters": "এখনো অধ্যায় নেই",
+ "novel.back": "লাইব্রেরিতে ফিরুন", "novel.chapters": "অধ্যায়", "novel.chapter": "অধ্যায়",
+ "novel.nonePublished": "কোনো অধ্যায় প্রকাশিত হয়নি।",
+ "read.prev": "← পূর্ববর্তী", "read.next": "পরবর্তী →", "read.chapters": "অধ্যায়",
+ },
+ pt: {
+ "nav.home": "Início", "nav.novels": "Romances", "nav.genres": "Gêneros",
+ "search.placeholder": "Pesquisar romances...", "search.button": "Pesquisar",
+ "prefs.language": "Idioma", "prefs.theme": "Tema", "prefs.themeLight": "Claro", "prefs.themeDark": "Escuro",
+ "footer.tagline": "Leitura fantástica em série inspirada em plataformas clássicas de web novels.",
+ "footer.browse": "Explorar", "footer.admin": "Admin",
+ "common.loading": "Carregando…", "common.unknown": "Desconhecido", "common.any": "Qualquer",
+ "common.viewAll": "Ver tudo", "common.chapters": "capítulos", "common.views": "visualizações",
+ "common.failed": "Falha ao carregar", "common.previous": "Anterior", "common.next": "Próximo",
+ "common.by": "por", "common.total": "total", "common.series": "séries",
+ "home.featured": "Série em destaque", "home.readNow": "Ler agora", "home.browse": "Explorar biblioteca",
+ "home.welcome": "Bem-vindo ao Full Story Novel", "home.emptyHint": "Adicione romances no painel admin para começar.",
+ "home.popularGenres": "Gêneros populares", "home.noGenres": "Sem gêneros ainda",
+ "home.popular": "Popular esta semana", "home.new": "Lançamentos", "home.updated": "Atualizados recentemente",
+ "home.nothing": "Nada aqui ainda.",
+ "novels.title": "Romances", "novels.search": "Pesquisar", "novels.genre": "Gênero",
+ "novels.status": "Status", "novels.language": "Idioma", "novels.sort": "Ordenar",
+ "novels.placeholder": "Título ou autor", "novels.empty": "Nenhum romance encontrado.",
+ "status.ONGOING": "Em andamento", "status.COMPLETED": "Concluído", "status.HIATUS": "Pausa",
+ "lang.ENGLISH": "Inglês", "lang.CHINESE": "Chinês", "lang.KOREAN": "Coreano",
+ "sort.popular": "Popular", "sort.rating": "Avaliação", "sort.newest": "Novo",
+ "sort.updated": "Atualizado", "sort.name": "Nome", "sort.chapters": "Capítulos",
+ "genres.title": "Gêneros", "genres.explore": "Explore este gênero.",
+ "novel.start": "Começar a ler", "novel.noChapters": "Sem capítulos ainda",
+ "novel.back": "Voltar à biblioteca", "novel.chapters": "Capítulos", "novel.chapter": "Capítulo",
+ "novel.nonePublished": "Nenhum capítulo publicado.",
+ "read.prev": "← Anterior", "read.next": "Próximo →", "read.chapters": "Capítulos",
+ },
+ ru: {
+ "nav.home": "Главная", "nav.novels": "Новеллы", "nav.genres": "Жанры",
+ "search.placeholder": "Поиск новелл...", "search.button": "Найти",
+ "prefs.language": "Язык", "prefs.theme": "Тема", "prefs.themeLight": "Светлая", "prefs.themeDark": "Тёмная",
+ "footer.tagline": "Серийное фэнтези в духе классических веб-новелл.",
+ "footer.browse": "Каталог", "footer.admin": "Админ",
+ "common.loading": "Загрузка…", "common.unknown": "Неизвестно", "common.any": "Любой",
+ "common.viewAll": "Смотреть все", "common.chapters": "глав", "common.views": "просмотров",
+ "common.failed": "Ошибка загрузки", "common.previous": "Назад", "common.next": "Далее",
+ "common.by": "автор", "common.total": "всего", "common.series": "серий",
+ "home.featured": "Избранная серия", "home.readNow": "Читать", "home.browse": "В библиотеку",
+ "home.welcome": "Добро пожаловать в Full Story Novel", "home.emptyHint": "Добавьте новеллы в админ-панели.",
+ "home.popularGenres": "Популярные жанры", "home.noGenres": "Пока нет жанров",
+ "home.popular": "Популярное за неделю", "home.new": "Новинки", "home.updated": "Недавно обновлено",
+ "home.nothing": "Пока пусто.",
+ "novels.title": "Новеллы", "novels.search": "Поиск", "novels.genre": "Жанр",
+ "novels.status": "Статус", "novels.language": "Язык", "novels.sort": "Сортировка",
+ "novels.placeholder": "Название или автор", "novels.empty": "Ничего не найдено.",
+ "status.ONGOING": "В процессе", "status.COMPLETED": "Завершено", "status.HIATUS": "Пауза",
+ "lang.ENGLISH": "Английский", "lang.CHINESE": "Китайский", "lang.KOREAN": "Корейский",
+ "sort.popular": "Популярные", "sort.rating": "Рейтинг", "sort.newest": "Новые",
+ "sort.updated": "Обновления", "sort.name": "Имя", "sort.chapters": "Главы",
+ "genres.title": "Жанры", "genres.explore": "Исследуйте этот жанр.",
+ "novel.start": "Начать чтение", "novel.noChapters": "Пока нет глав",
+ "novel.back": "К библиотеке", "novel.chapters": "Главы", "novel.chapter": "Глава",
+ "novel.nonePublished": "Нет опубликованных глав.",
+ "read.prev": "← Назад", "read.next": "Далее →", "read.chapters": "Оглавление",
+ },
+ ur: {
+ "nav.home": "ہوم", "nav.novels": "ناول", "nav.genres": "اقسام",
+ "search.placeholder": "ناول تلاش کریں...", "search.button": "تلاش",
+ "prefs.language": "زبان", "prefs.theme": "تھیم", "prefs.themeLight": "دن", "prefs.themeDark": "رات",
+ "footer.tagline": "کلاسک ویب ناول پلیٹ فارمز سے متاثر سلسلہ وار فنتاسی مطالعہ۔",
+ "footer.browse": "براؤز", "footer.admin": "ایڈمن",
+ "common.loading": "لوڈ ہو رہا ہے…", "common.unknown": "نامعلوم", "common.any": "کوئی بھی",
+ "common.viewAll": "سب دیکھیں", "common.chapters": "ابواب", "common.views": "ملاحظات",
+ "common.failed": "لوڈ ناکام", "common.previous": "پچھلا", "common.next": "اگلا",
+ "common.by": "از", "common.total": "کل", "common.series": "سیریز",
+ "home.featured": "نمایاں سیریز", "home.readNow": "ابھی پڑھیں", "home.browse": "لائبریری دیکھیں",
+ "home.welcome": "Full Story Novel میں خوش آمدید", "home.emptyHint": "شروع کرنے کے لیے ایڈمن سے ناول شامل کریں۔",
+ "home.popularGenres": "مقبول اقسام", "home.noGenres": "ابھی کوئی قسم نہیں",
+ "home.popular": "اس ہفتے مقبول", "home.new": "نئی ریلیز", "home.updated": "حال ہی میں اپڈیٹ",
+ "home.nothing": "ابھی کچھ نہیں۔",
+ "novels.title": "ناول", "novels.search": "تلاش", "novels.genre": "قسم",
+ "novels.status": "حیثیت", "novels.language": "زبان", "novels.sort": "ترتیب",
+ "novels.placeholder": "عنوان یا مصنف", "novels.empty": "کوئی ناول نہیں ملا۔",
+ "status.ONGOING": "جاری", "status.COMPLETED": "مکمل", "status.HIATUS": "وقفہ",
+ "lang.ENGLISH": "انگریزی", "lang.CHINESE": "چینی", "lang.KOREAN": "کوریائی",
+ "sort.popular": "مقبول", "sort.rating": "ریٹنگ", "sort.newest": "نیا",
+ "sort.updated": "اپڈیٹ", "sort.name": "نام", "sort.chapters": "ابواب",
+ "genres.title": "اقسام", "genres.explore": "اس قسم کو دیکھیں۔",
+ "novel.start": "پڑھنا شروع کریں", "novel.noChapters": "ابھی ابواب نہیں",
+ "novel.back": "لائبریری پر واپس", "novel.chapters": "ابواب", "novel.chapter": "باب",
+ "novel.nonePublished": "کوئی باب شائع نہیں۔",
+ "read.prev": "→ پچھلا", "read.next": "اگلا ←", "read.chapters": "ابواب",
+ },
+ ja: {
+ "nav.home": "ホーム", "nav.novels": "小説", "nav.genres": "ジャンル",
+ "search.placeholder": "小説を検索...", "search.button": "検索",
+ "prefs.language": "言語", "prefs.theme": "テーマ", "prefs.themeLight": "ライト", "prefs.themeDark": "ダーク",
+ "footer.tagline": "古典的なウェブ小説プラットフォームに着想を得た連載ファンタジー。",
+ "footer.browse": "閲覧", "footer.admin": "管理",
+ "common.loading": "読み込み中…", "common.unknown": "不明", "common.any": "すべて",
+ "common.viewAll": "すべて見る", "common.chapters": "章", "common.views": "閲覧",
+ "common.failed": "読み込み失敗", "common.previous": "前へ", "common.next": "次へ",
+ "common.by": "著者", "common.total": "合計", "common.series": "作品",
+ "home.featured": "注目作品", "home.readNow": "今すぐ読む", "home.browse": "ライブラリを見る",
+ "home.welcome": "Full Story Novel へようこそ", "home.emptyHint": "管理画面から小説を追加してください。",
+ "home.popularGenres": "人気ジャンル", "home.noGenres": "ジャンルはまだありません",
+ "home.popular": "今週の人気", "home.new": "新着", "home.updated": "最近更新",
+ "home.nothing": "まだありません。",
+ "novels.title": "小説", "novels.search": "検索", "novels.genre": "ジャンル",
+ "novels.status": "状態", "novels.language": "言語", "novels.sort": "並び替え",
+ "novels.placeholder": "タイトルまたは著者", "novels.empty": "一致する小説がありません。",
+ "status.ONGOING": "連載中", "status.COMPLETED": "完結", "status.HIATUS": "休載",
+ "lang.ENGLISH": "英語", "lang.CHINESE": "中国語", "lang.KOREAN": "韓国語",
+ "sort.popular": "人気", "sort.rating": "評価", "sort.newest": "新着",
+ "sort.updated": "更新", "sort.name": "名前", "sort.chapters": "章数",
+ "genres.title": "ジャンル", "genres.explore": "このジャンルを見る。",
+ "novel.start": "読み始める", "novel.noChapters": "章はまだありません",
+ "novel.back": "ライブラリに戻る", "novel.chapters": "目次", "novel.chapter": "第",
+ "novel.nonePublished": "公開された章はありません。",
+ "read.prev": "← 前の章", "read.next": "次の章 →", "read.chapters": "目次",
+ },
+ ko: {
+ "nav.home": "홈", "nav.novels": "소설", "nav.genres": "장르",
+ "search.placeholder": "소설 검색...", "search.button": "검색",
+ "prefs.language": "언어", "prefs.theme": "테마", "prefs.themeLight": "라이트", "prefs.themeDark": "다크",
+ "footer.tagline": "클래식 웹소설 플랫폼에서 영감을 받은 연재 판타지 독서.",
+ "footer.browse": "둘러보기", "footer.admin": "관리",
+ "common.loading": "로딩 중…", "common.unknown": "알 수 없음", "common.any": "전체",
+ "common.viewAll": "전체 보기", "common.chapters": "화", "common.views": "조회",
+ "common.failed": "불러오기 실패", "common.previous": "이전", "common.next": "다음",
+ "common.by": "작가", "common.total": "총", "common.series": "작품",
+ "home.featured": "추천 작품", "home.readNow": "바로 읽기", "home.browse": "서재 보기",
+ "home.welcome": "Full Story Novel에 오신 것을 환영합니다", "home.emptyHint": "관리자에서 소설을 추가하세요.",
+ "home.popularGenres": "인기 장르", "home.noGenres": "장르가 없습니다",
+ "home.popular": "이번 주 인기", "home.new": "신작", "home.updated": "최근 업데이트",
+ "home.nothing": "아직 없습니다.",
+ "novels.title": "소설", "novels.search": "검색", "novels.genre": "장르",
+ "novels.status": "상태", "novels.language": "언어", "novels.sort": "정렬",
+ "novels.placeholder": "제목 또는 작가", "novels.empty": "일치하는 소설이 없습니다.",
+ "status.ONGOING": "연재중", "status.COMPLETED": "완결", "status.HIATUS": "휴재",
+ "lang.ENGLISH": "영어", "lang.CHINESE": "중국어", "lang.KOREAN": "한국어",
+ "sort.popular": "인기", "sort.rating": "평점", "sort.newest": "최신",
+ "sort.updated": "업데이트", "sort.name": "이름", "sort.chapters": "화수",
+ "genres.title": "장르", "genres.explore": "이 장르를 탐색하세요.",
+ "novel.start": "읽기 시작", "novel.noChapters": "아직 회차가 없습니다",
+ "novel.back": "서재로 돌아가기", "novel.chapters": "목차", "novel.chapter": "제",
+ "novel.nonePublished": "게시된 회차가 없습니다.",
+ "read.prev": "← 이전", "read.next": "다음 →", "read.chapters": "목차",
+ },
+ fr: {
+ "nav.home": "Accueil", "nav.novels": "Romans", "nav.genres": "Genres",
+ "search.placeholder": "Rechercher des romans...", "search.button": "Rechercher",
+ "prefs.language": "Langue", "prefs.theme": "Thème", "prefs.themeLight": "Clair", "prefs.themeDark": "Sombre",
+ "footer.tagline": "Lecture fantasy en série inspirée des plateformes de web novels classiques.",
+ "footer.browse": "Parcourir", "footer.admin": "Admin",
+ "common.loading": "Chargement…", "common.unknown": "Inconnu", "common.any": "Tous",
+ "common.viewAll": "Tout voir", "common.chapters": "chapitres", "common.views": "vues",
+ "common.failed": "Échec du chargement", "common.previous": "Précédent", "common.next": "Suivant",
+ "common.by": "par", "common.total": "total", "common.series": "séries",
+ "home.featured": "Série à la une", "home.readNow": "Lire maintenant", "home.browse": "Parcourir la bibliothèque",
+ "home.welcome": "Bienvenue sur Full Story Novel", "home.emptyHint": "Ajoutez des romans depuis l’admin.",
+ "home.popularGenres": "Genres populaires", "home.noGenres": "Pas encore de genres",
+ "home.popular": "Populaire cette semaine", "home.new": "Nouveautés", "home.updated": "Récemment mis à jour",
+ "home.nothing": "Rien ici pour l’instant.",
+ "novels.title": "Romans", "novels.search": "Recherche", "novels.genre": "Genre",
+ "novels.status": "Statut", "novels.language": "Langue", "novels.sort": "Tri",
+ "novels.placeholder": "Titre ou auteur", "novels.empty": "Aucun roman trouvé.",
+ "status.ONGOING": "En cours", "status.COMPLETED": "Terminé", "status.HIATUS": "Pause",
+ "lang.ENGLISH": "Anglais", "lang.CHINESE": "Chinois", "lang.KOREAN": "Coréen",
+ "sort.popular": "Populaire", "sort.rating": "Note", "sort.newest": "Récent",
+ "sort.updated": "Mis à jour", "sort.name": "Nom", "sort.chapters": "Chapitres",
+ "genres.title": "Genres", "genres.explore": "Explorez ce genre.",
+ "novel.start": "Commencer", "novel.noChapters": "Pas encore de chapitres",
+ "novel.back": "Retour à la bibliothèque", "novel.chapters": "Chapitres", "novel.chapter": "Chapitre",
+ "novel.nonePublished": "Aucun chapitre publié.",
+ "read.prev": "← Précédent", "read.next": "Suivant →", "read.chapters": "Chapitres",
+ },
+ de: {
+ "nav.home": "Start", "nav.novels": "Romane", "nav.genres": "Genres",
+ "search.placeholder": "Romane suchen...", "search.button": "Suchen",
+ "prefs.language": "Sprache", "prefs.theme": "Thema", "prefs.themeLight": "Hell", "prefs.themeDark": "Dunkel",
+ "footer.tagline": "Serielle Fantasy-Lektüre inspiriert von klassischen Webnovel-Plattformen.",
+ "footer.browse": "Stöbern", "footer.admin": "Admin",
+ "common.loading": "Laden…", "common.unknown": "Unbekannt", "common.any": "Alle",
+ "common.viewAll": "Alle anzeigen", "common.chapters": "Kapitel", "common.views": "Aufrufe",
+ "common.failed": "Laden fehlgeschlagen", "common.previous": "Zurück", "common.next": "Weiter",
+ "common.by": "von", "common.total": "gesamt", "common.series": "Serien",
+ "home.featured": "Empfohlene Serie", "home.readNow": "Jetzt lesen", "home.browse": "Bibliothek öffnen",
+ "home.welcome": "Willkommen bei Full Story Novel", "home.emptyHint": "Füge Romane im Admin-Bereich hinzu.",
+ "home.popularGenres": "Beliebte Genres", "home.noGenres": "Noch keine Genres",
+ "home.popular": "Beliebt diese Woche", "home.new": "Neuerscheinungen", "home.updated": "Kürzlich aktualisiert",
+ "home.nothing": "Noch nichts hier.",
+ "novels.title": "Romane", "novels.search": "Suche", "novels.genre": "Genre",
+ "novels.status": "Status", "novels.language": "Sprache", "novels.sort": "Sortierung",
+ "novels.placeholder": "Titel oder Autor", "novels.empty": "Keine Treffer.",
+ "status.ONGOING": "Laufend", "status.COMPLETED": "Abgeschlossen", "status.HIATUS": "Pause",
+ "lang.ENGLISH": "Englisch", "lang.CHINESE": "Chinesisch", "lang.KOREAN": "Koreanisch",
+ "sort.popular": "Beliebt", "sort.rating": "Bewertung", "sort.newest": "Neu",
+ "sort.updated": "Aktualisiert", "sort.name": "Name", "sort.chapters": "Kapitel",
+ "genres.title": "Genres", "genres.explore": "Dieses Genre entdecken.",
+ "novel.start": "Lesen starten", "novel.noChapters": "Noch keine Kapitel",
+ "novel.back": "Zur Bibliothek", "novel.chapters": "Kapitel", "novel.chapter": "Kapitel",
+ "novel.nonePublished": "Keine veröffentlichten Kapitel.",
+ "read.prev": "← Zurück", "read.next": "Weiter →", "read.chapters": "Kapitel",
+ },
+ it: {
+ "nav.home": "Home", "nav.novels": "Romanzi", "nav.genres": "Generi",
+ "search.placeholder": "Cerca romanzi...", "search.button": "Cerca",
+ "prefs.language": "Lingua", "prefs.theme": "Tema", "prefs.themeLight": "Chiaro", "prefs.themeDark": "Scuro",
+ "footer.tagline": "Lettura fantasy a puntate ispirata alle piattaforme di web novel classiche.",
+ "footer.browse": "Sfoglia", "footer.admin": "Admin",
+ "common.loading": "Caricamento…", "common.unknown": "Sconosciuto", "common.any": "Qualsiasi",
+ "common.viewAll": "Vedi tutto", "common.chapters": "capitoli", "common.views": "visualizzazioni",
+ "common.failed": "Caricamento non riuscito", "common.previous": "Precedente", "common.next": "Successivo",
+ "common.by": "di", "common.total": "totale", "common.series": "serie",
+ "home.featured": "Serie in evidenza", "home.readNow": "Leggi ora", "home.browse": "Sfoglia la libreria",
+ "home.welcome": "Benvenuto su Full Story Novel", "home.emptyHint": "Aggiungi romanzi dal pannello admin.",
+ "home.popularGenres": "Generi popolari", "home.noGenres": "Nessun genere ancora",
+ "home.popular": "Popolari questa settimana", "home.new": "Nuove uscite", "home.updated": "Aggiornati di recente",
+ "home.nothing": "Ancora niente qui.",
+ "novels.title": "Romanzi", "novels.search": "Cerca", "novels.genre": "Genere",
+ "novels.status": "Stato", "novels.language": "Lingua", "novels.sort": "Ordina",
+ "novels.placeholder": "Titolo o autore", "novels.empty": "Nessun romanzo trovato.",
+ "status.ONGOING": "In corso", "status.COMPLETED": "Completato", "status.HIATUS": "Pausa",
+ "lang.ENGLISH": "Inglese", "lang.CHINESE": "Cinese", "lang.KOREAN": "Coreano",
+ "sort.popular": "Popolari", "sort.rating": "Valutazione", "sort.newest": "Nuovi",
+ "sort.updated": "Aggiornati", "sort.name": "Nome", "sort.chapters": "Capitoli",
+ "genres.title": "Generi", "genres.explore": "Esplora questo genere.",
+ "novel.start": "Inizia a leggere", "novel.noChapters": "Ancora nessun capitolo",
+ "novel.back": "Torna alla libreria", "novel.chapters": "Capitoli", "novel.chapter": "Capitolo",
+ "novel.nonePublished": "Nessun capitolo pubblicato.",
+ "read.prev": "← Precedente", "read.next": "Successivo →", "read.chapters": "Capitoli",
+ },
+};
+
+let lang = DEFAULT_LANG;
+let theme = "dark";
+
+function t(key, fallback) {
+ const dict = I18N[lang] || I18N.en;
+ return dict[key] || I18N.en[key] || fallback || key;
+}
+
+function applyDocumentLocale() {
+ document.documentElement.lang = lang;
+ document.documentElement.dir = RTL_LANGS.has(lang) ? "rtl" : "ltr";
+}
+
+function applyTheme() {
+ document.documentElement.setAttribute("data-theme", theme);
+ const btn = document.getElementById("theme-toggle");
+ if (btn) {
+ btn.textContent = theme === "light" ? "☾" : "☀";
+ btn.title = theme === "light" ? t("prefs.themeDark") : t("prefs.themeLight");
+ btn.setAttribute("aria-label", btn.title);
+ }
+}
+
+function applyStaticI18n() {
+ document.querySelectorAll("[data-i18n]").forEach((el) => {
+ el.textContent = t(el.getAttribute("data-i18n"));
+ });
+ document.querySelectorAll("[data-i18n-placeholder]").forEach((el) => {
+ el.setAttribute("placeholder", t(el.getAttribute("data-i18n-placeholder")));
+ });
+ const sel = document.getElementById("lang-select");
+ if (sel) {
+ sel.setAttribute("aria-label", t("prefs.language"));
+ sel.title = t("prefs.language");
+ }
+ applyTheme();
+}
+
+function initPrefs() {
+ try {
+ const savedLang = localStorage.getItem(LANG_KEY);
+ lang = savedLang && I18N[savedLang] ? savedLang : DEFAULT_LANG;
+ const savedTheme = localStorage.getItem(THEME_KEY);
+ theme = savedTheme === "light" || savedTheme === "dark" ? savedTheme : "dark";
+ } catch (_) {
+ lang = DEFAULT_LANG;
+ theme = "dark";
+ }
+ applyDocumentLocale();
+ applyTheme();
+
+ const sel = document.getElementById("lang-select");
+ if (sel) {
+ sel.innerHTML = LANGS.map(
+ (l) => `
${l.label} `
+ ).join("");
+ sel.addEventListener("change", () => {
+ lang = sel.value;
+ try {
+ localStorage.setItem(LANG_KEY, lang);
+ } catch (_) {}
+ applyDocumentLocale();
+ applyStaticI18n();
+ render();
+ });
+ }
+ const themeBtn = document.getElementById("theme-toggle");
+ if (themeBtn) {
+ themeBtn.addEventListener("click", () => {
+ theme = theme === "dark" ? "light" : "dark";
+ try {
+ localStorage.setItem(THEME_KEY, theme);
+ } catch (_) {}
+ applyTheme();
+ });
+ }
+ applyStaticI18n();
+}
+
+const app = document.getElementById("app");
+const state = { genres: [], genreTree: [] };
+
+function asGenreTree(list) {
+ const arr = Array.isArray(list) ? list : [];
+ if (arr.some((g) => Array.isArray(g.children) && g.children.length)) {
+ return arr.filter((g) => !g.parentId);
+ }
+ const parents = arr.filter((g) => !g.parentId);
+ const children = arr.filter((g) => g.parentId);
+ if (!parents.length) return arr;
+ return parents.map((p) => ({
+ ...p,
+ children: children.filter((c) => c.parentId === p.id || c.parentSlug === p.slug),
+ }));
+}
+
+function findGenreNode(tree, slug) {
+ const key = String(slug || "").toLowerCase();
+ for (const p of tree) {
+ if (String(p.slug).toLowerCase() === key) return { parent: p, child: null };
+ for (const c of p.children || []) {
+ if (String(c.slug).toLowerCase() === key) return { parent: p, child: c };
+ }
+ }
+ return { parent: null, child: null };
+}
+
+async function api(path) {
+ const res = await fetch(path);
+ if (!res.ok) throw new Error((await res.text()) || res.statusText);
+ return res.json();
+}
+
+function escapeHtml(s) {
+ return String(s ?? "")
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """);
+}
+
+function cover(url, title) {
+ if (url) return url;
+ const initial = (title || "?").slice(0, 1).toUpperCase();
+ const svg = encodeURIComponent(
+ `
${initial} `
+ );
+ return `data:image/svg+xml,${svg}`;
+}
+
+function formatViews(v) {
+ const n = Number(v || 0);
+ if (n >= 1e6) return (n / 1e6).toFixed(1) + "M " + t("common.views");
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + "K " + t("common.views");
+ return n + " " + t("common.views");
+}
+
+function statusLabel(s) {
+ return t("status." + s, s);
+}
+
+function languageLabel(s) {
+ return t("lang." + s, s);
+}
+
+function badges(novel) {
+ const items = [
+ `
${escapeHtml(statusLabel(novel.status))} `,
+ `
${escapeHtml(languageLabel(novel.language))} `,
+ ...((novel.genres || []).slice(0, 3).map((g) => `
${escapeHtml(g)} `)),
+ ];
+ return `
${items.join("")}
`;
+}
+
+function novelCard(n) {
+ return `
+
+
+
+
${escapeHtml(n.title)}
+
${escapeHtml(n.author || t("common.unknown"))} · ★ ${Number(n.rating || 0).toFixed(1)}
+
${n.chapterCount || 0} ${t("common.chapters")} · ${formatViews(n.views)}
+
+ `;
+}
+
+function section(title, items) {
+ return `
+
+
${(items || []).map(novelCard).join("") || `
${t("home.nothing")}
`}
`;
+}
+
+function parseRoute() {
+ const path = location.pathname.replace(/\/+$/, "") || "/";
+ const parts = path.split("/").filter(Boolean);
+ if (!parts.length) return { name: "home" };
+ if (parts[0] === "novels") return { name: "novels" };
+ if (parts[0] === "genres") return { name: "genres" };
+ if (parts[0] === "download" || parts[0] === "app") return { name: "download" };
+ if (parts[0] === "novel" && parts[1]) return { name: "novel", slug: decodeURIComponent(parts[1]) };
+ if (parts[0] === "read" && parts[1] && parts[2]) {
+ return {
+ name: "read",
+ novelSlug: decodeURIComponent(parts[1]),
+ chapterSlug: decodeURIComponent(parts[2]),
+ };
+ }
+ return { name: "home" };
+}
+
+async function renderHome() {
+ const data = await api("/api/home");
+ state.genreTree = asGenreTree(data.genres || []);
+ state.genres = state.genreTree;
+ const featured = (data.featured || [])[0];
+ app.innerHTML = `
+
+
+ ${
+ featured
+ ? `
+
+
${t("home.featured")}
+
${escapeHtml(featured.title)}
+ ${badges(featured)}
+
${escapeHtml((featured.synopsis || "").slice(0, 280))}${(featured.synopsis || "").length > 280 ? "…" : ""}
+
+
`
+ : `
${t("home.welcome")} ${t("home.emptyHint")}
`
+ }
+
+
+
${t("home.popularGenres")}
+
+
+
+ ${section(t("home.popular"), data.popular)}
+ ${section(t("home.new"), data.newReleases)}
+ ${section(t("home.updated"), data.recentlyUpdated)}
+ `;
+}
+
+async function renderNovels() {
+ const params = new URLSearchParams(location.search);
+ const q = params.get("q") || "";
+ const genre = params.get("genre") || "";
+ const status = params.get("status") || "";
+ const language = params.get("language") || "";
+ const sort = params.get("sort") || "popular";
+ const page = Number(params.get("page") || 0);
+ if (!state.genreTree.length) {
+ state.genreTree = asGenreTree(await api("/api/genres?tree=true"));
+ state.genres = state.genreTree;
+ }
+ const located = findGenreNode(state.genreTree, genre);
+ const parentSlug = located.parent ? located.parent.slug : "";
+ const childSlug = located.child ? located.child.slug : "";
+ const childOptions = located.parent ? located.parent.children || [] : [];
+ const filterSlug = childSlug || parentSlug || genre;
+
+ const qs = new URLSearchParams({ page: String(page), size: "24", sort });
+ if (q) qs.set("q", q);
+ if (filterSlug) qs.set("genre", filterSlug);
+ if (status) qs.set("status", status);
+ if (language) qs.set("language", language);
+
+ const data = await api(`/api/novels?${qs}`);
+ app.innerHTML = `
+
${t("novels.title")} ${data.total} ${t("common.series")}
+
+
${(data.items || []).map(novelCard).join("") || `
${t("novels.empty")}
`}
+
`;
+
+ document.getElementById("filter-form").addEventListener("change", (ev) => {
+ const fd = new FormData(document.getElementById("filter-form"));
+ const next = new URLSearchParams();
+ const parent = String(fd.get("parent") || "").trim();
+ const tag = String(fd.get("tag") || "").trim();
+ if (ev.target && ev.target.name === "parent") {
+ if (parent) next.set("genre", parent);
+ } else if (tag) {
+ next.set("genre", tag);
+ } else if (parent) {
+ next.set("genre", parent);
+ }
+ for (const [k, v] of fd.entries()) {
+ if (k === "parent" || k === "tag") continue;
+ if (String(v).trim()) next.set(k, String(v).trim());
+ }
+ history.pushState({}, "", `/novels?${next}`);
+ render();
+ });
+
+ function pageLink(p) {
+ const next = new URLSearchParams(params);
+ next.set("page", String(p));
+ return `/novels?${next}`;
+ }
+}
+
+async function renderGenres() {
+ const genres = asGenreTree(await api("/api/genres?tree=true"));
+ state.genreTree = genres;
+ app.innerHTML = `
+
${t("genres.title")}
+
+ ${genres
+ .map(
+ (g) => `
+ ${escapeHtml(g.name)}
+ ${escapeHtml(g.description || t("genres.explore"))}
+
+ `
+ )
+ .join("")}
+
`;
+}
+
+async function renderNovel(slug) {
+ const [novel, chapters] = await Promise.all([
+ api(`/api/novels/${encodeURIComponent(slug)}`),
+ api(`/api/novels/${encodeURIComponent(slug)}/chapters`),
+ ]);
+ const first = chapters[0];
+ app.innerHTML = `
+
+
+
+
${escapeHtml(novel.title)}
+
${t("common.by")} ${escapeHtml(novel.author || t("common.unknown"))} · ★ ${Number(novel.rating || 0).toFixed(1)} · ${formatViews(novel.views)}
+ ${badges(novel)}
+
${escapeHtml(novel.synopsis || "")}
+
+
+
+
`;
+}
+
+async function renderRead(novelSlug, chapterSlug) {
+ const chapter = await api(
+ `/api/novels/${encodeURIComponent(novelSlug)}/chapters/${encodeURIComponent(chapterSlug)}`
+ );
+ document.title = `${chapter.title} · ${chapter.novelTitle} · Full Story Novel`;
+ app.innerHTML = `
+
+
+ ${t("novel.chapter")} ${chapter.chapterNumber}: ${escapeHtml(chapter.title)}
+ ${escapeHtml(chapter.content)}
+
+ `;
+ window.scrollTo({ top: 0, behavior: "smooth" });
+}
+
+/** Public download-info;未上架时回退站内 APK 镜像(不暴露内部仓库)。 */
+const APP_DOWNLOAD = {
+ infoUrl: "https://admin.wyrs365.com/api/public/novel-reader/download-info",
+ localApk: "/downloads/FullStoryNovel-release.apk",
+ packageName: "wf.wyrs.com",
+};
+
+async function resolveAndroidApkUrl() {
+ try {
+ const res = await fetch(APP_DOWNLOAD.infoUrl, { credentials: "omit", cache: "no-store" });
+ if (res.ok) {
+ const json = await res.json();
+ const data = json && json.data ? json.data : json;
+ if (data && data.releaseApkOnShelf && data.releaseApkUrl) {
+ return { url: data.releaseApkUrl, source: "admin", name: data.releaseApkFileName || "FullStoryNovel.apk" };
+ }
+ if (data && data.appStoreOnShelf && data.appStoreUrl) {
+ return { url: data.appStoreUrl, source: "store", name: "App Store" };
+ }
+ }
+ } catch (_) {
+ /* fall through */
+ }
+ try {
+ const local = await fetch(APP_DOWNLOAD.localApk, { method: "HEAD", cache: "no-store" });
+ if (local.ok) {
+ return { url: APP_DOWNLOAD.localApk, source: "site", name: "FullStoryNovel-release.apk" };
+ }
+ } catch (_) {
+ /* fall through */
+ }
+ return {
+ url: APP_DOWNLOAD.localApk,
+ source: "site",
+ name: "FullStoryNovel-release.apk",
+ };
+}
+
+function ensureDownloadFonts() {
+ if (document.getElementById("fsn-dl-fonts")) return;
+ const link = document.createElement("link");
+ link.id = "fsn-dl-fonts";
+ link.rel = "stylesheet";
+ link.href =
+ "https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=Syne:wght@600;700;800&display=swap";
+ document.head.appendChild(link);
+}
+
+async function renderDownload() {
+ ensureDownloadFonts();
+ document.body.classList.add("page-download");
+ document.title = `${t("download.title")} · Full Story Novel`;
+ app.innerHTML = `
+
+
+
+
+
+
Full Story Novel
+
+ ${t("download.platform")}
+ ${t("download.title")}
+ ${t("download.lead")}
+
+ ${t("download.resolving")}
+
+
+ ${t("download.feature1")}
+ ${t("download.feature2")}
+ ${t("download.feature3")}
+
+
+ ${t("download.hint1")}
+ ${t("download.hint2")}
+ ${t("download.hint3")}
+
+
+ `;
+
+ const primary = document.getElementById("dl-primary");
+ const status = document.getElementById("dl-status");
+ const meta = document.getElementById("dl-meta");
+ const resolved = await resolveAndroidApkUrl();
+ if (primary) {
+ primary.href = resolved.url;
+ if (resolved.source === "store") primary.setAttribute("target", "_blank");
+ }
+ if (status) status.textContent = t("download.ready");
+ if (meta) {
+ meta.hidden = true;
+ meta.textContent = resolved.name || "";
+ }
+}
+
+async function render() {
+ const route = parseRoute();
+ document.title = "Full Story Novel";
+ document.body.classList.toggle("page-download", route.name === "download");
+ syncNavActive();
+ app.innerHTML = `
${t("common.loading")}
`;
+ try {
+ if (route.name === "home") await renderHome();
+ else if (route.name === "novels") await renderNovels();
+ else if (route.name === "genres") await renderGenres();
+ else if (route.name === "download") await renderDownload();
+ else if (route.name === "novel") await renderNovel(route.slug);
+ else if (route.name === "read") await renderRead(route.novelSlug, route.chapterSlug);
+ else await renderHome();
+ } catch (err) {
+ app.innerHTML = `
${t("common.failed")}: ${escapeHtml(err.message)}
`;
+ }
+ syncNavActive();
+}
+
+document.getElementById("search-form").addEventListener("submit", (e) => {
+ e.preventDefault();
+ const q = document.getElementById("search-input").value.trim();
+ history.pushState({}, "", q ? `/novels?q=${encodeURIComponent(q)}` : "/novels");
+ render();
+});
+
+document.addEventListener("click", (e) => {
+ const a = e.target.closest("a");
+ if (!a) return;
+ const href = a.getAttribute("href");
+ if (!href || href.startsWith("http") || href.startsWith("#") || a.target === "_blank") return;
+ if (href === "/privacy" || href === "/terms" || href === "/delete") return;
+ e.preventDefault();
+ history.pushState({}, "", href);
+ render();
+});
+
+window.addEventListener("popstate", render);
+initPrefs();
+initMobileNav();
+render();
+
+function initMobileNav() {
+ const topbar = document.querySelector(".topbar");
+ const toggle = document.getElementById("nav-toggle");
+ const nav = document.getElementById("site-nav");
+ if (!topbar || !toggle || !nav) return;
+
+ const setOpen = (open) => {
+ topbar.classList.toggle("is-nav-open", open);
+ toggle.setAttribute("aria-expanded", open ? "true" : "false");
+ };
+
+ toggle.addEventListener("click", () => {
+ setOpen(!topbar.classList.contains("is-nav-open"));
+ });
+
+ nav.addEventListener("click", (e) => {
+ if (e.target.closest("a")) setOpen(false);
+ });
+
+ const appDl = document.getElementById("app-dl-link");
+ if (appDl) {
+ appDl.addEventListener("click", () => setOpen(false));
+ }
+
+ document.addEventListener("click", (e) => {
+ if (!topbar.contains(e.target)) setOpen(false);
+ });
+
+ window.addEventListener("resize", () => {
+ if (window.matchMedia("(min-width: 901px)").matches) setOpen(false);
+ });
+}
+
+function syncNavActive() {
+ const path = location.pathname.replace(/\/+$/, "") || "/";
+ document.querySelectorAll("#site-nav a, #app-dl-link").forEach((a) => {
+ const href = (a.getAttribute("href") || "").replace(/\/+$/, "") || "/";
+ let active = false;
+ if (href === "/") active = path === "/" || path === "";
+ else if (href === "/novels") active = path === "/novels" || path.startsWith("/novel/");
+ else if (href === "/genres") active = path === "/genres";
+ else if (href === "/download") active = path === "/download" || path === "/app";
+ a.classList.toggle("active", active);
+ });
+}
diff --git a/fullstorynovel-web/delete/index.html b/fullstorynovel-web/delete/index.html
new file mode 100644
index 0000000..83b94a6
--- /dev/null
+++ b/fullstorynovel-web/delete/index.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
注销 — Full Story Novel
+
+
+
+
+
+
+
+
+
+
+ 注销账号
+ 在 Fullstorynovel 应用里注销。本网站没有单独的注销表单。
+ 在应用里怎么做
+
+ 打开 Fullstorynovel,进入「设置」。
+ 在「账号与安全」中点「注销账号」。还没登录时,应用会提示「请先登录后再注销账号」。
+ 页面会显示当前绑定的邮箱。先点「获取验证码」,验证码发到这个邮箱,再把验证码填进去。应用内的说明是:请先向绑定邮箱获取验证码,再确认注销;测试账号可以不填写验证码。
+ 点「确认注销」。应用会再问一次「确定注销账号?」,并说明此操作不可撤销,注销后将退出登录。
+
+ 提交之后会发生什么
+ 普通账号必须先通过发到绑定邮箱的验证码。通过后,服务器会让该账号的登录失效,并清除好友关系、会话以及相关联的账号数据,再删除这个正在使用的账号。应用内的说明是:注销后账号将被永久删除,这些数据一并清除且无法恢复。原来的邮箱可以重新注册,但历史数据不会找回。
+ 注销成功后,应用会清掉本机保存的登录状态。保存在本机的书籍和阅读进度不会随这次注销自动删掉。
+ 相关页面
+ 返回首页 · 隐私政策 · 用户协议
+
+
+
+
+
diff --git a/fullstorynovel-web/nginx-legal.snippet b/fullstorynovel-web/nginx-legal.snippet
new file mode 100644
index 0000000..dc7e3df
--- /dev/null
+++ b/fullstorynovel-web/nginx-legal.snippet
@@ -0,0 +1,32 @@
+# Insert inside the fullstorynovel.com :8443 server, before "location /" that proxies to 127.0.0.1:8095.
+# BEGIN fsn-site-js
+location = /assets/js/site.js {
+ root /opt/fullstorynovel/static-override;
+ try_files /assets/js/site.js =404;
+ add_header Cache-Control "no-cache";
+}
+# END fsn-site-js
+# BEGIN fsn-home-shell
+location = / {
+ root /opt/fullstorynovel/static-override;
+ try_files /public-index.html =404;
+ add_header Cache-Control "no-cache";
+}
+# END fsn-home-shell
+# BEGIN fsn-legal-pages
+location = /privacy {
+ root /opt/fullstorynovel/static-override;
+ try_files /privacy/index.html =404;
+ add_header Cache-Control "no-cache";
+}
+location = /terms {
+ root /opt/fullstorynovel/static-override;
+ try_files /terms/index.html =404;
+ add_header Cache-Control "no-cache";
+}
+location = /delete {
+ root /opt/fullstorynovel/static-override;
+ try_files /delete/index.html =404;
+ add_header Cache-Control "no-cache";
+}
+# END fsn-legal-pages
diff --git a/fullstorynovel-web/privacy/index.html b/fullstorynovel-web/privacy/index.html
new file mode 100644
index 0000000..7bf3d29
--- /dev/null
+++ b/fullstorynovel-web/privacy/index.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
隐私政策 — Full Story Novel
+
+
+
+
+
+
+
+
+
+
+引言 本政策包含以下内容:
一、我们如何收集和使用您的个人信息及其他信息
二、我们如何使用 Cookie 和同类技术
三、合法共享、转让、公开披露您个人信息的情形
四、我们如何安全地保护和保存您提供的信息
五、您如何访问和控制自己提供的个人信息
六、未成年人的个人信息保护
七、通知和修订
八、适用法律与争议解决
九、如何联系我们
特别提示 1、感谢您对 FullStoryNovel 软件的使用及信任,我们将持续致力于为您提供更加安全可靠的服务。
2、FullStoryNovel 软件平台所有的产品和/或服务均适用本隐私政策。
3、前述特定产品和/或服务的隐私政策构成本隐私政策的一部分,如与本隐私政策有不一致之处,以特定产品和/或服务的隐私政策为准。
4、除非本隐私政策另有明确所指,本隐私政策不适用于通过我们的产品和/或服务而接入的由第三方独立为您提供的产品和/或服务的情形。
5、本隐私政策仅适用于 14 周岁以上的用户,如果您是不满 14 周岁的儿童,请立即停止对本隐私政策的阅读和任何其他操作。
定义 1、【个人信息】个人信息是指以电子或者其他方式记录的能够单独或者与其他信息结合识别特定自然人身份或者反映特定自然人活动情况的各种信息。
2、【个人敏感信息】个人敏感信息是指一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等的个人信息。
一、我们如何收集和使用您的个人信息及其他信息 我们仅会出于以下合法目的,收集和使用您的个人信息及其他信息:
(一)您授权我们收集和使用您个人信息及其他信息的情形 我们的产品和/或服务包括一些特定业务功能和附加功能,这些功能包含了小说阅读、书签、阅读进度、护眼模式、小组件、网络媒体、互联网增值和广告等 FullStoryNovel 软件所提供的服务所必须的功能。
【友盟+移动统计SDK】SDK 名称:友盟+移动统计SDK;开发者:友盟同欣(北京)科技有限公司;收集信息范围:设备标识信息(含 Android ID/OAID 等)、IP 地址、网络状态、应用启动/停止时间等;目的:统计分析、基础反作弊;SDK 隐私政策链接:https://www.umeng.com/page/policy
【设备信息】为了保障您正常使用本产品和/或服务,我们会收集设备属性信息及连接信息。
【日志信息】我们的服务器可能会自动记录 IP 地址、语言、下载安装信息及服务日志等。
【相机/摄影机权限】您可在打开相机/摄影机权限后使用该功能进行主体更换、拍照发帖、修改个人头像等功能。
【取得已安装应用进程清单】服务跳转到其他应用之前,需要检测目标应用是否存在。
【加速度传感器】通过传感器信息检测屏幕方向,进行横竖屏切换。
以上信息均采用匿名的方式进行收集和保存,同时我们也会对信息采取加密处理。
【第三方 SDK 信息共享清单】 为实现统计分析、广告展示等功能,我们在取得您的同意后接入以下第三方 SDK。下列 SDK 名称、开发者、使用目的、收集个人信息范围、SDK 隐私政策链接与全国 SDK 管理服务平台(https://sdk.caict.ac.cn/official/#/home)登记信息保持一致。第三方 SDK 收集和处理信息等行为遵守其自身的隐私条款,我们可能会调整接入的第三方 SDK 并更新本目录。
(二)我们从第三方获得您个人信息及其他信息的情形 【第三方信息】为共同向您提供产品/服务,我们可能从关联公司、合作伙伴及其他受信任的第三方接收您的个人信息及其他信息。
(三)您个人信息及其他信息使用的规则 我们会根据法律规定及本隐私政策的约定并为实现我们的产品和/或服务功能对所收集的个人信息及其他信息进行合法的使用。
二、我们如何使用 Cookie 和同类技术 Cookies 的使用 1、为实现您联机体验,我们会在您的电脑或行动设备上发送 Cookies 以简化重复登录步骤并帮助判断登录状态。
2、我们不会将 Cookies 用于本隐私政策所述目的之外的任何用途。您可根据偏好管理或删除 Cookies。
三、合法共享、转让、公开披露您个人信息的情形 (一)共享 我们不会与 FullStoryNovel 软件及其关联公司以外的任何公司、组织和个人共享您的个人信息,但法律另有规定或取得您同意的除外。
(二)转让 我们不会将您的个人信息转让给任何公司、组织和个人,但取得同意或法律要求等情形除外。
(三)公开披露 我们仅会在取得您同意或法律要求的情况下,采取符合业界标准的安全防护措施公开披露您的个人信息。
(四)对第三方责任的声明 【第三方服务】请您注意,通过我们接入的第三方可能有自己的隐私权保护政策,建议您仔细查看第三方《隐私声明》及《服务协议》。
四、我们如何安全地保护和保存您提供的信息 (一)信息的保存地点 我们在中华人民共和国境内收集和产生的个人信息,保存在中华人民共和国境内。FullStoryNovel 软件不会向境外提供或保存个人信息。
(二)信息的保存期限 我们仅为实现服务目的所必需的时间保留您的个人信息。
(三)我们保护您个人信息的技术与措施 我们非常重视个人信息安全,并采取一切合理可行的措施保护您的个人信息,包括加密传输、访问控制及员工培训等。
FullStoryNovel 软件的网络服务采用了传输层安全协议等加密技术,通过 https 等方式提供安全服务。
五、您如何访问和控制自己提供的个人信息 1、您对自己的个人信息可行使访问、更正、删除等权利。
2、您可通过 FullStoryNovel 软件登录帐户查阅及修改个人信息。
3、我们将在验证身份后五个工作日内处理您的请求。
4、在法定情形下,我们可能无法回应您的部分请求。
六、未成年人的个人信息保护 1、若您是未满18周岁的未成年人,您应在监护人监护、指导下并取得监护人同意的情况下使用 FullStoryNovel 软件及相关服务。
2、我们重视对未成年人个人信息的保护。
3、我们为未成年人提供青少年模式,监护人应为未成年人选择使用青少年模式。
4、监护人应指导未成年人合理学习使用网络,避免沉迷虚拟空间。
七、通知和修订 1、为给您提供更好的服务,本隐私政策也会不定时更新,更新后将在 App 内公告或以其他适当方式提醒您。
2、如发生重大变更,我们将采取更具有提示作用的方式告知您。
3、若您继续使用我们的产品和/或服务,即表示您同意受修订后的本隐私政策的约束。
八、适用法律与争议解决 1、【法律适用】本隐私政策的运行、解释和争议的解决均适用中华人民共和国法律。
2、【争议解决】您和 FullStoryNovel 就本隐私政策内容或其运行发生任何争议的,双方应友好协商解决。
九、如何联系我们 如您对本隐私政策或您个人信息的相关事宜有任何问题、意见或建议,请通过电子邮件联系我们,电子邮箱地址为 asd272940236@foxmail.com
账号注销不在本网站提交。iOS 版的入口、邮箱验证码和删除范围见注销 页。
+
+ 返回首页 · 用户协议 · 注销
+
+
+
+
+
diff --git a/fullstorynovel-web/public-index.html b/fullstorynovel-web/public-index.html
new file mode 100644
index 0000000..ec88208
--- /dev/null
+++ b/fullstorynovel-web/public-index.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
Full Story Novel
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading…
+
+
+
+
+
+
+
+
diff --git a/fullstorynovel-web/terms/index.html b/fullstorynovel-web/terms/index.html
new file mode 100644
index 0000000..bb71f64
--- /dev/null
+++ b/fullstorynovel-web/terms/index.html
@@ -0,0 +1,79 @@
+
+
+
+
+
+
用户协议 — Full Story Novel
+
+
+
+
+
+
+
+
+
+
+一、导言 上海微雨如酥网络设计有限公司(以下简称「本公司」或「我们」)在此特别提醒您认真阅读、充分理解本《软件服务协议》(以下简称「本协议」):
1、本协议是您与 上海微雨如酥网络设计有限公司 之间关于您登录、使用「FullStoryNovel 软件」(下称「本软件」)服务所订立的协议。本协议描述本公司与您之间关于使用本软件所提供相关服务的权利义务,请仔细阅读本服务条款。
2、以下声明和本协议中,服务是指本公司现在或将来向用户提供的包括但不限于小说阅读、书签、阅读进度、护眼模式、小组件、网络媒体、互联网增值和广告等产品及服务(以下简称「服务」)。「用户」是指登录、使用、浏览本服务的个人或组织,本协议中更多的称为「您」。
3、您访问本站并下载 FullStoryNovel app 后,即表示您同意接受本服务协议的约束,而本服务协议即构成对双方具有约束力的法律文档。
二、服务协议的确认及接受 本站的各项电子服务的所有权和运作权归我们所有。您同意服务条款及隐私条款后,即成为本站的正式用户。用户确认:本服务条款是处理双方权利义务的契约,始终有效,法律另有强制性规定或双方另有特别约定的,依其规定。
1、【审慎阅读】请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款、法律适用和争议解决条款。
2、本协议签署后,您如有任何需要本公司说明条款的要求,请立即停止使用服务,同时立即致电或发送邮件至本公司客服。
3、您的登录、使用等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。
4、如果您未满18周岁,请在法定监护人的陪同下阅读本用户服务条款,并在使用本服务前取得监护人的同意。
5、本公司保留在中华人民共和国大陆地区现行法律法规允许的范围内自行决定拒绝服务、关闭用户帐号、清除或编辑内容或取消订单等的权利。
6、本软件的软件着作权及 App 上发布的所有信息与内容的版权均受着作权法保护。上海微雨如酥网络设计有限公司 保留所有未在本服务条款中明确授予的权利。
7、【服务协议的修改】根据国家法律法规的更新及网站营运需要,我们有权对本条款不时地进行修改。
三、软件的取得与更新 1、您可以直接从 FullStoryNovel 软件的官方网站上或从得到本公司授权的第三方取得本软件。
2、【从未授权第三方取得】如果您从未经本公司授权的第三方取得本软件,本公司无法保证该软件能够正常使用。
3、为了改善用户体验、完善服务内容,本公司将不断努力开发新的服务,并为您不时提供软件更新。
四、服务方式 1、除免费服务外,本软件可能提供部分收费服务。对于收费服务,本软件会在您使用之前给予明确的提示。
2、您应了解本软件可能对该等服务进行更改、更新或提高,并承诺不因服务更改而要求赔偿。
3、商品或服务价格、数量、性能介绍、是否有货等商品信息随时都有可能发生变动。
4、为回馈用户的支持,我们会不定期向用户发放一些优惠券或代金券。
5、若您在商品购买过程中遇到任何问题,均可发送邮件至 asd272940236@foxmail.com,我们的客服人员会及时与您取得联系并帮助您解决问题。
6、您同意,遵守法律及本协议规定,秉承善意使用本软件,且保证不会利用本软件进行非法活动或侵犯他人权利。
五、服务规则 1、您充分了解并同意,本软件仅是您提供信息的分享、发送及取得的平台,您必须为自己帐号下的一切行为负责。
2、您使用本软件服务发布或发送的任何内容并不代表或暗示本公司的观点或政策。
3、您须对在本软件上所发送信息的真实性、合法性、有效性等负全部责任。
4、本公司因业务发展需要,可能对本软件的全部或部分服务进行变更、暂停、限制、终止或撤销。
5、【广告、信息及相关服务】本软件提供的服务中可能包含广告、信息等内容。
6、您使用本软件应当遵守宪法法律,遵守公共秩序,尊重社会公德。
7、除非法律允许或本公司书面许可,您使用本服务过程中不得从事干扰本软件正常营运的行为。
8、本公司可依法停止传输违反法律法规或本协议约定的内容,并有权采取适当的法律行动。
9、本服务的所有权和运作权归本公司。
10、本协议未书面明示授权的其他一切权利仍归本公司所有。
11、【第三方服务】您在本公司软件平台上使用第三方提供的产品或服务时,除遵守本协议约定外,还应遵守第三方的用户协议。
六、您的权利与义务 1、本软件帐号的所有权归本公司所有,您获得本软件帐号的使用权。
2、您应当妥善保管帐号信息及帐号密码安全。
3、您应遵守本协议的各项条款,合法、正确、适当地使用本服务。
4、为保证 FullStoryNovel 软件的适用性以及您的使用体验,请您及时下载最新版本并升级。
七、隐私保护政策 1、保护用户个人信息是本公司的一项基本原则。本公司将按照本协议及《FullStoryNovel 软件隐私权政策》的规定合法收集、使用、安全保存您的个人信息。
2、您在使用本服务的过程中,可能需要填写一些必要的信息。
3、尊重用户个人隐私是本软件的一项基本政策。
4、我们从第三方获得您个人信息及其他信息的情形,均应符合法律法规规定。
5、您个人信息及其他信息使用的规则,均应以《隐私权政策》为准。
八、附则 1、本公司郑重提醒您注意本协议中免除本公司责任和加重您义务的条款,请您仔细阅读,自主考虑风险。
2、如本协议中的任何条款无论因何种原因完全或部分无效或不具有运行力,本协议的其余条款仍应有效并且有运行力。
3、本协议中的标题仅为方便而设,不具有法律效力。
4、【法律适用】本协议的解释、效力及纠纷的解决,适用中华人民共和国法律。
5、【争议解决】若您和本公司之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,您同意将纠纷或争议提交本公司所在地有管辖权的人民法院通过诉讼方式解决。
6、您同意,如因您违反法律规定或本协议规定给本软件造成损失,您将充分赔偿我们所遭受的损失。
若您对本协议及本软件服务有任何意见,欢迎联系本公司客服部门,电子邮箱地址为 asd272940236@foxmail.com
+ 返回首页 · 隐私政策 · 注销
+
+
+
+
+
diff --git a/health-web/assets/icon.png b/health-web/assets/icon.png
new file mode 100644
index 0000000..253f14c
Binary files /dev/null and b/health-web/assets/icon.png differ
diff --git a/health-web/assets/site.css b/health-web/assets/site.css
new file mode 100644
index 0000000..101adc9
--- /dev/null
+++ b/health-web/assets/site.css
@@ -0,0 +1,210 @@
+:root {
+ --bg: #07111f;
+ --bg-2: #10233d;
+ --card: rgba(255, 255, 255, 0.06);
+ --line: rgba(255, 255, 255, 0.14);
+ --text: #f4f7fb;
+ --muted: #b7c4d6;
+ --gold: #f6c453;
+ --heart: #e23d4a;
+ --cyan: #8ec8ff;
+ --shadow: 0 18px 50px rgba(0, 0, 0, 0.28);
+}
+
+* { box-sizing: border-box; }
+
+html { scroll-behavior: smooth; }
+
+body {
+ margin: 0;
+ min-height: 100vh;
+ color: var(--text);
+ background:
+ radial-gradient(900px 420px at 85% -10%, rgba(246, 196, 83, 0.16), transparent 60%),
+ radial-gradient(700px 380px at -10% 20%, rgba(226, 61, 74, 0.16), transparent 55%),
+ linear-gradient(180deg, var(--bg-2), var(--bg) 42%);
+ font-family: "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", "Microsoft YaHei", sans-serif;
+ line-height: 1.65;
+ overflow-x: hidden;
+}
+
+img { max-width: 100%; height: auto; display: block; }
+
+a { color: var(--cyan); }
+
+.wrap {
+ width: min(1040px, calc(100% - 32px));
+ margin: 0 auto;
+}
+
+.top {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+ background: rgba(7, 17, 31, 0.86);
+ backdrop-filter: blur(14px);
+ border-bottom: 1px solid var(--line);
+}
+
+.top-inner, .foot-inner {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 10px 18px;
+ padding: 12px 0;
+}
+
+.brand {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ color: var(--text);
+ text-decoration: none;
+ font-weight: 700;
+ letter-spacing: 0.01em;
+ min-width: 0;
+}
+
+.brand img {
+ width: 40px;
+ height: 40px;
+ border-radius: 12px;
+ flex: 0 0 auto;
+}
+
+.nav, .foot-links {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px 14px;
+ margin-left: auto;
+ max-width: 100%;
+}
+
+.nav a, .foot-links a {
+ color: var(--text);
+ text-decoration: none;
+ padding: 6px 0;
+ white-space: nowrap;
+}
+
+.nav a[aria-current="page"], .foot-links a[aria-current="page"] {
+ color: var(--gold);
+ font-weight: 700;
+}
+
+main { padding: 28px 0 48px; }
+
+.hero, .panel, .card {
+ background: var(--card);
+ border: 1px solid var(--line);
+ border-radius: 22px;
+ box-shadow: var(--shadow);
+}
+
+.hero {
+ display: grid;
+ grid-template-columns: 148px minmax(0, 1fr);
+ gap: 22px;
+ align-items: center;
+ padding: 28px;
+}
+
+.hero img {
+ width: 148px;
+ height: 148px;
+ border-radius: 32px;
+}
+
+h1, h2, h3 { line-height: 1.3; margin: 0 0 0.4em; }
+
+h1 { font-size: clamp(1.7rem, 4vw, 2.4rem); }
+
+.lead { color: var(--muted); margin: 0 0 1rem; font-size: 1.05rem; }
+
+.actions { display: flex; flex-wrap: wrap; gap: 10px; }
+
+.btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 42px;
+ padding: 8px 16px;
+ border-radius: 999px;
+ text-decoration: none;
+ border: 1px solid transparent;
+}
+
+.btn-primary { background: var(--heart); color: white; font-weight: 700; }
+.btn-ghost { color: var(--text); border-color: var(--line); background: rgba(255, 255, 255, 0.04); }
+
+.note {
+ margin-top: 16px;
+ color: var(--gold);
+ font-size: 0.95rem;
+}
+
+.section { margin-top: 28px; }
+
+.grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 14px;
+}
+
+.card { padding: 16px 16px 18px; min-width: 0; }
+.card h2, .card h3 { font-size: 1.05rem; }
+.card p, .panel p, .panel li { color: var(--muted); }
+.card p { margin: 0; }
+
+.panel { padding: 22px 22px 8px; overflow-wrap: anywhere; }
+.panel h1 { margin-bottom: 0.3em; }
+.panel .meta { color: var(--muted); margin-top: 0; }
+.panel h2 { font-size: 1.08rem; margin-top: 1.3rem; }
+.panel h3 { font-size: 1rem; margin-top: 1rem; }
+.panel ul, .panel ol { padding-left: 1.2rem; }
+.steps { counter-reset: step; list-style: none; padding-left: 0; }
+.steps li {
+ position: relative;
+ padding: 10px 10px 10px 46px;
+ margin: 0 0 10px;
+ background: rgba(255, 255, 255, 0.04);
+ border-radius: 14px;
+ color: var(--text);
+}
+.steps li::before {
+ counter-increment: step;
+ content: counter(step);
+ position: absolute;
+ left: 10px;
+ top: 10px;
+ width: 26px;
+ height: 26px;
+ border-radius: 50%;
+ background: var(--heart);
+ color: white;
+ display: grid;
+ place-items: center;
+ font-size: 0.85rem;
+ font-weight: 700;
+}
+
+.foot {
+ border-top: 1px solid var(--line);
+ color: var(--muted);
+}
+
+.foot strong { color: var(--text); }
+.foot p { margin: 4px 0 0; }
+
+@media (max-width: 800px) {
+ .grid { grid-template-columns: 1fr; }
+ .nav, .foot-links { margin-left: 0; width: 100%; }
+}
+
+@media (max-width: 420px) {
+ .wrap { width: min(1040px, calc(100% - 24px)); }
+ .hero { grid-template-columns: 1fr; padding: 18px; }
+ .hero img { width: 96px; height: 96px; border-radius: 24px; }
+ .panel { padding: 16px 14px 6px; }
+ .actions .btn { width: 100%; }
+}
diff --git a/health-web/delete/index.html b/health-web/delete/index.html
new file mode 100644
index 0000000..427ef95
--- /dev/null
+++ b/health-web/delete/index.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
注销 — Sleep Heart
+
+
+
+
+
+
+
+
+
+ 注销账号
+ 注销在 Sleep Heart 应用里完成。本网站不提供在线注销表单。
+ 入口
+ 需要先登录。未登录时,「设置」里不会出现「账号与安全」。
+
+ 打开底部「我的」。
+ 进入「设置」。
+ 进入「账号与安全」。
+ 点「注销账号」。
+
+ 确认
+ 应用会先询问「确认注销账号?」。说明文字是:注销将清除本机账号数据并退出登录,此操作不可撤销。随后会再询问「再次确认注销」,说明将清除本机昵称和头像并退出登录。两步都会同时提示:退出登录或注销应用账号不会取消 Apple 订阅。
+ 确认之后会发生什么
+
+ 清除这台设备上该账号的昵称、头像和会员标记,并退出登录。
+ 如果当时还持有登录凭证,应用会尝试通知服务器结束当前登录会话。
+ 当前应用代码不会向服务器提交永久删除账号。
+ 不会取消 Apple 订阅。若要停止续费,请在 iPhone 的「设置」里打开顶部 Apple 账户,进入「订阅」,选择 SleepHeart 中要停止续费的项目。
+
+ 也可以在「我的」里提交「意见反馈」,或发邮件到 asd272940236@foxmail.com 。
+ 返回首页
+
+
+
+
+
+
diff --git a/health-web/download/index.html b/health-web/download/index.html
new file mode 100644
index 0000000..1b1fe4e
--- /dev/null
+++ b/health-web/download/index.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+
下载 — Sleep Heart
+
+
+
+
+
+
+
+
+
+ 下载
+ Sleep Heart 是 iPhone 应用,应用内展示名为 SleepHeart。
+ 应用即将上线。目前没有已核实、可以公开打开的 App Store 或安卓应用市场地址,本页不放置商店链接。
+ 上架之后,请在 App Store 按应用名 SleepHeart 查找。请从本站公布的正式地址或 Apple 的商店页面安装,不要从未经授权的来源安装安装包。
+ 返回首页
+
+
+
+
+
+
diff --git a/health-web/index.html b/health-web/index.html
new file mode 100644
index 0000000..a4e5084
--- /dev/null
+++ b/health-web/index.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
Sleep Heart
+
+
+
+
+
+
+
+
+
+
+
+
Sleep Heart
+
在这台 iPhone 上查看夜间声音环境、估算指尖心率,并记下你自己填写的日常健康数字。可以听助眠音乐,按节奏做呼吸练习,登录后也可以在广场发帖。
+
+
测量和监测结果只供个人参考,不是医疗诊断,不能代替血压计、血糖仪、血氧仪、体温计或就医。
+
+
+
+
+ 可以做什么
+
+
+ 音乐
+ 播放助眠内容。场景包括自然白噪、深度冥想、呼吸疗愈、治愈乐器和脑波音乐。播放方式有顺序、随机、循环和勾选播放。
+
+
+ 心率
+ 用后置相机和闪光灯做指尖光学估算。画面在本机处理,不会上传。同一页可以手填体重、步数、血压、血糖、经期、血氧、体温和饮水。
+
+
+ 睡眠
+ 打开监测后使用麦克风,在本机识别夜间声音并保存可回放的短片段。录音和识别结果只留在这台 iPhone,不会上传。
+
+
+ 发现
+ 进入广场和呼吸训练。呼吸练习有箱式、4-7-8、舒缓吸呼和共振四种节奏,可以静音,也可以用喜欢的音乐做背景。
+
+
+ 我的
+ 管理账号、会员、主题、语言和意见反馈。已登录后,注销入口在「设置」里的「账号与安全」。
+
+
+ 会员
+ 会员音频可完整播放并收藏,本地音频导入不限数量,指尖心率测量不限次数。不购买也可以使用免费音频、本机健康记录、睡眠声监测和呼吸训练。
+
+
+
+
+
+
+
+
diff --git a/health-web/nginx/health.wyrs365.com.conf b/health-web/nginx/health.wyrs365.com.conf
new file mode 100644
index 0000000..7520f07
--- /dev/null
+++ b/health-web/nginx/health.wyrs365.com.conf
@@ -0,0 +1,74 @@
+# Sleep Heart website — health.wyrs365.com
+# Public :443 is stream ssl_preread (stream.d/spark-sni.conf, default → 127.0.0.1:8443).
+# TLS terminates on loopback :8443. Certificate is this name only.
+
+server {
+ listen 80;
+ listen [::]:80;
+ server_name health.wyrs365.com;
+
+ location /.well-known/acme-challenge/ {
+ root /var/www/certbot;
+ }
+
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ listen 127.0.0.1:8443 ssl proxy_protocol;
+ listen [::1]:8443 ssl proxy_protocol;
+ http2 on;
+ server_name health.wyrs365.com;
+
+ ssl_certificate /etc/letsencrypt/live/health.wyrs365.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/health.wyrs365.com/privkey.pem;
+ ssl_session_timeout 1d;
+ ssl_session_cache shared:HealthSSL:10m;
+
+ add_header Strict-Transport-Security "max-age=31536000" always;
+ add_header X-Content-Type-Options nosniff always;
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
+
+ root /var/www/health.wyrs365.com;
+ index index.html;
+ charset utf-8;
+
+ location = /favicon.ico {
+ try_files /assets/icon.png =404;
+ access_log off;
+ expires 7d;
+ }
+
+ location /assets/ {
+ expires 7d;
+ add_header Cache-Control "public";
+ try_files $uri =404;
+ }
+
+ location = /download {
+ try_files /download/index.html =404;
+ }
+
+ location = /delete {
+ try_files /delete/index.html =404;
+ }
+
+ location = /privacy {
+ try_files /privacy/index.html =404;
+ }
+
+ location = /terms {
+ try_files /terms/index.html =404;
+ }
+
+ location = /download/ { return 301 /download$is_args$args; }
+ location = /delete/ { return 301 /delete$is_args$args; }
+ location = /privacy/ { return 301 /privacy$is_args$args; }
+ location = /terms/ { return 301 /terms$is_args$args; }
+
+ location / {
+ try_files $uri $uri/ /index.html;
+ }
+}
diff --git a/health-web/privacy/index.html b/health-web/privacy/index.html
new file mode 100644
index 0000000..e0ac8d3
--- /dev/null
+++ b/health-web/privacy/index.html
@@ -0,0 +1,141 @@
+
+
+
+
+
+
隐私协议 — Sleep Heart
+
+
+
+
+
+
+
+
+
+ Sleep Heart 软件隐私权政策
+ 适用于 Sleep Heart 网站(health.wyrs365.com)及 Sleep Heart 应用。
+ 上海微雨如酥网络设计有限公司(以下简称「本公司」或「我们」)非常重视用户个人信息及隐私权的保护,因此我们制订了涵盖如何收集、存储、使用、共享和保护用户信息以及访问、更新、删除和保护这些信息方式的隐私政策。
+ 本版本发布时间:2026年10月2日
+
+ 引言
+ 本政策包含以下内容:
+ 一、我们如何收集和使用您的个人信息及其他信息
+ 二、我们如何使用 Cookie 和同类技术
+ 三、合法共享、转让、公开披露您个人信息的情形
+ 四、我们如何安全地保护和保存您提供的信息
+ 五、您如何访问和控制自己提供的个人信息
+ 六、未成年人的个人信息保护
+ 七、通知和修订
+ 八、适用法律与争议解决
+ 九、如何联系我们
+
+ 特别提示
+ 1、感谢您对 Sleep Heart 的使用及信任,我们将持续致力于为您提供更加安全可靠的服务。
+ 2、Sleep Heart 的产品和/或服务适用本隐私政策。
+ 3、若某一功能另有说明,该说明构成本隐私政策的一部分;如有不一致,以该功能的说明为准。
+ 4、除非本隐私政策另有明确所指,本隐私政策不适用于通过我们的产品和/或服务而接入的由第三方独立为您提供的产品和/或服务。
+ 5、本隐私政策仅适用于 14 周岁以上的用户。如果您是不满 14 周岁的儿童,请立即停止对本隐私政策的阅读和任何其他操作。
+
+ 定义
+ 1、【个人信息】个人信息是指以电子或者其他方式记录的能够单独或者与其他信息结合识别特定自然人身份或者反映特定自然人活动情况的各种信息。
+ 2、【个人敏感信息】个人敏感信息是指一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等的个人信息。健康相关记录可能属于此类信息。
+
+ 一、我们如何收集和使用您的个人信息及其他信息
+ 我们仅会出于以下合法目的,收集和使用您的个人信息及其他信息。
+ (一)您授权我们收集和使用您个人信息及其他信息的情形
+ Sleep Heart 提供助眠音乐、睡眠声监测、指尖心率估算、呼吸训练、健康指标记录、广场以及账号与意见反馈。测量和监测结果只供个人参考,不是医疗诊断。
+ 【会发送到服务器的信息】登录时发送邮箱、验证码或密码、设备标识 IDFV 和设备名称,用于登录和识别设备。意见反馈会发送您填写的正文、可选邮箱和应用版本。登录后在广场发布的帖子、评论、点赞、关注和举报,通过 HTTPS 发送到服务器。
+ 【只保存在这台设备上的信息】指尖测心率时的相机画面;睡眠声监测的录音和识别结果;您记录的体重、步数、血压、血糖、经期、血氧、体温和饮水;头像照片以及您导入的音乐。这些内容不会上传给我们。
+ 【Apple 健康】您若打开某一指标的「同步 Apple Health」,对应记录写入您的 Apple 健康,不会因此上传给我们。
+ 【蓝牙】只在本机连接您绑定的设备,不会因此上传扫描结果。
+ 【权限】相机、麦克风、蓝牙、相册和健康权限,只在您使用对应功能时申请。同意本政策之前,不会读取用于登录上报的设备标识,也不会提前申请这些权限。您可以拒绝这些权限,对应功能不可用,其他功能仍可使用。
+ 【我们不做的事】不使用 IDFA,不请求跨 App 跟踪,不出售个人信息。
+ 【第三方处理】
+ 会员通过 Apple 的 StoreKit 自动续期订阅处理。价格、续费和取消以 Apple 订阅管理中的显示为准。您主动打开 Apple 健康同步时,由 Apple 按其规则处理写入健康应用的记录。Sleep Heart 当前版本不接入统计类或广告类第三方 SDK,也不使用 IDFA。
+ (二)我们从第三方获得您个人信息及其他信息的情形
+ 为完成 Apple 订阅状态核对,应用会在本机读取 StoreKit 交易结果。除此之外,我们不会为了扩充档案而向其他公司购买您的个人信息。
+ (三)您个人信息及其他信息使用的规则
+ 我们会根据法律规定及本隐私政策的约定,为实现登录、意见反馈、广场互动和订阅状态展示而使用所收集的信息。
+
+ 二、我们如何使用 Cookie 和同类技术
+ 1、本网站是静态页面,不使用 Cookie 识别您。
+ 2、Sleep Heart 的登录不依赖本网站 Cookie。我们不会把 Cookie 用于本政策所述目的之外的用途。
+
+ 三、合法共享、转让、公开披露您个人信息的情形
+ (一)共享
+ 我们不会与 Sleep Heart 及其关联公司以外的任何公司、组织和个人共享您的个人信息,但法律另有规定、取得您同意,或为完成 Apple 订阅与您主动开启的 Apple 健康同步所必需的情形除外。
+ (二)转让
+ 我们不会将您的个人信息转让给任何公司、组织和个人,但取得同意或法律要求等情形除外。
+ (三)公开披露
+ 我们仅会在取得您同意或法律要求的情况下,采取符合业界标准的安全防护措施公开披露您的个人信息。您在广场主动发布的内容,会按产品功能向其他用户展示。
+ (四)对第三方责任的声明
+ Apple 订阅和 Apple 健康有各自的规则。建议您同时查看 Apple 的隐私说明与服务条款。
+
+ 四、我们如何安全地保护和保存您提供的信息
+ (一)信息的保存地点
+ 发送到服务器的账号、意见反馈和广场内容通过 HTTPS 传输并保存在我们的服务器上,用于提供相应功能。只留在设备上的测量画面、录音和手填健康数字,不会因此上传。
+ (二)信息的保存期限
+ 我们仅为实现服务目的所必需的时间保留已上传的个人信息。本机记录由您在设备上保留或清理。
+ (三)我们保护您个人信息的技术与措施
+ 我们对服务器通信使用 HTTPS。我们采取合理可行的访问控制措施保护已上传的信息。
+
+ 五、您如何访问和控制自己提供的个人信息
+ 1、您可以在应用内查看账号、反馈和广场相关内容,并在本机查看或清理只保存在设备上的记录。
+ 2、应用内注销的实际效果见注销 页:清除本机昵称、头像和会员标记并退出登录,并尝试结束当前登录会话。当前版本不会向服务器提交永久删除账号。
+ 3、您也可以通过本政策文末的邮箱提出访问、更正或删除请求。我们将在验证身份后五个工作日内处理。
+ 4、在法律要求保留,或无法验证请求人身份时,我们可能无法回应部分请求。
+
+ 六、未成年人的个人信息保护
+ 1、若您是未满 18 周岁的未成年人,请在监护人监护、指导下并取得监护人同意后使用 Sleep Heart。
+ 2、我们重视未成年人个人信息的保护。本政策不面向不满 14 周岁的儿童。
+ 3、监护人应指导未成年人合理使用网络。
+
+ 七、通知和修订
+ 1、为提供服务,本隐私政策会不时更新。更新后将在本网站或应用内以适当方式提供。
+ 2、如发生重大变更,我们将以更明确的方式告知您。
+ 3、若您在更新生效后继续使用产品和/或服务,即表示您同意受修订后的本隐私政策约束。
+
+ 八、适用法律与争议解决
+ 1、【法律适用】本隐私政策的运行、解释和争议的解决适用中华人民共和国法律。
+ 2、【争议解决】您和 Sleep Heart 就本隐私政策内容或其执行发生争议的,双方应友好协商解决。
+
+ 九、如何联系我们
+ 如您对本隐私政策或您的个人信息有任何问题、意见或建议,请发送电子邮件至 asd272940236@foxmail.com 。
+ 账号注销不在本网站提交。应用内入口和实际效果见注销 页。
+ 上海微雨如酥网络设计有限公司
+ 返回首页 · 用户协议 · 注销
+
+
+
+
+
+
diff --git a/health-web/terms/index.html b/health-web/terms/index.html
new file mode 100644
index 0000000..cb20d23
--- /dev/null
+++ b/health-web/terms/index.html
@@ -0,0 +1,118 @@
+
+
+
+
+
+
用户协议 — Sleep Heart
+
+
+
+
+
+
+
+
+
+ Sleep Heart 软件用户服务协议
+ 适用于 Sleep Heart 网站(health.wyrs365.com)及 Sleep Heart 应用。
+ 本版本发布时间:2026年10月2日
+
+ 一、导言
+ 上海微雨如酥网络设计有限公司(以下简称「本公司」或「我们」)在此特别提醒您认真阅读、充分理解本《软件服务协议》(以下简称「本协议」):
+ 1、本协议是您与上海微雨如酥网络设计有限公司之间关于您登录、使用「Sleep Heart」(下称「本软件」)所订立的协议。请仔细阅读。
+ 2、本协议所称服务,是指本公司现在或将来通过本软件提供的助眠音乐、睡眠声监测、指尖心率估算、呼吸训练、健康指标记录、广场和账号功能(以下简称「服务」)。「用户」是指登录、使用、浏览本服务的个人或组织,更多时候称为「您」。
+ 3、您下载或使用 Sleep Heart,即表示您同意接受本协议约束。本协议构成对双方有约束力的文件。
+
+ 二、服务协议的确认及接受
+ 本站电子服务的所有权和运作权归我们所有。您同意本协议及《Sleep Heart 软件隐私权政策》后,可以使用相应服务。本协议是处理双方权利义务的约定,法律另有强制性规定或双方另有约定的,从其规定。
+ 1、【审慎阅读】请您审慎阅读并充分理解各条款,特别是免除或者限制责任的条款、法律适用和争议解决条款。
+ 2、如您需要本公司对条款作出说明,请立即停止使用服务,并发送邮件至本公司客服邮箱。
+ 3、您的登录、使用等行为视为接受本协议。
+ 4、如果您未满 18 周岁,请在法定监护人陪同下阅读本协议,并在使用前取得监护人同意。
+ 5、在中华人民共和国大陆地区现行法律法规允许的范围内,本公司可以拒绝服务、停止传输违法内容或对违规账号采取限制措施。
+ 6、本软件的著作权及我们发布的内容受著作权法保护。上海微雨如酥网络设计有限公司保留本协议未明确授予的权利。
+ 7、【协议修改】根据法律法规更新及运营需要,我们有权不时修改本协议。重大变更将在本网站或应用内告知。
+
+ 三、软件的取得与更新
+ 1、请通过本网站公布的下载说明,或通过得到本公司授权的应用商店取得本软件。下载页若写明应用即将上线,则表示当时还没有可公开访问的商店地址。
+ 2、【从未授权第三方取得】如果您从未经本公司授权的第三方取得本软件,本公司无法保证该软件能够正常使用,也不对由此产生的损失负责。
+ 3、为改善使用体验,本公司可能不时提供软件更新。请及时安装与您的系统兼容的版本。
+
+ 四、服务方式
+ 1、除免费功能外,本软件提供 Apple 自动续期订阅。订阅组名称为 SleepHeart VIP,包含周、月、季、年四档,四档权益相同,区别是周期。收费前,购买页会展示来自 App Store 的名称和价格。
+ 2、确认购买后,才会通过 Apple 账户付款。您取消购买单时,不会完成这笔扣款。订阅按所选周期自动续期,除非您在当前周期结束至少 24 小时前取消。续费价格、管理和取消都在 Apple 的订阅管理里。
+ 3、在 iPhone 上可以打开「设置」,点顶部的 Apple 账户,进入「订阅」,选择 SleepHeart 里要停止续费的项目并取消订阅。取消续订不影响已经生效的使用时间。
+ 4、退出登录或注销应用账号不会取消 Apple 订阅。会员页可以恢复购买。会员状态跟随 Apple 购买账户,不由应用登录账号单独授予。
+ 5、四档会员权益为:会员音频可以完整播放并加入收藏;本地音频导入不限数量;指尖心率测量不限次数。不购买也可以使用免费音频、本机健康记录、睡眠声监测和呼吸训练。
+ 6、价格以 App Store 显示为准。商品信息可能变化,请以购买当时页面为准。
+ 7、若购买或恢复遇到问题,可发送邮件至 asd272940236@foxmail.com 。
+ 8、您同意遵守法律及本协议,善意使用本软件,不利用本软件从事非法活动或侵犯他人权利。
+
+ 五、服务规则
+ 1、本软件中的广场内容由用户提供。您必须为自己账号下的行为负责。
+ 2、您发布的内容并不代表本公司的观点。
+ 3、您应对所发送信息的真实性、合法性和有效性负责。请不要发布垃圾信息、骚扰、虚假或违法内容。您可以使用举报功能报告上述内容。未登录不能使用广场互动。
+ 4、本公司可能因业务需要变更、暂停、限制或终止全部或部分服务。
+ 5、测量和监测结果只供个人参考,不是医疗诊断,不能代替血压计、血糖仪、血氧仪、体温计或就医。呼吸训练是放松节奏,不是治疗。睡眠声里的静音标记不是呼吸暂停诊断。
+ 6、您使用本软件应当遵守宪法和法律,遵守公共秩序,尊重社会公德。
+ 7、除非法律允许或本公司书面许可,您不得干扰本软件正常运行,或对本软件进行反向工程等破坏行为。
+ 8、本公司可依法停止传输违反法律法规或本协议的内容,并采取相应措施。
+ 9、本协议未书面明示授权的其他权利仍归本公司所有。
+ 10、您使用 Apple 提供的订阅、健康或系统能力时,还应遵守 Apple 的相关条款。
+
+ 六、您的权利与义务
+ 1、本软件账号的所有权归本公司所有,您获得使用权。
+ 2、您应妥善保管账号和密码。
+ 3、您应合法、正确地使用本服务。
+ 4、注销的实际效果以应用内流程和注销 页为准。当前版本会清除本机昵称、头像和会员标记并退出登录,并尝试结束当前登录会话;不会取消 Apple 订阅,也不会向服务器提交永久删除账号。
+
+ 七、隐私保护政策
+ 1、保护用户个人信息是本公司的基本原则。我们将按照本协议及《Sleep Heart 软件隐私权政策 》收集、使用和保存您的个人信息。
+ 2、使用登录、意见反馈或广场时,您需要按页面提示提供相应信息。
+ 3、只留在本机的测量画面、睡眠录音、手填健康数字、头像和导入音乐,不会因此上传给我们。
+ 4、个人信息的具体规则以隐私权政策为准。
+
+ 八、附则
+ 1、请您特别阅读免除本公司责任和加重您义务的条款,并自行考虑风险。
+ 2、本协议任何条款若被认定无效,不影响其余条款的效力。
+ 3、本协议标题仅为方便阅读,不具有单独法律效力。
+ 4、【法律适用】本协议的解释、效力及纠纷的解决,适用中华人民共和国法律。
+ 5、【争议解决】若您和本公司发生纠纷,首先应友好协商;协商不成的,提交本公司所在地有管辖权的人民法院诉讼解决。
+ 6、如因您违反法律或本协议给我们造成损失,您应赔偿相应损失。
+ 若您对本协议有任何意见,请发送电子邮件至 asd272940236@foxmail.com 。
+ 上海微雨如酥网络设计有限公司
+ 返回首页 · 隐私协议 · 注销
+
+
+
+
+
+
diff --git a/website/about/index.html b/website/about/index.html
new file mode 100644
index 0000000..3bd9e84
--- /dev/null
+++ b/website/about/index.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+
关于 — Spark Messenger
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 关于
+ Spark Messenger
+ Spark Messenger 是面向好友、群聊与朋友圈的即时通讯应用。安全、简洁、跨端同步。
+
+
把对话、群聊与朋友圈收进同一束火花——安静、可靠、随处可达。
+
少一层噪音,多一点连接。消息直达,媒体直传,跨设备保持同一条时间线。
+
+
+
+ 一对一与群聊
+ 长连接实时推送,撤回与删除按会话清晰落地。
+
+
+ 朋友圈
+ 图片与短文按可见范围发布,不挤占会话列表。
+
+
+ 媒体直传
+ 对象存储签名上传,聊天里只留引用,加载更快。
+
+
+
+
+
+
+
+
diff --git a/website/assets/legal.css b/website/assets/legal.css
new file mode 100644
index 0000000..c0d5eba
--- /dev/null
+++ b/website/assets/legal.css
@@ -0,0 +1,229 @@
+:root {
+ color-scheme: light;
+ --ink: #1a221c;
+ --ink-soft: #3d4a40;
+ --mist: #f3efe6;
+ --paper: #faf7f0;
+ --card: rgba(255, 255, 255, 0.62);
+ --ember: #e35a1c;
+ --leaf: #2f6b4f;
+ --line: rgba(26, 34, 28, 0.14);
+ --font-display: "Bricolage Grotesque", "PingFang SC", "Hiragino Sans", "Noto Sans", "Segoe UI", sans-serif;
+ --font-body: "Source Serif 4", "Songti SC", "PingFang SC", "Hiragino Mincho ProN", "Yu Mincho", "Noto Serif CJK SC", "Geeza Pro", "Noto Naskh Arabic", "Thonburi", "Noto Sans Thai", Georgia, serif;
+}
+
+:root[data-theme="dark"] {
+ color-scheme: dark;
+ --ink: #f4f0e6;
+ --ink-soft: #c9d2c8;
+ --mist: #101512;
+ --paper: #1a221c;
+ --card: rgba(26, 34, 28, 0.72);
+ --ember: #ff8a4a;
+ --leaf: #8fceb0;
+ --line: rgba(244, 240, 230, 0.16);
+}
+
+@media (prefers-color-scheme: dark) {
+ :root:not([data-theme="light"]) {
+ color-scheme: dark;
+ --ink: #f4f0e6;
+ --ink-soft: #c9d2c8;
+ --mist: #101512;
+ --paper: #1a221c;
+ --card: rgba(26, 34, 28, 0.72);
+ --ember: #ff8a4a;
+ --leaf: #8fceb0;
+ --line: rgba(244, 240, 230, 0.16);
+ }
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ margin: 0;
+ min-height: 100vh;
+ color: var(--ink);
+ background:
+ radial-gradient(900px 480px at 0% -10%, rgba(227, 90, 28, 0.16), transparent 55%),
+ linear-gradient(180deg, var(--paper), var(--mist));
+ font-family: var(--font-body);
+ font-size: 1.0625rem;
+ line-height: 1.7;
+}
+
+a {
+ color: var(--ember);
+}
+
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ border: 0;
+}
+
+.top {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.75rem;
+ max-width: 46rem;
+ margin: 0 auto;
+ padding: 1rem 1.15rem 0;
+}
+
+.mark {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: var(--ink);
+ font-family: var(--font-display);
+ font-weight: 700;
+ text-decoration: none;
+}
+
+.mark img {
+ width: 1.75rem;
+ height: 1.75rem;
+ border-radius: 0.4rem;
+}
+
+.tools {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.tools select,
+.tools button {
+ min-height: 2.75rem;
+ border: 1px solid var(--line);
+ border-radius: 0.55rem;
+ background: var(--card);
+ color: var(--ink);
+ font-family: var(--font-display);
+ font-size: 0.95rem;
+}
+
+.tools select {
+ max-width: 9.5rem;
+ padding: 0 0.55rem;
+}
+
+.tools button {
+ padding: 0 0.85rem;
+ font-weight: 650;
+ cursor: pointer;
+}
+
+.tools select:focus,
+.tools button:focus {
+ outline: 2px solid var(--ember);
+ outline-offset: 2px;
+}
+
+main {
+ max-width: 46rem;
+ margin: 0 auto;
+ padding: 1.25rem 1.15rem 2.5rem;
+}
+
+article {
+ background: var(--card);
+ border: 1px solid var(--line);
+ border-radius: 1rem;
+ padding: 1.25rem 1.15rem 1.5rem;
+}
+
+article h1 {
+ margin: 0.35rem 0 0.75rem;
+ font-family: var(--font-display);
+ font-size: clamp(1.8rem, 5vw, 2.4rem);
+ line-height: 1.15;
+ letter-spacing: -0.03em;
+}
+
+article h2 {
+ margin: 1.35rem 0 0.4rem;
+ font-family: var(--font-display);
+ font-size: 1.15rem;
+ line-height: 1.35;
+}
+
+article p,
+article li {
+ margin: 0.45rem 0;
+}
+
+article ul {
+ margin: 0.35rem 0 0.6rem;
+ padding-inline-start: 1.2rem;
+}
+
+.eyebrow {
+ margin: 0;
+ color: var(--leaf);
+ font-family: var(--font-display);
+ font-size: 0.82rem;
+ font-weight: 650;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+.meta {
+ color: var(--ink-soft);
+}
+
+.foot {
+ max-width: 46rem;
+ margin: 0 auto;
+ padding: 0 1.15rem 2.25rem;
+ color: var(--ink-soft);
+ font-family: var(--font-display);
+ font-size: 0.92rem;
+}
+
+.foot p {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.55rem 0.75rem;
+ margin: 0.35rem 0;
+}
+
+.foot a {
+ color: inherit;
+}
+
+[hidden] {
+ display: none !important;
+}
+
+@media (max-width: 640px) {
+ .top {
+ align-items: flex-start;
+ flex-direction: column;
+ }
+
+ .tools,
+ .tools select {
+ width: 100%;
+ max-width: none;
+ }
+
+ .tools button {
+ flex: 0 0 auto;
+ }
+}
diff --git a/website/assets/legal.js b/website/assets/legal.js
new file mode 100644
index 0000000..e7fff67
--- /dev/null
+++ b/website/assets/legal.js
@@ -0,0 +1,166 @@
+(() => {
+ const LANGS = [
+ "zh-Hans", "zh-Hant", "en-US", "ja", "ko", "es-MX", "fr-FR",
+ "de-DE", "pt-BR", "ru", "ar-SA", "it", "th", "vi", "id",
+ ];
+
+ const UI = {
+ "zh-Hans": { home: "首页", privacy: "隐私政策", terms: "用户协议", toDark: "暗黑", toLight: "日间" },
+ "zh-Hant": { home: "首頁", privacy: "隱私政策", terms: "使用者協議", toDark: "深色", toLight: "日間" },
+ "en-US": { home: "Home", privacy: "Privacy Policy", terms: "Terms of Use", toDark: "Dark", toLight: "Light" },
+ ja: { home: "ホーム", privacy: "プライバシー", terms: "利用規約", toDark: "ダーク", toLight: "ライト" },
+ ko: { home: "홈", privacy: "개인정보", terms: "이용약관", toDark: "어둡게", toLight: "밝게" },
+ "es-MX": { home: "Inicio", privacy: "Privacidad", terms: "Condiciones", toDark: "Oscuro", toLight: "Claro" },
+ "fr-FR": { home: "Accueil", privacy: "Confidentialité", terms: "Conditions", toDark: "Sombre", toLight: "Clair" },
+ "de-DE": { home: "Start", privacy: "Datenschutz", terms: "Nutzung", toDark: "Dunkel", toLight: "Hell" },
+ "pt-BR": { home: "Início", privacy: "Privacidade", terms: "Termos", toDark: "Escuro", toLight: "Claro" },
+ ru: { home: "Главная", privacy: "Конфиденциальность", terms: "Условия", toDark: "Тёмная", toLight: "Светлая" },
+ "ar-SA": { home: "الرئيسية", privacy: "الخصوصية", terms: "الشروط", toDark: "داكن", toLight: "فاتح" },
+ it: { home: "Home", privacy: "Privacy", terms: "Condizioni", toDark: "Scuro", toLight: "Chiaro" },
+ th: { home: "หน้าแรก", privacy: "ความเป็นส่วนตัว", terms: "ข้อกำหนด", toDark: "มืด", toLight: "สว่าง" },
+ vi: { home: "Trang chủ", privacy: "Quyền riêng tư", terms: "Điều khoản", toDark: "Tối", toLight: "Sáng" },
+ id: { home: "Beranda", privacy: "Privasi", terms: "Ketentuan", toDark: "Gelap", toLight: "Terang" },
+ };
+
+ const HTML_LANG = {
+ "zh-Hans": "zh-CN",
+ "zh-Hant": "zh-TW",
+ "en-US": "en",
+ ja: "ja",
+ ko: "ko",
+ "es-MX": "es-MX",
+ "fr-FR": "fr",
+ "de-DE": "de",
+ "pt-BR": "pt-BR",
+ ru: "ru",
+ "ar-SA": "ar",
+ it: "it",
+ th: "th",
+ vi: "vi",
+ id: "id",
+ };
+
+ function norm(tag) {
+ if (!tag) return "";
+ const raw = String(tag).trim().replace(/_/g, "-");
+ if (LANGS.includes(raw)) return raw;
+ const lower = raw.toLowerCase();
+ if (lower === "zh" || lower === "zh-cn" || lower === "zh-sg" || lower === "zh-hans") return "zh-Hans";
+ if (lower === "zh-tw" || lower === "zh-hk" || lower === "zh-mo" || lower === "zh-hant") return "zh-Hant";
+ if (lower.startsWith("en")) return "en-US";
+ if (lower.startsWith("ja")) return "ja";
+ if (lower.startsWith("ko")) return "ko";
+ if (lower.startsWith("es")) return "es-MX";
+ if (lower.startsWith("fr")) return "fr-FR";
+ if (lower.startsWith("de")) return "de-DE";
+ if (lower.startsWith("pt")) return "pt-BR";
+ if (lower.startsWith("ru")) return "ru";
+ if (lower.startsWith("ar")) return "ar-SA";
+ if (lower.startsWith("it")) return "it";
+ if (lower.startsWith("th")) return "th";
+ if (lower.startsWith("vi")) return "vi";
+ if (lower === "id" || lower.startsWith("id-") || lower.startsWith("in")) return "id";
+ return "";
+ }
+
+ function detectLang() {
+ const query = new URLSearchParams(location.search).get("lang");
+ if (query) return norm(query) || "zh-Hans";
+ try {
+ const saved = norm(localStorage.getItem("spark-legal-lang"));
+ if (saved) return saved;
+ } catch (_) { /* ignore */ }
+ const list = navigator.languages && navigator.languages.length
+ ? navigator.languages
+ : [navigator.language || ""];
+ for (const item of list) {
+ const code = norm(item);
+ if (code) return code;
+ }
+ return "zh-Hans";
+ }
+
+ function effectiveTheme() {
+ const chosen = document.documentElement.getAttribute("data-theme");
+ if (chosen === "dark" || chosen === "light") return chosen;
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+ }
+
+ function applyTheme(mode) {
+ if (mode === "light" || mode === "dark") {
+ document.documentElement.setAttribute("data-theme", mode);
+ } else {
+ document.documentElement.removeAttribute("data-theme");
+ }
+ paintThemeButton();
+ }
+
+ function paintThemeButton() {
+ const button = document.getElementById("theme");
+ const lang = document.documentElement.getAttribute("data-lang") || "zh-Hans";
+ const ui = UI[lang] || UI["zh-Hans"];
+ if (!button) return;
+ const dark = effectiveTheme() === "dark";
+ button.textContent = dark ? ui.toLight : ui.toDark;
+ button.setAttribute("aria-pressed", dark ? "true" : "false");
+ }
+
+ function applyLang(code) {
+ const safe = LANGS.includes(code) ? code : "zh-Hans";
+ document.querySelectorAll("article[data-lang]").forEach((node) => {
+ node.hidden = node.getAttribute("data-lang") !== safe;
+ });
+ document.documentElement.lang = HTML_LANG[safe] || "zh-CN";
+ document.documentElement.dir = safe === "ar-SA" ? "rtl" : "ltr";
+ document.documentElement.setAttribute("data-lang", safe);
+ const heading = document.querySelector(`article[data-lang="${safe}"] h1`);
+ if (heading && heading.textContent) {
+ document.title = `${heading.textContent.trim()} — Spark Messenger`;
+ }
+ const ui = UI[safe];
+ document.querySelectorAll("[data-i18n]").forEach((node) => {
+ const key = node.getAttribute("data-i18n");
+ if (ui[key]) node.textContent = ui[key];
+ });
+ const select = document.getElementById("lang");
+ if (select) select.value = safe;
+ paintThemeButton();
+ }
+
+ applyLang(detectLang());
+
+ try {
+ const savedTheme = localStorage.getItem("spark-legal-theme");
+ if (savedTheme === "light" || savedTheme === "dark") applyTheme(savedTheme);
+ else paintThemeButton();
+ } catch (_) {
+ paintThemeButton();
+ }
+
+ const select = document.getElementById("lang");
+ if (select) {
+ select.addEventListener("change", () => {
+ applyLang(select.value);
+ try { localStorage.setItem("spark-legal-lang", select.value); } catch (_) { /* ignore */ }
+ const url = new URL(location.href);
+ url.searchParams.set("lang", select.value);
+ history.replaceState(null, "", url);
+ });
+ }
+
+ const themeButton = document.getElementById("theme");
+ if (themeButton) {
+ themeButton.addEventListener("click", () => {
+ const next = effectiveTheme() === "dark" ? "light" : "dark";
+ applyTheme(next);
+ try { localStorage.setItem("spark-legal-theme", next); } catch (_) { /* ignore */ }
+ });
+ }
+
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
+ const onScheme = () => {
+ if (!document.documentElement.getAttribute("data-theme")) paintThemeButton();
+ };
+ if (typeof media.addEventListener === "function") media.addEventListener("change", onScheme);
+ else if (typeof media.addListener === "function") media.addListener(onScheme);
+})();
diff --git a/website/assets/styles.css b/website/assets/styles.css
index 5e8c763..be9779b 100644
--- a/website/assets/styles.css
+++ b/website/assets/styles.css
@@ -66,9 +66,10 @@ a {
position: relative;
z-index: 2;
display: flex;
+ flex-wrap: wrap;
align-items: center;
justify-content: space-between;
- gap: 1rem;
+ gap: 0.75rem 1.25rem;
max-width: 1120px;
margin: 0 auto;
padding: 1.25rem 1.5rem 0;
@@ -96,21 +97,33 @@ a {
.top-nav {
display: flex;
- gap: 1.25rem;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ gap: 0.15rem 1.15rem;
font-family: var(--font-display);
font-size: 0.95rem;
font-weight: 500;
}
.top-nav a {
+ display: inline-flex;
+ align-items: center;
+ min-height: 2.25rem;
+ padding: 0.15rem 0.05rem;
text-decoration: none;
opacity: 0.78;
}
-.top-nav a:hover {
+.top-nav a:hover,
+.top-nav a[aria-current="page"] {
opacity: 1;
}
+.top-nav a[aria-current="page"] {
+ color: var(--ember);
+ box-shadow: inset 0 -2px 0 var(--ember);
+}
+
.hero {
position: relative;
z-index: 1;
@@ -512,6 +525,67 @@ a {
}
}
+.page {
+ position: relative;
+ z-index: 1;
+ max-width: 1120px;
+ margin: 0 auto;
+ padding: 2.5rem 1.5rem 4rem;
+}
+
+.page h1 {
+ margin: 0;
+ font-family: var(--font-display);
+ font-weight: 800;
+ font-size: clamp(2.4rem, 6vw, 4rem);
+ line-height: 0.98;
+ letter-spacing: -0.04em;
+}
+
+.page h2 {
+ margin: 2.2rem 0 0.55rem;
+ font-family: var(--font-display);
+ font-size: clamp(1.35rem, 3vw, 1.75rem);
+ font-weight: 700;
+ letter-spacing: -0.03em;
+}
+
+.page .prose {
+ max-width: 40rem;
+ color: var(--ink-soft);
+}
+
+.page .prose p,
+.page .prose li {
+ margin: 0.75rem 0;
+}
+
+.page .prose ul {
+ margin: 0.35rem 0 0;
+ padding-inline-start: 1.2rem;
+}
+
+.page-back {
+ display: inline-flex;
+ margin-top: 1.75rem;
+ font-family: var(--font-display);
+ font-weight: 650;
+ color: var(--ember);
+ text-decoration: none;
+}
+
+.page .feature-rail {
+ margin-top: 1.75rem;
+}
+
+@media (max-width: 720px) {
+ .top-nav {
+ flex: 1 1 100%;
+ justify-content: flex-start;
+ column-gap: 0.95rem;
+ }
+}
+
@media (max-width: 900px) {
.hero {
grid-template-columns: 1fr;
diff --git a/website/delete/index.html b/website/delete/index.html
new file mode 100644
index 0000000..3dba819
--- /dev/null
+++ b/website/delete/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
注销 — Spark Messenger
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 账号
+ 注销
+ 官网不能直接注销账号。请在已登录的 Spark Messenger 里完成。
+
+
在 App 内注销
+
使用当前账号发起注销后,系统会向这个账号绑定的邮箱发送注销验证码。验证码 5 分钟内有效,只发到绑定邮箱,不会发到手机号。验证通过并提交后,账号会被永久删除,不能再登录。
+
找不到入口时
+
如果 App 里暂时没有看到注销入口,请通过 App 内的「意见反馈」联系我们,说明需要注销账号。隐私协议也写明:可以通过意见反馈要求更正或删除与账号相关的信息。
+
返回首页
+
+
+
+
+
+
diff --git a/website/index.html b/website/index.html
index 4f66b62..6e04ab2 100644
--- a/website/index.html
+++ b/website/index.html
@@ -25,6 +25,10 @@
能力
下载
+ 隐私协议
+ 用户协议
+ 注销
+ 关于
@@ -98,6 +102,10 @@
sparkmessenger.wyrs365.com
·
sparkmsg.wyrs365.com
+
·
+
隐私政策
+
·
+
用户协议
diff --git a/website/legal/legal.html b/website/legal/legal.html
new file mode 100644
index 0000000..c86b51e
--- /dev/null
+++ b/website/legal/legal.html
@@ -0,0 +1,135 @@
+
+
+
+
+
+
Spark Messenger
+
+
+
+
+
+
+
+
+
引言 本政策包含以下内容:
一、我们如何收集和使用您的个人信息及其他信息
二、我们如何使用 Cookie 和同类技术
三、合法共享、转让、公开披露您个人信息的情形
四、我们如何安全地保护和保存您提供的信息
五、您如何访问和控制自己提供的个人信息
六、未成年人的个人信息保护
七、通知和修订
八、适用法律与争议解决
九、如何联系我们
特别提示 1、感谢您对 Spark Messenger(火花)的使用及信任,我们将持续致力于为您提供更加安全可靠的服务。
2、Spark Messenger(火花)平台所有的产品和/或服务均适用本隐私政策。
3、前述特定产品和/或服务的隐私政策构成本隐私政策的一部分,如与本隐私政策有不一致之处,以特定产品和/或服务的隐私政策为准。
4、除非本隐私政策另有明确所指,本隐私政策不适用于通过我们的产品和/或服务而接入的由第三方独立为您提供的产品和/或服务的情形。
5、本隐私政策仅适用于 14 周岁以上的用户,如果您是不满 14 周岁的儿童,请立即停止对本隐私政策的阅读和任何其他操作。
定义 1、【个人信息】个人信息是指以电子或者其他方式记录的能够单独或者与其他信息结合识别特定自然人身份或者反映特定自然人活动情况的各种信息。
2、【个人敏感信息】个人敏感信息是指一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等的个人信息。
一、我们如何收集和使用您的个人信息及其他信息 我们仅会出于以下合法目的,收集和使用您的个人信息及其他信息:
(一)您授权我们收集和使用您个人信息及其他信息的情形 我们的产品和/或服务包括一些特定业务功能和附加功能,这些功能包含了邮箱登录、消息收发、好友与群、广场、朋友圈和个人资料等 Spark Messenger(火花)所提供的服务所必须的功能。
为创建账号并投递消息,我们会处理你用于登录的邮箱和验证码、昵称与个人资料,以及你发送的文字、图片、好友关系、群、广场和朋友圈内容。
【友盟+移动统计SDK】SDK 名称:友盟+移动统计SDK;开发者:友盟同欣(北京)科技有限公司;收集信息范围:设备标识信息(含 Android ID/OAID 等)、IP 地址、网络状态、应用启动/停止时间等;目的:统计分析、基础反作弊;SDK 隐私政策链接:https://www.umeng.com/page/policy
【设备信息】为了保障您正常使用本产品和/或服务,我们会收集设备属性信息及连接信息。
【日志信息】我们的服务器可能会自动记录 IP 地址、语言、下载安装信息及服务日志等。
【相机/摄影机权限】您可在打开相机/摄影机权限后使用该功能进行主体更换、拍照发帖、修改个人头像等功能。
【取得已安装应用进程清单】服务跳转到其他应用之前,需要检测目标应用是否存在。
【加速度传感器】通过传感器信息检测屏幕方向,进行横竖屏切换。
以上信息均采用匿名的方式进行收集和保存,同时我们也会对信息采取加密处理。
【第三方 SDK 信息共享清单】 为实现统计分析、广告展示等功能,我们在取得您的同意后接入以下第三方 SDK。下列 SDK 名称、开发者、使用目的、收集个人信息范围、SDK 隐私政策链接与全国 SDK 管理服务平台(https://sdk.caict.ac.cn/official/#/home)登记信息保持一致。第三方 SDK 收集和处理信息等行为遵守其自身的隐私条款,我们可能会调整接入的第三方 SDK 并更新本目录。
(二)我们从第三方获得您个人信息及其他信息的情形 【第三方信息】为共同向您提供产品/服务,我们可能从关联公司、合作伙伴及其他受信任的第三方接收您的个人信息及其他信息。
(三)您个人信息及其他信息使用的规则 我们会根据法律规定及本隐私政策的约定并为实现我们的产品和/或服务功能对所收集的个人信息及其他信息进行合法的使用。
二、我们如何使用 Cookie 和同类技术 Cookies 的使用 1、为实现您联机体验,我们会在您的电脑或行动设备上发送 Cookies 以简化重复登录步骤并帮助判断登录状态。
2、我们不会将 Cookies 用于本隐私政策所述目的之外的任何用途。您可根据偏好管理或删除 Cookies。
三、合法共享、转让、公开披露您个人信息的情形 (一)共享 我们不会与 Spark Messenger(火花)及其关联公司以外的任何公司、组织和个人共享您的个人信息,但法律另有规定或取得您同意的除外。
(二)转让 我们不会将您的个人信息转让给任何公司、组织和个人,但取得同意或法律要求等情形除外。
(三)公开披露 我们仅会在取得您同意或法律要求的情况下,采取符合业界标准的安全防护措施公开披露您的个人信息。
(四)对第三方责任的声明 【第三方服务】请您注意,通过我们接入的第三方可能有自己的隐私权保护政策,建议您仔细查看第三方《隐私声明》及《服务协议》。
四、我们如何安全地保护和保存您提供的信息 (一)信息的保存地点 我们在中华人民共和国境内收集和产生的个人信息,保存在中华人民共和国境内。Spark Messenger(火花)不会向境外提供或保存个人信息。
(二)信息的保存期限 我们仅为实现服务目的所必需的时间保留您的个人信息。
(三)我们保护您个人信息的技术与措施 我们非常重视个人信息安全,并采取一切合理可行的措施保护您的个人信息,包括加密传输、访问控制及员工培训等。
Spark Messenger(火花)的网络服务采用了传输层安全协议等加密技术,通过 https 等方式提供安全服务。
五、您如何访问和控制自己提供的个人信息 1、您对自己的个人信息可行使访问、更正、删除等权利。
2、您可通过 Spark Messenger(火花)登录帐户查阅及修改个人信息。
3、我们将在验证身份后五个工作日内处理您的请求。
4、在法定情形下,我们可能无法回应您的部分请求。
六、未成年人的个人信息保护 1、若您是未满18周岁的未成年人,您应在监护人监护、指导下并取得监护人同意的情况下使用 Spark Messenger(火花)及相关服务。
2、我们重视对未成年人个人信息的保护。
3、我们为未成年人提供青少年模式,监护人应为未成年人选择使用青少年模式。
4、监护人应指导未成年人合理学习使用网络,避免沉迷虚拟空间。
七、通知和修订 1、为给您提供更好的服务,本隐私政策也会不定时更新,更新后将在 App 内公告或以其他适当方式提醒您。
2、如发生重大变更,我们将采取更具有提示作用的方式告知您。
3、若您继续使用我们的产品和/或服务,即表示您同意受修订后的本隐私政策的约束。
八、适用法律与争议解决 1、【法律适用】本隐私政策的运行、解释和争议的解决均适用中华人民共和国法律。
2、【争议解决】您和 Spark Messenger(火花)就本隐私政策内容或其运行发生任何争议的,双方应友好协商解决。
九、如何联系我们 如您对本隐私政策或您个人信息的相关事宜有任何问题、意见或建议,请通过电子邮件联系我们,电子邮箱地址为 asd272940236@foxmail.com。您也可以通过 App 内意见反馈联系我们。
+
引言 本政策包含以下內容:
一、我們如何收集和使用您的個人資訊及其他資訊
二、我們如何使用 Cookie 和同類技術
三、合法共享、轉讓、公開披露您個人資訊的情形
四、我們如何安全地保護和儲存您提供的資訊
五、您如何訪問和控制自己提供的個人資訊
六、未成年人的個人資訊保護
七、通知和修訂
八、適用法律與爭議解決
九、如何聯絡我們
特別提示 1、感謝您對 Spark Messenger(火花)的使用及信任,我們將持續致力於為您提供更加安全可靠的服務。
2、Spark Messenger(火花)平臺所有的產品和/或服務均適用本隱私政策。
3、前述特定產品和/或服務的隱私政策構成本隱私政策的一部分,如與本隱私政策有不一致之處,以特定產品和/或服務的隱私政策為準。
4、除非本隱私政策另有明確所指,本隱私政策不適用於透過我們的產品和/或服務而接入的由第三方獨立為您提供的產品和/或服務的情形。
5、本隱私政策僅適用於 14 週歲以上的使用者,如果您是不滿 14 週歲的兒童,請立即停止對本隱私政策的閱讀和任何其他操作。
定義 1、【個人資訊】個人資訊是指以電子或者其他方式記錄的能夠單獨或者與其他資訊結合識別特定自然人身份或者反映特定自然人活動情況的各種資訊。
2、【個人敏感資訊】個人敏感資訊是指一旦洩露、非法提供或濫用可能危害人身和財產安全,極易導致個人名譽、身心健康受到損害或歧視性待遇等的個人資訊。
一、我們如何收集和使用您的個人資訊及其他資訊 我們僅會出於以下合法目的,收集和使用您的個人資訊及其他資訊:
(一)您授權我們收集和使用您個人資訊及其他資訊的情形 我們的產品和/或服務包括一些特定業務功能和附加功能,這些功能包含了郵箱登入、訊息收發、好友與群、廣場、朋友圈和個人資料等 Spark Messenger(火花)所提供的服務所必須的功能。
為建立帳號並投遞訊息,我們會處理你用於登入的郵箱和驗證碼、暱稱與個人資料,以及你傳送的文字、圖片、好友關係、群、廣場和朋友圈內容。
【友盟+移動統計SDK】SDK 名稱:友盟+移動統計SDK;開發者:友盟同欣(北京)科技有限公司;收集資訊範圍:裝置標識資訊(含 Android ID/OAID 等)、IP 地址、網路狀態、應用啟動/停止時間等;目的:統計分析、基礎反作弊;SDK 隱私政策連結:https://www.umeng.com/page/policy
【裝置資訊】為了保障您正常使用本產品和/或服務,我們會收集裝置屬性資訊及連線資訊。
【日誌資訊】我們的伺服器可能會自動記錄 IP 地址、語言、下載安裝資訊及服務日誌等。
【相機/攝影機許可權】您可在開啟相機/攝影機許可權後使用該功能進行主體更換、拍照發帖、修改個人頭像等功能。
【取得已安裝應用程序清單】服務跳轉到其他應用之前,需要檢測目標應用是否存在。
【加速度感測器】透過感測器資訊檢測螢幕方向,進行橫豎屏切換。
以上資訊均採用匿名的方式進行收集和儲存,同時我們也會對資訊採取加密處理。
【第三方 SDK 資訊共享清單】 為實現統計分析、廣告展示等功能,我們在取得您的同意後接入以下第三方 SDK。下列 SDK 名稱、開發者、使用目的、收集個人資訊範圍、SDK 隱私政策連結與全國 SDK 管理服務平臺(https://sdk.caict.ac.cn/official/#/home)登記資訊保持一致。第三方 SDK 收集和處理資訊等行為遵守其自身的隱私條款,我們可能會調整接入的第三方 SDK 並更新本目錄。
(二)我們從第三方獲得您個人資訊及其他資訊的情形 【第三方資訊】為共同向您提供產品/服務,我們可能從關聯公司、合作伙伴及其他受信任的第三方接收您的個人資訊及其他資訊。
(三)您個人資訊及其他資訊使用的規則 我們會根據法律規定及本隱私政策的約定併為實現我們的產品和/或服務功能對所收集的個人資訊及其他資訊進行合法的使用。
二、我們如何使用 Cookie 和同類技術 Cookies 的使用 1、為實現您聯機體驗,我們會在您的電腦或行動裝置上傳送 Cookies 以簡化重複登入步驟並幫助判斷登入狀態。
2、我們不會將 Cookies 用於本隱私政策所述目的之外的任何用途。您可根據偏好管理或刪除 Cookies。
三、合法共享、轉讓、公開披露您個人資訊的情形 (一)共享 我們不會與 Spark Messenger(火花)及其關聯公司以外的任何公司、組織和個人共享您的個人資訊,但法律另有規定或取得您同意的除外。
(二)轉讓 我們不會將您的個人資訊轉讓給任何公司、組織和個人,但取得同意或法律要求等情形除外。
(三)公開披露 我們僅會在取得您同意或法律要求的情況下,採取符合業界標準的安全防護措施公開披露您的個人資訊。
(四)對第三方責任的宣告 【第三方服務】請您注意,透過我們接入的第三方可能有自己的隱私權保護政策,建議您仔細檢視第三方《隱私宣告》及《服務協議》。
四、我們如何安全地保護和儲存您提供的資訊 (一)資訊的儲存地點 我們在中華人民共和國境內收集和產生的個人資訊,儲存在中華人民共和國境內。Spark Messenger(火花)不會向境外提供或儲存個人資訊。
(二)資訊的儲存期限 我們僅為實現服務目的所必需的時間保留您的個人資訊。
(三)我們保護您個人資訊的技術與措施 我們非常重視個人資訊保安,並採取一切合理可行的措施保護您的個人資訊,包括加密傳輸、訪問控制及員工培訓等。
Spark Messenger(火花)的網路服務採用了傳輸層安全協議等加密技術,透過 https 等方式提供安全服務。
五、您如何訪問和控制自己提供的個人資訊 1、您對自己的個人資訊可行使訪問、更正、刪除等權利。
2、您可透過 Spark Messenger(火花)登入帳戶查閱及修改個人資訊。
3、我們將在驗證身份後五個工作日內處理您的請求。
4、在法定情形下,我們可能無法回應您的部分請求。
六、未成年人的個人資訊保護 1、若您是未滿18週歲的未成年人,您應在監護人監護、指導下並取得監護人同意的情況下使用 Spark Messenger(火花)及相關服務。
2、我們重視對未成年人個人資訊的保護。
3、我們為未成年人提供青少年模式,監護人應為未成年人選擇使用青少年模式。
4、監護人應指導未成年人合理學習使用網路,避免沉迷虛擬空間。
七、通知和修訂 1、為給您提供更好的服務,本隱私政策也會不定時更新,更新後將在 App 內公告或以其他適當方式提醒您。
2、如發生重大變更,我們將採取更具有提示作用的方式告知您。
3、若您繼續使用我們的產品和/或服務,即表示您同意受修訂後的本隱私政策的約束。
八、適用法律與爭議解決 1、【法律適用】本隱私政策的執行、解釋和爭議的解決均適用中華人民共和國法律。
2、【爭議解決】您和 Spark Messenger(火花)就本隱私政策內容或其執行發生任何爭議的,雙方應友好協商解決。
九、如何聯絡我們 如您對本隱私政策或您個人資訊的相關事宜有任何問題、意見或建議,請透過電子郵件聯絡我們,電子郵箱地址為 asd272940236@foxmail.com。您也可以透過 App 內意見反饋聯絡我們。
+
Introduction This Policy covers the following:
1. How we collect and use your personal information and other information
2. How we use cookies and similar technologies
3. Lawful sharing, transfer, and public disclosure of your personal information
4. How we securely protect and store the information you provide
5. How you access and control the personal information you provide
6. Protection of minors' personal information
7. Notices and revisions
8. Applicable law and dispute resolution
9. How to contact us
Special notice 1. Thank you for using and trusting Spark Messenger. We will keep working to provide a safer and more reliable service.
2. This Privacy Policy applies to all products and/or services of the Spark Messenger platform.
3. A privacy policy for a specific product and/or service forms part of this Privacy Policy. If there is a conflict, the specific policy prevails.
4. Unless this Privacy Policy expressly says otherwise, it does not apply to products and/or services that a third party provides to you independently through our products and/or services.
5. This Privacy Policy applies only to users aged 14 or older. If you are a child under 14, please stop reading this Privacy Policy and stop any other action immediately.
Definitions 1. [Personal information] Personal information means information recorded electronically or by other means that, alone or combined with other information, can identify a natural person or reflect a natural person's activities.
2. [Sensitive personal information] Sensitive personal information means personal information that, if leaked, unlawfully provided, or misused, may endanger personal or property safety, or is highly likely to harm reputation, physical or mental health, or lead to discriminatory treatment.
1. How we collect and use your personal information and other information We collect and use your personal information and other information only for the following lawful purposes.
(I) Situations in which you authorize us to collect and use your personal information and other information Our products and/or services include specific functions and additional functions. These functions include email sign-in, messaging, friends and groups, the square, moments, and profiles, which are necessary for the services provided by Spark Messenger.
To create an account and deliver messages, we process the email address and verification code you use to sign in, your nickname and profile, and the text, images, friend connections, groups, square posts, and moments you send.
[Umeng+ Mobile Analytics SDK] SDK name: Umeng+ Mobile Analytics SDK; developer: Umeng Tongxin (Beijing) Technology Co., Ltd.; information collected: device identifiers (including Android ID/OAID), IP address, network status, and app start and stop times; purpose: statistics and basic anti-fraud; SDK privacy policy: https://www.umeng.com/page/policy
[Device information] To keep the products and/or services available, we collect device attributes and connection information.
[Log information] Our servers may automatically record IP address, language, download and installation information, and service logs.
[Camera permission] After you turn on the camera, you may use it to replace a subject, post a photo, or change your profile photo.
[Installed application process list] Before a service opens another application, it needs to check whether the target application is present.
[Accelerometer] Sensor information is used to detect screen orientation and switch between portrait and landscape.
The information above is collected and stored in anonymized form, and we also encrypt it.
[Third-party SDK sharing list] To provide statistics, advertising, and similar functions, we integrate the following third-party SDKs after obtaining your consent. The SDK name, developer, purpose, scope of personal information, and SDK privacy-policy link stay consistent with the national SDK management platform (https://sdk.caict.ac.cn/official/#/home). A third-party SDK processes information under its own privacy terms. We may change the integrated SDKs and update this list.
(II) Situations in which we obtain your personal information and other information from third parties [Third-party information] To provide products or services together with others, we may receive your personal information and other information from affiliates, partners, and other trusted third parties.
(III) Rules for using your personal information and other information We use the collected personal information and other information lawfully, as required by law and this Privacy Policy, and in order to provide the functions of our products and/or services.
2. How we use cookies and similar technologies Use of cookies 1. To support your online experience, we may send cookies to your computer or mobile device to simplify repeat sign-in and help determine whether you are signed in.
2. We do not use cookies for any purpose beyond this Privacy Policy. You may manage or delete cookies according to your preference.
3. Lawful sharing, transfer, and public disclosure of your personal information (I) Sharing We do not share your personal information with any company, organization, or individual outside Spark Messenger and its affiliates, except where the law provides otherwise or we have your consent.
(II) Transfer We do not transfer your personal information to any company, organization, or individual, except with your consent or where the law requires it.
(III) Public disclosure We publicly disclose your personal information only with your consent or where the law requires it, and we use security measures consistent with industry practice.
(IV) Statement on third-party responsibility [Third-party services] A third party you reach through us may have its own privacy policy. Please read that third party's privacy statement and service agreement.
4. How we securely protect and store the information you provide (I) Where information is stored Personal information we collect and generate in the People's Republic of China is stored in the People's Republic of China. Spark Messenger does not provide or store personal information outside China.
(II) How long information is kept We keep your personal information only for the time needed to provide the services.
(III) Technical measures and safeguards We take reasonably practicable measures to protect your personal information, including encrypted transmission, access control, and staff training.
Spark Messenger uses transport-layer security and other encryption, and provides the service over HTTPS and similar means.
5. How you access and control the personal information you provide 1. You may access, correct, and delete your personal information.
2. You may view and change personal information after signing in to Spark Messenger.
3. After we verify your identity, we will handle your request within five business days.
4. In situations provided by law, we may be unable to respond to part of a request.
6. Protection of minors' personal information 1. If you are under 18, you should use Spark Messenger and related services under a guardian's supervision and guidance, and with the guardian's consent.
2. We value the protection of minors' personal information.
3. We provide a youth mode. A guardian should choose youth mode for a minor.
4. Guardians should guide minors to use the internet reasonably and to avoid excessive immersion in virtual space.
7. Notices and revisions 1. To provide a better service, this Privacy Policy will be updated from time to time. After an update, we will give notice in the app or in another appropriate way.
2. If there is a material change, we will use a more prominent notice.
3. If you continue to use our products and/or services, you agree to be bound by the revised Privacy Policy.
8. Applicable law and dispute resolution 1. [Governing law] The operation, interpretation, and dispute resolution of this Privacy Policy are governed by the laws of the People's Republic of China.
2. [Disputes] If you and Spark Messenger have a dispute about this Privacy Policy or its operation, both sides shall first try to resolve it through friendly consultation.
9. How to contact us If you have any question, comment, or suggestion about this Privacy Policy or your personal information, please contact us by email at asd272940236@foxmail.com. You may also contact us through in-app feedback.
+
一、导言 上海微雨如酥网络设计有限公司(以下简称「本公司」或「我们」)在此特别提醒您认真阅读、充分理解本《软件服务协议》(以下简称「本协议」):
1、本协议是您与 上海微雨如酥网络设计有限公司 之间关于您登录、使用「Spark Messenger(火花)」(下称「本软件」)服务所订立的协议。本协议描述本公司与您之间关于使用本软件所提供相关服务的权利义务,请仔细阅读本服务条款。
2、以下声明和本协议中,服务是指本公司现在或将来向用户提供的包括但不限于邮箱登录、消息收发、好友与群、广场、朋友圈和个人资料等产品及服务(以下简称「服务」)。「用户」是指登录、使用、浏览本服务的个人或组织,本协议中更多的称为「您」。
3、您访问本站并下载 Spark Messenger(火花) 后,即表示您同意接受本服务协议的约束,而本服务协议即构成对双方具有约束力的法律文档。
二、服务协议的确认及接受 本站的各项电子服务的所有权和运作权归我们所有。您同意服务条款及隐私条款后,即成为本站的正式用户。用户确认:本服务条款是处理双方权利义务的契约,始终有效,法律另有强制性规定或双方另有特别约定的,依其规定。
1、【审慎阅读】请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款、法律适用和争议解决条款。
2、本协议签署后,您如有任何需要本公司说明条款的要求,请立即停止使用服务,同时立即致电或发送邮件至本公司客服。
3、您的登录、使用等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。
4、如果您未满18周岁,请在法定监护人的陪同下阅读本用户服务条款,并在使用本服务前取得监护人的同意。
5、本公司保留在中华人民共和国大陆地区现行法律法规允许的范围内自行决定拒绝服务、关闭用户帐号、清除或编辑内容或取消订单等的权利。
6、本软件的软件着作权及 App 上发布的所有信息与内容的版权均受着作权法保护。上海微雨如酥网络设计有限公司 保留所有未在本服务条款中明确授予的权利。
7、【服务协议的修改】根据国家法律法规的更新及网站营运需要,我们有权对本条款不时地进行修改。
三、软件的取得与更新 1、您可以直接从 Spark Messenger(火花)的官方网站上或从得到本公司授权的第三方取得本软件。
2、【从未授权第三方取得】如果您从未经本公司授权的第三方取得本软件,本公司无法保证该软件能够正常使用。
3、为了改善用户体验、完善服务内容,本公司将不断努力开发新的服务,并为您不时提供软件更新。
四、服务方式 1、除免费服务外,本软件可能提供部分收费服务。对于收费服务,本软件会在您使用之前给予明确的提示。
2、您应了解本软件可能对该等服务进行更改、更新或提高,并承诺不因服务更改而要求赔偿。
3、商品或服务价格、数量、性能介绍、是否有货等商品信息随时都有可能发生变动。
4、为回馈用户的支持,我们会不定期向用户发放一些优惠券或代金券。
5、若您在商品购买过程中遇到任何问题,均可发送邮件至 asd272940236@foxmail.com,我们的客服人员会及时与您取得联系并帮助您解决问题。
6、您同意,遵守法律及本协议规定,秉承善意使用本软件,且保证不会利用本软件进行非法活动或侵犯他人权利。
五、服务规则 1、您充分了解并同意,本软件仅是您提供信息的分享、发送及取得的平台,您必须为自己帐号下的一切行为负责。
2、您使用本软件服务发布或发送的任何内容并不代表或暗示本公司的观点或政策。
3、您须对在本软件上所发送信息的真实性、合法性、有效性等负全部责任。
4、本公司因业务发展需要,可能对本软件的全部或部分服务进行变更、暂停、限制、终止或撤销。
5、【广告、信息及相关服务】本软件提供的服务中可能包含广告、信息等内容。
6、您使用本软件应当遵守宪法法律,遵守公共秩序,尊重社会公德。
7、除非法律允许或本公司书面许可,您使用本服务过程中不得从事干扰本软件正常营运的行为。
8、本公司可依法停止传输违反法律法规或本协议约定的内容,并有权采取适当的法律行动。
9、本服务的所有权和运作权归本公司。
10、本协议未书面明示授权的其他一切权利仍归本公司所有。
11、【第三方服务】您在本公司软件平台上使用第三方提供的产品或服务时,除遵守本协议约定外,还应遵守第三方的用户协议。
六、您的权利与义务 1、本软件帐号的所有权归本公司所有,您获得本软件帐号的使用权。
2、您应当妥善保管帐号信息及帐号密码安全。
3、您应遵守本协议的各项条款,合法、正确、适当地使用本服务。
4、为保证 Spark Messenger(火花)的适用性以及您的使用体验,请您及时下载最新版本并升级。
七、隐私保护政策 1、保护用户个人信息是本公司的一项基本原则。本公司将按照本协议及《Spark Messenger(火花)软件隐私权政策》的规定合法收集、使用、安全保存您的个人信息。
2、您在使用本服务的过程中,可能需要填写一些必要的信息。
3、尊重用户个人隐私是本软件的一项基本政策。
4、我们从第三方获得您个人信息及其他信息的情形,均应符合法律法规规定。
5、您个人信息及其他信息使用的规则,均应以《隐私权政策》为准。
八、附则 1、本公司郑重提醒您注意本协议中免除本公司责任和加重您义务的条款,请您仔细阅读,自主考虑风险。
2、如本协议中的任何条款无论因何种原因完全或部分无效或不具有运行力,本协议的其余条款仍应有效并且有运行力。
3、本协议中的标题仅为方便而设,不具有法律效力。
4、【法律适用】本协议的解释、效力及纠纷的解决,适用中华人民共和国法律。
5、【争议解决】若您和本公司之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,您同意将纠纷或争议提交本公司所在地有管辖权的人民法院通过诉讼方式解决。
6、您同意,如因您违反法律规定或本协议规定给本软件造成损失,您将充分赔偿我们所遭受的损失。
若您对本协议及本软件服务有任何意见,欢迎联系本公司客服部门,电子邮箱地址为 asd272940236@foxmail.com。您也可以通过 App 内意见反馈联系我们。
+
一、導言 上海微雨如酥網路設計有限公司(以下簡稱「本公司」或「我們」)在此特別提醒您認真閱讀、充分理解本《軟體服務協議》(以下簡稱「本協議」):
1、本協議是您與 上海微雨如酥網路設計有限公司 之間關於您登入、使用「Spark Messenger(火花)」(下稱「本軟體」)服務所訂立的協議。本協議描述本公司與您之間關於使用本軟體所提供相關服務的權利義務,請仔細閱讀本服務條款。
2、以下宣告和本協議中,服務是指本公司現在或將來向使用者提供的包括但不限於郵箱登入、訊息收發、好友與群、廣場、朋友圈和個人資料等產品及服務(以下簡稱「服務」)。「使用者」是指登入、使用、瀏覽本服務的個人或組織,本協議中更多的稱為「您」。
3、您訪問本站並下載 Spark Messenger(火花) 後,即表示您同意接受本服務協議的約束,而本服務協議即構成對雙方具有約束力的法律文件。
二、服務協議的確認及接受 本站的各項電子服務的所有權和運作權歸我們所有。您同意服務條款及隱私條款後,即成為本站的正式使用者。使用者確認:本服務條款是處理雙方權利義務的契約,始終有效,法律另有強制性規定或雙方另有特別約定的,依其規定。
1、【審慎閱讀】請您務必審慎閱讀、充分理解各條款內容,特別是免除或者限制責任的條款、法律適用和爭議解決條款。
2、本協議簽署後,您如有任何需要本公司說明條款的要求,請立即停止使用服務,同時立即致電或傳送郵件至本公司客服。
3、您的登入、使用等行為將視為對本協議的接受,並同意接受本協議各項條款的約束。
4、如果您未滿18週歲,請在法定監護人的陪同下閱讀本使用者服務條款,並在使用本服務前取得監護人的同意。
5、本公司保留在中華人民共和國大陸地區現行法律法規允許的範圍內自行決定拒絕服務、關閉使用者帳號、清除或編輯內容或取消訂單等的權利。
6、本軟體的軟體著作權及 App 上釋出的所有資訊與內容的版權均受著作權法保護。上海微雨如酥網路設計有限公司 保留所有未在本服務條款中明確授予的權利。
7、【服務協議的修改】根據國家法律法規的更新及網站營運需要,我們有權對本條款不時地進行修改。
三、軟體的取得與更新 1、您可以直接從 Spark Messenger(火花)的官方網站上或從得到本公司授權的第三方取得本軟體。
2、【從未授權第三方取得】如果您從未經本公司授權的第三方取得本軟體,本公司無法保證該軟體能夠正常使用。
3、為了改善使用者體驗、完善服務內容,本公司將不斷努力開發新的服務,併為您不時提供軟體更新。
四、服務方式 1、除免費服務外,本軟體可能提供部分收費服務。對於收費服務,本軟體會在您使用之前給予明確的提示。
2、您應瞭解本軟體可能對該等服務進行更改、更新或提高,並承諾不因服務更改而要求賠償。
3、商品或服務價格、數量、效能介紹、是否有貨等商品資訊隨時都有可能發生變動。
4、為回饋使用者的支援,我們會不定期向使用者發放一些優惠券或代金券。
5、若您在商品購買過程中遇到任何問題,均可傳送郵件至 asd272940236@foxmail.com,我們的客服人員會及時與您取得聯絡並幫助您解決問題。
6、您同意,遵守法律及本協議規定,秉承善意使用本軟體,且保證不會利用本軟體進行非法活動或侵犯他人權利。
五、服務規則 1、您充分了解並同意,本軟體僅是您提供資訊的分享、傳送及取得的平臺,您必須為自己帳號下的一切行為負責。
2、您使用本軟體服務釋出或傳送的任何內容並不代表或暗示本公司的觀點或政策。
3、您須對在本軟體上所傳送資訊的真實性、合法性、有效性等負全部責任。
4、本公司因業務發展需要,可能對本軟體的全部或部分服務進行變更、暫停、限制、終止或撤銷。
5、【廣告、資訊及相關服務】本軟體提供的服務中可能包含廣告、資訊等內容。
6、您使用本軟體應當遵守憲法法律,遵守公共秩序,尊重社會公德。
7、除非法律允許或本公司書面許可,您使用本服務過程中不得從事幹擾本軟體正常營運的行為。
8、本公司可依法停止傳輸違反法律法規或本協議約定的內容,並有權採取適當的法律行動。
9、本服務的所有權和運作權歸本公司。
10、本協議未書面明示授權的其他一切權利仍歸本公司所有。
11、【第三方服務】您在本公司軟體平臺上使用第三方提供的產品或服務時,除遵守本協議約定外,還應遵守第三方的使用者協議。
六、您的權利與義務 1、本軟體帳號的所有權歸本公司所有,您獲得本軟體帳號的使用權。
2、您應當妥善保管帳號資訊及帳號密碼安全。
3、您應遵守本協議的各項條款,合法、正確、適當地使用本服務。
4、為保證 Spark Messenger(火花)的適用性以及您的使用體驗,請您及時下載最新版本並升級。
七、隱私保護政策 1、保護使用者個人資訊是本公司的一項基本原則。本公司將按照本協議及《Spark Messenger(火花)軟體隱私權政策》的規定合法收集、使用、安全儲存您的個人資訊。
2、您在使用本服務的過程中,可能需要填寫一些必要的資訊。
3、尊重使用者個人隱私是本軟體的一項基本政策。
4、我們從第三方獲得您個人資訊及其他資訊的情形,均應符合法律法規規定。
5、您個人資訊及其他資訊使用的規則,均應以《隱私權政策》為準。
八、附則 1、本公司鄭重提醒您注意本協議中免除本公司責任和加重您義務的條款,請您仔細閱讀,自主考慮風險。
2、如本協議中的任何條款無論因何種原因完全或部分無效或不具有執行力,本協議的其餘條款仍應有效並且有執行力。
3、本協議中的標題僅為方便而設,不具有法律效力。
4、【法律適用】本協議的解釋、效力及糾紛的解決,適用中華人民共和國法律。
5、【爭議解決】若您和本公司之間發生任何糾紛或爭議,首先應友好協商解決,協商不成的,您同意將糾紛或爭議提交本公司所在地有管轄權的人民法院透過訴訟方式解決。
6、您同意,如因您違反法律規定或本協議規定給本軟體造成損失,您將充分賠償我們所遭受的損失。
若您對本協議及本軟體服務有任何意見,歡迎聯絡本公司客服部門,電子郵箱地址為 asd272940236@foxmail.com。您也可以透過 App 內意見反饋聯絡我們。
+
1. Introduction Shanghai Weiyu Rusu Network Design Co., Ltd. (the "Company" or "we") asks you to read and fully understand these Software Terms of Service (these "Terms").
1. These Terms are the agreement between you and Shanghai Weiyu Rusu Network Design Co., Ltd. about your sign-in to and use of "Spark Messenger" (the "Software"). They describe the rights and obligations of the Company and you regarding the services provided through the Software. Please read them carefully.
2. In the statements below and in these Terms, the services mean the products and services the Company provides now or in the future, including email sign-in, messaging, friends and groups, the square, moments, and profiles (the "Services"). A "user" is a person or organization that signs in, uses, or browses the Services, and is more often called "you" in these Terms.
3. After you visit this site and download Spark Messenger, you agree to be bound by these Terms, and these Terms are a legal document binding on both sides.
2. Confirmation and acceptance of the Terms Ownership and operation of the electronic services on this site belong to us. After you agree to the Terms and the Privacy Policy, you become a user of this site. You confirm that these Terms are the contract that handles the rights and obligations of both sides, that they remain effective, and that mandatory law or a special agreement between the sides prevails where it applies.
1. [Careful reading] Please read and fully understand each clause, especially clauses that exclude or limit liability, and clauses on governing law and dispute resolution.
2. After these Terms are entered into, if you need the Company to explain a clause, please stop using the Services immediately and contact the Company's customer service by phone or email.
3. Your sign-in, use, and similar actions are treated as acceptance of these Terms, and you agree to be bound by them.
4. If you are under 18, please read these Terms with a legal guardian and obtain the guardian's consent before using the Services.
5. The Company reserves the right, within the scope allowed by the laws in force in mainland China, to refuse service, close a user account, remove or edit content, or cancel an order.
6. The copyright in the Software and in the information and content published in the app is protected by copyright law. Shanghai Weiyu Rusu Network Design Co., Ltd. reserves all rights not expressly granted in these Terms.
7. [Changes to the Terms] We may revise these Terms from time to time as laws are updated and as the site's operation requires.
3. Obtaining and updating the Software 1. You may obtain the Software from the official website of Spark Messenger or from a third party authorized by the Company.
2. [Obtained from an unauthorized third party] If you obtain the Software from a third party that the Company has not authorized, the Company cannot guarantee that the Software will work normally.
3. To improve the experience and the Services, the Company will keep developing new services and will provide software updates from time to time.
4. How the Services are provided 1. Besides free services, the Software may offer some paid services. For a paid service, the Software will give a clear prompt before you use it.
2. You understand that the Software may change, update, or improve those services, and you agree not to claim compensation because of a service change.
3. Product or service price, quantity, performance description, and availability may change at any time.
4. To thank users for their support, we may from time to time issue coupons or vouchers.
5. If you meet any problem while purchasing a product, you may email asd272940236@foxmail.com. Our customer service will contact you and help resolve it.
6. You agree to comply with the law and these Terms, to use the Software in good faith, and not to use the Software for illegal activity or to infringe other people's rights.
5. Service rules 1. You fully understand and agree that the Software is a platform for you to share, send, and obtain information, and that you are responsible for everything done under your account.
2. Any content you publish or send through the Software does not represent or imply the Company's views or policies.
3. You are fully responsible for the authenticity, legality, and validity of information you send on the Software.
4. Because of business needs, the Company may change, suspend, limit, terminate, or withdraw all or part of the Software's services.
5. [Advertising, information, and related services] The services provided by the Software may include advertising, information, and similar content.
6. When using the Software, you shall abide by the Constitution and the law, abide by public order, and respect social morality.
7. Unless the law allows it or the Company gives written permission, you must not interfere with the normal operation of the Software while using the Services.
8. The Company may stop transmitting content that violates laws or these Terms, and may take appropriate legal action.
9. Ownership and operation of the Services belong to the Company.
10. All other rights not expressly granted in writing in these Terms remain with the Company.
11. [Third-party services] When you use a product or service provided by a third party on the Company's software platform, you shall also comply with that third party's user agreement, in addition to these Terms.
6. Your rights and obligations 1. Ownership of a Software account belongs to the Company. You receive a right to use the Software account.
2. You shall keep the account information and the account password secure.
3. You shall comply with these Terms and use the Services lawfully, correctly, and appropriately.
4. To keep Spark Messenger compatible and to protect your experience, please download the latest version and upgrade in time.
7. Privacy Policy 1. Protecting users' personal information is a basic principle of the Company. The Company will collect, use, and securely store your personal information as stated in these Terms and the Spark Messenger Privacy Policy.
2. While using the Services, you may need to fill in some necessary information.
3. Respecting users' privacy is a basic policy of the Software.
4. Where we obtain your personal information and other information from third parties, we will do so in compliance with laws and regulations.
5. The rules for using your personal information and other information are those in the Privacy Policy.
8. Miscellaneous 1. The Company reminds you to pay attention to clauses that exempt the Company from liability or increase your obligations. Please read them carefully and consider the risks yourself.
2. If any clause of these Terms is wholly or partly invalid or unenforceable for any reason, the remaining clauses remain valid and enforceable.
3. Headings in these Terms are for convenience only and have no legal effect.
4. [Governing law] The interpretation, validity, and dispute resolution of these Terms are governed by the laws of the People's Republic of China.
5. [Disputes] If any dispute arises between you and the Company, it shall first be resolved through friendly consultation. If consultation fails, you agree to submit the dispute to the people's court with jurisdiction at the Company's location.
6. You agree that if you cause loss to the Software by violating the law or these Terms, you will fully compensate the loss we suffer.
If you have any comment on these Terms or the Software services, please contact the Company's customer service by email at asd272940236@foxmail.com. You may also contact us through in-app feedback.
+
+
+
diff --git a/website/privacy/index.html b/website/privacy/index.html
new file mode 100644
index 0000000..24c2cc5
--- /dev/null
+++ b/website/privacy/index.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website/terms/index.html b/website/terms/index.html
new file mode 100644
index 0000000..b6b66c5
--- /dev/null
+++ b/website/terms/index.html
@@ -0,0 +1 @@
+