MoreRSS

site iconBAI YUN修改

WEB 全栈开发,注重产品用户体验,关注长期价值,BUILD WEB3。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

BAI YUN的 RSS 预览

浙江杭州电信 IPTV 内网融合教程:在局域网任意设备观看 IPTV

2026-01-15 23:01:08

背景

传统的 IPTV 需要使用运营商提供的 IPTV Box 连接电视才能观看,这种方案有几个缺点:

  • 客厅如果只有一个网口就得在上网和 IPTV 之间二选一
  • 每次看 IPTV 必须切换视频信号到 IPTV Box,稍微麻烦一些
  • 必须忍受 IPTV Box 的 UI/UX
  • 客厅电视没有空闲的 HDMI 端口可用(已经连接了多个设备,例如游戏机、其他电视盒子)

如果你想解决这些问题。网络上通常有很多术语,令人眼花缭乱,例如 IPTV 组播转单播、IPTV 单线复用、光猫超级管理员密码之类的概念。

本文经过实际测试摸索,找到一条相对简单高效的方案,大概只需要10分钟时间即可配置完毕。

前置条件

  • 已开通 IPTV 服务,如果你已经在用融合宽带套餐,每个月加 10 块钱就可以
  • 光猫和路由器放在一起,可以从光猫接两根网线到路由器
  • 光猫有单独标识的 ITV 端口
  • 局域网内有可以安装 docker 镜像的设备(例如 NAS)或者你有其他办法可以在局域网内部署 https://github.com/stackia/rtp2httpd
  • OpenWrt 软路由或者其他支持自定义 dhcp client hostname 和 option 的路由器

前置测试

我的光猫是在安装宽带时就设置了桥接模式加路由器拨号,除此以外没有改过网络接口相关设置。也就说你不需要超级管理员账密。

将光猫 ITV 口接一根网线连到电脑,在电脑网络设置里手动设置此连接的 IP(指定为 192.168.1.1xx)具体 IP 段一般和光猫背面展示的控制台地址一致。本文后面以此 IP 段示例。
网关指定为 192.168.1.1

然后使用 VLC 播放器播放组播地址,可以从以下项目找具体地址:
https://github.com/FHZDCJ/Zhejiang_Telecom_IPTV/blob/main/Zhejiang_Multicast/Zhejiang_Telecom_IPTV.m3u

格式:rtp://233.xxx.xxx.xxx:5140,如果可以正常播放组播源,则继续后面的步骤。

在执行此测试的时候建议关闭 Wi-Fi 和 surge 之类的工具。确保所有请求直接通过网线发给光猫的 ITV 口。

组播转单播

组播转单播架构图

如果前面的测试通过,说明你当前的网络条件可以正常播放组播源信号。

接下来为了实现在局域网内任意设备观看 IPTV,需要将组播信号(通常是 rtp 协议)转为单播信号(http 协议)。

首先需要在局域网内正常部署 https://github.com/stackia/rtp2httpd 服务。
我是直接在 NAS 上通过 Docker Compose 部署的,配置如下:

services:
  rtp2httpd:
    image: ghcr.io/stackia/rtp2httpd:latest
    container_name: rtp2httpd
    network_mode: host
    command: --noconfig --verbose 2 --listen 5140 --maxclients 20

待你可以正常访问 http://NAS-IP:5140/status 之后再进行下一步。

将光猫 ITV 口连接到路由器的第二个 WAN 口(第一个 WAN 口用于正常上网),这一步的主要目的是实现在正常上网的这个 LAN(局域网) 里面通过 HTTP 单播源观看 IPTV。

我用的是 Unifi 路由器,直接在控制台新建一个 WAN 口,关联刚才连接 ITV 口的端口,同时勾选 IGMP proxy 开关(这个很关键),选择静态 ip。

IGMP Proxy 和 ITV WAN 口配置

此时在 VLC 里打开 rtp2httpd 格式的单播信号源地址:

http://192.168.10.20:5140/rtp/239.xxx.xxx.xxx:5140

这里 192.168.10.20 是我的 NAS 地址,里面用 docker 部署了rtp2httpd(host 网络模式,默认绑定在 5140 端口),239.xxx.xxx.xxx 是具体 IPTV 频道的组播地址。

正常情况下这里就可以正常观看了。

最后,为了方便切换所有可观看的频道,可以将这里的 m3u 文件进行修改:
https://github.com/FHZDCJ/Zhejiang_Telecom_IPTV/blob/main/Zhejiang_Multicast/Zhejiang_Telecom_IPTV_ONLINE_LOGO.m3u

替换里面的链接为 rtp2httpd 格式,以下是替换后的示例:

#EXTM3U
#EXTINF:-1 tvg-id="CCTV1" tvg-name="CCTV1" group-title="央视",CCTV1综合
http://192.168.10.20:5140/rtp/233.xxx.xxx.xxx:5140
#EXTINF:-1 tvg-id="CCTV2" tvg-name="CCTV2" group-title="央视",CCTV2财经
http://192.168.10.20:5140/rtp/233.xxx.xxx.xxx:5140

将修改后的 m3u 文件导入到 APTV 之类的软件即可在 Apple TV、Mac、iPhone 等局域网设备观看 IPTV 频道。

关于 IGMP Snooping

这个开关实际测试,开了之后总会遇到各种问题,会导致断流或者不可用。

IGMP Snooping 配置开关

前面新建 WAN 口的时候我们开启了 IGMP Proxy,IPTV 信号成功进入了局域网(LAN),但此时如果你没有开启(或设备不支持)IGMP Snooping 就会发生“泛洪机制”。

IGMP Snooping 泛洪对比图

为什么会发生泛洪?
IGMPProxy 的工作(L3): 路由器把 WAN 口进来的 IPTV 视频流(比如 20Mbps 的高清流)转发到了 LAN 口。

交换机/LAN 的困惑(L2): 到了局域网这一层,普通的二层交换机(或者路由器内部集成的交换芯片)如果不运行 IGMP Snooping,它就看不懂这个组播包。

默认行为: 对于看不懂的组播包,交换机的默认处理方式是把它当成广播(Broadcast)。它会想:“我不知道谁要这个包,为了保险起见,我发给所有人吧!”

下图是局域网开启 IGMP Snooping 之前和之后的对比,注意当我在 Mac Mini 上用 APTV 观看 IPTV 频道时,Apple TV 和 Flex 摄像头的端口流量。

开启 IGMP Snooping 前后对比

可以清晰看到,虽然我只在 Mac Mini 上观看 IPTV,但是流量被发送到了其他局域网端口(这里是 Apple TV + Flex 摄像头)。这会造成带宽和性能浪费。

IGMP Snooping 就是用来解决这个问题的。
IGMP Snooping(窥探) 是二层交换机(或桥接接口)的一个功能。它的做法: “偷听” IGMP Proxy 和机顶盒之间的对话。效果:

它听到机顶盒说:“我要看 CCTV-5”。

它就在心里记下:“只有 LAN Port 2 需要这个组播流”。

当视频流过来时,它只把数据发给 Port 2,其他端口(Port 1, 3, Wi-Fi)完全收不到这个数据。有效避免了垃圾流量产生。

IGMP Snooping 开启后如果出现异常状况,例如观看 IPTV 几分钟后自动断开无信号,则可以尝试关闭此开关。

原始单播信号

组播最大的问题是性能影响,在观看 IPTV 的时候会给局域网内所有设备端口进行 “泛洪” 发送无意义流量包。

对于 IPTV 重度用户或者愿意花时间优化的人,我更推荐在局域网内直接使用原始单播信号观看。

所谓原始单播信号是指直接在局域网任意设备上使用下面这种格式的 URL 即可观看 IPTV 频道:

rtsp://115.xxx.xxx.xxx/PLTV/88888913/224/3221228078/xxx.smil

对于杭州电信来说,想要访问运营商提供的单播信号源,需要通过和 IPTV 盒子一样的认证才可以。

杭州电信的 IPTV 盒子使用 IPoE 认证,打开 IPTV 盒子的网络设置可以发现,正常通过认证的情况下可以获取到 10 开头的 IP 地址和网关地址。

要想认证通过拿到合法的 IP 和网关信息,IPTV 盒子会作为一个 DHCP Client 向运营商发送 DHCP 报文,并在报文里携带两个关键信息:

  1. hostname (option 12) 这个值是盒子的STB ID+mac地址拼接而成,具体格式见下方。
  2. vendorid (option 60) 这个值是盒子内部使用 IPoE 账密 + 其他逻辑计算生成后发送的,需要抓包获取

IPoE (IP over Ethernet) 是一种直接在以太网(Ethernet)上承载 IP 数据的网络接入技术,它替代了传统的 PPPoE,通过 DHCP 动态获取 IP 地址并利用用户的物理信息(如 MAC 地址、VLAN ID)进行认证。

获取 hostname

STB ID

记下盒子上的 STB ID 和 mac 地址,将两者拼在一起,去除 mac 地址里的冒号 :,字母转为全大写。下面是示例:
STB ID:00108325090207200000
mac 地址:B1:FD:F1:E2:58:FD

