微信读书体验分享

免费读书方案有很多, 但是微信读书的确是体验做的较好的一个. 希望免费读书的可以看 zlibrary.

这里主要分享微信读书的使用体验, 以及一些辅助工具, 如有任何侵权, 请联系我删除: [email protected]

微信读书自动打卡刷时长

只为便宜一点买微信读书会员.

只为便宜一点买微信读书会员

微信读书规则

  • 离线阅读计入总时长, 但需要联网上报
  • 网页版, 墨水屏, 小程序, 听书, 有声书收听都计入总时长
  • 对单次自动阅读或收听时长过长的行为, 平台将结合用户行为特征判断, 过长部分不计入总时长
  • 当日阅读超过5 分钟才算作有效阅读天数
  • 付费 5 元立即获得 2 天会员, 后续 30 日内打卡 29 天, 读书时长超过 30 小时, 可获得 30 天会员和 30 书币
  • 付费 50 元立即获得 30 天会员, 后续 365 日内打卡 360 天, 读书时长超过 300 小时, 可获得 365 天会员和 500 书币

根据实际操作, 还有如下未明确说明的特点:

  • 第 29 日打卡后立即获得读书会员奖励, 并可立即开始下一轮挑战会员打卡, 无需等待第 31 日开始下一轮挑战, 第 29 日的打卡既算上一轮的打卡, 也算下一轮的打卡.
  • 除第一轮需 29 日外, 后续每 28 日即可获得 32 日会员, 1+28*13=365, 一年可完成 13 轮, 花费 65 元, 获得 32*13=416 天会员和 390 书币.
  • 更划算的仍然是年卡挑战会员, 但周期更长, 风险更大.

工具特性

  • 使用有头浏览器
  • 支持本地浏览器和远程浏览器
  • 随机浏览器宽度和高度
  • 支持等待登录
  • 支持登录二维码刷新
  • 支持保存 cookies
  • 支持加载 cookies
  • 支持选择最近阅读的第 X 本书开始阅读
  • 默认随机选择一本书开始阅读
  • 支持自动阅读
  • 支持跳到下一章
  • 支持读完跳回第一章继续阅读
  • 支持选择阅读速度
  • 随机单页阅读时间
  • 随机翻页时间
  • 每分钟截图当前界面
  • 支持日志
  • 支持定时任务
  • 支持设置阅读时间
  • 支持邮件通知
  • 多平台支持: linux | windows | macos
  • 多架构支持: amd64 | arm64
  • 支持浏览器: chrome | MicrosoftEdge | firefox
  • 支持多用户
  • 异常时强制刷新
  • 使用统计

Linux

直接运行

# 安装nodejs
sudo apt install nodejs
# 老旧版本的 nodejs 需要安装 npm
sudo apt install npm
# 创建运行文件夹
mkdir -p $HOME/Documents/weread-challenge
cd $HOME/Documents/weread-challenge
# 安装依赖
npm install selenium-webdriver
# 下载脚本
wget https://storage1.techfetch.dev/weread-challenge/weread-challenge.js -O weread-challenge.js
# 通过环境变量设置运行参数
export WEREAD_BROWSER="chrome"
# 运行
WEREAD_BROWSER="chrome" node weread-challenge.js

如需邮件通知, 需安装 nodemailer: npm install nodemailer

Docker Compose 运行

services:
  app:
    image: jqknono/weread-challenge:latest
    pull_policy: always
    environment:
      - WEREAD_REMOTE_BROWSER=http://selenium:4444
      - WEREAD_DURATION=68
    volumes:
      - ./data:/app/data
    depends_on:
      selenium:
        condition: service_healthy

  selenium:
    image: selenium/standalone-chrome:4.26
    pull_policy: if_not_present
    shm_size: 2gb
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - SE_ENABLE_TRACING=false
      - SE_BIND_HOST=false
      - SE_JAVA_DISABLE_HOSTNAME_VERIFICATION=false
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:4444/wd/hub/status"]
      interval: 5s
      timeout: 60s
      retries: 10

保存为 docker-compose.yml, 运行 docker compose up -d.

Docker 运行

