73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"unicode"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Trailing dotted suffixes that EPG providers commonly append to channel ids
|
||
|
|
// (e.g. "Italia 1.it"). Conservative allow-list to avoid eating real id chars.
|
||
|
|
var idSuffixes = []string{".it", ".uk", ".de", ".com", ".us", ".fr", ".es", ".tv"}
|
||
|
|
|
||
|
|
// Trailing video-quality markers commonly appended by either the playlist or
|
||
|
|
// the EPG (e.g. open-epg uses "Italia 1 HD.it" while the playlist may say
|
||
|
|
// "Italia 1"). Stripped symmetrically from both sides. Order matters: longer
|
||
|
|
// markers first so " full hd" wins over a partial " hd" match.
|
||
|
|
var qualitySuffixes = []string{" full hd", " uhd", " fhd", " hd", " 4k", " sd"}
|
||
|
|
|
||
|
|
// normalizeChannelID returns a stable lookup key for a channel identifier,
|
||
|
|
// collapsing cosmetic divergences across sources:
|
||
|
|
//
|
||
|
|
// "Italia 1" / "Italia 1.it" / "Italia 1 HD.it" / "italia1" → "italia1"
|
||
|
|
func normalizeChannelID(id string) string {
|
||
|
|
s := strings.ToLower(strings.TrimSpace(id))
|
||
|
|
|
||
|
|
for _, suf := range idSuffixes {
|
||
|
|
if strings.HasSuffix(s, suf) {
|
||
|
|
s = s[:len(s)-len(suf)]
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Strip trailing quality markers, possibly stacked ("Italia 1 Full HD HD").
|
||
|
|
for {
|
||
|
|
matched := false
|
||
|
|
for _, suf := range qualitySuffixes {
|
||
|
|
if strings.HasSuffix(s, suf) {
|
||
|
|
s = s[:len(s)-len(suf)]
|
||
|
|
matched = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if !matched {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var b strings.Builder
|
||
|
|
b.Grow(len(s))
|
||
|
|
for _, r := range s {
|
||
|
|
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
||
|
|
b.WriteRune(r)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return b.String()
|
||
|
|
}
|
||
|
|
|
||
|
|
// buildIDMap turns a list of playlist tvg-ids into a normalized→canonical
|
||
|
|
// lookup. The canonical form is the playlist's exact tvg-id string; the EPG
|
||
|
|
// merger uses it to rewrite incoming channel/programme references.
|
||
|
|
func buildIDMap(tvgIDs []string) map[string]string {
|
||
|
|
m := make(map[string]string, len(tvgIDs))
|
||
|
|
for _, id := range tvgIDs {
|
||
|
|
key := normalizeChannelID(id)
|
||
|
|
if key == "" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if _, exists := m[key]; !exists {
|
||
|
|
m[key] = id
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return m
|
||
|
|
}
|