拼接后完整值就是 hostname 的值:

00108325090207200000B1FDF1E258FD

获取 vendorid (option 60)

这一步核心原理是抓取 IPTV 盒子开机后发送的 DHCP 报文,里面包含了盒子内部计算好的 vendorid。

抓包方式有很多种,简单的一种是直接将盒子用网线(交叉线)连接到电脑网口,电脑启动 Wireshark 捕获对应的网口,待盒子通电开机后,在 Wireshark 顶部搜索框输入 dhcp 过滤出所有 dhcp 报文。

找到对应报文点击 option 60,选中里面的 vendor info, 右键 copy as hex stream,复制到的内容应当是这种格式:00001f39d35c06c5560f91e4f652a438f7bd9ad33a5972fb06e75f6f45cb4fdfb190045a51153196b05f5a7b5d5b6f699b5d5b4956975b4900000000300e89ed9c786007ee110

将其保存起来。

注意 DHCP 报文里的 客户端 mac 地址要和 IPTV 盒子的 mac 地址匹配,避免被电脑自己发出的报文干扰。

配置主路由网络接口

我的光猫 ITV 口和主路由 UDM Port 4 用网线连接。确保 Port 4 没被分配给 WAN 口。

ITV 网口确保没被分配给 WAN 口

新建 IPTV VLAN

id 设置为 100,命名为 IPTV, 避免和其他 vlan id 混淆:

新建 vlan 100

设置 OpenWrt 对应的交换机端口

我的 OpenWrt 是一个树莓派,我将其插入了客厅 USW 交换机的 Port 6,需要正确配置此端口:

Native VLAN:选择局域网主 VLAN
Tagged VLAN Management:custom
Tagged VLANs:选择前面新增的 VLAN 100

OpenWrt 对应的交换机端口设置

配置 OpenWrt 软路由

由于我家里的 UDM 路由器不支持设置 DHCP Client 的 hostname,所以找来找去还是找一台设备刷个 OpenWrt 最简单,我是找了家里吃灰的树莓派 4B 刷了最新稳定版 OpenWrt。

修改网络接口

新增 一个 device,一个 interface:

vim /etc/config/network
config device
	option type '8021q'
	option ifname 'eth0'
	option vid '100'
	option name 'eth0.100'

config interface 'IPTV_WAN'
	option proto 'dhcp'
	option device 'eth0.100'
	option metric '20'
	option hostname '这里替换为前面拼接获取的hostname'
	option macaddr '这里替换为iptv盒子的完整mac地址'
	option sendopts '60:这里替换为前面抓包拿到的vendorid'
	option defaultroute '0'

修改 lan 的 IP 地址:

vim /etc/config/network

将 interface 'lan' 改为静态 IP,指定正确的局域网 IP 和网关地址。

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '主路由器局域网IP地址(没被使用的)'
	option netmask '255.255.255.0'
	option ip6assign '60'
	option gateway '主路由器网关地址'
	option metric '20'

修改 dhcp.sh 脚本

vim /lib/netifd/proto/dhcp.sh

原版:会导致 DHCP 报文发送两个 option 60


proto_run_command "$config" udhcpc \
		-p /var/run/udhcpc-$iface.pid \
		-s /lib/netifd/dhcp.script \
		-f -t 0 -i "$iface" \
		${ipaddr:+-r $ipaddr} \
		${hostname:+-x "hostname:$hostname"} \
		${vendorid:+-V "$vendorid"} \
		$clientid $defaultreqopts $broadcast $release $dhcpopts

修改后的版本:去除了 ${vendorid:+-V "$vendorid"} 这一行,增加了 -V '' \ 这行

	proto_run_command "$config" udhcpc \
		-p /var/run/udhcpc-$iface.pid \
		-s /lib/netifd/dhcp.script \
		-f -t 0 -i "$iface" \
		${ipaddr:+-r ${ipaddr/\/*/}} \
		${hostname:+-x "hostname:$hostname"} \
		-V '' \
		$clientid $defaultreqopts $broadcast $norelease $dhcpopts

设置静态路由

如果要正常在局域网内访问单播地址,就需要将单播服务器的 IP 设置静态路由让其可以正常走 IPTV-WAN 出去,最终走到光猫 ITV 口。

用下面的脚本自动化获取 IPTV_WAN 口的 网关 地址,然后添加静态路由。

所以后续如果要添加新的静态路由,则需要编辑这个脚本里的 TARGET_NET 变量。

vim /etc/hotplug.d/iface/99-iptv-route
#!/bin/sh

[ "$INTERFACE" = "IPTV_WAN" ] || exit 0

# 这里 115.233.40.0/21 这个段是单播服务器地址
TARGET_NET="115.233.40.0/21"

if [ "$ACTION" = "ifup" ]; then
    GW=$(ifstatus $INTERFACE | jsonfilter -e '@.inactive.route[@.target="0.0.0.0"].nexthop')
    if [ -z "$GW" ]; then
        GW=$(ifstatus $INTERFACE | jsonfilter -e '@.data.dhcpserver')
    fi

    if [ -n "$GW" ]; then
         # 强制单播服务器 IP 路由到 IPTV_WAN 口的网关地址
         ip route replace $TARGET_NET via $GW dev $DEVICE
         logger -t IPTV_Route "Fixed: Replaced DHCP route for $TARGET_NET via $GW"
    fi
fi

主路由静态 IP 设置

为了确保在局域网内访问单播服务器时,流量走光猫的 ITV 口出去,需要在主路由上指定静态 IP 路由表,实现局域网内任意设备访问单播服务器 IP -> 静态路由到 OpenWrt -> 走 IPTV_WAN -> 光猫 ITV 口。一旦路由策略不对,导致流量走到常规公网口去了,就会出现单播无法访问的情况。

UDM 静态IP策略

验证

以上配置全部调整好之后,重启网络以验证。注意待你重启后电脑就无法直接通过网线访问 OpenWrt 了,因为前面已经改成了主路由局域网内的 static 静态 IP,你需要将 OpenWrt 设备接入到主路由的 lan 口或者下面的交换机上面。再用你指定的静态 IP 重新访问。

重启 OpenWrt 网络:

/etc/init.d/network restart

到这里正常情况下就大功告成了,可以在局域网内直接播放原始单播信号源。

关于 OpenWrt 支持组播信号源

在本文最前面我们没有使用 OpenWrt 也实现了正常播放组播信号,但是如果你已经有一台 OpenWrt 了,并且按照本文前面的内容进行了单播相关的设置,此时如果想同时支持组播,需要声明防火墙规则:

vi /etc/config/firewall
# --- IPTV 专用规则 ---
# 允许 UDP 组播视频流量进入,否则有信号无画面
config rule
	option name 'Allow-IPTV-UDP'
	option src 'wan'
	option proto 'udp'
	option dest_ip '224.0.0.0/4'
	option target 'ACCEPT'

本文网络拓扑参考

组播转单播

组播转单播网络拓扑图

原始单播

为了正常访问原始单播信号源,网络架构变的复杂了很多。

总结

通过本文方案,唯一的物理链路修改是光猫到路由器多了一根网线,客厅网口和 HDMI 线完全没有任何调整,实现了在我现有的 Apple TV 设备上观看 IPTV 节目。整体具备低延迟高稳定性。

踩坑需要耗费不少时间,如果此文对你有帮助,欢迎通过 /buyMeCoffee 请我喝杯咖啡。

相关资源

要获得最佳阅读体验,请访问原文 https://baiyun.me/zhejiang-hangzhou-telecom-iptv

美国住宅 IP 提供商体验对比

2025-06-04 23:13:13

house

近期因为 ChatGPT 降智问题,研究和体验了一波美国住宅IP代理。

IPRoyal

  • 价格适中,网站交互简单,入门套餐门槛低
  • 可以直连节点(其他家大多需要先连接到入口网关),号称支持 udp 协议(我没测试)
  • 缺点是 IP 持有量似乎不大,美国加州 IP 一直缺货

IPRoyal web page

第一次就开到了数据上及其干净的美国住宅 IP:

ping0.cc IP检测结果

Bright Data

  • 交互、IP质量、稳定性、灵活性方面综合体验不错
  • 可以随时剔除不想要的IP,然后再加新的 IP 回来。
  • 有次它家部分 IP 故障了几个小时,恢复后把我之前精选的 IP 自动换了一个(地理位置不可控)我就停止续费了
  • 计费逻辑有些奇怪,多添加IP之后会立即扣一个月的钱,即使后面把这个IP删除了也不会返还
  • 如果是公司或者业务系统使用我会优先选这家

Bright Data web page

MarsProxies

  • 产品体验精致小巧,最大的特色是支持永不过期的流量包模式(IP定期轮转)
  • 住宅 IP 的延迟相比其他家高很多
  • ISP 代理 IP的延迟同样很高(即使我用同一个州的节点连接),界面上没有更换 IP 的入口,开出来的 IP 质量层次不齐,不推荐

MarsProxies web page

DECODO

  • 独享IP的入门门槛较高,需要10个IP起步(35美元/月)
  • 对支付宝支付不友好(需要支付额外10几个点的税费)
  • 静态住宅 IP 质量非常一般,不推荐
  • 动态住宅 IP 的IP 质量明显好很多,可惜不能指定 IP 固定,所以也不适合日常上网使用

DECODO web page

VIRCS 美国家庭住宅宽带 VPS

  • 这家号称是真实的家宽,我测试下来 IP 确实没问题(洛杉矶 AT&T 家宽),延迟和速度也正常。
  • 并且这家可以选择直接开一台 VPS 自行搭建自己喜欢的协议(也提供直接 SOCKS5 代理,价格几乎一样)
  • 主要缺点是价格相比传统的静态住宅IP服务商来说比较贵,最低 36 美元一个月,你可以获得一个 IPv4 和 IPv6,最大带宽 35Mbps(可加钱提升带宽)不限流量
  • 我实际用了几个月,可能是家宽的原因稳定性会差一些,对稳定性有要求的需要自备一个备选代理

其他几个超出预期的商家

体验测试中...

一些感想

  • 这些服务我觉得是适合写爬虫之类的程序时用于降低机器人拦截几率,而不是用于日常 VPN 上网,比如看油管之类的。实际体验下来它们大多延迟堪忧,下载东西挺快,但是对于浏览网页来说,体感上明显慢太多。
  • 要买原生住宅IP推荐选择美国这种IP多的国家,新加坡这种就很难碰到原生IP。
  • 隐身模式访问 https://www.reddit.com/ 可以初步判断这个 IP 有没有被认为是家宽 IP
  • 基本不支持转发 udp 流量,对于少部分依赖 udp/quic 协议的场景会是个问题
  • 对于ChatGPT这种场景优先选择独享住宅ip而不是定期轮转。以最大化提升ip可控性

题外话

最后,我认为 ChatGPT 这种根据 ip 偷偷降智的做法迟早会被市场教育,随着 AI 厂商竞争白热化,再搞这种小动作只会把用户拱手让给竞争对手,毕竟没有多少用户愿意花这么大代价去解决 ChatGPT 降智。除非 OpenAI 可以持续大幅领先对手。但,可能吗?能保持多久?

例如之前的 Claude 乱封号(刚续费会员)不退款,现在我都懒得看它一眼,Cursor 里我都优先选 Gemini 2.5 Pro。

要获得最佳阅读体验,请访问原文 https://baiyun.me/us-residential-ip-provider-comparison

Node.js 程序以 Keyless 模式从 1Password 读取密钥

2024-10-28 17:23:24

最近经常用 Node.js 写一些本地运行的脚本,需要安全的读取一些密钥密码之类的敏感信息,业界通常的做法是这样:

  • 通过环境变量读取
  • 通过在线的 KMS 系统读取

对于环境变量模式,一般情况需要在本地文件系统明文保存一些关键的密钥信息。本质上还是不太安全,例如你的钱包私钥明文放在本地文件系统,容易在未来的某一天爆雷,这种模式本质上不是无密码(Keyless)的。
对于 KMS 模式,需要依赖各种在线 KMS 服务,整体方案比较重,不太适合在本地电脑上轻量化使用。

本文使用 1Password 和官方提供的 CLI,在本地以无密码方式读取敏感信息。

具体方案

  1. 首先你需要是 1Password 用户(需要付费,家庭版比较实惠)
  2. 安装 CLI,我这里用 macOS 上的 brew 进行安装 brew install 1password-cli。具体可参考:https://developer.1password.com/docs/cli/get-started/
  3. 登录 1Password CLI:op account add
  4. 从 Node.js 读取指定的密钥
import { exec } from 'child_process'
import util from 'util'

const execPromise = util.promisify(exec)

// 使用内存缓存存储密钥
const secretCache = new Map<string, string>()

async function getSecretFromOnePassword(itemName: string, label: string): Promise<string> {
  const cacheKey = `${itemName}:${label}`

  // 检查缓存中是否已存在
  const cachedSecret = secretCache.get(cacheKey)
  if (cachedSecret) {
    console.log('从缓存获取密钥')
    return cachedSecret
  }

  console.log('从 1Password 获取密钥...')
  try {
    // 使用 op cli 获取 JSON 格式的 item 数据
    /*
        返回值示例:
        {
            "id": "xxx",
            "section": {
                "id": "add more"
            },
            "type": "CONCEALED",
            "label": "secret-key",
            "value": "xxx-value",
            "reference": "op://xxx/secret-key"
        }
        */
    const command = `op item get "${itemName}" --fields label="${label}" --format json`
    const { stdout } = await execPromise(command)

    // 解析返回的 JSON 并返回值
    const item = JSON.parse(stdout)
    if (item && item.value) {
      console.log('密钥获取成功')
      // 存入缓存
      secretCache.set(cacheKey, item.value)
      return item.value
    } else {
      throw new Error(`label "${label}" not found in item "${itemName}"`)
    }
  } catch (error) {
    console.error('从 1Password 获取密钥失败:', error)
    throw error
  }
}

