@@ -82,14 +82,14 @@ interface UpcomingMatchRow {
|
|||||||
|
|
||||||
const MIN_MATCHES = 3;
|
const MIN_MATCHES = 3;
|
||||||
|
|
||||||
const GOLCU_LEAGUES = new Set([
|
// const GOLCU_LEAGUES = new Set([
|
||||||
// Strategy generator'dan türetilen yüksek golcü ligler
|
// // Strategy generator'dan türetilen yüksek golcü ligler
|
||||||
// Lig isimleri veritabanındaki gibi
|
// // Lig isimleri veritabanındaki gibi
|
||||||
]);
|
// ]);
|
||||||
|
|
||||||
const DEFANSIF_LEAGUES = new Set([
|
// const DEFANSIF_LEAGUES = new Set([
|
||||||
// Düşük golcü ligler
|
// // Düşük golcü ligler
|
||||||
]);
|
// ]);
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// Service
|
// Service
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
FrequencyEngineService,
|
FrequencyEngineService,
|
||||||
type MatchCandidate,
|
type MatchCandidate,
|
||||||
type FrequencySignal,
|
|
||||||
} from "./frequency-engine.service";
|
} from "./frequency-engine.service";
|
||||||
|
|
||||||
export type PredictionRiskLevel = "LOW" | "MEDIUM" | "HIGH" | "EXTREME";
|
export type PredictionRiskLevel = "LOW" | "MEDIUM" | "HIGH" | "EXTREME";
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export class PredictionsController {
|
|||||||
|
|
||||||
const cached = await this.predictionsService.getCachedPrediction(matchId);
|
const cached = await this.predictionsService.getCachedPrediction(matchId);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
await this.analysisService.recordUsage(user.id, false);
|
// Do not record usage for cached predictions
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1295,8 +1295,8 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
|||||||
): Promise<MatchPredictionDto | null> {
|
): Promise<MatchPredictionDto | null> {
|
||||||
const memCached = this.predictionMemCache.get(matchId);
|
const memCached = this.predictionMemCache.get(matchId);
|
||||||
if (memCached) {
|
if (memCached) {
|
||||||
if (Date.now() - memCached.timestamp < 10 * 60 * 1000) {
|
if (Date.now() - memCached.timestamp < 5 * 60 * 1000) {
|
||||||
// 10 mins TTL
|
// 5 mins TTL
|
||||||
return memCached.payload;
|
return memCached.payload;
|
||||||
} else {
|
} else {
|
||||||
this.predictionMemCache.delete(matchId);
|
this.predictionMemCache.delete(matchId);
|
||||||
@@ -1312,7 +1312,7 @@ export class PredictionsService implements OnModuleInit, OnModuleDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cacheAge = Date.now() - prediction.updatedAt.getTime();
|
const cacheAge = Date.now() - prediction.updatedAt.getTime();
|
||||||
if (cacheAge > 6 * 60 * 60 * 1000) {
|
if (cacheAge > 1 * 60 * 60 * 1000) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export class ImageRendererService implements OnModuleInit {
|
|||||||
this.drawMatchBlock(ctx, data, theme, homeImg, awayImg);
|
this.drawMatchBlock(ctx, data, theme, homeImg, awayImg);
|
||||||
this.drawScoreBlock(ctx, data, theme);
|
this.drawScoreBlock(ctx, data, theme);
|
||||||
this.drawPicks(ctx, data.topPicks, theme);
|
this.drawPicks(ctx, data.topPicks, theme);
|
||||||
this.drawFooter(ctx, data, theme);
|
this.drawFooter(ctx, data);
|
||||||
|
|
||||||
const buffer = canvas.toBuffer("image/jpeg", { quality: 0.94 });
|
const buffer = canvas.toBuffer("image/jpeg", { quality: 0.94 });
|
||||||
fs.writeFileSync(outPath, buffer);
|
fs.writeFileSync(outPath, buffer);
|
||||||
@@ -460,7 +460,7 @@ export class ImageRendererService implements OnModuleInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private drawFooter(ctx: any, data: PredictionCardDto, theme: Theme) {
|
private drawFooter(ctx: any, data: PredictionCardDto) {
|
||||||
const riskText = `Risk: ${this.translateRisk(data.riskLevel)}`;
|
const riskText = `Risk: ${this.translateRisk(data.riskLevel)}`;
|
||||||
ctx.font = "900 34px Arial";
|
ctx.font = "900 34px Arial";
|
||||||
const riskW = Math.ceil(ctx.measureText(riskText).width + 72);
|
const riskW = Math.ceil(ctx.measureText(riskText).width + 72);
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import {
|
import { IsString, IsOptional, IsEnum } from "class-validator";
|
||||||
IsString,
|
|
||||||
IsOptional,
|
|
||||||
IsEnum,
|
|
||||||
IsDateString,
|
|
||||||
IsInt,
|
|
||||||
} from "class-validator";
|
|
||||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
import { Exclude, Expose, Type } from "class-transformer";
|
import { Exclude, Expose } from "class-transformer";
|
||||||
|
|
||||||
export enum PlanType {
|
export enum PlanType {
|
||||||
FREE = "free",
|
FREE = "free",
|
||||||
|
|||||||
@@ -9,15 +9,6 @@ export interface PaddleWebhookEvent {
|
|||||||
notification_id: string;
|
notification_id: string;
|
||||||
data: Record<string, unknown>;
|
data: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PaddleTransactionResponse {
|
|
||||||
data: {
|
|
||||||
id: string;
|
|
||||||
customer_id: string;
|
|
||||||
status: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PaddleService {
|
export class PaddleService {
|
||||||
private readonly logger = new Logger(PaddleService.name);
|
private readonly logger = new Logger(PaddleService.name);
|
||||||
|
|||||||
@@ -108,10 +108,10 @@ export class SubscriptionsService {
|
|||||||
await this.handleSubscriptionResumed(data);
|
await this.handleSubscriptionResumed(data);
|
||||||
break;
|
break;
|
||||||
case "transaction.completed":
|
case "transaction.completed":
|
||||||
this.logger.log(`Transaction completed: ${data.id}`);
|
this.logger.log(`Transaction completed: ${String(data.id)}`);
|
||||||
break;
|
break;
|
||||||
case "transaction.payment_failed":
|
case "transaction.payment_failed":
|
||||||
this.logger.warn(`Payment failed for transaction: ${data.id}`);
|
this.logger.warn(`Payment failed for transaction: ${String(data.id)}`);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.logger.debug(`Unhandled Paddle event: ${eventType}`);
|
this.logger.debug(`Unhandled Paddle event: ${eventType}`);
|
||||||
|
|||||||
@@ -466,8 +466,8 @@ export class DataFetcherTask {
|
|||||||
): { outcome: string; unitProfit: number } | null {
|
): { outcome: string; unitProfit: number } | null {
|
||||||
const summary = this.asRecord(row.payloadSummary);
|
const summary = this.asRecord(row.payloadSummary);
|
||||||
const mainPick = this.asRecord(summary.main_pick);
|
const mainPick = this.asRecord(summary.main_pick);
|
||||||
const market = String(mainPick.market || "");
|
const market = typeof mainPick.market === "string" ? mainPick.market : "";
|
||||||
const pick = String(mainPick.pick || "");
|
const pick = typeof mainPick.pick === "string" ? mainPick.pick : "";
|
||||||
const playable = mainPick.playable === true;
|
const playable = mainPick.playable === true;
|
||||||
const odds = Number(mainPick.odds || 0);
|
const odds = Number(mainPick.odds || 0);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user