# run selenium standalone
docker run --restart always -d --name selenium-live \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --shm-size="2g" \
  -p 4444:4444 \
  -p 7900:7900 \
  -e SE_ENABLE_TRACING=false \
  -e SE_BIND_HOST=false \
  -e SE_JAVA_DISABLE_HOSTNAME_VERIFICATION=false \
  -e SE_NODE_MAX_INSTANCES=10 \
  -e SE_NODE_MAX_SESSIONS=10 \
  -e SE_NODE_OVERRIDE_MAX_SESSIONS=true \
  selenium/standalone-chrome:4.26

# run weread-challenge
docker run --rm --name user-read \
  -v $HOME/weread-challenge/user/data:/app/data \
  -e WEREAD_REMOTE_BROWSER=http://172.17.0.2:4444 \
  -e WEREAD_DURATION=68 \
  weread-challenge:latest

# add another user
docker run --rm --name user2-read \
  -v $HOME/weread-challenge/user2/data:/app/data \
  -e WEREAD_REMOTE_BROWSER=http://172.17.0.2:4444 \
  -e WEREAD_DURATION=68 \
  weread-challenge:latest

创建定时任务

docker-compose 方式

WORKDIR=$HOME/weread-challenge
mkdir -p $WORKDIR
cd $WORKDIR
cat > $WORKDIR/docker-compose.yml <<EOF
services:
  app:
    image: jqknono/weread-challenge:latest
    pull_policy: always
    environment:
      - WEREAD_REMOTE_BROWSER=http://selenium:4444
      - WEREAD_DURATION=68
    volumes:
      - ./data:/app/data
    depends_on:
      selenium:
        condition: service_healthy

  selenium:
    image: selenium/standalone-chrome:4.26
    pull_policy: if_not_present
    shm_size: 2gb
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - SE_ENABLE_TRACING=false
      - SE_BIND_HOST=false
      - SE_JAVA_DISABLE_HOSTNAME_VERIFICATION=false
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:4444/wd/hub/status"]
      interval: 5s
      timeout: 60s
      retries: 10
EOF
# 首次启动后, 需微信扫描二维码登录, 二维码保存在 $HOME/weread-challenge/data/login.png
# 每天早上 7 点启动, 阅读68分钟
(crontab -l 2>/dev/null; echo "00 07 * * *  cd $WORKDIR && docker compose up -d") | crontab -

docker 方式

# 启动浏览器
docker run --restart always -d --name selenium-live \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --shm-size="2g" \
  -p 4444:4444 \
  -p 7900:7900 \
  -e SE_ENABLE_TRACING=false \
  -e SE_BIND_HOST=false \
  -e SE_JAVA_DISABLE_HOSTNAME_VERIFICATION=false \
  -e SE_NODE_MAX_INSTANCES=3 \
  -e SE_NODE_MAX_SESSIONS=3 \
  -e SE_NODE_OVERRIDE_MAX_SESSIONS=true \
  -e SE_SESSION_REQUEST_TIMEOUT=10 \
  -e SE_SESSION_RETRY_INTERVAL=3 \
  selenium/standalone-chrome:4.26

WEREAD_USER="user"
mkdir -p $HOME/weread-challenge/$WEREAD_USER/data

# Get container IP
Selenium_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' selenium-live)

# 首次启动后, 需微信扫描二维码登录, 二维码保存在 $HOME/weread-challenge/$WEREAD_USER/data/login.png
# 每天早上 7 点启动, 阅读68分钟
(crontab -l 2>/dev/null; echo "00 07 * * * docker run --rm --name ${WEREAD_USER}-read -v $HOME/weread-challenge/${WEREAD_USER}/data:/app/data -e WEREAD_REMOTE_BROWSER=http://${Selenium_IP}:4444 -e WEREAD_DURATION=68 -e WEREAD_USER=${WEREAD_USER} jqknono/weread-challenge:latest") | crontab -

Windows

# 安装nodejs
winget install -e --id Node.js.Node.js
# 创建运行文件夹
mkdir -p $HOME/Documents/weread-challenge
cd $HOME/Documents/weread-challenge
# 安装依赖
npm install selenium-webdriver
# 下载脚本powershell
Invoke-WebRequest -Uri https://storage1.techfetch.dev/weread-challenge/weread-challenge.js -OutFile weread-challenge.js
# 通过环境变量设置运行参数
$env:WEREAD_BROWSER="MicrosoftEdge"
# 运行
node weread-challenge.js

