长毛象的引用功能,在小森林和各种魔改都已经实现,虽然只有本站才能看见引用效果。
非官方客户端,例如IceCube也可以引用嘟文,本质上还是复制转发对象的链接罢了。
其实,我觉得这也可以了,毕竟本来长毛象官方就不让带评论转发,“以防对用户进行网暴”。

需求背景

但是,这还是令人有些不爽,能一个键解决的事,为什么还要多复制粘贴一下呢?而且这个纯手工引用的效果,让人一眼看不出我在评什么东西。恰好我的引用需求又很多,因为我关注的都是搬运推友的机器人🥺。
引用这个功能,我还是要加的。毕竟我想“网暴”谁,我直接天天截图,用爬虫拉他的推文就是了。你想用引用功能来限制别人裱人,就跟用宪法里国家主席的十年任期来限制总书记不能连任终身一样🤭所以我认为引用就必须毫无限制地加上!

然后我就参考了小森林的代码,这在他们首页有公布。我研究了一下代码以后发现,要实现引用功能,需要给数据库加一列,这个魔改就很超过了。当时长毛象稳定版还在v4.4.x,已经可以显示外站引用了,但是我们却不能引用别人。
宁与友邦,不与家奴了属于是
打不了洋人,还打不了你么
我给长毛象的GitHub仓库提了issue,要求加一个引用功能,他们回复“在做了”,预计在v4.5.0问世。其实我看见有feature-flag了,只是不知道怎么去除。而且我只是魔改,没打算硬分叉,所以先让官方飞一会儿,下次升级直接跳到main分支。

主站上线新功能

后来,官方主站解禁了引用功能,我用我的小号偷偷地看了一下,发现这不是坑爹么?所有升级前的嘟文,外站(旧版本长毛象和其他Fedi软件)所有的嘟文均“无权引用”!只有本站升级后,用户发帖,且选择你可以引用,你才能使用引用功能。

长毛象客户端的新功能

不仅限制网页端,本来IceCube可以引用的,升级实例以后,该账号也会显示“无权引用”。这不是沪C是什么啊?😅

沪C的梗也算全国闻名了,上海市外环线内,外地牌照可以进,但是上海的沪C不能进

长毛象这样也不算坏事,毕竟只需要轻微魔改一下就可以引用了嘛。以后的刷嘟体验肯定会显著提升的。

魔改过程

要实行起来比较复杂,毕竟从stable-4.4变基或合并到主分支可不是开玩笑的。

试验田的魔改

之前因为某些事,用我闲置的长毛象服务器,升级到了main分支。直接在那个服务器上测试代码修改后的效果,而不会导致我的实例崩坏。
我注释掉了一些代码,发现确实能够有效解除引用的限制,也粗浅地摸清了代码的原理。
缺点就是我之前的解除字数上限、媒体限制、置顶限制、个人资料限制、markdown魔改统统失效了。不过样式还是可以重新安装,元素宽度什么的还是要重新修改了。

合并入主分支

这个操作上次已经有经验,还是把我的custom4.4分支合并到我在main上面新建的魔改分支上。
在此之前,我试过变基,但是处理冲突处理了2个小时也没看到头。所以,还是得使用合并,再全部取消暂存,然后把文件和部分文件改动,一个一个地并到新的里面去,这样还省一点时间。
并完提交一次,再一个个地补充没并进去的魔改。测试我是把git克隆到另一个目录里去,新开一个Vagrant测试环境进行测试的。所有功能都没问题了,再丢弃剩下的所有文件和改动。

长毛象v4.5.x的引用功能代码和分析

关于引用功能的全部代码魔改,都已推送到我的GitHub仓库https://github.com/dongzhimin-xz/mastodon/tree/retoot-with-reply ,趁我还没删掉赶紧fork或克隆到本地吧

解决网页端引用按钮被禁情况

