|
45 | 45 | # "·" (MIDDLE DOT U+00B7) |
46 | 46 | # "" (GREEK ANO TELEIA U+0387) |
47 | 47 | M3U_SUBSTITUTIONS = ( |
48 | | - (",", " · "), # MIDDLE DOT (U+00B7) - BEST FOR CSV ROUND-TRIP |
| 48 | + (",", "_·_"), # MIDDLE DOT (U+00B7) - BEST FOR CSV ROUND-TRIP |
49 | 49 | ("-", "–"), # EN DASH (U+2013) WITH SPACES |
50 | 50 | ('"', "”"), # RIGHT DOUBLE QUOTATION MARK (U+201D) |
51 | 51 | ) |
@@ -365,16 +365,16 @@ def parse_attributes(line): |
365 | 365 | return out |
366 | 366 |
|
367 | 367 | def generate_reverse_subs(): |
368 | | - """Creates reverse mappings with smart space handling""" |
| 368 | + """ |
| 369 | + Creates reverse mappings for M3U -> CSV round-trip. |
| 370 | + - Preserves "_·_" placeholders (protected commas) safely. |
| 371 | + - Converts normal substitutions back to their original form. |
| 372 | + """ |
369 | 373 | reverse = {} |
| 374 | + |
370 | 375 | for orig, sub in reversed(M3U_SUBSTITUTIONS): |
371 | | - if orig.endswith(' '): # Handle space-preserving substitutions |
372 | | - reverse[sub] = orig |
373 | | - else: |
374 | | - reverse[sub] = orig |
375 | | - # Special case: Ensure middle dot becomes comma+space |
376 | | - if " · " in reverse: |
377 | | - reverse[" · "] = ", " |
| 376 | + reverse[sub.replace("_·_", " · ")] = orig |
| 377 | + |
378 | 378 | return reverse |
379 | 379 |
|
380 | 380 | @functools.lru_cache(maxsize=1) |
@@ -741,9 +741,9 @@ def list_to_m3u(stations, out_file): |
741 | 741 | if logo: |
742 | 742 | attrs.append(f'tvg-logo="{logo}"') |
743 | 743 | if current_group: |
744 | | - attrs.append(f'group-title="{current_group}"') |
| 744 | + attrs.append('group-title="{}"'.format(current_group.replace('_·_', ' · '))) |
745 | 745 |
|
746 | | - escaped_m3u_string = escape_m3u_string(name) |
| 746 | + escaped_m3u_string = escape_m3u_string(name).replace('_·_', ' · ') |
747 | 747 | if attrs: |
748 | 748 | joined_attrs = ' '.join(attrs) |
749 | 749 | string = (f"#EXTINF:-1 {joined_attrs}, " |
|
0 commit comments