discourse/lib/onebox/engine/tiktok_onebox.rb
Natalie Tay a9b1fb9b43
Some checks are pending
Licenses / run (push) Waiting to run
Linting / run (push) Waiting to run
Publish Assets / publish-assets (push) Waiting to run
Tests / core backend (push) Waiting to run
Tests / plugins backend (push) Waiting to run
Tests / core frontend (Chrome) (push) Waiting to run
Tests / plugins frontend (push) Waiting to run
Tests / themes frontend (push) Waiting to run
Tests / core system (push) Waiting to run
Tests / plugins system (push) Waiting to run
Tests / themes system (push) Waiting to run
Tests / core frontend (Firefox ESR) (push) Waiting to run
Tests / core frontend (Firefox Evergreen) (push) Waiting to run
Tests / chat system (push) Waiting to run
Tests / merge (push) Blocked by required conditions
FIX: Add ld+json VideoObject to each lazy video (#34678)
Lazily loaded videos currently won't be picked up by search engines as
they do not contain an iframe or VideoObject.

This commit uses a new API `build_plugin_html
"server:topic-show-crawler-post-end"` to insert populated
[ld+json](https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data#supported-formats)
into the end of each post which has a video.

Results:
-
https://search.google.com/test/rich-results/result?id=vegb8Qkz7HThsMbFaeN2AQ
-
https://search.google.com/test/rich-results/result?id=asumX41RneM2tMstchv45A
- (vimeo)
https://search.google.com/test/rich-results/result?id=EZWOMJCkDqEQIHfOLkSkcw

Note: 

There were originally two ways around this 
- add each VideoObject to the `post.cook` all the time agnostic of
crawler view
- or add them to the `<head>` with appropriate metadata, needing to
duplicate all post meta data within a `isPartOf` attribute.

I chose to create a new api so that we can satisfy both "only add the
meta data in crawler view" and prevent post metadata duplication.
2025-09-03 22:01:14 +08:00

68 lines
1.8 KiB
Ruby

# frozen_string_literal: true
module Onebox
module Engine
class TiktokOnebox
include Engine
include StandardEmbed
matches_domain("tiktok.com", "www.tiktok.com", "m.tiktok.com")
requires_iframe_origins "https://www.tiktok.com"
always_https
def self.matches_path(path)
path.match?(%r{^(/@.+/video/\d+|/v/\d+)(/\w+)?/?$})
end
def self.embed_url(video_id)
"https://www.tiktok.com/embed/v2/#{video_id}"
end
def placeholder_html
<<-HTML
<img
src="#{oembed_data.thumbnail_url}"
title="#{oembed_data.title}"
style="
max-width: #{oembed_data.thumbnail_width / 2}px;
max-height: #{oembed_data.thumbnail_height / 2}px;"
>
HTML
end
def to_html
video_height = oembed_data.thumbnail_height < 1024 ? 998 : oembed_data.thumbnail_height
height = (323.0 / 576) * video_height
<<-HTML
<iframe
class="tiktok-onebox"
src="#{self.class.embed_url(oembed_data.embed_product_id)}"
sandbox="allow-popups allow-popups-to-escape-sandbox allow-scripts allow-top-navigation allow-same-origin"
frameborder="0"
seamless="seamless"
scrolling="no"
style="
min-width: 323px;
height: #{height}px;
border: 4px solid #fff;
border-top: 3px solid #fff;
background-color: #fff;
border-radius: 9px;
"
></iframe>
HTML
end
private
def oembed_data
@oembed_data = get_oembed
end
def get_oembed_url
"https://www.tiktok.com/oembed?url=#{url}"
end
end
end
end