找到前端的转发按钮组件/app/javascript/mastodon/components/status/boost_button_utils.ts,删去如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
diff --git a/app/javascript/mastodon/components/status/boost_button_utils.ts b/app/javascript/mastodon/components/status/boost_button_utils.ts
index 5fc77ed30..ee2b1faf9 100644
--- a/app/javascript/mastodon/components/status/boost_button_utils.ts
+++ b/app/javascript/mastodon/components/status/boost_button_utils.ts
@@ -145,23 +145,5 @@ export function quoteItemState({
iconComponent: FormatQuote,
};

- if (!isPublic && !isMine) {
- iconText.disabled = true;
- iconText.iconComponent = FormatQuoteOff;
- iconText.meta = messages.quote_private;
- } else if (isQuoteAutomaticallyAccepted) {
- iconText.title = messages.quote;
- } else if (isQuoteManuallyAccepted) {
- iconText.title = messages.request_quote;
- iconText.meta = messages.quote_manual_review;
- // We don't show the disabled state when logged out
- } else if (isLoggedIn) {
- iconText.disabled = true;
- iconText.iconComponent = FormatQuoteOff;
- iconText.meta = isQuoteFollowersOnly
- ? messages.quote_followers_only
- : messages.quote_cannot;
- }
-
return iconText;
}

刚才所删的代码,意思是如果符合以下条件:

  • 不是公开嘟文,且不是你发送的
  • 该嘟文没被标为允许你引用(包括所有早两个月的旧版长毛象,还有外站misskey、pleroma、mitra等软件,外站的各种bot,均不允许你引用,虽然原作者并没表示拒绝你转发他/她)

你的引用按钮为灰色禁用状态,且显示“你无权引用”。只要删掉,你就可以引用嘟文,并开始编写你转评了

解决无法发送转评的情况