1Password 字段说明

在执行脚本时,系统会弹出 1Password 确认框,待你确认后,程序就可以获取到对应的密钥。

1Password 授权确认框

结束语

本文用 Node.js 示范了如何在本地以 Keyless 模式读取 1Password 里的密钥,实现原理本质上是包装调用了 1Password 官方的 CLI 程序,其他语言例如 Python、Java、Golang 之类的也可以很轻松的实现本文的逻辑。
这套方案特别适合加密货币钱包私钥或者 root 账号私钥之类敏感内容,通过本文的方案可以满足可信消费和安全存储。

要获得最佳阅读体验,请访问原文 https://baiyun.me/nodejs-keyless-read-1password-secrets

高效优雅的观影指南

2024-10-28 16:59:03

本文主要聚焦在如何高效、优雅的观看你想看的任意 影视剧、体育、综艺等节目,尤其是一些国外的影视资源。只探讨技术,不提供任何无版权资源。

背景

近些年海内外各大内容巨头均推出了自己的流媒体平台,对于用户来说面临一个问题:经常需要订阅很多家平台的会员才有可能看到自己想看的内容。

对于国内用户来说,还额外面临一些尴尬的问题,比如近些年广电总局的限外令,国外影视剧在国内以肉眼可见的速度减少,很多电影的出品方甚至会直接取消在国内院线上映,例如最近漫威的 雷神4,其他例如 花月杀手 这些均没有在国内院线上映。

即使好不容易在国内上映,很多情况也会面临删减、改台词等问题。

另外,国内主流的流媒体平台普遍还有几个大的现状:

  • 视频画面强制包含 显眼的平台 LOGO 标,有点狗皮膏药的感觉
  • 视频码率普遍低,即使开通了会员也好不在哪里(用户以为自己看的是 最高画质的 4k,实际上因为画面码率的原因,质量还不如高码率的 1080p)
  • 国内平台的电视剧流行在视频中直接硬编码嵌入大量广告,观看体验不够沉浸纯粹

流媒体平台

国内主要是爱优腾三家,国外就非常多了。

国外主要的流媒体订阅平台

