pgx
PGX — Lightweight Postgres for AI agents. Written in Rust. Thousands of isolated databases in one runtime. 🐘
翻译准备中
넥슨 오픈API로 EA SPORTS FC 온라인 감독모드 전적을 조회·집계하는 PyQt6 데스크톱 앱 (승률·선수 지표·전술 상성·슛 맵, SQLite 누적 저장)
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
넥슨 오픈API로 EA SPORTS FC 온라인 전적을 조회·집계하는 PyQt6 데스크톱 앱(윈도우). 구단주 닉네임을 검색하면 감독모드 전적을 받아와 승률·선수 지표·전술 상성 등을 화면으로 보여준다. v0.3.0 까지의 이름은 "피파 전적관리" — 저장소·데이터 폴더·exe 이름은 업데이트가 끊기지 않게 그대로 뒀다. 넥슨(NEXON)·EA 와 관련 없는 비공식 프로그램입니다. FC 온라인·EA SPORTS FC 는 각 사의 상표입니다. 무료이며 있는 그대로 제공되고, 쓰다 생긴 손해는 책임지지 않습니다. 자세한 것은 아래 이용 안내.查看完整 README ↗
넥슨 오픈API로 EA SPORTS FC 온라인 전적을 조회·집계하는 PyQt6 데스크톱 앱(윈도우). 구단주 닉네임을 검색하면 감독모드 전적을 받아와 승률·선수 지표·전술 상성 등을 화면으로 보여준다. v0.3.0 까지의 이름은 "피파 전적관리" — 저장소·데이터 폴더·exe 이름은 업데이트가 끊기지 않게 그대로 뒀다.
넥슨(NEXON)·EA 와 관련 없는 비공식 프로그램입니다. FC 온라인·EA SPORTS FC 는 각 사의 상표입니다. 무료이며 있는 그대로 제공되고, 쓰다 생긴 손해는 책임지지 않습니다. 자세한 것은 아래 이용 안내.
.env 의 FIFA_WEB_DATA=1). 끄면 랭커 카드·팀컬러·시즌 구분·선수 카드가 빈다.
요청에는 브라우저인 척하지 않고 앱 이름(FifaMatchTracker/<버전>)을 UA 로 밝힌다fifa.db)에 누적 — API가 과거를 무한히 주지는 않기 때문%LOCALAPPDATA%\피파전적관리\.env 에 저장, 저장소에 포함되지 않음). 넥슨이 키를 거절하면(만료·폐기) 그 자리에서 다시 묻는다| 메뉴 / 기능 | 내용 |
|---|---|
| 흐름 분석 | 집계를 문장으로 — 최근 흐름과 이기는/지는 방식을 글로 설명 · 연승·연패 직후 다음 경기 승률(전체 대비 ±%p) · 맨 위 강점·약점 칩(결정력·유효슛 비율·태클 성공 — 같은 경기 상대와 견줘 95% 구간이 0 을 안 품고 차이가 2.5%p 이상일 때만) · '마무리인가 창출인가'·'전반·후반 어디서 새나' 문장 |
| 전적 | 최근 경기 목록 — 결과·스코어·상대·점유율·슛 등 · 결과 필터 · 상대 팀컬러로 거르기(팀컬러를 조회한 상대만) · 찾기 칸 하나로 닉네임·팀컬러 찾기 · 상대 줄마다 (조회한 상대만)와 (고른 시즌) · — 내 계정 경기만, 최근 14일은 그날 수집 원본에서 꺼낸 정확한 점수·순위(저장하지 않고 보여 주기만), 그보다 옛 경기는 순위 구간 · 이 넷은 [상대 정보] 로 끄고 켜며, 창이 좁으면(1280 폭 등) 저절로 접힌다 · 오른쪽 클릭 (브라우저로 그 닉네임 검색) |
| 선수 지표 | [지표] 선수별 출전·평점·공격력·수비력·기대득점률·선방력(공식 미제공 값 역산) · [랭커 비교] 아래 |
| 전술·경기 결과 | [전술] 상대 전술(포메이션)별 승률(그대로 · 수비 줄 수 · 앞줄 수로 묶기) · [경기 결과] 결과·득점·실점 유형 분포 · [패스 스타일] 종류 6가지 비중·성공률, 이긴/진 경기 비교 |
| 상대 전적 | [전적] 구단주별 상성 — 매치업 필터(최근 50·100·200·500경기·직접 지정 · 상대마다 판수 1·3·5·10 미만 빼기 · 내 포메이션 · 상대의 지금 구단가치 칸(마지막 랭킹 스냅숏의 8분위 · 모름 따로)) · 승률 옆 전체 대비(필터에 걸린 경기 전체와의 차 · 8판 미만 상대는 비움) · 오른쪽 클릭 넥슨 데이터센터에서 보기 · [상대 순위] 내 경기마다 상대가 그날 몇 위 구간이었는지(1 |
| 포지션별 최다 상대 | [축구장] 열면 빈 화면 — 상대 팀컬러(찾기 칸)를 고르면 그 팀컬러 상대가 많이 쓴 포메이션이 사용 많은 순 3개(사용률·경기 수)로 나오고, 고른 포메이션의 11자리에 그 자리에서 가장 많이 만난 상대 카드를 채운다(만난 횟수·비율 · 가장 많이 쓴 포메이션이 먼저 눌려 있다 · 같은 포메이션 안에서는 가장 흔한 자리 구성 하나만 — RM 과 LAM 처럼 좌우가 다른 줄인 구성은 고르지 않는다) · 아래 접힌 표. [카드별] 자리를 고르면 상대가 그 자리에 쓴 카드 전부 — 사용률(그 자리가 나온 판 중) · 만난 판 · 그 카드를 만난 판의 내 승·무·패와 승률 · 팀컬러로 거르기 · "1만 위 안 상대만"(최근 14일 랭킹 수집 닉네임) |
| 팀컬러 | [팀컬러 승률] 상대 팀컬러별 경기·상대 수·승무패·승률 · "평균 대비"(팀컬러를 아는 경기 승률과의 차이) · 승률 칸 색 · 표본 적으면 흐림(정렬해도 맨 아래) · [팀컬러 랭킹] 만난 횟수·평균/최저/최고 팀가치 + 범위 막대(로그). 두 표 공용 최소 경기 수 필터 · 팀컬러 종류(국가·클럽·강화)·비주류만(랭킹 1만 명 중 100명 미만) 거르기 (2.13.1 — 랭커 메타 분석 표와 같은 값) · "효과" 열 [보기] → 넥슨 데이터센터 단계별 효과·적용 선수(100명씩 [더 보기] · 누를 때만 요청 · 7일 캐시) 창. 이름이 같은 강화·클럽 팀컬러(11쌍)는 엠블럼으로 갈라 "이름 · 강화"/"이름 · 클럽" |
| 구단주 비교 | 내 계정과 상대 최근 N경기, 탭 셋 — [지표·스쿼드] 승률·득실·점유율·평점·경기당 슛·유효슛 비율·패스/태클 성공률 · 차이가 뚜렷한 지표 최대 4개 요약(경기별 값의 z ≥ 2.5 · 양쪽 10경기 이상일 때만) · 키플레이어(골·평점 상위 3) · 양쪽 최근 스쿼드 축구장 / [슛·골 흐름] 두 사람의 슛 지도·결정력과 리드·골 흐름 나란히 / [자리별] 공격·미드·수비·GK 줄마다 가장 많이 세운 카드끼리 경기당 값. 새 요청 없이 이미 받은 상세만 쓴다 |
| 스쿼드 축구장 | 경기 목록 → 상대 스쿼드 · 구단주 비교 — 칩마다 포지션·강화 반영 OVR·강화·시세·이름, 위 띠에 스쿼드 가치·급여 합. 시세·급여·OVR 은 홈페이지에서 하루 최대 60장 자동으로(이용 안내 5 동의 뒤 · 캐시 우선) |
| 승률 그래프 | [승률·등급] 최근 N일 일별 승률(50% 기준선·7일 이동평균·경기 수 띠) · 하루 단위 등급(디비전) 계단 그래프(아래 막대로 구간 확대 — 14일 이하면 경기마다 점) · 슈퍼 챔피언스 달성 기록(날짜·시각) · [점수·예측] 지금 시즌 ELO 그래프(200·1,000위 컷 · 따라가기 · 순위 점선과 오른쪽 순위 축 (2.13.1)) · 시즌 점수 리포트(평균 · 가장 깊었던 하락과 같은 최고점 구간 중앙값 · 하루 평균 변화·오른 날·무승부 뺀 승률로 오르는 구간인가 — 하루 점 7개부터) · 구단가치 일별 그래프(검색·따라가기 때 적은 데이터센터 값) · 시즌 말 순위 예측(200위·1,000위 안 확률 · 예상 순위 범위 — 랭킹 수집이 켜져 있을 때 · 같은 카드에 200위·1,000위 예상 컷 점수(중앙값과 10~90% 범위) · 200위 안에 들려면 더 필요한 점수와 하루 판수 페이스 · 200위 안 확률과 주로 들 순위 보상 구간(FC — 넥슨 공식이 아니라 확인값)) · [일별 기록] 한 달 달력 — 날마다 승률·판수·FC, 그 시즌 승률 ± 2σ 밖인 날 ▲▼(5판 이상) · 이 달·이 시즌 하루 평균 · [순위 변동] 검색한 계정이 랭킹 수집 스냅숏 사이마다 왜 순위가 바뀌었나(경기 · 경기 + 스쿼드 · 스쿼드만 · 점수만 바뀜 · 밀림 · 1만 위 밖 · 수집 빠짐)와 포메이션·팀컬러·닉네임 바뀜 이력 — 최근 14일 |
| 기간별 추이 | 1일/2일/1주/1개월 단위 승률 그래프 + 전적 표(평균 대비 · 최고/최저 기간) + 연승·연패 기록 |
| 시즌별 성적 | 감독모드 랭킹 시즌별 승률 막대 + 전적·승률·지난 시즌 대비·등급 변화·평균 득실 비교 |
| 승부처 분석 | [선제골·역전] 선제골 승률, 시간대별 득실 분포, 시각대별 승률 · [리드·골 흐름] 최대 리드별 결과, 내 골의 성격(앞서는·동점·추격·쐐기·벌리기), 지고 있을 때 다음 골, 골 사이 시간 |
| 성적 진단 | [상대·점유율] 상대 등급(디비전)별 승률·평균 득실, 점유율 구간별 승률 · [규율·불운] (파울·경고·퇴장·오프사이드·코너킥·골대 나/상대 평균 · 골대·퇴장 경기 승률 · 종료 유형별 경기 수) · [등급 체류] 등급마다 머문 경기·날·승강 횟수 · [운 범위] 하루 승률이 운만으로 흔들릴 폭(평균 ± 2σ 띠 밖인 날 수 대 기대) · 몇 판부터 실력 차이로 읽나 · 최장 연승·연패의 우연 기준 · [경기 습관] 직전 경기 간격·세션 순번·시간대별 승률(표마다 카이제곱 판정) · [FC 보상] 이긴 경기마다 그 경기 등급의 승리 보상(챔피언스 15 · 슈퍼챔피언스 20 FC — 사용자 확인값)을 더한 합계와 100판당 · [자리별 수준] 미드필더 공격 · 수비수 공격·수비 세 칸을 1~3,000위 구단주 분포에 대 5단계(미달·1인분·잘함·에이스·압도) — 구단주 분포 받기를 켜고 이용 안내 11 에 동의해 새 바퀴가 돈 뒤부터. 내 그 줄 출전이 300판 미만이거나 단계가 애매하면 "판정 보류"(백분위와 90% 범위는 늘 보인다) |
| 선수별 결정력 | 슛·유효슛·골·전환율·xG·어시스트 랭킹 |
| 선수 지표 › 랭커 비교 | 내 카드(가장 많이 세운 자리)의 경기당 슛·유효슛·골·어시·드리블/패스 성공률·태클·블록을 같은 카드·같은 자리 상위 랭커 평균과 "나 / 랭커"로(넥슨 오픈API ranker-stats · 하루 캐시 · 표본 적으면 흐림) |
| 슛 맵 | 슛 좌표를 하프 피치에 시각화(내 슛 / 상대 슛 실점 위치) · [어시스트] 골마다 어시 위치 → 슛 위치 선 · [공격 루트] 슛을 세트피스·헤더·중거리·크로스·컷백·중앙 연계·어시 없음으로 나눠 같은 경기 상대와 결정력 비교 |
| 선수 카드 | 능력치·특성·시세·클럽경력 + 강화단계·적응도·팀컬러 시뮬레이터 · [내 기록] 그 카드 슛 맵·주 단위 전환율·주 단위 평균 평점 · [랭커 기록] 그 카드를 쓴 상위 랭커들의 포지션별 경기당 기록(오픈API — 홈페이지 데이터를 꺼도 보인다) |
| 스쿼드·이적 › 가계부 | 넥슨은 API 키 주인 계정의 거래만 준다 — 맨 위 "내 계정" 띠(최근 300경기 (카드, 강화) 중 구매 기록에 있는 비율을 참고로) · 넥슨 반영 기준 마지막 거래 날짜. 내 계정이면 지출·수입·순지출 · 실현 손익(같은 카드 선입선출 추정) · 취득가 없음 판매 · 보유 카드 평가 손익(홈페이지 오늘 시세, 하루 캐시) · 최근 구매·안 쓴 카드는 따로 |
| 스쿼드·이적 › 타임라인 | 카드 구매·판매·첫 출전·마지막 출전·강화 변화를 최신순으로 + 사건 앞뒤 20경기 승률·득실(출전은 선발만). 거래는 내 계정에만 |
| 스쿼드·이적 › 이력 | 포메이션(경기 기록의 선발 자리 수)·닉네임이 바뀐 구간을 최신순으로 — 기간·경기 수 · 3경기 미만으로 잠깐 바뀌었다 돌아온 것은 앞 구간에 붙여 "잠깐 바뀜" 에. 닉네임은 내 계정(API 키 주인)일 때만 (2.13.1) |
| 랭커 › 랭킹 추이 | 하루 한 번 모은 랭킹 1만 명(rank.db 영구 집계 — 원본 14일과 무관). [추이] 위에 1~3위 카드(하루 평균 판수 · 하루 FC 추정 범위 · 승률 막대 · 마지막 갱신 (2.13.1)) · 순위 컷 ELO(1·10·50·100·200위) · 구단가치 평균·중앙값 · 포메이션 비율 · 팀컬러 비율을 스냅숏 날짜별 그래프로(순위 구간 1 |
| 랭커 › 메타 분석 | 랭킹 수집 원본(최근 14일)에서 — [하루 승률] 팀컬러·포메이션별 하루 승÷(승+패)와 95% 구간(구간이 전체 평균을 품으면 "차이 없음"으로 흐림 · 그 사이 팀컬러를 바꾼 사람은 뺌) · [가성비] 팀컬러마다 평균 ELO·시즌 승률·구단가치 중앙값·챔스 이상 비율의 백분위로 1,000점(20명 이상 팀컬러가 5개 이상일 때) · [구단가치] 8구간 분포와 구간 × 팀컬러 점유·챔스 비율 · [구간 평균] 팀컬러·포메이션별 평균 ELO·구단가치 · [승률→점수] 하루 승률 칸마다 ELO 변화(중앙값·오른 날·5~95%)와 손익분기 + 검색한 계정의 최근 하루 승률로 같은 점수대 사람들의 하루 중앙값. 순위 구간 "상위 200·2,000·5,000·1만 명" · 포메이션 묶기(수비 줄 수 · 앞줄 수 · 비주류 묶음(1만 명 중 100명 미만을 한 줄로) — 메타 변화에도) · 팀컬러 표는 종류·비주류만 거르기 (2.13.1). 새 요청 없음 |
| 랭커 › 메타 분석 › 포지션 특성 | 랭킹 상위 500명이 포메이션마다 각 포지션 선수에게 실제로 넣어 둔 일반(5강~)·신규(8강~)·훈련(11강~) 특성과 훈련 코치 — 많이 넣은 순 3개와 그 포지션 선수 중 비율(칸이 안 열린 선수 포함). 구간 상위 200 / 500 · 포메이션은 모인 사람 수 순(30명 미만은 흐림) · 구간 대상의 절반이 안 모였으면 흐림. 랭킹 수집이 켜져 있고 이 탭을 열어 둔 동안만 받는다 — 마지막 경기는 랭커 픽과 같은 길(하루 300요청을 나눠 씀), 특성은 넥슨 스쿼드메이커(하루 최대 1,000요청). 게임 안에서 팀 전술을 저장한 때 기준이라 오래 저장 안 한 구단주는 뺀다 · 받은 것은 14일 · 수집을 끄면 지운다 · 표 위 내 스쿼드(지금) — 내 계정(API 키 주인) 닉네임으로 스쿼드메이커의 내 팀 칸을 하루 한 번 읽어(최대 7요청 · 위 상한 안) 최근 경기 선발 카드마다 특성·코치 (2.13.1 — 이용 안내 14 동의 뒤 · 관문이 꺼지면 지운다) (2.5.1 — 이용 안내 7 동의 뒤부터. 6 에 동의한 사람은 수집이 켜져 있으면 창을 볼 때, 꺼져 있으면 [정보] 에서 수집을 켤 때 묻는다 · 탭의 [안내 보고 동의] 로도) |
| 랭커 › 랭커 픽 | [픽] 랭킹 상위 200명(마지막 랭킹 스냅숏)의 팀컬러·포메이션 비율 · 줄별 많이 쓴 카드(사람 수·강화) · 내 최근 선발에 그 카드의 랭커 픽률. [추천] 내 팀컬러 랭커(① 상위 200 · ② 내 DB 의 상대 중 1만 위 안 — 요청 없음 · ③ 둘이 10명 미만이면 1,000위 안에서 최대 20명 더)가 많이 쓰는데 내 최근 선발에 없는 카드(줄별 · 3명 이상이 쓴 것만) · 내 구단가치·선발 강화 평균·포메이션이 그 후보들 사이 어디쯤인지 · 출처별 인원. 10명 미만이면 추천 안 함. 랭킹 수집이 켜져 있고 이 메뉴(또는 포지션 특성 탭)를 열어 둔 동안만 넥슨 오픈API(내 키)로 랭커마다 최근 경기 하나를 받는다 — 하루 최대 300요청, 3일 안에 받은 랭커는 다시 안 묻고, 429 를 두 번 받으면 그날 멈춘다. 받은 경기는 14일 · 수집을 끄면 지운다 |
| 랭커 › 선수로 구단주 찾기 | 카드(이름 2글자부터 · 시즌 · 강화 · 팀컬러)를 최근 30일 선발로 쓴 구단주 — 이 PC 에 저장된 경기(검색한 계정과 그 상대 · 랭커 픽)의 색인에서, 요청 없이. [이 카드만 / 선수(모든 시즌 카드)] 전환 — 선수면 같은 선수의 시즌 카드를 합쳐 찾고, 카드별·강화별 사용자 수 표가 붙는다. 두 번 누르면 그 구단주 검색 |
| 도움말 › 산출 방법 | 승률 식(무승부 분모) · 기대득점(xG) 표를 어떻게 세웠고 어디까지 확인했나 · 결정력 문장 기준 · FC 보상값 · 상대 순위 구간 · 역산한 값과 근사치 — 글 속 숫자는 설정·표에서 읽어 와 같이 바뀐다 (2.9.1) |
| 대시보드 | 맨 위 "이번 시즌 구단" 한 줄(어제 점수·승무패·FC · 지금 200위까지 · 구단가치 등수 · 시즌 최고점 · 챔스·슈챔 달성 판수 · 시즌 FC 와 등수 범위 — 남들 비교는 랭킹 수집이 켜져 있고 시즌 초부터 모았을 때만) · 그 아래 한 줄 총평(흐름 분석 문장·점수 낙폭 중 정해 둔 순서로 하나 — 표본이 모자라면 비움 (2.13.1)) · 지표 4개(시즌 승률 + 최근 20경기와의 차이·승무패 도넛·득실·연속) · 랭커 카드(등급 배지 아래에 내 팀컬러 엠블럼·주 포메이션 작은 축구장 — 아는 것만) · 승률 흐름 곡선(평균선·최고/최저) + 최근 20경기 · 나 vs 상대 평균 레이더 · 승부처 게이지 · 15분 득실 막대 · 흐름 분석 3줄 · 시간대 승률 · 자주 만난 상대. 카드마다 상세 메뉴와 같은 범위를 세고(구석에 표기), 누르면 그 메뉴로 간다 |
어두운 테마(theme.MODE 로 밝은 테마도 고를 수 있다). 닉네임을 검색하면 왼쪽 메뉴 + 대시보드로 넘어가고, 메뉴(경기·흐름·경기력·선수·팀컬러·랭커)
에서 상세 화면으로 들어간다. 한 메뉴 안의 구획은 제목 옆 탭으로 나뉜다(위 표의 [ ] — 2.1.1). 메뉴마다 마지막에 본 탭을
기억한다. 시즌·표시 범위·새 경기 확인은 위쪽 바에 고정이라 어느 화면에서든 같다.
스크린샷은 실데이터로 찍되 닉네임은 메모리에서만 익명화했다(내 구단주 · 상대1…). 랭커 카드(순위·구단가치)는 공개 랭킹에서 계정을 역추적할 수 있어 비웠다. 찍기 전 화면 글자 전부를 실제 닉네임 6,561개와 대조해 0건을 확인했다.
대시보드 — 지표 4개 · 랭커 카드 · 승률 흐름 · 나 vs 상대 레이더 · 승부처 · 15분 득실 · 흐름 분석 · 시간대 · 자주 만난 상대
| 선수 지표 — 포지션별 출전·평점·공수 지표(공식 미제공 값 역산) | 슛 맵 — 슛 좌표를 하프 피치에 시각화(골/유효슛/빗나감) |
| 전술·경기 결과 — 상대 포메이션별 승률, 득·실점 유형 | 승률 그래프 — 기간별 승률·등급(디비전) 계단 그래프 |
| 승부처 분석 — 선제골 승률, 시간 구간별 득실, 시각대별 승률 | 시즌별 성적 — 감독모드 랭킹 시즌별 전적·승률·평균 득실(진행 중 시즌 포함) |
| 팀컬러 승률 — 상대 팀컬러별 내 승률(시즌 전체 · 반영된 상대 수 표시) |
파이썬 없이 쓰는 방법이다. 바뀐 점은 CHANGELOG.md.
FifaMatchTracker-Setup-<버전>.exe 를 받아 실행한다. 관리자 권한은 필요 없다(사용자 폴더
%LOCALAPPDATA%\Programs\피파전적관리 에 깔린다). 시작 메뉴에 생기고, 바탕화면 아이콘은
설치할 때 고른다. 지우는 건 윈도우 "설정 → 앱"에서.
FifaMatchTracker-<버전>-portable.zip 을 폴더째 풀고 피파전적관리.exe 실행
(_internal 이 옆에 있어야 켜진다).%LOCALAPPDATA%\피파전적관리\ 에 쌓인다.
새 버전으로 바꿔도 그대로 남고, 지우려면 이 폴더를 지운다.%LOCALAPPDATA%\피파전적관리\logs\crash.log 를 보내 주면 된다.rank.db 에 쌓는다(원본 14일 · 집계는 계속). 홈페이지 데이터를 끄면 같이 꺼지고, 넥슨이
요청을 계속 막으면 스스로 꺼진다. 하루 안의 기록이 있으면 팀컬러도 거기서 읽어 넥슨 요청이 0이다.
넥슨 데이터 기준 시각(쪽마다 붙는 "※ … 기준")이 지난 수집과 같으면(점검 등) 1쪽만 보고 다음 시각에 다시 —
[정보] 에 "멈춰 있습니다"로 보인다. 2.3.1 부터 상위 20 표시 연속·시즌 최고점·첫 챔피언스 판수(2.12.1 부터 시즌 FC 범위 · 2.12.2 부터 챔피언스 이상 판수 범위도 — 안내 13 동의 뒤)를 재려고
다른 구단주의 프로필 번호(닉네임 없이)를 그 시즌 동안 두고, 시즌이 끝나면 숫자만 남긴다. 수집을 끄면 바로 지운다.
검색한 구단주의 ELO·순위는 수집과 상관없이 검색할 때마다 기록한다. [정보 › 저장 공간] 의 랭킹 수집 기록 [지우기] 로 둘 다 지운다 (2.13.1 에서 [정보] 아래 버튼을 옮김).fifa.db 에 둔다. 창을 닫아도(트레이) 10분마다 차례를 보고 이어 받으며, 검색과 엮이지 않고 따로 돈다. 끄면 받던
바퀴를 버리고 받아 둔 분포는 남긴다 · 랭킹 수집·홈페이지 데이터를 끄거나 랭킹 수집 기록을 지우면 분포까지 지운다.
켠 뒤 시작한 바퀴가 5,000건 안에 호출 한도(429)를 받으면 개발 키로 보고, 바퀴가 3번 이어서 못 끝나면, 키를 바꾸면 스스로 꺼진다
(.env FIFA_OWNER_DIST=켠 시각 · FIFA_OWNER_DIST_OFF=꺼진 사유). 다 받은 분포가 있고 켜져 있으면 흐름 분석 맨 위
결정력·태클 성공 칩과 "마무리" 문장이 같은 경기 상대 대신 1~3,000위 구단주 분포 속 내 위치(내 감독모드 최근 1,000판 ·
하위/상위 10% 이고 구간 안쪽 끝도 중앙을 안 넘을 때만 — 경향)로 판정한다. 칩에 마우스를 올리면 인원·내 판수·분포 기준일.
감독모드 1,000판이 안 되거나 다른 매치 종류를 보면 예전 판정 그대로. 유효슛 비율 칩은 늘 같은 경기 상대 대비.--tray, 시작 프로그램 등록).
설치판·포터블 exe 에서만 켤 수 있다. ⚠ 1.0.x 로 되돌리기 전에 끄세요 — 옛 버전은 --tray 를 몰라 부팅마다 창이 뜬다.
설치판을 제거하면 등록도 지운다.fifa.db 를 바꿔 끼운다 — 파일이 바로 줄고 옛 바이트가 안 남는다. 다른 실행본이 파일을 잡고 있으면 아무것도 안 지우고
"다시" 를 알린다. API 키(.env)·crash.log·창 설정은 지우지 않는다..env 에
FIFA_UPDATE_CHECK=0.python tools/release.py # 빌드 → zip · 설치 파일 → 개인정보 검사 → 공개 명령 출력
config.APP_VERSION 을 올리고 CHANGELOG.md 에 그 버전 절을 쓴 뒤 커밋한다(안 하면 멈춘다).tools/release.py 가 dist\ 에 FifaMatchTracker-Setup-vX.Y.Z.exe · FifaMatchTracker-vX.Y.Z-portable.zip · SHA256SUMS.txt 를 만들고,
배포물 안(exe 안의 압축된 코드까지)에서 이 PC 의 홈 폴더 경로 · 프로젝트 경로 · API 키 · git 이메일을
찾는다. 반드시 있어야 할 대조 문자열이 안 잡히면 "0건"을 믿지 않고 멈춘다.
더 찾을 말은 RELEASE_SCAN_EXTRA="a,b".gh release create … 를 확인하고 직접 친다 — 공개는 스크립트가 하지 않는다.설치 파일은 Inno Setup 6(무료)이 필요하다 — 스크립트는 installer/피파전적관리.iss.
앱의 새 버전 알림은 릴리스 태그(vX.Y.Z)를 읽는다.
git clone https://github.com/yim2412/fifa-match-tracker.git
cd fifa-match-tracker
# 1) 패키지 설치
pip install -r requirements.txt
# 2) API 키 — 앱을 처음 켜면 입력 창이 뜬다(아래 4번). 터미널 점검(3번)을 먼저
# 하려면 .env.example 을 복사해 .env 로 만들고 키를 넣는다
copy .env.example .env
notepad .env
# 3) API 연결 점검 (GUI 전에 먼저, 선택)
python check_api.py 내닉네임
# 4) 앱 실행
python app_main.py
# 5) 파싱·집계 회귀 테스트 (네트워크 없이, 실제 응답 픽스처로)
python tests/test_parsing.py
python tests/test_ui_smoke.py # 화면 배선(offscreen)
python tests/test_rankcollect.py # 랭킹 수집기
python tests/test_tray.py # 트레이 상주·자동 실행·한 번만 실행
python tests/test_ownerdist.py # 구단주 분포 받기·판정(가짜 API)
python tests/test_ownerdist_sched.py # 구단주 분포 예약·토글·동의·지우기(가짜 로더)
python tests/test_release.py # 배포 검사 로직
python tests/test_rules.py # 규칙 검사(인코딩·색·콤보박스·대화상자 크기·모달·신호·SQL 실행 계획)
python tests/test_review_kit.py # 계획 검토 준비 도구
| 파일 | 역할 |
|---|---|
app_main.py | PyQt6 UI — 검색 화면, 왼쪽 메뉴(NAV 표) + 위쪽 바 + 메뉴별 페이지(대시보드·흐름 분석·선수 지표·전술·승부처 분석·성적 진단·슛 맵·결정력·팀컬러·스쿼드·이적 등 18개 — 메뉴 안 구획은 페이지 안 탭 Tabs), 조회 워커 스레드 · 거래 받기(TradeLoader) |
dashboard.py | 대시보드 페이지 — 카드 배치·채우기(DashboardPage.render), 카드별 범위 규칙 |
charts.py | 대시보드 그래프(QPainter) — 영역 곡선·도넛·링 게이지·묶음 막대·레이더·결과 점·가로 막대 |
widgets.py | 화면 부품(위젯) — 카드(Card·add_shadow)·랭커 카드·표(FitTableWidget — 모든 표)·좁으면 두 줄로 접히는 위쪽 바(WrapBar)·세로 스크롤 틀(VScrollArea)·글꼴이 줄어드는 라벨(FitLabel)·승률/등급 그래프·축구장 v2(PitchWidget — 줄마다 폭을 나눠 칩이 안 겹친다 · 접는 구획 Collapsible)·슛 맵·NoScrollComboBox 등 |
theme.py | 테마 — 어두운·밝은 팔레트(MODE 로 선택)·전역 스타일시트(QSS)·apply()(Fusion + 팔레트 + 기본 글꼴). QSS 에 font-size 를 넣지 않는다(setFont 를 이긴다) |
nexon_api.py | 넥슨 오픈API 클라이언트. 엔드포인트 경로·에러코드가 전부 여기 상수에 모여 있다 |
models.py | 매치 상세 JSON → MatchSummary 파싱, Stats·상대 전적·승률 추이 집계 |
stats.py | 여러 경기 집계 — 선수 지표·전술·경기 결과. 역산해서 알아낸 상수가 여기 모여 있다 |
analysis.py | 집계 → 문장. 최근 흐름(최근 20경기)과 이기는/지는 패턴(누적 전체)을 규칙 기반으로 서술 |
predict_check.py | 예측 되짚기(50단계 B8) — 끝난 시즌의 내 계정 하나 최종 순위를 넥슨 홈페이지에서 한 번 확인(랭킹 수집 한 회차 끝에서 판정 · 이용 안내 11 동의 뒤) |
predict.py | 시즌 말 순위 예측(1.3.1) — 같은 점수대 구단주들의 실제 하루 ELO 변화(랭킹 수집 원본)를 이어 붙여 2,000번 굴린다. 아래 "시즌 말 순위 예측" |
core_api.py | 화면과 분석 사이의 경계 — 화면 쪽 파일은 분석 함수를 여기서만 가져온다 |
store.py | 조회한 경기를 SQLite(fifa.db)에 누적 — API가 오래된 경기를 버리는 것을 넘기 위해 |
storage.py | 정보 › 저장 공간 — 종류별 크기 재기·지우기(그림·상세 캐시 · 카드 표 · 내 기록 전부는 남길 행만 새 파일로 옮겨 fifa.db 바꿔 끼우기). 작업 스레드에서만 — 걸쇠·쓰는 쪽 멈추기는 app_main.MainWindow.clear_storage |
ranker.py | 넥슨 데이터센터에서 감독모드 순위·구단가치·ELO·팀컬러(+ 엠블럼)를 긁어온다(오픈API 엔 없음) |
teamcolor.py | 팀컬러 효과표(2.2.1) — 데이터센터 팀컬러 목록·단계별 효과·적용 선수(문서 없는 주소 — 상세·선수는 X-Requested-With 헤더, 넘김은 따라가지 않고 오류) · 이름이 같은 팀컬러를 가르는 화면 키(label·name_of) |
rankerstats.py | 랭커 기록 받기(1.4.1) — 하루 캐시(fifa.db ranker_stats)에 없는 (카드, 자리)만 넥슨에 50쌍씩(한 요청 상한은 URL 길이) · 데이터 없는 쌍도 그날 기억 |
tradecollect.py | 거래 기록 받기(1.4.1) — 키 주인 계정의 구매·판매를 fifa.db trades 에. 키가 바뀌면 옛 주인 거래는 따로 옮겨 두고(지우지 않는다) 새 주인 것을 다시 · 새 거래는 하루 한 번(7일 겹쳐서) · 첫 수집이 끊겨도 옛 거래를 이어 받는다 |
squad_timeline.py · trade_book.py | 스쿼드 타임라인(경기 + 거래 → 사건 · 구매↔판매 선입선출 짝 · 판 기록 없는 구매의 보유 상태) · 가계부(지출·수입·손익) — 화면 없이 계산만 |
ownerdist.py | 구단주 분포 v2(49단계) — 사용자 서비스 키로 1~3000위 구단주 150명의 최근 1000판을 받아 이름 없는 요약으로 저장하는 규칙(하루 계수 · 바퀴 상한 · 재시도 끔 · 429 전원 쉼 · 끊기면 그 구단주는 버림) · 분포 읽기·층 가중 백분위(조각 ②) · 예약이 쓰는 차례 판정 should_run·스스로 끌 사유 off_reason_after·지우기 purge·[정보] 상태 줄 status_text(조각 ③a). 로더·예약은 app_main.OwnerDistLoader·OwnerDistScheduler(셸 수명 — 창 밖) · 화면 판정은 app_main._dist_basis(칩·문장이 같이 · 허용·분포·내 감독모드 1000판이 없으면 None — 조각 ③b) |
rankerpick.py | 랭커 픽(2.1.1) — 스냅숏 상위 200명의 최근 경기를 오픈API 로 받는 규칙(하루 계수 · 재시도 끔 · 요청 간격 · 429 · 3일)과 화면 집계 · 추천(내 팀컬러 후보 ①②③ → 줄별 대체 카드 · 내 스쿼드 위치). 화면 없이 tests/test_rankerpick.py 가 잰다 |
trait_codes.py · traitcollect.py | 포지션 특성(2.5.1) — 특성·훈련 코치 이름표 · 넥슨 스쿼드메이커 팀 칸을 읽어 랭커 마지막 경기 선발과 맞는 팀을 찾는 규칙(하루 상한 · 막힘 · 낡은 값) · 포메이션·포지션별 사용률 집계(trait_usage). 화면 없이 tests/test_traits.py 가 잰다 |
rankcollect.py | 랭킹 1만 명을 하루 한 번 모아 rank.db 에 쌓는 수집기(1.1.1 — 기본 꺼짐, [정보] 에서 켠다). 팀컬러 목록과 같은 읽기를 나눠 쓴다. 2.3.1: 넥슨 기준 시각 · 메타 처리(process_meta — 점수 분포 · 상위 20 연속 · 시즌 최고점 · 첫 챔스 · 시즌 FC 범위 · 챔스 이상 판수 범위) · 정리(maintenance — 사람별 지우기 · 원본 정리 · WAL 비우기 · 옛 흔적 VACUUM). 터미널 확인: python rankcollect.py --pages 3 |
rankmeta.py | 랭커 메타 ② 스냅숏 읽기(2.4.1) — rank.db 를 읽기만 해 하루 승률 · 가성비 · 구단가치 분포 · 구간 평균 · 승률→점수 · 주간 요약 · 순위 변동 원인을 계산(요청·쓰기 0). 화면 없이 tests/test_rankmeta.py 가 잰다 |
tray.py | 트레이 상주(1.1.1) — 트레이 아이콘, 모든 종료가 거치는 quit_app, 한 번만 실행, 숨긴 창 기록 내려놓기, 상주 중 6시간마다 업데이트 확인 |
autostart.py | 자동 실행 — 윈도우 시작 프로그램(HKCU Run)에 "<exe>" --tray 등록(exe 에서만, 설치판·포터블 이름을 나눔) |
seasons.py | 감독모드 랭킹 시즌표(번호·이름·기간)를 데이터센터에서 긁어와 경기를 시즌에 나눠 담는다 |
images.py | 넥슨 CDN에서 선수 얼굴·등급/시즌 배지·구단/팀컬러 엠블럼·국기·특성 아이콘을 받아 디스크에 캐시(오픈API 아닌 정적 CDN, 비공식). 표 칸 그림의 주소(icon_url)와 받기(fetch_icon)는 여기 한 곳 — 화면 없이 tests/test_icons.py 가 잰다 |
playerinfo.py | 선수 카드 상세(능력치·특성·시세·클럽경력) — 넥슨 모바일 데이터센터 HTML 스크래핑 |
config.py | API 키 로드·저장(.env), DB 경로, 웹 데이터 스위치, 매치 종류·조회 개수 기본값 |
crashlog.py | 처리 안 된 예외를 %LOCALAPPDATA%\피파전적관리\logs\crash.log 에 남기고 첫 오류 때 위치를 알려 준다 |
check_api.py | 터미널에서 키·엔드포인트·집계·DB 동작 확인용 |
tests/test_storage.py | 저장 공간·걸쇠·내 특성 테스트(57 ③) — 바꿔 끼우기(남길 행만 · 남의 닉네임 바이트 없음 · 다른 연결이 잡으면 옛 파일 그대로 · 멈춤) · 스키마의 모든 표가 남김/버림 중 하나 · 그림·상세 캐시 · 걸쇠가 그 저장소에 쓰는 작업만 막나 · 모든 QThread 가 Worker 이고 저장소를 쓰면 WRITES 가 있나 · 내 스쿼드 특성 받기(번호 캐시 · 하루 한 번 · 막힘·상한) |
tests/test_parsing.py | 파싱·집계 회귀 테스트 — 실제 응답 픽스처로 골든값 고정(네트워크 없음) |
tests/test_rankcollect.py | 랭킹 수집기 테스트 — 가짜 랭킹 목록으로 쪽 판정·실패 대기·차단 시 끄기·잠금·집계·랭킹 추이(지금 시즌 · 하루 마지막) · 수집 간격 시뮬(저녁만 켜는 PC · 상시 PC · 1,000대) · 기준 시각·안 바뀐 데이터 · 메타 처리(연속·잘림·시즌 넘김·동의·끄기) · 지운 바이트(rank.db·-wal)(네트워크 없음) |
tests/test_rankmeta.py | 랭커 메타 ② 테스트 — 지어낸 rank.db 로 이웃 쌍(간격·시즌·기준 시각) · 앞 스냅숏 순위 구간 · 바꾼 사람·음수 차 빼기 · 가성비 손계산 · 순위 변동 판정 순서 · 주간 요약 · 1만 행 × 14스냅숏 CPU 예산 |
tests/test_trades.py | 거래 받기·시세 캐시 테스트 — 가짜 거래 목록으로 끊김·겹침·429·키 바뀜·하루 상한(네트워크 없음) |
tests/test_timeline.py | 타임라인·가계부 테스트 — 지어낸 경기·거래로 짝·보유 상태·앞뒤 창·범위 · 1만 경기 예산(300ms) |
tests/test_ownerdist.py | 구단주 분포 받기 테스트(49단계 조각 ①) — 가짜 API 로 하루 계수·바퀴 상한·429 쉼/그날 멈춤·끊긴 구단주 버리기와 이어 받기·.cache 안 씀·바퀴 종료(done/thin/dropped/aborted)·지운 소금·해시가 파일 바이트에 없는지까지 · 차례 판정·스스로 끌 사유·지우기·상태 줄 |
tests/test_ownerdist_sched.py | 구단주 분포 예약 테스트(49단계 조각 ③a · 랭킹 수집 기록 지우기가 rank.db 전에 로더를 멈추는지 ③b) — 가짜 로더로 --tray(창 없음) 틱·종료 뒤 진행 바퀴 남음·전제/토글/키 꺼짐별 멈춤과 지우기(로더가 돌면 끝난 뒤)·.env 손 수정·못 읽은 .env·연속 실패·개발 키·[정보] 토글과 잠김 이유 · 창이 로더를 양보시키지 않는지(소스 검사) |
tests/test_rankerpick.py | 선수 색인·랭커 픽 테스트 — 지어낸 경기·가짜 API 로 색인(몰수·깨진 경기)·백필 이어 하기·하루 상한·429·닉네임 바뀜·지우기(지운 닉네임이 파일 바이트에 없는지까지) · 추천 후보 출처·문턱 경계 · 2만 경기 백필 · 추천 200명 예산 |
tests/test_tray.py | 트레이 상주 테스트 — 종료 진입점·X 숨김 규칙·한 번만 실행 판정·자동 실행(가짜 레지스트리)·내려놓기 미룸 |
tests/test_analysis.py | 흐름 분석 회귀 테스트 — 임계값 경계·가중치 정규화(네트워크 없음) |
tests/test_rules.py | 규칙 검사 — 프로젝트 규칙(인코딩 명시·색은 theme.py 에서만 등)을 코드 전체에 기계로 대조하고, 모든 SQL 의 실행 계획에 큰 표 통째 정렬이 없는지 본다 |
tests/test_predict.py | 예측 테스트 — 가짜 스냅숏으로 하루 걸음 표본·되돌림 상식·흐름 쏠림·골든·원인별 문구(네트워크 없음) |
tests/test_predict_check.py | 예측 되짚기(50단계 B8) 테스트 — 가짜 fifa.db·가짜 순위 조회로 관문·키 지문·시즌 대조·다시 묻기 3일·취소·지우기(네트워크 없음) |
tests/test_compare.py | 구단주 비교 확장(50단계 D1) 테스트 — 지어낸 경기 상세로 차이 요약의 z 문턱·표 값 방향·최소 경기 수 · 자리 줄 대표 카드 짝짓기(네트워크 없음) |
tools/season_notice.py | 시즌 종료일 공지 — 최신 릴리스 본문의 안 보이는 한 줄만 바꾼 파일과 gh release edit 명령을 출력(공개는 사람이) |
tools/check_predictions.py | 시즌이 끝난 뒤 남겨 둔 예측을 실제 최종 순위와 대조(수동) |
tools/review_kit.py | 계획 검토 준비 — 계획 절이 짚은 코드 조각 묶음(bundle) · 회차 사이 바뀐 계획 줄(diff) · 주장 장부 빈 표(ledger). 쓰는 법은 docs/ROADMAP.md "검토 방법" |
기본 매치 종류는 감독모드(52) 다 — 이 앱은 감독모드 전적을 본다.
fifa.db)API는 과거를 무한히 주지 않는다. 한 번에 받는 개수 상한이 100이고, offset으로
그보다 과거까지 받을 수 있지만 끝이 있다.
2026-09-05 실측 (GB쭈우 · 감독모드 · get_match_ids)
offset=0 100개 offset=500 100개
offset=100 100개 offset=3000 24개 ← 여기서 끝. 총 3,024경기
같은 시점 fifa.db에는 7,859경기가 있다(2026-06-17~). API가 닿는 가장 오래된
경기는 대략 2026-08-04(DB 기준 최신에서 3,024번째)이라, 한 달 남짓 지난 경기는
API에서 사라진다.
⚠️ 여기 오래 틀린 값이 적혀 있었다. "API는 최근 100경기까지만 준다 · 하루만 걸러도 영영 못 가져온다" — 100은 한 번에 받는 개수 상한이지 전체 상한이 아니다. 이 판단은 2026-07-18(
d872ef5)에 이미 정정됐는데 문서에는 반영되지 않았고, 오히려 07-24 README 정비 때 다시 적혔다. 2026-09-05에 실측으로 고쳤다. 누적 저장이 필요하다는 결론 자체는 그대로다 — 이유의 규모가 틀렸을 뿐이다.
그래서 조회할 때마다 fifa.db에 쌓고, 화면은 API가 아니라 DB를 그린다.
검색하는 순간이 곧 수집이라, 자주 보는 계정일수록 데이터가 길어진다.
저장 기준은 ouid — 구단주명은 바뀌어도 ouid는 안 바뀐다
경기 원본은 한 번만 — 한 경기에 두 명이 나오므로 matches / match_players로 분리.
상대를 검색하면 이미 받아 둔 경기가 재활용된다
이미 있는 경기는 API를 다시 부르지 않는다 (store.existing_ids)
등록 계정 — 조회하면 자동 등록. 목록에서 고르면 바로 조회. 등록 해제해도 경기 기록은 남는다
검색 속도 — 저장된 기록 읽기(1만 경기 약 2초, 대부분 JSON 해석)는 넥슨 조회와 동시에 한다.
켤 때 마지막으로 검색한 계정의 기록을 뒤에서 미리 읽어 두므로 그 계정은 더 빠르다(화면은 검색창 그대로).
2026-10-04 실측(1만 832경기): 검색 → 첫 화면 5.3초 → 마지막 계정 약 1.3초 · 다른 계정 약 3초.
처음 보는 계정은 경기 상세를 동시 24개로 받는다(3,130경기 119초 → 38초, 서비스 키). 429 를 받으면
그 검색은 2개로 내린다(app_main.DETAIL_WORKERS · DETAIL_WORKERS_THROTTLED)
⚠️ DB 를 열 때 통계를 갱신한다(PRAGMA optimize) — 통계가 생기면 SQLite 가 계획을 바꾸므로,
경기 기록 본문을 읽는 쿼리는 (종류, 날짜) 인덱스를 직접 지정한다(안 그러면 본문을 통째로 정렬했다)
거래 기록(1.4.1) — trades(구매·판매 한 줄씩, ouid 열 없음 — API 키 주인의 거래라서) · trade_state(키 지문 ·
받기 진행 · 내 계정) · card_prices(카드 강화 단계별 시세, 하루 캐시). 2026-10-06 실측: 첫 수집 163요청 · 19초 ·
구매 4,430 + 판매 11,473건 · DB +3.8MB. 거래 API 는 2022-01-27 부터 주고, 반영은 며칠 늦을 수 있다(그날 마지막 거래 09-30)
카드 정보(2.1.1) — card_info(카드 하나에 급여·1강 OVR · 30일) · api_budget(그날 쓰임별 홈페이지 요청 수 — 축구장 칩 60 ·
가계부 시세 80. 재시작해도 남는다). 강화별 OVR 은 1강 값 + config.GRADE_OVR_BONUS(시뮬레이터 실측 — check_api 가 다시 대조)
선수 색인(2.1.1) — match_squads(카드 · 날짜 · 경기 · 구단주 · 자리 · 강화 — 선발만, 정수 키 WITHOUT ROWID) + 번호 표
squad_owner·squad_match. 새 경기는 저장과 같은 커밋에서, 옛 경기는 켠 뒤 30초(트레이 시작이면 2분)부터 낮은 우선순위로
1,000경기씩 채운다(검색이 돌면 양보). 2026-10-06 실DB 사본(2.1만 경기): 14.7MB · CPU 4.5초 · 가장 많이 쓰인 카드 조회 4.4ms
랭커 픽(2.1.1) — ranker_squads(랭커마다 ouid·최근 경기·받은 시각·실패) · ranker_matches(랭커 픽으로 들어온 경기 표시 —
14일 정리·지우기의 범위. 검색한 계정이 나온 경기는 지우지 않는다). 모든 연결이 secure_delete — 지운 다른 구단주 닉네임이
파일 빈칸에 남지 않게(VACUUM 은 안 한다)
한계: API가 이미 버린 과거는 못 되살린다. 처음 조회 시점에 API가 주는 만큼 (실측 3,024경기 · 약 한 달)이 시작점이고, 그보다 이전은 없다. 조회 간격이 그보다 길어지면 그 사이가 뚫린다.
ranker.py)순위·구단가치·랭킹점수(ELO)는 오픈API(JSON)에 없다. 넥슨 공식 데이터센터 웹페이지에는 있어서 거기서 긁어온다.
https://fconline.nexon.com/datacenter/rank_inner?rt=manager&strCharacterName=<닉네임>
ranker.py 한 곳에만 둔다 — 깨지면
실제 응답과 대조해 거기만 고친다.ranker.fetch_rank_page · RankListLoader).
찾을 수 있는 범위(1만 위 안)는 같고 요청은 500번으로 고정이다. 적으면 그 상대만 검색한다.
store.TEAM_COLOR_TTL_DAYS) — 그 사이엔 그날 새로 만난 상대만 검색하고, 만료되면 다시 목록을 읽는다(약 50초).config.TEAMCOLOR_DUP_NAMES —
2026-10-06 목록 801개 실측)은 랭킹 행의 팀컬러 엠블럼으로 가른다. 엠블럼은 fifa.db team_colors.emblem
(읽은 시각\t종류/파일 — 옛 버전이 이름만 바꾼 줄을 시각으로 가려낸다) · rank.db 옆 표 snapshot_emblems
(옛 버전이 그대로 수집할 수 있게 snapshot_rows 는 안 건드린다). 엠블럼 없이 읽은 옛 줄은 "(구분 전)"으로 흐리게.
넥슨이 새 쌍을 만들면 python check_api.py <닉네임> 의 팀컬러 목록 줄이 [FAIL] 이다.teamcolor.py) — 효과 창을 열 때만 데이터센터 목록(1.2MB · 7일 저장)·그 팀컬러 상세(단계)·
적용 선수 JSON(한 번 최대 100명 · OVR 상한으로 이어 받는다)을 읽는다. 상세·선수 주소는 넥슨 사이트의 스크립트가
보내는 X-Requested-With 헤더가 있어야 열린다(없으면 오류 페이지로 넘긴다). 받은 선수의 급여·시세는 카드 캐시에도
넣는다 — 그 JSON 의 OVR 은 선수 페이지 1강 OVR 과 달라(2026-10-06 실측 122 vs 125) 쓰지 않는다.predict.py)"지금 흐름이 이어지면 시즌이 끝날 때 몇 위쯤일까"를 확률로 낸다. 랭킹 수집이 켜져 있어야 한다.
tools/season_notice.py 로
릴리스 본문에 <!-- season-end: … start: … --> 한 줄을 넣는다 — 앱은 업데이트 확인 응답에서 읽는다(새 버전 불필요).tools/check_predictions.py.seasons.py)오픈API 는 경기에 시즌을 달아주지 않는다(matchDate 만 준다). 대신 데이터센터
랭킹 페이지가 시즌 목록을 기간과 함께 갖고 있어서, 그 기간표로 경기를 나눈다.
matchDate 등)은 UTC 다 — matchtime.py 가 KST 로 바꿔 읽는다(2026-10-25 실측 ·
그전엔 모든 경기 시각이 9시간 일렀다). 시즌표 날짜는 KST 그대로 경기의 KST 시각과 견준다.https://fconline.nexon.com/datacenter/rank?rt=manager
→ ChangeSeason(89) "시즌 3 (2026-05-28~2026-07-30)"
rt 에 따라 시즌 번호가 다르다(공식경기 91 = 감독모드 89, 기간은 같다).
이 앱은 감독모드만 다루므로 항상 rt=manager 로 받는다.seasons 테이블)에 캐시하고 하루에 한 번만 다시 긁는다. 조회에
실패해도 지난 캐시를 그대로 쓰고, 캐시조차 없으면 시즌 기능만 빠진 채 판수
기준 화면은 평소대로 돈다.https://open.api.nexon.comx-nxopen-api-key사용 중인 엔드포인트 (nexon_api.py 상단 상수):
| 상수 | 경로 | 용도 |
|---|---|---|
EP_ID | /fconline/v1/id | 닉네임 → ouid |
EP_USER_BASIC | /fconline/v1/user/basic | 계정 기본 정보 |
EP_MAX_DIVISION | /fconline/v1/user/maxdivision | 최고 티어 · 그 티어 최근 달성일(시즌 무관) |
EP_USER_MATCH | /fconline/v1/user/match | 매치 id 목록 |
EP_MATCH_DETAIL | /fconline/v1/match-detail | 매치 상세 |
메타데이터(매치 종류·선수·시즌·등급)는 인증 없이 https://open.api.nexon.com/static/fconline/meta/{name}.json.
공식 문서가 자바스크립트로 렌더링돼 경로를 자동 대조하지 못했다.
check_api.py가 FAIL이면 공식 문서와 대조해nexon_api.py상단 상수만 고치면 된다.
실제 응답 100경기로 확인한 내용. 상수는 stats.py 상단에 있다.
| 항목 | 내용 | 어떻게 확인했나 |
|---|---|---|
shoot.goalTotal 등이 null | 상대 탈주 등 기록 없는 경기는 키를 빼지 않고 null로 준다. .get(k, 0)은 기본값이 안 먹으니 타입까지 확인해야 한다(models._i) | 30경기 조회 시 TypeError로 재현 |
shootDetail[].result | 3 = 골 | result==3 개수가 goalTotal 합계와 정확히 일치(126/126) |
shootDetail[].goalTime | 비트 패킹. >>24 = 구간(0 전반/1 후반/2 연장전반/3 연장후반), & 0xFFFFFF = 경과 초 | 구간 0·1은 최대 49.8분(45+추가), 2·3은 19.1분(15+추가)으로 딱 맞음 |
shootDetail[].type | 슛 유형. 1 일반(D) · 2 감아차기(ZD) · 3 헤더 · 6 땅볼(DD) · 7 발리 · 8 프리킥 · 9 페널티킥 | 8·9는 goalFreekick/goalPenaltyKick 집계와 200개 선수-경기 행에서 경기별 정확히 일치. 나머지는 같은 계정 100경기의 유형별 골 수 합계와 일치 |
shootDetail[].result 1 · 2 | 1 = 유효슛(막힘) · 2 = 빗나감(3은 골) | effectiveShootTotal == 골+result1이 1189/1190, shootTotal == shootDetail 총개수가 1190/1190 |
shootDetail[].x · .y | 슛 좌표(0~1 정규화). x=1.0이 상대 골문 쪽(슛이 x>0.48에 몰림), y=0.5가 폭 중앙. assistX/Y·hitPost·inPenalty도 있음 | 실제 캐시 1,190 선수-경기로 범위·방향 확인 |
type 4 · 10 · 13 · 14 | 미상. "알 수 없음"으로 표시 | 근거 없음 |
shoot.shootOutScore | 승부차기 점수. 승부차기가 없었으면 양쪽 0 | 2:2 무승부인데 승/패가 갈린 경기에서만 0이 아님 |
spPosition | 28 = SUB(교체 명단). 전술은 GK·SUB 제외하고 수비(1-8)-수미(9-11)-미드(12-16)-공미(17-19)-공격(20-27) 인원 | 실제 100경기 대조로 상대 전술별 승률 확인(4-1-2-3-0 → 51.7%, 31승3무26패) |
매치 상세는 경기별 실제 스쿼드를 준다(현재 스쿼드를 돌려주는 게 아니다). 볼타 66경기에서 서로 다른 스쿼드 조합 10개가 나오는 것으로 확인.
앞으로 할 일(버전별 상세 계획)은
docs/ROADMAP.md한 곳에 있다. 아래는 이미 끝난 것들이다.
stats.aggregate_playersstats.formation_statsPlayerStat).
실제 100경기로 검증했다. 선방력은 defending 합계가 아니라 경기당 평균×100이다 — 100경기 표본에서
우연히 합계처럼 보였을 뿐, 경기 수가 다르면 값이 완전히 달라진다models.opponent_stats, "상대 전적" 탭models.win_rate_trend(월별), "승률 추이" 탭store.pyimages.py. 오픈API가 아니라 비공식 CDN 직링크
(fco.dn.nexoncdn.co.kr)라 넥슨이 바꾸면 깨질 수 있다playerinfo.py, 상대 스쿼드·선수 지표
표·포지션별 최다 상대 표에서 선수 클릭(더블클릭)fconline.nexon.com)가 실제로 쓰는
/datacenter/PlayerAbility 엔드포인트를 그대로 호출해서 넥슨 서버가
계산한 값을 받는다(playerinfo.fetch_player_ability) — 팀컬러 종류(600여개)별
보너스 조합표를 넥슨이 공개하지 않아 근사가 불가능하므로, 정확성을 위해
매 조작마다 재조회하는 방식을 택함. 팀컬러 드롭다운은 응답 HTML에 같이 오는
그 선수 전용 선택지로 채운다(전체 목록 페이지 불필요). 레벨 UI는 없음 —
소속 팀컬러는 항상 그 팀컬러의 최대 레벨(대부분 4)로 자동 조회하고, 강화
팀컬러는 항목 자체에 레벨이 있으며("Lv.2 금빛 물결"), 관계 팀컬러는 레벨이 없다.
능력치 값 색상도 데이터센터와 같은 10점 구간 기준(playerinfo.stat_color).
"포지션별 오버롤" 탭 — 데이터센터 축구장 그림의 16개 포지션 값(1강·적응도 +1 기준)stats.own_squadmodels.period_stats) + 현재/최장 연승·연패(models.longest_streaks)shootDetail만으로 계산(추가 조회 없음).
선제골 승률(stats.clutch_summary: 내가 선제골/선제 실점 시 승률, 역전승·역전패),
정규시간 15분 6구간+연장의 득실 분포(stats.goal_minute_buckets),
시각대별 승률(stats.time_of_day_rates: 심야/오전/오후/저녁밤 4구간)shootDetail을 슈터(spId)·도움(assistSpId)별로 모아
선수별 슛·유효슛·골·전환율·xG·어시스트(stats.finishing_ranking). "선수별 결정력"
탭, 골−xG에 색(+초록/−빨강), 선수 더블클릭 시 선수 카드. 표시 구간 기준stats.shot_xg. 넥슨이 정답값을 안 줘서 추정치(비공식).
2.9.1 부터 격자 표: 골라인 거리 5m × 중앙 폭 5m × 슛 종류 칸마다 실제 득점 비율(표본이 적은 칸은
상위 칸 쪽으로 당김 · 페널티킥은 상수). 감독모드 약 2만 6천 경기의 슛에서 개발자 계정 슛을 빼고 세웠다 —
표는 xg_grid.py(생성물 · python tools/fit_xg.py --write), 읽기는 xgmodel.predict.
옛 로지스틱(거리·각도 + 헤더 ×0.7)보다 검증 슛 로그손실 11% 낮고 보정 오차 6.9 → 0.8%p(ROADMAP 43 측정 2·2d).
보정을 잰 등급은 챔피언스shootDetail의 x/y 좌표를 공격 진영 하프 피치 위에 점으로
(stats.shot_map, widgets.ShotMapWidget). 골=초록·유효슛=노랑·빗나감=회색,
골대맞음은 흰 테두리. "슛 맵" 탭에서 내 슛/상대 슛(실점 위치) 토글, 골·유효슛·
빗나감 종류별 표시 on/off 체크박스, 표시 구간 기준. 요약(슛·골·유효슛률·전환율)은
필터와 무관하게 전체 기준으로 표시. 상대 슛은 좌표가 상대 공격 기준이라 y(좌우)를
뒤집어 내 시점으로 통일stats.shot_type_breakdown ·
stats.shot_distance_breakdown · widgets.RatioBarRow). 이미 만든 ShotMap만
쓰는 순수 계산이라 추가 조회·파싱이 없다. 분모가 골이 아니라 슛 —
"전체 골 중 헤딩이 10%"(result_breakdown.goal_types)와 "헤딩 슛의 20%가
들어간다"는 다른 지표다. 거리는 박스 안(inPenalty) / 박스 밖 ~25m / 25m 이상,
박스 안 여부는 좌표 환산 대신 넥슨이 직접 주는 inPenalty를 그대로 쓴다.
슛 5개 미만인 칸은 비율을 숨긴다(MIN_BUCKET_SHOTS) — 1/2=50%는 정보가 아니다.
위쪽 내 슛/상대 슛 토글이 그대로 걸려서 상대 슛으로 두면 "어떤 유형·거리에
실점하는가"가 된다division)별 승률·
평균 득실(stats.division_stats)과 내 점유율 구간별(열세<40·균형40~60·우세>60)
승률(stats.possession_stats). 누적 전체 기준. 1.2.1 규율·불운(stats.discipline_stats) —
몰수는 결과 문자열이 아니라 양쪽 matchEndType 으로 가른다(stats.end_kind — 몰수 경기의
matchResult 는 그냥 "승"·"패"라, 그전엔 "경기 결과"의 몰수 줄이 늘 0 이었다)stats.after_streak_rates. 흐림 기준은 흐름 분석 문장과 같은
analysis.streak_min_n(전체의 2%, 최소 8). 실DB 3계정에서 차이가 최대 5.9%p 라 문장은 거의 안 나온다user/maxdivision 을 메인 검색마다 1건(재시도 없음 · 상세 받기가 끝난 뒤),
랭커 카드 머리 아래 한 줄. 신호(max_division_ready)는 늘 finished_ok 뒤에 보낸다stats.pair_synergy).
1.2.1 에서 삭제(메뉴 정리)analysis.narrate). 최근 흐름은 최근 20경기,
이기는/지는 패턴은 누적 전체 기준으로 나눠 잰다(패턴을 20경기로 말하면 조건부로
쪼갤 때 표본이 6~8경기로 줄어 노이즈를 패턴으로 읽는다). 두 층을 대조해
"선제골 승률은 76%인데 최근엔 선제골 자체가 안 나온다" 같은 문장을 만든다.
규칙별 최소 표본에 못 미치면 문장을 내지 않는다만들면서 무엇이 어떻게 깨졌고 어떻게 알아냈는지를 docs/notes/ 에
두 편으로 적었다. 계산이 어려운 앱이 아니라서, 틀린 것도 계산이 아닌 쪽에서 나왔다.
| 노트 | |
|---|---|
| 01 | 정정한 사실을 문서에 다시 심었다 — 틀렸다고 커밋에 적어 놓고 6일 뒤 문서에 그 문장을 다시 넣었다 |
| 02 | 숫자로는 침묵하고 막대로는 말했다 — 표본이 모자라 비율은 숨기면서 막대는 실제 길이로 그렸다 |
고르고 남은 후보 40건과 왜 안 골랐는지는 CANDIDATES.md.
다섯 프로젝트의 공개 색인은 https://yim2412.github.io 에 있다.
앱 첫 실행 창과 [정보] 창에 같은 글이 있다(notice.py 한 곳). 요약:
%LOCALAPPDATA%\피파전적관리 에만 있다. 오류 기록(crash.log)에는 PC 폴더 경로(사용자 이름)가 들어갈 수
있으니 보내기 전에 열어 확인한다.소스 코드는 MIT. 배포하는 실행 파일은 PyQt6(GPL v3) 를 포함하므로 실행 파일 전체는 GPL v3
조건으로 배포된다 — 소스는 이 저장소에 있다. 포함된 오픈소스 목록은 notice.THIRD_PARTY, 라이선스 전문은
배포물의 _internal\licenses\(빌드 때 설치된 패키지에서 모으고, tools/release.py 가 빠진 게 없는지 확인한다).