修改content-disposition解决Firefox无法直接打开种子等文件的问题

Firefox有个问题,就是对于某些文件类型,即使你在设置里设置了“始终使用XXX打开”:

001

部分站点击下载该类型文件时仍然会出来弹窗询问。这个问题已经困扰我很多年,其背后原理其实也早已知晓:凡是response header有content-disposition: attachment的HTTP request,即便是有“始终用XXX打开”的设置,也依然会弹出下载框(仅限“Use xxx application”的情况;如果你设的是保存到本地,倒是可以免询问下载)。

根据Bugzilla的ticket,这么设是为用户的安全考虑,防止稀里糊涂就用本地程序打开了什么恶意文件。虽然我个人觉得完全站不住脚:如果网站真的想这么干,他把content-disposition设成别的不就完了?

这个问题最烦的就是种子文件,因为99%的情况我是要直接用uT打开的。常去的tracker里,只有eh的tracker有这个问题,其他几家,DMHY用的是content-type: application/octet-stream,所以根本没有content-disposition的问题;nyaa.si用的则是content-disposition: inline,也无问题。

在pre-57年代其实就有个扩展叫InlineDisposition(还有无数克隆,57能用的应该是这个),可以自动把一切content-disposition: attachment变成inline,但是缺点在于

  1. 没有filter,什么都会变成inline,包括一些网站的图片下载链接也会变成在浏览器里打开,很不方便;
  2. 会导致很多文件下载时文件名乱码——这个更烦一点。为什么?这里按下不表,后面我们会专门谈起。

所以,我也就一直这么忍了过来,就是每次在eh下种子都要多点那么一下确认。

使用Header Editor替换种子文件的 header

今天,我突然发现Header Editor这款很不错的国产插件居然也有修改response header的功能,于是稍微调试了一下,果然可以搞定eh的tracker了。具体规则么,也很简单,就是

  • Rule type:Modify response header,
  • Match type:Domain,
  • ehtracker.org,
  • Execute type:normal
  • Header name:content-disposition
  • Header value:inline

就OK。不过这有个问题:你没发现一个站搞这一出,你就得重新加一条。

通过参考HE的评论区某人的评论,我发现可以用Custom function的方式来处理:先把上面的Rule的Match type改成All,以及Execute type改成Custom function,然后输入以下代码:

不过这里有个小问题,因为我们简单粗暴地把整个content-disposition header给替换成了inline,而没有保持原有的filename字段。虽然对于我们直接打开其实没有什么影响,但是强迫症作祟,我想能否用正则,仅替换最前面的“attachment”为inline,后面的还保留?

let res = a.value.replace(/^attachment/iu, "inline");

这样的形式思路应该没问题,但是实际操作中,会发现这么一改,我发现有时候会导致整个修改完全失效,又回退到原始的header。这是怎么回事呢?

Header的编码

这就不得不牵扯到一个很重要的Header的编码问题了。

拿这个 Ehtracker这个种子为例:

https://ehtracker.org/get/1111939/8ac51291db878d860b7d064be9745ae838a0b7eb.torrent

先观察原始header(这里顺便一提,用Firefox的网络控制台永远只能看到原始header,看不到插件更改之后的):

003

奇怪,文件名部分居然是乱码?但是,在对话框或者真正保存下来的时候却正常:

004

稍加研究,原来HTTP Header的编码(曾)是限制在ISO-8859-1,直到RFC2047起才允许使用其他编码。在实践上,仍在大量使用ISO-8859-1,甚至绝大部分字段只用ASCII。

至于ISO-8859-1,也就是所谓Latin-1,你就大概理解成和GBK类似的西方的二字节编码就行。那么我们把刚才那个字段复制出来:

(C92) [比村乳業 (比村奇石)] 月曜日のたわわ そのIV (オリジナル).zip.torrent

然后用Python稍微处理一下:

mystring = '(C92) [比村乳業 (比村奇石)] 月曜日のたわわ そのIV (オリジナル).zip.torrent'
mystring.encode(encoding='iso-8859-1').decode('utf-8')

输出:'(C92) [比村乳業 (比村奇石)] 月曜日のたわわ そのIV (オリジナル).zip.torrent’

符合预想。

JS的话,原生Byte和多编码转换的支持极为贫乏,一般都得用库,但是这个特例可以用一个trick:

decodeURIComponent(escape('比村奇石'))