平台 公司 简介 订阅用户数量 代表作
Netflix Netflix, Inc. 全球最大的流媒体平台之一,以其丰富的原创内容和广泛的影视库而闻名。 超过2.3亿 - 《怪奇物语》 (Stranger Things) - 《纸牌屋》 (House of Cards) - 《王冠》 (The Crown)
Amazon Prime Video Amazon.com, Inc. 提供广泛的电影和电视剧集,并且拥有不少高质量的原创内容。 超过2亿 - 《指环王:力量之戒》 - 《了不起的麦瑟尔夫人》 (The Marvelous Mrs. Maisel)
Disney+ The Walt Disney Company 提供迪士尼、皮克斯、漫威、星球大战和国家地理的内容。 超过1.6亿 - 《曼达洛人》 (The Mandalorian) - 《旺达幻视》 (WandaVision) - 《洛基》 (Loki)
HBO Max Warner Bros. Discovery 提供HBO经典剧集以及Warner Bros.的电影和原创内容。 超过7700万 - 《权力的游戏》 (Game of Thrones) - 《切尔诺贝利》 (Chernobyl)
Hulu The Walt Disney Company (majority stake) & Comcast (minority stake) 提供丰富的电视剧集、电影和原创内容,主要面向美国市场。 超过4800万 - 《使女的故事》 (The Handmaid's Tale)
Paramount+ Paramount Global 提供派拉蒙电影公司、CBS、MTV、Nickelodeon等品牌的内容。 超过4600万 - 《星际迷航:发现号》 (Star Trek: Discovery) - 《黄石》 (Yellowstone) - 《好妻子》 (The Good Wife)
Apple TV+ Apple Inc. 苹果公司推出的流媒体平台,专注于高质量的原创内容,默认支持双杜比。 超过4000万 - 《基地》 - 《人生切割术》

影响视频质量的关键参数

除了耳熟能详的 分辨率和帧率。真正显著影响视频质量的主要包括以下几点:

  • 码率(Bitrate):码率是每秒传输的数据量,通常用kbps(千比特每秒)或Mbps(兆比特每秒)表示。码率越高,视频质量越好,但文件大小也会增大。常见的码率有2500kbps、5000kbps等。

  • 动态范围(Dynamic Range):动态范围指视频中最亮和最暗部分的差异。高动态范围(HDR)视频能显示更多的亮部和暗部细节。

    • 通俗的说,就是该亮的时候非常亮,例如聚光灯和日光、该暗的时候非常暗。同时确保细节依旧显示清晰。

    • 业界主流的 HDR 格式:

      主流 HDR 格式

  • 音频格式:好的音频质量可以确保你听到更多细节,更加沉浸。

    • 目前业界主流的高质量音频格式:

      高质量音频格式

观影工作流

  1. 获取内容
  2. 存储内容
  3. 整理内容
  4. 观看

内容获取

如果一些内容刚好这些流媒体平台都没有,这时候就有很多用户会使用 Bittorrent 协议以 p2p 的形式分享资源。

目前 BT 协议产生的流量依旧在全球流量占比中有接近 3% 的比例,比 Google 的流量还要高。

TOP 流量统计表

BT 协议是任何人都可以随时加入和离开的,它有一些缺点:

  • 吸血鬼太多(下载完就跑,从不主动上传)
  • 老的内容没人上传

所以,PT 诞生了,PT(Private Torrent) 本质上还是 BT,只不过它的 Tracker 是私有的,只有白名单用户可以连接到这个 Tracker 进而下载内容。如果用户只下载不上传,或者上传比例太低,账号就会自动被 ban,这样确保了 PT 的用户体验在大部分情况下比 BT 好很多。

PT 站点种子列表

内容获取流程:

  1. 确认家里宽带是否开通公网 IP(移动一般不行)
  2. 找一个适合自己的 BT/PT 站点,PT 站点基本都需要邀请码(可以找周围朋友获取,或者部分站点可以走官方的捐款途径获取邀请码)
  3. 设置下载工具:推荐用 qBittorrent
  4. 检查上传是否正常

很多片源都会自带中文字幕,对于一些新的资源没有带字幕的,可以去 subhd 之类的字幕分享网站下载。

内容存储

推荐方案是用 NAS,它相当于一台 24 小时开机、体积小巧、低功耗的电脑,厂商在设计上特地为内容存储做了优化,用户买回来插上硬盘就可以开箱即用。

大部分 NAS 上面都可以运行 Docker 容器,基于这个可以跑不少服务,且长期稳定运行。

绿联 NAS 控制台界面截图

NAS 品牌:群晖、威联通、极空间、绿联。对于喜欢折腾的用户来说推荐前两者,小白用户推荐后两者。

内容整理 + 观看

内容整理是指:自动从内容库识别这部影片的元信息(剧名、海报、剧照、卡司、分集信息)

Infuse 这款软件可以很高效实现内容整理、跨设备云端同步观看进度。以及正确播放几乎所有格式的视频,包括杜比视界。

Apple TV

Apple TV

Mac

Mac

iPhone

iPhone

基于这套工作流可以让我们的观影体验变得纯净且高质量。

观影设备

  1. 电影院:对于少数制作精良、大场面的电影,例如 沙丘、指环王,首选 电影院(杜比影院、IMAX 二代激光)
  2. 在家观看:NAS + AppleTV + 大尺寸电视(Sony、LG)+ 音响系统

音响系统

声音对于观影体验是至关重要的,相比于获得优质的视频画面,想要获得一个好的声音效果是更复杂的。

通常,优质的音响系统会让你感受到身临其境的沉浸感。相反,如果你能明显地感觉到声音来自某个特定方向,那就意味着声场质量很差。另外,一个常见的误解是声音并非越大越好,好声音的关键在于营造身临其境的空间感,同时保持扎实和清晰的层次。

选购音响系统首先要关注的是声道,不同声道的体验从普通到优秀排名如下:

  • 2.1 立体声
  • 5.1 环绕声
  • 7.1 环绕声(相比 5.1 多了两个天空声道)

这里小数点左边的数字表示音响数量,右边的 .1 表示一个独立的低音音响。例如 5.1 环绕声至少需要 5 个音响 + 一个独立的低音音响,前面放置三个作为左中右三个声道,后面放置两个作为后置的左右声道。

传统音响系统对于普通人的复杂之处在于:搞定复杂的布线、找到合适的摆放位置、了解不同房间布局对于声音的影响、了解声音校准,光搞清楚这些概念大部分人可能就要放弃了。

所以对于大多数人我的推荐有以下几种方案:

  1. 普通方案:两个 Apple HomePod 组成立体声,配合 AppleTV + eARC 音频回传,两个 HomePod 价格在 4500 元左右。
  2. 高级方案:Sony HT-A9M2 (BRAVIA Theater Quad) 多声道无线分体音响 + Sony 无线低音音响组成环绕声,价格在 16000 元左右。

以上几种方案都通过无线技术大幅简化了布线和音响摆放位置的问题,且都自带校准功能(HomePod 是全自动的, Sony 需要在 App 里手动触发一次)。

在有选择的情况下,始终优先选择用多个分体音响组多声道,而不是用单个回音壁代替。

关于 HomePod 组立体声和传统 5.1 音响系统的效果对比可以查看这个视频:https://www.youtube.com/watch?v=DPZ11P6ojpE

要获得最佳阅读体验,请访问原文 https://baiyun.me/efficient-elegant-movie-watching-guide

基于 Surge 的 DNS 优化指南

2023-09-27 13:23:33

要获得良好的网络冲浪体验,DNS 设置是至关重要的。本文主要介绍如何使用 Surge 来提高 DNS 隐私和安全性,特别是在复杂的网络环境下,并分享一些经验,其中的原理也可以应用到诸如 Clash、Shadowrocket、Quantumult X 之类的软件。

Host 配置

Host 配置决定了你访问一个域名时 surge 如何解析这个域名的 DNS 记录,想获得高效安全的 DNS 解析体验,首先需要先根据你所处的网络环境配置合适的 Host 规则,先看一个配置示例:

[Host]
local.example.net = 127.0.0.1
local.xxx.net = 1.1.1.1

*xxxx-inc.com = server:system
*example*.com = server:system

*.* = server:https://223.6.6.6/dns-query

各种规则可以总结归类为三个梯队,优先级从上到下:

  1. 本地开发测试域名:直接将域名绑定到指定 IP
  2. 企业内部域名:用系统 DNS 解析(server:system),以保障可用性
  3. 公网域名:排除上述两种之后,剩下的就是一些公网域名了,可以考虑用 DNS Over HTTPS 或脚本自定义解析

需要注意的是,如果遇到配置了 /etc/hosts 不生效,可以检查对应域名是否在 surge 配置里指定了其他服务器解析,有时候会导致冲突。解决方案:

  • 可以把 /etc/hosts 里的内容挪到 surge 配置里
  • 或者关闭系统代理,只开启增强模式
  • 也可以使用 skip-proxy 配置项将对应域名加进去,这样就不走系统代理了
  • 如果在命令行里声明了 http_proxy 之类的变量,执行 curl 的时候需要指定 --noproxy '*' 参数避免将请求发送给 Surge

希望后续 surge 能优化这个点,提供更直观的配置。

减少本地 DNS 解析

对于希望走代理的请求,应该尽量避免它们在本地触发 DNS 解析,最好将你常用的需要代理的网站加到 surge 的规则列表中,例如:

[Rule]
DOMAIN-SUFFIX,google.com,📡 Proxy
DOMAIN-SUFFIX,x.com,📡 Proxy

如果你有大量域名需要代理,可以使用 Surge 提供的 rule-set 或者 domain-set 将这些规则和域名维护到单独的文件中,通过 URL 来引用和自动更新,例如:

# 自定义代理域名
RULE-SET,https://ruleset.example.com/proxy.txt,📡 Proxy

# GitHub 项目维护的代理域名
DOMAIN-SET,https://cdn.jsdelivr.net/gh/Loyalsoldier/surge-rules@release/proxy.txt,📡 Proxy

按照上述设置后,访问这些域名将不会在本地触发 DNS 解析,请求会直接发送到代理服务器,由它负责 DNS 解析,这样既可以提升隐私也可以获得更好的 DNS 解析结果。

好的 surge 配置应该尽量避免在前面的规则触发 DNS 解析,将需要触发 DNS 的规则尽量放置的末尾,下面是一个示例:

DOMAIN-SUFFIX,github.com,📡 Proxy
PROCESS-NAME,go-ipfs*,📡 Proxy
USER-AGENT,Figma,📡 Proxy

IP-CIDR,66.197.128.0/17,📡 Proxy,no-resolve

IP-CIDR,23.246.0.0/12,DIRECT
RULE-SET,LAN,DIRECT
GEOIP,CN,DIRECT
  1. 域名、UA、ProcessName 等不需要触发 DNS 解析的规则放第一梯队
  2. 包含 no-resolve 参数的规则不会触发 DNS 解析,可以放第二梯队,
  3. 最后是 IP-CIDR、LAN、GEOIP 这些必须触发 DNS 解析的规则

解决 Surge 增强模式和企业 VPN 冲突

很多大型企业内部都有自己研发的 VPN 客户端(基于 TUN 模式),当你在公司外通过企业 VPN 访问内部域名通常需要特殊设定优化才能避免和 Surge 冲突。

本文接下来使用 10.x.x.x 作为企业内网 DNS IP 示例。

[General]
# 10.x.x.x 换成企业内网的固定 DNS 服务器(如果有的话)用于兜底
dns-server = system, 10.x.x.x
# 企业内部域名确保返回真实的 IP,这样才能被企业 VPN 的 TUN 路由表匹配到。
always-real-ip =  %INSERT% *.your-corp.com

[Host]
# 将内网 DNS 管理的 zone 直接指定用内网 DNS 服务器解析
*your-corp.com = server:10.x.x.x

注意:尽量避免使用 surge 的 tun-excluded-routes 配置,如果你把公司内网IP段加入到这个配置,有可能引发和企业 VPN 的冲突或者各种兼容性问题。

例如 10.x.x.x 是你的企业内网 DNS IP,如果你将其加到 surge 的 tun-excluded-routes 配置里:

tun-excluded-routes = 10.x.x.x/32

重启 surge 后,查看路由表就会发现这个 IP 被 surge 又插入了一遍,你再 ping 这个 IP 就发现 ping 不通了(即使开了企业 VPN),因为此时它是走 192.168.10.1 这个家庭网关出口的自然访问不通了。

netstat -rn -f inet | grep 10.x
10.x.x.x      192.168.10.1       UGHS                  en0
10.x.x.x/32   10.2.x.x           UGSc                utun5

下面是一些辅助命令,如果配置过程遇到问题可以结合这些命令排查。

确定内网 DNS 服务器,可以使用下面的命令:(先关闭 surge 增强模式。)

scutil --dns
DNS configuration (for scoped queries)

resolver #1
  search domain[0] : router.home
  nameserver[0] : 10.x.x.x
  if_index : 15 (en0)
  flags    : Scoped, Request A records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)

