Files
xTeVe/src/xepg.go
2019-09-04 20:16:11 +02:00

996 lines
22 KiB
Go

package src
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"path"
"runtime"
"strconv"
"strings"
"time"
)
// Provider XMLTV Datei überprüfen
func checkXMLCompatibility(id string, body []byte) (err error) {
var xmltv XMLTV
var compatibility = make(map[string]int)
err = xml.Unmarshal(body, &xmltv)
if err != nil {
return
}
compatibility["xmltv.channels"] = len(xmltv.Channel)
compatibility["xmltv.programs"] = len(xmltv.Program)
setProviderCompatibility(id, "xmltv", compatibility)
return
}
// XEPG Daten erstellen
func buildXEPG(background bool) {
if System.ScanInProgress == 1 {
return
}
System.ScanInProgress = 1
if Settings.EpgSource == "XEPG" {
switch background {
case true:
go func() {
createXEPGMapping()
createXEPGDatabase()
mapping()
cleanupXEPG()
createXMLTVFile()
createM3UFile()
go cachingImages()
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
System.ScanInProgress = 0
// Cache löschen
/*
Data.Cache.XMLTV = make(map[string]XMLTV)
Data.Cache.XMLTV = nil
*/
runtime.GC()
}()
case false:
createXEPGMapping()
createXEPGDatabase()
mapping()
cleanupXEPG()
go func() {
createXMLTVFile()
createM3UFile()
go cachingImages()
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
System.ScanInProgress = 0
// Cache löschen
//Data.Cache.XMLTV = make(map[string]XMLTV)
//Data.Cache.XMLTV = nil
runtime.GC()
}()
}
} else {
getLineup()
System.ScanInProgress = 0
}
}
// XEPG Daten aktualisieren
func updateXEPG(background bool) {
if System.ScanInProgress == 1 {
return
}
System.ScanInProgress = 1
if Settings.EpgSource == "XEPG" {
switch background {
case false:
createXEPGDatabase()
mapping()
cleanupXEPG()
go func() {
createXMLTVFile()
createM3UFile()
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
System.ScanInProgress = 0
}()
case true:
System.ScanInProgress = 0
}
} else {
System.ScanInProgress = 0
}
// Cache löschen
//Data.Cache.XMLTV = nil //make(map[string]XMLTV)
//Data.Cache.XMLTV = make(map[string]XMLTV)
return
}
// Mapping Menü für die XMLTV Dateien erstellen
func createXEPGMapping() {
Data.XMLTV.Files = getLocalProviderFiles("xmltv")
Data.XMLTV.Mapping = make(map[string]interface{})
var tmpMap = make(map[string]interface{})
var friendlyDisplayName = func(channel Channel) (displayName string) {
var dn = channel.DisplayName
displayName = dn[0].Value
switch len(dn) {
case 1:
displayName = dn[0].Value
default:
displayName = fmt.Sprintf("%s (%s)", dn[1].Value, dn[0].Value)
}
return
}
if len(Data.XMLTV.Files) > 0 {
for i := len(Data.XMLTV.Files) - 1; i >= 0; i-- {
var file = Data.XMLTV.Files[i]
var err error
var fileID = strings.TrimSuffix(getFilenameFromPath(file), path.Ext(getFilenameFromPath(file)))
showInfo("XEPG:" + "Parse XMLTV file: " + getProviderParameter(fileID, "xmltv", "name"))
//xmltv, err = getLocalXMLTV(file)
var xmltv XMLTV
err = getLocalXMLTV(file, &xmltv)
if err != nil {
Data.XMLTV.Files = append(Data.XMLTV.Files, Data.XMLTV.Files[i+1:]...)
var errMsg = err.Error()
err = errors.New(getProviderParameter(fileID, "xmltv", "name") + ": " + errMsg)
ShowError(err, 000)
}
// XML Parsen (Provider Datei)
if err == nil {
// Daten aus der XML Datei in eine temporäre Map schreiben
var xmltvMap = make(map[string]interface{})
for _, c := range xmltv.Channel {
var channel = make(map[string]interface{})
channel["id"] = c.ID
channel["display-name"] = friendlyDisplayName(*c)
channel["icon"] = c.Icon.Src
xmltvMap[c.ID] = channel
}
tmpMap[getFilenameFromPath(file)] = xmltvMap
Data.XMLTV.Mapping[getFilenameFromPath(file)] = xmltvMap
}
}
Data.XMLTV.Mapping = tmpMap
tmpMap = make(map[string]interface{})
} else {
if System.ConfigurationWizard == false {
showWarning(1007)
}
}
// Auswahl für den Dummy erstellen
var dummy = make(map[string]interface{})
var times = []string{"30", "60", "90", "120"}
for _, i := range times {
var dummyChannel = make(map[string]string)
dummyChannel["display-name"] = i + " Minutes"
dummyChannel["id"] = i + "_Minutes"
dummyChannel["icon"] = ""
dummy[dummyChannel["id"]] = dummyChannel
}
Data.XMLTV.Mapping["xTeVe Dummy"] = dummy
return
}
// XEPG Datenbank erstellen / aktualisieren
func createXEPGDatabase() (err error) {
var allChannelNumbers []float64
Data.Cache.Streams.Active = []string{}
Data.XEPG.Channels, err = loadJSONFileToMap(System.File.XEPG)
if err != nil {
ShowError(err, 1004)
return err
}
var createNewID = func() (xepg string) {
var firstID = 0 //len(Data.XEPG.Channels)
newXEPGID:
if _, ok := Data.XEPG.Channels["x-ID."+strconv.FormatInt(int64(firstID), 10)]; ok {
firstID++
goto newXEPGID
}
xepg = "x-ID." + strconv.FormatInt(int64(firstID), 10)
return
}
var getFreeChannelNumber = func() (xChannelID string) {
var firstFreeNumber float64 = Settings.MappingFirstChannel
newNumber:
if indexOfFloat64(firstFreeNumber, allChannelNumbers) == -1 {
xChannelID = fmt.Sprintf("%g", firstFreeNumber)
allChannelNumbers = append(allChannelNumbers, firstFreeNumber)
} else {
firstFreeNumber++
goto newNumber
}
return
}
showInfo("XEPG:" + "Update database")
// Kanal mit fehlenden Kanalnummern löschen
for id, dxc := range Data.XEPG.Channels {
var xepgChannel XEPGChannelStruct
err = json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
if err != nil {
return
}
if len(xepgChannel.XChannelID) == 0 {
delete(Data.XEPG.Channels, id)
}
if xChannelID, err := strconv.ParseFloat(xepgChannel.XChannelID, 64); err == nil {
allChannelNumbers = append(allChannelNumbers, xChannelID)
}
}
var xepgChannels = make(map[string]interface{})
for k, v := range Data.XEPG.Channels {
xepgChannels[k] = v
}
for _, dsa := range Data.Streams.Active {
var channelExists = false // Entscheidet ob ein Kanal neu zu Datenbank hinzugefügt werden soll.
var channelHasUUID = false // Überprüft, ob der Kanal (Stream) eindeutige ID's besitzt
var currentXEPGID string // Aktuelle Datenbank ID (XEPG). Wird verwendet, um den Kanal in der Datenbank mit dem Stream der M3u zu aktualisieren
var m3uChannel M3UChannelStructXEPG
err = json.Unmarshal([]byte(mapToJSON(dsa)), &m3uChannel)
if err != nil {
return
}
Data.Cache.Streams.Active = append(Data.Cache.Streams.Active, m3uChannel.Name)
// XEPG Datenbank durchlaufen um nach dem Kanal zu suchen.
for xepg, dxc := range xepgChannels {
var xepgChannel XEPGChannelStruct
err = json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
if err != nil {
return
}
// Vergleichen des Streams anhand einer UUID in der M3U mit dem Kanal in der Databank
if len(xepgChannel.UUIDValue) > 0 && len(m3uChannel.UUIDValue) > 0 {
if xepgChannel.UUIDValue == m3uChannel.UUIDValue && xepgChannel.UUIDKey == m3uChannel.UUIDKey {
channelExists = true
channelHasUUID = true
currentXEPGID = xepg
break
}
} else {
// Vergleichen des Streams mit dem Kanal in der Databank anhand des Kanalnamens
//fmt.Println(xepgChannel.Name, xepgChannel.UUIDKey, xepgChannel.UUIDValue)
if xepgChannel.Name == m3uChannel.Name {
channelExists = true
currentXEPGID = xepg
break
}
}
}
//os.Exit(0)
switch channelExists {
case true:
// Bereits vorhandener Kanal
var xepgChannel XEPGChannelStruct
err = json.Unmarshal([]byte(mapToJSON(Data.XEPG.Channels[currentXEPGID])), &xepgChannel)
if err != nil {
return
}
// Streaming URL aktualisieren
xepgChannel.URL = m3uChannel.URL
// Name aktualisieren, anhand des Names wird überprüft ob der Kanal noch in einer Playlist verhanden. Funktion: cleanupXEPG
xepgChannel.Name = m3uChannel.Name
// Kanalname aktualisieren, nur mit Kanal ID's möglich
if channelHasUUID == true {
if xepgChannel.XUpdateChannelName == true {
xepgChannel.XName = m3uChannel.Name
}
}
// Kanallogo aktualisieren. Wird bei vorhandenem Logo in der XMLTV Datei wieder überschrieben
if xepgChannel.XUpdateChannelIcon == true {
xepgChannel.TvgLogo = m3uChannel.TvgLogo
}
Data.XEPG.Channels[currentXEPGID] = xepgChannel
case false:
// Neuer Kanal
var xepg = createNewID()
var xChannelID = getFreeChannelNumber()
var newChannel XEPGChannelStruct
newChannel.FileM3UID = m3uChannel.FileM3UID
newChannel.FileM3UName = m3uChannel.FileM3UName
newChannel.FileM3UPath = m3uChannel.FileM3UPath
newChannel.Values = m3uChannel.Values
newChannel.GroupTitle = m3uChannel.GroupTitle
newChannel.Name = m3uChannel.Name
newChannel.TvgID = m3uChannel.TvgID
newChannel.TvgLogo = m3uChannel.TvgLogo
newChannel.TvgName = m3uChannel.TvgName
newChannel.URL = m3uChannel.URL
newChannel.XmltvFile = ""
newChannel.XMapping = ""
if len(m3uChannel.UUIDKey) > 0 {
newChannel.UUIDKey = m3uChannel.UUIDKey
newChannel.UUIDValue = m3uChannel.UUIDValue
}
newChannel.XName = m3uChannel.Name
newChannel.XGroupTitle = m3uChannel.GroupTitle
newChannel.XEPG = xepg
newChannel.XChannelID = xChannelID
Data.XEPG.Channels[xepg] = newChannel
}
}
err = saveMapToJSONFile(System.File.XEPG, Data.XEPG.Channels)
if err != nil {
return
}
return
}
// Kanäle automatisch zuordnen und das Mapping überprüfen
func mapping() (err error) {
showInfo("XEPG:" + "Map channels")
for xepg, dxc := range Data.XEPG.Channels {
var xepgChannel XEPGChannelStruct
err = json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
if err != nil {
return
}
// Automatische Mapping für neue Kanäle. Wird nur ausgeführt, wenn der Kanal deaktiviert ist und keine XMLTV Datei und kein XMLTV Kanal zugeordnet ist.
if xepgChannel.XActive == false {
// Werte kann "-" sein, deswegen len < 1
if len(xepgChannel.XmltvFile) < 1 && len(xepgChannel.XmltvFile) < 1 {
var tvgID = xepgChannel.TvgID
// Default für neuen Kanal setzen
xepgChannel.XmltvFile = "-"
xepgChannel.XMapping = "-"
Data.XEPG.Channels[xepg] = xepgChannel
for file, xmltvChannels := range Data.XMLTV.Mapping {
if channel, ok := xmltvChannels.(map[string]interface{})[tvgID]; ok {
if channelID, ok := channel.(map[string]interface{})["id"].(string); ok {
xepgChannel.XmltvFile = file
xepgChannel.XMapping = channelID
xepgChannel.XActive = true
// Falls in der XMLTV Datei ein Logo existiert, wird dieses verwendet. Falls nicht, dann das Logo aus der M3U Datei
if icon, ok := channel.(map[string]interface{})["icon"].(string); ok {
if len(icon) > 0 {
xepgChannel.TvgLogo = icon
}
}
Data.XEPG.Channels[xepg] = xepgChannel
break
}
}
}
}
}
// Überprüfen, ob die zugeordneten XMLTV Dateien und Kanäle noch existieren.
if xepgChannel.XActive == true {
var mapping = xepgChannel.XMapping
var file = xepgChannel.XmltvFile
if file != "xTeVe Dummy" {
if value, ok := Data.XMLTV.Mapping[file].(map[string]interface{}); ok {
if channel, ok := value[mapping].(map[string]interface{}); ok {
// Kanallogo aktualisieren
if logo, ok := channel["icon"].(string); ok {
if xepgChannel.XUpdateChannelIcon == true && len(logo) > 0 {
xepgChannel.TvgLogo = logo
}
}
} else {
ShowError(fmt.Errorf(fmt.Sprintf("Missing EPG data: %s", xepgChannel.Name)), 0)
showWarning(2302)
xepgChannel.XActive = false
}
} else {
var fileID = strings.TrimSuffix(getFilenameFromPath(file), path.Ext(getFilenameFromPath(file)))
ShowError(fmt.Errorf("Missing XMLTV file: %s", getProviderParameter(fileID, "xmltv", "name")), 0)
showWarning(2301)
xepgChannel.XActive = false
}
}
if len(xepgChannel.XmltvFile) == 0 {
xepgChannel.XmltvFile = "-"
xepgChannel.XActive = false
}
if len(xepgChannel.XMapping) == 0 {
xepgChannel.XMapping = "-"
xepgChannel.XActive = false
}
Data.XEPG.Channels[xepg] = xepgChannel
}
}
err = saveMapToJSONFile(System.File.XEPG, Data.XEPG.Channels)
if err != nil {
return
}
return
}
// XMLTV Datei erstellen
func createXMLTVFile() (err error) {
Data.Cache.ImagesFiles = []string{}
Data.Cache.ImagesURLS = []string{}
Data.Cache.ImagesCache = []string{}
files, err := ioutil.ReadDir(System.Folder.ImagesCache)
if err == nil {
for _, file := range files {
if indexOfString(file.Name(), Data.Cache.ImagesCache) == -1 {
Data.Cache.ImagesCache = append(Data.Cache.ImagesCache, file.Name())
}
}
}
if len(Data.XMLTV.Files) == 0 && len(Data.Streams.Active) == 0 {
Data.XEPG.Channels = make(map[string]interface{})
return
}
showInfo("XEPG:" + fmt.Sprintf("Create XMLTV file (%s)", System.File.XML))
var xepgXML XMLTV
xepgXML.Generator = System.Name
if System.Branch == "master" {
xepgXML.Source = fmt.Sprintf("%s - %s", System.Name, System.Version)
} else {
xepgXML.Source = fmt.Sprintf("%s - %s.%s", System.Name, System.Version, System.Build)
}
var tmpProgram = &XMLTV{}
for _, dxc := range Data.XEPG.Channels {
var xepgChannel XEPGChannelStruct
err := json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
if err == nil {
if xepgChannel.XActive == true {
// Kanäle
var channel Channel
channel.ID = xepgChannel.XChannelID
channel.Icon = Icon{Src: getCacheImageURL(xepgChannel.TvgLogo)}
channel.DisplayName = append(channel.DisplayName, DisplayName{Value: xepgChannel.XName})
xepgXML.Channel = append(xepgXML.Channel, &channel)
// Programme
*tmpProgram, err = getProgramData(xepgChannel)
if err == nil {
for _, program := range tmpProgram.Program {
xepgXML.Program = append(xepgXML.Program, program)
}
}
}
}
}
var content, _ = xml.MarshalIndent(xepgXML, " ", " ")
var xmlOutput = []byte(xml.Header + string(content))
writeByteToFile(System.File.XML, xmlOutput)
xepgXML = XMLTV{}
//saveMapToJSONFile(System.File.Images, Data.Cache.ImageCache)
return
}
// Programmdaten erstellen (createXMLTVFile)
func getProgramData(xepgChannel XEPGChannelStruct) (xepgXML XMLTV, err error) {
var xmltvFile = System.Folder.Data + xepgChannel.XmltvFile
var channelID = xepgChannel.XMapping
var xmltv XMLTV
if xmltvFile == System.Folder.Data+"xTeVe Dummy" {
xmltv = createDummyProgram(xepgChannel)
} else {
err = getLocalXMLTV(xmltvFile, &xmltv)
if err != nil {
return
}
}
for _, xmltvProgram := range xmltv.Program {
if xmltvProgram.Channel == channelID {
//fmt.Println(&channelID)
var program = &Program{}
// Channel ID
program.Channel = xepgChannel.XChannelID
program.Start = xmltvProgram.Start
program.Stop = xmltvProgram.Stop
// Title
program.Title = xmltvProgram.Title
// Sub title (Untertitel)
program.SubTitle = xmltvProgram.SubTitle
// Description (Beschreibung)
program.Desc = xmltvProgram.Desc
// Category (Kategorie)
getCategory(program, xmltvProgram, xepgChannel)
// Country (Länder)
program.Country = xmltvProgram.Country
// Program icon (Poster / Cover)
getPoster(program, xmltvProgram, xepgChannel)
// Language (Sprache)
program.Language = xmltvProgram.Language
// Episodes numbers (Episodennummern)
getEpisodeNum(program, xmltvProgram, xepgChannel)
// Video (Videoparameter)
getVideo(program, xmltvProgram, xepgChannel)
// Date (Datum)
program.Date = xmltvProgram.Date
// Previously shown (Wiederholung)
program.PreviouslyShown = xmltvProgram.PreviouslyShown
// New (Neu)
program.New = xmltvProgram.New
// Live
program.Live = xmltvProgram.Live
xepgXML.Program = append(xepgXML.Program, program)
}
}
return
}
// Dummy Daten erstellen (createXMLTVFile)
func createDummyProgram(xepgChannel XEPGChannelStruct) (dummyXMLTV XMLTV) {
var currentTime = time.Now()
var dateArray = strings.Fields(currentTime.String())
var offset = " " + dateArray[2]
var currentDay = currentTime.Format("20060102")
var startTime, _ = time.Parse("20060102150405", currentDay+"000000")
showInfo("Create Dummy Guide:" + "Time offset" + offset + " - " + xepgChannel.XName)
var dl = strings.Split(xepgChannel.XMapping, "_")
dummyLength, err := strconv.Atoi(dl[0])
if err != nil {
ShowError(err, 000)
return
}
for d := 0; d < 4; d++ {
var epgStartTime = startTime.Add(time.Hour * time.Duration(d*24))
for t := dummyLength; t <= 1440; t = t + dummyLength {
var epgStopTime = epgStartTime.Add(time.Minute * time.Duration(dummyLength))
var epg Program
poster := Poster{}
epg.Channel = xepgChannel.XMapping
epg.Start = epgStartTime.Format("20060102150405") + offset
epg.Stop = epgStopTime.Format("20060102150405") + offset
epg.Title = append(epg.Title, &Title{Value: xepgChannel.XName + " (" + epgStartTime.Weekday().String()[0:2] + ". " + epgStartTime.Format("15:04") + " - " + epgStopTime.Format("15:04") + ")", Lang: "en"})
epg.Desc = append(epg.Desc, &Desc{Value: "xTeVe: (" + strconv.Itoa(dummyLength) + " Minutes) " + epgStartTime.Weekday().String() + " " + epgStartTime.Format("15:04") + " - " + epgStopTime.Format("15:04"), Lang: "en"})
if Settings.XepgReplaceMissingImages == true {
poster.Src = getCacheImageURL(xepgChannel.TvgLogo)
epg.Poster = append(epg.Poster, poster)
}
if xepgChannel.XCategory != "Movie" {
epg.EpisodeNum = append(epg.EpisodeNum, &EpisodeNum{Value: epgStartTime.Format("2006-01-02 15:04:05"), System: "original-air-date"})
}
epg.New = &New{Value: ""}
dummyXMLTV.Program = append(dummyXMLTV.Program, &epg)
epgStartTime = epgStopTime
}
}
return
}
// Kategorien erweitern (createXMLTVFile)
func getCategory(program *Program, xmltvProgram *Program, xepgChannel XEPGChannelStruct) {
for _, i := range xmltvProgram.Category {
category := &Category{}
category.Value = i.Value
category.Lang = i.Lang
program.Category = append(program.Category, category)
}
if len(xepgChannel.XCategory) > 0 {
category := &Category{}
category.Value = xepgChannel.XCategory
category.Lang = "en"
program.Category = append(program.Category, category)
}
return
}
// Programm Poster Cover aus der XMLTV Datei laden
func getPoster(program *Program, xmltvProgram *Program, xepgChannel XEPGChannelStruct) {
for _, poster := range xmltvProgram.Poster {
poster.Src = getCacheImageURL(poster.Src)
program.Poster = append(program.Poster, poster)
}
if Settings.XepgReplaceMissingImages == true {
if len(xmltvProgram.Poster) == 0 {
var poster Poster
poster.Src = getCacheImageURL(xepgChannel.TvgLogo)
program.Poster = append(program.Poster, poster)
}
}
}
// Episodensystem übernehmen, falls keins vorhanden ist und eine Kategorie im Mapping eingestellt wurden, wird eine Episode erstellt
func getEpisodeNum(program *Program, xmltvProgram *Program, xepgChannel XEPGChannelStruct) {
program.EpisodeNum = xmltvProgram.EpisodeNum
if len(xepgChannel.XCategory) > 0 && xepgChannel.XCategory != "Movie" {
if len(xmltvProgram.EpisodeNum) == 0 {
var timeLayout = "20060102150405"
t, err := time.Parse(timeLayout, strings.Split(xmltvProgram.Start, " ")[0])
if err == nil {
program.EpisodeNum = append(program.EpisodeNum, &EpisodeNum{Value: t.Format("2006-01-02 15:04:05"), System: "original-air-date"})
} else {
ShowError(err, 0)
}
}
}
return
}
// Videoparameter erstellen (createXMLTVFile)
func getVideo(program *Program, xmltvProgram *Program, xepgChannel XEPGChannelStruct) {
var video Video
video.Present = xmltvProgram.Video.Present
video.Colour = xmltvProgram.Video.Colour
video.Aspect = xmltvProgram.Video.Aspect
video.Quality = xmltvProgram.Video.Quality
if len(xmltvProgram.Video.Quality) == 0 {
if strings.Contains(strings.ToUpper(xepgChannel.XName), " HD") || strings.Contains(strings.ToUpper(xepgChannel.XName), " FHD") {
video.Quality = "HDTV"
}
if strings.Contains(strings.ToUpper(xepgChannel.XName), " UHD") || strings.Contains(strings.ToUpper(xepgChannel.XName), " 4K") {
video.Quality = "UHDTV"
}
}
program.Video = video
return
}
// Lokale Provider XMLTV Datei laden
func getLocalXMLTV(file string, xmltv *XMLTV) (err error) {
if _, ok := Data.Cache.XMLTV[file]; !ok {
// Cache initialisieren
if len(Data.Cache.XMLTV) == 0 {
Data.Cache.XMLTV = make(map[string]XMLTV)
}
// XML Daten lesen
content, err := readByteFromFile(file)
// Lokale XML Datei existiert nicht im Ordner: data
if err != nil {
ShowError(err, 1004)
err = errors.New("Local copy of the file no longer exists")
return err
}
// XML Datei parsen
err = xml.Unmarshal(content, &xmltv)
if err != nil {
return err
}
Data.Cache.XMLTV[file] = *xmltv
} else {
*xmltv = Data.Cache.XMLTV[file]
}
return
}
// M3U Datei erstellen
func createM3UFile() {
showInfo("XEPG:" + fmt.Sprintf("Create M3U file (%s)", System.File.M3U))
_, err := buildM3U([]string{})
if err != nil {
ShowError(err, 000)
}
saveMapToJSONFile(System.File.URLS, Data.Cache.StreamingURLS)
return
}
// XEPG Datenbank bereinigen
func cleanupXEPG() {
showInfo("XEPG:" + fmt.Sprintf("Cleanup database"))
Data.XEPG.XEPGCount = 0
for id, dxc := range Data.XEPG.Channels {
var xepgChannel XEPGChannelStruct
err := json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
if err == nil {
if indexOfString(xepgChannel.Name, Data.Cache.Streams.Active) == -1 {
delete(Data.XEPG.Channels, id)
} else {
if xepgChannel.XActive == true {
Data.XEPG.XEPGCount++
}
}
}
}
err := saveMapToJSONFile(System.File.XEPG, Data.XEPG.Channels)
if err != nil {
ShowError(err, 000)
return
}
showInfo("XEPG Channels:" + fmt.Sprintf("%d", Data.XEPG.XEPGCount))
if len(Data.Streams.Active) > 0 && Data.XEPG.XEPGCount == 0 {
showWarning(2005)
}
return
}
// Streaming URL für die Channels App generieren
func getStreamByChannelID(channelID string) (playlistID, streamURL string, err error) {
err = errors.New("Channel not found")
for _, dxc := range Data.XEPG.Channels {
var xepgChannel XEPGChannelStruct
err := json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
fmt.Println(xepgChannel.XChannelID)
if err == nil {
if channelID == xepgChannel.XChannelID {
playlistID = xepgChannel.FileM3UID
streamURL = xepgChannel.URL
return playlistID, streamURL, nil
}
}
}
return
}