惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
IT之家
IT之家
博客园 - Franky
Stack Overflow Blog
Stack Overflow Blog
宝玉的分享
宝玉的分享
Recent Announcements
Recent Announcements
Engineering at Meta
Engineering at Meta
S
SegmentFault 最新的问题
V
Visual Studio Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
H
Help Net Security
V
V2EX
H
Hackread – Cybersecurity News, Data Breaches, AI and More
量子位
博客园 - 叶小钗
J
Java Code Geeks
博客园 - 【当耐特】
月光博客
月光博客
爱范儿
爱范儿
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
小众软件
小众软件

atpX

自建 S3 兼容对象存储服务 Garage 听风的歌 偶尔是深夜就好了 新玩具 AirPods Pro 3 公交车上的时间 从 WHOIS 到 RDAP 通过 WireGuard 访问 NFS 共享文件 自建音乐串流服务探索 我停止了探索 Fediverse 互联网背景噪音 我的数字生活降级 小城与确定性的墙 一只特立独行的猪 Fediverse 与社交 承认的勇气 我的博客写作流程 网站新增 Misc 页面 擅长对线的鲍勃 在 Chroot 环境下使用 Rsync 同步 再见 JavaScript 当我玩博客时我在玩什么 为什么我的博客没有友链页面 小熊猫与大熊猫 (HDR 照片测试) 是时候为网站开启 HTTP/3 支持了吗 使用 AdGuard Home 搭建自用 DoH 服务 谈谈读书与消遣 2023 年终总结 西安两日游 从 AirPods「升级」到 EarPods Docker 搭建去中心化的微博客平台 Mastodon
mediaX - 轻量书影音记录管理工具
ATP · 2024-08-22 · via atpX

前段时间写 Misc 页面 的时候就在考虑书影音记录的数据源问题,最后得出结论还得有一份自己本地的备份才好。Excel 固然可以满足,但不够优雅,搜索 media tracker 也能找到不少已经比较完善的项目,但我只想要一个小而美。于是决定着手开发一个自己的书影音记录管理工具。

一开始准备用 Python 或者 PHP 写,不过既然主要目的是备份,运行环境要求自然越低越好,最好只需要一个可执行文件和 SQLite 数据库。目光最终转向了 Rust 和 Go 语言。

上一次接触 Go 还是多年前的 Hello World,所以这个项目也是抱着学习的态度,想到哪写到哪,写到哪查到哪。奋发图强了半个多月,基本功能也比较完善了,如有需要欢迎使用体验。

Github 项目地址:https://github.com/scenery/mediax

项目简介

mediaX 是一款使用 Go 语言开发的个人阅读/观影/看剧/追番/游戏记录 Web 管理工具。

特点:

  • Go 原生 Web 开发,无外部框架
  • 轻量,简单,无任何 JavaScript 代码
  • 数据库使用 SQLite + 纯 Go 实现的驱动 glebarez/sqlite,无 CGO 依赖
  • 支持从豆瓣或 Bangumi 导入已有历史记录
  • 支持新增条目时自动从豆瓣或 Bangumi 获取数据
  • 支持导出内部记录为 JSON 数据

预览:

主页和分类页
主页和分类页。
v0.6.0 详情页和添加条目页面
详情页和添加条目页面。

Update: 2025-05-03

最近一周花时间更新了下 mediaX,v0.6.0 版本对样式和功能进行了较大幅度的改动,主要包括:

  • 优化 html 页面结构,重新设计导航栏和页面样式
  • 支持配置文件,可仅启用需要的类别
  • 支持用户登录,需在配置文件中设置用户名和密码
  • 分类页面添加排序功能,优化分页导航
  • 简化缓存逻辑,优化搜索性能
主页和分类页
v0.6.0 主页和分类页。
v0.6.0 详情页和添加条目页面
v0.6.0 详情页和添加条目页面。

条目的信息字段没有设计太多,只记录一些关键数据。网页样式上延续了本站的风格没有风格同样没有使用任何 JavaScript 代码和 Cookie(v0.6.0 版本为了排序功能,加了一行仅有的内联 JS this.form.submit();为了用户功能也被迫使用了 Cookie),因此部分功能实现上比较受限。总之 mediaX 预期是一个运行在树莓派、NAS 等设备上的局域网应用,并无过多的安全设计,如需放到公网使用请使用 HTTPS 或加密 Tunnel 连接,同时也请在 Web Server 上做好鉴权和 IP 限制。

