Not what I initially intended, as this is limited to the emotes I downloaded, but my quick and dirty approach was (using Laravel - so pure php would be without helpers like storage_path
or dd
):
Caution: Those downloads take quite some time. So you will run into timeouts if you just run them with an eg 30s php timeout. So either start it from CLI or set the time limit to infinite (eg set_time_limit(0);
or in php.ini: max_execution_time = 0
)
Step 1: Download the emotes
Alternative #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);
}
}
}
Alternative #2: FFZ
1) Get FFZ image ids
// 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) Download the images in 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, 512, 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);
}
Step 2: Create the emotes dictionary
Now, that you have all those images stored in your storage path, we need to create a dictionary to look them up (as in this approach it is done via 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
Step 2: Replace emotes in messages
// 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
Like I said, quick and dirty. If you have time, you sure find a better approach. Maybe reverse-engineering the chrome extensions for replacement makes more sense ;)