resolver #2
  nameserver[0] : 198.18.0.2
  if_index : 38 (utun4)
  flags    : Scoped, Request A records
  reach    : 0x00000002 (Reachable)

找到上面 nameserver[0] 后面的 IP,用 dig 测试能否解析内网域名:

dig your-corp.com @10.x.x.x

找到可以解析出正确 IP 的那个 namesever 就是内网 DNS 服务器。当然一般内网都有固定的 IP 段,可以辅助判断。

开启企业 VPN 之后可以通过以下命令查看哪些 IP 段会走企业 VPN 出口:

netstat -rn -f inet

下面示例中,10.2.x.x 就是企业VPN的网关地址,10.x.x.x/32,9.x.x.x/32 这些 IP 段是企业内网IP。

Routing tables

Internet:
Destination        Gateway            Flags               Netif Expire
default            link#38            UCSg                utun4
default            192.168.10.1       UGScIg                en0
8.x.x.x/28         10.2.x.x           UGSc                utun5
9.x.x.x/32         10.2.x.x           UGSc                utun5
10.x.x.x/32        10.2.x.x           UGSc                utun5

查看所有的 TUN 设备:

ifconfig | grep -B3 -A5 utun

更多参考

要获得最佳阅读体验,请访问原文 https://baiyun.me/surge-dns-optimization-guide

RIME 鼠须管输入法简明使用教程

2023-04-07 11:21:38

工作中经常见到大量同事花名被打错的场景,本文分享了我近几年在用的输入法,完美解决了这个问题。

本文适合有以下需求的读者:

  • 很在意输入法隐私,不想让第三方知道自己输入了什么
  • 很在意打字效率和准确性
  • 经常要输入一些自定义词组

在接触到 RIME 之前,我用过很多款中文输入法,从最早的搜狗、到后来的百度、必应Bing输入法(后来改名叫微软拼音输入法)。其中 Windows 上最满意的是必应输入法,无奈 Mac 平台用不了。后来 Mac 上一直使用了好多年百度输入法,打字词库总是缺少一种称手的感觉,又找不到好的代替。

另外考虑到这类国内厂商的输入法基本毫无隐私和安全可言,它们都是免费产品,如果不是为了获取用户数据,那他们开发和持续维护这些输入法的目的是什么呢?

🐭 RIME 鼠须管

RIME

Rime(中州韵)是一个开源的输入法引擎,鼠须管是基于 Rime 构建的一款开源输入法,面向 macOS 平台。

我很早就听说过这款输入法的大名,也遇到很多人推荐它,但是被它繁杂的配置劝退了。最近,看到有人做了一套配置集合,整合了很多常用的功能,配合官方的配置管理工具让使用门槛一下子降低了好多。

接下来是一个简明指南,可以帮你快速安装和配置好一个开箱即用的输入法。

继续阅读需要的一些前置要求:

  1. 了解基本的 linux/unix 命令,例如 cat、vim 用于在命令行查看和编辑文件
  2. 了解 git 和 brew 这些工具,用于安装必要的程序

安装

# 回到家目录,可选
cd ~

# 安装 plum,这是 Rime 官方的配置管理工具
git clone --depth=1 https://github.com/rime/plum
cd plum

# 安装 Rime 配置:雾凇拼音
bash rime-install iDvel/rime-ice:others/recipes/full

# 安装 鼠须管 Squirrel,安装之后需要登出系统重新登入才能添加输入法
brew install --cask squirrel

下面是雾凇拼音提供的功能概览图

雾凇拼音功能概览图

修改个人配置

鼠须管和默认配置安装好之后,其实已经可以正常使用了。本节的示例教你如何正确的做一些个性化配置。

RIME 设置

执行 vim ~/Library/Rime/default.custom.yaml,填入以下配置,下面的配置主要做了两个事情:

  • 输入法方案只保留了全拼(schema: rime_ice),删除了默认启用的双拼方案
  • 开启了 ⇧Shift 键切换英文
# Rime Patch settings
# encoding: utf-8

patch:
  # 方案列表
  schema_list:
    - schema: rime_ice

  # 中西文切换
  #
  # 【good_old_caps_lock】 CapsLock 切换到大写或切换中英。
  # (macOS 偏好设置的优先级更高,如果勾选【使用大写锁定键切换“ABC”输入法】则始终会切换输入法)
  #
  # 切换中英:
  # 不同的选项表示:打字打到一半时按下了 CapsLock、Shift、Control 后:
  # commit_code  上屏原始的编码,然后切换到英文
  # commit_text  上屏拼出的词句,然后切换到英文
  # clear        清除未上屏内容,然后切换到英文
  # inline_ascii 无输入时,切换中英;有输入时,切换到临时英文模式,按回车上屏后回到中文状态
  # noop         屏蔽快捷键,不切换中英,但不要屏蔽 CapsLock
  ascii_composer:
    good_old_caps_lock: true  # true | false
    switch_key:
      Caps_Lock: commit_code   # commit_code | commit_text | clear
      Shift_L: commit_code     # commit_code | commit_text | inline_ascii | clear | noop
      Shift_R: commit_code     # commit_code | commit_text | inline_ascii | clear | noop
      Control_L: noop          # commit_code | commit_text | inline_ascii | clear | noop
      Control_R: noop          # commit_code | commit_text | inline_ascii | clear | noop

鼠须管设置

鼠须管有很多内置的主题,你可以直接将他们的名字填到下面配置的 color_schema 字段即可,我这里没有使用内置主题,而是从网络上找了两款接近 macOS 原生输入法的主题。

执行 vim ~/Library/Rime/squirrel.custom.yaml,填入以下配置:

# Squirrel Patch settings
# encoding: utf-8
#
# 内置皮肤展示: https://github.com/NavisLab/rime-pifu
# 鼠须管配置指南: https://github.com/LEOYoon-Tsaw/Rime_collections/blob/master/鼠鬚管介面配置指南.md
# 鼠须管作者写的图形化的皮肤设计器: https://github.com/LEOYoon-Tsaw/Squirrel-Designer

