Build (final_path, hls_dir, final_filename) using DVR templates. The HLS working directory is hidden and tagged with the recording id (e.g. ``.dvr_71_hls``) so it cannot collide with another recording's files and so orphan-cleanup utilities can identify internal scratch directo
(channel, program, start_time, end_time, recording_id)
| 1001 | |
| 1002 | |
| 1003 | def _build_output_paths(channel, program, start_time, end_time, recording_id): |
| 1004 | """ |
| 1005 | Build (final_path, hls_dir, final_filename) using DVR templates. |
| 1006 | |
| 1007 | The HLS working directory is hidden and tagged with the recording id |
| 1008 | (e.g. ``.dvr_71_hls``) so it cannot collide with another recording's |
| 1009 | files and so orphan-cleanup utilities can identify internal scratch |
| 1010 | directories unambiguously. |
| 1011 | """ |
| 1012 | from core.models import CoreSettings |
| 1013 | # Root for DVR recordings: fixed to /data/recordings inside the container |
| 1014 | library_root = '/data/recordings' |
| 1015 | |
| 1016 | is_movie, season, episode, year, sub_title = _parse_epg_tv_movie_info(program) |
| 1017 | show = _safe_name(program.get('title') if isinstance(program, dict) else channel.name) |
| 1018 | title = _safe_name(program.get('title') if isinstance(program, dict) else channel.name) |
| 1019 | sub_title = _safe_name(sub_title) |
| 1020 | season = int(season) if season is not None else 0 |
| 1021 | episode = int(episode) if episode is not None else 0 |
| 1022 | year = year or str(start_time.year) |
| 1023 | |
| 1024 | values = { |
| 1025 | 'show': show, |
| 1026 | 'title': title, |
| 1027 | 'sub_title': sub_title, |
| 1028 | 'season': season, |
| 1029 | 'episode': episode, |
| 1030 | 'year': year, |
| 1031 | 'channel': _safe_name(channel.name), |
| 1032 | 'start': start_time.strftime('%Y%m%d_%H%M%S'), |
| 1033 | 'end': end_time.strftime('%Y%m%d_%H%M%S'), |
| 1034 | } |
| 1035 | |
| 1036 | template = CoreSettings.get_dvr_movie_template() if is_movie else CoreSettings.get_dvr_tv_template() |
| 1037 | # Build relative path from templates with smart fallbacks |
| 1038 | rel_path = None |
| 1039 | if not is_movie and (season == 0 or episode == 0): |
| 1040 | # TV fallback template when S/E are missing |
| 1041 | try: |
| 1042 | tv_fb = CoreSettings.get_dvr_tv_fallback_template() |
| 1043 | rel_path = tv_fb.format(**values) |
| 1044 | except Exception: |
| 1045 | # Older setting support |
| 1046 | try: |
| 1047 | fallback_root = CoreSettings.get_dvr_tv_fallback_dir() |
| 1048 | except Exception: |
| 1049 | fallback_root = "TV_Shows" |
| 1050 | rel_path = f"{fallback_root}/{show}/{values['start']}.mkv" |
| 1051 | if not rel_path: |
| 1052 | try: |
| 1053 | rel_path = template.format(**values) |
| 1054 | except Exception: |
| 1055 | rel_path = None |
| 1056 | # Movie-specific fallback if formatting failed or title missing |
| 1057 | if is_movie and not rel_path: |
| 1058 | try: |
| 1059 | m_fb = CoreSettings.get_dvr_movie_fallback_template() |
| 1060 | rel_path = m_fb.format(**values) |