Prefetch poster info for a scheduled recording so the UI can show art in Upcoming.
(recording_id)
| 3193 | |
| 3194 | @shared_task |
| 3195 | def prefetch_recording_artwork(recording_id): |
| 3196 | """Prefetch poster info for a scheduled recording so the UI can show art in Upcoming.""" |
| 3197 | try: |
| 3198 | from .models import Recording |
| 3199 | rec = Recording.objects.get(id=recording_id) |
| 3200 | cp = rec.custom_properties or {} |
| 3201 | |
| 3202 | # Bail out if the recording is already active or finished — run_recording |
| 3203 | # handles poster resolution itself, and saving here can race with status updates. |
| 3204 | current_status = cp.get("status", "") |
| 3205 | if current_status in ("recording", "completed", "stopped", "interrupted"): |
| 3206 | return "skipped: status is " + current_status |
| 3207 | |
| 3208 | program = cp.get("program") or {} |
| 3209 | |
| 3210 | # Enrich empty program dicts (manual recordings) from EPG time-slot data. |
| 3211 | # Persists matched title/description for display in the recording card. |
| 3212 | if isinstance(program, dict) and not program.get("user_edited") and not program.get("id") and not program.get("title"): |
| 3213 | epg_match = _match_epg_program_by_timeslot( |
| 3214 | rec.channel.epg_data, rec.start_time, rec.end_time, |
| 3215 | ) |
| 3216 | if epg_match: |
| 3217 | program.update(epg_match) |
| 3218 | cp["program"] = program |
| 3219 | |
| 3220 | poster_logo_id, poster_url = _resolve_poster_for_program( |
| 3221 | rec.channel.name, program, channel_logo_id=rec.channel.logo_id, |
| 3222 | ) |
| 3223 | updated = False |
| 3224 | if poster_logo_id and cp.get("poster_logo_id") != poster_logo_id: |
| 3225 | cp["poster_logo_id"] = poster_logo_id |
| 3226 | updated = True |
| 3227 | if poster_url and cp.get("poster_url") != poster_url: |
| 3228 | cp["poster_url"] = poster_url |
| 3229 | updated = True |
| 3230 | # Enrich with rating if available from ProgramData.custom_properties |
| 3231 | try: |
| 3232 | from apps.epg.models import ProgramData |
| 3233 | prog_id = program.get("id") if isinstance(program, dict) else None |
| 3234 | if prog_id: |
| 3235 | epg_program = ProgramData.objects.filter(id=prog_id).only("custom_properties").first() |
| 3236 | if epg_program and isinstance(epg_program.custom_properties, dict): |
| 3237 | rating_val = epg_program.custom_properties.get("rating") |
| 3238 | rating_sys = epg_program.custom_properties.get("rating_system") |
| 3239 | season_val = epg_program.custom_properties.get("season") |
| 3240 | episode_val = epg_program.custom_properties.get("episode") |
| 3241 | onscreen = epg_program.custom_properties.get("onscreen_episode") |
| 3242 | if rating_val and cp.get("rating") != rating_val: |
| 3243 | cp["rating"] = rating_val |
| 3244 | updated = True |
| 3245 | if rating_sys and cp.get("rating_system") != rating_sys: |
| 3246 | cp["rating_system"] = rating_sys |
| 3247 | updated = True |
| 3248 | if season_val is not None and cp.get("season") != season_val: |
| 3249 | cp["season"] = season_val |
| 3250 | updated = True |
| 3251 | if episode_val is not None and cp.get("episode") != episode_val: |
| 3252 | cp["episode"] = episode_val |
nothing calls this directly
no test coverage detected