Compare commits
16 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b3b17f458d | |||
| 47ebaa4fcd | |||
| bebb0a0aa5 | |||
| 3046a2d0b3 | |||
| e7d26abf2f | |||
| 2c85531360 | |||
| 88eabe4613 | |||
| 9ebb2fc9ab | |||
| 844967f578 | |||
| c9b4ee7af6 | |||
| f164cd286b | |||
| e30630ad9d | |||
| b269e01bbf | |||
| 09197b4389 | |||
| b58d4e6f9e | |||
| bf78690baa |
17 changed files with 739 additions and 63 deletions
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
8
.idea/Lotto2PY.iml
generated
Normal file
8
.idea/Lotto2PY.iml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.9" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Lotto2PY.iml" filepath="$PROJECT_DIR$/.idea/Lotto2PY.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
291
6aus49APP/app.py
Normal file
291
6aus49APP/app.py
Normal file
|
|
@ -0,0 +1,291 @@
|
||||||
|
# /opt/lotto/app.py
|
||||||
|
import os
|
||||||
|
from datetime import date, datetime
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from fastapi import FastAPI, Query, Request, HTTPException
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
from fastapi.templating import Jinja2Templates
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from sqlalchemy import create_engine, text
|
||||||
|
from sqlalchemy.engine import Engine, Row
|
||||||
|
from sqlalchemy.pool import NullPool
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 0) Konfiguration laden
|
||||||
|
# --------------------------------------------------------
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
DATABASE_URL = os.getenv("DATABASE_URL")
|
||||||
|
if not DATABASE_URL:
|
||||||
|
raise RuntimeError("DATABASE_URL nicht gesetzt (.env prüfen)")
|
||||||
|
|
||||||
|
PAGE_SIZE = int(os.getenv("PAGE_SIZE", "10"))
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 1) App und DB initialisieren
|
||||||
|
# --------------------------------------------------------
|
||||||
|
engine: Engine = create_engine(DATABASE_URL, poolclass=NullPool, future=True)
|
||||||
|
|
||||||
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
STATIC_DIR = os.path.join(BASE_DIR, "static")
|
||||||
|
TEMPLATE_DIR = os.path.join(BASE_DIR, "templates")
|
||||||
|
|
||||||
|
app = FastAPI(title="Lotto Ziehungen API")
|
||||||
|
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
||||||
|
templates = Jinja2Templates(directory=TEMPLATE_DIR)
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 2) Modelle (Pydantic)
|
||||||
|
# --------------------------------------------------------
|
||||||
|
class Draw(BaseModel):
|
||||||
|
datum: Optional[date]
|
||||||
|
z1: Optional[int]
|
||||||
|
z2: Optional[int]
|
||||||
|
z3: Optional[int]
|
||||||
|
z4: Optional[int]
|
||||||
|
z5: Optional[int]
|
||||||
|
z6: Optional[int]
|
||||||
|
sz: Optional[int]
|
||||||
|
sz1: Optional[int]
|
||||||
|
sz2: Optional[int]
|
||||||
|
super6: Optional[str]
|
||||||
|
spiel77: Optional[str]
|
||||||
|
|
||||||
|
class DrawList(BaseModel):
|
||||||
|
total: int
|
||||||
|
items: List[Draw]
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 3) Hilfsfunktionen
|
||||||
|
# --------------------------------------------------------
|
||||||
|
def normalize_date_sql(column: str) -> str:
|
||||||
|
return (
|
||||||
|
f"COALESCE("
|
||||||
|
f" (CASE WHEN {column} REGEXP '^[0-9]{{4}}-[0-9]{{2}}-[0-9]{{2}}$' THEN DATE({column}) END),"
|
||||||
|
f" STR_TO_DATE({column}, '%d.%m.%Y'),"
|
||||||
|
f" STR_TO_DATE(SUBSTRING_INDEX({column}, '/', -1), '%d.%m.%y')"
|
||||||
|
f")"
|
||||||
|
)
|
||||||
|
|
||||||
|
def row_to_draw(row: Row) -> Draw:
|
||||||
|
return Draw(**row)
|
||||||
|
|
||||||
|
def _to_date(s: Optional[str]) -> Optional[date]:
|
||||||
|
if not s:
|
||||||
|
return None
|
||||||
|
t = s.strip()
|
||||||
|
if not t:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return date.fromisoformat(t)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
for fmt in ("%d.%m.%Y", "%d.%m.%y"):
|
||||||
|
try:
|
||||||
|
return datetime.strptime(t, fmt).date()
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
return None
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 4) Routen
|
||||||
|
# --------------------------------------------------------
|
||||||
|
@app.get("/", response_class=HTMLResponse)
|
||||||
|
async def index(request: Request):
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
"index.html", {"request": request, "page_size": PAGE_SIZE}
|
||||||
|
)
|
||||||
|
|
||||||
|
# -------------------- API: Ziehungen (JSON) ---------------------
|
||||||
|
@app.get("/api/draws", response_model=DrawList)
|
||||||
|
async def list_draws(
|
||||||
|
game: str = Query("6aus49", pattern="^(6aus49|euro)$"),
|
||||||
|
date_from: Optional[date] = Query(None),
|
||||||
|
date_to: Optional[date] = Query(None),
|
||||||
|
limit: int = Query(PAGE_SIZE, ge=1, le=500),
|
||||||
|
offset: int = Query(0, ge=0),
|
||||||
|
order: str = Query("desc", pattern="^(asc|desc)$"),
|
||||||
|
):
|
||||||
|
tbl = "`6aus49`" if game == "6aus49" else "`euro`"
|
||||||
|
dx = normalize_date_sql(f"{tbl}.datum")
|
||||||
|
|
||||||
|
if game == "6aus49":
|
||||||
|
base_select = f"""
|
||||||
|
SELECT {dx} AS datum,
|
||||||
|
z1, z2, z3, z4, z5, z6, sz,
|
||||||
|
CAST(super6 AS CHAR) AS super6,
|
||||||
|
CAST(spiel77 AS CHAR) AS spiel77,
|
||||||
|
NULL AS sz1, NULL AS sz2
|
||||||
|
FROM {tbl}
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
base_select = f"""
|
||||||
|
SELECT {dx} AS datum,
|
||||||
|
z1, z2, z3, z4, z5,
|
||||||
|
NULL AS z6, NULL AS sz,
|
||||||
|
NULL AS super6, NULL AS spiel77,
|
||||||
|
sz1, sz2
|
||||||
|
FROM {tbl}
|
||||||
|
"""
|
||||||
|
|
||||||
|
where_parts = []
|
||||||
|
params = {}
|
||||||
|
if date_from:
|
||||||
|
where_parts.append("datum >= :date_from")
|
||||||
|
params["date_from"] = date_from
|
||||||
|
if date_to:
|
||||||
|
where_parts.append("datum <= :date_to")
|
||||||
|
params["date_to"] = date_to
|
||||||
|
where_sql = "WHERE " + " AND ".join(where_parts) if where_parts else ""
|
||||||
|
order_sql = "ORDER BY datum DESC" if order == "desc" else "ORDER BY datum ASC"
|
||||||
|
|
||||||
|
count_sql = f"SELECT COUNT(*) AS cnt FROM ({base_select}) AS t {where_sql}"
|
||||||
|
data_sql = f"SELECT * FROM ({base_select}) AS t {where_sql} {order_sql} LIMIT :limit OFFSET :offset"
|
||||||
|
|
||||||
|
with engine.begin() as conn:
|
||||||
|
total = conn.execute(text(count_sql), params).scalar_one()
|
||||||
|
rows = conn.execute(text(data_sql), {**params, "limit": limit, "offset": offset}).mappings().all()
|
||||||
|
items = [row_to_draw(r) for r in rows]
|
||||||
|
|
||||||
|
return DrawList(total=total, items=items)
|
||||||
|
|
||||||
|
# -------------------- API: Detail (JSON) ------------------------
|
||||||
|
@app.get("/api/draw/{game}/{draw_date}", response_model=Draw)
|
||||||
|
async def get_draw(game: str, draw_date: date):
|
||||||
|
tbl = "`6aus49`" if game == "6aus49" else "`euro`"
|
||||||
|
dx = normalize_date_sql(f"{tbl}.datum")
|
||||||
|
|
||||||
|
if game == "6aus49":
|
||||||
|
sql = text(f"""
|
||||||
|
SELECT {dx} AS datum,
|
||||||
|
z1, z2, z3, z4, z5, z6, sz,
|
||||||
|
CAST(super6 AS CHAR) AS super6,
|
||||||
|
CAST(spiel77 AS CHAR) AS spiel77,
|
||||||
|
NULL AS sz1, NULL AS sz2
|
||||||
|
FROM {tbl}
|
||||||
|
WHERE {dx} = :d
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
sql = text(f"""
|
||||||
|
SELECT {dx} AS datum,
|
||||||
|
z1, z2, z3, z4, z5,
|
||||||
|
NULL AS z6, NULL AS sz,
|
||||||
|
NULL AS super6, NULL AS spiel77,
|
||||||
|
sz1, sz2
|
||||||
|
FROM {tbl}
|
||||||
|
WHERE {dx} = :d
|
||||||
|
""")
|
||||||
|
|
||||||
|
with engine.begin() as conn:
|
||||||
|
row = conn.execute(sql, {"d": draw_date}).mappings().first()
|
||||||
|
if not row:
|
||||||
|
raise HTTPException(status_code=404, detail="Ziehung nicht gefunden")
|
||||||
|
return row_to_draw(row)
|
||||||
|
|
||||||
|
# -------------------- UI / HTMX (HTML) -------------------------
|
||||||
|
@app.get("/ui/draws", response_class=HTMLResponse)
|
||||||
|
async def ui_draws(
|
||||||
|
request: Request,
|
||||||
|
game: str = Query("6aus49", pattern="^(6aus49|euro)$"),
|
||||||
|
date_from: Optional[str] = Query(None),
|
||||||
|
date_to: Optional[str] = Query(None),
|
||||||
|
limit: int = Query(PAGE_SIZE, ge=1, le=500),
|
||||||
|
offset: int = Query(0, ge=0),
|
||||||
|
order: str = Query("desc", pattern="^(asc|desc)$"),
|
||||||
|
):
|
||||||
|
d_from = _to_date(date_from)
|
||||||
|
d_to = _to_date(date_to)
|
||||||
|
|
||||||
|
result = await list_draws(game, d_from, d_to, limit, offset, order) # type: ignore
|
||||||
|
|
||||||
|
rows_html = []
|
||||||
|
if game == "6aus49":
|
||||||
|
header = (
|
||||||
|
"<tr><th>Datum</th><th>Zahlen</th><th>Superzahl</th><th>Super 6</th><th>Spiel 77</th></tr>"
|
||||||
|
)
|
||||||
|
for r in result.items:
|
||||||
|
numbers = " ".join(
|
||||||
|
f"<span class='badge'>{getattr(r, f'z{i}')}</span>"
|
||||||
|
for i in range(1, 7)
|
||||||
|
if getattr(r, f"z{i}") is not None
|
||||||
|
)
|
||||||
|
sz_html = "" if r.sz is None else r.sz
|
||||||
|
rows_html.append(
|
||||||
|
f"<tr><td>{r.datum or ''}</td><td class='numbers'>{numbers}</td>"
|
||||||
|
f"<td><b>{sz_html}</b></td><td>{r.super6 or ''}</td><td>{r.spiel77 or ''}</td></tr>"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
header = "<tr><th>Datum</th><th>Zahlen</th><th>Super 1</th><th>Super 2</th></tr>"
|
||||||
|
for r in result.items:
|
||||||
|
numbers = " ".join(
|
||||||
|
f"<span class='badge'>{getattr(r, f'z{i}')}</span>"
|
||||||
|
for i in range(1, 6)
|
||||||
|
if getattr(r, f"z{i}") is not None
|
||||||
|
)
|
||||||
|
sz1_html = "" if r.sz1 is None else r.sz1
|
||||||
|
sz2_html = "" if r.sz2 is None else r.sz2
|
||||||
|
rows_html.append(
|
||||||
|
f"<tr><td>{r.datum or ''}</td><td class='numbers'>{numbers}</td>"
|
||||||
|
f"<td><b>{sz1_html}</b></td><td><b>{sz2_html}</b></td></tr>"
|
||||||
|
)
|
||||||
|
|
||||||
|
html = (
|
||||||
|
f"<p class='muted'>Treffer: {result.total}</p>"
|
||||||
|
f"<table role='grid'><thead>{header}</thead><tbody>{''.join(rows_html)}</tbody></table>"
|
||||||
|
)
|
||||||
|
return HTMLResponse(html)
|
||||||
|
|
||||||
|
# -------------------- UI: Header-Kugeln (inkl. Datum) -------------------------
|
||||||
|
@app.get("/ui/header", response_class=HTMLResponse)
|
||||||
|
async def ui_header(
|
||||||
|
game: str = Query("6aus49", pattern="^(6aus49|euro)$"),
|
||||||
|
date_from: Optional[str] = Query(None),
|
||||||
|
date_to: Optional[str] = Query(None),
|
||||||
|
order: str = Query("desc", pattern="^(asc|desc)$"),
|
||||||
|
):
|
||||||
|
d_from = _to_date(date_from)
|
||||||
|
d_to = _to_date(date_to)
|
||||||
|
|
||||||
|
result = await list_draws(game, d_from, d_to, limit=1, offset=0, order=order) # type: ignore
|
||||||
|
if not result.items:
|
||||||
|
return HTMLResponse("<div class='balls' aria-hidden='true'></div>")
|
||||||
|
|
||||||
|
r = result.items[0]
|
||||||
|
date_label = r.datum.strftime("%d.%m.%Y") if r.datum else ""
|
||||||
|
|
||||||
|
if game == "6aus49":
|
||||||
|
nums = " ".join(
|
||||||
|
f"<div class='ball'>{getattr(r, f'z{i}')}</div>"
|
||||||
|
for i in range(1, 7)
|
||||||
|
if getattr(r, f"z{i}") is not None
|
||||||
|
)
|
||||||
|
sz_html = "" if r.sz is None else f"<div class='ball super-ball'><b>{r.sz}</b></div>"
|
||||||
|
html = f"""
|
||||||
|
<div class="balls" title="Letzte Ziehung {date_label}">
|
||||||
|
{nums}{sz_html}
|
||||||
|
<span class="label">Stand: {date_label}</span>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
nums = " ".join(
|
||||||
|
f"<div class='ball'>{getattr(r, f'z{i}')}</div>"
|
||||||
|
for i in range(1, 6)
|
||||||
|
if getattr(r, f"z{i}") is not None
|
||||||
|
)
|
||||||
|
s1 = "" if r.sz1 is None else f"<div class='star'>{r.sz1}</div>"
|
||||||
|
s2 = "" if r.sz2 is None else f"<div class='star'>{r.sz2}</div>"
|
||||||
|
html = f"""
|
||||||
|
<div class="balls" title="Letzte Ziehung {date_label}">
|
||||||
|
{nums}{s1}{s2}
|
||||||
|
<span class="label">Stand: {date_label}</span>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
return HTMLResponse(html)
|
||||||
|
|
||||||
|
# -------------------- Healthcheck --------------------------
|
||||||
|
@app.get("/health")
|
||||||
|
def health():
|
||||||
|
return {"status": "ok"}
|
||||||
15
6aus49APP/requirements.txt
Normal file
15
6aus49APP/requirements.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
fastapi==0.115.0
|
||||||
|
uvicorn[standard]==0.30.0
|
||||||
|
SQLAlchemy==2.0.34
|
||||||
|
PyMySQL==1.1.1
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
jinja2==3.1.4
|
||||||
|
pydantic==2.9.2
|
||||||
|
fastapi==0.115.0
|
||||||
|
uvicorn[standard]==0.30.0
|
||||||
|
SQLAlchemy==2.0.34
|
||||||
|
psycopg2-binary==2.9.9
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
jinja2==3.1.4
|
||||||
|
pydantic==2.9.2
|
||||||
|
|
||||||
41
6aus49APP/static/app.js
Normal file
41
6aus49APP/static/app.js
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
function renderDrawsTable(data) {
|
||||||
|
if (!data || !Array.isArray(data.items)) {
|
||||||
|
return '<p class="muted">Keine Daten</p>';
|
||||||
|
}
|
||||||
|
const rows = data.items.map(d => `
|
||||||
|
<tr>
|
||||||
|
<td class="nowrap"><a href="/api/draw/${d.datum}" target="_blank">${d.datum}</a></td>
|
||||||
|
<td class="numbers">${[d.z1,d.z2,d.z3,d.z4,d.z5,d.z6].map(n => `<span class="badge">${n}</span>`).join(' ')}</td>
|
||||||
|
<td class="nowrap"><strong>${d.sz}</strong></td>
|
||||||
|
</tr>
|
||||||
|
`).join('');
|
||||||
|
return `
|
||||||
|
<p class="muted">Treffer: ${data.total}</p>
|
||||||
|
<table role="grid">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Datum</th><th>Zahlen</th><th>Superzahl</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>${rows}</tbody>
|
||||||
|
</table>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFrequencyPanels(data) {
|
||||||
|
const z = (data.zahlen || []).map(x => `<tr><td>${x.zahl}</td><td>${x.haeufigkeit}</td></tr>`).join('');
|
||||||
|
const sz = (data.superzahl || []).map(x => `<tr><td>${x.zahl}</td><td>${x.haeufigkeit}</td></tr>`).join('');
|
||||||
|
return `
|
||||||
|
<div>
|
||||||
|
<h3>Häufigkeit Zahlen (1–49)</h3>
|
||||||
|
<table role="grid">
|
||||||
|
<thead><tr><th>Zahl</th><th>Häufigkeit</th></tr></thead>
|
||||||
|
<tbody>${z}</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Häufigkeit Superzahl (0–9)</h3>
|
||||||
|
<table role="grid">
|
||||||
|
<thead><tr><th>Superzahl</th><th>Häufigkeit</th></tr></thead>
|
||||||
|
<tbody>${sz}</tbody>
|
||||||
|
</table>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
143
6aus49APP/templates/index.html
Normal file
143
6aus49APP/templates/index.html
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Lotto-Ziehungen</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
|
||||||
|
<link rel="icon" href="{{ request.url_for('static', path='favicon.ico') if request else '/static/favicon.ico' }}">
|
||||||
|
<style>
|
||||||
|
:root{
|
||||||
|
--brand-green:#0a6;
|
||||||
|
--brand-green-dark:#085f42;
|
||||||
|
--table-border:#ddd;
|
||||||
|
--paper:#fff;
|
||||||
|
--bg:#f6f6f6;
|
||||||
|
--ink:#222;
|
||||||
|
--muted:#666;
|
||||||
|
--gold:#c6a100;
|
||||||
|
--gold2:#f1d65c;
|
||||||
|
}
|
||||||
|
body{
|
||||||
|
font-family:"Segoe UI", Arial, sans-serif;
|
||||||
|
background:var(--bg);
|
||||||
|
color:var(--ink);
|
||||||
|
margin:0; padding:2rem;
|
||||||
|
}
|
||||||
|
main{
|
||||||
|
max-width:960px; margin:0 auto;
|
||||||
|
background:var(--paper);
|
||||||
|
border:1px solid #ddd; border-radius:8px;
|
||||||
|
box-shadow:0 2px 5px rgba(0,0,0,.05);
|
||||||
|
padding:2rem 2.5rem;
|
||||||
|
}
|
||||||
|
.brandbar{ display:flex; align-items:center; justify-content:space-between; gap:1rem; margin-bottom:.2rem; }
|
||||||
|
.brand-left{ display:flex; align-items:center; gap:.8rem; }
|
||||||
|
.brand-left img{ height:54px; width:auto; display:block; filter:drop-shadow(0 2px 2px rgba(0,0,0,.15)); }
|
||||||
|
h1{ margin:0; font-size:1.9rem; font-weight:600; letter-spacing:.02em; }
|
||||||
|
|
||||||
|
/* Kugeln */
|
||||||
|
.balls{ display:flex; align-items:center; gap:.35rem; flex-wrap:wrap; }
|
||||||
|
.ball, .star{
|
||||||
|
display:inline-flex; align-items:center; justify-content:center;
|
||||||
|
width:34px; height:34px; border-radius:50%;
|
||||||
|
font-weight:700; font-size:.95rem; color:#fff;
|
||||||
|
box-shadow:inset 0 2px 6px rgba(0,0,0,.25), 0 1px 2px rgba(0,0,0,.08);
|
||||||
|
user-select:none;
|
||||||
|
}
|
||||||
|
.ball{
|
||||||
|
background:radial-gradient(120% 120% at 30% 30%, #15b77d 0%, var(--brand-green) 55%, var(--brand-green-dark) 100%);
|
||||||
|
text-shadow:0 1px 1px rgba(0,0,0,.35);
|
||||||
|
border:1px solid var(--brand-green-dark);
|
||||||
|
}
|
||||||
|
/* Superzahl jetzt goldfarben */
|
||||||
|
.super-ball {
|
||||||
|
background: radial-gradient(120% 120% at 30% 30%, var(--gold2) 0%, var(--gold) 70%, #8a6f00 100%);
|
||||||
|
color: #231;
|
||||||
|
border: 1px solid #a88600;
|
||||||
|
font-weight: 800;
|
||||||
|
text-shadow: 0 1px 1px rgba(255,255,255,.4);
|
||||||
|
}
|
||||||
|
/* Eurojackpot Sterne */
|
||||||
|
.star{
|
||||||
|
background:radial-gradient(120% 120% at 30% 30%, var(--gold2) 0%, var(--gold) 70%, #8a6f00 100%);
|
||||||
|
color:#231; border:1px solid #a88600; font-weight:800;
|
||||||
|
}
|
||||||
|
.balls .label{
|
||||||
|
margin-left:.5rem; font-size:.85rem; color:#666; font-weight:600; white-space:nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.service-note{ text-align:center; margin:.4rem 0 1.6rem 0; font-size:.95rem; color:var(--muted); font-style:italic; }
|
||||||
|
|
||||||
|
form{ display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:.6rem; margin-bottom:1rem; }
|
||||||
|
label{ font-weight:500; }
|
||||||
|
input, select, button{ padding:.35rem .6rem; border:1px solid #bbb; border-radius:4px; background:#fff; font-size:.95rem; }
|
||||||
|
button{ background:var(--brand-green); color:#fff; border:none; font-weight:600; cursor:pointer; transition:background .2s; }
|
||||||
|
button:hover{ background:#098557; }
|
||||||
|
|
||||||
|
table{ width:100%; border-collapse:collapse; margin-top:.5rem; font-size:.95rem; }
|
||||||
|
th, td{ border:1px solid var(--table-border); padding:.45rem .5rem; text-align:center; }
|
||||||
|
th{ background:#efefef; font-weight:600; }
|
||||||
|
.numbers{ text-align:left; }
|
||||||
|
.badge{ display:inline-block; background:var(--brand-green); color:#fff; padding:.25em .5em; border-radius:.4em; margin:0 .1em; font-weight:600; }
|
||||||
|
.muted{ color:#555; font-size:.9rem; margin-top:.5rem; text-align:right; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<!-- Kopf mit Logo links + dynamischen Kugeln rechts -->
|
||||||
|
<div class="brandbar">
|
||||||
|
<div class="brand-left">
|
||||||
|
<img src="{{ request.url_for('static', path='logo.png') }}" alt="Hintergasse Logo">
|
||||||
|
<h1>Lotto-Ziehungen</h1>
|
||||||
|
</div>
|
||||||
|
<div id="header-balls"
|
||||||
|
hx-get="/ui/header"
|
||||||
|
hx-include="#filter-form"
|
||||||
|
hx-trigger="load, change from:#filter-form"
|
||||||
|
hx-target="#header-balls"
|
||||||
|
hx-swap="innerHTML"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="service-note">Ein Service der Hintergasse – Angaben ohne Gewähr!</p>
|
||||||
|
|
||||||
|
<!-- Filterformular -->
|
||||||
|
<form id="filter-form"
|
||||||
|
hx-get="/ui/draws"
|
||||||
|
hx-target="#results"
|
||||||
|
hx-trigger="change, submit"
|
||||||
|
hx-swap="innerHTML">
|
||||||
|
<label for="game">Spiel:</label>
|
||||||
|
<select name="game" id="game">
|
||||||
|
<option value="6aus49">6 aus 49</option>
|
||||||
|
<option value="euro">Eurojackpot</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label for="date_from">von:</label>
|
||||||
|
<input type="date" name="date_from" />
|
||||||
|
|
||||||
|
<label for="date_to">bis:</label>
|
||||||
|
<input type="date" name="date_to" />
|
||||||
|
|
||||||
|
<label for="order">Sortierung:</label>
|
||||||
|
<select name="order">
|
||||||
|
<option value="desc" selected>neueste zuerst</option>
|
||||||
|
<option value="asc">älteste zuerst</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label for="limit">Limit:</label>
|
||||||
|
<input type="number" name="limit" value="{{ page_size }}" min="1" max="500" />
|
||||||
|
|
||||||
|
<button type="submit">Anzeigen</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- Ergebnisliste -->
|
||||||
|
<div id="results"
|
||||||
|
hx-get="/ui/draws"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-target="#results"
|
||||||
|
hx-swap="innerHTML"></div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
56
6aus49APP/templates/index.html.bak
Normal file
56
6aus49APP/templates/index.html.bak
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>6aus49 – Auswertung</title>
|
||||||
|
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
|
||||||
|
<style>
|
||||||
|
body { max-width: 1100px; margin: auto; }
|
||||||
|
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px,1fr)); gap: .5rem; }
|
||||||
|
.nowrap { white-space: nowrap; }
|
||||||
|
.numbers span { display:inline-block; min-width: 2.2ch; text-align: center; }
|
||||||
|
.badge { border: 1px solid var(--pico-primary); border-radius: 4px; padding: 0 .3rem; margin: 0 .1rem; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>6aus49 – Ziehungen</h1>
|
||||||
|
|
||||||
|
<!-- Reduziertes Filterformular -->
|
||||||
|
<form id="filterForm" class="grid"
|
||||||
|
hx-get="/ui/draws"
|
||||||
|
hx-target="#result"
|
||||||
|
hx-trigger="change, submit"
|
||||||
|
hx-include="#filterForm">
|
||||||
|
<label>
|
||||||
|
Von
|
||||||
|
<input type="date" name="date_from">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Bis
|
||||||
|
<input type="date" name="date_to">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Limit
|
||||||
|
<input type="number" name="limit" min="1" max="500" value="10">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Reihenfolge
|
||||||
|
<select name="order">
|
||||||
|
<option value="desc" selected>Neueste zuerst</option>
|
||||||
|
<option value="asc">Älteste zuerst</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<div style="grid-column: 1 / -1; display:flex; gap:.5rem;">
|
||||||
|
<button type="submit" class="primary">Anzeigen</button>
|
||||||
|
<button type="reset">Zurücksetzen</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- Ergebniscontainer: lädt initial -->
|
||||||
|
<div id="result" hx-get="/ui/draws" hx-trigger="load" hx-target="#result">
|
||||||
|
<!-- Tabelle wird hier eingefügt -->
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
42
Euro2SQL.py
42
Euro2SQL.py
|
|
@ -1,42 +0,0 @@
|
||||||
import requests
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
# URL der Zielseite (Eurojackpot bei ARD-Text)
|
|
||||||
url = "https://lotto.gmx.de/eurojackpot/zahlen-quoten"
|
|
||||||
|
|
||||||
# HTTP-Request senden
|
|
||||||
response = requests.get(url)
|
|
||||||
response.raise_for_status() # Fehlerprüfung
|
|
||||||
|
|
||||||
# HTML mit BeautifulSoup parsen
|
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
|
||||||
|
|
||||||
# Formatierten HTML-Code ausgeben
|
|
||||||
formatted_html = soup.prettify()
|
|
||||||
|
|
||||||
# Ausgabe in der Konsole
|
|
||||||
#print(formatted_html)
|
|
||||||
|
|
||||||
url = "https://lotto.gmx.de/eurojackpot/zahlen-quoten"
|
|
||||||
response = requests.get(url)
|
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
|
||||||
|
|
||||||
# Finde den ersten div mit einer bestimmten Klasse
|
|
||||||
html_code = soup.find("div", class_="std")
|
|
||||||
print(html_code)
|
|
||||||
# HTML parsen
|
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
|
||||||
|
|
||||||
# Robust: finde <b>-Tag mit "Gewinnzahlen" (normalisiert auf Whitespace!)
|
|
||||||
b_tag = soup.find("b", string=lambda s: s and "gewinnzahlen" in s.lower())
|
|
||||||
|
|
||||||
if b_tag:
|
|
||||||
table = b_tag.find_parent().find_next_sibling("table")
|
|
||||||
if table:
|
|
||||||
gewinnzahlen = [int(td.get_text(strip=True)) for td in table.find_all("td")]
|
|
||||||
print("Gewinnzahlen:", gewinnzahlen)
|
|
||||||
else:
|
|
||||||
print("Tabelle nicht gefunden.")
|
|
||||||
else:
|
|
||||||
print("<b>Gewinnzahlen</b> nicht gefunden.")
|
|
||||||
|
|
||||||
10
README.md
10
README.md
|
|
@ -3,15 +3,21 @@
|
||||||
Der Neustart eines längst aufgegeben Projektes:
|
Der Neustart eines längst aufgegeben Projektes:
|
||||||
Es werden die aktuell gezogenen Lottozahlen per Cronjob
|
Es werden die aktuell gezogenen Lottozahlen per Cronjob
|
||||||
(00 21 * * 3,6 python3 /home/scripts/lotto2py.py)
|
(00 21 * * 3,6 python3 /home/scripts/lotto2py.py)
|
||||||
von den beiden Seiten
|
von den drei Seiten
|
||||||
|
|
||||||
* https://www.ard-text.de/mobil/581 (Samstagsziehung)
|
* https://www.ard-text.de/mobil/581 (Samstagsziehung)
|
||||||
* https://www.ard-text.de/mobil/582 (Mittwochsziehung)
|
* https://www.ard-text.de/mobil/582 (Mittwochsziehung)
|
||||||
|
* https://www.ard-text.de/mobil/583 (EuroJackpot)
|
||||||
|
|
||||||
gescrapt.
|
gescrapt.
|
||||||
|
|
||||||
Todos:
|
Todos:
|
||||||
1. [x] https://www.ard-text.de/mobil/583 (Eurojackpot)
|
1. [x] https://www.ard-text.de/mobil/583 (Eurojackpot)
|
||||||
2. [x] Ablage in SQL-Datenbank (MariaDB)
|
2. [x] Ablage in SQL-Datenbank (MariaDB)
|
||||||
3. [ ] Webinterface
|
3. [x] Webinterface https://lotto.hintergasse.de
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
_Hinweis:
|
||||||
|
Ein Teil des Codes wurde durch Chat-GPT (GPT-4o) generiert. Dieser wurde durch den Inhaber des Repositorys modifiziert und angepast._
|
||||||
|
.
|
||||||
|
|
|
||||||
33
datum.py
Normal file
33
datum.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
# --- Verbindung herstellen ---
|
||||||
|
connection = pymysql.connect(
|
||||||
|
host='10.0.1.123',
|
||||||
|
user='hubobel',
|
||||||
|
password='polier2003',
|
||||||
|
database='hubobel',
|
||||||
|
charset='utf8mb4',
|
||||||
|
cursorclass=pymysql.cursors.Cursor
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
# Beispielwerte
|
||||||
|
z1, z2, z3, z4, z5 = 10, 22, 38, 42, 48
|
||||||
|
|
||||||
|
# --- Prüfabfrage: existiert diese Kombination? ---
|
||||||
|
sql_check = """
|
||||||
|
SELECT 1 FROM `euro`
|
||||||
|
WHERE z1 = %s AND z2 = %s AND z3 = %s AND z4 = %s AND z5 = %s
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
cursor.execute(sql_check, (z1, z2, z3, z4, z5))
|
||||||
|
exists = cursor.fetchone() is not None
|
||||||
|
|
||||||
|
if exists:
|
||||||
|
print("✅ Kombination existiert bereits.")
|
||||||
|
else:
|
||||||
|
print("🆕 Kombination ist neu – kann eingefügt werden.")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
connection.close()
|
||||||
12
lotto2py.conf
Normal file
12
lotto2py.conf
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"Telegram": {
|
||||||
|
"Chat_ID": "322673713",
|
||||||
|
"TOKEN": "680737840:AAEaa7Vxl_kZz_LWS1_S-lH6Eda7HXqu6Y4"
|
||||||
|
},
|
||||||
|
"mail": {
|
||||||
|
"mail_folder": "",
|
||||||
|
"mail_host": "",
|
||||||
|
"mail_pass": "",
|
||||||
|
"mail_user": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
121
lotto2py.py
121
lotto2py.py
|
|
@ -44,10 +44,12 @@ def notify_telegram(text):
|
||||||
requests.post(url, params=params)
|
requests.post(url, params=params)
|
||||||
def Euro():
|
def Euro():
|
||||||
url = 'https://www.ard-text.de/mobil/583'
|
url = 'https://www.ard-text.de/mobil/583'
|
||||||
response = requests.get(url)
|
headers = {
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
|
||||||
|
}
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
soup = BeautifulSoup(response.text, "html.parser")
|
||||||
ziffern = []
|
|
||||||
ZahlenEuro = {
|
ZahlenEuro = {
|
||||||
'Freitag': {'Datum': '', 'Z1': '', 'Z2': '', 'Z3': '', 'Z4': '', 'Z5': '', 'Eurozahl1': '', 'Eurozahl2': ''},
|
'Freitag': {'Datum': '', 'Z1': '', 'Z2': '', 'Z3': '', 'Z4': '', 'Z5': '', 'Eurozahl1': '', 'Eurozahl2': ''},
|
||||||
'Dienstag': {'Datum': '', 'Z1': '', 'Z2': '', 'Z3': '', 'Z4': '', 'Z5': '', 'Eurozahl1': '', 'Eurozahl2': ''}}
|
'Dienstag': {'Datum': '', 'Z1': '', 'Z2': '', 'Z3': '', 'Z4': '', 'Z5': '', 'Eurozahl1': '', 'Eurozahl2': ''}}
|
||||||
|
|
@ -69,19 +71,22 @@ def Euro():
|
||||||
bb = 'Eurozahl' + str(aa)
|
bb = 'Eurozahl' + str(aa)
|
||||||
ZahlenEuro[Tag][bb] = int(c)
|
ZahlenEuro[Tag][bb] = int(c)
|
||||||
aa = aa + 1
|
aa = aa + 1
|
||||||
|
jahr = datetime.now().year
|
||||||
|
tag = datetime.now().day
|
||||||
|
monat = datetime.now().month
|
||||||
|
ZahlenEuro[Tag]['Datum'] = f"{jahr}-{monat}-{tag}"
|
||||||
Tag = 'Dienstag'
|
Tag = 'Dienstag'
|
||||||
for b in soup.find("p", string=lambda s: s and "dienstag" in s.lower()):
|
for b in soup.find("p", string=lambda s: s and "dienstag" in s.lower()):
|
||||||
ZahlenEuro[Tag]['Datum'] = b
|
ZahlenEuro[Tag]['Datum'] = b
|
||||||
tabelle = b.find_parent().find_next_sibling("table")
|
tabelle = b.find_parent().find_next_sibling("table")
|
||||||
a = 1
|
a = 1
|
||||||
print(b)
|
#print(b)
|
||||||
for n in tabelle.find_all("td"):
|
for n in tabelle.find_all("td"):
|
||||||
c = (n.get_text(strip=True))
|
c = (n.get_text(strip=True))
|
||||||
b = 'Z' + str(a)
|
b = 'Z' + str(a)
|
||||||
ZahlenEuro[Tag][b] = int(c)
|
ZahlenEuro[Tag][b] = int(c)
|
||||||
a = a + 1
|
a = a + 1
|
||||||
eurozahlen_tags = soup.find_all("b", string=lambda s: s and "eurozahlen" in s.lower())
|
eurozahlen_tags = soup.find_all("b", string=lambda s: s and "eurozahlen" in s.lower())
|
||||||
|
|
||||||
aa = 1
|
aa = 1
|
||||||
if len(eurozahlen_tags) >= 2:
|
if len(eurozahlen_tags) >= 2:
|
||||||
eurozahlen_table_2 = eurozahlen_tags[1].find_next("table")
|
eurozahlen_table_2 = eurozahlen_tags[1].find_next("table")
|
||||||
|
|
@ -90,10 +95,16 @@ def Euro():
|
||||||
bb = 'Eurozahl' + str(aa)
|
bb = 'Eurozahl' + str(aa)
|
||||||
ZahlenEuro[Tag][bb] = int(i)
|
ZahlenEuro[Tag][bb] = int(i)
|
||||||
aa = aa + 1
|
aa = aa + 1
|
||||||
|
jahr = datetime.now().year
|
||||||
|
tag = datetime.now().day
|
||||||
|
monat = datetime.now().month
|
||||||
|
ZahlenEuro[Tag]['Datum'] = f"{jahr}-{monat}-{tag}"
|
||||||
return ZahlenEuro
|
return ZahlenEuro
|
||||||
def Normalziehung(a):
|
def Normalziehung(a):
|
||||||
wochentag = datetime.today().weekday()
|
wochentag = datetime.today().weekday()
|
||||||
jahr = datetime.now().year
|
jahr = datetime.now().year
|
||||||
|
tag = f"{datetime.now().day:02d}"
|
||||||
|
monat = datetime.now().month
|
||||||
|
|
||||||
url = "https://www.ard-text.de/mobil/" + str(a)
|
url = "https://www.ard-text.de/mobil/" + str(a)
|
||||||
|
|
||||||
|
|
@ -124,7 +135,7 @@ def Normalziehung(a):
|
||||||
datum_woche = line.strip()
|
datum_woche = line.strip()
|
||||||
break
|
break
|
||||||
# Regex: Hauptzahlen finden (z. B. Zeile enthält "11 20 28 30 35 41")
|
# Regex: Hauptzahlen finden (z. B. Zeile enthält "11 20 28 30 35 41")
|
||||||
match_haupt = re.search(r"\s(\d{1,2}(?:\s+\d{1,2}){5})\s", text)
|
match_haupt = re.search(r"\s(\d{1,2}(?:\s+\d{1,2}){6})\s", text)
|
||||||
if match_haupt:
|
if match_haupt:
|
||||||
lottozahlen = [int(n) for n in match_haupt.group(1).split()]
|
lottozahlen = [int(n) for n in match_haupt.group(1).split()]
|
||||||
|
|
||||||
|
|
@ -162,7 +173,7 @@ def Normalziehung(a):
|
||||||
ef = str((ab + str(cd)))
|
ef = str((ab + str(cd)))
|
||||||
Lottozahlen[ef] = i
|
Lottozahlen[ef] = i
|
||||||
cd = cd + 1
|
cd = cd + 1
|
||||||
Lottozahlen['Datum'] = str(jahr) + ' / ' + str(datum_woche)
|
Lottozahlen['Datum'] = f"{jahr}-{monat}-{tag}"
|
||||||
Lottozahlen['Superzahl'] = superzahl
|
Lottozahlen['Superzahl'] = superzahl
|
||||||
Lottozahlen['Spiel77'] = int(game77)
|
Lottozahlen['Spiel77'] = int(game77)
|
||||||
Lottozahlen['Super6'] = int(subber6)
|
Lottozahlen['Super6'] = int(subber6)
|
||||||
|
|
@ -183,9 +194,14 @@ def SQLnorm(data):
|
||||||
"','" + str(data['Super6']) + "','" + str(data['Spiel77']) + "')"
|
"','" + str(data['Super6']) + "','" + str(data['Spiel77']) + "')"
|
||||||
sql_q = "SELECT * FROM 6aus49 WHERE datum like '%" + data['Datum'] + "%'"
|
sql_q = "SELECT * FROM 6aus49 WHERE datum like '%" + data['Datum'] + "%'"
|
||||||
resp = cursor.execute(sql_q)
|
resp = cursor.execute(sql_q)
|
||||||
if resp == 0:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if test == 0:
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
|
|
||||||
|
notify_telegram(str(data))
|
||||||
connection.commit()
|
connection.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
@ -203,9 +219,10 @@ def SQLdienstag(data):
|
||||||
data['Eurozahl2']) + "')"
|
data['Eurozahl2']) + "')"
|
||||||
sql_q = "SELECT * FROM euro WHERE datum like '%" + data['Datum'] + "%'"
|
sql_q = "SELECT * FROM euro WHERE datum like '%" + data['Datum'] + "%'"
|
||||||
resp = cursor.execute(sql_q)
|
resp = cursor.execute(sql_q)
|
||||||
if resp == 0:
|
if test == 0:
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
print(resp)
|
notify_telegram(str(data))
|
||||||
|
#print(resp)
|
||||||
connection.commit()
|
connection.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
@ -222,8 +239,9 @@ def SQLfreitag(data):
|
||||||
data['Eurozahl2']) + "')"
|
data['Eurozahl2']) + "')"
|
||||||
sql_q = "SELECT * FROM euro WHERE datum like '%" + data['Datum'] + "%'"
|
sql_q = "SELECT * FROM euro WHERE datum like '%" + data['Datum'] + "%'"
|
||||||
resp = cursor.execute(sql_q)
|
resp = cursor.execute(sql_q)
|
||||||
if resp == 0:
|
if test == 0:
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
|
notify_telegram(str(data))
|
||||||
|
|
||||||
connection.commit()
|
connection.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
@ -240,7 +258,7 @@ def SQLsamstag(data):
|
||||||
"','" + str(data['Super6']) + "','" + str(data['Spiel77']) + "')"
|
"','" + str(data['Super6']) + "','" + str(data['Spiel77']) + "')"
|
||||||
sql_q = "SELECT * FROM samstag WHERE datum like '%" + data['Datum'] + "%'"
|
sql_q = "SELECT * FROM samstag WHERE datum like '%" + data['Datum'] + "%'"
|
||||||
resp = cursor.execute(sql_q)
|
resp = cursor.execute(sql_q)
|
||||||
if resp == 0:
|
if test == 0:
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
connection.commit()
|
connection.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
@ -257,36 +275,101 @@ def SQLmittwoch(data):
|
||||||
"','" + str(data['Super6']) + "','" + str(data['Spiel77']) + "')"
|
"','" + str(data['Super6']) + "','" + str(data['Spiel77']) + "')"
|
||||||
sql_q = "SELECT * FROM samstag WHERE datum like '%" + data['Datum'] + "%'"
|
sql_q = "SELECT * FROM samstag WHERE datum like '%" + data['Datum'] + "%'"
|
||||||
resp = cursor.execute(sql_q)
|
resp = cursor.execute(sql_q)
|
||||||
if resp == 0:
|
|
||||||
|
if test == 0:
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
connection.commit()
|
connection.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
connection.close()
|
connection.close()
|
||||||
|
def SQLtesteuro(data):
|
||||||
|
print(data)
|
||||||
|
connection = pymysql.connect(
|
||||||
|
host='10.0.1.123',
|
||||||
|
user='hubobel',
|
||||||
|
password='polier2003',
|
||||||
|
database='hubobel',
|
||||||
|
charset='utf8mb4',
|
||||||
|
cursorclass=pymysql.cursors.Cursor
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
# Beispielwerte
|
||||||
|
z1, z2, z3, z4, z5 = data['Z1'], data['Z2'],data['Z3'],data['Z4'],data['Z5']
|
||||||
|
sql_check = """
|
||||||
|
SELECT 1 FROM `euro`
|
||||||
|
WHERE z1 = %s AND z2 = %s AND z3 = %s AND z4 = %s AND z5 = %s
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
cursor.execute(sql_check, (z1, z2, z3, z4, z5))
|
||||||
|
exists = cursor.fetchone() is not None
|
||||||
|
|
||||||
|
if exists:
|
||||||
|
print("✅ Kombination existiert bereits.")
|
||||||
|
a = 1
|
||||||
|
else:
|
||||||
|
print("🆕 Kombination ist neu – kann eingefügt werden.")
|
||||||
|
a = 0
|
||||||
|
|
||||||
|
finally:
|
||||||
|
connection.close()
|
||||||
|
return a
|
||||||
|
def SQLtestsechs(data):
|
||||||
|
print(data)
|
||||||
|
connection = pymysql.connect(
|
||||||
|
host='10.0.1.123',
|
||||||
|
user='hubobel',
|
||||||
|
password='polier2003',
|
||||||
|
database='hubobel',
|
||||||
|
charset='utf8mb4',
|
||||||
|
cursorclass=pymysql.cursors.Cursor
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
# Beispielwerte
|
||||||
|
z1, z2, z3, z4, z5, z6 = data['Z1'], data['Z2'],data['Z3'],data['Z4'],data['Z5'],data['Z6']
|
||||||
|
sql_check = """
|
||||||
|
SELECT 1 FROM `6aus49`
|
||||||
|
WHERE z1 = %s AND z2 = %s AND z3 = %s AND z4 = %s AND z5 = %s AND z6 = %s
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
cursor.execute(sql_check, (z1, z2, z3, z4, z5, z6))
|
||||||
|
exists = cursor.fetchone() is not None
|
||||||
|
|
||||||
|
if exists:
|
||||||
|
print("✅ Kombination existiert bereits.")
|
||||||
|
a = 1
|
||||||
|
else:
|
||||||
|
print("🆕 Kombination ist neu – kann eingefügt werden.")
|
||||||
|
a = 0
|
||||||
|
|
||||||
|
finally:
|
||||||
|
connection.close()
|
||||||
|
return a
|
||||||
|
|
||||||
passw = conf()
|
passw = conf()
|
||||||
telegram_chat_id = passw['Telegram']['Chat_ID']
|
telegram_chat_id = passw['Telegram']['Chat_ID']
|
||||||
telegram_token = passw['Telegram']['TOKEN']
|
telegram_token = passw['Telegram']['TOKEN']
|
||||||
|
|
||||||
wochentag = datetime.today().weekday()
|
wochentag = datetime.today().weekday()
|
||||||
#wochentag = 2
|
#wochentag = 4
|
||||||
|
|
||||||
if wochentag == 2:
|
if wochentag == 2:
|
||||||
Zahl = Normalziehung(582)
|
Zahl = Normalziehung(582)
|
||||||
|
test = SQLtestsechs(Zahl)
|
||||||
SQLnorm(Zahl)
|
SQLnorm(Zahl)
|
||||||
SQLmittwoch(Zahl)
|
|
||||||
notify_telegram(str(Zahl))
|
|
||||||
elif wochentag == 5:
|
elif wochentag == 5:
|
||||||
Zahl = Normalziehung(581)
|
Zahl = Normalziehung(581)
|
||||||
|
test = SQLtestsechs(Zahl)
|
||||||
SQLnorm(Zahl)
|
SQLnorm(Zahl)
|
||||||
SQLsamstag(Zahl)
|
|
||||||
notify_telegram(str(Zahl))
|
|
||||||
elif wochentag == 1:
|
elif wochentag == 1:
|
||||||
Zahl = Euro()
|
Zahl = Euro()
|
||||||
|
test = SQLtesteuro(Zahl['Dienstag'])
|
||||||
SQLdienstag(Zahl['Dienstag'])
|
SQLdienstag(Zahl['Dienstag'])
|
||||||
notify_telegram(str(Zahl['Dienstag']))
|
|
||||||
elif wochentag == 4:
|
elif wochentag == 4:
|
||||||
Zahl = Euro()
|
Zahl = Euro()
|
||||||
|
test = SQLtesteuro(Zahl['Freitag'])
|
||||||
SQLfreitag(Zahl['Freitag'])
|
SQLfreitag(Zahl['Freitag'])
|
||||||
notify_telegram(str(Zahl['Freitag']))
|
|
||||||
else:
|
else:
|
||||||
quit()
|
quit()
|
||||||
|
|
|
||||||
BIN
screen1.jpg
Normal file
BIN
screen1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 413 KiB |
Loading…
Add table
Add a link
Reference in a new issue