这个trick之所以能工作,是因为escape函数是基于RFC 1738,所以用的是latin-1 encoding来encode(是编码成百分号的URL encoding形式,例如ƒ=%83(83是16进制下该符号在latin-1的码位);但是decodeURIComponent却是decode UTF-8 encoding下的URL encoding的字符用的,所以这个操作就相当于latin-1编码成byte再utf-8解码成字符串,也就是还原了我们的真实字符串。

上面是讲我们自个儿如何来翻译这串乱码。那Firefox自己在处理时,工作顺序大概有两种可能:

  1. 从字节码开始
    • ->直接用UTF-8解码->真实文件名字符串
    • ->同时用Latin-1解码->显示为dev tools里那串乱码
  2. 从那串乱码字符串开始
    • ->用Latin-1编码为Byte->用UTF-8解码->得到真实文件名字符串
    • ->直接显示dev tools里那串乱码

虽然浏览器最底层肯定从byte开始处理,而不是字符串,但是这里有必要区分一下两种情况——因为我们替换的时候只能替换字符串而不是byte,所以其实我们的流程更接近2,但是要倒过来:

你的原始非ASCII字符串->用UTF-8编码成byte->用latin-1解码成乱码字符串

当你搞出来这坨乱码字符串之后,替换原始header,Firefox会再按照上面流程2的分支一处理,给你搞出正确的文件名来。

如果你不这么做,直接上汉字比如

a.value = 'attachment; filename=\"汉字.txt\"'

Firefox会发现第一步用latin-1编码就失败(因为超出了latin-1的字符范围了),于是他直接catch错误跳出,完全忽视你对response header的替换,而改用回原始的header了。

至于制作乱码字符串的方法,自然也就是把前面的反过来:

unescape(encodeURIComponent("呵"))

用Python的话就是:

mystring = '呵'
b.encode(encoding='utf-8').decode('iso-8859-1')

输出是å\x91µ,复制到我们刚才的脚本里(没错,包括转义符\x91),稍微简化下:

for (let a of val) {
if (a.name.toLowerCase() === 'content-disposition') {
console.log("orig: " + a.value);
a.value = 'attachment; filename=\"å\x91µ.txt\"';
break;
}
}

然后再点击上面ehtracker那个链接试试,变成“呵.txt”了吧?

我还有个有趣的发现。上面我们看到我们是先把我们的字符串用UTF-8编码成byte,然后byte按Latin-1解码成那串乱码对吧?其实最开始的编码也支持本地locale,对我来说就是GBK:

mystring = '呵'
b.encode(encoding='gbk').decode('iso-8859-1')

这回输出变成了ºÇ,到上面的脚本里替换一下,再点ehtracker的链接,依然可以获得“呵.txt”的文件名。当然,如果你的系统不是简体中文,我就不能保证也工作了。

当然,这俩不能混用,要么就全GBK,要么就全UTF-8。否则轻则部分乱码,重则直接挂掉。

不过细心的读者可能会发现:HE工作时,他读取到的原始header里的字符串应该就是乱码字符串,如果仅仅是替换最前面的attachement为inline(都是ASCII字符),应该根本牵扯不到你这一大堆,永远会work才对啊?

咳,这个我研究了一个多小时,甚至自己写了个扩展调试才发现,有可能是因为我有另外一个扩展Download Filename Encoding 已经自己偷偷把乱码字符串给替换成正常了…所以你再直接塞回header Firefox不认。而且这俩扩展的顺序还不一定,所以时好时坏。之所以说有可能,因为有时候哪怕只要重启一下Firefox就无法重现…不过,凡是bug发生的时候,会看到那个字符串在传入HE的时候就已经是正常字符串(而不是乱码字符串)了。

Edit:经过了又长达X(X远大于我愿意承认的数量…)小时的debugging,我终于发现了根本原因:在Firefox release 57左右有一个很短暂的时期,webRequest.onHeadersReceived.addListener给callback的header是原始字符串,而不是latin-1编码的乱码字符串。这个“Bug”恰好影响且只影响目前的Firefox stable (57.0.4),所以我总是无法稳定重现(因为我平时用的是stable,测试都用beta或者Nightly…)

我用mozregression找到的Bug出现的regression window是9月7日,bug消失的fix window是9月28日。前者倒是能看到有和responseHeader有关的东西,但是后者我翻来覆去看了半天也不知道为啥会影响header的编码。嘛不管了不管了。

这里也得顺便提下,我还试了在Chrome下(WebExt确实方便,直接无缝导入Chrome,就是brower这个对象得还改名chrome),Chrome返回的content-disposition header的就不是乱码,而是真实字符串。

同理,你如果要修改的话,Chrome不需要处理,Firefox就得处理,即

另外,还学了几个新东西:

一、WebExt写个扩展真的好简单……比起原来的XPI啥的。改response header就简单地加个

在background的JS里就OK(权限什么的反而相对比较麻烦些)。完整代码(其实也就是这个+manifest.json)在GitHub上。

另外,测试的时候也别老操人家EH了,我做了个http mock:http://www.mocky.io/v2/5a523c8e2e0000a928c03a73

二、RFC 5987新增加了直接用UTF-8记录文件名的方法(SO讨论),语法为

Content-Disposition: attachment; filename*=UTF-8''{URL编码之后的字符串}

例如“你好.txt”就是(用encodeURIComponent帮你编码)

Content-Disposition: attachment; filename*=UTF-8''%E4%BD%A0%E5%A5%BD.txt

而且不需要双引号括起来文件名了,因为空格都被变成%20了。

用JS的话,就是

Advertisements

《偶像大师 百万现场!剧场时光》的Appeal值计算公式和范例

玩《偶像大师 百万现场!剧场时光》也1个月了。这游戏里有一个很重要的元素是偶像队伍组合:根据组合不同,会得到不同的所谓“Appeal值”,然后这个值是和你最后打歌的分数成正比的。

不过奇怪的是,查了一圈Wiki,发现这么重要的值,居然没有人发过计算公式。当然,基本而言就是每个偶像卡面数据加上一些加成,但是这游戏里加成很多样,还有guest和support的设定,所以虽然知道个大概,但是具体也并不是那么清晰明了。另外,游戏里的自动选人功能也挺蠢的,有时候并不会选到最佳组合(A值最高或者单项最高的5张卡组队都不能保证是总A值最高);我想写一个更好的组队脚本,但是首先也得要有这个公式。

于是昨天花了几个小时在excel里不断尝试,总算把这个公式给摸出来了。

excel
这都是血汗啊

计算公式

游戏里每个偶像卡分别有三个属性,Vocal(Vo),Dance(Da),和Visual(Vi)。三者之和即为Appeal值。这个卡面数据即为下称的基础值。同时,每个卡又分为三个类型,PrincessFairyAngel。根据Type不同,最多可能有三种加成方式:Center位技能加成,Guest Center位技能加成,歌曲类型加成。

打歌时的组队由5个自选偶像+1个Guest偶像(由其他玩家提供)+10个系统自选Support成员组成。

那么先来重点,对于每个属性,公式如下:

基础值 = 5个上场队员卡面值+Guest卡面值+10个Support卡面值/2

Bonus = 6个队员(5+guest)卡面值 * (C位技能加成[需匹配Type和属性]+Guest C位技能加成[需匹配Type和属性] + 歌曲加成[需匹配Type]) + Support卡面值*(歌曲加成 [需匹配Type])

几个注意点:

  • Guest和上场队员受到的加成一致,完全可以当做是6人组。在匹配属性的前提下,最多可以受到C位技能加成(例如:Fairy类型90% Dance值)、Guest带的C位技能加成(例如:Fairy类型90% Dance值)和歌曲类型加成(+30%总Appeal值)三者,加法叠加。也就是说,只要属性一致,最多可以获得某个属性(例如Dance)加成210%、其他属性加成30%的效果。
  • Support队员只收到歌曲类型的30%加成(当然,属性也得匹配),不受任何C位技能加成。另外,Support系统是自动根据当前歌曲类型加成之后的Appeal值中选最高的10位。所以是不会亏你的。

UI上的各个数值的解释&计算范例

其实主要内容就上面这些了,不过UI元素上很多地方都有数值显示,有时候很不一致或者误导,下面接一个例子主要讲一下每个UI元素代表什么。

选Guest的页面

选Guest界面默认显示的是Guest 基础值+歌曲Type 加成Only的总和。等待几秒会切换模式显示详情,这里分项显示的括号内为歌曲Type 匹配加成(基础值的0%或者30%),括号前为加成之后的总和。这个我觉得是有一丁点误导,因为我们前面已经说了,Guest实际并不只受到歌曲加成。

001

这里可以看到,我选了个蓝(Fairy)歌,所有30%的加成。简单验算下,Vocal的5512/1.3=4240(基础值),4240*0.3=1272(Bonus)。

主界面

002.png

主界面没什么好说的,就一个数值——合计Appeal值。这个数值等于基础值+所有Bonus之总和,也就是你的最终A值。

这里我的偶像的基础数据如下:

属性 1 2 3 4 5
Vo 1195 938 2740 1187 919
Da 671 1182 1894 931 930
Vi 902 651 3544 656 959
Sum 2768 2771 8178 2774 2808

注意我故意选了4个Princess的,方便计算(因为加成是0)。至于我的Guest的基础数据,是上面贴的那个伊织(注意这里是去掉那30%之后的真·基础值):

属性 Guest
Vo 4240
Da 5997
Vi 7832
Sum 18069

Support界面

003.png

Support页面也是只有一个数据——总Appeal,这个数值是Support的基础值+bonus(歌曲加成[需匹配Type])之和的50%。根据公式,Support只计算歌曲类型加成,所以这个数据是准确的。

让我们列一下我这10个Support:

属性 白石 Julia SSR 白濑 律子 Julia SR 美也 Ami 静香 二阶堂 SUM
 编号 1 2 3 4 5 6 7 8 9 10
Vo 5366 7017 3354 3192 3079 4374 3771 5414 2729 3808 42104
Da 3974 3805 6193 5685 4347 5582 6951 6943 3817 2504 49801
Vi 6851 5355 4762 4264 5708 3169 5405 3743 4891 5052 49200
Sum 16191 16177 14309 13141 13134 13125 16127 16100 11437 11364 141105

嗯,因为有两个是Angel的,不受加成,所以分类计算下(已经乘了50%):

属性 Support-Fairy Support-Angel Support-Sum
Base Vo 16459.5 4592.5 21052
Da 17953.5 6947 24900.5
Vi 20026 4574 24600
Sum 54439 16113.5 70552.5
Bonus Vo 4937.85 0 4937.85
Da 5386.05 0 5386.05
Vi 6007.8 0 6007.8
Sum 16331.7 0 16331.7
Sum  Vo 21397.35 4592.5 25989.85
 Da 23339.55 6947 30286.55
 Vi 26033.8 4574 30607.8
Sum 70770.7 16113.5 86884.2

最后的总和是86884.2,和UI显示的86878不超过0.01%,可以接受。至于为什么会比UI数值稍高,估计是游戏内浮点运算有截断为整数的步骤,或是显示的整数属性实际是小一点的浮点数。同样的误差在下面的Bonus计算里也有。

“i”内的合计Appeal详细

004.png

重头戏来了——点击合计A值后面的感叹号,可以得到这个详情。这里,括号前黑字为所有基础值 ,括号里蓝字为 (+所有Bonus)。上面的合计Appeal和外面是一样的,就是把这些全部加起来而已。可以看到,这里和选Guest界面的数值就有不一致之处:那里括号前面的数值是包含括号内的加成的,这里却不包含

基础值的计算,其实就是把我上面那几个表格加起来,这里除了那种单数Support的数值除以二之后会出现0.5之外,其他可以做到丝毫不差。没什么难度。Bonus的计算,则稍微复杂点。

这里,我的C位技能是Fairy类型+30% Vi,我的Guest的C位技能是Fairy类型+90% Vi。不过成员中是Fairy类型的只有我的C和Guest他俩,各+90% Vi。另外,歌曲类型是Fairy,所以这俩人所有属性再+30%,另外support 10人中的八人也享受(且只享受)这个30%加成。至于其他4个成员和2个support,则是0加成。

所以,总体加成是:3号位和Guest:Vo+30%,Da+30%,Vi+150%。8个Support:所有属性+30%。数据实在太多,我贴个图片表格好了:

005

这里,红字为游戏UI原始数据(包括卡片数值和上面谈的UI上的数值),黑字为计算数据。

看第一个表最后三列,可以看到我的计算和UI的数值基本完全一致。

选人策略

其实选人策略根本不需要这么复杂的公式啦,估计老Producer早就会了,不过还是废话两句。

  1. 所有卡片类型和歌曲一致——30%可不能小看。
  2. 属性方面,先看自己手头有什么C位技能,如果只有一个90%那自然选那个属性的。如果有很多的话,就依次下面的步骤试试,实验的时候别忘了切Guest!
  3. 确定属性之后Guest也选那个属性+90%的(不要选所有Appeal+30%的,一般不如单属性+90%分高)
  4. 卡组一般就直接无脑系统おすすめ自动选特定类型-特定属性的5个最高就行。
  5. 有较小概率出现偏科卡,这时候要把5号位的卡换成未上场该属性卡种最高合计Appeal值的选手看一下(强调,不要相信卡面切换时的卡面差值,那个不显示加成,没有任何意义,亲自选出来一下看看总A值的变化才准)。虽然一般不会有什么提升,即使有一般也就两位数……
  6. 别忘了A值不是一切,还有技能。能全连的自然盾奶、Combo就换掉了,依然用上面的方式选人。我记得有日站说同类技能会覆盖所以不要选一样的,这个我没研究过。

iTunes高清专辑封面获取详解

算是对前文(以及下面评论)的一点点扩充。如果只是需要获取高清封面,其实前文的内容就够了;这里是自己瞎研究的成果记录而已。

iTunes search API

之前有提到过“iTunes Artwork Finder”这个很好用的网站,其实只要稍微看一下他的源代码,就知道其原理是调用Apple或者说iTunes的一个公开搜索API(官方介绍博文):

http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsSearch?term={keyword}&country={country code}&entity={type}

其中country code是两位(比如日本=jp),type就是类型,专辑就是album了。

那么还以上次的那张专辑为例:

http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsSearch?term=花ハ踊レヤいろはにほ&country=jp&entity=album

返回的结果是json(虽然莫名地是txt后缀):

可以看到,我们关心的是artworkUrl100或者artworkUrl60这个属性。其地址是:

http://is5.mzstatic.com/image/thumb/Music5/v4/56/94/1f/56941fcf-ee47-d474-7e3e-f0bea7f8da0c/source/100x100bb.jpg

这里前面的是id等,最后这部分的“100x100bb.jpg”,其完整格式是:

{w}x{h}({resize_method}-{q}).{ext}

其中括号内为可选参数。

w和h是尺寸很好理解,那个resize_method是用来控制如何控制尺寸的,比如如果什么也不填,就会把图像不改变比例缩放到能fit进给定宽高的大小内;如果加了w参数,就fit width而无视高度;加了h以此类推。至于bb到底是什么我还没搞明白(官方文档默认就用bb但是也没说代表什么),似乎和不加没区别。至于最后的-q,是JPEG质量因子,默认不填等于80。如果要获取最大质量,只需要附加大于等于100的数字即可,例如-100或者-999。上文的评论里我有说到在iTunes web页面的图像质量稍差,就是因为那里没加专门的质量参数的缘故。

所以,我们可以用上述公式拼出自己想要的图片,例如600x0w-90.jpg(600宽,90%质量JPEG)这类。当然,我们追求最大质量的情况下,可以直接获取png格式最大尺寸,使用99999x99999.png即可。

iTunes web API

那么这个search API这边的就说完了,下面说回iTunes自己的web页面那边。和绝大部分现代网站一样,iTunes也是内容通过API的方式异步读取(MVVM,用的应该是Ember.js框架)。通过控制台很容易便找到上述专辑的API call:https://itunes.apple.com/jp/album/huaha-yongreyairohaniho-ep/id907305525?isWebExpV2=true&dataOnly=true

太长了我就不贴出来了,不过这里有一个有趣之处:这里,该专辑对应的artwork的url是

https://is4-ssl.mzstatic.com/image/thumb/Music3/v4/8e/1d/5f/8e1d5f93-917c-6c49-c331-a62830fdf0c9/AVCA-74538.jpg/{w}x{h}bb.{f}

然而专辑里每个曲目对应的url却是不一样的

https://is2-ssl.mzstatic.com/image/thumb/Music5/v4/56/94/1f/56941fcf-ee47-d474-7e3e-f0bea7f8da0c/source/{w}x{h}bb.{f}

可以看出,这个和上面用API获取到的是一样的(ID是56941fcf开头,地址含有“source”),而整个专辑的却不是(ID是8e1d5f93开头,地址含有AVCA-74538.jpg)。这个现象我在前文也有提到。虽然不是很理解为什么会有这种区别,不过这两张图是完全相同的(A vs B)。

iTunes页面添加脚本

既然我们知道两种方式获取的图像链接虽然不同但是是同一张图像,我们直接通过分析iTunes web页面上的略缩图,可以轻易生成大图的链接。这个User脚本可以给iTunes页面添加一个链接,点击就可以直接打开大图(是添加在图片左下方的X songs那里,而且是JPG,可以自行替换为PNG)。但是我发现这个脚本虽然在美国iTunes好使,在日本站不工作。究其原因,就是日站那边的API call的速度很慢,而且call回来之后他会重写页面的几乎所有元素,所以如果用脚本提前给某个元素添加了链接,会后面被API的xhr给重新改写掉。

虽然可能有更elegant的方法,不过我简单粗暴地用setTimeout()加了个延时,就好使了。另外,我也没用上面那个,而是自己手写了一个:

https://github.com/fireattack/scripts/blob/master/itunes_cover_art_click_to_show_original.user.js

区别在于这个是直接点击封面略缩图获取大图。

11/30更新:用MutationObserver重写了,现在检测到DOM变化之后会再插入一次(应该是一次就够),不用再用弱智的延时了。

Firefox “Quantum” revisited

いよいよ明日!终于Firefox正式版也要更新至所谓的Quantum(57)了。自从上文之后,我本想直接试用测试版的57,不过用了两天还是难受的不行,没坚持下来(主要还是tab操作难受),换回了56正式版。那么这又过了一个多月,情况是否有所改善呢?

本文主要针对基于前文提出的那些问题一一讲解,所以请对照观看。前文已经替代掉的插件就略过不写。

FlagFox

依然还没更新,还没决定用哪个替代,不过这个不太重要。

Greasemonkey

彻底换用TM。以后基于这个原则:凡是Firefox和Chrome能通用的都通用,不想折腾。而且TM确实好用,这个没得说(除了强制更新脚本的UI非常啰嗦以外)。过一段研究下用Google Drive能不能实现跨浏览器Sync。

Image Search Options

作者已经自行更新了WE版本。至于效果嘛……我先贴一下这个新版的菜单你感受一下:

is

至于WE版本的限制,你再感受一下:

Due to limitations in the available WebExtensions APIs, the following feature changes needed to be made:

Direct POST no longer works for websites where no new page is generated by a POST request.

To work around the POST issue, an intermediary “Use IMGDATA to URL Host” option has been added. This option uses POST to upload the image to a temporary host, and then uses a URL provided by that temporary host to perform a GET request with the option’s settings. The intermediary host is also used when data uris and other non-usable URLs are encountered if the selected option is not set to use ::$IMGDATA::.

Right click on context menu items is no longer usable for triggering the alternate option settings. This functionality has been replaced with the shift key, and a checkbox added to the context menu. To use the alternate options, hold down the shift key while clicking on a menu item, or first click the ‘Use Alternate’ option checkbox.

It is no longer possible to add multiple options to the main menu, a submenu will be created automaticly.

It is no longer possible to search for images stored on your local system, we will look into alternative solutions for an upcoming version.

嗯这里面要命的是两点:第一个POST必须用服务器中转的方式;但是即使用了服务器中转,也还是不支持本地图片。这个就很烦了,想搜索QQ里的图再也不能拖进浏览器->直接右键搜索了。第二点是UI限制,现在菜单(单个插件?)只支持一个菜单项,所以所有的选项都必须被包在里面很繁琐;然后不支持右键点击调用备用方式(一般是POST),必须shift。总之就是戴着脚镣跳舞咯。

那这么麻烦我还不如直接用Search By Image这个脚本了。这个脚本对于本地图的支持是先呼出菜单,然后把图片拖进菜单里,基本和原来的操作差不多。另外理论上Chrome里还额外支持ctrl+V粘贴进菜单,但是我试了下复制QQ里的图大概由于QQ的剪贴板对象特殊的原因还是不行,所以没啥大用(复制本地图片一般是可以)。不过也有个缺点,不支持网图直接POST/中转的方法搜索(对于某些有referer检查的网站比如exhentai就会有问题。Chrome可以用先右键复制图片到剪贴板的方式workaround一下,Firefox就吃瘪了)。

Image Zoom

本体就不用幻想更新了,上次提到的三个中最接近的Zoom Image更新了2.0版,现在有fit to screen了,只不过快捷键是右键+中键(而且还不能再按一次复原),但是基本属于可以用的范畴。

Pearl Crescent Page Saver screenshot tool

嗯为了找这个的替代品,我试了市场排名靠前的一坨:

screenshot

这里面很多功能都贼多,有非常详尽的编辑工具,如果你比较需要那些,推荐自己去试试。而且这些插件普遍感觉是由专业团队开发,UI非常漂亮,这个点赞。

不过我在意的是一个功能:截网站全屏,要快快快快,而且不要有烦人的肉眼可见的滚动效果。试了前几个(包括我之前用的Page saver的WE版)发现都有滚动,我几乎怀疑是不是WE根本做不到——直到发现了Screengrab!这个。这个功能不多,就是基本的截全站、选择区域、截当前可见等等,但是菜单简练精干,有复制到剪贴板、保存图片等方便的选项,完全符合我的需求。最最重要的当然是,截全屏多快好省,没有滚动(也因此我发现一个效果,对于那种页面上的悬浮框,不会像其他的截图工具那样出现重复好几次的问题)。

Show Location

没希望。

Tab Mix Plus

这边情况还是和上次一样绝望。

而且在试用Firefox 57的几天内我发现个更为蛋疼的问题:在Firefox里,可以做到按Ctrl+tab按最近浏览的顺序切换(即和Windows的alt+tab一样,按一次会回到上一个你用的标签,按住ctrl不放按多次tab以此类推),而不是单纯地左右。这个功能可以排进我心目中的“Chrome不可理喻的缺失功能”TOP 3。不过自从TMP挂掉我才发现,原来早在1年前左右,有两个和Tab切换相关的选项居然合并了:一个是“是否按照最近浏览的顺序切换”,一个是“切换时是否显示略缩图(而非直接切换)”。如果你想“按最近浏览的顺序切换”,就必须同时“切换时显示略缩图而不是直接切换”。

对于这俩选项的合并,开发者是这么说的

Without previews, switching in recently used order between more than two tabs would be unusable.

这简直笑掉大牙,难不成之前一直这么用的用户都不是正常人了?事实上,如果没有缩略图而直接切换,用户可以在全尺寸的网页中预览(只要按着ctrl不松开),如果不是自己想要的再点击一次tab就是了;结果现在必须要现在那个根本看不清的略缩图里找到自己的tab,完全是可用性的下降。

Pre57可以用TMP单独关闭后者,TMP挂掉了我就不知道怎么办了。

拖拽

我用smartUp Gesture有一段时间了,总体还是不错的,而且还附赠了我原来从来没习惯用过的鼠标手势功能,我现在也偶尔会用手势来完成ctrl+shift+T的功能(但是由于WE的限制,很多页面手势无效[比如空白页],实际用起来并不算完全舒服)。至于拖拽功能,这个插件里有两组拖拽——一个简单一个超级。其实我的需求简单拖拽完全就够,但是他的简单拖拽bug很多,最影响使用的就是有些时候拖拽某些角度时会无效,而同样方向设定在超级拖拽就没问题。另外一个在Chrome发现的问题(估计Firefox也有):如果在一些比较复杂的页面(例如:YouTube带播放列表的播放页面),拖拽会变的奇卡无比,估计是实现方式比较奇怪的原因导致JS负载过重?

xThunder

好像有人在说什么Open with啥的,我没研究还。

结语

那么基本就是这样了。总体而言嘛还是能用的范畴,但是诸多不爽是不可避免的。姑且备份了一份profile,如果实在不行就回滚52ESR先用着再看情况了。另外这里吐槽一下reddit的/r/firefox一片circlejerk、歌舞升平,虽然倒也没啥错,不过实在让人怀疑那里使用扩展数量超过5的power user到底有多少……不过仔细想想之前去问过几个uc的问题,那里大部分连uc是啥都不知道,确实不能指望太多就是了。

迁移至Firefox 57

57终于近在眼前了。9月28日Firefox release通道就要升级到56,作为beta版用户,则近两天应该就有57b的推送。拖了这么久,也是时候整理下自用的传统扩展的情况了。

关于XUL扩展的整体情况,可以参见这个list。可以说比较大型的(样式表,User脚本,广告拦截)且和UI无关的应该都有替代品了。这里主要汇总一下个人用的。

Classic Theme Restorer

很显然不会被移植到57啦。其实CTR的数不胜数的选项中我用的不多,这里记录下自己实际用到的。

标签栏在地址栏下方 – 暂时可以修改userChrome.css(但是这玩意据说也要淘汰):

@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* only needed once */

/* tabs on bottom */
#navigator-toolbox toolbar:not(#nav-bar):not(#toolbar-menubar) {-moz-box-ordinal-group:10}
#TabsToolbar {-moz-box-ordinal-group:1000!important}

更新:我试了下,效果比CTR的实现丑好多,懒得去研究调哪些CSS细节了,直接放弃了tabs on bottom了。

修改回老式搜索框 – 无理。实际上,从之前几个版本就不行了。这里必须发泄一下,这个堪称是Firefox最蠢的改动。之前的搜索框可以很方便地在几个搜索引擎里切换,然后搜索你的关键词。现在呢?必须先输入关键词,再用按钮去选搜搜引擎。缺点在于:

  1. 无法获取非默认引擎的搜索建议;
  2. 无法快速修改默认引擎(唯一的方法:ctrl+箭头一个个选,20+引擎你选去吧),也就是说如果你要连续用非默认引擎搜索多次的话,每次都得去重新找对应引擎的按钮点;
  3. 极其键盘不友好;
  4. 完全无法区分同样icon的不同引擎,例如各种语言版本的维基百科

如果只是技术改进的阵痛也就罢了,关键在于这个东西的引入完全是和雅虎签了引擎协议之后为了强推雅虎搜索,不顾用户体验的阴招,说白了就是出卖了自己的灵魂。其设计的唯一目的就是让用户不能随便地(不进入设置改不了)修改默认引擎,从而保证能stick在Yahoo上。该改动的主持人在Bugzilla各种语焉不详,对于众多抱怨(例如:为什么搜索栏不显示当前引擎图标?)前言不搭后语,甚至遭到众多同样是Mozilla员工的质疑(这个东西从计划到实行只有极短的时间,不符合正常周期,也根本不知道有没有做遥感和UX test)。

因为这个恶心的改动,我几乎把所有的用非默认引擎(例如维基)的操作全部迁徙到了Chrome:Chrome虽然没有搜索栏,但是不知道高到哪里去了:它会自动识别新的搜索引擎,你只需要打对应网址的开头然后tab(例如,英文维基就是en+tab),然后输入关键词就行了。搜索建议什么的全有,流畅至极。所以怎么说Firefox作死呢?当然,Firefox里你也能用给书签加keyword的方式来搞地址栏搜索,但是一,keyword得一一手动设置,二,依然没有搜索建议,和Chrome的比,天上地下。

书签星星恢复到地址栏里,增加RSS按钮 – UI相关,八成无理。更新:我发现原来57默认又把书签星星挪回地址栏了,呵呵。

about:addons显示扩展版本 – 无理——57+应该是不允许修改Fx的内部页面的。

FlagFox

作者号称开发中。暂时替代品:Country Flags & IP Whois 或者 Country Flag +

Gmail™ Notifier (restartless)

改用Chrome也有的Checker Plus for Gmail™,更好用。

Greasemonkey

现在已经有TamperMonkeyViolentmonkey两个用户很多的替代品了,GM自己也在开发WebExt版本。个人还在纠结中,TM在Chrome一直用,感觉UI可以殴打GM;但是毕竟是闭源的,这点VM加分。GM自己的WebExt版怕是等不到…

Image Search Options

图像反向搜索,作者为SauceNAO站长。极少数支持POST反向搜索(可以支持本地图片、有ref限制的网站搜索)的扩展,但是57的API似乎还做不到(同理,Chrome上也没有能比的扩展)。市场里有无数类似的没有一一尝试,这个还行(只支持GET)。

如果这个没有替代品了那绝对是一大损失,这是少数现在Firefox优越于Chrome的地方之一了——在Fx56,我可以直接拖一张本地图(例如从QQ)进Firefox,然后用各种引擎搜索(Chrome自带的图像反向搜索context menu倒是可以搜本地,但是只有Google)。

Image Zoom

另外一个坚守Fx的理由之一,其实这个扩展我大概2、3年前才开始用,但是一下就爱上了。其作用说起来很简单:在任意图片上,按住右键,然后可以用滚轮缩放。另外,可以通过按住右键+点击左键的方式来讲图片放缩为fit to screen。功能虽简单,但是非常实用,尤其是现在许多网站为了省事不用专门的略缩图,很多图片元素其实都是大图,这样可以看得很清楚。

这个扩展虽然有高达十万用户,但是其实作者在13年之后就没有更新过。在5X版本已经开始不太好用,现在我在用的其实是这个Image Zoom (ugly fixes)(虽然叫fix,其实还有点小毛病,比如缩放后mouse up时不能正确地取消右键菜单等。但是勉强能用)。

Fx57之后的替代品有:

Zoom Image:日本人开发的,用户极少,但是这个其实是和之前的Image Zoom最接近的——滚轮的操作完全一致(而且有个选项,可以选择是浮动显示图片还是依然在原有容器内,更方便)。就是还缺少右键+左键fit to screen缩放的功能,希望以后作者能加上。

Image Zoomer:支持右键+左键fit to screen,但是手感很奇怪,另外不支持滚轮,倒是支持按住右键+拖拽的方式,不是特别适应。

Zoom Image To Fit:这个设定也很奇怪了,先右键+左键进入缩放模式,然后可以用滚轮缩放等等。反正用着不舒服。

虽然这仨暂时都不完美,但是至少说明WebExt是可以开发出Image Zoom这样的软件的。There is hope!

Keyword Search

这个扩展的名称起得非常烂,因为完全看不出作用(更糟,甚至误导)。其真实作用是:锁定地址栏为X搜索引擎(例:Google),而不是像Fx默认那样根据搜索栏引擎改变。当然由于上面所提到的,我已经基本不用搜索栏了,但是依然不能否认这扩展的巨大作用。有了这个我可以固定地址栏为Goolge,搜索栏用维基百科什么的。不过由于工作原理所致,地址栏的搜索建议也算是废了(建议依然会出你当前用的搜索引擎的而不是你锁定的)。

暂时没找到替代,感觉也不一定有API。

Pearl Crescent Page Saver screenshot tool

Pre-57最好用的截图软件,但是技术极其原始,甚至不支持e10s(和不重启安装),其实早就该换掉了…Firefox现在自带一个截图工具,非常难用(连自动截图整个网站的功能都暂时没有:本来有后来说是有性能问题暂时阉割了),不过市场有大量WebExt的应该不愁找不到,我暂时还没比较就是了。

RefControl

已经Referer Control替代。功能其实是多一些的,但是这个UI非常拙计和反直觉。

这里多说一句,WebExt的扩展的选项UI大多是类似网页的形式,比起XUL扩展的传统桌面软件UI风格,最大的问题就在于风格不统一,而很多开发者的审美和design经验实在是有点惨不忍睹,所以可以说是群魔乱舞了(Chrome那边也一样),也算是一个笑点。

RightToClick

这个扩展作者居然直接从市场删掉了orz。说白了就是解锁右键菜单,解锁复制,反正就是破网站用JS实现的一堆防复制功能用的。我在Chrome是用Allow Copy这个,蛮好用。

Firefox的WebExt替代方面,市场排名第一的“Enable Right Click and Copy”这个非常辣鸡,每次自动插入JS进网页(而不是点击才使用),导致经常很多网站功能不正常(看评论就知),推荐用这个国人开发的“快乐右键”(Happy Right-Click。唯一的美中不足是图标在地址栏,有点丑且不好定制。顺便一提,我一般测试这种的功能,都是拿某个日文歌词站w(测试的时候注意确实地测试下到底能不能粘贴内容出来;有的网站光解锁select的权限还不行)。

Show Location

国人开发的扩展,更新肯定是没什么希望了(Last Updated: April 25, 2012)。作用就是根据IP显示服务器地址(根据本地的或者离线的纯真数据库)在地址栏,感觉应该WebExt能实现就是了。

Stylish

WebExt之后自然不能修改Fx本身的界面了,那些请移步userChrome.css。扩展本身嘛,作者(就是userstyles.org开发的)一直没回应是否会开发WebExt版本,而且之前Stylish Chrome版被某个用户分析公司收购引发了一些争议,我那边已经换用了一个fork Stylus了。Firefox这边自然也可以用Stylus(虽然UI真的很丑),其他选择有另外一个fork xStyle国产)、Website Theme Manager等。

Tab Mix Plus

另外一个庞大、但是大部分功能要入土的重型扩展——甚至拥有自己的bugzilla ticket

我个人主要用以下几个功能:

  • 强制紧挨当前tab右侧打开所有新tab(包括链接、书签、新建标签页等等):Firefox默认(以及Chrome)是只有当前页面的里的链接会在紧挨着右边打开,其他一律在最后打开。我个人不喜欢这样,鼠标移动太远。
    • 更新:可以用Open Tabs Next to Current,虽然实现很蠢(先开在最后然后再移动,肉眼可以见动画…),但是API限制下只能做到这样了。
  • 保留窗口,即使关闭了所有Tab
    • 更新:Firefox有选项:browser.tabs.closeWindowWithLastTab;false
  • 中键点击Tab栏空白处恢复最后关闭的Tab(默认:新建Tab);
    • 更新:目前没有标签栏事件处理,做不到。
  • 双击Tab栏空白处新建标签页(默认:同Windows默认标题栏,最大化/恢复窗口);
    • 同上:目前没有标签栏事件处理,做不到。
  • UI:将未读标签显示为红色斜体;
  • UI:右侧Tab列表下拉菜单按钮始终显示;
  • UI:控制Tab宽度为100px-250px

目前不知道多少可以用其他扩展或者userChrome.css实现。

uc

就是uc脚本(userChrome.JS)相关。还好我就用一个拖拽的,未来可以用Glitter Drag(国产)替代更新:另外一个国产扩展:smartUp Gesture,还有鼠标手势功能(不如说手势才是主打)。不过作者刚开始移植Fx(之前在Chrome),功能似乎略有残缺。

xThunder

直接调用迅雷下载的工具,比迅雷官方的好用。作者早已跑路不过一直能用。57肯定GG了。

其他

其他的一些曾经用过、但是本来就用得少干脆直接删掉的:

DownThemAll! | Places Maintenance

其他在用的已经是WebExt的在用的扩展一览:

Bookmarks Organizer | EPUBreaderReddit Enhancement SuiteRedirectoruBlock OriginYouku HTML5 PlayerYouTube Plus