Docker 运行同 Linux.

MacOS

# 安装nodejs
brew install node
# 创建运行文件夹
mkdir -p $HOME/Documents/weread-challenge
cd $HOME/Documents/weread-challenge
# 安装依赖
npm install selenium-webdriver
# 下载脚本
wget https://storage1.techfetch.dev/weread-challenge/weread-challenge.js -O weread-challenge.js
# 通过环境变量设置运行参数
export WEREAD_BROWSER="chrome"
# 运行
node weread-challenge.js

Docker 运行同 Linux.

多用户支持

# 启动浏览器
docker run --restart always -d --name selenium-live \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --shm-size="2g" \
  -p 4444:4444 \
  -p 7900:7900 \
  -e SE_ENABLE_TRACING=false \
  -e SE_BIND_HOST=false \
  -e SE_JAVA_DISABLE_HOSTNAME_VERIFICATION=false \
  -e SE_NODE_MAX_INSTANCES=10 \
  -e SE_NODE_MAX_SESSIONS=10 \
  -e SE_NODE_OVERRIDE_MAX_SESSIONS=true \
  selenium/standalone-chrome:4.26

WEREAD_USER1="user1"
WEREAD_USER2="user2"
mkdir -p $HOME/weread-challenge/$WEREAD_USER1/data
mkdir -p $HOME/weread-challenge/$WEREAD_USER2/data

# Get container IP
Selenium_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' selenium-live)

# 首次启动后, 需微信扫描二维码登录, 二维码保存在:
# /$HOME/weread-challenge/${WEREAD_USER1}/data/login.png
# /$HOME/weread-challenge/${WEREAD_USER2}/data/login.png
# 每天早上 7 点启动, 阅读68分钟
(crontab -l 2>/dev/null; echo "00 07 * * * docker run --rm --name ${WEREAD_USER1}-read -v $HOME/weread-challenge/${WEREAD_USER1}/data:/app/data -e WEREAD_REMOTE_BROWSER=http://${Selenium_IP}:4444 -e WEREAD_DURATION=68 -e WEREAD_USER=${WEREAD_USER1} jqknono/weread-challenge:latest") | crontab -
(crontab -l 2>/dev/null; echo "00 07 * * * docker run --rm --name ${WEREAD_USER2}-read -v $HOME/weread-challenge/${WEREAD_USER2}/data:/app/data -e WEREAD_REMOTE_BROWSER=http://${Selenium_IP}:4444 -e WEREAD_DURATION=68 -e WEREAD_USER=${WEREAD_USER2} jqknono/weread-challenge:latest") | crontab -

可配置项

环境变量 默认值 可选值 说明
WEREAD_USER weread-default - 用户标识
WEREAD_REMOTE_BROWSER "" - 远程浏览器地址
WEREAD_DURATION 10 - 阅读时长
WEREAD_SPEED slow slow,normal,fast 阅读速度
WEREAD_SELECTION random [0-4] 选择阅读的书籍
WEREAD_BROWSER chrome chrome,MicrosoftEdge,firefox 浏览器
ENABLE_EMAIL false true,false 邮件通知
EMAIL_SMTP "" - 邮箱 SMTP 服务器
EMAIL_USER "" - 邮箱用户名
EMAIL_PASS "" - 邮箱密码
EMAIL_TO "" - 收件人
WEREAD_AGREE_TERMS true true,false 隐私同意条款

容器多架构支持

支持 linux/amd64,linux/arm64, 支持树莓派等开发板.

docker buildx create --name weread-challenge
docker buildx use weread-challenge
docker buildx inspect --bootstrap
docker buildx build --platform linux/amd64,linux/arm64 -t jqknono/weread-challenge:base -f Dockerfile.base --push .
docker buildx build --platform linux/amd64,linux/arm64 -t jqknono/weread-challenge:latest -f Dockerfile.quick --push .

