Flash 保存计划 Encore

引言

前几日 Steam 仙剑奇侠传系列大包 打折,四、五、六、五前传四部仙剑只要 ¥12.2,加之大促挂卡掉了张闪卡小赚五块,不到七块喜加四,畅玩了一番。

仙剑系列之前只玩过 137:

  • 7 虽然剧本不堪,系统和九泉世界观的构建确实不错,而且前不久加入了 XGP,试错成本很低
  • 3 年代久远,当时玩的因为这是上海软星的第一部作品,不久之后还出了电视剧
  • 1 玩的版本比较多,DOS 版、95 版、98 柔情版、SS 版,顺带一提 SS 版仙剑也是土星上唯一的官方国产游戏

打完五前传弃坑六(开场 CG 世界观搞得那么大,结果操作人物初次战斗是打小混混)适逢 Switch 版「轩辕剑叁:云和山的彼端」发售,于是搞了一个,然后被各种恶性 bug 折磨直到死档删游 :)

终于要进入正题了,印象中轩辕剑我只玩过初代和 3 外传「天之痕」,结果昨天晚上突然想到鬼谷工作室做的天之痕 Flash 同人「上古神器」,这才想到,当年玩的压根就不是天之痕。

上古神器 1 标题界面

轩辕剑传说:鬼谷之泪™

又想到之前下过 在线 DOS 游戏 的全站 ROM(chinese-dos-games),顺藤摸瓜果然搜到了 Flash 保存计划,于是看到个网站就想爬的爬虫瘾犯了,一番操作写了一个 Bash 全站下载脚本。

当然,因为这个量比较大,统计数据页面 显示有 165,670 个 Flash,文件总大小 430.22 GiB,全部下下来还是有点费劲,所以只是写了,没有真的抓取。如果只需要单个 Flash,在游戏界面即可下载。

此外注意原项目采用 CC BY-SA 4.0 DEED 许可证,使用请保证遵守开源协议。

前置信息

  • Flash 保存计划项目地址: flash-archive-project
  • 需要的 flash.json: https://raw.githubusercontent.com/rwv/flash-archive-project/main/flash.json
  • 获取 SWF 文件: https://flash-swf.zczc.cz/{sha256}.swf
  • jq

jq

jq 用来处理 JSON 数据相当方便,我在 Awesome One-liner 中也多次使用,随便举个🌰️,获取 Citra 最新的 nightly build 下载 URL:

# Get Citra Nightly Download URL
GITHUB_URL=$(curl --silent --location https://api.github.com/repos/citra-emu/citra-nightly/releases/latest | jq --raw-output ".assets[].browser_download_url" | grep --extended-regexp "citra-linux-.*?.tar.xz")

完整的 flash.json 有 8M,这里只贴个简化版简单说一下数据清洗:

{
    "0000633ee403f443cffbfc9ee16d919a91954eb8e7e9d7dd72af3f59abe202cc": {
        "sha256": "0000633ee403f443cffbfc9ee16d919a91954eb8e7e9d7dd72af3f59abe202cc",
        "size": 233234,
        "original": "http://www.flashempire.com/theater/flash/2001-06/725.swf",
        "ref": {
            "flashempire": {
                "author": "ZOLLIS",
                "id": 737,
                "name": "北京的梦想",
                "popularity": 7288,
                "url": "http://www.flashempire.com/theater/play.php?id=737"
            }
        }
    },
    "000becacfecf648c39d547da798b5527b6fba89f48bb44f3708be88920ea823c": {
        "sha256": "000becacfecf648c39d547da798b5527b6fba89f48bb44f3708be88920ea823c",
        "size": 4031690,
        "original": "http://www.flash8.net/uploadflash/16/flash8net_15491.swf",
        "ref": {
            "flash8": {
                "author": "vincent",
                "description": "这个片子是偶然做起来的\n和此前完全不同的感觉\n基本没做剧本\n想哪做哪\n就算一个小尝实验了:)\n以后继续实验新的东西",
                "email": "dayong7645@163.com",
                "id": 15491,
                "name": "迷墙(the wall)",
                "original": false,
                "uploader": "大大大苹果",
                "url": "http://www.flash8.net/flash/15491.shtml"
            }
        }
    }
}

可以看到 JSON 包括了几乎全部的元数据,不过下载全站需要用到的只有 sha256name。文档是不可能看的,用法是不可能会的,但是可以塞文档问 GPT。

由于 JSON 文件中的 sha256 是作为对象的属性,我们需要使用 keys 函数来获取属性名,然后再提取对应的 sha256 值:

jq 'keys[] as $key | .[$key].sha256' file.json

这个表达式首先使用 keys[] 函数获取所有的属性名,然后使用 as $key 将每个属性名存储在变量 $key 中,最后使用 .[$key].sha256 来提取对应的 sha256 值。

同理,提取 ref 下面的 name(注意中间字段不一定是 flashempire,也可能是 flash8 或者其他内容):

jq 'keys[] as $key | .[$key].ref | .[] | .name' file.json

以及构造输出为 {sha256} name 的格式,比如这样:

0000633ee403f443cffbfc9ee16d919a91954eb8e7e9d7dd72af3f59abe202cc 北京的梦想
000becacfecf648c39d547da798b5527b6fba89f48bb44f3708be88920ea823c 迷墙(the wall)

需要将两个字段拼接在一起时,可以使用字符串插值来实现:

jq 'keys[] as $key | "\(.[$key].sha256) \(.[$key].ref[].name)"' file.json

sed

sed 也是老生常谈,我在 富婆妹 FD 机翻汉化补丁润色笔记 中曾经提到过,BTW 这篇文章至今都有不小的访问量,实在是匪夷所思, 甚至怀疑被(Artemis 引擎)机翻教程引用了,不过只要保留原文链接,想用就用吧,我对机翻并没有抵触情绪,不然也不会写 VNR 了。

#jq 最后拼接出的字符串带双引号,不符合 hash 的格式,但正好利用这个双引号来构造下载 URL。

"0000633ee403f443cffbfc9ee16d919a91954eb8e7e9d7dd72af3f59abe202cc 北京的梦想"
"000becacfecf648c39d547da798b5527b6fba89f48bb44f3708be88920ea823c 迷墙(the wall)"

#前置信息 中已经给出 SWF 的下载地址,只需要根据 jq 中提取的 sha256 加上前缀和后缀即可:

# Before
0000633ee403f443cffbfc9ee16d919a91954eb8e7e9d7dd72af3f59abe202cc
# After
https://flash-swf.zczc.cz/0000633ee403f443cffbfc9ee16d919a91954eb8e7e9d7dd72af3f59abe202cc.swf

实际命令也没什么难的,注意转义 https:// 中的 / 即可:

# 构建 URL
cat sha256.txt | sed 's/"/https:\/\/flash-swf.zczc.cz\//' | sed 's/"/.swf/' > wget-list.txt

这里本来想用变量,方便后续下载全站截图,然而 sed 单双引号混用有点麻烦,遂作罢。

SWF_PREFIX="https://flash-swf.zczc.cz/"
SWF_SUFFIX=".swf"

还有一个问题,直接下载下来的 SWF 都是 0000633ee403f443cffbfc9ee16d919a91954eb8e7e9d7dd72af3f59abe202cc.swf 这种名字,鬼才知道哪个是哪个,下载后手动重命名为 北京的梦想.swf 才便于搜索。而 jq 中插值生成的 hash 除了用来校验下载文件,还可以用作批量重命名。

这一步的 sed 看着复杂,其实只需要注意先后顺序即可,随便一个文本编辑器打开正则替换,或者直接另存为 CSV 和 UTF-8 BOM 编码,用 Excel 操作也不成问题:

# 构建文件名替换脚本
cat file.txt | sed 's/ /.swf / ; s/"/mv /' | sed 's/"/.swf/' | sed 's/ / "/'2 | sed 's/.swf/.swf"/'2 | sed -E '1s/^/#!\/bin\/bash\n/' > file-rename.sh

注意替换完成后,需要手动打开脚本检查一下,有很多 edge case 没有考虑,懒得优化,比如 L1654 癫当 神奇玫瑰花(第一集).swf 有错位,导致直到 L4875 的三千多行无法正常处理。处理也很简单,找个有代码高亮的编辑器花几分钟改改就能用,总好过手动重命名这一万多个文件。

脚本

最后附上完整脚本,还是那句话,遵守原项目协议,请勿滥用。
#!/bin/bash
# Flash Archive Project Downloader
# Author: Vinfall
# License: GPL

# 这里只下载 SWF,没有下载对应截图
wget https://raw.githubusercontent.com/rwv/flash-archive-project/main/flash.json

# 提取有关信息
cat flash.json | jq 'keys[] as $key | .[$key].sha256' | sort | uniq > sha256.txt
#cat flash.json | jq 'keys[] as $key | .[$key].ref | .[] | .name' | sort | uniq > name.txt
cat flash.json | jq 'keys[] as $key | "\(.[$key].sha256) \(.[$key].ref[].name)"' | sort | uniq > file.txt

# 构建 sha256sum
cat file.txt | sed 's/"//' | sed 's/"/.swf/' > hash.txt

# 构建 URL
#SWF_PREFIX=https://flash-swf.zczc.cz/
#SWF_SUFFIX=.swf
cat sha256.txt | sed 's/"/https:\/\/flash-swf.zczc.cz\//' | sed 's/"/.swf/' > wget-list.txt

# 构建文件名替换脚本
cat file.txt | sed 's/ /.swf / ; s/"/mv /' | sed 's/"/.swf/' | sed 's/ / "/'2 | sed 's/.swf/.swf"/'2 | sed -E '1s/^/#!\/bin\/bash\n/' > file-rename.sh

# 批量下载并重命名
wget --continue -i wget-list.txt
sha256sum -c --ignore-missing hash.txt
#bash file-rename.sh

# Garbage clean
rm sha256.txt name.txt file.txt

echo 'Done'
#rm wget-list.txt file-rename.sh file.txt

Vinfall's Geekademy

Sine īrā et studiō