在 Twitch 以外的网站上使用 BetterTTV 或 FrankerFaceZ 1) 获取 FFZ 图像 ID2) 用 PHP 下载图片

问题描述

有没有办法在 twitch.tv 以外的网站上使用例如 BetterTTVFranzerFaceZ (FFZ) 来替换表情?

我想在 twitch 上显示在线提醒(通过浏览器源代码实现)。发送的消息通常包含诸如 OMEGALULPogU 之类的表情。

我知道我可以下载图像并替换字符串中的表情符号。这已经在起作用了。但是,总是缺少一些表情(因为我需要全部实现)。

那么有没有办法在 twitch 以外的页面上使用其中一个表情替换系统?

例如这条消息

Hey PogU :)

应该变成

Hey <img src="...."> :)

我没有找到任何可能性,但至少对于 BetterTTV 来说,有一个选项可以实现 javascript 文件,因为必须有一种方法。

解决方法

不是我最初的意图,因为这仅限于我下载的表情,但我的快速和肮脏的方法是(使用 Laravel - 所以纯 php 将没有像 storage_path 这样的助手或 dd):

注意:这些下载需要相当长的时间。因此,如果您只是使用例如 30 秒 php 超时 运行它们,则会遇到超时。因此,要么从 CLI 启动它,要么将时间限制设置为无限(例如 set_time_limit(0); 或在 php.ini 中:max_execution_time = 0

第一步:下载表情

替代方案 1:BTTV

<?php

// Download emotes first and put them into a json (multiple times using offset): https://api.betterttv.net/3/emotes/shared/top?offset=1199&limit=100
// Merge them into one emotes.json file
function downloadBTTV() {
    $emotes = json_decode(file_get_contents(storage_path('emotes.json')),false,512,JSON_THROW_ON_ERROR);
    $used_filenames = [];
    $used_emotes = [];
    foreach($emotes as $emote) {
        try{
            $url = 'https://cdn.betterttv.net/emote/' . $emote->emote->id .  '/1x';
            $filename = $emote->emote->code . '.' . $emote->emote->imageType;
            if(!isset($used_filenames[$filename])) {
                $used_filenames[$filename] = 0;
            }
            $used_filenames[$filename]++;
            $full_filename = storage_path('emotes/'  . $filename);
            if(!is_file($full_filename) && in_array($emotes->emote->code,$used_emotes)) {
                file_put_contents($full_filename,file_get_contents($url));
                $used_emotes[] = $emote->emote->code;
            }
        } catch(\Exception $e) {
            dd(get_defined_vars(),$emote);
        }

    }
}

替代方案 #2:FFZ

1) 获取 FFZ 图像 ID

// Open page https://www.frankerfacez.com/emoticons/wall?q=&sort=count-desc&days=0 and scroll a lot down
// Then execute the following js code on the page

var emotes = {};
document.querySelectorAll('a.thumbnail').forEach(function(el,index){
    var href = el.getAttribute('href');
    var name = el.querySelector('h3').textContent.toLowerCase();
    var id = href.substr(href.lastIndexOf("/")+1,href.indexOf('-') - href.lastIndexOf('/') - 1);
    if(!emotes.hasOwnProperty(name)) {
        emotes[name] = id;
    }
});
console.log(Object.keys(emotes).length)
copy(emotes);

2) 用 PHP 下载图片

<?php
// 2a) Create a variable like that from the clipboard (copied in javascript in step 1)
$ffz_emotes_json = <<<'EOL'
{
  "pog": "210748","omegalul": "128054",//...
}
EOL;

function downloadFFZ() {
    global $ffz_emotes_json;

    $emotes = json_decode($ffz_emotes_json,true,JSON_THROW_ON_ERROR);
    $new_emotes = [];
    $skipped_emotes = [];
    foreach($emotes as $emote => $id) {
        $url = 'https://cdn.frankerfacez.com/emoticon/' . $id .  '/1';
        $filename = $emote . '.png';
        $filename_gif = $emote . '.gif';

        $full_filename_png = storage_path('emotes/'  . $filename);
        $full_filename_gif = storage_path('emotes/'  . $filename_gif);

        if(!is_file($full_filename_png) && !is_file($full_filename_gif) ) {
            file_put_contents($full_filename_png,file_get_contents($url));
            $new_emotes[] = $emote;
        } else {
            $skipped_emotes[] = $emote;
        }
    }
    dd($new_emotes,$skipped_emotes);
}

第 2 步:创建表情字典

现在,您已将所有这些图像存储在存储路径中,我们需要创建一个字典来查找它们(在这种方法中,它是通过 javascript 完成的)。

<?php
function generateEmotesJS()
{
    $files = glob(public_path('img/emotes/*'));
    echo "window.EMOTES = {\n";
    /** @var DirectoryIterator $fileInfo */
    foreach (new DirectoryIterator(public_path('img/emotes/*')) as $fileInfo) {
        if($fileInfo->isDot()) continue;
        echo '    "' . $fileInfo->getBasename('.' .$fileInfo->getExtension()) .'": "' . $fileInfo->getExtension() .  "\",\n";
    }
    echo "};";
}
// store this output in your javascript file

第 2 步:替换消息中的表情

// You already have something like this in your file from the previous step
window.EMOTES = {
    "!treat": "png","(ditto)": "gif","02ayaya": "png",// ...
};

// call this function to replace the emotes:
window.replaceEmotes = function(message)
{
    // https://stackoverflow.com/a/59664804/936284
    return message.split(/([\W])/).map(function(el,index){
        if(index % 2 === 0) {
            lower = el.toLowerCase();
            if(EMOTES.hasOwnProperty(lower)) {
                return '<img src="/img/emotes/' + lower + '.' + EMOTES[lower] + '" alt="' + el + '">';
            }
        }
        return el;
    }).join("")
}

// You can now call this:
console.log(replaceEmotes('Hey PogU :)'));
// Returns: Hey <img src="/img/emotes/pogu.png" alt="PogU"> :)
console.log(replaceEmotes("Hey ho OMEGALUL"));
// Returns Hey ho <img src="/img/emotes/omegalul.png" alt="OMEGALUL">
console.log(replaceEmotes("Test Kappa\nTest > all <3"));
// Returns: Test <img src="/img/emotes/kappa.png" alt="Kappa">
// Test > all <3

就像我说的,又快又脏。如果你有时间,你肯定会找到更好的方法。也许对 chrome 扩展进行逆向工程以进行替换更有意义 ;)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...