phpbb-extensions / mediaembed

A phpBB extension to enable embedded rich media content from other sites in posts
https://www.phpbb.com/customise/db/extension/mediaembed/
GNU General Public License v2.0
16 stars 10 forks source link

Add support for Bluesky #106

Open rxu opened 3 hours ago

rxu commented 3 hours ago

Add Bluesky to keep in sync with the latest text-formatter code. Possible yaml:

name: Bluesky
host: bsky.app
homepage: https://bsky.app/
example: https://bsky.app/profile/jamesgunn.bsky.social/post/3l6kscjixz22q
extract: "!bsky\\.app/profile/(?'name'[A-Za-z0-9.]+)/post/(?'id'\\w+)!"
oembed:
    endpoint: https://embed.bsky.app/oembed
    scheme: [https://bsky.app/profile/{@name}/post/{@id](https://bsky.app/profile/%7B@name%7D/post/%7B@id)}
scrape:
    - extract: "!\"did\":\\s*\"did:(?'did'[a-zA-Z0-9._:%-]+)\"!"
    - match: "//"
    - url: https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor={@name}
iframe:
    width: "550"
    height: "350"
    src: [https://embed.bsky.app/embed/did:{@did}/app.bsky.feed.post/{@id](https://embed.bsky.app/embed/did:%7B@did%7D/app.bsky.feed.post/%7B@id)}

Or alternatively, exported from the latest text-formatter:

attributes:
  embedder:
    filterChain:
      - "#regexp(/^(?:[-\\w]*\\.)*bsky\\.app$/)"
    required: 1
  url:
    filterChain:
      - urldecode
      - "#regexp(/^at:\\/\\/[.:\\w]+\\/[.\\w]+\\/\\w+$/)"
    required: 1
example:
  - "https://bsky.app/profile/bsky.app/post/3kkrqzuydho2v"
  - "https://bsky.app/profile/bnewbold.net/post/3kxjq2auebs2f"
extract:
  - "#https://(?'embedder'[.\\w]+)/oembed.*?url=(?'url'[\\w%.]+)#"
helper: "s9e\\TextFormatter\\Plugins\\MediaEmbed\\Configurator\\SiteHelpers\\BlueskyHelper"
homepage: "https://bsky.app/"
host:
  - "bsky.app"
iframe:
  data-s9e-livepreview-ignore-attrs: style
  height: 600
  onload: "let c=new MessageChannel;c.port1.onmessage=e=>this.style.height=e.data+'px';this.contentWindow.postMessage('s9e:init','*',[c.port2])"
  src: "https://s9e.github.io/iframe/2/bluesky.min.html#<xsl:value-of select=\"@url\"/>#<xsl:value-of select=\"@embedder\"/>"
  width: 600
name: "Bluesky"
scrape:
  - extract:
      - "#https://(?'embedder'[.\\w]+)/oembed.*?url=(?'url'[\\w%.]+)#"
    match:
      - "#/profile/[^/]+/post/.#"
source: "https://embed.bsky.app/"
tags:
  - social
rxu commented 3 hours ago

Both don't work. The latter produces error like Fatal error: Uncaught RuntimeException: Regexp filter is missing a 'regexp' value in ....

Adding this code to the listener allows to go beyond the error

            if ($siteId == 'bluesky')
            {
                $hosts = array_keys(
                    (array) ($event['configurator']->registeredVars['MediaEmbed.hosts'] ?? []),
                    $siteId,
                    true
                );
                $event['configurator']->tags[$siteId]->attributes['embedder']->filterChain[0]->setRegexp(
                    '/^(?:[-\w]*\.)*' . $this->builder->build($hosts) . '$/'
                );
                $event['configurator']->tags[$siteId]->attributes['embedder']->required = 1;
                $event['configurator']->tags[$siteId]->attributes['url']->filterChain[0] = 'urldecode';
                $event['configurator']->tags[$siteId]->attributes['url']->filterChain[1]->setRegexp(
                    '/^at:\\/\\/[.:\\w]+\\/[.\\w]+\\/\\w+' . $this->builder->build($hosts) . '$/'
                );
                $event['configurator']->tags[$siteId]->attributes['url']->required = 1;
            }

But then another one: Fatal error: Uncaught ArgumentCountError: Too few arguments to function s9e\TextFormatter\Parser\AttributeFilters\RegexpFilter::filter(), 1 passed and exactly 2 expected

JoshyPHP commented 3 hours ago

Yeah, it seems that version doesn't support custom regexps in site definitions. You could set the regexp manually after adding the site, or just remove it altogether since the library doesn't consider it unsafe.

$configurator = new s9e\TextFormatter\Configurator;

$siteConfig = json_decode(<<<'JSON'
    {
        "attributes":{
            "embedder":{
                "filterChain":[
                ],
                "required":true
            },
            "url":{
                "filterChain":[
                    "urldecode"
                ],
                "required":true
            }
        },
        "example":[
            "https:\/\/bsky.app\/profile\/bsky.app\/post\/3kkrqzuydho2v",
            "https:\/\/bsky.app\/profile\/jamesgunn.bsky.social\/post\/3l6kscjixz22q"
        ],
        "extract":[
            "#https:\/\/(?'embedder'[.\\w]+)\/oembed.*?url=(?'url'[\\w%.]+)#"
        ],
        "helper":"s9e\\TextFormatter\\Plugins\\MediaEmbed\\Configurator\\SiteHelpers\\BlueskyHelper",
        "homepage":"https:\/\/bsky.app\/",
        "host":[
            "bsky.app"
        ],
        "iframe":{
            "data-s9e-livepreview-ignore-attrs":"style",
            "height":600,
            "onload":"let c=new MessageChannel;c.port1.onmessage=e=>this.style.height=e.data+'px';this.contentWindow.postMessage('s9e:init','*',[c.port2])",
            "src":"https:\/\/s9e.github.io\/iframe\/2\/bluesky.min.html#<xsl:value-of select=\"@url\"\/>#<xsl:value-of select=\"@embedder\"\/>",
            "width":600
        },
        "name":"Bluesky",
        "scrape":[
            {
                "extract":[
                    "#https:\/\/(?'embedder'[.\\w]+)\/oembed.*?url=(?'url'[\\w%.]+)#"
                ],
                "match":[
                    "#\/profile\/[^\/]+\/post\/.#"
                ]
            }
        ],
        "source":"https:\/\/embed.bsky.app\/",
        "tags":[
            "social"
        ]
    }
JSON, true);

$configurator->MediaEmbed->add('bluesky', $siteConfig);

extract($configurator->finalize());

$text = 'https://bsky.app/profile/bsky.app/post/3kkrqzuydho2v';
$xml  = $parser->parse($text);
$html = $renderer->render($xml);

die("$html\n");
rxu commented 2 hours ago

Thanks for the hint. With this code

attributes:
    embedder:
        required: true
    url:
        required: true
example:
    - "https://bsky.app/profile/bsky.app/post/3kkrqzuydho2v"
    - "https://bsky.app/profile/bnewbold.net/post/3kxjq2auebs2f"
extract: "#https://(?'embedder'[.\\w]+)/oembed.*?url=(?'url'[\\w%.]+)#"
homepage: "https://bsky.app/"
host: "bsky.app"
iframe:
    data-s9e-livepreview-ignore-attrs: style
    height: 600
    onload: "let c=new MessageChannel;c.port1.onmessage=e=>this.style.height=e.data+'px';this.contentWindow.postMessage('s9e:init','*',[c.port2])"
    src: "https://s9e.github.io/iframe/2/bluesky.min.html#<xsl:value-of select=\"@url\"/>#<xsl:value-of select=\"@embedder\"/>"
    width: 600
name: "Bluesky"
scrape:
    extract: "#https://(?'embedder'[.\\w]+)/oembed.*?url=(?'url'[\\w%.]+)#"
    match: "#/profile/[^/]+/post/.#"
source: "https://embed.bsky.app/"
tags:
    - social

there're no errors, but example URLs don't load (loads ok directly in a browser). image

The relevant source code is (looks like the iframe's body is empty):

<div class="content"><iframe data-s9e-mediaembed="bluesky" allowfullscreen="" loading="lazy" onload="let c=new MessageChannel;c.port1.onmessage=e=>this.style.height=e.data+'px';this.contentWindow.postMessage('s9e:init','*',[c.port2])" scrolling="no" src="https://s9e.github.io/iframe/2/bluesky.min.html#at%3A%2F%2Fdid%3Aplc%3A44ybard66vv44zksje25o7dz%2Fapp.bsky.feed.post%2F3kxjq2auebs2f#embed.bsky.app" style="border:0;height:600px;max-width:600px;width:100%"></iframe></div>

#document(https://s9e.github.io/iframe/2/bluesky.min.html#at%3A%2F%2Fdid%3Aplc%3A44ybard66vv44zksje25o7dz%2Fapp.bsky.feed.post%2F3kxjq2auebs2f#embed.bsky.app)

<html><head><title>Content from Bluesky</title><style>body{margin:0}iframe{border:0;height:100vh;width:100%}</style><script>((e,c)=>{c.onload=()=>{let b=e.createElement('iframe'),d;c.onmessage=a=>{if('s9e:init'!==a.data||d)a.source===b.contentWindow&&+a.data.height&&d.postMessage(+a.data.height);else if(d=a.ports[0],a=/^#at:\/(\/[\w.:]+\/[\w.:]+\/[\w.:]+)(?:#([.\w]+))?$/.exec(c.location.hash))b.loading='eager',b.scrolling='no',b.src='//'+(a[2]||'embed.bsky.app')+'/embed'+a[1]+'?id=0',e.body.append(b)}}})(document,window)</script></head><body></body></html>