patch:
  style:
    color_scheme: macos_light       # 将皮肤名称输入在此处
    color_scheme_dark: macos_dark   # 暗色模式下的皮肤名称

  # 皮肤列表
  preset_color_schemes:
    macos_light:
      name: "MacOS 浅色/MacOS Light"
      author: 小码哥
      font_face: "PingFangSC"          # 字体及大小
      font_point: 16
      label_font_face: "PingFangSC"    # 序号字体及大小
      label_font_point: 12
      comment_font_face: "PingFangSC"  # 注字体及大小
      comment_font_point: 16
      candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间
      candidate_list_layout: linear   # 候选排布:层叠 stacked | 行 linear
      text_orientation: horizontal    # 行文向: 横 horizontal | 纵 vertical
      inline_preedit: true            # 拼音位于: 候选框 false | 行内 true
      translucency: false             # 磨砂: false | true
      mutual_exclusive: false         # 色不叠加: false | true
      border_height: 1                # 外边框 高
      border_width: 1                 # 外边框 宽
      corner_radius: 5                # 外边框 圆角半径
      hilited_corner_radius: 5       # 选中框 圆角半径
      surrounding_extra_expansion: 0 # 候选项背景相对大小?
      shadow_size: 0                 # 阴影大小
      line_spacing: 5                # 行间距
      base_offset: 0                 # 字基高
      alpha: 1                       # 透明度,0~1
      spacing: 10                    # 拼音与候选项之间的距离 (inline_preedit: false)
      color_space: srgb                       # 色彩空间: srgb | display_p3
      back_color: 0xFFFFFF                    # 底色
      hilited_candidate_back_color: 0xD75A00  # 选中底色
      label_color: 0x999999                   # 序号颜色
      hilited_candidate_label_color: 0xFFFFFF # 选中序号颜色
      candidate_text_color: 0x3c3c3c          # 文字颜色
      hilited_candidate_text_color: 0xFFFFFF  # 选中文字颜色
      comment_text_color: 0x999999            # 注颜色
      hilited_comment_text_color: 0xFFFFFF    # 选中注颜色
      text_color: 0x424242                    # 拼音颜色 (inline_preedit: false)
      hilited_text_color: 0xFFFFFF            # 选中拼音颜色 (inline_preedit: false)
      candidate_back_color: 0xe9e9ea          # 候选项底色
      # preedit_back_color:                   # 拼音底色 (inline_preedit: false)
      hilited_back_color: 0xD75A00            # 选中拼音底色 (inline_preedit: false)
      border_color: 0xFFFFFF                  # 外边框颜色

    macos_dark:
      name: "MacOS 深色/MacOS Dark"
      author: 小码哥
      font_face: "PingFangSC"          # 字体及大小
      font_point: 16
      label_font_face: "PingFangSC"    # 序号字体及大小
      label_font_point: 12
      comment_font_face: "PingFangSC"  # 注字体及大小
      comment_font_point: 16
      candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间
      candidate_list_layout: linear   # 候选排布:层叠 stacked | 行 linear
      text_orientation: horizontal    # 行文向: 横 horizontal | 纵 vertical
      inline_preedit: true            # 拼音位于: 候选框 false | 行内 true
      translucency: false             # 磨砂: false | true
      mutual_exclusive: false         # 色不叠加: false | true
      border_height: 1                # 外边框 高
      border_width: 1                 # 外边框 宽
      corner_radius: 5                # 外边框 圆角半径
      hilited_corner_radius: 5       # 选中框 圆角半径
      surrounding_extra_expansion: 0 # 候选项背景相对大小?
      shadow_size: 0                 # 阴影大小
      line_spacing: 5                # 行间距
      base_offset: 0                 # 字基高
      alpha: 1                       # 透明度,0~1
      spacing: 10                    # 拼音与候选项之间的距离 (inline_preedit: false)
      color_space: srgb                       # 色彩空间: srgb | display_p3
      back_color: 0x1f1e2d                  # 底色
      hilited_candidate_back_color: 0xD75A00  # 选中底色
      label_color: 0x999999                   # 序号颜色
      hilited_candidate_label_color: 0xFFFFFF # 选中序号颜色
      candidate_text_color: 0xe9e9ea          # 文字颜色
      hilited_candidate_text_color: 0xFFFFFF  # 选中文字颜色
      comment_text_color: 0x999999            # 注颜色
      hilited_comment_text_color: 0x999999    # 选中注颜色
      text_color: 0x808080                    # 拼音颜色 (inline_preedit: false)
      hilited_text_color: 0xFFFFFF            # 选中拼音颜色 (inline_preedit: false)
      candidate_back_color: 0xe9e9ea          # 候选项底色
      # preedit_back_color:                   # 拼音底色 (inline_preedit: false)
      hilited_back_color: 0xD75A00            # 选中拼音底色 (inline_preedit: false)
      border_color: 0x050505                  # 外边框颜色

    wechat_light:
      name: "微信浅色/Wechat Light"
      author: 小码哥
      font_face: "PingFangSC"          # 字体及大小
      font_point: 16
      label_font_face: "PingFangSC"    # 序号字体及大小
      label_font_point: 13
      comment_font_face: "PingFangSC"  # 注字体及大小
      comment_font_point: 16
      candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间
      candidate_list_layout: linear   # 候选排布:层叠 stacked | 行 linear
      text_orientation: horizontal    # 行文向: 横 horizontal | 纵 vertical
      inline_preedit: true            # 拼音位于: 候选框 false | 行内 true
      translucency: false             # 磨砂: false | true
      mutual_exclusive: false         # 色不叠加: false | true
      border_height: 1                # 外边框 高
      border_width: 1                 # 外边框 宽
      corner_radius: 5                # 外边框 圆角半径
      hilited_corner_radius: 5       # 选中框 圆角半径
      surrounding_extra_expansion: 0 # 候选项背景相对大小?
      shadow_size: 0                 # 阴影大小
      line_spacing: 5                # 行间距
      base_offset: 0                 # 字基高
      alpha: 1                       # 透明度,0~1
      spacing: 10                    # 拼音与候选项之间的距离 (inline_preedit: false)
      color_space: srgb                       # 色彩空间: srgb | display_p3
      back_color: 0xFFFFFF                    # 底色
      hilited_candidate_back_color: 0x79af22  # 选中底色
      label_color: 0x999999                   # 序号颜色
      hilited_candidate_label_color: 0xFFFFFF # 选中序号颜色
      candidate_text_color: 0x3c3c3c          # 文字颜色
      hilited_candidate_text_color: 0xFFFFFF  # 选中文字颜色
      comment_text_color: 0x999999            # 注颜色
      hilited_comment_text_color: 0x999999    # 选中注颜色
      text_color: 0x424242                    # 拼音颜色 (inline_preedit: false)
      hilited_text_color: 0x999999            # 选中拼音颜色 (inline_preedit: false)
      candidate_back_color: 0xe9e9ea          # 候选项底色
      # preedit_back_color:                   # 拼音底色 (inline_preedit: false)
      hilited_back_color: 0x79af22            # 选中拼音底色 (inline_preedit: false)
      border_color: 0xFFFFFF                  # 外边框颜色

    wechat_dark:
      name: "微信深色/Wechat Dark"
      author: 小码哥
      font_face: "PingFangSC"          # 字体及大小
      font_point: 16
      label_font_face: "PingFangSC"    # 序号字体及大小
      label_font_point: 13
      comment_font_face: "PingFangSC"  # 注字体及大小
      comment_font_point: 16
      candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间
      candidate_list_layout: linear   # 候选排布:层叠 stacked | 行 linear
      text_orientation: horizontal    # 行文向: 横 horizontal | 纵 vertical
      inline_preedit: true            # 拼音位于: 候选框 false | 行内 true
      translucency: false             # 磨砂: false | true
      mutual_exclusive: false         # 色不叠加: false | true
      border_height: 1                # 外边框 高
      border_width: 1                 # 外边框 宽
      corner_radius: 5                # 外边框 圆角半径
      hilited_corner_radius: 5       # 选中框 圆角半径
      surrounding_extra_expansion: 0 # 候选项背景相对大小?
      shadow_size: 0                 # 阴影大小
      line_spacing: 5                # 行间距
      base_offset: 0                 # 字基高
      alpha: 1                       # 透明度,0~1
      spacing: 10                    # 拼音与候选项之间的距离 (inline_preedit: false)
      color_space: srgb                       # 色彩空间: srgb | display_p3
      back_color: 0x151515                    # 底色
      hilited_candidate_back_color: 0x79af22  # 选中底色
      label_color: 0x999999                   # 序号颜色
      hilited_candidate_label_color: 0xFFFFFF # 选中序号颜色
      candidate_text_color: 0xbbbbbb          # 文字颜色
      hilited_candidate_text_color: 0xFFFFFF  # 选中文字颜色
      comment_text_color: 0x999999            # 注颜色
      hilited_comment_text_color: 0xFFFFFF    # 选中注颜色
      text_color: 0xbbbbbb                    # 拼音颜色 (inline_preedit: false)
      hilited_text_color: 0x999999            # 选中拼音颜色 (inline_preedit: false)
      candidate_back_color: 0xbbbbbb          # 候选项底色
      # preedit_back_color:                   # 拼音底色 (inline_preedit: false)
      hilited_back_color: 0x79af22            # 选中拼音底色 (inline_preedit: false)
      border_color: 0x292929                  # 外边框颜色

拷贝完之后,右上角输入法切换到 Squirrel 点击 Deploy 让配置生效。
Deploy配置

上面我用的配置文件都是 *.custom.yaml 结尾,这种模式称之为打补丁模式,主要是为了避免修改原配置文件,这样以后输入法配置升级就很容易了。

设置同步功能

使用鼠须管自带的用户数据同步功能配合 iCloud 之类的网盘,可以轻松将你的输入法配置和词库跨设备同步,对于多台设备,鼠须管会自动合并用户词库。

  1. 编辑 installation.yaml 文件
