缩略图生成与 Markdown 渲染问题

你好,

自 Discourse 2.5.0 最新版本发布以来,我在缩略图生成方面遇到了问题。
看起来缩略图现在由核心功能生成,这导致所有缩略图都被清空了。
我尝试了各种操作来恢复它们,下面我将解释在哪些情况下这些操作无效。

注意:这次变更可能有很好的理由,但引入突然的行为变更从而破坏现有功能,且没有提供升级指南或 opting-in 机制,这确实令人难以接受。请考虑这一点。:confounded:

上下文

  • Discourse 2.5.0 beta4 (faeb5793ba)
  • Topic List Preview 插件 4.4.0
  • WP-Discourse 帖子以完整 HTML 形式发布在 Discourse 主题中(第一条消息)。

关于帖子内容,这是一个示例(已为您格式化):

内容

为方便起见,以下是图片的 HTML 代码:

<img
        width="150"
        height="84"
        src="https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-150x84.jpg"
        class="attachment-thumbnail size-thumbnail"
        alt=""
        srcset="
            https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-150x84.jpg     150w,
            https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-300x169.jpg    300w,
            https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-1200x675.jpg  1200w,
            https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-1536x864.jpg  1536w,
            https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-2048x1152.jpg 2048w,
            https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-788x443.jpg    788w,
            https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית.jpg           1280w
        "
        sizes="(max-width: 150px) 100vw, 150px"
    />
<div data-wp>
    <a
        href="https://www.banggood.com/Xiaomi-Redmi-Router-AC2100-2033Mbps-2_4G-5G-Dual-Band-Wireless-Router-6High-Gain-Antennas-128MB-OpenWRT-WiFi-Router-p-1614038.html"
        target="_blank"
        ><img src="https://zuzu.deals/wp-content/uploads/2020/01/5e3128b4e5da7-150x150.jpg"/>
    </a>
    <div>
        <div data-buy>
            <a
                href="https://www.banggood.com/Xiaomi-Redmi-Router-AC2100-2033Mbps-2_4G-5G-Dual-Band-Wireless-Router-6High-Gain-Antennas-128MB-OpenWRT-WiFi-Router-p-1614038.html"
                target="_blank">קנייה
            </a>
            <span data-clipboard-text="BG38b2ac" data-coupon>BG38b2ac</span><i></i>
        </div>
        <div data-price>$43.99</div>
    </div>
</div>
<hr />
<p>
    <small>
        &nbsp;פורסם ב:&nbsp;<a href="https://zuzu.deals/%d7%a7%d7%95%d7%a4%d7%95%d7%9f-%d7%91%d7%9c%d7%a2%d7%93%d7%99-%d7%a8%d7%90%d7%95%d7%98%d7%a8-%d7%97%d7%96%d7%a7-%d7%95%d7%97%d7%93%d7%a9-%d7%a9%d7%9c-%d7%a9%d7%99%d7%90%d7%95%d7%9e%d7%99-xiaomi-re-2/"></a>
    </small>
</p>
<br />
<p>נעים להכיר!</p>

在 Discourse 更新之前

TLP 在我们的外部图片上一直工作正常,无论是在创建主题还是编辑主题时。
然而,由于 Markdown 问题,我们禁用了下载远程图片到本地选项。

Markdown 渲染问题

这不是主要问题,但在 Discourse 升级后仍然发生,以下是解释。
当 Discourse 下载并用其 Markdown 语法替换图片 HTML 时——在我们的上下文中,结果如下:

[...]<a href="<link_here>" target="_blank">![|150x150](upload://l0iarnA6SPVAyJN5l7pnQxZnPvE.jpeg)</a>[...]

Discourse 无法渲染该图片

图片

image

要修复此问题,您需要在上方至少添加一个空行:

[...]<a href="<link_here>" target="_blank">

![|150x150](upload://l0iarnA6SPVAyJN5l7pnQxZnPvE.jpeg)</a>[...]
图片

能否允许渲染被 HTML 包围的 Markdown 图片呢?

在 Discourse 更新之后

设置

据此,有人建议我重新烘焙所有帖子以下载图片。问题就在这里变得奇怪了。

  1. rake posts:rebake 效果不大(至少在主题的第一条消息上如此,但它确实触发了大量 PullHotlinkedImages
    1.1. 查看一些主题后,我认为带有 classsrcset 属性的图片 HTML 是原因,所以我尝试用以下代码规范化所有图片(我不懂 Ruby)—— 这对某些主题有所帮助
    1.2. 然而,由于 Markdown 问题,我不得不添加换行符来修复。—— 至少对于这些主题,缩略图可以正常工作了
代码
Post.where(post_number: 1)
    .where("raw LIKE '%<img%/>%'")
    .each 
        do |post|
            post.raw.gsub!(/<img[^>]+(src="[^"]+")[^>]+\/>/, "<img \\1 />")
            post.save!(validate: true)
            post.rebake!  
        end

Post
  .where(post_number: 1)
  .where("raw LIKE '%upload://%'").each 
     do |post|  
       post.raw.gsub!(/(!\[.*upload:\/\/.*\))/, "\n\n\\1") 
       post.save!(validate: false); 
       post.rebake! 
     end
  1. 手动编辑(不更改内容,仅保存)被忽略的主题通常有效。图片会被下载。
    2.1. 有些主题即使编辑后仍被忽略。我可以看到 PullHotlinkedImages 被触发,但没有下载任何图片。(例如使用此 HTML <img src="https://zuzu.reviews/wp-content/uploads/2020/05/HiZERO-VS-BISSEL-VS-שואב-אלחוטי-VS-שואב-רובוטי-VS-מגב-ודלי-VS-מטאטא-VS-ספונגה-חשמלית-150x84.jpg" />链接
  2. 在规范化之后,看到编辑可以帮助下载图片,我尝试多次运行 rake posts:rebake —— 没有效果
  3. 然后我尝试使用 Rails 控制台,类似于上面的代码,但使用特定主题 ID,并且仅执行 post.rebake! —— 没有效果
  4. 并非主题中的所有图片都能被下载。
  5. @Canapin 指向 Download remote images from older posts? - #3 by vinothkannans 不幸的是没有帮助

有些图片能工作,有些不能,这简直令人疯狂。我认为这不是标准问题。图片设置很高。我真的不明白背后的逻辑是什么,这看起来很随机。

目前,我们仍然有很多缺失的缩略图。可能大多数可以通过手动编辑/保存来修复,但这不可行。我正在为一个客户做这件事,而且我已经浪费了很多时间试图解决这个问题。

我不介意使用上传图片作为缩略图,但是:

  • 您能告诉我图片无法下载是否有特定原因吗?有哪些设置可以帮助?我们需要什么?如何调试?
  • 是否有一种方法可以通过控制台强制下载它们,类似于编辑/保存?
  • 能否允许被 HTML 包围的 Markdown 图片渲染?

希望我对问题的描述足够准确。

提前感谢任何帮助和解决方案。

2 个赞

你好 @Arkshine,很遗憾听到你遇到了问题。很抱歉,我们无法保证与所有第三方插件的兼容性,尤其是当它们覆盖了超出我们插件 API 范围的核心行为时。未来,TLP 应该能够减少所使用的核心覆盖数量,希望稳定性会因此得到改善。

请注意,我们现在还提供了 官方解决方案 来显示缩略图,该方案完全使用我们支持的插件 API 实现。

你说得对,核心缩略图仅适用于本地图片。最终,TLP 也会拉取图片并将其本地存储,因此现在的区别在于,我们使用 pull_hotlinked_images 任务以一致的方式完成所有操作。

听起来我们这里有几个问题需要解决。我认为最好将它们分开处理,以免遗漏任何内容。阅读你的帖子后,我看到了两点:

拉取远程图片不应导致无效的 HTML/Markdown,因此我们将尝试修复此问题。请创建一个 bug 主题并提及我,我们会着手调查。

同样,特殊字符不应在此处破坏图片。请再创建一个 bug 主题,我们会进行查看。

4 个赞

感谢回复,@david

关于带有特殊字符的 Markdown 链接,没问题。谢谢。


不过,我最终的主要问题仍然是如何让 Discourse 强制下载图片。Markdown 的问题可以通过控制台解决,而且并非所有链接都包含特殊字符。我们仍然有很多主题没有缩略图。这正是我寻求帮助的地方

例如,这个链接就不包含特殊字符。除非我点击 保存编辑,否则图片既不会通过控制台重新烘焙下载,也不会通过 重建 HTML 链接下载。

是否有某些 Rails 命令或其他方法可以强制 Discourse 像执行 保存编辑 那样下载图片?


我实际上已经尝试过使用该组件,但效果不佳。不过,一旦缩略图问题得到解决,我会再试一次。

这是联盟营销网站吗?

这很奇怪。我有一个想法——这些帖子是由系统用户创建的吗?还是由 Discobot 创建的?

大多数是普通管理员用户。这些主题是通过 WP Discourse 的 API 创建的。

例如这个:

@Arkshine 那里原本应该有个链接吗?

抱歉,我在测试时用一个例子进行处理,但不小心按到了按钮。

话说回来,我开始执行这段代码,看看是否会有帮助(如果看起来刺眼,请见谅!)

Post
  .joins(:topic)
  .where(post_number: 1)
  .where('topics.visible = true')
  .where('topics.deleted_at IS NULL')
  .each do |post| 
     post.baked_version = nil
     post.save!(validate: false)
     post.rebake!
   end

这花了一些时间。我注意到有很多 Jobs::PullHotlinkedImages 任务在运行。
但看起来并没有太大帮助。

如果你查看某个特定主题,例如这个 主题

从控制台可以看到,它触发了 Jobs::ProcessPost,但没有触发 Jobs::PullHotlinkedImages

[106] pry(main)> Post.update_all(baked_version: nil)
=> 38808

[107] pry(main)> Post.where(post_number: 1, topic_id: 64215).each do |post| post.rebake!; end
=> [#<Post:0x0000557fe01f2fd8
  id: 79717,
  user_id: 3,
  topic_id: 64215,
  post_number: 1,
  raw:
   "<div data-wp><a href=\"https://www.mooki.co.il/gaming/hbilvt-giiming-mwtlmvt/mvwb-giiming-khvl-sparkfox-wvlhn-giiming-mqcvei-lumi-whvr-2\" target=\"_blank\"><img src=\"https://zuzu.deals/wp-content/uploads/2020/05/5ebcf97155cd2-150x150.png\" /></a><div><div data-buy><a href=\"https://www.mooki.co.il/gaming/hbilvt-giiming-mwtlmvt/mvwb-giiming-khvl-sparkfox-wvlhn-giiming-mqcvei-lumi-whvr-2\" target=\"_blank\">קנייה</a><span data-clipboard-text=\"GLA679\" data-coupon>GLA679</span><i></i></div><div data-price>₪679 <span data-old-price>₪1378</span></div></div></div><hr /><p><small>&nbsp;פורסם ב:&nbsp;<a href=\"https://zuzu.deals/%d7%91%d7%9c%d7%a2%d7%93%d7%99-%d7%95%d7%91%d7%9e%d7%97%d7%99%d7%a8-%d7%97%d7%98%d7%99%d7%a4%d7%94-%d7%9e%d7%95%d7%a9%d7%91-%d7%92%d7%99%d7%99%d7%9e%d7%99%d7%a0%d7%92-%d7%90%d7%93%d7%95%d7%9d-spark/\"></a></small></p><br><p><img src=\"https://www.mooki.co.il/pub/media/catalog/product/cache/0f831c1845fc143d00d6d1ebc49f446a/_/s/_sparkfox_k1_5_.png\" /></p>\n<p style=\"text-align: center;\">בין אם אתם גיימרים ובין אם אתם פשוט עובדים ויושבים כל היום והגב כבר זועק לכיסא טוב יותר, הנה לכם עוד מבצע בלעדי במחיר חטיפה!<br />\nכיסא גיימינג מפנק, אוזניות גיימינג ומשלוח מהיר בחינם, עם אחריות יבואן רשמי &#8211; רק ב679₪!!!</p>\n<p style=\"text-align: center;\">השתמשו בקופה בקופון הבלעדי &#8211; <strong>GLA679</strong></p>\n<div> <img src=\"https://zuzu.deals/wp-content/uploads/2020/05/90902-801-09_2_1.jpg\" /></div>\n<div>\n<h3 style=\"text-align: center;\">מושב גיימינג מקצועי SPARKFOX GC60P</h3>\n</div>\n<div>מושב גיימינג בעל עיצוב מיוחד למשחקי מחשב לנוחות מקסימאלית למשתמש</div>\n<div>\n<ul>\n<li>מושב בעל משענת גב גבוהה</li>\n<li>נוחות המקסימאלית למשך זמן משחק ארוך</li>\n<li>זוג כריות לתמיכה בצוואר ובגב התחתון</li>\n<li>סוג חומר: ספוג יצוק</li>\n<li>סוג מסגרת: מתכת</li>\n<li>חומר: עור עם סיבי פחם</li>\n<li>משענות ידיים: מתכווננות מעלה / מטה</li>\n<li>סוג מנגנון: פרפר</li>\n<li>סוג הרמה: הידראולית Class4</li>\n<li>טווח משענת גב: 90°-180°</li>\n<li>סוג בסיס: ניילון</li>\n<li>חומר גלגל: ניילון</li>\n<li>יכולת נשיאה: עד 150 ק”ג</li>\n<li>אחריות: שנה</li>\n</ul>\n<div><strong>מידות</strong></div>\n<div>\n<ul>\n<li>רוחב: 67 ס&quot;מ</li>\n<li>עומק: 67 ס&quot;מ</li>\n<li>גובה משתנה: 124-132 ס&quot;מ</li>\n</ul>\n<h3></h3>\n<p><img src=\"https://zuzu.deals/wp-content/uploads/2020/05/90902-802-08_3_1.jpg\" /></p>\n<h3 style=\"text-align: center;\">אוזניות גיימינג SPARKFOX K1</h3>\n<div>אוזניות גיימינג בעיצוב מיוחד לנוחות מקסימלית לשמע ודיבור וביטול רעשי רקע</div>\n<div>\n<ul>\n<li>ניתנות לשימוש ברוב הקונסולות הקיימות בשוק</li>\n<li>שמע וניהול שיחות בטלפונים ובמחשבים ניידים</li>\n<li>ווסת עוצמת השמע הינו בכבל של האוזנייה- לגישה נוחה</li>\n<li>שמע מעולה ממנהלי התקנים גדולים של 50 מ&quot;מ</li>\n<li>בקרי עוצמת הקול וההשתקה</li>\n<li>כוסות אוזניים מרופדות גדולות לנוחות מרבית</li>\n<li>קשת האוזנייה מתכווננת להתאמה מושלמת לראשכם</li>\n<li>מתחבר ישירות ליציאת בקרי 3.5 מ&quot;מ</li>\n</ul>\n</div>\n<div>מצורף מתאם מיוחד לחיבור האוזניות למחשב נייח ע&quot;י מפצל 3.5 מ&quot;מ ל 2 יציאות 3.5 מ&quot;מ</div>\n</div>\n</div>\n<p>&nbsp;</p>\n<div data-custom-html=\"\"></div>",
  cooked:
   "<div data-wp=\"\">\n<a href=\"https://www.mooki.co.il/gaming/hbilvt-giiming-mwtlmvt/mvwb-giiming-khvl-sparkfox-wvlhn-giiming-mqcvei-lumi-whvr-2\" target=\"_blank\"><img src=\"https://zuzu.deals/wp-content/uploads/2020/05/5ebcf97155cd2-150x150.png\"></a><div>\n<div data-buy=\"\">\n<a href=\"https://www.mooki.co.il/gaming/hbilvt-giiming-mwtlmvt/mvwb-giiming-khvl-sparkfox-wvlhn-giiming-mqcvei-lumi-whvr-2\" target=\"_blank\">קנייה</a><span data-clipboard-text=\"GLA679\" data-coupon=\"\">GLA679</span><i></i>\n</div>\n<div data-price=\"\">₪679 <span data-old-price=\"\">₪1378</span>\n</div>\n</div>\n</div><hr><p><small> 发布于:<a href=\"https://zuzu.deals/%d7%91%d7%9c%d7%a2%d7%93%d7%99-%d7%95%d7%91%d7%9e%d7%97%d7%99%d7%a8-%d7%97%d7%98%d7%99%d7%a4%d7%94-%d7%9e%d7%95%d7%a9%d7%91-%d7%92%d7%99%d7%99%d7%9e%d7%99%d7%a0%d7%92-%d7%90%d7%93%d7%95%d7%9d-spark/\"></a></small></p><br><p><img src=\"https://www.mooki.co.il/pub/media/catalog/product/cache/0f831c1845fc143d00d6d1ebc49f446a/_/s/_sparkfox_k1_5_.png\"></p>\n<p>无论你们是游戏玩家,还是整天坐着工作、背部已经发出需要更好椅子的信号,这里还有一个独家优惠,价格超值!<br>\n豪华游戏椅、游戏耳机,并附赠免费快速配送,享受官方进口商保修 – 仅需 679₪!!!</p>\n<p>请在结账时使用独家优惠券 – <strong>GLA679</strong></p>\n<div> <img src=\"https://zuzu.deals/wp-content/uploads/2020/05/90902-801-09_2_1.jpg\">\n</div>\n<div>\n<h3>专业游戏座椅 SPARKFOX GC60P</h3>\n</div>\n<div>专为电脑游戏设计的游戏座椅,为用户提供最大舒适度</div>\n<div>\n<ul>\n<li>高靠背座椅</li>\n<li>长时间游戏时的最大舒适度</li>\n<li>颈部和腰部支撑枕一对</li>\n<li>材质类型:模压泡沫</li>\n<li>框架类型:金属</li>\n<li>材质:带碳纤维的人造革</li>\n<li>扶手:可上下调节</li>\n<li>机构类型:蝴蝶式</li>\n<li>升降类型:Class4 液压</li>\n<li>靠背调节范围:90°-180°</li>\n<li>底座类型:尼龙</li>\n<li>轮子材质:尼龙</li>\n<li>承重能力:最高 150 公斤</li>\n<li>保修期:一年</li>\n</ul>\n<div><strong>尺寸</strong></div>\n<div>\n<ul>\n<li>宽度:67 厘米</li>\n<li>深度:67 厘米</li>\n<li>可调高度:124-132 厘米</li>\n</ul>\n<h3></h3>\n<p><img src=\"https://zuzu.deals/wp-content/uploads/2020/05/90902-802-08_3_1.jpg\"></p>\n<h3>游戏耳机 SPARKFOX K1</h3>\n<div>专为舒适听音和通话设计,具备背景噪音消除功能的游戏耳机</div>\n<div>\n<ul>\n<li>适用于市面上大多数游戏主机</li>\n<li>支持电话和笔记本电脑的音频和通话管理</li>\n<li>音量调节器位于耳机线上,方便操作</li>\n<li>配备 50 毫米大驱动单元,提供卓越音质</li>\n<li>具备音量和静音控制</li>\n<li>大号软垫耳罩,提供极致舒适感</li>\n<li>可调节头带,完美贴合您的头部</li>\n<li>直接连接 3.5 毫米控制器接口</li>\n</ul>\n</div>\n<div>附带专用适配器,通过 3.5 毫米一分二分线器将耳机连接到台式机,提供两个 3.5 毫米接口</div>\n</div>\n</div>\n<p> </p>\n<div data-custom-html=\"\"></div>",
  created_at: Thu, 14 May 2020 07:55:31 UTC +00:00,
  updated_at: Tue, 26 May 2020 14:56:16 UTC +00:00,
  reply_to_post_number: nil,
  reply_count: 0,
  quote_count: 0,
  deleted_at: nil,
  off_topic_count: 0,
  like_count: 0,
  incoming_link_count: 2,
  bookmark_count: 0,
  score: 10.8,
  reads: 4,
  post_type: 1,
  sort_order: 1,
  last_editor_id: -1,
  hidden: false,
  hidden_reason_id: nil,
  notify_moderators_count: 0,
  spam_count: 0,
  illegal_count: 0,
  inappropriate_count: 0,
  last_version_at: Thu, 14 May 2020 09:19:26 UTC +00:00,
  user_deleted: false,
  reply_to_user_id: nil,
  percent_rank: 0.0,
  notify_user_count: 0,
  like_score: 0,
  deleted_by_id: nil,
  edit_reason: nil,
  word_count: 939,
  version: 3,
  cook_method: 1,
  wiki: false,
  baked_at: Tue, 26 May 2020 16:59:49 UTC +00:00,
  baked_version: 2,
  hidden_at: nil,
  self_edits: 2,
  reply_quoted: false,
  via_email: false,
  raw_email: nil,
  public_version: 3,
  action_code: nil,
  image_url: "https://zuzu.deals/wp-content/uploads/2020/05/5ebcf97155cd2-150x150.png",
  locked_by_id: nil,
  image_upload_id: nil>]

如果我从编辑器中点击“保存编辑”:

我能看到良好的显示效果 image

然后我可以看到图片已被下载:

啊,我明白了。这里的问题在于

因为在调度拉取外链图片任务之前,我们有这样的逻辑:

该逻辑旨在避免无限循环地调度 pull_hotlinked_image 任务。但也许我们需要改进这一逻辑。你能检查一下其中某篇帖子的修订历史,看看它为何最后是由系统编辑的吗?

2 个赞

关于这个主题:

  1. image
  2. image (类别变更)
  3. image (仅我点击了“保存编辑”)
  4. image (系统用 Markdown 替换了图片)

所以,我想这是否是因为类别变更导致的?

1 个赞

是的,这就能解释原因了!作为临时解决方案,您可以通过以下方式手动运行拉取热链接图片的任务:

Jobs.enqueue_in(10, :pull_hotlinked_images, post_id: post.id)

不过我们需要一个更好的解决方案。我会将其加入我的待办事项列表。

5 个赞

太棒了,让我试试!

编辑:

确认一下,该命令非常有效。现在大部分图片都已恢复。再次感谢!

仍有一些边缘情况未处理,例如包含特殊字符的图片,或者被标记为损坏但实际上正常的图片主题(重建 HTML 可修复它们,然后保存编辑即可下载)。如果 #9890 被合并,并且对 Markdown 进行修复,那么很可能就能解决所有问题。

2 个赞

我刚合并了这个针对系统用户编辑的修复:

我认为其他问题都已拆分到独立话题中,但如果我们遗漏了什么,请随时@Arkshine 创建新话题。

3 个赞

顺便一提,我刚刚移除了这个设置。我们在拉取热链接图片时不再检查帖子年龄。

cc @merefield

6 个赞

此主题已在 28 小时后自动关闭。不再允许新回复。