Files
vrobbler/vrobbler/apps/discgolf/utils.py
Colin Powell 1f5fada8b1
Some checks failed
build / test (push) Has been cancelled
[discgolf] Add new scrobble type
2026-06-20 00:37:18 -04:00

127 lines
3.7 KiB
Python

import csv
import logging
from datetime import datetime
from dateutil.parser import parse as parse_datetime
from django.utils import timezone
from people.models import Person
from scrobbles.models import Scrobble
from scrobbles.notifications import ScrobbleNtfyNotification
logger = logging.getLogger(__name__)
def _parse_udisc_datetime(raw: str) -> datetime:
return parse_datetime(raw)
def _resolve_player(name: str) -> Person:
person, _ = Person.objects.get_or_create(name=name.strip())
return person
def import_udisc_csv(
file_path: str, user_id: int, record_error=None
) -> list[Scrobble]:
from discgolf.models import DiscGolfCourse
new_scrobbles = []
with open(file_path, newline="", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
rows = list(reader)
if not rows:
return []
par_row = None
player_rows = []
for row in rows:
name = row.get("PlayerName", "").strip()
if name.lower() == "par":
par_row = row
else:
player_rows.append(row)
if not par_row:
return []
course_name = par_row.get("CourseName", "").strip()
layout_name = par_row.get("LayoutName", "").strip()
start_date_raw = par_row.get("StartDate", "").strip()
start_dt = _parse_udisc_datetime(start_date_raw) if start_date_raw else timezone.now()
number_of_holes = sum(1 for k in par_row if k.startswith("Hole") and k[4:].isdigit())
par_total_str = par_row.get("Total", "").strip()
par_total = int(par_total_str) if par_total_str.isdigit() else None
par_per_hole = {}
for k, v in par_row.items():
if k.startswith("Hole") and k[4:].isdigit() and v:
hole_num = int(k[4:])
try:
par_per_hole[f"hole_{hole_num}"] = int(v)
except (ValueError, TypeError):
pass
course, _ = DiscGolfCourse.objects.get_or_create(
title=course_name,
defaults={
"layout_name": layout_name,
"number_of_holes": number_of_holes,
"par_total": par_total,
"par_per_hole": par_per_hole or None,
},
)
is_teams = "+" in player_rows[0].get("PlayerName", "") if player_rows else False
round_type = "Teams" if is_teams else "Singles"
scores = {}
for row in player_rows:
player_name = row.get("PlayerName", "").strip()
hole_scores = {}
for k, v in row.items():
if k.startswith("Hole") and k[4:].isdigit() and v:
hole_num = int(k[4:])
try:
hole_scores[f"hole_{hole_num}"] = int(v)
except (ValueError, TypeError):
pass
total_str = row.get("Total", "").strip()
total = int(total_str) if total_str.isdigit() else None
if total is not None:
hole_scores["total"] = total
if is_teams:
people = player_name.split("+")
person_ids = [_resolve_player(p.strip()).id for p in people]
hole_scores["person_ids"] = person_ids
else:
person = _resolve_player(player_name)
hole_scores["person_id"] = person.id
scores[player_name] = hole_scores
log = {
"scores": scores,
"course_name": course_name,
"par": par_total,
"round_type": round_type,
}
scrobble_dict = {
"user_id": user_id,
"timestamp": start_dt,
"source": "uDisc",
"playback_position_seconds": 0,
"log": log,
}
scrobble = Scrobble.create_or_update(course, user_id, scrobble_dict)
if scrobble:
new_scrobbles.append(scrobble)
ScrobbleNtfyNotification(scrobble).send()
return new_scrobbles