注意事项

  • 28 日刷满 30 小时, 需每日至少 65 分钟, 而不是每日 60 分钟.
  • 微信读书统计可能会漏数分钟, 期望每日获得 65 分钟, 建议调整阅读时长到 68 分钟
  • 网页扫码登录 cookies 有效期为 30 天, 30 天后需重新扫码登录, 适合月挑战会员
  • 邮件通知可能被识别为垃圾邮件, 建议在收件方添加白名单
  • 本项目仅供学习交流使用, 请勿用于商业用途, 请勿用于违法用途
  • 如存在可能的侵权, 请联系 [email protected], 本项目会立即删除

隐私政策

  • 隐私获取
    • 本项目搜集使用者的 cookies 部分信息, 以用于使用者统计和展示.
    • 搜集使用者的使用信息, 包含: 用户名称 | 首次使用时间 | 最近使用时间 | 总使用次数 | 浏览器类型 | 操作系统类别 | 阅读时长设置 | 异常退出原因
    • 如不希望被搜集任何信息, 可设置启动参数WEREAD_AGREE_TERMS=false
  • 风险提示
    • cookies 可用于微信读书网页登录, 登录后可以执行书架操作, 但本工具不会使用搜集的信息进行登录操作.
    • 腾讯保护机制确保异常登录时, 手机客户端将收到风险提示, 可在手机客户端设置->登录设备中确认登录设备.
    • 本工具纯 js 实现, 容易反混淆和扩展, 第三方可以继续开发. 即使信任本工具, 也应在使用自动化工具时, 经常确认登录设备, 避免书架被恶意操作.

参考

关闭独显以省电

这篇文分享给台式机很少关机, 经常远程回家中的台式机上工作的朋友.

我的主力工作机和游戏机是同一台机器, 显示屏是 4K 144Hz, 日常都是开着独显, 普通操作显示都会更顺滑一些, 但是功耗也是明显更大.

以下截图里的功率同时带着一个 J4125 小主机, 日常功耗在 18w 上下, 因此结论可能有不准确的地方

不开游戏, 在桌面快速滑动鼠标的峰值功率可以到192w

关闭独显后, 刷新率降到 60Hz, 峰值功率降到120w上下.

在外隧道回家工作是使用的腾讯的一个入门主机, 带宽较小, 远端刷新率只有 30hz, 这种情况用独显是没有意义, 可以考虑切换到集显.

多数时候, 我不直接使用远程桌面, 而是使用 vscode 的远程开发, 优势是隐蔽, 占用带宽小, 几乎是本地开发的体验.

普通代码编辑时, 约 72w, 与关闭独显前的 120w 相比, 有一定的节能效果.

使用remote ssh进行远程开发时, 可以用使用脚本关闭独显.

脚本保存为switch_dedicate_graphic_cards.ps1, 使用方法为switch_dedicate_graphic_cards.ps1 off

# Usage: switch_dedicate_graphic_cards.ps1 on|off

# Get parameters
$switch = $args[0]

# exit if no parameter is passed
if ($switch -eq $null) {
    Write-Host "Usage: switch_dedicate_graphic_cards.ps1 on|off" -ForegroundColor Yellow
    exit
}

# Get display devices
$displayDevices =  Get-CimInstance -Namespace root\cimv2 -ClassName Win32_VideoController

# If there is no display device or only one display device, exit
if ($displayDevices.Count -le 1) {
    Write-Host "No display device found."
    exit
}

# Get dedicated graphic cards
$dedicatedGraphicCards = $displayDevices | Where-Object { $_.Description -like "*NVIDIA*" }

# If there is no dedicated graphic card, exit
if ($dedicatedGraphicCards.Count -eq 0) {
    Write-Host "No dedicated graphic card found."
    exit
}

# turn dedicated graphic cards on or off
if ($switch -eq "on") {
    $dedicatedGraphicCards | ForEach-Object { pnputil /enable-device $_.PNPDeviceID }
    Write-Host "Dedicated graphic cards are turned on."
} elseif ($switch -eq "off") {
    $dedicatedGraphicCards | ForEach-Object { pnputil /disable-device $_.PNPDeviceID }
    Write-Host "Dedicated graphic cards are turned off."
} else {
    Write-Host "Invalid parameter."
    Write-Host "Usage: switch_dedicate_graphic_cards.ps1 on|off" -ForegroundColor Yellow
}

