@@ -20,100 +20,53 @@ import {
|
||||
@Injectable()
|
||||
export class MatchesService {
|
||||
private readonly logger = new Logger(MatchesService.name);
|
||||
private qualifiedLeagueIds: string[] = [];
|
||||
private topLeagueIds: string[] = [];
|
||||
|
||||
constructor(private readonly prisma: PrismaService) {
|
||||
this.loadQualifiedLeagues();
|
||||
this.loadTopLeagues();
|
||||
}
|
||||
|
||||
private loadTopLeagues() {
|
||||
try {
|
||||
const topLeaguesPath = path.join(process.cwd(), "top_leagues.json");
|
||||
if (fs.existsSync(topLeaguesPath)) {
|
||||
this.topLeagueIds = JSON.parse(fs.readFileSync(topLeaguesPath, "utf8"));
|
||||
this.logger.log(
|
||||
`Loaded ${this.topLeagueIds.length} top leagues for filtering.`,
|
||||
);
|
||||
const filePath = path.join(process.cwd(), "top_leagues.json");
|
||||
if (fs.existsSync(filePath)) {
|
||||
this.topLeagueIds = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.warn(`Failed to load top_leagues.json: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate flag URL from country code or name using flagcdn.com
|
||||
* Falls back to a name-to-code mapping for Turkish country names
|
||||
*/
|
||||
private getCountryFlagUrl(
|
||||
countryCode?: string | null,
|
||||
countryName?: string | null,
|
||||
): string | undefined {
|
||||
// If we have a 2-letter ISO code, use it directly
|
||||
if (countryCode && countryCode.length === 2) {
|
||||
return `https://flagcdn.com/w40/${countryCode.toLowerCase()}.png`;
|
||||
}
|
||||
|
||||
// Fallback: map common Turkish country names to ISO codes
|
||||
const COUNTRY_NAME_TO_CODE: Record<string, string> = {
|
||||
"Türkiye": "tr",
|
||||
"İngiltere": "gb-eng",
|
||||
"İspanya": "es",
|
||||
"İtalya": "it",
|
||||
"Almanya": "de",
|
||||
"Fransa": "fr",
|
||||
"Portekiz": "pt",
|
||||
"Hollanda": "nl",
|
||||
"Belçika": "be",
|
||||
"İskoçya": "gb-sct",
|
||||
"Galler": "gb-wls",
|
||||
"İrlanda": "ie",
|
||||
"Avusturya": "at",
|
||||
"İsviçre": "ch",
|
||||
"Yunanistan": "gr",
|
||||
"Polonya": "pl",
|
||||
"Çekya": "cz",
|
||||
"Hırvatistan": "hr",
|
||||
"Sırbistan": "rs",
|
||||
"Danimarka": "dk",
|
||||
"Norveç": "no",
|
||||
"İsveç": "se",
|
||||
"Finlandiya": "fi",
|
||||
"Rusya": "ru",
|
||||
"Ukrayna": "ua",
|
||||
"Romanya": "ro",
|
||||
"Macaristan": "hu",
|
||||
"Bulgaristan": "bg",
|
||||
"Arjantin": "ar",
|
||||
"Brezilya": "br",
|
||||
"Meksika": "mx",
|
||||
"ABD": "us",
|
||||
"Japonya": "jp",
|
||||
"Güney Kore": "kr",
|
||||
"Çin": "cn",
|
||||
"Avustralya": "au",
|
||||
"Suudi Arabistan": "sa",
|
||||
"BAE": "ae",
|
||||
"Katar": "qa",
|
||||
"Mısır": "eg",
|
||||
"Güney Afrika": "za",
|
||||
"Kolombiya": "co",
|
||||
"Şili": "cl",
|
||||
"Peru": "pe",
|
||||
"Ekvador": "ec",
|
||||
"Paraguay": "py",
|
||||
"Uruguay": "uy",
|
||||
"Avrupa": "eu",
|
||||
"Dünya": "un",
|
||||
};
|
||||
|
||||
if (countryName) {
|
||||
const code = COUNTRY_NAME_TO_CODE[countryName];
|
||||
if (code) {
|
||||
return `https://flagcdn.com/w40/${code}.png`;
|
||||
private loadQualifiedLeagues() {
|
||||
try {
|
||||
const filePath = path.join(process.cwd(), "qualified_leagues.json");
|
||||
if (fs.existsSync(filePath)) {
|
||||
this.qualifiedLeagueIds = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||
this.logger.log(
|
||||
`Loaded ${this.qualifiedLeagueIds.length} qualified leagues for filtering.`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.warn(`Failed to load qualified_leagues.json: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
/**
|
||||
* Generate URL for the country flag served from Mackolik
|
||||
*/
|
||||
private getCountryFlagUrl(countryId?: string | null): string | undefined {
|
||||
if (!countryId) return undefined;
|
||||
return `https://file.mackolikfeeds.com/areas/${countryId}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate URL for the team logo served from local uploads
|
||||
*/
|
||||
private getTeamLogoUrl(teamId?: string | null): string | undefined {
|
||||
if (!teamId) return undefined;
|
||||
return `https://file.mackolikfeeds.com/teams/${teamId}`;
|
||||
}
|
||||
|
||||
private getLiveFilter(): Prisma.LiveMatchWhereInput {
|
||||
@@ -215,10 +168,9 @@ export class MatchesService {
|
||||
|
||||
if (leagueId) {
|
||||
where.leagueId = leagueId;
|
||||
} else if (this.topLeagueIds.length > 0) {
|
||||
// Always filter by top leagues when no specific leagueId is requested
|
||||
// This ensures match list is consistent with the active leagues sidebar
|
||||
where.leagueId = { in: this.topLeagueIds };
|
||||
} else if (this.qualifiedLeagueIds.length > 0) {
|
||||
// Only show matches from qualified leagues (leagues with historical data for AI analysis)
|
||||
where.leagueId = { in: this.qualifiedLeagueIds };
|
||||
}
|
||||
|
||||
if (status === "LIVE") {
|
||||
@@ -375,7 +327,9 @@ export class MatchesService {
|
||||
country: {
|
||||
id: match.league?.country?.id || "",
|
||||
name: match.league?.country?.name || "",
|
||||
flagUrl: match.league?.country?.flagUrl || this.getCountryFlagUrl(null, match.league?.country?.name),
|
||||
flagUrl:
|
||||
match.league?.country?.flagUrl ||
|
||||
this.getCountryFlagUrl(match.league?.country?.id),
|
||||
},
|
||||
sport: sport,
|
||||
matches: [],
|
||||
@@ -430,11 +384,11 @@ export class MatchesService {
|
||||
htScoreAway: undefined,
|
||||
homeTeamName: match.homeTeam?.name || "Unknown",
|
||||
homeTeamLogo: match.homeTeamId
|
||||
? `https://file.mackolikfeeds.com/teams/${match.homeTeamId}`
|
||||
? this.getTeamLogoUrl(match.homeTeamId)
|
||||
: undefined,
|
||||
awayTeamName: match.awayTeam?.name || "Unknown",
|
||||
awayTeamLogo: match.awayTeamId
|
||||
? `https://file.mackolikfeeds.com/teams/${match.awayTeamId}`
|
||||
? this.getTeamLogoUrl(match.awayTeamId)
|
||||
: undefined,
|
||||
leagueName: match.league?.name,
|
||||
countryName: match.league?.country?.name,
|
||||
@@ -442,7 +396,15 @@ export class MatchesService {
|
||||
});
|
||||
}
|
||||
|
||||
return Array.from(leaguesMap.values());
|
||||
return Array.from(leaguesMap.values()).sort((a, b) => {
|
||||
const aIdx = this.topLeagueIds.indexOf(a.id);
|
||||
const bIdx = this.topLeagueIds.indexOf(b.id);
|
||||
const aPriority = aIdx === -1 ? 999 : aIdx;
|
||||
const bPriority = bIdx === -1 ? 999 : bIdx;
|
||||
|
||||
if (aPriority !== bPriority) return aPriority - bPriority;
|
||||
return (a.name || "").localeCompare(b.name || "");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,6 +427,7 @@ export class MatchesService {
|
||||
const leagues = await this.prisma.$queryRaw<any[]>`
|
||||
SELECT
|
||||
l.id, l.name, l.code,
|
||||
c.id as country_id,
|
||||
c.name as country_name,
|
||||
c.flag_url as country_flag,
|
||||
COUNT(lm.id)::int as match_count,
|
||||
@@ -474,34 +437,21 @@ export class MatchesService {
|
||||
JOIN leagues l ON lm.league_id = l.id
|
||||
LEFT JOIN countries c ON l.country_id = c.id
|
||||
WHERE lm.sport = ${sport}
|
||||
${this.topLeagueIds.length > 0 ? Prisma.sql`AND l.id IN (${Prisma.join(this.topLeagueIds)})` : Prisma.empty}
|
||||
${this.qualifiedLeagueIds.length > 0 ? Prisma.sql`AND l.id IN (${Prisma.join(this.qualifiedLeagueIds)})` : Prisma.empty}
|
||||
AND (
|
||||
(lm.mst_utc >= ${todayMs} AND lm.status NOT IN (${Prisma.join(finishedStatuses)}) AND COALESCE(lm.state, '') NOT IN (${Prisma.join(finishedStates)}))
|
||||
OR lm.status IN (${Prisma.join(liveStatuses)})
|
||||
OR lm.state IN (${Prisma.join(liveStates)})
|
||||
)
|
||||
GROUP BY l.id, l.name, l.code, c.name, c.flag_url
|
||||
GROUP BY l.id, l.name, l.code, c.id, c.name, c.flag_url
|
||||
ORDER BY l.name ASC
|
||||
`;
|
||||
|
||||
// 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",
|
||||
];
|
||||
|
||||
return leagues
|
||||
.filter((l) => l.match_count > 0)
|
||||
.sort((a, b) => {
|
||||
const aIdx = PRIORITY.findIndex((p) => a.name?.includes(p));
|
||||
const bIdx = PRIORITY.findIndex((p) => b.name?.includes(p));
|
||||
const aIdx = this.topLeagueIds.indexOf(a.id);
|
||||
const bIdx = this.topLeagueIds.indexOf(b.id);
|
||||
|
||||
const aPriority = aIdx === -1 ? 999 : aIdx;
|
||||
const bPriority = bIdx === -1 ? 999 : bIdx;
|
||||
@@ -514,7 +464,7 @@ export class MatchesService {
|
||||
name: l.name,
|
||||
code: l.code,
|
||||
countryName: l.country_name,
|
||||
countryFlag: l.country_flag || this.getCountryFlagUrl(null, l.country_name),
|
||||
countryFlag: l.country_flag || this.getCountryFlagUrl(l.country_id),
|
||||
matchCount: l.match_count,
|
||||
liveCount: l.live_count,
|
||||
}));
|
||||
@@ -553,13 +503,9 @@ export class MatchesService {
|
||||
scoreAway: m.scoreAway,
|
||||
status: m.status,
|
||||
homeTeamName: m.homeTeam?.name,
|
||||
homeTeamLogo: m.homeTeamId
|
||||
? `https://file.mackolikfeeds.com/teams/${m.homeTeamId}`
|
||||
: null,
|
||||
homeTeamLogo: m.homeTeamId ? this.getTeamLogoUrl(m.homeTeamId) : null,
|
||||
awayTeamName: m.awayTeam?.name,
|
||||
awayTeamLogo: m.awayTeamId
|
||||
? `https://file.mackolikfeeds.com/teams/${m.awayTeamId}`
|
||||
: null,
|
||||
awayTeamLogo: m.awayTeamId ? this.getTeamLogoUrl(m.awayTeamId) : null,
|
||||
leagueName: m.league?.name,
|
||||
countryName: m.league?.country?.name,
|
||||
})),
|
||||
@@ -860,13 +806,13 @@ export class MatchesService {
|
||||
homeTeam: {
|
||||
...match.homeTeam,
|
||||
logo: match.homeTeamId
|
||||
? `https://file.mackolikfeeds.com/teams/${match.homeTeamId}`
|
||||
? this.getTeamLogoUrl(match.homeTeamId)
|
||||
: match.homeTeam?.logoUrl || null,
|
||||
},
|
||||
awayTeam: {
|
||||
...match.awayTeam,
|
||||
logo: match.awayTeamId
|
||||
? `https://file.mackolikfeeds.com/teams/${match.awayTeamId}`
|
||||
? this.getTeamLogoUrl(match.awayTeamId)
|
||||
: match.awayTeam?.logoUrl || null,
|
||||
},
|
||||
stats: {
|
||||
|
||||
Reference in New Issue
Block a user