Analise recencia
@@ -81,7 +81,7 @@
{{ form.lottery_type }}
-
Baseado no historico recente simulado ate o admin importar dados reais.
+
Baseado no histórico recente já restaurado no banco e nas configurações atuais de cada loteria.
{{ form.lottery_type.errors }}
@@ -258,17 +258,11 @@ document.addEventListener('DOMContentLoaded', function() {
let selectedNumbers = new Set();
let currentMax = 60;
- const lotteryConfigs = {
- 'mega_sena': 60,
- 'quina': 80,
- 'dupla_sena': 50,
- 'lotomania': 100,
- 'lotofacil': 25
- };
+ const lotteryConfigs = {{ lottery_configs_json|safe }};
function renderGrid() {
const type = lotterySelect.value;
- currentMax = lotteryConfigs[type] || 60;
+ currentMax = (lotteryConfigs[type] && lotteryConfigs[type].max_number) || 60;
grid.innerHTML = '';
selectedNumbers.clear();
updateUI();
@@ -301,8 +295,9 @@ document.addEventListener('DOMContentLoaded', function() {
renderGrid(); // Initial load
btnLive.onclick = async () => {
- if (selectedNumbers.size < 6) {
- alert('Por favor, selecione pelo menos 6 números.');
+ const minimumRequired = (lotteryConfigs[lotterySelect.value] && lotteryConfigs[lotterySelect.value].numbers_to_draw) || 6;
+ if (selectedNumbers.size < minimumRequired) {
+ alert(`Por favor, selecione pelo menos ${minimumRequired} números para esta loteria.`);
return;
}
diff --git a/core/views.py b/core/views.py
index 484c64f..c8ab532 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,72 +1,259 @@
-from django.shortcuts import render, get_object_or_404, redirect
-from django.http import JsonResponse, HttpResponse
-from .models import Lottery, DrawResult, AdminAccess
from collections import Counter
-import random
-from django import get_version
-import json
import csv
+import json
+import math
+import random
+
+from django import get_version
+from django.http import HttpResponse, JsonResponse
+from django.shortcuts import get_object_or_404, redirect, render
+
+from .forms import LotterySimulatorForm
+from .models import AdminAccess, DrawResult, Lottery
+
+
+def _format_int(value):
+ return f"{int(value):,}".replace(",", ".")
+
+
+def _format_percent(value):
+ if value <= 0:
+ return "0%"
+ if value < 0.000001:
+ return "< 0,000001%"
+ return f"{value:.6f}%".replace(".", ",")
+
+
+def _parse_annulled_numbers(lottery):
+ return [int(number.strip()) for number in lottery.annulled_numbers.split(",") if number.strip().isdigit()]
+
+
+def _lottery_queryset():
+ return Lottery.objects.all().order_by("id")
+
+
+def _lottery_choices():
+ return [(lottery.name, lottery.get_name_display()) for lottery in _lottery_queryset()]
+
+
+def _get_recent_draws(lottery, draws_to_consider=0):
+ queryset = DrawResult.objects.filter(lottery=lottery).order_by("-draw_number")
+ if draws_to_consider:
+ queryset = queryset[:draws_to_consider]
+ return [[int(number) for number in draw.numbers.split(",") if number] for draw in queryset]
+
+
+def _rank_numbers(lottery, draw_matrix):
+ total_draws = len(draw_matrix)
+ if not total_draws:
+ ordered = list(range(1, lottery.max_number + 1))
+ return ordered, ordered[: lottery.numbers_to_draw], ordered[-lottery.numbers_to_draw :]
+
+ counts = Counter(number for draw in draw_matrix for number in draw)
+ last_seen = {}
+ for index, draw in enumerate(draw_matrix):
+ for number in draw:
+ last_seen.setdefault(number, index)
+
+ scored = []
+ for number in range(1, lottery.max_number + 1):
+ frequency_score = counts.get(number, 0) / total_draws
+ delay_score = last_seen.get(number, total_draws) / total_draws
+ total_score = (frequency_score * 0.7) + (delay_score * 0.3)
+ scored.append((number, total_score))
+
+ scored.sort(key=lambda item: (-item[1], item[0]))
+ ranked_numbers = [number for number, _ in scored]
+ hot_numbers = ranked_numbers[: lottery.numbers_to_draw]
+ cold_numbers = [number for number, _ in sorted(scored, key=lambda item: (item[1], item[0]))[: lottery.numbers_to_draw]]
+ return ranked_numbers, hot_numbers, cold_numbers
+
+
+def _generate_suggestions(lottery, ranked_numbers, games_requested, annulled_numbers):
+ if not ranked_numbers:
+ ranked_numbers = list(range(1, lottery.max_number + 1))
+
+ filtered_pool = [number for number in ranked_numbers if number not in annulled_numbers]
+ if len(filtered_pool) < lottery.numbers_to_draw:
+ filtered_pool = ranked_numbers[:]
+
+ pool_size = min(len(filtered_pool), max(lottery.numbers_to_draw * 4, lottery.numbers_to_draw))
+ candidate_pool = filtered_pool[:pool_size]
+ display_total = min(games_requested, 12) if games_requested < 1_000_000_000_000 else 6
+
+ suggestions = []
+ seen = set()
+ attempt = 0
+ while len(suggestions) < display_total and attempt < display_total * 10:
+ generator = random.Random(f"{lottery.name}:{games_requested}:{attempt}:{','.join(map(str, candidate_pool[:20]))}")
+ sample = sorted(generator.sample(candidate_pool, k=min(lottery.numbers_to_draw, len(candidate_pool))))
+ key = tuple(sample)
+ if key not in seen and len(sample) == lottery.numbers_to_draw:
+ seen.add(key)
+ suggestions.append(sample)
+ attempt += 1
+
+ if not suggestions:
+ suggestions.append(sorted(candidate_pool[: lottery.numbers_to_draw]))
+
+ return suggestions
+
+
+def _build_lottery_cards(lotteries):
+ tagline_map = {
+ "mega_sena": "6 dezenas no volante principal",
+ "quina": "5 dezenas com universo amplo",
+ "dupla_sena": "duas chances por concurso",
+ "lotomania": "análise ampla para dezenas recorrentes",
+ "lotofacil": "equilíbrio para 15 dezenas",
+ "timemania": "histórico recente com foco estatístico",
+ "dia_de_sorte": "recorte curto com leitura de frequência",
+ "federal": "modelo estatístico interno por sequência",
+ "super_sete": "sequências compactas por coluna",
+ "maismilionaria": "base principal de 6 dezenas",
+ }
+
+ cards = []
+ for lottery in lotteries:
+ try:
+ combinations = math.comb(lottery.max_number, lottery.numbers_to_draw)
+ odds = f"1 em {_format_int(combinations)}"
+ except ValueError:
+ odds = "Configuração personalizada"
+
+ cards.append({
+ "label": lottery.get_name_display(),
+ "tagline": tagline_map.get(lottery.name, "Análise estatística por histórico real"),
+ "picks": lottery.numbers_to_draw,
+ "range_max": lottery.max_number,
+ "odds": odds,
+ })
+ return cards
+
+
+def _build_home_result(form):
+ if not form.is_valid():
+ return None
+
+ lottery = get_object_or_404(Lottery, name=form.cleaned_data["lottery_type"])
+ draws_to_consider = int(form.cleaned_data["draws_to_consider"])
+ games_requested = int(form.cleaned_data["games_to_generate"])
+ draw_matrix = _get_recent_draws(lottery, draws_to_consider)
+ ranked_numbers, hot_numbers, cold_numbers = _rank_numbers(lottery, draw_matrix)
+ annulled_numbers = _parse_annulled_numbers(lottery)
+ reclaimed_numbers = [number for number in hot_numbers if number in annulled_numbers]
+ total_combinations = math.comb(lottery.max_number, lottery.numbers_to_draw)
+ probability = 100 / total_combinations if total_combinations else 0
+ suggestions = _generate_suggestions(lottery, ranked_numbers, games_requested, annulled_numbers)
+
+ trillion_labels = {
+ 1000000000000: "1 trilhão",
+ 10000000000000: "10 trilhões",
+ 30000000000000: "30 trilhões",
+ 60000000000000: "60 trilhões",
+ }
+
+ return {
+ "lottery": lottery.get_name_display(),
+ "draws_used": len(draw_matrix),
+ "total_combinations": _format_int(total_combinations),
+ "odds": f"1 em {_format_int(total_combinations)}",
+ "percent": _format_percent(probability),
+ "hot_numbers": hot_numbers,
+ "cold_numbers": cold_numbers,
+ "annulled_numbers": annulled_numbers,
+ "reclaimed_numbers": reclaimed_numbers,
+ "suggestions": suggestions,
+ "is_trillion": games_requested >= 1000000000000,
+ "trillion_label": trillion_labels.get(games_requested, _format_int(games_requested)),
+ }
+
def home(request):
- """Página inicial com resumo das estatísticas de IA."""
- loterias = Lottery.objects.all()
+ """Página inicial com resumo das estatísticas e simulador principal."""
+ lotteries = list(_lottery_queryset())
+ form = LotterySimulatorForm(
+ request.POST or None,
+ lottery_choices=[(lottery.name, lottery.get_name_display()) for lottery in lotteries],
+ )
+ result = _build_home_result(form) if request.method == "POST" else None
+
stats = []
- for lottery in loterias:
- last_draw = DrawResult.objects.filter(lottery=lottery).order_by('-draw_number').first()
+ for lottery in lotteries:
+ last_draw = DrawResult.objects.filter(lottery=lottery).order_by("-draw_number").first()
stats.append({
- 'name': lottery.get_name_display(),
- 'key': lottery.name,
- 'last_draw': last_draw.draw_number if last_draw else "N/A",
- 'last_numbers': last_draw.numbers.split(',') if last_draw else [],
- 'max_number': lottery.max_number
+ "name": lottery.get_name_display(),
+ "key": lottery.name,
+ "last_draw": last_draw.draw_number if last_draw else "N/A",
+ "last_numbers": last_draw.numbers.split(",") if last_draw else [],
+ "max_number": lottery.max_number,
+ "numbers_to_draw": lottery.numbers_to_draw,
})
- return render(request, "core/index.html", {"stats": stats, "django_version": get_version()})
+
+ overview_names = [lottery.get_name_display() for lottery in lotteries[:4]]
+ lottery_configs = {
+ lottery.name: {
+ "max_number": lottery.max_number,
+ "numbers_to_draw": lottery.numbers_to_draw,
+ }
+ for lottery in lotteries
+ }
+
+ context = {
+ "form": form,
+ "result": result,
+ "stats": stats,
+ "django_version": get_version(),
+ "lottery_cards": _build_lottery_cards(lotteries),
+ "lottery_count": len(lotteries),
+ "lottery_overview": ", ".join(overview_names) + (" e mais" if len(lotteries) > 4 else ""),
+ "lottery_configs_json": json.dumps(lottery_configs),
+ }
+ return render(request, "core/index.html", context)
+
def lottery_info_api(request, lottery_key):
- """
- Supercomputador de Elite 99.9% - Sincronizado com 10.000 concursos.
- Calcula dezenas de elite baseadas em convergência matemática de alto desempenho.
- """
+ """Retorna indicadores estatísticos da loteria selecionada para o gerador sequencial."""
lottery = get_object_or_404(Lottery, name=lottery_key)
- annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
-
- draws_db = DrawResult.objects.filter(lottery=lottery).order_by('draw_number')
- real_draws = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
+ annulled = _parse_annulled_numbers(lottery)
+
+ draws_db = DrawResult.objects.filter(lottery=lottery).order_by("draw_number")
+ real_draws = [[int(n) for n in draw.numbers.split(",")] for draw in draws_db]
last_real_num = draws_db.last().draw_number if draws_db.exists() else 0
-
+
random.seed(f"{lottery_key}_supercomputer")
all_draws = list(real_draws)
max_num = lottery.max_number
n_draw = lottery.numbers_to_draw
-
+
while len(all_draws) < 10000:
- hist_flat = [n for d in all_draws[-50:] for n in d]
+ hist_flat = [number for draw in all_draws[-50:] for number in draw]
counts = Counter(hist_flat)
candidates = []
- for n in range(1, max_num + 1):
- score = 100 - (counts.get(n, 0) * 2)
- candidates.append((n, score + random.randint(1, 10)))
- candidates.sort(key=lambda x: x[1], reverse=True)
- all_draws.append(sorted([c[0] for c in candidates[:n_draw]]))
+ for number in range(1, max_num + 1):
+ score = 100 - (counts.get(number, 0) * 2)
+ candidates.append((number, score + random.randint(1, 10)))
+ candidates.sort(key=lambda item: item[1], reverse=True)
+ all_draws.append(sorted(candidate[0] for candidate in candidates[:n_draw]))
- global_counts = Counter(n for d in all_draws for n in d)
+ global_counts = Counter(number for draw in all_draws for number in draw)
last_seen_real = {}
- if real_draws:
- for i, d in enumerate(reversed(real_draws)):
- for n in d:
- if n not in last_seen_real: last_seen_real[n] = i
-
- elite_candidates = []
- for n in range(1, max_num + 1):
- if n in annulled: continue
- freq_score = (global_counts.get(n, 0) / 10000.0) * 100
- delay_score = last_seen_real.get(n, len(real_draws)) * 1.5
- total_score = (freq_score * 0.4) + (delay_score * 0.6)
- elite_candidates.append({'num': n, 'score': total_score})
+ for index, draw in enumerate(reversed(real_draws)):
+ for number in draw:
+ last_seen_real.setdefault(number, index)
- elite_candidates.sort(key=lambda x: x['score'], reverse=True)
- elite_greens = [c['num'] for c in elite_candidates[:20]]
- next_prediction = sorted([c['num'] for c in elite_candidates[:n_draw]])
+ elite_candidates = []
+ for number in range(1, max_num + 1):
+ if number in annulled:
+ continue
+ freq_score = (global_counts.get(number, 0) / 10000.0) * 100
+ delay_score = last_seen_real.get(number, len(real_draws)) * 1.5
+ total_score = (freq_score * 0.4) + (delay_score * 0.6)
+ elite_candidates.append({"num": number, "score": total_score})
+
+ elite_candidates.sort(key=lambda item: item["score"], reverse=True)
+ elite_greens = [candidate["num"] for candidate in elite_candidates[:20]]
+ next_prediction = sorted(candidate["num"] for candidate in elite_candidates[:n_draw])
return JsonResponse({
"name": lottery.get_name_display(),
@@ -74,78 +261,112 @@ def lottery_info_api(request, lottery_key):
"numbers_to_draw": lottery.numbers_to_draw,
"elite_greens": elite_greens,
"annulled_numbers": annulled,
- "reclaimed_numbers": [n for n in elite_greens if n in annulled][:5],
+ "reclaimed_numbers": [number for number in elite_greens if number in annulled][:5],
"supercomputer_sync": 10000,
"last_real_contest": last_real_num,
"next_prediction": next_prediction,
- "precision": "99.9%"
+ "precision": "99.9%",
})
+
def sequential_generator(request):
- loterias = Lottery.objects.all()
+ loterias = _lottery_queryset()
return render(request, "core/sequential_generator.html", {"loterias": loterias})
+
def lottery_results(request):
- loterias = Lottery.objects.all()
+ loterias = _lottery_queryset()
results_data = []
for lottery in loterias:
- all_draws = DrawResult.objects.filter(lottery=lottery).order_by('-draw_number')
+ all_draws = DrawResult.objects.filter(lottery=lottery).order_by("-draw_number")
if all_draws.exists():
current_draw = all_draws.first()
- current_numbers = [n.strip().zfill(2) for n in current_draw.numbers.split(',')]
+ current_numbers = [number.strip().zfill(2) for number in current_draw.numbers.split(",")]
results_data.append({
- 'lottery': lottery,
- 'last_draw': current_draw,
- 'current_numbers': current_numbers,
- 'prediction': ["??"] * lottery.numbers_to_draw
+ "lottery": lottery,
+ "last_draw": current_draw,
+ "current_numbers": current_numbers,
+ "prediction": ["??"] * lottery.numbers_to_draw,
})
return render(request, "core/results_ia.html", {"results": results_data})
+
def hits_report(request):
return render(request, "core/hits_report.html")
+
def admin_login(request):
if request.method == "POST":
key = request.POST.get("private_key")
if AdminAccess.objects.filter(private_key=key).exists() or key == "admin123":
- request.session['admin_auth'] = True
- return redirect('admin_dashboard')
+ request.session["admin_auth"] = True
+ return redirect("admin_dashboard")
return render(request, "core/admin_login.html")
+
def admin_logout(request):
request.session.flush()
- return redirect('home')
+ return redirect("home")
+
def admin_dashboard(request):
- if not request.session.get('admin_auth'): return redirect('admin_login')
- loterias = Lottery.objects.all()
+ if not request.session.get("admin_auth"):
+ return redirect("admin_login")
+ loterias = _lottery_queryset()
return render(request, "core/admin_dashboard.html", {"loterias": loterias})
+
def edit_lottery(request, lottery_id):
- if not request.session.get('admin_auth'): return redirect('admin_login')
+ if not request.session.get("admin_auth"):
+ return redirect("admin_login")
lottery = get_object_or_404(Lottery, id=lottery_id)
if request.method == "POST":
lottery.annulled_numbers = request.POST.get("annulled_numbers", "")
lottery.save()
- return redirect('admin_dashboard')
+ return redirect("admin_dashboard")
return render(request, "core/edit_lottery.html", {"lottery": lottery})
+
def full_report(request):
return render(request, "core/full_report.html")
+
def download_funnel(request, lottery_id):
lottery = get_object_or_404(Lottery, id=lottery_id)
- response = HttpResponse(content_type='text/csv')
- response['Content-Disposition'] = f'attachment; filename="funnel_{lottery.name}.csv"'
+ response = HttpResponse(content_type="text/csv")
+ response["Content-Disposition"] = f'attachment; filename="funnel_{lottery.name}.csv"'
writer = csv.writer(response)
- writer.writerow(['Number', 'Status'])
- annulled = lottery.annulled_numbers.split(',')
- for n in range(1, lottery.max_number + 1):
- writer.writerow([n, 'Annulled' if str(n) in annulled else 'Active'])
+ writer.writerow(["Number", "Status"])
+ annulled = lottery.annulled_numbers.split(",")
+ for number in range(1, lottery.max_number + 1):
+ writer.writerow([number, "Annulled" if str(number) in annulled else "Active"])
return response
+
def ai_auto_predict(request, lottery_id=None):
return JsonResponse({"status": "success", "message": "Neural re-calibration complete."})
+
def live_math(request):
- return JsonResponse({"status": "live", "data": random.sample(range(1, 61), 6)})
+ if request.method != "POST":
+ return JsonResponse({"error": "Método não permitido."}, status=405)
+
+ payload = json.loads(request.body or "{}")
+ lottery_key = payload.get("lottery")
+ numbers = [int(number) for number in payload.get("numbers", []) if str(number).isdigit()]
+ lottery = get_object_or_404(Lottery, name=lottery_key)
+
+ draw_matrix = _get_recent_draws(lottery, 50)
+ ranked_numbers, hot_numbers, _ = _rank_numbers(lottery, draw_matrix)
+ top_window = set(ranked_numbers[: max(lottery.numbers_to_draw * 2, lottery.numbers_to_draw)])
+ overlap_score = sum(1 for number in numbers if number in top_window)
+ hot_overlap = sum(1 for number in numbers if number in hot_numbers)
+ diversity_bonus = 5 if len(set(number % 2 for number in numbers)) > 1 else 0
+ score = min(99, 35 + (overlap_score * 8) + (hot_overlap * 10) + diversity_bonus)
+
+ return JsonResponse({
+ "status": "success" if score >= 70 else "warning",
+ "score": score,
+ "numbers_checked": len(numbers),
+ "lottery": lottery.get_name_display(),
+ })
diff --git a/restore_app.py b/restore_app.py
index 597b18a..ce553a2 100644
--- a/restore_app.py
+++ b/restore_app.py
@@ -1,87 +1,107 @@
import os
-import django
-import requests
from datetime import datetime
-# Setup Django environment
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
+import django
+import requests
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
django.setup()
-from core.models import Lottery, DrawResult, AdminAccess
+from core.models import AdminAccess, DrawResult, Lottery
+
+
+LOTTERIES = [
+ {"name": "mega_sena", "api_name": "megasena", "min": 1, "max": 60, "draw": 6},
+ {"name": "quina", "api_name": "quina", "min": 1, "max": 80, "draw": 5},
+ {"name": "dupla_sena", "api_name": "duplasena", "min": 1, "max": 50, "draw": 6},
+ {"name": "lotomania", "api_name": "lotomania", "min": 0, "max": 99, "draw": 50},
+ {"name": "lotofacil", "api_name": "lotofacil", "min": 1, "max": 25, "draw": 15},
+ {"name": "timemania", "api_name": "timemania", "min": 1, "max": 80, "draw": 7},
+ {"name": "dia_de_sorte", "api_name": "diadesorte", "min": 1, "max": 31, "draw": 7},
+ {"name": "federal", "api_name": "federal", "min": 0, "max": 99999, "draw": 5},
+ {"name": "super_sete", "api_name": "supersete", "min": 0, "max": 9, "draw": 7},
+ {"name": "maismilionaria", "api_name": "maismilionaria", "min": 1, "max": 50, "draw": 6},
+]
+
def restore_lotteries():
- lotteries_data = [
- ('mega_sena', 1, 60, 6),
- ('quina', 1, 80, 5),
- ('dupla_sena', 1, 50, 6),
- ('lotomania', 0, 99, 50),
- ('lotofacil', 1, 25, 15),
- ('timemania', 1, 80, 7),
- ('dia_de_sorte', 1, 31, 7),
- ('federal', 0, 99999, 5),
- ('super_sete', 0, 9, 7),
- ('maismilionaria', 1, 50, 6),
- ]
-
- for name, min_n, max_n, to_draw in lotteries_data:
- Lottery.objects.get_or_create(
- name=name,
+ created = 0
+ for item in LOTTERIES:
+ lottery, was_created = Lottery.objects.get_or_create(
+ name=item["name"],
defaults={
- 'min_number': min_n,
- 'max_number': max_n,
- 'numbers_to_draw': to_draw
- }
+ "min_number": item["min"],
+ "max_number": item["max"],
+ "numbers_to_draw": item["draw"],
+ },
)
- print("Loterias inicializadas.")
+ if not was_created:
+ changed = False
+ for field, value in {
+ "min_number": item["min"],
+ "max_number": item["max"],
+ "numbers_to_draw": item["draw"],
+ }.items():
+ if getattr(lottery, field) != value:
+ setattr(lottery, field, value)
+ changed = True
+ if changed:
+ lottery.save(update_fields=["min_number", "max_number", "numbers_to_draw"])
+ created += int(was_created)
+ print(f"Loterias prontas. Novas criadas: {created}")
+
def restore_admin():
- if not AdminAccess.objects.exists():
- admin = AdminAccess.objects.create(private_key='admin123')
- print(f"Chave Admin criada: {admin.private_key}")
- else:
- print(f"Chave Admin existente: {AdminAccess.objects.first().private_key}")
+ admin, created = AdminAccess.objects.get_or_create(private_key="admin123")
+ print(f"Chave admin pronta: {admin.private_key} ({'nova' if created else 'existente'})")
-def sync_all_latest():
- from core.views import sync_results
- sync_results()
- print("Sincronização dos últimos resultados concluída.")
-def sync_specific(lottery_name, contest_number):
- mapping = {
- 'mega_sena': 'megasena',
- 'lotofacil': 'lotofacil',
- }
- api_name = mapping.get(lottery_name)
- if not api_name: return
+def sync_history(draws_per_lottery=40):
+ session = requests.Session()
+ inserted = 0
+
+ for item in LOTTERIES:
+ lottery = Lottery.objects.get(name=item["name"])
+ latest_url = f"https://loteriascaixa-api.herokuapp.com/api/{item['api_name']}/latest"
+ latest_response = session.get(latest_url, timeout=15)
+ latest_response.raise_for_status()
+ latest_data = latest_response.json()
+ latest_contest = int(latest_data["concurso"])
+
+ current_inserted = 0
+ for contest in range(latest_contest, max(latest_contest - draws_per_lottery, 0), -1):
+ contest_url = f"https://loteriascaixa-api.herokuapp.com/api/{item['api_name']}/{contest}"
+ response = session.get(contest_url, timeout=15)
+ if response.status_code != 200:
+ continue
- lottery = Lottery.objects.get(name=lottery_name)
- try:
- url = f"https://loteriascaixa-api.herokuapp.com/api/{api_name}/{contest_number}"
- response = requests.get(url, timeout=5)
- if response.status_code == 200:
data = response.json()
- draw_number = int(data.get('concurso'))
- if not DrawResult.objects.filter(lottery=lottery, draw_number=draw_number).exists():
- date_str = data.get('data')
- draw_date = datetime.strptime(date_str, "%d/%m/%Y").date()
- numbers_list = data.get('dezenas', [])
- numbers_str = ",".join([str(int(n)) for n in numbers_list])
- DrawResult.objects.create(
- lottery=lottery,
- draw_number=draw_number,
- draw_date=draw_date,
- numbers=numbers_str
- )
- print(f"Sincronizado específico: {lottery_name} Concurso {draw_number}")
- except Exception as e:
- print(f"Erro ao sincronizar {lottery_name} {contest_number}: {e}")
+ dezenas = data.get("dezenas") or []
+ if not dezenas:
+ continue
-if __name__ == "__main__":
+ draw_date = datetime.strptime(data["data"], "%d/%m/%Y").date()
+ numbers_str = ",".join(str(int(number)) for number in dezenas)
+
+ _, created = DrawResult.objects.get_or_create(
+ lottery=lottery,
+ draw_number=int(data["concurso"]),
+ defaults={"draw_date": draw_date, "numbers": numbers_str},
+ )
+ inserted += int(created)
+ current_inserted += int(created)
+
+ print(f"{item['name']}: ultimo={latest_contest}, novos={current_inserted}")
+
+ print(f"Total de resultados inseridos agora: {inserted}")
+
+
+def main():
restore_lotteries()
restore_admin()
- sync_all_latest()
- # Concursos solicitados na história
- for contest in [2976, 2977]:
- sync_specific('mega_sena', contest)
- sync_specific('lotofacil', contest)
- print("Restauração concluída!")
+ sync_history(draws_per_lottery=40)
+ print("Restauração concluída com sucesso.")
+
+
+if __name__ == "__main__":
+ main()