docker

k8s 和 docker

docker介绍

  • docker介绍

docker 介绍

  • docker 是一个应用容器引擎, 可以打包应用及其依赖包到一个可移植的容器中, 然后发布到任何流行的 Linux 或 Windows 机器上, 也可以实现虚拟化.
  • 为什么会有 docker, 因为开发和运维经常遇到一类问题, 那就是应用在开发人员的环境上运行没有任何问题, 但在实际生产环境中却 bug 百出.
    • 程序的运行从硬件架构到操作系统, 再到应用程序, 这些都是不同的层次, 但是开发人员往往只关注应用程序的开发, 而忽略了其他层次的问题.
    • docker 的出现就是为了解决这个问题, 它将应用程序及其依赖, 打包在一个容器中, 这样就不用担心环境的问题了.
  • 同步开发和生产环境, 使开发人员可以在本地开发, 测试, 部署应用程序, 而不用担心环境的问题. 显著提升了开发和运维的效率, 代价是一点点资源的浪费.

我极力建议所有开发者都学会使用容器进行开发和部署, 它以相对很低的代价, 为你的应用程序提供一个稳定的运行环境, 从而提高开发和运维的效率.

使用一些通俗的语言来描述使用 docker 的一种工作流:

  1. 从零创建一个开发的环境, 包含了操作系统, 应用程序, 依赖包, 配置文件等等.
    • 环境可以在任何地方运行, 也可以在任何地方创建.
    • 环境对源码编译的结果稳定且可预测, 行为完全一致.
    • 环境中程序的运行不会产生任何歧义.
    • 最好是可以使用声明式的方式来创建环境(docker-compose), 进一步减少环境的隐藏差异, 环境的一切都已在声明里展示.
  2. 创建一个 commit, 创建镜像, 这相当于一个快照, 保存当前的环境, 以便以后使用.
  3. 分享镜像给其它开发和运维, 大家基于相同语境同步展开工作.
  4. 随着业务的发展需求, 修改镜像, 重新创建 commit, 重新创建镜像, 重新分发.

docker 的基本架构

adguard

利用DNS服务平滑切换网络服务

假设服务域名为example.domain, 原服务器 IP 地址为A, 由于服务器迁移或 IP 更换, 新服务器 IP 地址为B, 为了保证用户无感知, 可以通过 DNS 服务平滑切换网络服务.

  1. 原服务状态, example.domain 解析到 IP 地址A
  2. 过渡状态, example.domain 解析到 IP 地址AB
  3. 新服务状态, example.domain 解析到 IP 地址B, 移除 IP 地址A

说明: 当用户获得两个解析地址时, 客户端会选择其中一个地址进行连接, 当连接失败时, 会尝试其它地址, 以此保证服务的可用性.

由于 DNS 解析存在缓存, 为了保证平滑切换, 需要在过渡状态保持一段时间, 以确保所有缓存失效.

我这里需要迁移的是 dns 服务, 可以在过渡状态中设置DNS重写, 加快迁移过程.

A 服务重写规则:

A服务重写

B 服务重写规则:

B服务重写

原迁移过程拓展为:

  1. 原服务状态, example.domain 解析到 IP 地址A
  2. 过渡状态, example.domaindns A服务中重写到AB, 在dns B服务中重写到B
  3. 新服务状态, example.domain 解析到 IP 地址B, 移除 IP 地址A

当用户仍在使用dns A服务时, 可以获得两个地址, 有一半的概率会选择dns A服务.
另外一半的概率会切换到dns B服务, dns B服务故障时切换回dns A. dns B服务未故障时, 将只会获得一个地址, 因而用户会停留在dns B服务中.
这样我们可以逐步的减少dns A服务的资源消耗, 而不是直接停止, 实现更平滑的迁移.

测试工具

  • 测试工具

测试工具

简易server-client代码

  • 简易server-client代码

简易 server-client 代码 windows

Windows

Complete Winsock Client Code Complete Winsock Server Code

Linux

Linux Socket Programming Simple client/server application in C

AI

Copilot系列

  • Copilot系列