This commit is contained in:
2026-04-16 17:21:48 +03:00
parent c8fa4c442d
commit c8e7e4e927
116 changed files with 3720 additions and 4197 deletions
+70 -70
View File
@@ -1,14 +1,14 @@
import { Injectable, Logger } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';
import { PrismaService } from '../../database/prisma.service';
import { Injectable, Logger } from "@nestjs/common";
import * as fs from "fs";
import * as path from "path";
import { PrismaService } from "../../database/prisma.service";
import {
Sport,
MatchQueryDto,
LeagueWithMatchesDto,
ActiveLeagueDto,
} from './dto';
import { Prisma } from '@prisma/client';
} from "./dto";
import { Prisma } from "@prisma/client";
@Injectable()
export class MatchesService {
@@ -21,9 +21,9 @@ export class MatchesService {
private loadTopLeagues() {
try {
const topLeaguesPath = path.join(process.cwd(), 'top_leagues.json');
const topLeaguesPath = path.join(process.cwd(), "top_leagues.json");
if (fs.existsSync(topLeaguesPath)) {
this.topLeagueIds = JSON.parse(fs.readFileSync(topLeaguesPath, 'utf8'));
this.topLeagueIds = JSON.parse(fs.readFileSync(topLeaguesPath, "utf8"));
this.logger.log(
`Loaded ${this.topLeagueIds.length} top leagues for filtering.`,
);
@@ -39,22 +39,22 @@ export class MatchesService {
{
status: {
in: [
'LIVE',
'1H',
'2H',
'HT',
'1Q',
'2Q',
'3Q',
'4Q',
'Playing',
'Half Time',
"LIVE",
"1H",
"2H",
"HT",
"1Q",
"2Q",
"3Q",
"4Q",
"Playing",
"Half Time",
],
},
},
{
state: {
in: ['live', 'firsthalf', 'secondhalf'],
in: ["live", "firsthalf", "secondhalf"],
},
},
],
@@ -66,12 +66,12 @@ export class MatchesService {
OR: [
{
status: {
in: ['Finished', 'Played', 'FT', 'AET', 'PEN', 'Ended'],
in: ["Finished", "Played", "FT", "AET", "PEN", "Ended"],
},
},
{
state: {
in: ['Finished', 'post', 'FT', 'postGame'],
in: ["Finished", "post", "FT", "postGame"],
},
},
],
@@ -134,16 +134,16 @@ export class MatchesService {
if (leagueId) {
where.leagueId = leagueId;
} else if (status === 'LIVE' && this.topLeagueIds.length > 0) {
} else if (status === "LIVE" && this.topLeagueIds.length > 0) {
// Filter live matches by top leagues by default if no leagueId is provided
where.leagueId = { in: this.topLeagueIds };
}
if (status === 'LIVE') {
if (status === "LIVE") {
andConditions.push(this.getLiveFilter());
} else if (status === 'UPCOMING' || status === 'NOT_STARTED') {
} else if (status === "UPCOMING" || status === "NOT_STARTED") {
andConditions.push(this.getUpcomingFilter(Date.now()));
} else if (status === 'FINISHED') {
} else if (status === "FINISHED") {
andConditions.push(this.getFinishedFilter());
} else if (status) {
where.status = status;
@@ -170,9 +170,9 @@ export class MatchesService {
// Team filter
if (team) {
if (team.role === 'home') {
if (team.role === "home") {
where.homeTeamId = team.id;
} else if (team.role === 'away') {
} else if (team.role === "away") {
where.awayTeamId = team.id;
} else {
andConditions.push({
@@ -197,7 +197,7 @@ export class MatchesService {
const matches = await this.prisma.liveMatch.findMany({
where,
select: { id: true },
orderBy: { mstUtc: 'asc' }, // Sort by nearest match first
orderBy: { mstUtc: "asc" }, // Sort by nearest match first
take: limit,
});
@@ -220,7 +220,7 @@ export class MatchesService {
AND: [this.getUpcomingFilter(Date.now())],
},
select: { id: true },
orderBy: { mstUtc: 'asc' },
orderBy: { mstUtc: "asc" },
take: limit,
});
console.log(
@@ -283,16 +283,16 @@ export class MatchesService {
const leaguesMap = new Map<string, LeagueWithMatchesDto>();
for (const match of matches) {
const leagueId = match.leagueId || 'unknown';
const leagueId = match.leagueId || "unknown";
if (!leaguesMap.has(leagueId)) {
leaguesMap.set(leagueId, {
id: leagueId,
name: match.league?.name || 'Unknown League',
name: match.league?.name || "Unknown League",
code: match.league?.code || undefined,
country: {
id: match.league?.country?.id || '',
name: match.league?.country?.name || '',
id: match.league?.country?.id || "",
name: match.league?.country?.name || "",
flagUrl: match.league?.country?.flagUrl || undefined,
},
sport: sport,
@@ -306,13 +306,13 @@ export class MatchesService {
const structuredOdds: any[] = [];
if (
match.odds &&
typeof match.odds === 'object' &&
typeof match.odds === "object" &&
!Array.isArray(match.odds)
) {
const oddsObj = match.odds as Record<string, Record<string, number>>;
for (const [marketName, selections] of Object.entries(oddsObj)) {
const structuredSelections: Record<string, { odd: string }> = {};
if (selections && typeof selections === 'object') {
if (selections && typeof selections === "object") {
for (const [selName, selOdd] of Object.entries(selections)) {
structuredSelections[selName] = { odd: String(selOdd) };
}
@@ -325,15 +325,15 @@ export class MatchesService {
}
// Map status for frontend
let displayStatus = match.status || 'NS';
if (match.state === 'live') {
displayStatus = 'LIVE';
let displayStatus = match.status || "NS";
if (match.state === "live") {
displayStatus = "LIVE";
} else if (
match.state === 'post' ||
match.state === 'FT' ||
match.status === 'Finished'
match.state === "post" ||
match.state === "FT" ||
match.status === "Finished"
) {
displayStatus = 'Finished';
displayStatus = "Finished";
}
league.matches.push({
@@ -349,11 +349,11 @@ export class MatchesService {
scoreAway: match.scoreAway ?? undefined,
htScoreHome: undefined, // LiveMatch table doesn't have HT scores separately usually
htScoreAway: undefined,
homeTeamName: match.homeTeam?.name || 'Unknown',
homeTeamName: match.homeTeam?.name || "Unknown",
homeTeamLogo: match.homeTeamId
? `https://file.mackolikfeeds.com/teams/${match.homeTeamId}`
: undefined,
awayTeamName: match.awayTeam?.name || 'Unknown',
awayTeamName: match.awayTeam?.name || "Unknown",
awayTeamLogo: match.awayTeamId
? `https://file.mackolikfeeds.com/teams/${match.awayTeamId}`
: undefined,
@@ -390,15 +390,15 @@ export class MatchesService {
// Priority sorting (Mackolik style)
const PRIORITY = [
'Trendyol Süper Lig',
'Süper Lig',
'Trendyol 1. Lig',
'1. Lig',
'Premier Lig',
'LaLiga',
'Serie A',
'Bundesliga',
'Ligue 1',
"Trendyol Süper Lig",
"Süper Lig",
"Trendyol 1. Lig",
"1. Lig",
"Premier Lig",
"LaLiga",
"Serie A",
"Bundesliga",
"Ligue 1",
];
return leagues
@@ -410,7 +410,7 @@ export class MatchesService {
const bPriority = bIdx === -1 ? 999 : bIdx;
if (aPriority !== bPriority) return aPriority - bPriority;
return (a.name || '').localeCompare(b.name || '');
return (a.name || "").localeCompare(b.name || "");
})
.map((l) => ({
id: l.id,
@@ -439,7 +439,7 @@ export class MatchesService {
include: { country: true },
},
},
orderBy: { mstUtc: 'desc' },
orderBy: { mstUtc: "desc" },
skip,
take: limit,
}),
@@ -482,7 +482,7 @@ export class MatchesService {
createdAt: stat.createdAt,
};
if ((sport || '').toLowerCase() === 'basketball') {
if ((sport || "").toLowerCase() === "basketball") {
return {
...base,
points: stat.points,
@@ -532,7 +532,7 @@ export class MatchesService {
basketballTeamStats: true,
playerParticipations: {
include: { player: true },
orderBy: [{ isStarting: 'desc' }, { position: 'asc' }],
orderBy: [{ isStarting: "desc" }, { position: "asc" }],
},
playerEvents: {
include: {
@@ -540,7 +540,7 @@ export class MatchesService {
assistPlayer: true,
substitutedOut: true,
},
orderBy: [{ periodId: 'asc' }, { timeMinute: 'asc' }],
orderBy: [{ periodId: "asc" }, { timeMinute: "asc" }],
},
oddCategories: {
include: { selections: true },
@@ -562,15 +562,15 @@ export class MatchesService {
if (liveMatch) {
// Map liveMatch status
let displayStatus = liveMatch.status || 'NS';
if (liveMatch.state === 'live') {
displayStatus = 'LIVE';
let displayStatus = liveMatch.status || "NS";
if (liveMatch.state === "live") {
displayStatus = "LIVE";
} else if (
liveMatch.state === 'post' ||
liveMatch.state === 'FT' ||
liveMatch.status === 'Finished'
liveMatch.state === "post" ||
liveMatch.state === "FT" ||
liveMatch.status === "Finished"
) {
displayStatus = 'Finished';
displayStatus = "Finished";
}
match = {
@@ -607,14 +607,14 @@ export class MatchesService {
if (
match.isLiveSource &&
match.odds &&
typeof match.odds === 'object' &&
typeof match.odds === "object" &&
!Array.isArray(match.odds)
) {
// Parse JSON odds from LiveMatch
const oddsObj = match.odds as Record<string, Record<string, number>>;
for (const [marketName, selections] of Object.entries(oddsObj)) {
odds[marketName] = {};
if (selections && typeof selections === 'object') {
if (selections && typeof selections === "object") {
for (const [selName, selOdd] of Object.entries(selections)) {
odds[marketName][selName] = { odd: String(selOdd) };
}
@@ -628,7 +628,7 @@ export class MatchesService {
for (const sel of cat.selections) {
if (sel.name) {
odds[cat.name][sel.name] = {
odd: sel.oddValue || '',
odd: sel.oddValue || "",
sov: sel.sov ?? undefined,
};
}
@@ -637,7 +637,7 @@ export class MatchesService {
}
const sportStats =
match.sport === 'basketball'
match.sport === "basketball"
? match.basketballTeamStats || []
: match.footballTeamStats || [];
const normalizedTeamStats = sportStats.map((s: any) =>
@@ -692,7 +692,7 @@ export class MatchesService {
// Fuzzy search
team = await this.prisma.team.findFirst({
where: {
name: { contains: trimmedName, mode: 'insensitive' },
name: { contains: trimmedName, mode: "insensitive" },
sport: sport as any,
},
select: { id: true },