Phase 3: Go hygiene pass, runtime PUID/PGID, fork README
continuous-integration/drone/push Build encountered an error
continuous-integration/drone/push Build encountered an error
Go: - staticcheck 399 -> 0 with staticcheck.conf (style checks ST1000/1003/ 1005/1016/1020/1021/1022 excluded; error strings are shown in the UI). - io/ioutil and rand.Seed removed; CloseNotifier kept with a lint-ignore until the Phase 2 context rewrite. - Dead code deleted: Auto handler, getStreamByChannelID, updateXEPG, indexOfInt, jsonToMapInt64, removeOldSystemData, randomTime, and the commented-out blocks in struct-buffer.go and internal/authentication. - Duplicates folded: cacheImagesInBackground(), one addErrorToStream(). - Bugs found by SA4006/SA5001: os.Create handle leaked per ffmpeg segment (buffer.go), http.NewRequest error unchecked (buffer.go), xepg.json migration wrote null on read error (migrate.go), WriteUserData errors silently dropped (authentication.go), defer Close before error check (buffer.go, toolchain.go). checkFilePermission results were discarded; an unwritable config or temp dir is now fatal at start-up. - gofmt applied repo-wide; Drone runs gofmt check and staticcheck. Docker: - Entrypoint starts as root, applies PUID/PGID (falls back to XTEVE_UID/ XTEVE_GID, then image defaults), fixes config ownership only when it differs, then drops to xteve via su-exec. --user starts skip all of it. - /xteve removed from LEGACY_CONFIG_DIRS (it is the parent of the default). - mwader/static-ffmpeg pinned to 7.1.1; VOLUME /xteve/config. - Compose files pull registry.coadcorp.com/nathan/xteve:latest, use PUID/PGID/TZ, and explain that SSDP needs host networking. - .dockerignore excludes the npm toolchain (bundle stays in html/js). Docs: README rewritten for the fork (about, registry, compose, env vars, security notes); README-DEV gains a container section.
This commit is contained in:
+10
-6
@@ -63,7 +63,7 @@ func createFirstUserForAuthentication(username, password string) (token string,
|
||||
|
||||
func tokenAuthentication(token string) (newToken string, err error) {
|
||||
|
||||
if System.ConfigurationWizard == true {
|
||||
if System.ConfigurationWizard {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ func urlAuth(r *http.Request, requestType string) (err error) {
|
||||
|
||||
case "m3u":
|
||||
level = "authentication.m3u"
|
||||
if Settings.AuthenticationM3U == true {
|
||||
if Settings.AuthenticationM3U {
|
||||
token, err = authentication.UserAuthentication(username, password)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -119,7 +119,7 @@ func urlAuth(r *http.Request, requestType string) (err error) {
|
||||
|
||||
case "xml":
|
||||
level = "authentication.xml"
|
||||
if Settings.AuthenticationXML == true {
|
||||
if Settings.AuthenticationXML {
|
||||
token, err = authentication.UserAuthentication(username, password)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -150,18 +150,22 @@ func checkAuthorizationLevel(token, level string) (err error) {
|
||||
|
||||
if v, ok := userData[level].(bool); ok {
|
||||
|
||||
if v == false {
|
||||
if !v {
|
||||
err = errors.New("No authorization")
|
||||
}
|
||||
|
||||
} else {
|
||||
userData[level] = false
|
||||
err = authentication.WriteUserData(userID, userData)
|
||||
if err = authentication.WriteUserData(userID, userData); err != nil {
|
||||
ShowError(err, 0)
|
||||
}
|
||||
err = errors.New("No authorization")
|
||||
}
|
||||
|
||||
} else {
|
||||
err = authentication.WriteUserData(userID, userData)
|
||||
if err = authentication.WriteUserData(userID, userData); err != nil {
|
||||
ShowError(err, 0)
|
||||
}
|
||||
err = errors.New("No authorization")
|
||||
}
|
||||
|
||||
|
||||
+179
-180
@@ -1,274 +1,273 @@
|
||||
package src
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
b64 "encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func xTeVeAutoBackup() (err error) {
|
||||
|
||||
var archiv = "xteve_auto_backup_" + time.Now().Format("20060102_1504") + ".zip"
|
||||
var target string
|
||||
var sourceFiles = make([]string, 0)
|
||||
var oldBackupFiles = make([]string, 0)
|
||||
var debug string
|
||||
var archiv = "xteve_auto_backup_" + time.Now().Format("20060102_1504") + ".zip"
|
||||
var target string
|
||||
var sourceFiles = make([]string, 0)
|
||||
var oldBackupFiles = make([]string, 0)
|
||||
var debug string
|
||||
|
||||
if len(Settings.BackupPath) > 0 {
|
||||
System.Folder.Backup = Settings.BackupPath
|
||||
}
|
||||
if len(Settings.BackupPath) > 0 {
|
||||
System.Folder.Backup = Settings.BackupPath
|
||||
}
|
||||
|
||||
showInfo("Backup Path:" + System.Folder.Backup)
|
||||
showInfo("Backup Path:" + System.Folder.Backup)
|
||||
|
||||
err = checkFolder(System.Folder.Backup)
|
||||
if err != nil {
|
||||
ShowError(err, 1070)
|
||||
return
|
||||
}
|
||||
err = checkFolder(System.Folder.Backup)
|
||||
if err != nil {
|
||||
ShowError(err, 1070)
|
||||
return
|
||||
}
|
||||
|
||||
// Alte Backups löschen
|
||||
files, err := ioutil.ReadDir(System.Folder.Backup)
|
||||
// Alte Backups löschen
|
||||
files, err := os.ReadDir(System.Folder.Backup)
|
||||
|
||||
if err == nil {
|
||||
if err == nil {
|
||||
|
||||
for _, file := range files {
|
||||
for _, file := range files {
|
||||
|
||||
if filepath.Ext(file.Name()) == ".zip" && strings.Contains(file.Name(), "xteve_auto_backup") {
|
||||
oldBackupFiles = append(oldBackupFiles, file.Name())
|
||||
}
|
||||
if filepath.Ext(file.Name()) == ".zip" && strings.Contains(file.Name(), "xteve_auto_backup") {
|
||||
oldBackupFiles = append(oldBackupFiles, file.Name())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Alle Backups löschen
|
||||
var end int
|
||||
switch Settings.BackupKeep {
|
||||
case 0:
|
||||
end = 0
|
||||
default:
|
||||
end = Settings.BackupKeep - 1
|
||||
}
|
||||
// Alle Backups löschen
|
||||
var end int
|
||||
switch Settings.BackupKeep {
|
||||
case 0:
|
||||
end = 0
|
||||
default:
|
||||
end = Settings.BackupKeep - 1
|
||||
}
|
||||
|
||||
for i := 0; i < len(oldBackupFiles)-end; i++ {
|
||||
for i := 0; i < len(oldBackupFiles)-end; i++ {
|
||||
|
||||
os.RemoveAll(System.Folder.Backup + oldBackupFiles[i])
|
||||
debug = fmt.Sprintf("Delete backup file:%s", oldBackupFiles[i])
|
||||
showDebug(debug, 1)
|
||||
os.RemoveAll(System.Folder.Backup + oldBackupFiles[i])
|
||||
debug = fmt.Sprintf("Delete backup file:%s", oldBackupFiles[i])
|
||||
showDebug(debug, 1)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if Settings.BackupKeep == 0 {
|
||||
return
|
||||
}
|
||||
if Settings.BackupKeep == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
} else {
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Backup erstellen
|
||||
if err == nil {
|
||||
// Backup erstellen
|
||||
if err == nil {
|
||||
|
||||
target = System.Folder.Backup + archiv
|
||||
target = System.Folder.Backup + archiv
|
||||
|
||||
for _, i := range SystemFiles {
|
||||
sourceFiles = append(sourceFiles, System.Folder.Config+i)
|
||||
}
|
||||
for _, i := range SystemFiles {
|
||||
sourceFiles = append(sourceFiles, System.Folder.Config+i)
|
||||
}
|
||||
|
||||
sourceFiles = append(sourceFiles, System.Folder.ImagesUpload)
|
||||
sourceFiles = append(sourceFiles, System.Folder.ImagesUpload)
|
||||
|
||||
err = zipFiles(sourceFiles, target)
|
||||
err = zipFiles(sourceFiles, target)
|
||||
|
||||
if err == nil {
|
||||
if err == nil {
|
||||
|
||||
debug = fmt.Sprintf("Create backup file:%s", target)
|
||||
showDebug(debug, 1)
|
||||
debug = fmt.Sprintf("Create backup file:%s", target)
|
||||
showDebug(debug, 1)
|
||||
|
||||
showInfo("Backup file:" + target)
|
||||
showInfo("Backup file:" + target)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
func xteveBackup() (archiv string, err error) {
|
||||
|
||||
err = checkFolder(System.Folder.Temp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = checkFolder(System.Folder.Temp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
archiv = "xteve_backup_" + time.Now().Format("20060102_1504") + ".zip"
|
||||
archiv = "xteve_backup_" + time.Now().Format("20060102_1504") + ".zip"
|
||||
|
||||
var target = System.Folder.Temp + archiv
|
||||
var sourceFiles = make([]string, 0)
|
||||
var target = System.Folder.Temp + archiv
|
||||
var sourceFiles = make([]string, 0)
|
||||
|
||||
for _, i := range SystemFiles {
|
||||
sourceFiles = append(sourceFiles, System.Folder.Config+i)
|
||||
}
|
||||
for _, i := range SystemFiles {
|
||||
sourceFiles = append(sourceFiles, System.Folder.Config+i)
|
||||
}
|
||||
|
||||
sourceFiles = append(sourceFiles, System.Folder.Data)
|
||||
sourceFiles = append(sourceFiles, System.Folder.Data)
|
||||
|
||||
err = zipFiles(sourceFiles, target)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
err = zipFiles(sourceFiles, target)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
func xteveRestore(archive string) (newWebURL string, err error) {
|
||||
|
||||
var newPort, oldPort, backupVersion, tmpRestore string
|
||||
var newPort, oldPort, backupVersion, tmpRestore string
|
||||
|
||||
tmpRestore = System.Folder.Temp + "restore" + string(os.PathSeparator)
|
||||
tmpRestore = System.Folder.Temp + "restore" + string(os.PathSeparator)
|
||||
|
||||
err = checkFolder(tmpRestore)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = checkFolder(tmpRestore)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Zip Archiv in tmp entpacken
|
||||
err = extractZIP(archive, tmpRestore)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Zip Archiv in tmp entpacken
|
||||
err = extractZIP(archive, tmpRestore)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Neue Config laden um den Port und die Version zu überprüfen
|
||||
newConfig, err := loadJSONFileToMap(tmpRestore + "settings.json")
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
// Neue Config laden um den Port und die Version zu überprüfen
|
||||
newConfig, err := loadJSONFileToMap(tmpRestore + "settings.json")
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
|
||||
backupVersion = newConfig["version"].(string)
|
||||
if backupVersion < System.Compatibility {
|
||||
err = errors.New(getErrMsg(1013))
|
||||
return
|
||||
}
|
||||
backupVersion = newConfig["version"].(string)
|
||||
if backupVersion < System.Compatibility {
|
||||
err = errors.New(getErrMsg(1013))
|
||||
return
|
||||
}
|
||||
|
||||
// Zip Archiv in den Config Ordner entpacken
|
||||
err = extractZIP(archive, System.Folder.Config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Zip Archiv in den Config Ordner entpacken
|
||||
err = extractZIP(archive, System.Folder.Config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Neue Config laden um den Port und die Version zu überprüfen
|
||||
newConfig, err = loadJSONFileToMap(System.Folder.Config + "settings.json")
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
// Neue Config laden um den Port und die Version zu überprüfen
|
||||
newConfig, err = loadJSONFileToMap(System.Folder.Config + "settings.json")
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
|
||||
newPort = newConfig["port"].(string)
|
||||
oldPort = Settings.Port
|
||||
newPort = newConfig["port"].(string)
|
||||
oldPort = Settings.Port
|
||||
|
||||
if newPort == oldPort {
|
||||
if newPort == oldPort {
|
||||
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
}
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
}
|
||||
|
||||
loadSettings()
|
||||
loadSettings()
|
||||
|
||||
err := Init()
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return "", err
|
||||
}
|
||||
err := Init()
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = StartSystem(true)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return "", err
|
||||
}
|
||||
err = StartSystem(true)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
var url = System.URLBase + "/web/"
|
||||
newWebURL = strings.Replace(url, ":"+oldPort, ":"+newPort, 1)
|
||||
var url = System.URLBase + "/web/"
|
||||
newWebURL = strings.Replace(url, ":"+oldPort, ":"+newPort, 1)
|
||||
|
||||
os.RemoveAll(tmpRestore)
|
||||
os.RemoveAll(tmpRestore)
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
func xteveRestoreFromWeb(input string) (newWebURL string, err error) {
|
||||
|
||||
// Base64 Json String in base64 umwandeln
|
||||
b64data := input[strings.IndexByte(input, ',')+1:]
|
||||
// Base64 Json String in base64 umwandeln
|
||||
b64data := input[strings.IndexByte(input, ',')+1:]
|
||||
|
||||
// Base64 in bytes umwandeln und speichern
|
||||
sDec, err := b64.StdEncoding.DecodeString(b64data)
|
||||
// Base64 in bytes umwandeln und speichern
|
||||
sDec, err := b64.StdEncoding.DecodeString(b64data)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var archive = System.Folder.Temp + "restore.zip"
|
||||
var archive = System.Folder.Temp + "restore.zip"
|
||||
|
||||
err = writeByteToFile(archive, sDec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writeByteToFile(archive, sDec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newWebURL, err = xteveRestore(archive)
|
||||
newWebURL, err = xteveRestore(archive)
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
// XteveRestoreFromCLI : Wiederherstellung über die Kommandozeile
|
||||
func XteveRestoreFromCLI(archive string) (err error) {
|
||||
|
||||
var confirm string
|
||||
var confirm string
|
||||
|
||||
println()
|
||||
showInfo(fmt.Sprintf("Version:%s Build: %s", System.Version, System.Build))
|
||||
showInfo(fmt.Sprintf("Backup File:%s", archive))
|
||||
showInfo(fmt.Sprintf("System Folder:%s", getPlatformPath(System.Folder.Config)))
|
||||
println()
|
||||
println()
|
||||
showInfo(fmt.Sprintf("Version:%s Build: %s", System.Version, System.Build))
|
||||
showInfo(fmt.Sprintf("Backup File:%s", archive))
|
||||
showInfo(fmt.Sprintf("System Folder:%s", getPlatformPath(System.Folder.Config)))
|
||||
println()
|
||||
|
||||
fmt.Print("All data will be replaced with those from the backup. Should the files be restored? [yes|no]:")
|
||||
fmt.Print("All data will be replaced with those from the backup. Should the files be restored? [yes|no]:")
|
||||
|
||||
fmt.Scanln(&confirm)
|
||||
fmt.Scanln(&confirm)
|
||||
|
||||
switch strings.ToLower(confirm) {
|
||||
switch strings.ToLower(confirm) {
|
||||
|
||||
case "yes":
|
||||
break
|
||||
case "yes":
|
||||
break
|
||||
|
||||
case "no":
|
||||
return
|
||||
case "no":
|
||||
return
|
||||
|
||||
default:
|
||||
fmt.Println("Invalid input")
|
||||
return
|
||||
default:
|
||||
fmt.Println("Invalid input")
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if len(System.Folder.Config) > 0 {
|
||||
if len(System.Folder.Config) > 0 {
|
||||
|
||||
err = checkFilePermission(System.Folder.Config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = checkFilePermission(System.Folder.Config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = xteveRestore(archive)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = xteveRestore(archive)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
showHighlight(fmt.Sprintf("Restor:Backup was successfully restored. %s can now be started normally", System.Name))
|
||||
showHighlight(fmt.Sprintf("Restor:Backup was successfully restored. %s can now be started normally", System.Name))
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
+77
-86
@@ -11,7 +11,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -146,7 +145,7 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
}
|
||||
|
||||
// Neuer Stream bei einer bereits aktiven Playlist
|
||||
if newStream == true {
|
||||
if newStream {
|
||||
|
||||
// Prüfen ob die Playlist noch einen weiteren Stream erlaubt (Tuner)
|
||||
if len(playlist.Streams) >= playlist.Tuner {
|
||||
@@ -193,7 +192,7 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
}
|
||||
|
||||
// Überprüfen ob der Stream breits von einem anderen Client abgespielt wird
|
||||
if playlist.Streams[streamID].Status == false && newStream == true {
|
||||
if !playlist.Streams[streamID].Status && newStream {
|
||||
|
||||
// Neuer Buffer wird benötigt
|
||||
stream = playlist.Streams[streamID]
|
||||
@@ -235,7 +234,7 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
|
||||
if stream, ok := playlist.Streams[streamID]; ok {
|
||||
|
||||
if stream.Status == false {
|
||||
if !stream.Status {
|
||||
|
||||
timeOut++
|
||||
|
||||
@@ -261,6 +260,7 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
|
||||
// HTTP Clientverbindung überwachen
|
||||
|
||||
//lint:ignore SA1019 replaced by request context in Phase 2
|
||||
cn, ok := w.(http.CloseNotifier)
|
||||
if ok {
|
||||
|
||||
@@ -310,10 +310,11 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
var fileName = stream.Folder + f
|
||||
|
||||
file, err := os.Open(fileName)
|
||||
defer file.Close()
|
||||
|
||||
if err == nil {
|
||||
|
||||
defer file.Close()
|
||||
|
||||
l, err := file.Stat()
|
||||
if err == nil {
|
||||
|
||||
@@ -327,7 +328,7 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
|
||||
file.Seek(0, 0)
|
||||
|
||||
if streaming == false {
|
||||
if !streaming {
|
||||
|
||||
contentType := http.DetectContentType(buffer)
|
||||
_ = contentType
|
||||
@@ -406,7 +407,7 @@ func getTmpFiles(stream *ThisStream) (tmpFiles []string) {
|
||||
|
||||
if _, err := os.Stat(tmpFolder); !os.IsNotExist(err) {
|
||||
|
||||
files, err := ioutil.ReadDir(getPlatformPath(tmpFolder))
|
||||
files, err := os.ReadDir(getPlatformPath(tmpFolder))
|
||||
if err != nil {
|
||||
ShowError(err, 000)
|
||||
return
|
||||
@@ -455,7 +456,7 @@ func killClientConnection(streamID int, playlistID string, force bool) {
|
||||
|
||||
var playlist = p.(Playlist)
|
||||
|
||||
if force == true {
|
||||
if force {
|
||||
delete(playlist.Streams, streamID)
|
||||
showInfo(fmt.Sprintf("Streaming Status:Playlist: %s - Tuner: %d / %d", playlist.PlaylistName, len(playlist.Streams), playlist.Tuner))
|
||||
return
|
||||
@@ -531,6 +532,21 @@ func clientConnection(stream ThisStream) (status bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// addErrorToStream : Fehler an die Clientverbindung des Streams weitergeben
|
||||
func addErrorToStream(playlist Playlist, streamID int, playlistID string, err error) {
|
||||
|
||||
var stream = playlist.Streams[streamID]
|
||||
|
||||
if c, ok := BufferClients.Load(playlistID + stream.MD5); ok {
|
||||
|
||||
var clients = c.(ClientConnection)
|
||||
clients.Error = err
|
||||
BufferClients.Store(playlistID+stream.MD5, clients)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
if p, ok := BufferInformation.Load(playlistID); ok {
|
||||
@@ -575,26 +591,12 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
}
|
||||
|
||||
var addErrorToStream = func(err error) {
|
||||
|
||||
var stream = playlist.Streams[streamID]
|
||||
|
||||
if c, ok := BufferClients.Load(playlistID + stream.MD5); ok {
|
||||
|
||||
var clients = c.(ClientConnection)
|
||||
clients.Error = err
|
||||
BufferClients.Store(playlistID+stream.MD5, clients)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
os.RemoveAll(getPlatformPath(tmpFolder))
|
||||
|
||||
err := checkFolder(tmpFolder)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -609,11 +611,11 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
return
|
||||
}
|
||||
|
||||
var stream ThisStream = playlist.Streams[streamID]
|
||||
var stream = playlist.Streams[streamID]
|
||||
|
||||
if stream.Status == false {
|
||||
if !stream.Status {
|
||||
|
||||
if strings.Index(stream.URL, ".m3u8") != -1 {
|
||||
if strings.Contains(stream.URL, ".m3u8") {
|
||||
showInfo("Streaming Type:" + "[HLS / M3U8]")
|
||||
} else {
|
||||
showInfo("Streaming Type:" + "[TS]")
|
||||
@@ -631,7 +633,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
for {
|
||||
|
||||
if clientConnection(stream) == false {
|
||||
if !clientConnection(stream) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -654,6 +656,14 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
Redirect:
|
||||
|
||||
req, err := http.NewRequest("GET", currentURL, nil)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
killClientConnection(streamID, playlistID, true)
|
||||
clientConnection(stream)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", getUserAgent())
|
||||
req.Header.Set("Connection", "close")
|
||||
//req.Header.Set("Range", "bytes=0-")
|
||||
@@ -679,7 +689,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
fmt.Println("Current URL:", currentURL)
|
||||
ShowError(err, 0)
|
||||
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
|
||||
killClientConnection(streamID, playlistID, true)
|
||||
clientConnection(stream)
|
||||
@@ -708,7 +718,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
err = errors.New("Streaming server")
|
||||
ShowError(err, 4002)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -719,7 +729,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
} else {
|
||||
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -749,7 +759,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
showDebug(debug, 1)
|
||||
|
||||
BufferInformation.Store(playlist.PlaylistID, playlist)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
|
||||
killClientConnection(streamID, playlistID, true)
|
||||
clientConnection(stream)
|
||||
@@ -759,7 +769,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
}
|
||||
|
||||
// Informationen über den Streamingserver auslesen
|
||||
if stream.Status == false {
|
||||
if !stream.Status {
|
||||
|
||||
if len(stream.URLStreamingServer) == 0 {
|
||||
|
||||
@@ -802,10 +812,10 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
// M3U8 Playlist
|
||||
case "application/x-mpegurl", "application/vnd.apple.mpegurl", "audio/mpegurl", "audio/x-mpegurl":
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
}
|
||||
|
||||
stream.Body = string(body)
|
||||
@@ -815,7 +825,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
err = parseM3U8(&stream)
|
||||
if err != nil {
|
||||
ShowError(err, 4050)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
}
|
||||
|
||||
// Video Stream (TS)
|
||||
@@ -835,7 +845,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
var tmpFile = fmt.Sprintf("%s%d.ts", tmpFolder, tmpSegment)
|
||||
|
||||
if clientConnection(stream) == false {
|
||||
if !clientConnection(stream) {
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
@@ -843,7 +853,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
bufferFile, err := os.Create(tmpFile)
|
||||
if err != nil {
|
||||
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
bufferFile.Close()
|
||||
resp.Body.Close()
|
||||
return
|
||||
@@ -866,7 +876,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
if err != nil && err != io.EOF {
|
||||
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
resp.Body.Close()
|
||||
return
|
||||
|
||||
@@ -877,7 +887,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
if _, err := bufferFile.Write(buffer[:n]); err != nil {
|
||||
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
resp.Body.Close()
|
||||
return
|
||||
|
||||
@@ -887,7 +897,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
fileSize = fileSize + n
|
||||
|
||||
if clientConnection(stream) == false {
|
||||
if !clientConnection(stream) {
|
||||
|
||||
resp.Body.Close()
|
||||
bufferFile.Close()
|
||||
@@ -929,7 +939,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
tmpFile = fmt.Sprintf("%s%d.ts", tmpFolder, tmpSegment)
|
||||
|
||||
if clientConnection(stream) == false {
|
||||
if !clientConnection(stream) {
|
||||
|
||||
bufferFile.Close()
|
||||
resp.Body.Close()
|
||||
@@ -944,7 +954,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
bufferFile, err = os.Create(tmpFile)
|
||||
if err != nil {
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
@@ -970,7 +980,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
err = errors.New("Streaming error")
|
||||
ShowError(err, 4003)
|
||||
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
@@ -978,7 +988,7 @@ func connectToStreamingServer(streamID int, playlistID string) {
|
||||
s++
|
||||
|
||||
// Wartezeit für den Download das nächste Segments berechnen
|
||||
if stream.HLS == true {
|
||||
if stream.HLS {
|
||||
|
||||
var sleep float64
|
||||
|
||||
@@ -1143,14 +1153,13 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(stream.Body, "#EXTM3U") {
|
||||
|
||||
var lines = strings.Split(strings.Replace(stream.Body, "\r\n", "\n", -1), "\n")
|
||||
|
||||
if stream.DynamicBandwidth == false {
|
||||
if !stream.DynamicBandwidth {
|
||||
stream.DynamicStream = make(map[int]DynamicStream)
|
||||
}
|
||||
|
||||
@@ -1173,7 +1182,7 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
}
|
||||
|
||||
// M3U8 enthällt mehrere Links zu weiteren M3U8 Wiedergabelisten (Bandbreitenoption)
|
||||
if segment.Info == true && len(line) > 0 && line[0:1] != "#" {
|
||||
if segment.Info && len(line) > 0 && line[0:1] != "#" {
|
||||
|
||||
var dynamicStream DynamicStream
|
||||
|
||||
@@ -1217,7 +1226,7 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
|
||||
noNewSegment = true
|
||||
|
||||
if stream.Status == false {
|
||||
if !stream.Status {
|
||||
|
||||
if len(m3u8Segments) >= 2 {
|
||||
m3u8Segments = m3u8Segments[0 : len(m3u8Segments)-1]
|
||||
@@ -1229,7 +1238,7 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
|
||||
segment = s
|
||||
|
||||
if stream.Status == false {
|
||||
if !stream.Status {
|
||||
|
||||
noNewSegment = false
|
||||
stream.LastSequence = segment.Sequence
|
||||
@@ -1255,9 +1264,9 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
|
||||
}
|
||||
|
||||
if noNewSegment == false {
|
||||
if !noNewSegment {
|
||||
|
||||
if stream.DynamicBandwidth == true {
|
||||
if stream.DynamicBandwidth {
|
||||
switchBandwidth(stream)
|
||||
} else {
|
||||
stream.Segment = append(stream.Segment, segment)
|
||||
@@ -1265,7 +1274,7 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
|
||||
}
|
||||
|
||||
if noNewSegment == true {
|
||||
if noNewSegment {
|
||||
|
||||
var sleep = lastSegmentDuration * 0.5
|
||||
|
||||
@@ -1371,33 +1380,19 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
return
|
||||
}
|
||||
|
||||
var addErrorToStream = func(err error) {
|
||||
|
||||
var stream = playlist.Streams[streamID]
|
||||
|
||||
if c, ok := BufferClients.Load(playlistID + stream.MD5); ok {
|
||||
|
||||
var clients = c.(ClientConnection)
|
||||
clients.Error = err
|
||||
BufferClients.Store(playlistID+stream.MD5, clients)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
os.RemoveAll(getPlatformPath(tmpFolder))
|
||||
|
||||
err := checkFolder(tmpFolder)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = checkFile(path)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1409,7 +1404,7 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
f, err := os.Create(tmpFile)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1461,7 +1456,7 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
ShowError(err, 0)
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1471,11 +1466,11 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
ShowError(err, 0)
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(buf.Bytes()) == 0 && stream.Status == false {
|
||||
if len(buf.Bytes()) == 0 && !stream.Status {
|
||||
showInfo(bufferType + ":Processing data")
|
||||
}
|
||||
|
||||
@@ -1543,7 +1538,7 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
cmd.Process.Kill()
|
||||
err = errors.New("Timout")
|
||||
ShowError(err, 4006)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
cmd.Wait()
|
||||
f.Close()
|
||||
return
|
||||
@@ -1553,11 +1548,11 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
|
||||
}
|
||||
|
||||
if fileSize == 0 && stream.Status == false {
|
||||
if fileSize == 0 && !stream.Status {
|
||||
showInfo("Streaming Status:Receive data from " + bufferType)
|
||||
}
|
||||
|
||||
if clientConnection(stream) == false {
|
||||
if !clientConnection(stream) {
|
||||
cmd.Process.Kill()
|
||||
f.Close()
|
||||
cmd.Wait()
|
||||
@@ -1574,7 +1569,7 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
if _, err := f.Write(buffer[:n]); err != nil {
|
||||
cmd.Process.Kill()
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
cmd.Wait()
|
||||
f.Close()
|
||||
return
|
||||
@@ -1582,7 +1577,7 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
|
||||
if fileSize >= bufferSize/2 {
|
||||
|
||||
if tmpSegment == 1 && stream.Status == false {
|
||||
if tmpSegment == 1 && !stream.Status {
|
||||
close(t)
|
||||
close(streamStatus)
|
||||
showInfo(fmt.Sprintf("Streaming Status:Buffering data from %s", bufferType))
|
||||
@@ -1591,7 +1586,7 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
f.Close()
|
||||
tmpSegment++
|
||||
|
||||
if stream.Status == false {
|
||||
if !stream.Status {
|
||||
Lock.Lock()
|
||||
stream.Status = true
|
||||
playlist.Streams[streamID] = stream
|
||||
@@ -1603,13 +1598,11 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
|
||||
fileSize = 0
|
||||
|
||||
var errCreate, errOpen error
|
||||
f, errCreate = os.Create(tmpFile)
|
||||
f, errOpen = os.OpenFile(tmpFile, os.O_APPEND|os.O_WRONLY, 0600)
|
||||
if errCreate != nil || errOpen != nil {
|
||||
f, err = os.OpenFile(tmpFile, os.O_CREATE|os.O_TRUNC|os.O_APPEND|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
cmd.Process.Kill()
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
cmd.Wait()
|
||||
f.Close()
|
||||
return
|
||||
@@ -1623,7 +1616,7 @@ func thirdPartyBuffer(streamID int, playlistID string) {
|
||||
cmd.Wait()
|
||||
|
||||
err = errors.New(bufferType + " error")
|
||||
addErrorToStream(err)
|
||||
addErrorToStream(playlist, streamID, playlistID, err)
|
||||
ShowError(err, 1204)
|
||||
|
||||
time.Sleep(time.Duration(500) * time.Millisecond)
|
||||
@@ -1694,7 +1687,6 @@ func debugRequest(req *http.Request) {
|
||||
debug = "Request:* * * * * * END HTTP(S) REQUEST * * * * * *"
|
||||
showDebug(debug, debugLevel)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func debugResponse(resp *http.Response) {
|
||||
@@ -1739,5 +1731,4 @@ func debugResponse(resp *http.Response) {
|
||||
debug = "Pesponse:* * * * * * END RESPONSE * * * * * * "
|
||||
showDebug(debug, debugLevel)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
+11
-4
@@ -152,8 +152,9 @@ func Init() (err error) {
|
||||
|
||||
// Berechtigung aller Ordner überprüfen
|
||||
err = checkFilePermission(System.Folder.Config)
|
||||
if err == nil {
|
||||
err = checkFilePermission(System.Folder.Temp)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
|
||||
// Separaten tmp Ordner für jede Instanz
|
||||
@@ -165,6 +166,12 @@ func Init() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
err = checkFilePermission(System.Folder.Temp)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
|
||||
err = removeChildItems(getPlatformPath(System.Folder.Temp))
|
||||
if err != nil {
|
||||
return
|
||||
@@ -173,7 +180,7 @@ func Init() (err error) {
|
||||
// Branch festlegen
|
||||
System.Branch = Settings.Branch
|
||||
|
||||
if System.Dev == true {
|
||||
if System.Dev {
|
||||
System.Branch = "Development"
|
||||
}
|
||||
|
||||
@@ -217,7 +224,7 @@ func StartSystem(updateProviderFiles bool) (err error) {
|
||||
showInfo(fmt.Sprintf("Unfiltered Chan. Limit:%d", System.UnfilteredChannelLimit))
|
||||
|
||||
// Providerdaten aktualisieren
|
||||
if len(Settings.Files.M3U) > 0 && Settings.FilesUpdate == true || updateProviderFiles == true {
|
||||
if len(Settings.Files.M3U) > 0 && Settings.FilesUpdate || updateProviderFiles {
|
||||
|
||||
err = xTeVeAutoBackup()
|
||||
if err != nil {
|
||||
|
||||
+13
-22
@@ -73,10 +73,6 @@ func updateServerSettings(request RequestStruct) (settings SettingsStruct, err e
|
||||
|
||||
}
|
||||
|
||||
if len(newUpdateTimes) == 0 {
|
||||
//newUpdateTimes = append(newUpdateTimes, "0000")
|
||||
}
|
||||
|
||||
value = newUpdateTimes
|
||||
|
||||
case "cache.images":
|
||||
@@ -179,7 +175,7 @@ func updateServerSettings(request RequestStruct) (settings SettingsStruct, err e
|
||||
return
|
||||
}
|
||||
|
||||
if Settings.AuthenticationWEB == false {
|
||||
if !Settings.AuthenticationWEB {
|
||||
|
||||
Settings.AuthenticationAPI = false
|
||||
Settings.AuthenticationM3U = false
|
||||
@@ -221,7 +217,7 @@ func updateServerSettings(request RequestStruct) (settings SettingsStruct, err e
|
||||
|
||||
settings = Settings
|
||||
|
||||
if reloadData == true {
|
||||
if reloadData {
|
||||
|
||||
err = buildDatabaseDVR()
|
||||
if err != nil {
|
||||
@@ -232,7 +228,7 @@ func updateServerSettings(request RequestStruct) (settings SettingsStruct, err e
|
||||
|
||||
}
|
||||
|
||||
if cacheImages == true {
|
||||
if cacheImages {
|
||||
|
||||
if Settings.EpgSource == "XEPG" && System.ImageCachingInProgress == 0 {
|
||||
|
||||
@@ -271,7 +267,7 @@ func updateServerSettings(request RequestStruct) (settings SettingsStruct, err e
|
||||
|
||||
}
|
||||
|
||||
if createXEPGFiles == true {
|
||||
if createXEPGFiles {
|
||||
|
||||
go func() {
|
||||
createXMLTVFile()
|
||||
@@ -280,7 +276,7 @@ func updateServerSettings(request RequestStruct) (settings SettingsStruct, err e
|
||||
|
||||
}
|
||||
|
||||
if triggerPlexGuideReload == true {
|
||||
if triggerPlexGuideReload {
|
||||
queuePlexGuideRefresh("settings change")
|
||||
}
|
||||
|
||||
@@ -378,7 +374,7 @@ func saveFiles(request RequestStruct, fileType string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if reloadData == true {
|
||||
if reloadData {
|
||||
|
||||
err = buildDatabaseDVR()
|
||||
if err != nil {
|
||||
@@ -452,7 +448,6 @@ func deleteLocalProviderFiles(dataID, fileType string) {
|
||||
os.RemoveAll(System.Folder.Data + dataID + fileExtension)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Filtereinstellungen speichern (WebUI)
|
||||
@@ -505,7 +500,7 @@ func saveFilter(request RequestStruct) (settings SettingsStruct, err error) {
|
||||
if len(filter) == 0 {
|
||||
|
||||
err = errors.New(getErrMsg(1014))
|
||||
if newFilter == true {
|
||||
if newFilter {
|
||||
delete(filterMap, dataID)
|
||||
}
|
||||
|
||||
@@ -573,7 +568,7 @@ func saveXEpgMapping(request RequestStruct) (err error) {
|
||||
// Wenn während des erstellen der Datanbank das Mapping erneut gespeichert wird, wird die Datenbank erst später erneut aktualisiert.
|
||||
go func() {
|
||||
|
||||
if System.BackgroundProcess == true {
|
||||
if System.BackgroundProcess {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -591,7 +586,7 @@ func saveXEpgMapping(request RequestStruct) (err error) {
|
||||
cleanupXEPG()
|
||||
System.ScanInProgress = 0
|
||||
buildXEPG(false)
|
||||
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
|
||||
showInfo("XEPG:" + "Ready to use")
|
||||
|
||||
System.BackgroundProcess = false
|
||||
|
||||
@@ -632,7 +627,7 @@ func saveUserData(request RequestStruct) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if request.DeleteUser == true {
|
||||
if request.DeleteUser {
|
||||
err = authentication.RemoveUser(userID)
|
||||
return
|
||||
}
|
||||
@@ -859,7 +854,7 @@ func buildDatabaseDVR() (err error) {
|
||||
for n, i := range playlistFile {
|
||||
|
||||
var channels []any
|
||||
var groupTitle, tvgID, uuid int = 0, 0, 0
|
||||
var groupTitle, tvgID, uuid = 0, 0, 0
|
||||
var keys = []string{"group-title", "tvg-id", "uuid"}
|
||||
var compatibility = make(map[string]int)
|
||||
|
||||
@@ -905,11 +900,7 @@ func buildDatabaseDVR() (err error) {
|
||||
if value, ok := s[key]; ok {
|
||||
if len(value) > 0 {
|
||||
|
||||
if _, ok := tmpGroupsM3U[value]; ok {
|
||||
tmpGroupsM3U[value]++
|
||||
} else {
|
||||
tmpGroupsM3U[value] = 1
|
||||
}
|
||||
tmpGroupsM3U[value]++
|
||||
|
||||
groupTitle++
|
||||
}
|
||||
@@ -985,7 +976,7 @@ func buildDatabaseDVR() (err error) {
|
||||
|
||||
for group, count := range tmpGroupsM3U {
|
||||
var text = fmt.Sprintf("%s (%d)", group, count)
|
||||
var value = fmt.Sprintf("%s", group)
|
||||
var value = group
|
||||
Data.Playlist.M3U.Groups.Text = append(Data.Playlist.M3U.Groups.Text, text)
|
||||
Data.Playlist.M3U.Groups.Value = append(Data.Playlist.M3U.Groups.Value, value)
|
||||
}
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ func getLineup() (jsonContent []byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if xepgChannel.XActive == true {
|
||||
if xepgChannel.XActive {
|
||||
var stream LineupStream
|
||||
stream.GuideName = xepgChannel.XName
|
||||
stream.GuideNumber = xepgChannel.XChannelID
|
||||
|
||||
+16
-16
@@ -1,30 +1,30 @@
|
||||
package src
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func uploadLogo(input, filename string) (logoURL string, err error) {
|
||||
|
||||
b64data := input[strings.IndexByte(input, ',')+1:]
|
||||
b64data := input[strings.IndexByte(input, ',')+1:]
|
||||
|
||||
// BAse64 in bytes umwandeln un speichern
|
||||
sDec, err := b64.StdEncoding.DecodeString(b64data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// BAse64 in bytes umwandeln un speichern
|
||||
sDec, err := b64.StdEncoding.DecodeString(b64data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var file = fmt.Sprintf("%s%s", System.Folder.ImagesUpload, filename)
|
||||
var file = fmt.Sprintf("%s%s", System.Folder.ImagesUpload, filename)
|
||||
|
||||
err = writeByteToFile(file, sDec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = writeByteToFile(file, sDec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logoURL = fmt.Sprintf("%s://%s/data_images/%s", System.ServerProtocol.XML, System.Domain, filename)
|
||||
logoURL = fmt.Sprintf("%s://%s/data_images/%s", System.ServerProtocol.XML, System.Domain, filename)
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
+28
-32
@@ -20,45 +20,41 @@ func ShowSystemInfo() {
|
||||
fmt.Println("OK")
|
||||
println()
|
||||
|
||||
fmt.Println(fmt.Sprintf("Version: %s %s.%s", System.Name, System.Version, System.Build))
|
||||
fmt.Println(fmt.Sprintf("Branch: %s", System.Branch))
|
||||
fmt.Println(fmt.Sprintf("Folder (config): %s", System.Folder.Config))
|
||||
fmt.Printf("Version: %s %s.%s\n", System.Name, System.Version, System.Build)
|
||||
fmt.Printf("Branch: %s\n", System.Branch)
|
||||
fmt.Printf("Folder (config): %s\n", System.Folder.Config)
|
||||
|
||||
fmt.Println(fmt.Sprintf("Streams: %d / %d", len(Data.Streams.Active), len(Data.Streams.All)))
|
||||
fmt.Println(fmt.Sprintf("Filter: %d", len(Data.Filter)))
|
||||
fmt.Println(fmt.Sprintf("XEPG Chanels: %d", int(Data.XEPG.XEPGCount)))
|
||||
fmt.Printf("Streams: %d / %d\n", len(Data.Streams.Active), len(Data.Streams.All))
|
||||
fmt.Printf("Filter: %d\n", len(Data.Filter))
|
||||
fmt.Printf("XEPG Chanels: %d\n", int(Data.XEPG.XEPGCount))
|
||||
|
||||
println()
|
||||
fmt.Println(fmt.Sprintf("IPv4 Addresses:"))
|
||||
fmt.Println("IPv4 Addresses:")
|
||||
|
||||
for i, ipv4 := range System.IPAddressesV4 {
|
||||
|
||||
switch count := i; {
|
||||
|
||||
case count < 10:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
fmt.Printf(" %d. %s\n", count, ipv4)
|
||||
case count < 100:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
fmt.Printf(" %d. %s\n", count, ipv4)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
println()
|
||||
fmt.Println(fmt.Sprintf("IPv6 Addresses:"))
|
||||
fmt.Println("IPv6 Addresses:")
|
||||
|
||||
for i, ipv4 := range System.IPAddressesV6 {
|
||||
|
||||
switch count := i; {
|
||||
|
||||
case count < 10:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
fmt.Printf(" %d. %s\n", count, ipv4)
|
||||
case count < 100:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
fmt.Printf(" %d. %s\n", count, ipv4)
|
||||
|
||||
}
|
||||
|
||||
@@ -67,33 +63,33 @@ func ShowSystemInfo() {
|
||||
println("---")
|
||||
|
||||
fmt.Println("Settings [General]")
|
||||
fmt.Println(fmt.Sprintf("UUID: %s", Settings.UUID))
|
||||
fmt.Println(fmt.Sprintf("Tuner (Plex / Emby): %d", Settings.Tuner))
|
||||
fmt.Println(fmt.Sprintf("EPG Source: %s", Settings.EpgSource))
|
||||
fmt.Printf("UUID: %s\n", Settings.UUID)
|
||||
fmt.Printf("Tuner (Plex / Emby): %d\n", Settings.Tuner)
|
||||
fmt.Printf("EPG Source: %s\n", Settings.EpgSource)
|
||||
|
||||
println("---")
|
||||
|
||||
fmt.Println("Settings [Files]")
|
||||
fmt.Println(fmt.Sprintf("Schedule: %s", strings.Join(Settings.Update, ",")))
|
||||
fmt.Println(fmt.Sprintf("Files Update: %t", Settings.FilesUpdate))
|
||||
fmt.Println(fmt.Sprintf("Folder (tmp): %s", Settings.TempPath))
|
||||
fmt.Println(fmt.Sprintf("Image Chaching: %t", Settings.CacheImages))
|
||||
fmt.Println(fmt.Sprintf("Missing EPG Mode: %s", Settings.XepgMissingEPGMode))
|
||||
fmt.Println(fmt.Sprintf("Replace EPG Image: %t", Settings.XepgReplaceMissingImages))
|
||||
fmt.Printf("Schedule: %s\n", strings.Join(Settings.Update, ","))
|
||||
fmt.Printf("Files Update: %t\n", Settings.FilesUpdate)
|
||||
fmt.Printf("Folder (tmp): %s\n", Settings.TempPath)
|
||||
fmt.Printf("Image Chaching: %t\n", Settings.CacheImages)
|
||||
fmt.Printf("Missing EPG Mode: %s\n", Settings.XepgMissingEPGMode)
|
||||
fmt.Printf("Replace EPG Image: %t\n", Settings.XepgReplaceMissingImages)
|
||||
|
||||
println("---")
|
||||
|
||||
fmt.Println("Settings [Streaming]")
|
||||
fmt.Println(fmt.Sprintf("Buffer: %s", Settings.Buffer))
|
||||
fmt.Println(fmt.Sprintf("UDPxy: %s", Settings.UDPxy))
|
||||
fmt.Println(fmt.Sprintf("Buffer Size: %d KB", Settings.BufferSize))
|
||||
fmt.Println(fmt.Sprintf("Timeout: %d ms", int(Settings.BufferTimeout)))
|
||||
fmt.Println(fmt.Sprintf("User Agent: %s", Settings.UserAgent))
|
||||
fmt.Printf("Buffer: %s\n", Settings.Buffer)
|
||||
fmt.Printf("UDPxy: %s\n", Settings.UDPxy)
|
||||
fmt.Printf("Buffer Size: %d KB\n", Settings.BufferSize)
|
||||
fmt.Printf("Timeout: %d ms\n", int(Settings.BufferTimeout))
|
||||
fmt.Printf("User Agent: %s\n", Settings.UserAgent)
|
||||
|
||||
println("---")
|
||||
|
||||
fmt.Println("Settings [Backup]")
|
||||
fmt.Println(fmt.Sprintf("Folder (backup): %s", Settings.BackupPath))
|
||||
fmt.Println(fmt.Sprintf("Backup Keep: %d", Settings.BackupKeep))
|
||||
fmt.Printf("Folder (backup): %s\n", Settings.BackupPath)
|
||||
fmt.Printf("Backup Keep: %d\n", Settings.BackupKeep)
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package authentication
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -44,90 +43,6 @@ type Cookie struct {
|
||||
RawExpires string
|
||||
}
|
||||
|
||||
// Framework examples
|
||||
|
||||
/*
|
||||
func main() {
|
||||
var err error
|
||||
|
||||
var checkErr = func(err error) {
|
||||
log.Println(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
err = Init("", 10) // Path to save the data, Validity of tokens in minutes | (error)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
|
||||
err = CreateDefaultUser("admin", "123")
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
err = CreateNewUser("xteve", "xteve") // Username, Password | (error)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
|
||||
|
||||
err, token := UserAuthentication("xteve", "xteve") // Username, Password | (error, token)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
} else {
|
||||
fmt.Println("UserAuthentication()")
|
||||
fmt.Println("Token:", token)
|
||||
fmt.Println("---")
|
||||
}
|
||||
|
||||
err, newToken := CheckTheValidityOfTheToken(token) // Current token | (error, new token)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
} else {
|
||||
fmt.Println("CheckTheValidityOfTheToken()")
|
||||
fmt.Println("New Token:", newToken)
|
||||
fmt.Println("---")
|
||||
}
|
||||
|
||||
err, userID := GetUserID(newToken) // Current token | (error, user id)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
} else {
|
||||
fmt.Println("GetUserID()")
|
||||
fmt.Println("User ID:", userID)
|
||||
fmt.Println("---")
|
||||
}
|
||||
|
||||
|
||||
var userData = make(map[string]interface{})
|
||||
userData["type"] = "Administrator"
|
||||
err = WriteUserData(userID, userData) // User id, user data | (error)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
err, userData = ReadUserData(userID) // User id | (error, userData)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
} else {
|
||||
fmt.Println("ReadUserData()")
|
||||
fmt.Println("User data:", userData)
|
||||
fmt.Println("---")
|
||||
}
|
||||
|
||||
err = RemoveUser(userID)
|
||||
if err != nil {
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
// Init : databasePath = Path to authentication.json
|
||||
func Init(databasePath string, validity int) (err error) {
|
||||
database = filepath.Dir(databasePath) + string(os.PathSeparator) + databaseFile
|
||||
@@ -457,7 +372,7 @@ func CheckTheValidityOfTheTokenFromHTTPHeader(w http.ResponseWriter, r *http.Req
|
||||
// Framework tools
|
||||
|
||||
func checkInit() (err error) {
|
||||
if initAuthentication == false {
|
||||
if !initAuthentication {
|
||||
err = createError(000)
|
||||
}
|
||||
|
||||
@@ -472,7 +387,7 @@ func saveDatabase(tmpMap any) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(database, []byte(jsonString), 0600)
|
||||
err = os.WriteFile(database, []byte(jsonString), 0600)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -481,7 +396,7 @@ func saveDatabase(tmpMap any) (err error) {
|
||||
}
|
||||
|
||||
func loadDatabase() (err error) {
|
||||
jsonString, err := ioutil.ReadFile(database)
|
||||
jsonString, err := os.ReadFile(database)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -587,14 +502,6 @@ loopToken:
|
||||
return
|
||||
}
|
||||
|
||||
func mapToJSON(tmpMap any) string {
|
||||
jsonString, err := json.MarshalIndent(tmpMap, "", " ")
|
||||
if err != nil {
|
||||
return "{}"
|
||||
}
|
||||
return string(jsonString)
|
||||
}
|
||||
|
||||
// SetCookieToken : set cookie
|
||||
func SetCookieToken(w http.ResponseWriter, token string) http.ResponseWriter {
|
||||
expiration := time.Now().Add(time.Minute * time.Duration(tokenValidity))
|
||||
|
||||
+121
-122
@@ -1,178 +1,177 @@
|
||||
package imgcache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Cache : Cache strcut
|
||||
type Cache struct {
|
||||
path string
|
||||
cacheURL string
|
||||
caching bool
|
||||
images map[string]string
|
||||
Queue []string
|
||||
Cache []string
|
||||
Image imageFunc
|
||||
sync.RWMutex
|
||||
path string
|
||||
cacheURL string
|
||||
caching bool
|
||||
images map[string]string
|
||||
Queue []string
|
||||
Cache []string
|
||||
Image imageFunc
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
type imageFunc struct {
|
||||
GetURL func(string) string
|
||||
Caching func()
|
||||
Remove func()
|
||||
GetURL func(string) string
|
||||
Caching func()
|
||||
Remove func()
|
||||
}
|
||||
|
||||
// New : New cahce
|
||||
func New(path, chacheURL string, caching bool) (c *Cache, err error) {
|
||||
|
||||
c = &Cache{}
|
||||
c = &Cache{}
|
||||
|
||||
c.images = make(map[string]string)
|
||||
c.path = path
|
||||
c.cacheURL = chacheURL
|
||||
c.caching = caching
|
||||
c.Queue = []string{}
|
||||
c.Cache = []string{}
|
||||
c.images = make(map[string]string)
|
||||
c.path = path
|
||||
c.cacheURL = chacheURL
|
||||
c.caching = caching
|
||||
c.Queue = []string{}
|
||||
c.Cache = []string{}
|
||||
|
||||
var queue []string
|
||||
var queue []string
|
||||
|
||||
c.Image.GetURL = func(src string) (cacheURL string) {
|
||||
c.Image.GetURL = func(src string) (cacheURL string) {
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
src = strings.Trim(src, "\r\n")
|
||||
src = strings.Trim(src, "\r\n")
|
||||
|
||||
if c.caching == false {
|
||||
return src
|
||||
}
|
||||
if !c.caching {
|
||||
return src
|
||||
}
|
||||
|
||||
u, err := url.Parse(src)
|
||||
if err != nil || len(filepath.Ext(u.Path)) == 0 {
|
||||
return src
|
||||
}
|
||||
u, err := url.Parse(src)
|
||||
if err != nil || len(filepath.Ext(u.Path)) == 0 {
|
||||
return src
|
||||
}
|
||||
|
||||
var filename = fmt.Sprintf("%s%s", strToMD5(src), filepath.Ext(u.Path))
|
||||
if cacheURL, ok := c.images[fmt.Sprintf("%s%s", strToMD5(src), filepath.Ext(u.Path))]; ok {
|
||||
return cacheURL
|
||||
}
|
||||
var filename = fmt.Sprintf("%s%s", strToMD5(src), filepath.Ext(u.Path))
|
||||
if cacheURL, ok := c.images[fmt.Sprintf("%s%s", strToMD5(src), filepath.Ext(u.Path))]; ok {
|
||||
return cacheURL
|
||||
}
|
||||
|
||||
if indexOfString(filename, c.Cache) == -1 {
|
||||
if indexOfString(filename, c.Cache) == -1 {
|
||||
|
||||
if indexOfString(src, c.Queue) == -1 {
|
||||
c.Queue = append(c.Queue, src)
|
||||
}
|
||||
if indexOfString(src, c.Queue) == -1 {
|
||||
c.Queue = append(c.Queue, src)
|
||||
}
|
||||
|
||||
} else {
|
||||
c.images[filename] = c.cacheURL + filename
|
||||
src = c.cacheURL + filename
|
||||
}
|
||||
} else {
|
||||
c.images[filename] = c.cacheURL + filename
|
||||
src = c.cacheURL + filename
|
||||
}
|
||||
|
||||
/*
|
||||
if _, err := os.Stat(c.path + filename); err != nil {
|
||||
//c.images[filename] = c.cacheURL + filename
|
||||
if indexOfString(src, c.Queue) == -1 {
|
||||
c.Queue = append(c.Queue, src)
|
||||
}
|
||||
} else {
|
||||
c.images[filename] = c.cacheURL + filename
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if _, err := os.Stat(c.path + filename); err != nil {
|
||||
//c.images[filename] = c.cacheURL + filename
|
||||
if indexOfString(src, c.Queue) == -1 {
|
||||
c.Queue = append(c.Queue, src)
|
||||
}
|
||||
} else {
|
||||
c.images[filename] = c.cacheURL + filename
|
||||
}
|
||||
*/
|
||||
|
||||
return src
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
c.Image.Caching = func() {
|
||||
c.Image.Caching = func() {
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
var filename string
|
||||
var filename string
|
||||
|
||||
for _, src := range c.Queue {
|
||||
for _, src := range c.Queue {
|
||||
|
||||
resp, err := http.Get(src)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
resp, err := http.Get(src)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
continue
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
continue
|
||||
}
|
||||
|
||||
filename = fmt.Sprintf("%s%s%s%s", c.path, string(os.PathSeparator), strToMD5(src), filepath.Ext(src))
|
||||
filename = fmt.Sprintf("%s%s%s%s", c.path, string(os.PathSeparator), strToMD5(src), filepath.Ext(src))
|
||||
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(file, resp.Body)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
_, err = io.Copy(file, resp.Body)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
u, err := url.Parse(src)
|
||||
if err == nil {
|
||||
c.images[fmt.Sprintf("%s%s", strToMD5(src), filepath.Ext(u.Path))] = c.cacheURL + filename
|
||||
}
|
||||
u, err := url.Parse(src)
|
||||
if err == nil {
|
||||
c.images[fmt.Sprintf("%s%s", strToMD5(src), filepath.Ext(u.Path))] = c.cacheURL + filename
|
||||
}
|
||||
|
||||
queue = append(queue, src)
|
||||
queue = append(queue, src)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for _, q := range queue {
|
||||
c.Queue = removeStringFromSlice(q, c.Queue)
|
||||
}
|
||||
for _, q := range queue {
|
||||
c.Queue = removeStringFromSlice(q, c.Queue)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
c.Image.Remove = func() {
|
||||
c.Image.Remove = func() {
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
files, err := ioutil.ReadDir(c.path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
files, err := os.ReadDir(c.path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
for _, file := range files {
|
||||
|
||||
switch c.caching {
|
||||
switch c.caching {
|
||||
|
||||
case true:
|
||||
if _, ok := c.images[file.Name()]; !ok {
|
||||
os.RemoveAll(c.path + file.Name())
|
||||
}
|
||||
case true:
|
||||
if _, ok := c.images[file.Name()]; !ok {
|
||||
os.RemoveAll(c.path + file.Name())
|
||||
}
|
||||
|
||||
case false:
|
||||
os.RemoveAll(c.path + file.Name())
|
||||
}
|
||||
case false:
|
||||
os.RemoveAll(c.path + file.Name())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(c.path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
files, err := os.ReadDir(c.path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
c.Cache = append(c.Cache, file.Name())
|
||||
}
|
||||
for _, file := range files {
|
||||
c.Cache = append(c.Cache, file.Name())
|
||||
}
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
package imgcache
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func strToMD5(str string) string {
|
||||
md5Hasher := md5.New()
|
||||
md5Hasher.Write([]byte(str))
|
||||
return hex.EncodeToString(md5Hasher.Sum(nil))
|
||||
md5Hasher := md5.New()
|
||||
md5Hasher.Write([]byte(str))
|
||||
return hex.EncodeToString(md5Hasher.Sum(nil))
|
||||
}
|
||||
|
||||
func indexOfString(str string, slice []string) int {
|
||||
|
||||
for i, v := range slice {
|
||||
if str == v {
|
||||
return i
|
||||
}
|
||||
}
|
||||
for i, v := range slice {
|
||||
if str == v {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
return -1
|
||||
}
|
||||
|
||||
func removeStringFromSlice(str string, slice []string) []string {
|
||||
|
||||
var i = indexOfString(str, slice)
|
||||
var i = indexOfString(str, slice)
|
||||
|
||||
if i != -1 {
|
||||
slice = append(slice[:i], slice[i+1:]...)
|
||||
}
|
||||
if i != -1 {
|
||||
slice = append(slice[:i], slice[i+1:]...)
|
||||
}
|
||||
|
||||
return slice
|
||||
return slice
|
||||
}
|
||||
|
||||
@@ -3,18 +3,18 @@ package m3u
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type M3UStream struct {
|
||||
GroupTitle string `json:"group-title,required"`
|
||||
Name string `json:"name,required"`
|
||||
TvgID string `json:"tvg-id,required"`
|
||||
TvgLogo string `json:"tvg-logo,required"`
|
||||
TvgName string `json:"tvg-name,required"`
|
||||
URL string `json:"url,required"`
|
||||
GroupTitle string `json:"group-title"`
|
||||
Name string `json:"name"`
|
||||
TvgID string `json:"tvg-id"`
|
||||
TvgLogo string `json:"tvg-logo"`
|
||||
TvgName string `json:"tvg-name"`
|
||||
URL string `json:"url"`
|
||||
UUIDKey string `json:"_uuid.key,omitempty"`
|
||||
UUIDValue string `json:"_uuid.value,omitempty"`
|
||||
}
|
||||
@@ -22,7 +22,7 @@ type M3UStream struct {
|
||||
func TestStream1(t *testing.T) {
|
||||
|
||||
var file = "test_list_1.m3u"
|
||||
var content, err = ioutil.ReadFile(file)
|
||||
var content, err = os.ReadFile(file)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
@@ -58,26 +58,26 @@ func checkStream(streamInterface []any) (err error) {
|
||||
err = json.Unmarshal(jsonString, &m3uStream)
|
||||
if err == nil {
|
||||
|
||||
log.Print(fmt.Sprintf("Stream: %d", i))
|
||||
log.Print(fmt.Sprintf("Name*: %s", m3uStream.Name))
|
||||
log.Print(fmt.Sprintf("URL*: %s", m3uStream.URL))
|
||||
log.Print(fmt.Sprintf("tvg-name: %s", m3uStream.TvgName))
|
||||
log.Print(fmt.Sprintf("tvg-id**: %s", m3uStream.TvgID))
|
||||
log.Print(fmt.Sprintf("tvg-logo: %s", m3uStream.TvgLogo))
|
||||
log.Print(fmt.Sprintf("group-title**: %s", m3uStream.GroupTitle))
|
||||
log.Printf("Stream: %d", i)
|
||||
log.Printf("Name*: %s", m3uStream.Name)
|
||||
log.Printf("URL*: %s", m3uStream.URL)
|
||||
log.Printf("tvg-name: %s", m3uStream.TvgName)
|
||||
log.Printf("tvg-id**: %s", m3uStream.TvgID)
|
||||
log.Printf("tvg-logo: %s", m3uStream.TvgLogo)
|
||||
log.Printf("group-title**: %s", m3uStream.GroupTitle)
|
||||
|
||||
if len(m3uStream.UUIDKey) > 0 {
|
||||
log.Print(fmt.Sprintf("UUID key***: %s", m3uStream.UUIDKey))
|
||||
log.Print(fmt.Sprintf("UUID value: %s", m3uStream.UUIDValue))
|
||||
log.Printf("UUID key***: %s", m3uStream.UUIDKey)
|
||||
log.Printf("UUID value: %s", m3uStream.UUIDValue)
|
||||
} else {
|
||||
log.Print(fmt.Sprintf("UUID key: false"))
|
||||
log.Print("UUID key: false")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Println(fmt.Sprintf("- - - - - (*: Required) | (**: Nice to have) | (***: Love it) - - - - -"))
|
||||
log.Println("- - - - - (*: Required) | (**: Nice to have) | (***: Love it) - - - - -")
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -2,7 +2,6 @@ package m3u
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"regexp"
|
||||
@@ -124,7 +123,7 @@ func MakeInterfaceFromM3U(byteStream []byte) (allChannels []any, err error) {
|
||||
if strings.Contains(strings.ToLower(key), "id") {
|
||||
|
||||
if indexOfString(value, uuids) != -1 {
|
||||
log.Println(fmt.Sprintf("Channel: %s - %s = %s ", stream["name"], key, value))
|
||||
log.Printf("Channel: %s - %s = %s ", stream["name"], key, value)
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -114,18 +114,18 @@ func filterThisStream(s any) (status bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if match == true {
|
||||
if match {
|
||||
|
||||
if len(exclude) > 0 {
|
||||
var status = checkConditions(search, exclude, "exclude")
|
||||
if status == false {
|
||||
if !status {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if len(include) > 0 {
|
||||
var status = checkConditions(search, include, "include")
|
||||
if status == false {
|
||||
if !status {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ func buildM3U(groups []string) (m3u string, err error) {
|
||||
err := json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
|
||||
if err == nil {
|
||||
|
||||
if xepgChannel.XActive == true {
|
||||
if xepgChannel.XActive {
|
||||
|
||||
if len(groups) > 0 {
|
||||
|
||||
|
||||
+1
-9
@@ -1,15 +1,12 @@
|
||||
package src
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InitMaintenance : Wartungsprozess initialisieren
|
||||
func InitMaintenance() (err error) {
|
||||
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
go maintenance()
|
||||
|
||||
return
|
||||
@@ -50,7 +47,7 @@ func maintenance() {
|
||||
ShowError(err, 000)
|
||||
}
|
||||
|
||||
if Settings.CacheImages == false && System.ImageCachingInProgress == 0 {
|
||||
if !Settings.CacheImages && System.ImageCachingInProgress == 0 {
|
||||
removeChildItems(System.Folder.ImagesCache)
|
||||
}
|
||||
|
||||
@@ -68,8 +65,3 @@ func maintenance() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func randomTime(min, max int) int {
|
||||
rand.Seed(time.Now().Unix())
|
||||
return rand.Intn(max-min) + min
|
||||
}
|
||||
|
||||
@@ -131,6 +131,9 @@ func convertToNewFilter(oldFilter []any) (newFilterMap map[int]any) {
|
||||
func setValueForUUID() (err error) {
|
||||
|
||||
xepg, err := loadJSONFileToMap(System.File.XEPG)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, c := range xepg {
|
||||
|
||||
|
||||
+18
-18
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -26,7 +26,7 @@ var plexRefreshState = struct {
|
||||
// queuePlexGuideRefresh schedules a debounced Plex DVR guide refresh.
|
||||
func queuePlexGuideRefresh(reason string) {
|
||||
|
||||
if Settings.UsePlexAPI == false {
|
||||
if !Settings.UsePlexAPI {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func queuePlexGuideRefresh(reason string) {
|
||||
plexRefreshState.reason = reason
|
||||
}
|
||||
|
||||
if plexRefreshState.scheduled == true || plexRefreshState.inProgress == true {
|
||||
if plexRefreshState.scheduled || plexRefreshState.inProgress {
|
||||
plexRefreshState.queued = true
|
||||
plexRefreshState.Unlock()
|
||||
return
|
||||
@@ -78,13 +78,13 @@ func runPlexGuideRefresh(initialDelay time.Duration) {
|
||||
plexRefreshState.inProgress = false
|
||||
nextDelay := time.Duration(0)
|
||||
|
||||
if runAgain == true && Settings.UsePlexAPI == true {
|
||||
if runAgain && Settings.UsePlexAPI {
|
||||
plexRefreshState.scheduled = true
|
||||
nextDelay = plexRefreshDelayLocked()
|
||||
}
|
||||
plexRefreshState.Unlock()
|
||||
|
||||
if runAgain == false || Settings.UsePlexAPI == false {
|
||||
if !runAgain || !Settings.UsePlexAPI {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ func plexRefreshDelayLocked() (delay time.Duration) {
|
||||
const minDelay = 2 * time.Second
|
||||
const cooldown = 20 * time.Second
|
||||
|
||||
if plexRefreshState.lastRun.IsZero() == true {
|
||||
if plexRefreshState.lastRun.IsZero() {
|
||||
return minDelay
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func plexRefreshDelayLocked() (delay time.Duration) {
|
||||
func refreshPlexGuide(reason string) (err error) {
|
||||
|
||||
baseURL, token, ready := getPlexConfig()
|
||||
if ready == false {
|
||||
if !ready {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func getPlexConfig() (baseURL, token string, ready bool) {
|
||||
baseURL = strings.TrimSpace(Settings.PlexURL)
|
||||
token = strings.TrimSpace(Settings.PlexToken)
|
||||
|
||||
if strings.HasPrefix(baseURL, "http://") == false && strings.HasPrefix(baseURL, "https://") == false && len(baseURL) > 0 {
|
||||
if !strings.HasPrefix(baseURL, "http://") && !strings.HasPrefix(baseURL, "https://") && len(baseURL) > 0 {
|
||||
baseURL = "http://" + baseURL
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ func getPlexConfig() (baseURL, token string, ready bool) {
|
||||
|
||||
if len(baseURL) == 0 || len(token) == 0 {
|
||||
|
||||
if plexRefreshState.missingConfigLogged == false {
|
||||
if !plexRefreshState.missingConfigLogged {
|
||||
showInfo("Plex API:Skipped refresh because plex.url or plex.token is empty")
|
||||
plexRefreshState.missingConfigLogged = true
|
||||
}
|
||||
@@ -221,14 +221,14 @@ func discoverPlexDVRs(baseURL, token string) (dvrs []map[string]any, err error)
|
||||
}
|
||||
|
||||
mediaContainer, ok := payload["MediaContainer"].(map[string]any)
|
||||
if ok == false {
|
||||
if !ok {
|
||||
err = errors.New("Plex API response missing MediaContainer")
|
||||
return
|
||||
}
|
||||
|
||||
for _, key := range []string{"Dvr", "DVR", "Directory", "Metadata"} {
|
||||
if raw, found := mediaContainer[key]; found == true {
|
||||
if list, ok := raw.([]any); ok == true {
|
||||
if raw, found := mediaContainer[key]; found {
|
||||
if list, ok := raw.([]any); ok {
|
||||
dvrs = convertToPlexMapSlice(list)
|
||||
if len(dvrs) > 0 {
|
||||
return
|
||||
@@ -246,7 +246,7 @@ func convertToPlexMapSlice(list []any) (dvrs []map[string]any) {
|
||||
dvrs = make([]map[string]any, 0, len(list))
|
||||
|
||||
for _, item := range list {
|
||||
if dvr, ok := item.(map[string]any); ok == true {
|
||||
if dvr, ok := item.(map[string]any); ok {
|
||||
dvrs = append(dvrs, dvr)
|
||||
}
|
||||
}
|
||||
@@ -264,10 +264,10 @@ func getPlexReloadEndpoints(dvr map[string]any) (endpoints []string) {
|
||||
if len(endpoint) == 0 {
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(endpoint, "/") == false {
|
||||
if !strings.HasPrefix(endpoint, "/") {
|
||||
endpoint = "/" + endpoint
|
||||
}
|
||||
if added[endpoint] == true {
|
||||
if added[endpoint] {
|
||||
return
|
||||
}
|
||||
added[endpoint] = true
|
||||
@@ -275,7 +275,7 @@ func getPlexReloadEndpoints(dvr map[string]any) (endpoints []string) {
|
||||
}
|
||||
|
||||
if key := getPlexMapString(dvr, "key"); len(key) > 0 {
|
||||
if strings.HasPrefix(key, "/") == true {
|
||||
if strings.HasPrefix(key, "/") {
|
||||
add(strings.TrimRight(key, "/") + "/reloadGuide")
|
||||
} else {
|
||||
add("/livetv/dvrs/" + url.PathEscape(key) + "/reloadGuide")
|
||||
@@ -294,7 +294,7 @@ func getPlexReloadEndpoints(dvr map[string]any) (endpoints []string) {
|
||||
func getPlexMapString(data map[string]any, field string) string {
|
||||
|
||||
for key, value := range data {
|
||||
if strings.EqualFold(key, field) == false {
|
||||
if !strings.EqualFold(key, field) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func doPlexRequest(method, baseURL, endpoint, token string) (status int, body []
|
||||
defer resp.Body.Close()
|
||||
|
||||
status = resp.StatusCode
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@ package src
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -152,7 +152,7 @@ func getProviderData(fileType, fileID string) (err error) {
|
||||
}
|
||||
|
||||
// Wenn eine ID vorhanden ist und nicht mit der aus der Datanbank übereinstimmt, wird die Aktualisierung übersprungen (goto)
|
||||
if len(fileID) > 0 && newProvider == false {
|
||||
if len(fileID) > 0 && !newProvider {
|
||||
if dataID != fileID {
|
||||
goto Done
|
||||
}
|
||||
@@ -204,7 +204,7 @@ func getProviderData(fileType, fileID string) (err error) {
|
||||
ShowError(err, 000)
|
||||
var downloadErr = err
|
||||
|
||||
if newProvider == false {
|
||||
if !newProvider {
|
||||
|
||||
// Prüfen ob ältere Datei vorhanden ist
|
||||
var file = System.Folder.Data + dataID + fileExtension
|
||||
@@ -236,7 +236,7 @@ func getProviderData(fileType, fileID string) (err error) {
|
||||
}
|
||||
|
||||
// Berechnen der Fehlerquote
|
||||
if newProvider == false {
|
||||
if !newProvider {
|
||||
|
||||
if value, ok := dataMap[dataID].(map[string]any); ok {
|
||||
|
||||
@@ -322,7 +322,7 @@ func downloadFileFromServer(providerURL string) (filename string, body []byte, e
|
||||
|
||||
}
|
||||
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+58
-64
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func showInfo(str string) {
|
||||
|
||||
if System.Flag.Info == true {
|
||||
if System.Flag.Info {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ func showInfo(str string) {
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func showDebug(str string, level int) {
|
||||
@@ -73,7 +72,6 @@ func showDebug(str string, level int) {
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func showHighlight(str string) {
|
||||
@@ -105,7 +103,6 @@ func showHighlight(str string) {
|
||||
|
||||
addNotification(notification)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func showWarning(errCode int) {
|
||||
@@ -121,7 +118,6 @@ func showWarning(errCode int) {
|
||||
WebScreenLog.Warnings++
|
||||
mutex.Unlock()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShowError : Zeigt die Fehlermeldungen in der Konsole
|
||||
@@ -139,7 +135,6 @@ func ShowError(err error, errCode int) {
|
||||
WebScreenLog.Errors++
|
||||
mutex.Unlock()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func printLogOnScreen(logMsg string, logType string) {
|
||||
@@ -211,7 +206,6 @@ func logCleanUp() {
|
||||
|
||||
WebScreenLog.Log = logs
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Fehlercodes
|
||||
@@ -224,79 +218,79 @@ func getErrMsg(errCode int) (errMsg string) {
|
||||
|
||||
// Errors
|
||||
case 1001:
|
||||
errMsg = fmt.Sprintf("Web server could not be started.")
|
||||
errMsg = "Web server could not be started."
|
||||
case 1002:
|
||||
errMsg = fmt.Sprintf("No local IP address found.")
|
||||
errMsg = "No local IP address found."
|
||||
case 1003:
|
||||
errMsg = fmt.Sprintf("Invalid xml")
|
||||
errMsg = "Invalid xml"
|
||||
case 1004:
|
||||
errMsg = fmt.Sprintf("File not found")
|
||||
errMsg = "File not found"
|
||||
case 1005:
|
||||
errMsg = fmt.Sprintf("Invalid M3U file, an extended M3U file is required.")
|
||||
errMsg = "Invalid M3U file, an extended M3U file is required."
|
||||
case 1006:
|
||||
errMsg = fmt.Sprintf("No playlist!")
|
||||
errMsg = "No playlist!"
|
||||
case 1007:
|
||||
errMsg = fmt.Sprintf("XEPG requires an XMLTV file.")
|
||||
errMsg = "XEPG requires an XMLTV file."
|
||||
case 1010:
|
||||
errMsg = fmt.Sprintf("Invalid file compression")
|
||||
errMsg = "Invalid file compression"
|
||||
case 1011:
|
||||
errMsg = fmt.Sprintf("Data is corrupt or unavailable, %s now uses an older version of this file", System.Name)
|
||||
case 1012:
|
||||
errMsg = fmt.Sprintf("Invalid formatting of the time")
|
||||
errMsg = "Invalid formatting of the time"
|
||||
case 1013:
|
||||
errMsg = fmt.Sprintf("Invalid settings file (settings.json), file must be at least version %s", System.Compatibility)
|
||||
case 1014:
|
||||
errMsg = fmt.Sprintf("Invalid filter rule")
|
||||
errMsg = "Invalid filter rule"
|
||||
|
||||
case 1020:
|
||||
errMsg = fmt.Sprintf("Data could not be saved, invalid keyword")
|
||||
errMsg = "Data could not be saved, invalid keyword"
|
||||
|
||||
// Datenbank Update
|
||||
case 1030:
|
||||
errMsg = fmt.Sprintf("Invalid settings file (%s)", System.File.Settings)
|
||||
case 1031:
|
||||
errMsg = fmt.Sprintf("Database error. The database version of your settings is not compatible with this version.")
|
||||
errMsg = "Database error. The database version of your settings is not compatible with this version."
|
||||
|
||||
// M3U Parser
|
||||
case 1050:
|
||||
errMsg = fmt.Sprintf("Invalid duration specification in the M3U8 playlist.")
|
||||
errMsg = "Invalid duration specification in the M3U8 playlist."
|
||||
|
||||
case 1060:
|
||||
errMsg = fmt.Sprintf("Invalid characters found in the tvg parameters, streams with invalid parameters were skipped.")
|
||||
errMsg = "Invalid characters found in the tvg parameters, streams with invalid parameters were skipped."
|
||||
|
||||
// Dateisystem
|
||||
case 1070:
|
||||
errMsg = fmt.Sprintf("Folder could not be created.")
|
||||
errMsg = "Folder could not be created."
|
||||
case 1071:
|
||||
errMsg = fmt.Sprintf("File could not be created")
|
||||
errMsg = "File could not be created"
|
||||
case 1072:
|
||||
errMsg = fmt.Sprintf("File not found")
|
||||
errMsg = "File not found"
|
||||
|
||||
// Backup
|
||||
case 1090:
|
||||
errMsg = fmt.Sprintf("Automatic backup failed")
|
||||
errMsg = "Automatic backup failed"
|
||||
|
||||
// Websockets
|
||||
case 1100:
|
||||
errMsg = fmt.Sprintf("WebUI build error")
|
||||
errMsg = "WebUI build error"
|
||||
case 1101:
|
||||
errMsg = fmt.Sprintf("WebUI request error")
|
||||
errMsg = "WebUI request error"
|
||||
case 1102:
|
||||
errMsg = fmt.Sprintf("WebUI response error")
|
||||
errMsg = "WebUI response error"
|
||||
|
||||
// PMS Guide Numbers
|
||||
case 1200:
|
||||
errMsg = fmt.Sprintf("Could not create file")
|
||||
errMsg = "Could not create file"
|
||||
|
||||
// Stream URL Fehler
|
||||
case 1201:
|
||||
errMsg = fmt.Sprintf("Plex stream error")
|
||||
errMsg = "Plex stream error"
|
||||
case 1202:
|
||||
errMsg = fmt.Sprintf("Steaming URL could not be found in any playlist")
|
||||
errMsg = "Steaming URL could not be found in any playlist"
|
||||
case 1203:
|
||||
errMsg = fmt.Sprintf("Steaming URL could not be found in any playlist")
|
||||
errMsg = "Steaming URL could not be found in any playlist"
|
||||
case 1204:
|
||||
errMsg = fmt.Sprintf("Streaming was stopped by third party transcoder (FFmpeg / VLC)")
|
||||
errMsg = "Streaming was stopped by third party transcoder (FFmpeg / VLC)"
|
||||
|
||||
// Warnings
|
||||
case 2000:
|
||||
@@ -304,86 +298,86 @@ func getErrMsg(errCode int) (errMsg string) {
|
||||
case 2001:
|
||||
errMsg = fmt.Sprintf("%s has loaded more than %d streams. Use the filter to reduce the number of streams.", System.Name, System.UnfilteredChannelLimit)
|
||||
case 2002:
|
||||
errMsg = fmt.Sprintf("PMS can not play m3u8 streams")
|
||||
errMsg = "PMS can not play m3u8 streams"
|
||||
case 2003:
|
||||
errMsg = fmt.Sprintf("PMS can not play streams over RTSP.")
|
||||
errMsg = "PMS can not play streams over RTSP."
|
||||
case 2004:
|
||||
errMsg = fmt.Sprintf("Buffer is disabled for this stream.")
|
||||
errMsg = "Buffer is disabled for this stream."
|
||||
case 2005:
|
||||
errMsg = fmt.Sprintf("There are no channels mapped, use the mapping menu to assign EPG data to the channels.")
|
||||
errMsg = "There are no channels mapped, use the mapping menu to assign EPG data to the channels."
|
||||
case 2010:
|
||||
errMsg = fmt.Sprintf("No valid streaming URL")
|
||||
errMsg = "No valid streaming URL"
|
||||
case 2020:
|
||||
errMsg = fmt.Sprintf("FFmpeg binary was not found. Check the FFmpeg binary path in the xTeVe settings.")
|
||||
errMsg = "FFmpeg binary was not found. Check the FFmpeg binary path in the xTeVe settings."
|
||||
case 2021:
|
||||
errMsg = fmt.Sprintf("VLC binary was not found. Check the VLC path binary in the xTeVe settings.")
|
||||
errMsg = "VLC binary was not found. Check the VLC path binary in the xTeVe settings."
|
||||
|
||||
case 2099:
|
||||
errMsg = fmt.Sprintf("Updates have been disabled by the developer")
|
||||
errMsg = "Updates have been disabled by the developer"
|
||||
|
||||
// Tuner
|
||||
case 2105:
|
||||
errMsg = "The number of tuners has changed, you have to delete " + System.Name + " in Plex / Emby HDHR and set it up again."
|
||||
case 2106:
|
||||
errMsg = fmt.Sprintf("This function is only available with XEPG as EPG source")
|
||||
errMsg = "This function is only available with XEPG as EPG source"
|
||||
|
||||
case 2110:
|
||||
errMsg = fmt.Sprintf("Don't run this as Root!")
|
||||
errMsg = "Don't run this as Root!"
|
||||
|
||||
case 2300:
|
||||
errMsg = fmt.Sprintf("No channel logo found in the XMLTV or M3U file.")
|
||||
errMsg = "No channel logo found in the XMLTV or M3U file."
|
||||
case 2301:
|
||||
errMsg = fmt.Sprintf("XMLTV file no longer available, channel has been deactivated.")
|
||||
errMsg = "XMLTV file no longer available, channel has been deactivated."
|
||||
case 2302:
|
||||
errMsg = fmt.Sprintf("Channel ID in the XMLTV file has changed. Channel has been deactivated.")
|
||||
errMsg = "Channel ID in the XMLTV file has changed. Channel has been deactivated."
|
||||
|
||||
// Benutzerauthentifizierung
|
||||
case 3000:
|
||||
errMsg = fmt.Sprintf("Database for user authentication could not be initialized.")
|
||||
errMsg = "Database for user authentication could not be initialized."
|
||||
case 3001:
|
||||
errMsg = fmt.Sprintf("The user has no authorization to load the channels.")
|
||||
errMsg = "The user has no authorization to load the channels."
|
||||
|
||||
// Buffer
|
||||
case 4000:
|
||||
errMsg = fmt.Sprintf("Connection to streaming source was interrupted.")
|
||||
errMsg = "Connection to streaming source was interrupted."
|
||||
case 4001:
|
||||
errMsg = fmt.Sprintf("Too many errors connecting to the provider. Streaming is canceled.")
|
||||
errMsg = "Too many errors connecting to the provider. Streaming is canceled."
|
||||
case 4002:
|
||||
errMsg = fmt.Sprintf("New URL for the redirect to the streaming server is missing")
|
||||
errMsg = "New URL for the redirect to the streaming server is missing"
|
||||
case 4003:
|
||||
errMsg = fmt.Sprintf("Server sends an incompatible content-type")
|
||||
errMsg = "Server sends an incompatible content-type"
|
||||
case 4004:
|
||||
errMsg = fmt.Sprintf("This error message comes from the provider")
|
||||
errMsg = "This error message comes from the provider"
|
||||
case 4005:
|
||||
errMsg = fmt.Sprintf("Temporary buffer files could not be deleted")
|
||||
errMsg = "Temporary buffer files could not be deleted"
|
||||
case 4006:
|
||||
errMsg = fmt.Sprintf("Server connection timeout")
|
||||
errMsg = "Server connection timeout"
|
||||
|
||||
// Buffer (M3U8)
|
||||
case 4050:
|
||||
errMsg = fmt.Sprintf("Invalid M3U8 file")
|
||||
errMsg = "Invalid M3U8 file"
|
||||
case 4051:
|
||||
errMsg = fmt.Sprintf("#EXTM3U header is missing")
|
||||
errMsg = "#EXTM3U header is missing"
|
||||
|
||||
// Caching
|
||||
case 4100:
|
||||
errMsg = fmt.Sprintf("Unknown content type for downloaded image")
|
||||
errMsg = "Unknown content type for downloaded image"
|
||||
case 4101:
|
||||
errMsg = fmt.Sprintf("Invalid URL, original URL is used for this image")
|
||||
errMsg = "Invalid URL, original URL is used for this image"
|
||||
|
||||
// API
|
||||
case 5000:
|
||||
errMsg = fmt.Sprintf("Invalid API command")
|
||||
errMsg = "Invalid API command"
|
||||
|
||||
// Update Server
|
||||
case 6001:
|
||||
errMsg = fmt.Sprintf("Ivalid key")
|
||||
errMsg = "Ivalid key"
|
||||
case 6002:
|
||||
errMsg = fmt.Sprintf("Update failed")
|
||||
errMsg = "Update failed"
|
||||
case 6003:
|
||||
errMsg = fmt.Sprintf("Update server not available")
|
||||
errMsg = "Update server not available"
|
||||
case 6004:
|
||||
errMsg = fmt.Sprintf("xTeVe update available")
|
||||
errMsg = "xTeVe update available"
|
||||
|
||||
default:
|
||||
errMsg = fmt.Sprintf("Unknown error / warning (%d)", errCode)
|
||||
|
||||
+47
-47
@@ -1,72 +1,72 @@
|
||||
package src
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/koron/go-ssdp"
|
||||
"github.com/koron/go-ssdp"
|
||||
)
|
||||
|
||||
// SSDP : SSPD / DLNA Server
|
||||
func SSDP() (err error) {
|
||||
|
||||
if Settings.SSDP == false || System.Flag.Info == true {
|
||||
return
|
||||
}
|
||||
if !Settings.SSDP || System.Flag.Info {
|
||||
return
|
||||
}
|
||||
|
||||
showInfo(fmt.Sprintf("SSDP / DLNA:%t", Settings.SSDP))
|
||||
showInfo(fmt.Sprintf("SSDP / DLNA:%t", Settings.SSDP))
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
|
||||
ad, err := ssdp.Advertise(
|
||||
fmt.Sprintf("upnp:rootdevice"), // send as "ST"
|
||||
fmt.Sprintf("uuid:%s::upnp:rootdevice", System.DeviceID), // send as "USN"
|
||||
fmt.Sprintf("%s/device.xml", System.URLBase), // send as "LOCATION"
|
||||
System.AppName, // send as "SERVER"
|
||||
1800) // send as "maxAge" in "CACHE-CONTROL"
|
||||
ad, err := ssdp.Advertise(
|
||||
"upnp:rootdevice", // send as "ST"
|
||||
fmt.Sprintf("uuid:%s::upnp:rootdevice", System.DeviceID), // send as "USN"
|
||||
fmt.Sprintf("%s/device.xml", System.URLBase), // send as "LOCATION"
|
||||
System.AppName, // send as "SERVER"
|
||||
1800) // send as "maxAge" in "CACHE-CONTROL"
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Debug SSDP
|
||||
if System.Flag.Debug == 3 {
|
||||
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
|
||||
}
|
||||
// Debug SSDP
|
||||
if System.Flag.Debug == 3 {
|
||||
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
|
||||
}
|
||||
|
||||
go func(adv *ssdp.Advertiser) {
|
||||
go func(adv *ssdp.Advertiser) {
|
||||
|
||||
aliveTick := time.Tick(300 * time.Second)
|
||||
aliveTick := time.Tick(300 * time.Second)
|
||||
|
||||
loop:
|
||||
for {
|
||||
loop:
|
||||
for {
|
||||
|
||||
select {
|
||||
select {
|
||||
|
||||
case <-aliveTick:
|
||||
err = adv.Alive()
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
adv.Bye()
|
||||
adv.Close()
|
||||
break loop
|
||||
}
|
||||
case <-aliveTick:
|
||||
err = adv.Alive()
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
adv.Bye()
|
||||
adv.Close()
|
||||
break loop
|
||||
}
|
||||
|
||||
case <-quit:
|
||||
adv.Bye()
|
||||
adv.Close()
|
||||
os.Exit(0)
|
||||
break loop
|
||||
case <-quit:
|
||||
adv.Bye()
|
||||
adv.Close()
|
||||
os.Exit(0)
|
||||
break loop
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}(ad)
|
||||
}(ad)
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
@@ -108,147 +108,3 @@ type BandwidthCalculation struct {
|
||||
Stop time.Time
|
||||
TimeDiff float64
|
||||
}
|
||||
|
||||
/*
|
||||
var args = "-hide_banner -loglevel panic -re -i " + url + " -codec copy -f mpegts pipe:1"
|
||||
//var args = "-re -i " + url + " -codec copy -f mpegts pipe:1"
|
||||
cmd := exec.Command("/usr/local/bin/ffmpeg", strings.Split(args, " ")...)
|
||||
|
||||
//run := exec.Command("/usr/local/bin/ffmpeg", "-hide_banner", "-loglevel", "panic", "-re", "-i", url, "-codec", "copy", "-f", "mpegts", "pipe:1")
|
||||
//run := exec.Command("/usr/local/bin/ffmpeg", "-re", "-i", url, "-codec", "copy", "-f", "mpegts", "pipe:1")
|
||||
|
||||
stderr, _ := cmd.StderrPipe()
|
||||
cmd.Start()
|
||||
|
||||
scanner := bufio.NewScanner(stderr)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
for scanner.Scan() {
|
||||
m := scanner.Text()
|
||||
fmt.Println(m)
|
||||
}
|
||||
cmd.Wait()
|
||||
|
||||
os.Exit(0)
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
ffmpegOut, _ := run.StderrPipe()
|
||||
//run.Start()
|
||||
|
||||
scanner = bufio.NewScanner(ffmpegOut)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
for scanner.Scan() {
|
||||
m := scanner.Text()
|
||||
fmt.Println(m)
|
||||
}
|
||||
|
||||
ffmpegOut, err = run.StdoutPipe()
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
|
||||
stderr, stderrErr := run.StderrPipe()
|
||||
if stderrErr != nil {
|
||||
fmt.Println(stderrErr)
|
||||
}
|
||||
|
||||
_ = stderr
|
||||
|
||||
if startErr := run.Start(); startErr != nil {
|
||||
fmt.Println(startErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
n, err := ffmpegOut.Read(buffer)
|
||||
_ = n
|
||||
_ = stream
|
||||
_ = fileSize
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
defer bufferFile.Close()
|
||||
|
||||
scanner = bufio.NewScanner(ffmpegOut)
|
||||
|
||||
for scanner.Scan() {
|
||||
//fmt.Printf("%s\n", scanner.Text())
|
||||
//fmt.Println(scanner)
|
||||
thisLine := scanner.Text()
|
||||
line := make([]byte, len(thisLine))
|
||||
|
||||
buffer = append(buffer, line...)
|
||||
|
||||
fmt.Println(len(buffer))
|
||||
|
||||
if len(buffer) > tmpFileSize {
|
||||
|
||||
if _, err := bufferFile.Write(buffer[:]); err != nil {
|
||||
|
||||
ShowError(err, 0)
|
||||
addErrorToStream(err)
|
||||
run.Process.Kill()
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
buffer = make([]byte, 1024*Settings.BufferSize*2)
|
||||
|
||||
debug = fmt.Sprintf("Buffer Status:Done (%s)", tmpFile)
|
||||
showDebug(debug, 2)
|
||||
|
||||
bufferFile.Close()
|
||||
|
||||
stream.Status = true
|
||||
playlist.Streams[streamID] = stream
|
||||
BufferInformation.Store(playlistID, playlist)
|
||||
|
||||
tmpSegment++
|
||||
|
||||
tmpFile = fmt.Sprintf("%s%d.ts", tmpFolder, tmpSegment)
|
||||
|
||||
if clientConnection(stream) == false {
|
||||
|
||||
bufferFile.Close()
|
||||
run.Process.Kill()
|
||||
|
||||
err = os.RemoveAll(stream.Folder)
|
||||
if err != nil {
|
||||
ShowError(err, 4005)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
bufferFile, err = os.Create(tmpFile)
|
||||
if err != nil {
|
||||
addErrorToStream(err)
|
||||
run.Process.Kill()
|
||||
return
|
||||
}
|
||||
|
||||
fileSize = 0
|
||||
|
||||
if n == 0 {
|
||||
bufferFile.Close()
|
||||
run.Process.Kill()
|
||||
break
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
+53
-54
@@ -155,81 +155,81 @@ type Filter struct {
|
||||
|
||||
// XEPGChannelStruct : XEPG Struktur
|
||||
type XEPGChannelStruct struct {
|
||||
FileM3UID string `json:"_file.m3u.id,required"`
|
||||
FileM3UName string `json:"_file.m3u.name,required"`
|
||||
FileM3UPath string `json:"_file.m3u.path,required"`
|
||||
GroupTitle string `json:"group-title,required"`
|
||||
Name string `json:"name,required"`
|
||||
TvgID string `json:"tvg-id,required"`
|
||||
TvgLogo string `json:"tvg-logo,required"`
|
||||
TvgName string `json:"tvg-name,required"`
|
||||
URL string `json:"url,required"`
|
||||
UUIDKey string `json:"_uuid.key,required"`
|
||||
FileM3UID string `json:"_file.m3u.id"`
|
||||
FileM3UName string `json:"_file.m3u.name"`
|
||||
FileM3UPath string `json:"_file.m3u.path"`
|
||||
GroupTitle string `json:"group-title"`
|
||||
Name string `json:"name"`
|
||||
TvgID string `json:"tvg-id"`
|
||||
TvgLogo string `json:"tvg-logo"`
|
||||
TvgName string `json:"tvg-name"`
|
||||
URL string `json:"url"`
|
||||
UUIDKey string `json:"_uuid.key"`
|
||||
UUIDValue string `json:"_uuid.value,omitempty"`
|
||||
Values string `json:"_values,required"`
|
||||
XActive bool `json:"x-active,required"`
|
||||
XCategory string `json:"x-category,required"`
|
||||
XChannelID string `json:"x-channelID,required"`
|
||||
XEPG string `json:"x-epg,required"`
|
||||
XGroupTitle string `json:"x-group-title,required"`
|
||||
XMapping string `json:"x-mapping,required"`
|
||||
XmltvFile string `json:"x-xmltv-file,required"`
|
||||
XName string `json:"x-name,required"`
|
||||
XUpdateChannelIcon bool `json:"x-update-channel-icon,required"`
|
||||
XUpdateChannelName bool `json:"x-update-channel-name,required"`
|
||||
XDescription string `json:"x-description,required"`
|
||||
Values string `json:"_values"`
|
||||
XActive bool `json:"x-active"`
|
||||
XCategory string `json:"x-category"`
|
||||
XChannelID string `json:"x-channelID"`
|
||||
XEPG string `json:"x-epg"`
|
||||
XGroupTitle string `json:"x-group-title"`
|
||||
XMapping string `json:"x-mapping"`
|
||||
XmltvFile string `json:"x-xmltv-file"`
|
||||
XName string `json:"x-name"`
|
||||
XUpdateChannelIcon bool `json:"x-update-channel-icon"`
|
||||
XUpdateChannelName bool `json:"x-update-channel-name"`
|
||||
XDescription string `json:"x-description"`
|
||||
}
|
||||
|
||||
// M3UChannelStructXEPG : M3U Struktur für XEPG
|
||||
type M3UChannelStructXEPG struct {
|
||||
FileM3UID string `json:"_file.m3u.id,required"`
|
||||
FileM3UName string `json:"_file.m3u.name,required"`
|
||||
FileM3UPath string `json:"_file.m3u.path,required"`
|
||||
GroupTitle string `json:"group-title,required"`
|
||||
Name string `json:"name,required"`
|
||||
TvgID string `json:"tvg-id,required"`
|
||||
TvgLogo string `json:"tvg-logo,required"`
|
||||
TvgName string `json:"tvg-name,required"`
|
||||
URL string `json:"url,required"`
|
||||
UUIDKey string `json:"_uuid.key,required"`
|
||||
UUIDValue string `json:"_uuid.value,required"`
|
||||
Values string `json:"_values,required"`
|
||||
FileM3UID string `json:"_file.m3u.id"`
|
||||
FileM3UName string `json:"_file.m3u.name"`
|
||||
FileM3UPath string `json:"_file.m3u.path"`
|
||||
GroupTitle string `json:"group-title"`
|
||||
Name string `json:"name"`
|
||||
TvgID string `json:"tvg-id"`
|
||||
TvgLogo string `json:"tvg-logo"`
|
||||
TvgName string `json:"tvg-name"`
|
||||
URL string `json:"url"`
|
||||
UUIDKey string `json:"_uuid.key"`
|
||||
UUIDValue string `json:"_uuid.value"`
|
||||
Values string `json:"_values"`
|
||||
}
|
||||
|
||||
// FilterStruct : Filter Struktur
|
||||
type FilterStruct struct {
|
||||
Active bool `json:"active,required"`
|
||||
CaseSensitive bool `json:"caseSensitive,required"`
|
||||
Description string `json:"description,required"`
|
||||
Exclude string `json:"exclude,required"`
|
||||
Filter string `json:"filter,required"`
|
||||
Include string `json:"include,required"`
|
||||
Name string `json:"name,required"`
|
||||
Active bool `json:"active"`
|
||||
CaseSensitive bool `json:"caseSensitive"`
|
||||
Description string `json:"description"`
|
||||
Exclude string `json:"exclude"`
|
||||
Filter string `json:"filter"`
|
||||
Include string `json:"include"`
|
||||
Name string `json:"name"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Type string `json:"type,required"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// StreamingURLS : Informationen zu allen streaming URL's
|
||||
type StreamingURLS struct {
|
||||
Streams map[string]StreamInfo `json:"channels,required"`
|
||||
Streams map[string]StreamInfo `json:"channels"`
|
||||
}
|
||||
|
||||
// StreamInfo : Informationen zum Kanal für die streaming URL
|
||||
type StreamInfo struct {
|
||||
ChannelNumber string `json:"channelNumber,required"`
|
||||
Name string `json:"name,required"`
|
||||
PlaylistID string `json:"playlistID,required"`
|
||||
URL string `json:"url,required"`
|
||||
URLid string `json:"urlID,required"`
|
||||
ChannelNumber string `json:"channelNumber"`
|
||||
Name string `json:"name"`
|
||||
PlaylistID string `json:"playlistID"`
|
||||
URL string `json:"url"`
|
||||
URLid string `json:"urlID"`
|
||||
}
|
||||
|
||||
// Notification : Notifikationen im Webinterface
|
||||
type Notification struct {
|
||||
Headline string `json:"headline,required"`
|
||||
Message string `json:"message,required"`
|
||||
New bool `json:"new,required"`
|
||||
Time string `json:"time,required"`
|
||||
Type string `json:"type,required"`
|
||||
Headline string `json:"headline"`
|
||||
Message string `json:"message"`
|
||||
New bool `json:"new"`
|
||||
Time string `json:"time"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// SettingsStruct : Inhalt der settings.json
|
||||
@@ -283,4 +283,3 @@ type SettingsStruct struct {
|
||||
XepgReplaceMissingImages bool `json:"xepg.replace.missing.images"`
|
||||
WizardCompleted bool `json:"wizard.completed"`
|
||||
}
|
||||
|
||||
|
||||
+20
-20
@@ -3,7 +3,7 @@ package src
|
||||
// RequestStruct : Anfragen über die Websocket Schnittstelle
|
||||
type RequestStruct struct {
|
||||
// Befehle an xTeVe
|
||||
Cmd string `json:"cmd,required"`
|
||||
Cmd string `json:"cmd"`
|
||||
|
||||
// Benutzer
|
||||
DeleteUser bool `json:"deleteUser,omitempty"`
|
||||
@@ -79,46 +79,46 @@ type ResponseStruct struct {
|
||||
DVR string `json:"DVR"`
|
||||
EpgSource string `json:"epgSource"`
|
||||
Errors int `json:"errors"`
|
||||
M3U string `json:"m3u-url,required"`
|
||||
M3U string `json:"m3u-url"`
|
||||
OS string `json:"os"`
|
||||
Streams string `json:"streams"`
|
||||
UUID string `json:"uuid"`
|
||||
Version string `json:"version"`
|
||||
Warnings int `json:"warnings"`
|
||||
XEPGCount int64 `json:"xepg"`
|
||||
XML string `json:"xepg-url,required"`
|
||||
XML string `json:"xepg-url"`
|
||||
} `json:"clientInfo"`
|
||||
|
||||
Data struct {
|
||||
Playlist struct {
|
||||
M3U struct {
|
||||
Groups struct {
|
||||
Text []string `json:"text,required"`
|
||||
Value []string `json:"value,required"`
|
||||
} `json:"groups,required"`
|
||||
} `json:"m3u,required"`
|
||||
} `json:"playlist,required"`
|
||||
Text []string `json:"text"`
|
||||
Value []string `json:"value"`
|
||||
} `json:"groups"`
|
||||
} `json:"m3u"`
|
||||
} `json:"playlist"`
|
||||
|
||||
StreamPreviewUI struct {
|
||||
Active []string `json:"activeStreams,required"`
|
||||
Inactive []string `json:"inactiveStreams,required"`
|
||||
Active []string `json:"activeStreams"`
|
||||
Inactive []string `json:"inactiveStreams"`
|
||||
}
|
||||
} `json:"data,required"`
|
||||
} `json:"data"`
|
||||
|
||||
Alert string `json:"alert,omitempty"`
|
||||
ConfigurationWizard bool `json:"configurationWizard,required"`
|
||||
ConfigurationWizard bool `json:"configurationWizard"`
|
||||
Error string `json:"err,omitempty"`
|
||||
Log WebScreenLogStruct `json:"log,required"`
|
||||
Log WebScreenLogStruct `json:"log"`
|
||||
LogoURL string `json:"logoURL,omitempty"`
|
||||
OpenLink string `json:"openLink,omitempty"`
|
||||
OpenMenu string `json:"openMenu,omitempty"`
|
||||
Reload bool `json:"reload,omitempty"`
|
||||
Settings SettingsStruct `json:"settings,required"`
|
||||
Status bool `json:"status,required"`
|
||||
Settings SettingsStruct `json:"settings"`
|
||||
Status bool `json:"status"`
|
||||
Token string `json:"token,omitempty"`
|
||||
Users map[string]any `json:"users,omitempty"`
|
||||
Wizard int `json:"wizard,omitempty"`
|
||||
XEPG map[string]any `json:"xepg,required"`
|
||||
XEPG map[string]any `json:"xepg"`
|
||||
|
||||
Notification map[string]Notification `json:"notification,omitempty"`
|
||||
}
|
||||
@@ -135,7 +135,7 @@ type APIRequestStruct struct {
|
||||
type APIResponseStruct struct {
|
||||
EpgSource string `json:"epg.source,omitempty"`
|
||||
Error string `json:"err,omitempty"`
|
||||
Status bool `json:"status,required"`
|
||||
Status bool `json:"status"`
|
||||
StreamsActive int64 `json:"streams.active,omitempty"`
|
||||
StreamsAll int64 `json:"streams.all,omitempty"`
|
||||
StreamsXepg int64 `json:"streams.xepg,omitempty"`
|
||||
@@ -149,7 +149,7 @@ type APIResponseStruct struct {
|
||||
|
||||
// WebScreenLogStruct : Logs werden im RAM gespeichert und für das Webinterface bereitgestellt
|
||||
type WebScreenLogStruct struct {
|
||||
Errors int `json:"errors,required"`
|
||||
Log []string `json:"log,required"`
|
||||
Warnings int `json:"warnings,required"`
|
||||
Errors int `json:"errors"`
|
||||
Log []string `json:"log"`
|
||||
Warnings int `json:"warnings"`
|
||||
}
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ type SubTitle struct {
|
||||
Value string `xml:",chardata"`
|
||||
}
|
||||
|
||||
//Desc : Programmbeschreibung
|
||||
// Desc : Programmbeschreibung
|
||||
type Desc struct {
|
||||
Lang string `xml:"lang,attr"`
|
||||
Value string `xml:",chardata"`
|
||||
|
||||
+2
-5
@@ -13,7 +13,7 @@ import (
|
||||
// Entwicklerinfos anzeigen
|
||||
func showDevInfo() {
|
||||
|
||||
if System.Dev == true {
|
||||
if System.Dev {
|
||||
|
||||
fmt.Print("\033[31m")
|
||||
fmt.Println("* * * * * D E V M O D E * * * * *")
|
||||
@@ -25,7 +25,6 @@ func showDevInfo() {
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Alle Systemordner erstellen
|
||||
@@ -261,7 +260,7 @@ func saveSettings(settings SettingsStruct) (err error) {
|
||||
|
||||
Settings = settings
|
||||
|
||||
if System.Dev == true {
|
||||
if System.Dev {
|
||||
Settings.UUID = "2019-01-DEV-xTeVe!"
|
||||
}
|
||||
|
||||
@@ -301,7 +300,6 @@ func setGlobalDomain(domain string) {
|
||||
System.Addresses.XML = getErrMsg(2106)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UUID generieren
|
||||
@@ -323,7 +321,6 @@ func setDeviceID() {
|
||||
System.DeviceID = fmt.Sprintf("%s:%d", id, Settings.Tuner)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Provider Streaming-URL zu xTeVe Streaming-URL konvertieren
|
||||
|
||||
+14
-39
@@ -7,7 +7,7 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -59,11 +59,8 @@ func checkFile(filename string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
switch mode := fi.Mode(); {
|
||||
case mode.IsDir():
|
||||
if fi.Mode().IsDir() {
|
||||
err = fmt.Errorf("%s: %s", file, getErrMsg(1072))
|
||||
case mode.IsRegular():
|
||||
break
|
||||
}
|
||||
|
||||
return
|
||||
@@ -97,7 +94,7 @@ func checkFilePermission(dir string) (err error) {
|
||||
|
||||
var filename = dir + "permission.test"
|
||||
|
||||
err = ioutil.WriteFile(filename, []byte(""), 0644)
|
||||
err = os.WriteFile(filename, []byte(""), 0644)
|
||||
if err == nil {
|
||||
err = os.RemoveAll(filename)
|
||||
}
|
||||
@@ -125,12 +122,6 @@ func getFilenameFromPath(path string) (file string) {
|
||||
return filepath.Base(path)
|
||||
}
|
||||
|
||||
// Nicht mehr verwendete Systemdaten löschen
|
||||
func removeOldSystemData() {
|
||||
// Temporären Ordner löschen
|
||||
os.RemoveAll(System.Folder.Temp)
|
||||
}
|
||||
|
||||
// Sucht eine Datei im OS
|
||||
func searchFileInOS(file string) (path string) {
|
||||
|
||||
@@ -197,14 +188,6 @@ func jsonToMap(content string) map[string]any {
|
||||
return (tmpMap)
|
||||
}
|
||||
|
||||
func jsonToMapInt64(content string) map[int64]any {
|
||||
|
||||
var tmpMap = make(map[int64]any)
|
||||
json.Unmarshal([]byte(content), &tmpMap)
|
||||
|
||||
return (tmpMap)
|
||||
}
|
||||
|
||||
func jsonToInterface(content string) (tmpMap any, err error) {
|
||||
|
||||
err = json.Unmarshal([]byte(content), &tmpMap)
|
||||
@@ -221,7 +204,7 @@ func saveMapToJSONFile(file string, tmpMap any) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(filename, []byte(jsonString), 0644)
|
||||
err = os.WriteFile(filename, []byte(jsonString), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -232,16 +215,17 @@ func saveMapToJSONFile(file string, tmpMap any) error {
|
||||
func loadJSONFileToMap(file string) (tmpMap map[string]any, err error) {
|
||||
|
||||
f, err := os.Open(getPlatformFile(file))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(f)
|
||||
content, err := io.ReadAll(f)
|
||||
|
||||
if err == nil {
|
||||
err = json.Unmarshal([]byte(content), &tmpMap)
|
||||
}
|
||||
|
||||
f.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -249,10 +233,12 @@ func loadJSONFileToMap(file string) (tmpMap map[string]any, err error) {
|
||||
func readByteFromFile(file string) (content []byte, err error) {
|
||||
|
||||
f, err := os.Open(getPlatformFile(file))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
content, err = ioutil.ReadAll(f)
|
||||
f.Close()
|
||||
content, err = io.ReadAll(f)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -260,7 +246,7 @@ func readByteFromFile(file string) (content []byte, err error) {
|
||||
func writeByteToFile(file string, data []byte) (err error) {
|
||||
|
||||
var filename = getPlatformFile(file)
|
||||
err = ioutil.WriteFile(filename, data, 0644)
|
||||
err = os.WriteFile(filename, data, 0644)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -275,7 +261,7 @@ func readStringFromFile(file string) (str string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
content, err = ioutil.ReadFile(filename)
|
||||
content, err = os.ReadFile(filename)
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
@@ -395,17 +381,6 @@ func indexOfFloat64(element float64, data []float64) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func indexOfInt(element int, data []int) int {
|
||||
|
||||
for k, v := range data {
|
||||
if element == v {
|
||||
return (k)
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func getMD5(str string) string {
|
||||
|
||||
md5Hasher := md5.New()
|
||||
|
||||
+20
-57
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -40,8 +40,6 @@ func StartWebserver() (err error) {
|
||||
http.HandleFunc("/data_images/", DataImages)
|
||||
http.HandleFunc("/healthz", Healthz)
|
||||
|
||||
//http.HandleFunc("/auto/", Auto)
|
||||
|
||||
showInfo("DVR IP:" + System.IPAddress + ":" + Settings.Port)
|
||||
|
||||
var ips = len(System.IPAddressesV4) + len(System.IPAddressesV6) - 1
|
||||
@@ -90,7 +88,7 @@ func Index(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
case "/lineup.json":
|
||||
if Settings.AuthenticationPMS == true {
|
||||
if Settings.AuthenticationPMS {
|
||||
|
||||
_, err := basicAuth(r, "authentication.pms")
|
||||
if err != nil {
|
||||
@@ -123,7 +121,6 @@ func Index(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
httpStatusError(w, r, 500)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Stream : Web Server /stream/
|
||||
@@ -151,12 +148,12 @@ func Stream(w http.ResponseWriter, r *http.Request) {
|
||||
showInfo(fmt.Sprintf("Buffer:false [%s]", Settings.Buffer))
|
||||
|
||||
case "xteve":
|
||||
if strings.Index(streamInfo.URL, "rtsp://") != -1 || strings.Index(streamInfo.URL, "rtp://") != -1 {
|
||||
if strings.Contains(streamInfo.URL, "rtsp://") || strings.Contains(streamInfo.URL, "rtp://") {
|
||||
err = errors.New("RTSP and RTP streams are not supported")
|
||||
ShowError(err, 2004)
|
||||
|
||||
showInfo("Streaming URL:" + streamInfo.URL)
|
||||
http.Redirect(w, r, streamInfo.URL, 302)
|
||||
http.Redirect(w, r, streamInfo.URL, http.StatusFound)
|
||||
|
||||
showInfo("Streaming Info:URL was passed to the client")
|
||||
return
|
||||
@@ -181,7 +178,7 @@ func Stream(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
case "-":
|
||||
showInfo("Streaming URL:" + streamInfo.URL)
|
||||
http.Redirect(w, r, streamInfo.URL, 302)
|
||||
http.Redirect(w, r, streamInfo.URL, http.StatusFound)
|
||||
|
||||
showInfo("Streaming Info:URL was passed to the client.")
|
||||
showInfo("Streaming Info:xTeVe is no longer involved, the client connects directly to the streaming server.")
|
||||
@@ -191,32 +188,6 @@ func Stream(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Auto : HDHR routing (wird derzeit nicht benutzt)
|
||||
func Auto(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var channelID = strings.Replace(r.RequestURI, "/auto/v", "", 1)
|
||||
fmt.Println(channelID)
|
||||
|
||||
/*
|
||||
switch Settings.Buffer {
|
||||
|
||||
case true:
|
||||
var playlistID, streamURL, err = getStreamByChannelID(channelID)
|
||||
if err == nil {
|
||||
bufferingStream(playlistID, streamURL, w, r)
|
||||
} else {
|
||||
httpStatusError(w, r, 404)
|
||||
}
|
||||
|
||||
case false:
|
||||
httpStatusError(w, r, 423)
|
||||
}
|
||||
*/
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// xTeVe : Web Server /xmltv/ und /m3u/
|
||||
@@ -250,7 +221,7 @@ func xTeVe(w http.ResponseWriter, r *http.Request) {
|
||||
requestType = "m3u"
|
||||
groupTitle = r.URL.Query().Get("group-title")
|
||||
|
||||
if System.Dev == false {
|
||||
if !System.Dev {
|
||||
// false: Dateiname wird im Header gesetzt
|
||||
// true: M3U wird direkt im Browser angezeigt
|
||||
w.Header().Set("Content-Disposition", "attachment; filename="+getFilenameFromPath(path))
|
||||
@@ -286,7 +257,6 @@ func xTeVe(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(content))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Images : Image Cache /images/
|
||||
@@ -306,7 +276,6 @@ func Images(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
w.Write(content)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DataImages : Image Pfad für Logos / Bilder die hochgeladen wurden /data_images/
|
||||
@@ -326,7 +295,6 @@ func DataImages(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
w.Write(content)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// WS : Web Sockets /ws/
|
||||
@@ -362,7 +330,7 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if System.ConfigurationWizard == false {
|
||||
if !System.ConfigurationWizard {
|
||||
|
||||
switch Settings.AuthenticationWEB {
|
||||
|
||||
@@ -425,7 +393,7 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
response.OpenMenu = strconv.Itoa(indexOfString("settings", System.WEB.Menu))
|
||||
|
||||
if Settings.AuthenticationWEB == true && authenticationUpdate == false {
|
||||
if Settings.AuthenticationWEB && !authenticationUpdate {
|
||||
response.Reload = true
|
||||
}
|
||||
|
||||
@@ -568,7 +536,7 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var requestMap = make(map[string]any) // Debug
|
||||
_ = requestMap
|
||||
if System.Dev == true {
|
||||
if System.Dev {
|
||||
fmt.Println(mapToJSON(requestMap))
|
||||
}
|
||||
|
||||
@@ -581,7 +549,7 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
response = setDefaultResponseData(response, true)
|
||||
if System.ConfigurationWizard == true {
|
||||
if System.ConfigurationWizard {
|
||||
response.ConfigurationWizard = System.ConfigurationWizard
|
||||
}
|
||||
|
||||
@@ -593,7 +561,6 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Healthz : Liveness endpoint for container healthchecks and monitoring.
|
||||
@@ -629,7 +596,7 @@ func Web(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if System.ScanInProgress == 0 {
|
||||
|
||||
if Settings.WizardCompleted == false && len(Settings.Files.M3U) == 0 && len(Settings.Files.HDHR) == 0 {
|
||||
if !Settings.WizardCompleted && len(Settings.Files.M3U) == 0 && len(Settings.Files.HDHR) == 0 {
|
||||
System.ConfigurationWizard = true
|
||||
}
|
||||
|
||||
@@ -675,7 +642,7 @@ func Web(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
// Redirect, damit die Daten aus dem Browser gelöscht werden.
|
||||
w = authentication.SetCookieToken(w, token)
|
||||
http.Redirect(w, r, "/web", 301)
|
||||
http.Redirect(w, r, "/web", http.StatusMovedPermanently)
|
||||
return
|
||||
|
||||
}
|
||||
@@ -691,11 +658,11 @@ func Web(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w = authentication.SetCookieToken(w, token)
|
||||
http.Redirect(w, r, "/web", 301) // Redirect, damit die Daten aus dem Browser gelöscht werden.
|
||||
http.Redirect(w, r, "/web", http.StatusMovedPermanently) // Redirect, damit die Daten aus dem Browser gelöscht werden.
|
||||
|
||||
} else {
|
||||
w = authentication.SetCookieToken(w, "-")
|
||||
http.Redirect(w, r, "/web", 301) // Redirect, damit die Daten aus dem Browser gelöscht werden.
|
||||
http.Redirect(w, r, "/web", http.StatusMovedPermanently) // Redirect, damit die Daten aus dem Browser gelöscht werden.
|
||||
}
|
||||
|
||||
return
|
||||
@@ -723,7 +690,7 @@ func Web(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(allUserData) == 0 && Settings.AuthenticationWEB == true {
|
||||
if len(allUserData) == 0 && Settings.AuthenticationWEB {
|
||||
file = "create-first-user.html"
|
||||
}
|
||||
|
||||
@@ -828,13 +795,12 @@ func API(w http.ResponseWriter, r *http.Request) {
|
||||
response.Status = false
|
||||
response.Error = err.Error()
|
||||
w.Write([]byte(mapToJSON(response)))
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
response.Status = true
|
||||
|
||||
if Settings.API == false {
|
||||
if !Settings.API {
|
||||
httpStatusError(w, r, 423)
|
||||
return
|
||||
}
|
||||
@@ -844,7 +810,7 @@ func API(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
b, err := io.ReadAll(r.Body)
|
||||
defer r.Body.Close()
|
||||
if err != nil {
|
||||
httpStatusError(w, r, 400)
|
||||
@@ -860,7 +826,7 @@ func API(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("content-type", "application/json")
|
||||
|
||||
if Settings.AuthenticationAPI == true {
|
||||
if Settings.AuthenticationAPI {
|
||||
var token string
|
||||
switch len(request.Token) {
|
||||
case 0:
|
||||
@@ -957,7 +923,6 @@ func API(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Write([]byte(mapToJSON(response)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Download : Datei Download
|
||||
@@ -975,7 +940,6 @@ func Download(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
os.RemoveAll(System.Folder.Temp + getFilenameFromPath(path))
|
||||
w.Write([]byte(content))
|
||||
return
|
||||
}
|
||||
|
||||
func setDefaultResponseData(response ResponseStruct, data bool) (defaults ResponseStruct) {
|
||||
@@ -999,7 +963,7 @@ func setDefaultResponseData(response ResponseStruct, data bool) (defaults Respon
|
||||
switch System.Branch {
|
||||
|
||||
case "master":
|
||||
defaults.ClientInfo.Version = fmt.Sprintf("%s", System.Version)
|
||||
defaults.ClientInfo.Version = System.Version
|
||||
|
||||
default:
|
||||
defaults.ClientInfo.Version = fmt.Sprintf("%s (%s)", System.Version, System.Build)
|
||||
@@ -1007,7 +971,7 @@ func setDefaultResponseData(response ResponseStruct, data bool) (defaults Respon
|
||||
|
||||
}
|
||||
|
||||
if data == true {
|
||||
if data {
|
||||
|
||||
defaults.Users, _ = authentication.GetAllUserData()
|
||||
//defaults.DVR = System.DVRAddress
|
||||
@@ -1048,7 +1012,6 @@ func setDefaultResponseData(response ResponseStruct, data bool) (defaults Respon
|
||||
|
||||
func httpStatusError(w http.ResponseWriter, r *http.Request, httpStatusCode int) {
|
||||
http.Error(w, fmt.Sprintf("%s [%d]", http.StatusText(httpStatusCode), httpStatusCode), httpStatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
func getContentType(filename string) (contentType string) {
|
||||
|
||||
+41
-140
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"sort"
|
||||
@@ -71,28 +71,9 @@ func buildXEPG(background bool) {
|
||||
createM3UFile()
|
||||
queuePlexGuideRefresh("xepg rebuild")
|
||||
|
||||
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
|
||||
showInfo("XEPG:" + "Ready to use")
|
||||
|
||||
if Settings.CacheImages == true && System.ImageCachingInProgress == 0 {
|
||||
|
||||
go func() {
|
||||
|
||||
System.ImageCachingInProgress = 1
|
||||
showInfo(fmt.Sprintf("Image Caching:Images are cached (%d)", len(Data.Cache.Images.Queue)))
|
||||
|
||||
Data.Cache.Images.Image.Caching()
|
||||
Data.Cache.Images.Image.Remove()
|
||||
showInfo("Image Caching:Done")
|
||||
|
||||
createXMLTVFile()
|
||||
createM3UFile()
|
||||
queuePlexGuideRefresh("xepg image cache refresh")
|
||||
|
||||
System.ImageCachingInProgress = 0
|
||||
|
||||
}()
|
||||
|
||||
}
|
||||
cacheImagesInBackground()
|
||||
|
||||
System.ScanInProgress = 0
|
||||
|
||||
@@ -118,28 +99,9 @@ func buildXEPG(background bool) {
|
||||
createM3UFile()
|
||||
queuePlexGuideRefresh("xepg rebuild")
|
||||
|
||||
if Settings.CacheImages == true && System.ImageCachingInProgress == 0 {
|
||||
cacheImagesInBackground()
|
||||
|
||||
go func() {
|
||||
|
||||
System.ImageCachingInProgress = 1
|
||||
showInfo(fmt.Sprintf("Image Caching:Images are cached (%d)", len(Data.Cache.Images.Queue)))
|
||||
|
||||
Data.Cache.Images.Image.Caching()
|
||||
Data.Cache.Images.Image.Remove()
|
||||
showInfo("Image Caching:Done")
|
||||
|
||||
createXMLTVFile()
|
||||
createM3UFile()
|
||||
queuePlexGuideRefresh("xepg image cache refresh")
|
||||
|
||||
System.ImageCachingInProgress = 0
|
||||
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
|
||||
showInfo("XEPG:" + "Ready to use")
|
||||
|
||||
System.ScanInProgress = 0
|
||||
|
||||
@@ -161,52 +123,30 @@ func buildXEPG(background bool) {
|
||||
|
||||
}
|
||||
|
||||
// XEPG Daten aktualisieren
|
||||
func updateXEPG(background bool) {
|
||||
// cacheImagesInBackground : Bilder im Hintergrund cachen, danach XMLTV- und M3U-Datei neu erstellen
|
||||
func cacheImagesInBackground() {
|
||||
|
||||
if System.ScanInProgress == 1 {
|
||||
if !Settings.CacheImages || System.ImageCachingInProgress != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
System.ScanInProgress = 1
|
||||
go func() {
|
||||
|
||||
if Settings.EpgSource == "XEPG" {
|
||||
System.ImageCachingInProgress = 1
|
||||
showInfo(fmt.Sprintf("Image Caching:Images are cached (%d)", len(Data.Cache.Images.Queue)))
|
||||
|
||||
switch background {
|
||||
Data.Cache.Images.Image.Caching()
|
||||
Data.Cache.Images.Image.Remove()
|
||||
showInfo("Image Caching:Done")
|
||||
|
||||
case false:
|
||||
createXMLTVFile()
|
||||
createM3UFile()
|
||||
queuePlexGuideRefresh("xepg image cache refresh")
|
||||
|
||||
createXEPGDatabase()
|
||||
mapping()
|
||||
cleanupXEPG()
|
||||
System.ImageCachingInProgress = 0
|
||||
|
||||
go func() {
|
||||
}()
|
||||
|
||||
createXMLTVFile()
|
||||
createM3UFile()
|
||||
queuePlexGuideRefresh("xepg update")
|
||||
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
|
||||
@@ -219,7 +159,6 @@ func createXEPGMapping() {
|
||||
|
||||
var friendlyDisplayName = func(channel Channel) (displayName string) {
|
||||
var dn = channel.DisplayName
|
||||
displayName = dn[0].Value
|
||||
|
||||
switch len(dn) {
|
||||
case 1:
|
||||
@@ -277,11 +216,10 @@ func createXEPGMapping() {
|
||||
}
|
||||
|
||||
Data.XMLTV.Mapping = tmpMap
|
||||
tmpMap = make(map[string]any)
|
||||
|
||||
} else {
|
||||
|
||||
if System.ConfigurationWizard == false {
|
||||
if !System.ConfigurationWizard {
|
||||
showWarning(1007)
|
||||
}
|
||||
|
||||
@@ -304,7 +242,6 @@ func createXEPGMapping() {
|
||||
|
||||
Data.XMLTV.Mapping["xTeVe Dummy"] = dummy
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// XEPG Datenbank erstellen / aktualisieren
|
||||
@@ -339,7 +276,7 @@ func createXEPGDatabase() (err error) {
|
||||
|
||||
sort.Float64s(allChannelNumbers)
|
||||
|
||||
var firstFreeNumber float64 = Settings.MappingFirstChannel
|
||||
var firstFreeNumber = Settings.MappingFirstChannel
|
||||
|
||||
for {
|
||||
|
||||
@@ -469,14 +406,14 @@ func createXEPGDatabase() (err error) {
|
||||
xepgChannel.Name = m3uChannel.Name
|
||||
|
||||
// Kanalname aktualisieren, nur mit Kanal ID's möglich
|
||||
if channelHasUUID == true {
|
||||
if xepgChannel.XUpdateChannelName == true {
|
||||
if channelHasUUID {
|
||||
if xepgChannel.XUpdateChannelName {
|
||||
xepgChannel.XName = m3uChannel.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Kanallogo aktualisieren. Wird bei vorhandenem Logo in der XMLTV Datei wieder überschrieben
|
||||
if xepgChannel.XUpdateChannelIcon == true {
|
||||
if xepgChannel.XUpdateChannelIcon {
|
||||
xepgChannel.TvgLogo = m3uChannel.TvgLogo
|
||||
}
|
||||
|
||||
@@ -602,7 +539,7 @@ func findXEPGReplacementChannel(xmltvChannels map[string]any, xepgChannel XEPGCh
|
||||
|
||||
for id, data := range xmltvChannels {
|
||||
xmltvChannel, castOK := data.(map[string]any)
|
||||
if castOK == false {
|
||||
if !castOK {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -615,7 +552,7 @@ func findXEPGReplacementChannel(xmltvChannels map[string]any, xepgChannel XEPGCh
|
||||
}
|
||||
|
||||
displayName, hasDisplayName := xmltvChannel["display-name"].(string)
|
||||
if hasDisplayName == false {
|
||||
if !hasDisplayName {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -660,7 +597,7 @@ func mapping() (err error) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if !xepgChannel.XActive {
|
||||
|
||||
// Werte kann "-" sein, deswegen len < 1
|
||||
if len(xepgChannel.XmltvFile) < 1 && len(xepgChannel.XMapping) < 1 {
|
||||
@@ -704,7 +641,7 @@ func mapping() (err error) {
|
||||
}
|
||||
|
||||
// Überprüfen, ob die zugeordneten XMLTV Dateien und Kanäle noch existieren.
|
||||
if xepgChannel.XActive == true {
|
||||
if xepgChannel.XActive {
|
||||
|
||||
var mapping = xepgChannel.XMapping
|
||||
var file = xepgChannel.XmltvFile
|
||||
@@ -718,7 +655,7 @@ func mapping() (err error) {
|
||||
// Kanallogo aktualisieren
|
||||
if logo, ok := channel["icon"].(string); ok {
|
||||
|
||||
if xepgChannel.XUpdateChannelIcon == true && len(logo) > 0 {
|
||||
if xepgChannel.XUpdateChannelIcon && len(logo) > 0 {
|
||||
xepgChannel.TvgLogo = logo
|
||||
}
|
||||
|
||||
@@ -729,7 +666,7 @@ func mapping() (err error) {
|
||||
xepgChannel.XMapping = channelID
|
||||
|
||||
if logo, ok := replacementChannel["icon"].(string); ok {
|
||||
if xepgChannel.XUpdateChannelIcon == true && len(logo) > 0 {
|
||||
if xepgChannel.XUpdateChannelIcon && len(logo) > 0 {
|
||||
xepgChannel.TvgLogo = logo
|
||||
}
|
||||
}
|
||||
@@ -752,7 +689,7 @@ func mapping() (err error) {
|
||||
name = xepg
|
||||
}
|
||||
|
||||
if strictMissingEPGMode == true {
|
||||
if strictMissingEPGMode {
|
||||
missingEPGCount++
|
||||
appendXEPGIssueSample(missingEPGSamples, name)
|
||||
xepgChannel.XActive = false
|
||||
@@ -772,7 +709,7 @@ func mapping() (err error) {
|
||||
providerName = file
|
||||
}
|
||||
|
||||
if strictMissingEPGMode == true {
|
||||
if strictMissingEPGMode {
|
||||
missingXMLTVCount++
|
||||
appendXEPGIssueSample(missingXMLTVSamples, providerName)
|
||||
xepgChannel.XActive = false
|
||||
@@ -849,7 +786,7 @@ func createXMLTVFile() (err error) {
|
||||
Data.Cache.ImagesURLS = []string{}
|
||||
Data.Cache.ImagesCache = []string{}
|
||||
|
||||
files, err := ioutil.ReadDir(System.Folder.ImagesCache)
|
||||
files, err := os.ReadDir(System.Folder.ImagesCache)
|
||||
if err == nil {
|
||||
|
||||
for _, file := range files {
|
||||
@@ -887,7 +824,7 @@ func createXMLTVFile() (err error) {
|
||||
err := json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
|
||||
if err == nil {
|
||||
|
||||
if xepgChannel.XActive == true {
|
||||
if xepgChannel.XActive {
|
||||
|
||||
// Kanäle
|
||||
var channel Channel
|
||||
@@ -902,9 +839,7 @@ func createXMLTVFile() (err error) {
|
||||
*tmpProgram, err = getProgramData(xepgChannel)
|
||||
if err == nil {
|
||||
|
||||
for _, program := range tmpProgram.Program {
|
||||
xepgXML.Program = append(xepgXML.Program, program)
|
||||
}
|
||||
xepgXML.Program = append(xepgXML.Program, tmpProgram.Program...)
|
||||
|
||||
}
|
||||
|
||||
@@ -947,7 +882,7 @@ func getProgramData(xepgChannel XEPGChannelStruct) (xepgXML XMLTV, err error) {
|
||||
|
||||
err = getLocalXMLTV(xmltvFile, &xmltv)
|
||||
if err != nil {
|
||||
if relaxedMissingEPGMode == true {
|
||||
if relaxedMissingEPGMode {
|
||||
fallbackToDummy()
|
||||
err = nil
|
||||
}
|
||||
@@ -1024,7 +959,7 @@ func getProgramData(xepgChannel XEPGChannelStruct) (xepgXML XMLTV, err error) {
|
||||
|
||||
}
|
||||
|
||||
if len(xepgXML.Program) == 0 && relaxedMissingEPGMode == true && xmltvFile != System.Folder.Data+"xTeVe Dummy" {
|
||||
if len(xepgXML.Program) == 0 && relaxedMissingEPGMode && xmltvFile != System.Folder.Data+"xTeVe Dummy" {
|
||||
fallbackToDummy()
|
||||
}
|
||||
|
||||
@@ -1072,7 +1007,7 @@ func createDummyProgram(xepgChannel XEPGChannelStruct) (dummyXMLTV XMLTV) {
|
||||
epg.Desc = append(epg.Desc, &Desc{Value: xepgChannel.XDescription, Lang: "en"})
|
||||
}
|
||||
|
||||
if Settings.XepgReplaceMissingImages == true {
|
||||
if Settings.XepgReplaceMissingImages {
|
||||
poster.Src = imgc.Image.GetURL(xepgChannel.TvgLogo)
|
||||
epg.Poster = append(epg.Poster, poster)
|
||||
}
|
||||
@@ -1114,7 +1049,6 @@ func getCategory(program *Program, xmltvProgram *Program, xepgChannel XEPGChanne
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Programm Poster Cover aus der XMLTV Datei laden
|
||||
@@ -1127,7 +1061,7 @@ func getPoster(program *Program, xmltvProgram *Program, xepgChannel XEPGChannelS
|
||||
program.Poster = append(program.Poster, poster)
|
||||
}
|
||||
|
||||
if Settings.XepgReplaceMissingImages == true {
|
||||
if Settings.XepgReplaceMissingImages {
|
||||
|
||||
if len(xmltvProgram.Poster) == 0 {
|
||||
var poster Poster
|
||||
@@ -1161,7 +1095,6 @@ func getEpisodeNum(program *Program, xmltvProgram *Program, xepgChannel XEPGChan
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Videoparameter erstellen (createXMLTVFile)
|
||||
@@ -1187,7 +1120,6 @@ func getVideo(program *Program, xmltvProgram *Program, xepgChannel XEPGChannelSt
|
||||
|
||||
program.Video = video
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Lokale Provider XMLTV Datei laden
|
||||
@@ -1236,7 +1168,6 @@ func createM3UFile() {
|
||||
|
||||
saveMapToJSONFile(System.File.URLS, Data.Cache.StreamingURLS)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// XEPG Datenbank bereinigen
|
||||
@@ -1254,7 +1185,7 @@ func cleanupXEPG() {
|
||||
sourceIDs = append(sourceIDs, source)
|
||||
}
|
||||
|
||||
showInfo("XEPG:" + fmt.Sprintf("Cleanup database"))
|
||||
showInfo("XEPG:" + "Cleanup database")
|
||||
Data.XEPG.XEPGCount = 0
|
||||
|
||||
for id, dxc := range Data.XEPG.Channels {
|
||||
@@ -1266,7 +1197,7 @@ func cleanupXEPG() {
|
||||
if indexOfString(xepgChannel.Name+xepgChannel.FileM3UID, Data.Cache.Streams.Active) == -1 {
|
||||
delete(Data.XEPG.Channels, id)
|
||||
} else {
|
||||
if xepgChannel.XActive == true {
|
||||
if xepgChannel.XActive {
|
||||
Data.XEPG.XEPGCount++
|
||||
}
|
||||
}
|
||||
@@ -1291,34 +1222,4 @@ func cleanupXEPG() {
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user