vim ~/Library/Rime/installation.yaml
  1. 修改内容参考如下:
# 本机的 ID 标志,默认是一串 UUID。生成的文件夹是这个名字,可以改成更好识别的名称
installation_id: "mbp16"
# 同步的路径,默认如没有设置此属性,则是在当前配置目录的 `sync/` 文件夹
sync_dir: "/Users/YOUR_NAME/Library/Mobile Documents/com~apple~CloudDocs/RimeSync"
  1. 修改好之后,右上角输入法切换到 Squirrel 点击 Sync user data 即可完成数据同步,之后改动配置后需要再次重复此操作。目前官方没有提供自动触发同步的功能,因为在同步用户数据期间,输入法会处于不可用状态。

RIME 的同步功能是 配置单向同步 + 用户词库双向同步,举个例子:A 设备开启同步功能后,B 设备并不会自动获得相同的配置,这两个设备只会自动合并用户词库(也就是你的自造词)。

RIME 同步功能图解

设置自动同步

如果你觉得经常手动同步用户数据比较麻烦,也可以配合 sleepwatcher 在电脑休眠和唤醒的时候自动触发同步,具体做法如下:

brew install sleepwatcher
touch ~/.sleep
chmod +x ~/.sleep

编辑 ~/.sleep 文件,填入以下内容:

#!/usr/bin/env bash

# 触发鼠须管同步用户数据
/Library/Input\ Methods/Squirrel.app/Contents/MacOS/Squirrel --sync

配置好之后,重启 sleepwatcher

brew services restart sleepwatcher

这时候可以休眠电脑等10秒再唤醒,检查 sync_dir 里面的 rime_ice.userdb.txt 文件修改时间是否变了。如果不生效,请检查 ~/.sleep 脚本是否正确,可以手动执行看下效果,以及重启 sleepwatcher.

上面的 ~/.sleep 脚本是在电脑休眠之前执行,根据你的需要还可以定义一个 ~/.wakeup 脚本在唤醒后执行。

配置更新

前面我们用的预设配置是 雾凇拼音 这个项目提供的,后续可以通过下面的命令更新配置以获得新功能和 Bugfix。

更新雾凇拼音:所有配置和词库(更新前建议先备份 ~/Library/Rime 目录,更新后所有非 .custom.yaml 结尾的配置文件会被覆盖)

# 先回到 plum 安装目录,如果你将 plum 安装在了其他目录,这里需要修改
cd ~/plum
bash rime-install iDvel/rime-ice:others/recipes/full

更新雾凇拼音:所有词库文件

cd ~/plum
bash rime-install iDvel/rime-ice:others/recipes/all_dicts

如果你用下来感觉挺好的没啥问题,那建议只更新词库就行了。

对于自定义的补丁配置文件,尤其是 *.custom.yaml 和自定义字典,建议将其备份到自己的 git 仓库保存,防止配置意外被覆盖或丢失。

使用技巧

RIME 有些很有用的使用技巧新手刚开始不仔细研究可能发现不了,这里我罗列一些非常好用的技巧。

删除不想要的自造词

打字久了很容易在不经意间产生一些错误的自造词,这时候如果不处理就很容易在后续的输入过程中继续使用这些错误的自造词。

要删除不想要的自造词,你可以使用方向键选中要删除的候选词,再按下 Fn+Shift+Delete 即可删除。

手册原文:只能夠從用戶詞典中刪除詞組。用於碼表中原有的詞組時,只會取消其調頻效果。

使用 Tab 键在拼音之间切换光标

当你打了一段话,发现前面的拼音打错了,或者想单独修改前面的某个字,这时候不用狂按退格键,你可以直接按 Tab 键或 Shift + Tab 在拼音中前后切换光标到对应的拼音。

Tab键切换光标示例

进阶说明

按照上面的步骤操作下来你已经入门了,这时候如果你想让 RIME 输入法更顺手更符合你的习惯偏好就需要了解进阶概念了。

修改配置

如果你想调整一些自定义的设置,可以先查看以下两个文件,可以对整体配置有个概念:

  1. cat ~/Library/Rime/default.yaml 这是 Rime 输入法引擎的默认配置文件,大部分跟输入有关的核心配置都在这里
# Rime default settings
# encoding: utf-8
#
# 小狼毫似乎不支持 Control+Shift 开头的快捷键,可自行修改成别的。
# 鼠须管在 Sublime Text、Telegram 等个别软件中也无法使用 Control+Shift+数字 的快捷键,可暂时用方案选单切换。

config_version: '2023-03-03'

# 方案列表
schema_list:
  - schema: rime_ice
  - schema: double_pinyin
  - schema: double_pinyin_flypy

# 菜单
menu:
  page_size: 5  # 候选词个数
  # alternative_select_labels: [ ①, ②, ③, ④, ⑤, ⑥, ⑦, ⑧, ⑨, ⑩ ]  # 修改候选项标签
  # alternative_select_keys: ASDFGHJKL  # 如编码字符占用数字键,则需另设选字键

# 方案选单相关
switcher:
  caption: 「方案选单」
  hotkeys:
    # - F4
    # - Control+grave
    # - Alt+grave
    - Control+Shift+grave
  save_options:  # 开关记忆,从方案选单(而非快捷键)切换时会记住的选项,需要记忆的开关不能设定 reset
    - ascii_punct
    - traditionalization
    - emoji
  fold_options: true            # 呼出时是否折叠,多方案时建议折叠 true ,一个方案建议展开 false
  abbreviate_options: true      # 折叠时是否缩写选项
  option_list_separator: ' / '  # 折叠时的选项分隔符

# 中西文切换
#
# 【good_old_caps_lock】 CapsLock 切换到大写或切换中英。
# (macOS 偏好设置的优先级更高,如果勾选【使用大写锁定键切换“ABC”输入法】则始终会切换输入法)
#
# 切换中英:
# 不同的选项表示:打字打到一半时按下了 CapsLock、Shift、Control 后: 
# commit_code  上屏原始的编码,然后切换到英文
# commit_text  上屏拼出的词句,然后切换到英文
# clear        清除未上屏内容,然后切换到英文
# inline_ascii 无输入时,切换中英;有输入时,切换到临时英文模式,按回车上屏后回到中文状态
# noop         屏蔽快捷键,不切换中英,但不要屏蔽 CapsLock
ascii_composer:
  good_old_caps_lock: true  # true | false
  switch_key:
    Caps_Lock: clear  # commit_code | commit_text | clear
    Shift_L: noop     # commit_code | commit_text | inline_ascii | clear | noop
    Shift_R: noop     # commit_code | commit_text | inline_ascii | clear | noop
    Control_L: noop   # commit_code | commit_text | inline_ascii | clear | noop
    Control_R: noop   # commit_code | commit_text | inline_ascii | clear | noop


# punctuator 和 recognizer 由具体方案指定了
punctuator:
  full_shape:
  half_shape:
  symbols:
recognizer:
  patterns:


# 快捷键
key_binder:
  # 以词定字(上屏当前词句的第一个或最后一个字)
  select_first_character:
  select_last_character: "grave"

  bindings:
    # Tab/Shift+Tab 切换光标至下/上一个拼音
    - { when: composing, accept: Shift+Tab, send: Shift+Left }
    - { when: composing, accept: Tab, send: Shift+Right }
    # Tab/Shift+Tab 翻页
    # - { when: has_menu, accept: Shift+Tab, send: Page_Up }
    # - { when: has_menu, accept: Tab, send: Page_Down }

    # 翻页 - =
    - { when: has_menu, accept: minus, send: Page_Up }
    - { when: has_menu, accept: equal, send: Page_Down }

    # 翻页 , .
    # 需要额外注释掉方案中 recognizer/patterns 下的 url_2 选项(这个会覆盖掉句号的行为)
    # - { when: paging, accept: comma, send: Page_Up }
    # - { when: has_menu, accept: period, send: Page_Down }

    # 翻页 [ ]
    # - { when: paging, accept: bracketleft, send: Page_Up }
    # - { when: has_menu, accept: bracketright, send: Page_Down }

    # numbered_mode_switch:
    # - { when: always, accept: Control+Shift+1, select: .next }               # 在最近的两个方案之间切换
    # - { when: always, accept: Control+Shift+2, toggle: ascii_mode }          # 切换中英
    - { when: always, accept: Control+Shift+3, toggle: ascii_punct }           # 切换中英标点
    - { when: always, accept: "Control+Shift+4", toggle: traditionalization }  # 切换简繁
    # - { when: always, accept: Control+Shift+5, toggle: full_shape }          # 切换全半角

# key_binder 按键速查 https://github.com/LEOYoon-Tsaw/Rime_collections/blob/master/Rime_description.md

  1. cat ~/Library/Rime/squirrel.yaml 这是鼠须管输入法的配置,包含主题配色之类的设置