* 该项目主要是为了满足个人学习和使用需要,暂不接受新功能建议,如果有额外功能需求欢迎 fork 修改(MIT 协议)。

使用说明

mediaX 从 v0.6.0 版本开始通过配置文件启动,默认加载程序目录下的 config.json 文件,也可通过 --config 参数指定。配置文件格式如下:

{
    "server": {
        "address": "0.0.0.0",
        "port": 8080,
        "use_https": false
    },
    "user": {
        "username": "username",
        "password": "{bcrypt}$2a$password"
    },
    "session_timeout": "168h",
    "categories": ["book", "movie", "tv", "anime", "game"],
    "pagination": {
        "page_size": 10
    },
    "api_key": ""
}

其中:

  • address: 监听地址,默认 0.0.0.0
  • port: 监听端口,默认 8080
  • use_https: 启用安全连接,默认 false,建议在 HTTPS 环境下开启
  • username: 用户名,限制 1 至 64 个字符
  • password: 密码,限制 4 至 64 个字符
  • session_timeout: 登录过期时间,默认 168h(7天)
  • categories: 开启的分类模块,默认全部开启
  • page_size: 分页条目数量,限制 10 至 50 长度
  • api_key: 默认为空,不启用 API 功能

配置文件中用户名和密码不能为空,且密码使用 BCrypt 加密,可使用 --bcrypt 参数加密,例如:

# 设置密码: hubcap-oxidation-album-glitzy-tying
# Linux / macOS
./mediax --bcrypt "hubcap-oxidation-album-glitzy-tying"
# Windows
mediax.exe --bcrypt "hubcap-oxidation-album-glitzy-tying"

# 输出:
{bcrypt}$2a$10$kR.uXEAfE.ADUoGd5SaXqu75HjGwzSdmi2rbFHX/OT8DrkoltS7a6

将输出的值填入配置文件 password 字段中即可。

mediaX 支持导入豆瓣(图书/电影/剧集)或 Bangumi 番组计划(图书/电影/剧集/番剧/游戏)数据来源的个人历史记录,其中 Bangumi 的电影和剧集记录因 API 返回内容限制未做详细区分,简单的判断如果只有一集归类为电影,大于一集则归类为剧集。

  • 导入豆瓣数据:首先使用「豆伴」导出数据,安装好插件后,进入设置连接账号,然后点击浏览器任务栏插件图标选择 新建任务,选择备份的项目中只勾选第一个 影/音/书/游/剧,等待任务完成后,点击右上方 浏览备份 - 备份数据库,解压下载的文件,其中的 tofu[xxxxxx].json 为需要的文件。
  • 导入 Bangumi 数据:可以直接使用 Bangumi 提供的 API 获得数据,在返回结果最后的 total 属性中可以看到你的记录总数,由于单次请求最多返回 50 条记录,如果超过 50 条需要修改 offset 分页参数多获取几次,最后将所有数据汇总保存为 JSON 文件。

导入数据

将 JSON 文件放到 mediaX 程序相同目录下,执行命令:

# Linux / macOS
./mediax --import <douban|bangumi> --file <file.json> [--download-image]
# Windows
mediax.exe --import <douban|bangumi> --file <file.json> [--download-image]

# e.g. 导入豆瓣数据
# ./mediax --import douban --file tofu[xxxxxx].json --download-image

最后的 --download-image 为可选参数,如果加上则导入的时候会尝试下载封面图片,如果数据量大的话会比较耗时(为了避免 IP 被 ban 下载间隔为 1s),请耐心等待。

不推荐重复导入一个文件,如果重复导入文件,目前只是简单的比对已导入的记录(原链接)和已下载的图片文件是否已经存在,如果存在则跳过导入。

导出数据

mediaX 支持导出内部数据为 JSON 文件:

{
  "subjects": [
    {
      "uuid": string,
      "subject_type": string,
      "title": string,
      "alt_title": string,
      "pub_date": string,
      "creator": string,
      "press": string,
      "status": int,
      "rating": int,
      "summary": string,
      "comment": string,
      "external_url": string,
      "mark_date": string,
      "created_at": string
    }
  ],
  "export_time": string,
  "total_count": int
}

导出命令:

