new format and marketplace
This commit is contained in:
115
image/tenor.js
Normal file
115
image/tenor.js
Normal file
@@ -0,0 +1,115 @@
|
||||
class Tenor {
|
||||
baseUrl = "https://tenor.com";
|
||||
|
||||
constructor() {
|
||||
this.type = "image-board";
|
||||
this.lastQuery = null;
|
||||
this.seenIds = new Set();
|
||||
}
|
||||
|
||||
async search(query, page = 1, perPage = 48) {
|
||||
query = query?.trim() || "thighs";
|
||||
|
||||
if (query !== this.lastQuery) {
|
||||
this.lastQuery = query;
|
||||
this.seenIds.clear();
|
||||
}
|
||||
|
||||
const url = `${this.baseUrl}/search/${query.replaceAll(" ", "-")}-gifs`;
|
||||
|
||||
const { result } = await this.scrape(
|
||||
url,
|
||||
async (page) => {
|
||||
return page.evaluate(() => {
|
||||
const items = document.querySelectorAll('div.GifList figure, figure');
|
||||
const results = [];
|
||||
|
||||
items.forEach(fig => {
|
||||
const link = fig.querySelector('a');
|
||||
const img = fig.querySelector('img');
|
||||
if (!link || !img) return;
|
||||
|
||||
const href = link.getAttribute('href') || "";
|
||||
const idMatch = href.match(/-(\d+)(?:$|\/?$)/);
|
||||
const id = idMatch ? idMatch[1] : null;
|
||||
|
||||
const imgUrl =
|
||||
img.getAttribute('src') ||
|
||||
img.getAttribute('data-src');
|
||||
|
||||
const tagsRaw = img.getAttribute('alt') || "";
|
||||
const tags = tagsRaw.trim().split(/\s+/).filter(Boolean);
|
||||
|
||||
if (id && imgUrl && !imgUrl.includes("placeholder")) {
|
||||
results.push({
|
||||
id,
|
||||
image: imgUrl,
|
||||
sampleImageUrl: imgUrl,
|
||||
tags,
|
||||
type: "preview"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const uniqueResults = Array.from(
|
||||
new Map(results.map(r => [r.id, r])).values()
|
||||
);
|
||||
|
||||
return {results: uniqueResults, hasNextPage: true};
|
||||
});
|
||||
},
|
||||
{
|
||||
waitSelector: "figure",
|
||||
timeout: 30000,
|
||||
scrollToBottom: true,
|
||||
renderWaitTime: 3000,
|
||||
loadImages: true
|
||||
}
|
||||
);
|
||||
|
||||
const newResults = result.results.filter(r => !this.seenIds.has(r.id));
|
||||
newResults.forEach(r => this.seenIds.add(r.id));
|
||||
|
||||
return {
|
||||
results: newResults.map(r => ({
|
||||
id: r.id,
|
||||
image: r.image,
|
||||
tags: r.tags,
|
||||
})),
|
||||
hasNextPage: result.hasNextPage,
|
||||
page
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
async getInfo(id) {
|
||||
const url = `${this.baseUrl}/view/gif-${id}`;
|
||||
|
||||
const { result } = await this.scrape(
|
||||
url,
|
||||
async (page) => {
|
||||
return page.evaluate(() => {
|
||||
const img = document.querySelector(".Gif img");
|
||||
const fullImage = img?.src || null;
|
||||
|
||||
const tags = [...document.querySelectorAll(".tag-list li a .RelatedTag")]
|
||||
.map(t => t.textContent.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
return { fullImage, tags };
|
||||
});
|
||||
},
|
||||
{ waitSelector: ".Gif img", timeout: 15000 }
|
||||
);
|
||||
|
||||
return {
|
||||
id,
|
||||
image: result.fullImage,
|
||||
tags: result.tags,
|
||||
title: result.tags?.join(" ") || `Tenor GIF ${id}`,
|
||||
headers: ""
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Tenor;
|
||||
Reference in New Issue
Block a user