From 99ec7a3593d18eb29dfca2d06e9e197aee5322f6 Mon Sep 17 00:00:00 2001 From: OSint Date: Tue, 9 Jul 2024 23:06:00 -0500 Subject: [PATCH] adding all project logic --- package.json | 1 + pnpm-lock.yaml | 21 +++ src/config/config.ts | 10 ++ src/database/dbClient.ts | 8 ++ src/index.ts | 15 +- src/jsons/girls.json | 130 ++++++++++++++++++ src/models/servers.ts | 5 + src/models/video.ts | 8 ++ src/models/webhooks.ts | 10 ++ src/services/cdnService.ts | 3 + src/services/discordService.ts | 10 ++ src/services/getVideos.ts | 50 ------- .../{videoConvert.ts => videoDownloader.ts} | 65 +-------- src/services/videosService.ts | 32 +++++ src/services/xvideosService.ts | 54 ++++++++ src/utils/getGirl.ts | 5 +- src/utils/getTag.ts | 26 ++++ src/utils/handleRepeated.ts | 48 ------- 18 files changed, 328 insertions(+), 173 deletions(-) create mode 100644 src/jsons/girls.json create mode 100644 src/models/servers.ts create mode 100644 src/models/webhooks.ts create mode 100644 src/services/cdnService.ts create mode 100644 src/services/discordService.ts delete mode 100644 src/services/getVideos.ts rename src/services/{videoConvert.ts => videoDownloader.ts} (61%) create mode 100644 src/services/videosService.ts create mode 100644 src/services/xvideosService.ts create mode 100644 src/utils/getTag.ts delete mode 100644 src/utils/handleRepeated.ts diff --git a/package.json b/package.json index ed4ccd2..bdb039c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@neondatabase/serverless": "^0.9.4", "@rodrigogs/xvideos": "^1.3.0", "axios": "^1.7.2", + "discord-webhook-node": "^1.1.8", "dotenv": "^16.4.5", "drizzle-orm": "^0.31.4", "puppeteer": "^22.12.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66458cc..e871de2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ dependencies: axios: specifier: ^1.7.2 version: 1.7.2 + discord-webhook-node: + specifier: ^1.1.8 + version: 1.1.8 dotenv: specifier: ^16.4.5 version: 16.4.5 @@ -1218,6 +1221,15 @@ packages: resolution: {integrity: sha512-xd4D8kHQtB0KtWW0c9xBZD5LVtm9chkMOfs/3Yn01RhT/sFIsVtzTtypfKoFfWBaL+7xCYLxjOLkhwPXaX/Kcg==} dev: false + /discord-webhook-node@1.1.8: + resolution: {integrity: sha512-3u0rrwywwYGc6HrgYirN/9gkBYqmdpvReyQjapoXARAHi0P0fIyf3W5tS5i3U3cc7e44E+e7dIHYUeec7yWaug==} + dependencies: + form-data: 3.0.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + /dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} dependencies: @@ -1627,6 +1639,15 @@ packages: optional: true dev: false + /form-data@3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} diff --git a/src/config/config.ts b/src/config/config.ts index e69de29..27d90ce 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -0,0 +1,10 @@ +import { config } from 'dotenv'; +config(); + +export const DatabaseConfig = { + dbUrl: process.env.DATABASE_URL as string +}; + +export const CdnConfig = { + cdnUrl: process.env.CND_URL as string, +} \ No newline at end of file diff --git a/src/database/dbClient.ts b/src/database/dbClient.ts index e69de29..ec62681 100644 --- a/src/database/dbClient.ts +++ b/src/database/dbClient.ts @@ -0,0 +1,8 @@ +import { neon } from '@neondatabase/serverless'; +import { drizzle } from 'drizzle-orm/neon-http'; + +import { DatabaseConfig } from '../config/config'; + +const db = drizzle(neon(DatabaseConfig.dbUrl)); + +export default db; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 17de33d..e13b274 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,3 @@ -import { getVideos } from "./services/getVideos"; +import { getVideos } from "./services/videosService"; -const runGetVideos = async () => { - try { - await getVideos(); - } catch (error) { - console.error("Error in getVideos:", error); - } - - // Llamar a la función nuevamente después de que se complete - setTimeout(runGetVideos, 0); -}; - -runGetVideos(); +getVideos(); diff --git a/src/jsons/girls.json b/src/jsons/girls.json new file mode 100644 index 0000000..233977a --- /dev/null +++ b/src/jsons/girls.json @@ -0,0 +1,130 @@ +[ + { + "name": "Daniela 🍓", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257092623261237308/432889137_441981384946590_1527129978413301309_n.png?ex=6683263d&is=6681d4bd&hm=9172612bafb7c50f778122cc763d9de0315d554cf45af6784b1f12aaafab9e87&=&format=webp&quality=lossless&width=662&height=662" + }, + { + "name": "Ximena 😈", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117154378121256/2_JS296597445.png?ex=66833d15&is=6681eb95&hm=aa7e2f5d82dbc3c5b54f93ab447884c5f49f143aa74c4d6e9b41e4f9534d895d&=&format=webp&quality=lossless&width=386&height=437" + }, + { + "name": "Marcianita 🥰", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117187089633371/fans-top.png?ex=66833d1d&is=6681eb9d&hm=6264a98ecb88dcca225f4f12c3b518f40171715d370356f47ee1722ed1ac8543&=&format=webp&quality=lossless&width=881&height=587" + }, + { + "name": "Fer 🙈", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117249580564584/images.png?ex=66833d2c&is=6681ebac&hm=bffbe57fdd4c927487839f90d6c6b24296563953fe4fc31852493f670b366dbf&=&format=webp&quality=lossless&width=281&height=280" + }, + { + "name": "Isabella ❤️‍🔥", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117314818641951/Snapinsta-app_327167239_1421996155330576_2952491947825490116_n_1080.png?ex=66833d3b&is=6681ebbb&hm=aeaf45e7a23bbefaeac679abd8051ac373c13c1ac28e7b9eaefa3f953e4dff44&=&format=webp&quality=lossless&width=350&height=437" + }, + { + "name": "Canaria 💋", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117340236124160/7347cd7630504861bc5b56cc0e198b11_md.png?ex=66833d42&is=6681ebc2&hm=5e55bf95bb0ac9d68b4a6310cbdd4e7c9721ab34ce34eb631aad4b7e2d86e959&=&format=webp&quality=lossless&width=582&height=437" + }, + { + "name": "Alicia 🫦", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117396330745866/0_PAY-Its-really-offensive-OnlyFans-model-is-KICKED-OUT-of-26000-holiday-home-after-sharing-sexy-p.png?ex=66833d4f&is=6681ebcf&hm=fd51fef2f5dc2889e6da1cf583543b4124bae8057a61402262de16bcc874ffc6&=&format=webp&quality=lossless&width=291&height=437" + }, + { + "name": "Almita 🍑", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117425510383706/mercedes.png?ex=66833d56&is=6681ebd6&hm=c34c5dbc0fbb1d59b513cd042d0c19c7cea899aac6b277e6fe2787644be11b9c&=&format=webp&quality=lossless&width=438&height=437" + }, + { + "name": "Bridgette 💦", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117446016598026/mercedes1.png?ex=66833d5b&is=6681ebdb&hm=d56a70c0cebfa0b384affd74a8c56baf75fb8c9727e832ac2a419d666dedb646&=&format=webp&quality=lossless&width=438&height=437" + }, + { + "name": "Alisson 🥛", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117517986660453/Sun_Instagram_image_download_null_184102.png?ex=66833d6c&is=6681ebec&hm=5e09758413f900ed86b55c9b5df2cdd9578f7f40feaf9512747074921596ec24&=&format=webp&quality=lossless&width=353&height=437" + }, + { + "name": "Mei ❤️", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117588647972915/ab8cb350-4828-11ed-beff-d50264dd8abe.png?ex=66833d7d&is=6681ebfd&hm=24cb24d43bdd79ed1e84bf7edb0b2d70fca5509496325eb075c09c8b42ccfaca&=&format=webp&quality=lossless&width=350&height=437" + }, + { + "name": "Fifi 💕", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117608977895494/0_I-swore-off-sex-after-heartbreak-no-man-deserves-to-take-me-to-bed-says-OnlyFans-model.png?ex=66833d82&is=6681ec02&hm=1f40b8439a5c9a38c1d7a68ed75806076fbcd78208956741cb8968c9e8c99fdd&=&format=webp&quality=lossless&width=582&height=437" + }, + { + "name": "Valerie 🍒", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257117969646092310/NINTCHDBPICT000658831317.png?ex=66833dd8&is=6681ec58&hm=c39be33b78bbac38b938a52a34ea6049107c202bb3410338a23759af72ac92f4&=&format=webp&quality=lossless&width=530&height=662" + }, + { + "name": "Tali 😇", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118002902728734/JUGYcByQrI2z3iWH.png?ex=66833de0&is=6681ec60&hm=0023c299bafa1d01ed003c3ee50eb75f03491a2ccb846bceffeba4916728a2b0&=&format=webp&quality=lossless&width=372&height=662" + }, + { + "name": "Nimi 💖", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118092488867901/images.png?ex=66833df5&is=6681ec75&hm=ece001624aec3236f7cd3477ee0d955b65c4416e57ad06f6f79fb9f4d3dd6f96&=&format=webp&quality=lossless&width=280&height=281" + }, + { + "name": "Mariam 💗", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118093998686359/images.png?ex=66833df5&is=6681ec75&hm=c104096a11498357044569b8b022fd9872b7c9ab5dcaf9d4f446661c083e425c&=&format=webp&quality=lossless&width=367&height=213" + }, + { + "name": "Ariana 💞", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118114550644776/images.png?ex=66833dfa&is=6681ec7a&hm=a6addaf621e99cb3a2b5c1b2a35b83cee353ba120334d051fcd1a194f51f972b&=&format=webp&quality=lossless&width=375&height=210" + }, + { + "name": "Tele 💖", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118170712375456/kelsey1.png?ex=66833e08&is=6681ec88&hm=354fdc6f6ceeb4e914ffe57abb018f3c2f8f16e0f72effb2b202273e8959517e&=&format=webp&quality=lossless&width=377&height=437" + }, + { + "name": "Nandi 🥵", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118189494603937/7c0480979adf69470661fc8200764a64.png?ex=66833e0c&is=6681ec8c&hm=00750d8d28d13629e5fea5c702b14340fbad0595ac025300d996cb633032728e&=&format=webp&quality=lossless&width=687&height=386" + }, + { + "name": "Nat 😈", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118228744765522/B9730710753Z.png?ex=66833e15&is=6681ec95&hm=c642e2cf8ac0e55e438cf64379fe810f971565197ca27d174f745de468160583&=&format=webp&quality=lossless&width=676&height=437" + }, + { + "name": "Maria 🥰", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118281429549066/image9.png?ex=66833e22&is=6681eca2&hm=440162c0025b76e10c4eb15a01da7e178e9c191cf34cc95c1cfdf502f91b507c&=&format=webp&quality=lossless&width=400&height=437" + }, + { + "name": "Gia 🙈", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118370667561021/tailamaddison-onlyfans-stepdad-caught-15.png?ex=66833e37&is=6681ecb7&hm=1b9e7722d7ef69b1a7e02364cb219ec69d132961897417e1a4c8da8d71edfbe5&=&format=webp&quality=lossless&width=500&height=337" + }, + { + "name": "Shura ❤️‍🔥", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118405882941552/image.png?ex=66833e40&is=6681ecc0&hm=4ac7b93d4280f5670291dae60ef54eb5bdce6eeab5e2dd31a516a8fec0832c11&=&format=webp&quality=lossless&width=365&height=437" + }, + { + "name": "Ivy 💋", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118431560601730/1_PAY-OnlyFans-model-kicked-off-nudist-beach-for-filming-racy-content.png?ex=66833e46&is=6681ecc6&hm=b269d6bc7e4d7334218cdb1924f251cffc7875154841f1ff0a78f380221cc764&=&format=webp&quality=lossless&width=350&height=437" + }, + { + "name": "Tete 🫦", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118517640167534/1_OnlyFans-star-Courtney-Clenney-has-been-charged-with-murdering-her-boyfriend-Christian-Obumseli-in-t.png?ex=66833e5a&is=6681ecda&hm=1a4a6d751db64fc0ab677b9db1b78d1474be3533d936384171e442dbdf998de2&=&format=webp&quality=lossless&width=291&height=437" + }, + { + "name": "Mitsu 🍑", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118553723637770/2_OnlyFans-model-offered-1m-for-sex-looks-splashing-in-poolside-vid-in-non-existent-thong.png?ex=66833e63&is=6681ece3&hm=57e9515233f6a92d332976f808910d451f33296ca8a7c4fe9594cc494d5b6502&=&format=webp&quality=lossless&width=768&height=511" + }, + { + "name": "Xyra 💦", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118570459172974/0_jennalee_275142746_4962983330411438_2543567959700643132_n.png?ex=66833e67&is=6681ece7&hm=92ac0dd22d0e0493a637072de21856626963bb9d98c0a1837e21b48e6332c261&=&format=webp&quality=lossless&width=350&height=437" + }, + { + "name": "Jannet 🥛", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257135244822315100/183fa812b6825c0d0a1735c3d06d8ba1.png?ex=66834dee&is=6681fc6e&hm=f610b46b70f73f57e317ebf73fc70581a0432622cb730e6427d48824ed45c08a&=&format=webp&quality=lossless&width=396&height=437" + }, + { + "name": "Lia ❤️", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257118633939964084/Z6JLNWEKTFA75PYNRFPCKRT6WU.png?ex=66833e76&is=6681ecf6&hm=ca460656ab3fd9dc63a265eba2b670d7f4c399b6f9bb4525242499e827100bdd&=&format=webp&quality=lossless&width=348&height=437" + }, + { + "name": "Camila 💕", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257120842106540192/1_Aussie-Model-Lucy-Banks-Calls-OnlyFans-A-Feminist-Movement.png?ex=66834084&is=6681ef04&hm=cc6deb9a07c4e956dd8e93d44970bc83d57dd355c05f35567cc9a3ee6ddf7a78&=&format=webp&quality=lossless&width=291&height=437" + }, + { + "name": "Melu 🍒", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257120890374586410/28283066-8309817-Dark_world_Model_Allison_Parker_has_revealed_there_is_nothing_gl-a-1_1591683965839.png?ex=66834090&is=6681ef10&hm=4cc13507564945cf047918cacc5abc46c21ee676e215f8d3aae10c192e9d5a52&=&format=webp&quality=lossless&width=578&height=437" + }, + { + "name": "Francheska 😇", + "image": "https://media.discordapp.net/attachments/1256702993190096908/1257120913405771807/40941c664547df3944799f305014acf1.png?ex=66834095&is=6681ef15&hm=9186a48621bd699c22eff371d53476db6ea64699acd1c844a970342505f08131&=&format=webp&quality=lossless&width=350&height=437" + } +] diff --git a/src/models/servers.ts b/src/models/servers.ts new file mode 100644 index 0000000..d6c3747 --- /dev/null +++ b/src/models/servers.ts @@ -0,0 +1,5 @@ +import { pgTable, varchar } from 'drizzle-orm/pg-core'; + +export const servers = pgTable('servers', { + server_id: varchar('server_id', { length: 255 }).primaryKey() +}); \ No newline at end of file diff --git a/src/models/video.ts b/src/models/video.ts index e69de29..2d62eb3 100644 --- a/src/models/video.ts +++ b/src/models/video.ts @@ -0,0 +1,8 @@ +import { pgTable, varchar } from "drizzle-orm/pg-core"; +export const videos = pgTable("videos", { + x_url: varchar("x_url", { length: 255 }).primaryKey(), + title: varchar("name", { length: 255 }).notNull(), + url: varchar("url", { length: 255 }).notNull(), + preview: varchar("preview", { length: 255 }).notNull(), + channel_tag: varchar("channel_tag", { length: 100 }).notNull(), +}); diff --git a/src/models/webhooks.ts b/src/models/webhooks.ts new file mode 100644 index 0000000..b41627e --- /dev/null +++ b/src/models/webhooks.ts @@ -0,0 +1,10 @@ +import { pgTable, varchar } from 'drizzle-orm/pg-core'; +import { servers } from './servers'; + +export const webhooks = pgTable('webhooks', { + server_id: varchar('server_id') // Debe coincidir con el nombre en la tabla 'servers' + .notNull() + .references(() => servers.server_id), + webhook_url: varchar('webhook_url', { length: 255 }).notNull(), + channel_tag: varchar('channel_tag', { length: 100 }).notNull() +}); \ No newline at end of file diff --git a/src/services/cdnService.ts b/src/services/cdnService.ts new file mode 100644 index 0000000..a5cd67c --- /dev/null +++ b/src/services/cdnService.ts @@ -0,0 +1,3 @@ +export const uploadToCdn = async (file: string) => { + console.log(file, "succesfully uploaded to cdn!"); +} \ No newline at end of file diff --git a/src/services/discordService.ts b/src/services/discordService.ts new file mode 100644 index 0000000..42fa903 --- /dev/null +++ b/src/services/discordService.ts @@ -0,0 +1,10 @@ +import { Webhook } from "discord-webhook-node"; +import { getGirl } from "../utils/getGirl"; + +export const sendingWebhook = async (file: string, webhook_url: string) => { + const girl = await getGirl(); + const hook = new Webhook(webhook_url); + hook.setAvatar(girl.image); + hook.setUsername(girl.name); + hook.sendFile(file); +}; diff --git a/src/services/getVideos.ts b/src/services/getVideos.ts deleted file mode 100644 index 635b6ba..0000000 --- a/src/services/getVideos.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { processVideo } from "./videoConvert"; -import { getGirl } from "../getGirl"; -import * as fs from "fs/promises"; - -const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -export const getVideos = async () => { - for (const item of webhooks) { - const [key, webhookUrl] = Object.entries(item)[0]; - - let videoPath = ""; - let alternativeIndex = 0; - let next; - const girl = await getGirl(); - while (!videoPath) { - try { - videoPath = await processVideo(key, alternativeIndex, next); - next = false; - if (videoPath.includes("Error processing video")) { - alternativeIndex++; - if (alternativeIndex >= 27) { - console.log(`No more videos available for ${key}. Skipping.`); - alternativeIndex = 0; - next = true; - continue; - } - continue; - } - - console.log(`Message sent to ${key}`); - break; // Salir del bucle si el video se envió con éxito - } catch (error) { - console.error(`Error sending message to ${key}:`, error); - break; // Salir del bucle en caso de error - } finally { - if (videoPath && !videoPath.includes("Error processing video")) { - try { - await fs.unlink(videoPath); - console.log(`File ${videoPath} deleted successfully`); - } catch (unlinkError) { - console.error(`Error deleting file ${videoPath}:`, unlinkError); - } - } - await sleep(500000); // Esperar 120 segundos antes de procesar el siguiente webhook - } - } - } -}; - -// Llama a getVideos una vez al inicio diff --git a/src/services/videoConvert.ts b/src/services/videoDownloader.ts similarity index 61% rename from src/services/videoConvert.ts rename to src/services/videoDownloader.ts index 257730a..422fcb2 100644 --- a/src/services/videoConvert.ts +++ b/src/services/videoDownloader.ts @@ -3,9 +3,6 @@ import fs from "fs"; import path from "path"; import util from "util"; import axios from "axios"; -import { addProcessedTitle } from "../utils/handleRepeated"; -const xvideos = require("@rodrigogs/xvideos"); - const pipeline = util.promisify(require("stream").pipeline); const downloadFile = async (url: string, outputPath: string) => { @@ -14,14 +11,12 @@ const downloadFile = async (url: string, outputPath: string) => { method: "GET", responseType: "stream", }); - if (response.status !== 200) throw new Error(`Failed to fetch ${url}`); - const writer = fs.createWriteStream(outputPath); await pipeline(response.data, writer); }; -const scrapeLocoloader = async ( +const getVideoFile = async ( pageUrl: string, outputFilePath: string, retries = 3 @@ -37,10 +32,8 @@ const scrapeLocoloader = async ( waitUntil: "networkidle2", } ); - // Wait for the necessary elements to load await page.waitForSelector(".list-group-item-action", { timeout: 30000 }); - // Get the specific download link const downloadLink = await page.evaluate(() => { const links = Array.from( @@ -49,15 +42,10 @@ const scrapeLocoloader = async ( const targetLink = links.find((link) => link.href.includes("mp4")); return targetLink ? targetLink.href : null; }); - - if (!downloadLink) { - throw new Error("Download link not found."); - } - + if (!downloadLink) throw new Error("Download link not found."); // Download the file console.log(`Downloading video from ${downloadLink}...`); await downloadFile(downloadLink, outputFilePath); - console.log(`Video downloaded successfully: ${outputFilePath}`); await browser.close(); return; @@ -74,57 +62,18 @@ const scrapeLocoloader = async ( }; export const processVideo = async ( - query: string, - alternativeIndex: number = 0, - next: boolean = false + url: string, + title: string, ): Promise => { try { - let page = 1; - if (next) { - page++; - } - const searchResults = await xvideos.videos.search({ k: query, page }); - if (searchResults.videos.length === 0) { - throw new Error("No videos found"); - } - let video; - let videoIndex = alternativeIndex; - - while (videoIndex < searchResults.videos.length) { - const v = searchResults.videos[videoIndex]; - if (v.duration.includes("h")) { - videoIndex++; - continue; - } else if (parseInt(v.duration.split(" ")[0], 10) > 6) { - videoIndex++; - continue; - } else { - const videoTitle = v.title.replace(/[\/\\?%*:|"<>]/g, "_"); - const titleProcessed = await addProcessedTitle(videoTitle); - if (!titleProcessed) { - videoIndex++; - continue; - } - video = v; - break; - } - } - - if (!video) throw new Error("No suitable video found"); - - const videoUrl = video.url; - const videoTitle = video.title.replace(/[\/\\?%*:|"<>]/g, "_"); const outputFilePath = path.join( __dirname, "videos", - `${videoTitle}_converted.mp4` + `${title}_converted.mp4` ); - - console.log(`Processing video from ${videoUrl}...`); - await scrapeLocoloader(videoUrl, outputFilePath); - + console.log(`Processing video from ${url}...`); + await getVideoFile(url, outputFilePath); console.log(`Video converted successfully: ${outputFilePath}`); - return outputFilePath; } catch (error: any) { console.error("Error processing video:", error); diff --git a/src/services/videosService.ts b/src/services/videosService.ts new file mode 100644 index 0000000..d7eed41 --- /dev/null +++ b/src/services/videosService.ts @@ -0,0 +1,32 @@ +import { processVideo } from "./videoDownloader"; +import * as fs from "fs/promises"; +import { getTag } from "../utils/getTag"; +import { getRandomVideo, checkFileSize } from "./xvideosService"; +import { sendingWebhook } from "./discordService"; +import { uploadToCdn } from "./cdnService"; + +export const getVideos = async () => { + const res = await getTag(); + if (!res) throw new Error("No tags found"); + const { webhook_url, channel_tag } = res; + const { url, title } = await getRandomVideo(channel_tag); + let file; + try { + file = await processVideo(url, title); // get video filepath + if ((await checkFileSize(file)) < 25) { + await sendingWebhook(file, webhook_url); + console.log(`Message sent to ${channel_tag}`); + } // send to discord + await uploadToCdn(file); // upload to cdn + } catch (error) { + console.error(`Error sending message to ${channel_tag}:`, error); + } finally { + try { + if (!file) return; + await fs.unlink(file); + console.log(`File ${file} deleted successfully`); + } catch (unlinkError) { + console.error(`Error deleting file ${file}:`, unlinkError); + } + } +}; diff --git a/src/services/xvideosService.ts b/src/services/xvideosService.ts new file mode 100644 index 0000000..9c6aea1 --- /dev/null +++ b/src/services/xvideosService.ts @@ -0,0 +1,54 @@ +const xvideos = require("@rodrigogs/xvideos"); +import { eq } from "drizzle-orm"; +import db from "../database/dbClient"; +import { promises as fs } from "fs"; +import { videos } from "../models/video"; + +export const getRandomVideo = async ( + k: string +): Promise<{ url: string; title: string; duration: string; k: string }> => { + try { + const { pagination } = await xvideos.videos.search({ k }); + const lastPage = pagination.pages[pagination.pages.length - 1]; + const page = Math.floor(Math.random() * lastPage) + 1; + const { videos } = await xvideos.videos.search({ k, page }); + const randomVideo = videos[Math.floor(Math.random() * videos.length)]; + const { url, title, duration } = randomVideo; + return { url, title, duration, k }; + } catch (error) { + console.error("Error getting random video", error); + throw new Error("Error getting random video"); + } +}; + +const validateVideo = async ( + url: string, + title: string, + duration: string, + k: string +): Promise<{ url: string; title: string }> => { + const videoExists = await db + .select() + .from(videos) + .where(eq(videos.x_url, url)); + if ( + duration.includes("h") || + parseInt(duration.split(" ")[0], 10) > 6 || + videoExists.length > 0 + ) { + const newVideo = await getRandomVideo(k); + return validateVideo(newVideo.url, newVideo.title, newVideo.duration, k); + } + title = title.replace(/[\/\\?%*:|"<>]/g, "_"); + return { url, title }; +}; + +export const checkFileSize = async (file: string): Promise => { + try { + const stats = await fs.stat(file); + return stats.size / (1024 * 1024); + } catch (error) { + console.error("Error checking file size", error); + throw new Error("Error checking file size"); + } +}; diff --git a/src/utils/getGirl.ts b/src/utils/getGirl.ts index c54937c..b8486b8 100644 --- a/src/utils/getGirl.ts +++ b/src/utils/getGirl.ts @@ -1,9 +1,6 @@ -import girls from "./jsons/girls.json"; +import girls from "../jsons/girls.json"; export const getGirl = (): { name: string; image: string } => { - // Generate a random index const randomIndex = Math.floor(Math.random() * girls.length); - - // Return the item at the random index return girls[randomIndex]; }; diff --git a/src/utils/getTag.ts b/src/utils/getTag.ts new file mode 100644 index 0000000..034b176 --- /dev/null +++ b/src/utils/getTag.ts @@ -0,0 +1,26 @@ +import db from "../database/dbClient"; +import { webhooks } from "../models/webhooks"; + +export const getTag = async (): Promise<{ + channel_tag: string; + webhook_url: string; +} | null> => { + try { + const result = await db + .select({ + channel_tag: webhooks.channel_tag, + webhook_url: webhooks.webhook_url, + }) + .from(webhooks); + if (result.length === 0) return null; + const randomIndex = Math.floor(Math.random() * result.length); + const random = result[randomIndex]; + return { + channel_tag: random.channel_tag, + webhook_url: random.webhook_url, + }; + } catch (error) { + console.error("Error fetching random tag:", error); + throw new Error("Failed to fetch random tag"); + } +}; diff --git a/src/utils/handleRepeated.ts b/src/utils/handleRepeated.ts deleted file mode 100644 index ec720c1..0000000 --- a/src/utils/handleRepeated.ts +++ /dev/null @@ -1,48 +0,0 @@ -// processedTitlesManager.ts -import * as fs from "fs/promises"; -import path from "path"; - -const processedTitlesFile = path.join(__dirname, "processedTitles.json"); - -// Leer el archivo de títulos procesados -export const readProcessedTitles = async (): Promise> => { - try { - const data = await fs.readFile(processedTitlesFile, "utf-8"); - return new Set(JSON.parse(data)); - } catch (error: any) { - if (error.code === "ENOENT") { - // Si el archivo no existe, devolver un conjunto vacío - return new Set(); - } - throw error; - } -}; - -// Escribir en el archivo de títulos procesados -export const writeProcessedTitles = async ( - titles: Set -): Promise => { - try { - await fs.writeFile( - processedTitlesFile, - JSON.stringify([...titles], null, 2) - ); - return true; - } catch (error) { - console.error("Error writing processed titles:", error); - return false; - } -}; - -// Añadir un título al archivo de títulos procesados -export const addProcessedTitle = async (title: string): Promise => { - try { - const titles = await readProcessedTitles(); - if (titles.has(title)) return false; - titles.add(title); - return await writeProcessedTitles(titles); - } catch (error: any) { - console.error("Error adding processed title:", error); - return false; - } -};