YouTube 下载 1080p:yt-dlp 实战与自建服务
本文讲的是用开源工具 yt-dlp 在本地下载,以及把它包成一个只给自己用的小服务(在线聚合下载站为什么不再推荐,见下一节)。部署时需要的两件事另见:代理怎么搭、Docker 怎么装。 适用范围仅限你有权下载的内容:自己上传的视频、CC 授权作品、权利人明确允许下载的素材、以及所在司法辖区允许的个人存档。抓取受版权保护的内容并再分发是侵权;绕过平台的付费/DRM 限制通常同时违反服务条款。越过上面这两条线,后果由你自己承担。 为什么不再推荐在线下载站原来的做法是把视频链接粘给某个在线聚合下载站,让它在服务器上解析好再丢给你一个文件。这套玩法的代价在这几年逐渐显现: 可用性极差:这类站点的解析依赖 YouTube 的接口细节,平台一改就集体挂掉,域名换得比修得快。 注入式广告与跳转:免费站的变现方式通常是弹窗、套娃跳转、伪装成「下载」按钮的推广;解析页正是挂马和钓鱼的重灾区,因为访问者天然准备点「下载」。 隐私代价:你粘贴的是完整 URL(含视频 ID),部分站点还要求登录或装浏览器扩展。对「下载一个视频」这件事来说,这个代价不成比例。 分辨率虚标:页面上写着支持 ...
Java——record、sealed 与模式匹配
record 是透明的数据载体,sealed 是受控的继承层次,模式匹配是”检查类型 + 提取数据”的一体化写法。单独看,它们各自只是语法糖;合起来才是 Java 版的代数数据类型(ADT):sealed 说明”一共有哪几种可能”,record 说明”每种可能携带哪些数据”,switch 模式匹配负责把这两种信息穷尽地消费掉。本文的代码在 JDK 21.0.8 与 JDK 25 上编译运行通过;凡是与版本绑定的结论都标注了对应的 JEP 编号与转正版本。 三个特性的版本坐标写 Java 最容易踩的坑是”我记忆里 JDK 8 就有/就删了”。先把版本对齐: record:JEP 395,JDK 16 转正(此前 JDK 14 的 JEP 359、JDK 15 的 JEP 384 两次预览) instanceof 模式:JEP 394,JDK 16 转正(JEP 305 / JDK 14、JEP 375 / JDK 15 预览) sealed 类与接口:JEP 409,JDK 17 转正(JEP 360 / JDK 15、JEP 397 ...
Java——虚拟线程实战
虚拟线程(Virtual Threads)由 JEP 444 在 JDK 21 转正,它把「一个请求一个线程」写法的成本从操作系统线程降到了 JVM 对象级别。它买来的是吞吐(scale),不是延迟(speed):把 CPU 密集任务丢进去只会得到负数收益。按「什么时候有用、什么时候是负优化」这条线,依次是调度结构、池化禁忌、限流方式、固定(pinning)问题、ThreadLocal 放大和排障手段。 虚拟线程的两层结构平台线程、虚拟线程与载体平台线程是操作系统线程的薄包装,一个平台线程在其整个生命周期内独占一条 OS 线程,所以它的数量上限就是 OS 线程的上限。虚拟线程同样是 java.lang.Thread 的实例,但不绑定到某条固定的 OS 线程:它只在需要执行 CPU 指令时才占有一条 OS 线程,遇到阻塞操作就把 OS 线程让出去。 被让出去的这条 OS 线程叫载体线程(carrier)。虚拟线程的调度器是 JDK 自己实现的,它是一个工作在 FIFO 模式下的 work-stealing ForkJoinPool,把大量(M)虚拟线程调度到少量(N)载体线程上...
Java——CompletableFuture 异步编程实战
CompletableFuture 是 JDK 8 引入的异步编排工具(java.util.concurrent,类上 @since 1.8),同时实现了 Future<T> 与 CompletionStage<T>。它解决的问题是:把「查用户、查订单、算总价」这类有依赖关系或可以并行执行的步骤,写成一条声明式的异步链,而不是一堆层层嵌套的回调或者手动管理线程。本文逐条讲清每个 API 的语义边界:谁有返回值、谁吞异常、回调在哪个线程跑、默认线程池有什么坑、取消到底能不能打断正在执行的任务,以及它与仍在预览中的结构化并发(StructuredTaskScope)的差别。文中所有输出都来自 JDK 25(LTS)在 macOS 上的实测,示例代码可以原样编译运行。 示例里复用两个类型与一批工具方法,避免每个代码块都重复声明。先看这两段公共代码,后面的例子都直接引用它们。 123456789101112131415161718192021222324252627282930313233343536373839404142import java.util.L...
Java——Stream API 常见误用
Stream API 从 Java 8 引入,声明式的写法很容易让人把它当成「换一套语法写循环」。它自带一套求值模型(惰性)、一套并发模型(ForkJoinPool)和一组明确契约(identity、结合律、有序性、一次性消费),违反契约的代码常常在单测里跑得好好的,换个数据量或换成并行流才炸。 验证环境文中所有代码都在下面的环境编译并运行,javac -Xlint:all 无告警: 123java version "25" 2025-09-16 LTSJava(TM) SE Runtime Environment (build 25+37-LTS-3491)javac 25 涉及版本能力差异的结论一律标注 JDK 版本与 JEP 编号;纯 API 增补(没有对应 JEP 的)以 javadoc 里的 @since 为准。文中出现的实测数字都是本机(Apple M1 Pro)单次运行结果,用途是展示量级差异,不是基准测试。 本文使用的数据模型123456789record OrderLine(String sku, int qty) {...
Ubuntu 24.04 配置 Sing-box 代理服务器完整指南
在服务器上跑一个本地代理,让终端和 Docker 都走它,是部署里很常见的一步。这篇按 sing-box 当前文档(1.14 线)整理,配置在本机用 sing-box check 与真实启动 + curl -x 双向验证过。如果你照抄的是 2023–2024 年的教程,大概率会在启动时直接失败:inbounds[].sniff 在 1.13.0 被移除、geoip 路由规则在 1.12.0 被移除,两者都会让 1.13 以上的版本拒绝加载配置。 1. 什么是 Sing-boxsing-box 是一个通用代理平台,服务端与客户端共用一个二进制。它支持 VMess、VLESS、Trojan、Shadowsocks、Hysteria、WireGuard 等协议,可以在服务器上把远端代理转成(或直接暴露为)本机可用的 SOCKS5 / HTTP 代理。 它的配置格式在 1.x 期间改动频繁,每次大改都会把旧字段标记 deprecated,过一两个版本再移除。所以用 sing-box 的第一条经验是:配置以官方文档为准,并留意 Deprecated 页面。 2. 准备工作 一...
Java——Optional类的使用
Optional 是一个容器对象:要么包含一个非 null 的值,要么为空(empty)。有值时 isPresent() 返回 true、get() 返回该值;为空时 isPresent() 返回 false。它不保存 null——容器内部的 null 只表示「没有值」(Optional.empty() 与 ofNullable(null) 拿到的都是它);Optional 变量本身也永远不该是 null,这是官方 API Note 明确要求的。Optional 把「这个值可能为空」写进类型,让调用方必须显式处理;它并不消除空指针异常。 用例中的Person类 12345678public class Person { private String name; private int age; private String password; private List<String> hobbies; // getter and setter} 创建Optional对象使用empty()方法创建空的Optio...
Ubuntu 22.04 / 24.04 / 26.04 中安装 Docker 和 Docker Compose
以下步骤适用于 Ubuntu 22.04 / 24.04 / 26.04 LTS,命令需要 sudo 权限。 Ubuntu 20.04(Focal)已在 2025 年 5 月结束标准支持,之后进入需要 Ubuntu Pro 的 ESM 阶段;Docker 官方安装文档现在也只列 26.04、24.04、22.04 三个 LTS。新机器直接用 24.04 或 26.04。 什么是Docker?Docker是一款开源的容器化平台,通过将应用程序与其运行环境打包成轻量级容器,实现跨平台一致性运行。其核心特点包括: 轻量高效:共享宿主机内核,无需完整操作系统虚拟化 环境一致性:容器镜像可在开发、测试、生产环境无缝运行 快速部署:秒级启动时间,支持弹性扩缩容 资源隔离:每个容器拥有独立的文件系统、网络和进程空间 核心概念解析 术语 说明 镜像(Image) 静态模板文件,包含应用程序及其运行环境(类似软件安装包) 容器(Container) 镜像的运行实例,提供隔离的运行时环境 仓库(Registry) 镜像存储和分发平台(如Docker Hub...
设计模式——建造者模式(Builder pattern)
概述 The intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations. 将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示 使用场景 当一个类的构造参数个数超过了4个,而且这些参数有些是可选的参数,考虑使用构造者模式; 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时; 当构造过程中允许被构造的对象有不同的表示时。 Builder设计模式中涉及到的参与者 Builder 为创建一个Product对象的各个部件指定抽象接口。 ConcreteBuilder 实现 Builder 的接口以构造和装配该产品的各个部件。 定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建 提供一个检索产品...
Hexo 个人博客初始化
准备工作安装软件 node : https://nodejs.org/ (Hexo 8 要求 Node.js ≥ 20.19.0) git : https://git-scm.com/ hexo-cli : npm install -g hexo-cli(不想全局安装,可在项目里 npm install hexo,之后一律用 npx hexo) Hexo 初始化123hexo init blog # 生成站点骨架,并顺带装好依赖cd bloghexo server # 访问 http://localhost:4000/ 机器上没有全局 hexo 时,把上面的 hexo 换成 npx hexo。 Hexo基础修改网站基础配置信息修改网站各种资料,例如标题、副标题、关键词等信息,请修改博客根目录的站点配置文件 _config.yml(邮箱这类社交信息不在站点配置里,而在主题配置 _config.butterfly.yml 的 social 段) 12345678# Sitetitle: Lianglliu's Blogsubtitle: '...