# Squirrel settings
# encoding: utf-8
#
# 内置皮肤展示: https://github.com/NavisLab/rime-pifu
# 鼠须管配置指南: https://github.com/LEOYoon-Tsaw/Rime_collections/blob/master/鼠鬚管介面配置指南.md
# 鼠须管作者写的图形化的皮肤设计器: https://github.com/LEOYoon-Tsaw/Squirrel-Designer

config_version: '2023-02-27'

# options: last | default | _custom_
# last: the last used latin keyboard layout
# default: US (ABC) keyboard layout
# _custom_: keyboard layout of your choice, e.g. 'com.apple.keylayout.USExtended' or simply 'USExtended'
keyboard_layout: default

# for veteran chord-typist
chord_duration: 0.1  # seconds

# options: always | never | appropriate
show_notifications_when: appropriate

# ascii_mode、inline、no_inline、vim_mode 等等设定,可参考 /Library/Input Methods/Squirrel.app/Contents/SharedSupport/squirrel.yaml
app_options:
  # com.apple.Spotlight:
  #   ascii_mode: true    # 开启默认英文
  # com.microsoft.VSCode:
  #   ascii_mode: false   # 关闭默认英文

style:
  # 选择皮肤,亮色与暗色主题
  color_scheme: purity_of_form_custom
  color_scheme_dark: purity_of_form_custom

  # 预设选项:(可被皮肤覆盖;如果皮肤没写,则默认使用这些属性。)
  text_orientation: horizontal  # horizontal | vertical
  inline_preedit: true
  corner_radius: 10
  hilited_corner_radius: 0
  border_height: 0
  border_width: 0
  line_spacing: 5
  spacing: 10
  #candidate_format: '%c. %@'
  #base_offset: 6
  font_face: 'Lucida Grande'
  font_point: 21
  #label_font_face: 'Lucida Grande'
  label_font_point: 18
  #comment_font_face: 'Lucida Grande'
  comment_font_point: 18


# 皮肤列表
preset_color_schemes:
  # 对 purity_of_form 略微调整颜色,让色彩更柔和点,补全其他选项和注释
  purity_of_form_custom:
    name: "純粹的形式/Purity of Form Custom"
    author: 雨過之後、佛振
    font_face: ""                   # 字体及大小
    font_point: 18
    label_font_face: "Helvetica"    # 序号字体及大小
    label_font_point: 12
    comment_font_face: "Helvetica"  # 注字体及大小
    comment_font_point: 16
    candidate_list_layout: stacked  # 候选排布:层叠 stacked | 行 linear
    text_orientation: horizontal    # 行文向: 横 horizontal | 纵 vertical
    inline_preedit: true            # 拼音位于: 候选框 false | 行内 true
    translucency: false             # 磨砂: false | true
    mutual_exclusive: false         # 色不叠加: false | true
    border_height: 0               # 外边框 高
    border_width: 0                # 外边框 宽
    corner_radius: 10              # 外边框 圆角半径
    hilited_corner_radius: 0       # 选中框 圆角半径
    surrounding_extra_expansion: 0 # 候选项背景相对大小?
    shadow_size: 0                 # 阴影大小
    line_spacing: 5                # 行间距
    base_offset: 0                 # 字基高
    alpha: 1                       # 透明度,0~1
    spacing: 10                    # 拼音与候选项之间的距离 (inline_preedit: false)
    color_space: srgb                       # 色彩空间: srgb | display_p3
    back_color: 0x545554                    # 底色
    hilited_candidate_back_color: 0xE3E3E3  # 选中底色
    label_color: 0xBBBBBB                   # 序号颜色
    hilited_candidate_label_color: 0x4C4C4C # 选中序号颜色
    candidate_text_color: 0xEEEEEE          # 文字颜色
    hilited_candidate_text_color: 0x000000  # 选中文字颜色
    comment_text_color: 0x808080            # 注颜色
    hilited_comment_text_color: 0x808080    # 选中注颜色
    text_color: 0x808080                    # 拼音颜色 (inline_preedit: false)
    hilited_text_color: 0xEEEEEE            # 选中拼音颜色 (inline_preedit: false)
    # candidate_back_color:                 # 候选项底色
    # preedit_back_color:                   # 拼音底色 (inline_preedit: false)
    # hilited_back_color:                   # 选中拼音底色 (inline_preedit: false)
    # border_color:                         # 外边框颜色

碰到你想修改的配置项,有两种修改方案:

  1. 直接修改 default.yaml,这种方式的缺点是后续你更新雾凇拼音配置的时候会被覆盖掉
  2. patch 打补丁,本文前面用到的 *.custom.yaml 文件就是使用这种方案,想用 patch 的方式修改 default.yaml,需要新建一个 default.custom.yaml 文件用来覆盖 default.yaml 中的配置项,具体格式可以参考本文开头的示例。

修改配置文件后记得重新 Deploy。

自定义短语

  • cat ~/Library/Rime/custom_phrase.txt 查看现有短语和配置说明

自定义字典

对于拼音输入法来说,不管是全拼还是双拼,都面临一个问题:重码。相同的拼音对应多个发音类似的词语,如果第一屏候选词没出现用户想要的词,就会严重影响输入效率。

一款输入法好不好用,在很大程度上是看这款输入法的字典好不好用,字典不是越大越多越好,而是要契合用户的使用场景,越大的字典重码率通常会越高,越容易让用户感觉首屏候选词经常出现不了自己想要的词。

根据自己的日常使用场景来挂载对应的词库,并在平时逐步定制积累自定义词库是一个不错的选择。

本文使用的雾凇拼音已经默认做了很多输入优化和字典优化,如果你使用一段时间后想实现更好的打字效果,制作你的自定义字典是个不错的选择(当然你多次重复输入一个词语也会自动造词的)

举个例子,一些大公司喜欢让员工起花名,随着时间推移员工人数飞速增长,起两个字的中文花名就是个很困难的事情,所以经常能看到许多新员工的花名奇奇怪怪,生僻字和谐音很常见。这时候你用拼音输入法打同事的花名就非常麻烦和难受。针对这种情况就可以用自定义字典很好的解决,后续输入同事的花名效率就会非常高。

要制作自定义字典,请先切换到 Rime 的用户配置目录:cd ~/Library/Rime

先查看雾凇拼音的默认字典配置:cat rime_ice.dict.yaml

# Rime dictionary
# encoding: utf-8

---
name: rime_ice
version: "2023-03-04"
import_tables:
  - cn_dicts/8105     # 字表
  # - cn_dicts/41448  # 大字表(按需启用)
  - cn_dicts/base     # 基础词库
  - cn_dicts/sogou    # 搜狗流行词
  - cn_dicts/ext      # 扩展词库
  - cn_dicts/tencent  # 腾讯词向量(大词库,部署时间较长)
  - cn_dicts/others   # 一些杂项

  # 建议把扩展词库放到下面,有重复词条时,最上面的权重生效
  # 下面两个是我自己加的自定义字典
  - cn_dicts/names      # 自定义人名词库
  - en_dicts/my_en_ext  # 扩充英文词语
...

编辑自定义字典:vim cn_dicts/names.dict.yaml,这里的 names.dict.yaml 要改成你自己的字典名称。

内容是这样的:

---
name: names
version: "1"
sort: by_weight
...

维恩 wei en 100
步鲁斯 bu lu si 100

这里需要格外注意字典内容的缩进,正确的示例如下,用 Tab 分割不同的列,用空格分割拼音:

拼音	pin yin 1234
拼音<Tab>pin<Space>yin<Tab>1234

最好不要直接复制这段配置(制表符被转换为空格了),RIME 解析字典要依赖制表符识别不同的列,在编辑字典文件的时候记得先将编辑器缩进模式设置为 Tab 模式,建议先查看雾凇拼音的文档:编写词库,如果字典里的词没出现在首屏,可以增加权重,例如:1000000,默认建议先设置 100 就可以了。

一些缺点

  • 目前没有好的图形界面来修改配置和字典,不过对程序员来说问题不大,我建议将自定义的部分维护在 Git 仓库里,再配合一个自定义的更新脚本,实现一键备份、更新
  • 配置错误不会明确提示,例如字典格式不对、语法不对、引用了不存在的文件都不会明确提示你,如果你发现改配置后重新 Deploy 不生效,大概率是配置出错了,例如字典里没有用 Tab 分割。这种情况可以检查配置,或者手工去查看 Rime 日志文件(位于 $TMPDIR/rime.squirrel)

总结

通过几分钟时间你可以快速配置出一个好用、安全、隐私、轻量的输入法,它可以充分按照你的习惯和需求去定制,而且 RIME 有一个不错的用户手册可供你参考。如果你在意以上这些特点,那 RIME 可能是目前最好的选择。虽然它并不是完美的,也有一些小毛病,就看你怎么取舍了。

如果你想在 iOS 上也使用和 Mac 相同的词库,可以试一试 iOS 上的一款 Rime 实现:仓输入法。我自己实测下来直接将 Mac 端 Rime 配置导入到 iOS 端的仓输入法可以正常使用,不过得手动同步有些低效。

参考

要获得最佳阅读体验,请访问原文 https://baiyun.me/rime-simple-tutorial