Added Eldoradu Robux Price Sentry Job
Some checks failed
Push image to registry / build-image (push) Failing after 3m30s
Some checks failed
Push image to registry / build-image (push) Failing after 3m30s
This commit is contained in:
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Browser\Jobs\EldoradoRobuxPriceSentry;
|
||||||
|
|
||||||
|
use App\Browser\BrowserJob;
|
||||||
|
use App\Browser\JobDebugScreenshot;
|
||||||
|
use App\Browser\Jobs\InstagramRepost\DescriptionPipeline\InstagramDescriptionPipeline;
|
||||||
|
use App\Models\InstagramNotification;
|
||||||
|
use App\Models\InstagramRepost;
|
||||||
|
use App\Models\Job;
|
||||||
|
use App\Models\JobRun;
|
||||||
|
use App\Notification\Notifications\JobDebugNotification;
|
||||||
|
use App\Notification\Notifications\SimpleNotification;
|
||||||
|
use App\Notification\Providers\AllNotification;
|
||||||
|
use App\Services\Instagram\NotificationTypeDetector;
|
||||||
|
use Facebook\WebDriver\WebDriverBy;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Laravel\Dusk\Browser;
|
||||||
|
use App\Services\AIPrompt\OpenAPIPrompt;
|
||||||
|
|
||||||
|
class EldoradoRobuxPriceSentryJob extends BrowserJob implements ShouldBeUniqueUntilProcessing
|
||||||
|
{
|
||||||
|
// === CONFIGURATION ===
|
||||||
|
|
||||||
|
public $timeout = 600; // 10 minutes
|
||||||
|
private const APPROXIMATIVE_RUNNING_MINUTES = 20;
|
||||||
|
private const LINK = "https://www.eldorado.gg/fr/buy-robux/g/70-0-0";
|
||||||
|
protected string $downloadFolder = "app/Browser/downloads/EldoradoRobuxPriceSentry/";
|
||||||
|
|
||||||
|
protected Collection $jobInfos;
|
||||||
|
protected JobRun $jobRun;
|
||||||
|
|
||||||
|
public function __construct($jobId = 5)
|
||||||
|
{
|
||||||
|
parent::__construct($jobId);
|
||||||
|
|
||||||
|
$this->downloadFolder = base_path($this->downloadFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(Browser $browser): ?JobRun
|
||||||
|
{
|
||||||
|
$startTime = microtime(true);
|
||||||
|
|
||||||
|
Log::info("Running EldoradoRobuxPriceSentryJob");
|
||||||
|
$this->jobInfos = Job::find($this->jobId)->jobInfosTable();
|
||||||
|
$this->jobRun = new JobRun([
|
||||||
|
"job_id" => $this->jobId,
|
||||||
|
"success" => false,
|
||||||
|
]);
|
||||||
|
$this->jobRun->save();
|
||||||
|
|
||||||
|
dump("visiting " . microtime(true) - $startTime);
|
||||||
|
$browser->visit(self::LINK);
|
||||||
|
sleep(5);
|
||||||
|
$this->sendPrices($browser);
|
||||||
|
|
||||||
|
$this->jobRun->success = true;
|
||||||
|
$this->jobRun->save();
|
||||||
|
|
||||||
|
Log::info("EldoradoRobuxPriceSentryJob run ended");
|
||||||
|
|
||||||
|
return $this->jobRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function runTest(Browser $browser): ?JobRun
|
||||||
|
{
|
||||||
|
$this->jobInfos = Job::find($this->jobId)->jobInfosTable();
|
||||||
|
try {
|
||||||
|
$browser->visit(self::LINK);
|
||||||
|
sleep(5);
|
||||||
|
|
||||||
|
return $this->makeSimpleJobRun(
|
||||||
|
true,
|
||||||
|
"Test réussi",
|
||||||
|
"Datboi a réussi à charger la page Eldorado."
|
||||||
|
);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->makeSimpleJobRun(
|
||||||
|
false,
|
||||||
|
"Test échoué",
|
||||||
|
"Datboi n'a pas réussi à charger la page Eldorado :\n" . $e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendPrices(Browser $browser): void
|
||||||
|
{
|
||||||
|
$lowestPriceElement = $browser->driver->findElement(WebDriverBy::xpath('(//eld-offer-price)[2]/strong'));
|
||||||
|
$lowestPriceText = $lowestPriceElement->getText(); // Ex: " 0,00478 € "
|
||||||
|
$lowestPrice = (float)str_replace(["€", ","], ["", "."], trim($lowestPriceText));
|
||||||
|
|
||||||
|
$threshold = floatval(str_replace(",", ".", $this->jobInfos->get("eldorado_robux_price_threshold")));
|
||||||
|
dump($threshold);
|
||||||
|
|
||||||
|
Log::info("EldoradoRobuxPriceSentryJob: lowest price = $lowestPrice €, threshold = $threshold €");
|
||||||
|
|
||||||
|
if ($lowestPrice <= $threshold) {
|
||||||
|
$message = "Le prix des Robux sur Eldorado est actuellement de **" . number_format($lowestPrice, 5, ",", " ") . " €**/Robux, ce qui est inférieur ou égal au seuil de **" . number_format($threshold, 5, ",", " ") . " €**.\n\n[Voir l'offre sur Eldorado]( " . self::LINK . " )";
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
if ($this->jobInfos->get("eldorado_robux_price_discord_webhook") !== null) { // Custom discord webhook
|
||||||
|
$options["discord_webhook_url"] = $this->jobInfos->get("eldorado_robux_price_discord_webhook");
|
||||||
|
}
|
||||||
|
|
||||||
|
AllNotification::send(
|
||||||
|
new SimpleNotification(
|
||||||
|
$this->jobId,
|
||||||
|
"Alerte Robux Eldorado 🤑",
|
||||||
|
$message
|
||||||
|
),
|
||||||
|
$options
|
||||||
|
);
|
||||||
|
|
||||||
|
Log::info("EldoradoRobuxPriceSentryJob: alert sent");
|
||||||
|
} else {
|
||||||
|
Log::info("EldoradoRobuxPriceSentryJob: no alert sent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\InstagramAccount;
|
||||||
|
use App\Models\InstagramRepost;
|
||||||
|
use App\Models\Job;
|
||||||
|
use App\Models\JobInfo;
|
||||||
|
use App\Models\JobInfoType;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$newJobId = 5;
|
||||||
|
Job::forceCreate([
|
||||||
|
"id" => $newJobId,
|
||||||
|
"name" => "Eldorado Robux Price Sentry",
|
||||||
|
"description" => "Surveille les prix des Robux sur Eldorado.",
|
||||||
|
]);
|
||||||
|
|
||||||
|
$decimalType = JobInfoType::create([
|
||||||
|
"name" => "decimal",
|
||||||
|
]);
|
||||||
|
|
||||||
|
JobInfo::forceCreate([
|
||||||
|
"key" => "eldorado_robux_price_threshold",
|
||||||
|
"name" => "Seuil de prix des Robux",
|
||||||
|
"description" => "Le seuil de prix par robux en euros pour déclencher une alerte.",
|
||||||
|
"placeholder" => "0,00350",
|
||||||
|
"is_required" => true,
|
||||||
|
"job_info_type_id" => $decimalType->id,
|
||||||
|
"job_id" => $newJobId,
|
||||||
|
]);
|
||||||
|
|
||||||
|
JobInfo::forceCreate([
|
||||||
|
"key" => "eldorado_robux_price_discord_webhook",
|
||||||
|
"name" => "Webhook Discord pour les alertes de prix des Robux",
|
||||||
|
"description" => "L'URL du webhook Discord pour recevoir les alertes de prix des Robux.",
|
||||||
|
"placeholder" => "https://discord.com/api/webhooks/...",
|
||||||
|
"is_required" => false,
|
||||||
|
"job_info_type_id" => 4,
|
||||||
|
"job_id" => $newJobId,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Job::where("id", 5)->delete();
|
||||||
|
JobInfo::where("job_id", 5)->delete();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -47,7 +47,7 @@ const isActiveJobInfo = ref<JobInfo>({
|
|||||||
description: "Activer le job",
|
description: "Activer le job",
|
||||||
value: props.job.is_active,
|
value: props.job.is_active,
|
||||||
is_required: false,
|
is_required: false,
|
||||||
job_info_type: { name: "checkbox" } as JobInfoType,
|
job_info_type: { name: "boolean" } as JobInfoType,
|
||||||
} as JobInfo);
|
} as JobInfo);
|
||||||
|
|
||||||
async function testJob() {
|
async function testJob() {
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ const jobInfoType = props.jobInfo.job_info_type.name;
|
|||||||
<Label :for="'' + jobInfo.id" class="text">{{ jobInfo.name }}<span v-if="jobInfo.is_required" class="cursor-help" title="Requis" aria-label="Requis">*</span></Label>
|
<Label :for="'' + jobInfo.id" class="text">{{ jobInfo.name }}<span v-if="jobInfo.is_required" class="cursor-help" title="Requis" aria-label="Requis">*</span></Label>
|
||||||
<Description>{{ jobInfo.description }}</Description>
|
<Description>{{ jobInfo.description }}</Description>
|
||||||
<Input v-if="['text', 'email', 'password', 'url', 'number'].includes(jobInfoType)" :type="jobInfoType" :id="'' + jobInfo.id" :name="'' + jobInfo.id" :placeholder="jobInfo.placeholder" v-model="jobInfo.value as string" :required="jobInfo.is_required" />
|
<Input v-if="['text', 'email', 'password', 'url', 'number'].includes(jobInfoType)" :type="jobInfoType" :id="'' + jobInfo.id" :name="'' + jobInfo.id" :placeholder="jobInfo.placeholder" v-model="jobInfo.value as string" :required="jobInfo.is_required" />
|
||||||
<VModelCheckbox v-else :id="'' + jobInfo.id" :class="''" v-model="jobInfo.value as boolean" />
|
<Input v-else-if="jobInfoType == 'decimal'" :type="jobInfoType" :id="'' + jobInfo.id" :name="'' + jobInfo.id" :placeholder="jobInfo.placeholder" v-model="jobInfo.value as number" step="any" :required="jobInfo.is_required" />
|
||||||
|
<VModelCheckbox v-else-if="jobInfoType == 'boolean'" :id="'' + jobInfo.id" v-model="jobInfo.value as boolean" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Browser\Jobs\EldoradoRobuxPriceSentry\EldoradoRobuxPriceSentryJob;
|
||||||
use App\Browser\Jobs\Hellcase\HellcaseJob;
|
use App\Browser\Jobs\Hellcase\HellcaseJob;
|
||||||
use App\Browser\Jobs\HellcaseBattles\HellcaseBattlesJob;
|
use App\Browser\Jobs\HellcaseBattles\HellcaseBattlesJob;
|
||||||
use App\Browser\Jobs\InstagramRepost\InstagramNotificationHandlingJob;
|
use App\Browser\Jobs\InstagramRepost\InstagramNotificationHandlingJob;
|
||||||
@@ -27,3 +28,5 @@ Schedule::job(new HellcaseJob)->daily()->onOneServer()->withoutOverlapping()->na
|
|||||||
Schedule::job(new HellcaseBattlesJob)->hourly()->onOneServer()->withoutOverlapping()->name('hellcase_battles')->description('Hellcase battles job');
|
Schedule::job(new HellcaseBattlesJob)->hourly()->onOneServer()->withoutOverlapping()->name('hellcase_battles')->description('Hellcase battles job');
|
||||||
Schedule::job(new InstagramRepostJob)->everyThreeHours()->onOneServer()->withoutOverlapping()->name('instagram_reposts')->description('Instagram reposts job');
|
Schedule::job(new InstagramRepostJob)->everyThreeHours()->onOneServer()->withoutOverlapping()->name('instagram_reposts')->description('Instagram reposts job');
|
||||||
Schedule::job(new InstagramNotificationHandlingJob)->hourly()->onOneServer()->withoutOverlapping()->name('instagram_reposts_notifications')->description('Instagram reposts notification handling job');
|
Schedule::job(new InstagramNotificationHandlingJob)->hourly()->onOneServer()->withoutOverlapping()->name('instagram_reposts_notifications')->description('Instagram reposts notification handling job');
|
||||||
|
Schedule::job(new EldoradoRobuxPriceSentryJob)->dailyAt("14:00")->onOneServer()->withoutOverlapping()->name('eldorado_robux_price_sentry')->description('Eldorado Robux Price Sentry job');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user