# Linux / macOS
./mediax --export <all|anime|movie|book|tv|game> [--limit <number>]
# Windows
mediax.exe --export <all|anime|movie|book|tv|game> [--limit <number>]

# e.g. 导出最近 5 条图书数据,如果不加 --limit 参数则导出该类型全部记录
# ./mediax --export book --limit 5

导出的文件将自动保存在程序目录下。

API

目前 mediaX 支持通过 API 获取基本的个人收藏条目数据,请求接口如下:

/api/v0/collection

返回格式:

{
  "subjects": [
    {
      "uuid": string,
      "subject_type": string,
      "title": string,
      "alt_title": string,
      "pub_date": string,
      "creator": string,
      "press": string,
      "status": int,
      "rating": int,
      "summary": string,
      "comment": string,
      "external_url": string,
      "mark_date": string,
      "created_at": string
    }
  ],
  "response_tim": string,
  "total_count": int,
  "limit": int,
  "offset": int
}

你可以使用 --api-key 参数生成一个 API Key:

# Linux / macOS
./mediax --api-key
# Windows
mediax.ext --api-key

# 输出:
------- Generated API Key -------
API Key: 6ElNVkplRJgasQKfRyFNRDvxl0iV1kebIJpVl9Dt_Eg=
Hashed API Key: QEr6mA6HkILFwBYckw4Ek+9v41ooV64VGebOSDwqiKM=
---------------------------------

其中 Hashed API Key 需要复制到配置文件 config.jsonapi_key 字段中。请保管好 API Key,不要在非加密的公网中使用。如需重置,重新生成并替换即可。

可选参数:

  • type: 获取数据的类型,默认为所有类型,可选 book, movie, tv, anime, game
  • limit: 获取数据的数量限制,默认(最大)为 50
  • offset: 获取数据的起始位置(跳过的记录数量),默认为 0
  • sort: 排序方式,默认为 1(最近添加),可选 2: 最近标记,3: 最早添加,4: 最早标记

例如,使用 curl 命令获取数据:

# 获取最近 5 条图书数据
curl "http://localhost:8080/api/v0/collection?type=book&limit=5" \
  -H "Authorization: Bearer 6ElNVkplRJgasQKfRyFNRDvxl0iV1kebIJpVl9Dt_Eg="
# 获取第 6 至 10 条图书数据
curl "http://localhost:8080/api/v0/collection?type=book&limit=5&offset=5" \
  -H "Authorization: Bearer 6ElNVkplRJgasQKfRyFNRDvxl0iV1kebIJpVl9Dt_Eg="

Linux 上持久化运行

一个简单的持久化运行配置示例,新建 systemd 服务:

vim /etc/systemd/system/mediax.service

添加下面内容,其中 User 为运行服务的用户,需要有 mediaX 工作目录的读写权限, --port 8080 可以修改为你需要的运行端口。

[Unit]
Description=mediaX - https://github.com/scenery/mediax
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/path/to/mediax
ExecStart=/path/to/mediax/mediax --config /path/to/config.json
Restart=on-failure
RestartSec=10s

[Install]
WantedBy=multi-user.target

运行管理:

# 重新加载 systemd 配置:
sudo systemctl daemon-reload
# 设置开机自启:
sudo systemctl enable mediax
# 启动服务:
sudo systemctl start mediax
# 停止服务:
sudo systemctl stop mediax
# 服务状态:
sudo systemctl status mediax

写在最后

因为 Go 语言入门比较友好,整个项目也比较简单,开发过程中除了写缓存功能时大脑多次宕机外,其他都还算比较顺利。不过是个体力活,赞美 if err != nil

数据库最初设计时按类别建了多张表,差不多写完的时候突然觉得数据量又不大,一个正常地球人一生也读不了看不了多少,多表徒增复杂度,最后又把数据库重新设计合并为一张表。如果你是三体人可能会遇到数据库性能瓶颈。

导入记录功能需要用户提前准备数据,虽然可以写进程序里但没必要。新增条目时自动获取数据依赖 API,如果未来获取豆瓣数据失效,会考虑改为从 The Movie Database (TMDB) 上获取数据。顺便提一下导入豆瓣数据后搜索“未知”,可能会发现一些被豆瓣下架的条目,比如「V 字仇杀队」等,到 Wayback Machine 上搜一下相应链接说不定能在远古记录中找回来。

最后,这应该不是一个长期维护项目,稳定之后可能不怎么更新。