刚才的代码改完后,你写完转评点击发送,依旧会给你提示不能引用。这说明长毛象官方的代码,把你给五花大绑🥵。接下来继续我们的逃脱表演。
按F12观察发现,这次发送失败,根本没有请求发送给服务端。这说明是因为前端禁止你发送转评。
继续修改前端代码,原理我之前有提到过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
diff --git a/app/javascript/mastodon/actions/compose_typed.ts b/app/javascript/mastodon/actions/compose_typed.ts
index 6b38b25c2..081cd6116 100644
--- a/app/javascript/mastodon/actions/compose_typed.ts
+++ b/app/javascript/mastodon/actions/compose_typed.ts
@@ -170,24 +170,10 @@ export const quoteComposeByStatus = createAppThunk(
dispatch(showAlert({ message: messages.quoteErrorEdit }));
} else if (composeState.get('privacy') === 'direct') {
dispatch(showAlert({ message: messages.quoteErrorPrivateMention }));
- } else if (composeState.get('poll')) {
- dispatch(showAlert({ message: messages.quoteErrorPoll }));
} else if (
- composeState.get('is_uploading') ||
- (mediaAttachments &&
- typeof mediaAttachments !== 'string' &&
- typeof mediaAttachments !== 'number' &&
- typeof mediaAttachments !== 'boolean' &&
- mediaAttachments.size !== 0)
+ composeState.get('is_uploading')
) {
dispatch(showAlert({ message: messages.quoteErrorUpload }));
- } else if (composeState.get('quoted_status_id')) {
- dispatch(showAlert({ message: messages.quoteErrorQuote }));
- } else if (
- status.getIn(['quote_approval', 'current_user']) !== 'automatic' &&
- status.getIn(['quote_approval', 'current_user']) !== 'manual'
- ) {
- dispatch(showAlert({ message: messages.quoteErrorUnauthorized }));
} else if (
status.get('visibility') === 'unlisted' &&
!wasQuietPostHintModalDismissed

以上被删除的代码会让你在如下情况,禁止你发送带引用嘟文:

  1. 对方禁止引用时
  2. 你的嘟文有投票时
  3. 你的嘟文附加了媒体时

其中23是因为长毛象官方的“极简”设计理念而禁止的。

解决发送转评时,遭到后端拒绝的情况

做完以上步骤后,你会发现还是无法转评。这次现象稍微有点变化,调试浏览器发现,前端确实发送了请求,但是后端还是禁止了你的引用。
它根本不接受你的嘟文!
原理我之前也有提到过,你的请求会被mastodon-web.service所运行的puma给接收,经过router,送到controller。
因此,找到判断审核你嘟文是否合法,并且给你返回404的那个代码,将它删掉:

1
2
3
4
5
6
7
8
9
10
11
12
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index fd7757f2e..aa8f4a7ee 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -159,7 +159,6 @@ class Api::V1::StatusesController < Api::BaseController

def set_quoted_status
@quoted_status = Status.find(status_params[:quoted_status_id])&.proper if status_params[:quoted_status_id].present?
- authorize(@quoted_status, :quote?) if @quoted_status.present?
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
# TODO: distinguish between non-existing and non-quotable posts
render json: { error: I18n.t('statuses.errors.quoted_status_not_found') }, status: 404

这样,你的转评嘟文就可以发送了

解决转评发送后,显示“嘟文待发布”的情况

前端和后端的困境解开后,官方的代码依旧在围堵。后端代码还是会随时验证引用是否拥有原作者许可。我能做的,依旧只有不让它验证

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 3e4a71522..ffe6fc3af 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -109,7 +109,7 @@ class PostStatusService < BaseService
status.quote = Quote.create(quoted_status: @quoted_status, status: status)
status.quote.ensure_quoted_access

- status.quote.accept! if @quoted_status.local? && StatusPolicy.new(@status.account, @quoted_status).quote?
+ status.quote.accept!
end

def safeguard_mentions!(status)

外站折中方案

刚才说了,我只能让我实例的后端不验证嘟文是否经过许可,而长毛象官方不仅让长毛象的实例代码分布式验证转发许可,甚至还推动整个Fediverse社区引入这个标准来限制引用功能的使用。
本站引用的嘟文,如果被misskey、pleroma站点看到了,它们才不会管我的引用是否经过原作者的同意,我还是享有人权的。它们会以它们代码的方式来显示我的引用。
即使外站不显示我引用了啥,我还是可以让外站的Fedi友看到我引用了什么东西。运气不好,人家还可以点进原文链接进行品鉴;运气好的话,人家实例直接显示帖文预览。

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/app/lib/text_formatter.rb b/app/lib/text_formatter.rb
index 963cc0d1c..9e79fae17 100644
--- a/app/lib/text_formatter.rb
+++ b/app/lib/text_formatter.rb
@@ -181,7 +181,7 @@ class TextFormatter
return html if url.blank? || html.include?(url)

<<~HTML.squish
- <p class="quote-inline">RE: #{TextFormatter.shortened_link(url)}</p>#{html}
+ <p>RE: #{TextFormatter.shortened_link(url)}</p>#{html}
HTML
end
end

我发出去的转评,它其实是自带原文链接的。只是在长毛象的外站实例,它会隐藏属性有class="quote-inline"的元素。那我只要把自己的国籍丢掉,回国就不怕遭受暴政,还能享受外宾礼遇了🤭。

解决上一节无法生效的bug

将上述代码改动并入我的魔改分支后,会发现不显示我引用的原文链接了。这是因为我原先抄glitch代码时,写死了类型,也没魔改数据库,因此全部走的是/app/lib/advanced_text_formatter.rb(我的魔改日记也没有说明这个原理),所以官方代码改的肯定还不够,参考glitch最新版的魔改,进行代码修改:

1
2
3
4
5
6
7
8
9
10
11
12
diff --git a/app/lib/advanced_text_formatter.rb b/app/lib/advanced_text_formatter.rb
index 703b44437..fc67024fb 100644
--- a/app/lib/advanced_text_formatter.rb
+++ b/app/lib/advanced_text_formatter.rb
@@ -69,6 +69,8 @@ class AdvancedTextFormatter < TextFormatter
end
end

+ html = add_quote_fallback(html) if options[:quoted_status].present?
+
html.html_safe # rubocop:disable Rails/OutputSafety
end

解决部分外站实例导致的“嘟文已删除”问题

这个问题主要出现在长毛象v4.4.x的旧版本,和新版本4.5。更旧版本的外站长毛象则不存在这个问题。
原因是上述实例发出请求禁止你引用。我也不废话了,不费尽心思过滤外站的拒绝引用请求,直接注释掉响应请求的吊销代码就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/app/models/quote.rb b/app/models/quote.rb
index e81d42708..22f18a693 100644
--- a/app/models/quote.rb
+++ b/app/models/quote.rb
@@ -51,7 +51,7 @@ class Quote < ApplicationRecord

def reject!
if accepted?
- update!(state: :revoked)
+# update!(state: :revoked)
elsif !revoked?
update!(state: :rejected)
end

这样,外站被引用的长毛象用户,点击了删除本站某用户的引用,也不会影响到本站了。其他长毛象实例,包括v4.4.x还是受影响的,除非他们也废了象的武功。

解决长毛象(手机)客户端无法引用大部分嘟文的问题

刚才的一系列操作,可以让本站用户在网页端尽情转评别人的嘟文了,但是手机客户端仍然受限制,可能使用了其他前端也会有前端上的限制。
还有个很神奇的现象,当我登录旧版长毛象(v4.3.x)实例上的账号时,我的IceCube可以引用,但是新版实例的账号就无法引用别人的嘟文了。真的是v4.5的用户连畜生都不如😅
v4.5用户与狗不得入内

毛象(前朝公民除外)与狗不得入内

本节的魔改,不能让用户在别人的前端、官方客户端、第三方客户端直接引用v4.5用户禁止引用的嘟文。
原理很简单:把后端推到客户端的外站非长毛象嘟文,全都改成“自动批准转发”就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/app/models/concerns/status/interaction_policy_concern.rb b/app/models/concerns/status/interaction_policy_concern.rb
index da132a450..7f369701b 100644
--- a/app/models/concerns/status/interaction_policy_concern.rb
+++ b/app/models/concerns/status/interaction_policy_concern.rb
@@ -65,7 +65,7 @@ module Status::InteractionPolicyConcern

return :unknown if (automatic_policy | manual_policy).anybits?(QUOTE_APPROVAL_POLICY_FLAGS[:unsupported_policy])

- :denied
+ :automatic
end

def downgrade_quote_policy

后记

我觉得我这一篇博客对于毛象的魔改也没太大贡献,但是最值得肯定的一点就在于给毛象用户找回一点尊严。

这就让人联想到,最近武统台湾呼声很高,有网友就给出了非常中肯的回复

正所谓赢了有台湾岛,输了有新中国,这是真正的双赢——这下不得不支持了。

中国人就像小黄人找老大一样,到处拜青天大老爷。在幻想中,拜包青天。在缺粮食的时候,拜大贤良师,给自己喂粥。现在中国人缺的是尊严,没有尊严(例如把你打得一辈子下不了床,你虽然没有失去生命,但是这叫失去尊严,跟死了没两样)也跟活活饿死一样没有区别。平时加班到深夜,回家路上看到一堆我国“尊贵的客人”在地铁上拉屎撒尿没人管,你拿出水喝一口,警察马上就来对你罚款,回头再叫那几位贵宾给点面子,直接放走。第二天上班,早高峰,你好不容易找到座位,坐上去睡一会儿,警察上来一巴掌把你打醒,叫你给边上的外国人让座,“要发扬待客之道”。你说你站不起来,晶哥就连拖带拽地拉你去局子里坐坐。老外说:“别打了,多难看啊,我前两天刚入籍了台湾,不是客人了😀”晶哥说:“台湾?台湾也事外宾!”于是把你逮捕了。这时,你是否也想要一个能给你施舍点尊严的青天大老爷或者亭长呢?🙂

话说回来,把这段代码抄去,你这个站长也是得到了自己的赛博《太平要术》(东汉末年的启示录)😈