最近在看动画《佐贺偶像是传奇 卷土重来》(ゾンビランドサガ リベンジ),官方的同步网络放送有 Amazon Prime Video 和 AbemaTV。因为我已经订阅 Netflix 了,感觉 Prime Video 不怎么用得到,所以还是用免费的 Abema 吧。

然而 Abema 很不爽的一点就是动态分辨率(不如说很多流媒体网站都这样),就喜欢自己判断你网速够不够,然后给你播放带宽相应的清晰度。初衷估计是为了任何网络环境条件下都能流畅播放,可是讲道理,我就没见过这个自动判断准过几次。

就算在设置里开到最高画质,还是动不动给我跳到 480p 甚至是 360p。我他喵的到底是哪里不行,就只配看你这马赛克画质?

真是叔可忍婶不可忍,于是我去网上找有没有 Abema 强制 1080p 的方法(因为也有个 Chrome 启用 Netflix 1080p 的扩展),正好找到了一个

const open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
  arguments[1] = arguments[1].replace('720/playlist.m3u8', '1080/playlist.m3u8');
  open.apply(this, arguments);
};

看了一下,没想到原理还挺简单,就是油猴脚本劫持 XHR 请求方法,把其他清晰度的 m3u8 playlist 全部重定向到 1080p 的 playlist 上。这样不管怎样请求,实际返回的都是 1080p 清晰度的源了。想想确实是这个理,高啊!

还好以前捣鼓过一段时间 HLS 相关的东西,所以这些不算陌生。不过实际使用的时候发现 XMLHttpRequest 并没有拦截到 playlist.m3u8 之类的请求,看了一下,原来是 Abema 请求的时候改用了 fetch API。反正大同小异,稍微修改一下就行了。

修改后的脚本同样放在 Gist 上:

// ==UserScript==
// @name Abema 强制 1080p
// @description 把其他清晰度的播放列表强制指向1080p
// @version 1.1.0
// @run-at document-start
// @namespace Violentmonkey Scripts
// @match https://abema.tv/*
// @grant none
// ==/UserScript==

const originalFetch = window.fetch

window.fetch = (...args) => {
  const regex = /\/\d+\/playlist\.m3u8/

  if (typeof args[0] === 'string' && args[0].match(regex)) {
    args[0] = args[0].replace(regex, '/1080/playlist.m3u8')
    console.log(args[0])
  }

  return originalFetch(...args)
}

题外话,好久没追过新番了,但佐贺二期开播后我现在每天都想快进到周四……

啊啊啊!

zombieland-saga-revenge-ep3

好了,网页端的问题解决了,那么客户端是不是也可以用这个方法呢?

抓包看了一下,客户端请求的确实是同样的 URL,直接如法炮制。

不过要修改客户端的请求就不像 Web 浏览器那么简单了,需要用到 MitM(中间人)攻击。目前 iOS 平台上主流的代理软件应该都支持 MitM,比如 Surge/Quantumult X/Shadowrocket。下面以 Quantumult X 为例。

开启 MitM 功能,添加主机名如下:

更新:网页版和手机版请求的是 vod-abematv.akamaized.net,iPad 上请求的是 ds-vod-abematv.akamaized.net,搞不懂,直接通配符算了。

*abematv.akamaized.net

安装并信任证书(过程略),修改配置文件,添加重写规则:

[rewrite_local]
abematv\.akamaized\.net/.+/\d+/playlist\.m3u8 url request-header /\d+/playlist.m3u8 request-header /1080/playlist.m3u8

验证强制 1080p 是否成功(开启 HTTP 调试功能查看):

quantumult-x-rewrite

可以看到原本是要加载 720p 的,经过重写后实际加载的是 1080p 的 segment。

爽!