Merge branch 'pr/134' into beta

This commit is contained in:
marmei
2020-05-14 23:44:30 +02:00
15 changed files with 133 additions and 74 deletions

View File

@@ -1,3 +1,12 @@
#### 2.1.1.0116-beta
If no user agent is specified, the default FFmpeg or VLC user agent is used.
#### 2.1.1.0115-beta
```diff
+ GZIP compression for xteve.xml file. (http://xteve.ip:34400/xmltv/xteve.xml.gz)
- Removed protocol setting for reverse proxy. HTTPS can also be configured in the proxy, where it makes more sense.
```
#### 2.1.0.0106-beta #### 2.1.0.0106-beta
```diff ```diff
+ User-Agent is now also used by VLC and FFmpeg. + User-Agent is now also used by VLC and FFmpeg.

View File

@@ -20,7 +20,7 @@ menuItems.push(new MainMenuItem("logout", "{{.mainMenu.item.logout}}", "logout.p
var settingsCategory = new Array(); var settingsCategory = new Array();
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.general}}", "xteveAutoUpdate,tuner,epgSource,api")); settingsCategory.push(new SettingsCategoryItem("{{.settings.category.general}}", "xteveAutoUpdate,tuner,epgSource,api"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.files}}", "update,files.update,temp.path,cache.images,xepg.replace.missing.images")); settingsCategory.push(new SettingsCategoryItem("{{.settings.category.files}}", "update,files.update,temp.path,cache.images,xepg.replace.missing.images"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.streaming}}", "buffer,buffer.size.kb,buffer.timeout,user.agent,ffmpeg.path,ffmpeg.options,vlc.path,vlc.options")); settingsCategory.push(new SettingsCategoryItem("{{.settings.category.streaming}}", "buffer,udpxy,buffer.size.kb,buffer.timeout,user.agent,ffmpeg.path,ffmpeg.options,vlc.path,vlc.options"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.backup}}", "backup.path,backup.keep")); settingsCategory.push(new SettingsCategoryItem("{{.settings.category.backup}}", "backup.path,backup.keep"));
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.authentication}}", "authentication.web,authentication.pms,authentication.m3u,authentication.xml,authentication.api")); settingsCategory.push(new SettingsCategoryItem("{{.settings.category.authentication}}", "authentication.web,authentication.pms,authentication.m3u,authentication.xml,authentication.api"));
function showPopUpElement(elm) { function showPopUpElement(elm) {

View File

@@ -305,6 +305,17 @@ var SettingsCategory = /** @class */ (function () {
setting.appendChild(tdLeft); setting.appendChild(tdLeft);
setting.appendChild(tdRight); setting.appendChild(tdRight);
break; break;
case "udpxy":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.udpxy.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "udpxy", data);
input.setAttribute("placeholder", "{{.settings.udpxy.placeholder}}");
input.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(input);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
} }
return setting; return setting;
}; };
@@ -386,6 +397,9 @@ var SettingsCategory = /** @class */ (function () {
case "xepg.replace.missing.images": case "xepg.replace.missing.images":
text = "{{.settings.replaceEmptyImages.description}}"; text = "{{.settings.replaceEmptyImages.description}}";
break; break;
case "udpxy":
text = "{{.settings.udpxy.description}}";
break;
default: default:
text = ""; text = "";
break; break;

View File

@@ -183,52 +183,52 @@
"active": { "active": {
"title": "Active", "title": "Active",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"channelName": { "channelName": {
"title": "Channel Name", "title": "Channel Name",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"description": { "description": {
"title": "Channel Description", "title": "Channel Description",
"placeholder": "Used by the Dummy as an XML description", "placeholder": "Used by the Dummy as an XML description",
"description": "" "description": ""
}, },
"updateChannelName": { "updateChannelName": {
"title": "Update Channel Name", "title": "Update Channel Name",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"channelLogo": { "channelLogo": {
"title": "Logo URL", "title": "Logo URL",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"updateChannelLogo": { "updateChannelLogo": {
"title": "Update Channel Logo", "title": "Update Channel Logo",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"epgCategory": { "epgCategory": {
"title": "EPG Category", "title": "EPG Category",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"m3uGroupTitle": { "m3uGroupTitle": {
"title": "Group Title (xteve.m3u)", "title": "Group Title (xteve.m3u)",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"xmltvFile": { "xmltvFile": {
"title": "XMLTV File", "title": "XMLTV File",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
}, },
"xmltvChannel": { "xmltvChannel": {
"title": "XMLTV Channel", "title": "XMLTV Channel",
"placeholder": "", "placeholder": "",
"description": "" "description": ""
} }
}, },
"users": { "users": {
@@ -332,6 +332,11 @@
"info_vlc": "VLC connects to the streaming server" "info_vlc": "VLC connects to the streaming server"
}, },
"udpxy": {
"title": "UDPxy address",
"description": "The address of your UDPxy server. If set, and the channel URLs in the m3u is multicast, xTeVe will rewrite it so that it is accessed via the UDPxy service.",
"placeholder": "host:port"
},
"ffmpegPath": { "ffmpegPath": {
"title": "FFmpeg Binary Path", "title": "FFmpeg Binary Path",
"description": "Path to FFmpeg binary.", "description": "Path to FFmpeg binary.",

View File

@@ -15,7 +15,7 @@ var System SystemStruct
var WebScreenLog WebScreenLogStruct var WebScreenLog WebScreenLogStruct
// Settings : Inhalt der settings.json // Settings : Inhalt der settings.json
var Settings SettingsStrcut var Settings SettingsStruct
// Data : Alle Daten werden hier abgelegt. (Lineup, XMLTV) // Data : Alle Daten werden hier abgelegt. (Lineup, XMLTV)
var Data DataStruct var Data DataStruct

View File

@@ -15,7 +15,7 @@ import (
) )
// Einstellungen ändern (WebUI) // Einstellungen ändern (WebUI)
func updateServerSettings(request RequestStruct) (settings SettingsStrcut, err error) { func updateServerSettings(request RequestStruct) (settings SettingsStruct, err error) {
var oldSettings = jsonToMap(mapToJSON(Settings)) var oldSettings = jsonToMap(mapToJSON(Settings))
var newSettings = jsonToMap(mapToJSON(request.Settings)) var newSettings = jsonToMap(mapToJSON(request.Settings))
@@ -408,7 +408,7 @@ func deleteLocalProviderFiles(dataID, fileType string) {
} }
// Filtereinstellungen speichern (WebUI) // Filtereinstellungen speichern (WebUI)
func saveFilter(request RequestStruct) (settings SettingsStrcut, err error) { func saveFilter(request RequestStruct) (settings SettingsStruct, err error) {
var filterMap = make(map[int64]interface{}) var filterMap = make(map[int64]interface{})
var newData = make(map[int64]interface{}) var newData = make(map[int64]interface{})

View File

@@ -86,6 +86,7 @@ func ShowSystemInfo() {
fmt.Println("Settings [Streaming]") fmt.Println("Settings [Streaming]")
fmt.Println(fmt.Sprintf("Buffer: %s", Settings.Buffer)) 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("Buffer Size: %d KB", Settings.BufferSize))
fmt.Println(fmt.Sprintf("Timeout: %d ms", int(Settings.BufferTimeout))) fmt.Println(fmt.Sprintf("Timeout: %d ms", int(Settings.BufferTimeout)))
fmt.Println(fmt.Sprintf("User Agent: %s", Settings.UserAgent)) fmt.Println(fmt.Sprintf("User Agent: %s", Settings.UserAgent))

View File

@@ -99,6 +99,7 @@ type SystemStruct struct {
} }
URLBase string URLBase string
UDPxy string
Version string Version string
WEB struct { WEB struct {
Menu []string Menu []string
@@ -246,8 +247,8 @@ type Notification struct {
Type string `json:"type,required"` Type string `json:"type,required"`
} }
// SettingsStrcut : Inhalt der settings.json // SettingsStruct : Inhalt der settings.json
type SettingsStrcut struct { type SettingsStruct struct {
API bool `json:"api"` API bool `json:"api"`
AuthenticationAPI bool `json:"authentication.api"` AuthenticationAPI bool `json:"authentication.api"`
AuthenticationM3U bool `json:"authentication.m3u"` AuthenticationM3U bool `json:"authentication.m3u"`
@@ -290,6 +291,7 @@ type SettingsStrcut struct {
UpdateURL string `json:"update.url,omitempty"` UpdateURL string `json:"update.url,omitempty"`
UserAgent string `json:"user.agent"` UserAgent string `json:"user.agent"`
UUID string `json:"uuid"` UUID string `json:"uuid"`
UDPxy string `json:"udpxy"`
Version string `json:"version"` Version string `json:"version"`
XepgReplaceMissingImages bool `json:"xepg.replace.missing.images"` XepgReplaceMissingImages bool `json:"xepg.replace.missing.images"`
XteveAutoUpdate bool `json:"xteveAutoUpdate"` XteveAutoUpdate bool `json:"xteveAutoUpdate"`

View File

@@ -37,6 +37,7 @@ type RequestStruct struct {
FilesUpdate *bool `json:"files.update,omitempty"` FilesUpdate *bool `json:"files.update,omitempty"`
TempPath *string `json:"temp.path,omitempty"` TempPath *string `json:"temp.path,omitempty"`
Tuner *int `json:"tuner,omitempty"` Tuner *int `json:"tuner,omitempty"`
UDPxy *string `json:"udpxy,omitempty"`
Update *[]string `json:"update,omitempty"` Update *[]string `json:"update,omitempty"`
UserAgent *string `json:"user.agent,omitempty"` UserAgent *string `json:"user.agent,omitempty"`
XepgReplaceMissingImages *bool `json:"xepg.replace.missing.images,omitempty"` XepgReplaceMissingImages *bool `json:"xepg.replace.missing.images,omitempty"`
@@ -109,7 +110,7 @@ type ResponseStruct struct {
OpenLink string `json:"openLink,omitempty"` OpenLink string `json:"openLink,omitempty"`
OpenMenu string `json:"openMenu,omitempty"` OpenMenu string `json:"openMenu,omitempty"`
Reload bool `json:"reload,omitempty"` Reload bool `json:"reload,omitempty"`
Settings SettingsStrcut `json:"settings,required"` Settings SettingsStruct `json:"settings,required"`
Status bool `json:"status,required"` Status bool `json:"status,required"`
Token string `json:"token,omitempty"` Token string `json:"token,omitempty"`
Users map[string]interface{} `json:"users,omitempty"` Users map[string]interface{} `json:"users,omitempty"`

View File

@@ -90,7 +90,7 @@ func createSystemFiles() (err error) {
} }
// Einstellungen laden und default Werte setzen (xTeVe) // Einstellungen laden und default Werte setzen (xTeVe)
func loadSettings() (settings SettingsStrcut, err error) { func loadSettings() (settings SettingsStruct, err error) {
settingsMap, err := loadJSONFileToMap(System.File.Settings) settingsMap, err := loadJSONFileToMap(System.File.Settings)
if err != nil { if err != nil {
@@ -135,6 +135,7 @@ func loadSettings() (settings SettingsStrcut, err error) {
defaults["update"] = []string{"0000"} defaults["update"] = []string{"0000"}
defaults["user.agent"] = System.Name defaults["user.agent"] = System.Name
defaults["uuid"] = createUUID() defaults["uuid"] = createUUID()
defaults["udpxy"] = ""
defaults["version"] = System.DBVersion defaults["version"] = System.DBVersion
defaults["xteveAutoUpdate"] = true defaults["xteveAutoUpdate"] = true
defaults["temp.path"] = System.Folder.Temp defaults["temp.path"] = System.Folder.Temp
@@ -186,7 +187,7 @@ func loadSettings() (settings SettingsStrcut, err error) {
} }
// Einstellungen speichern (xTeVe) // Einstellungen speichern (xTeVe)
func saveSettings(settings SettingsStrcut) (err error) { func saveSettings(settings SettingsStruct) (err error) {
if settings.BackupKeep == 0 { if settings.BackupKeep == 0 {
settings.BackupKeep = 10 settings.BackupKeep = 10

File diff suppressed because one or more lines are too long

View File

@@ -30,6 +30,7 @@ func StartWebserver() (err error) {
http.HandleFunc("/api/", API) http.HandleFunc("/api/", API)
http.HandleFunc("/images/", Images) http.HandleFunc("/images/", Images)
http.HandleFunc("/data_images/", DataImages) http.HandleFunc("/data_images/", DataImages)
//http.HandleFunc("/auto/", Auto) //http.HandleFunc("/auto/", Auto)
showInfo("DVR IP:" + System.IPAddress + ":" + Settings.Port) showInfo("DVR IP:" + System.IPAddress + ":" + Settings.Port)
@@ -129,6 +130,12 @@ func Stream(w http.ResponseWriter, r *http.Request) {
return return
} }
// If an UDPxy host is set, and the stream URL is multicast (i.e. starts with 'udp://@'),
// then streamInfo.URL needs to be rewritten to point to UDPxy.
if Settings.UDPxy != "" && strings.HasPrefix(streamInfo.URL, "udp://@") {
streamInfo.URL = fmt.Sprintf("http://%s/udp/%s/", Settings.UDPxy, strings.TrimPrefix(streamInfo.URL, "udp://@"))
}
switch Settings.Buffer { switch Settings.Buffer {
case "-": case "-":

View File

@@ -22,7 +22,7 @@ menuItems.push(new MainMenuItem("logout", "{{.mainMenu.item.logout}}", "logout.p
// Kategorien für die Einstellungen // Kategorien für die Einstellungen
var settingsCategory = new Array() var settingsCategory = new Array()
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.general}}", "xteveAutoUpdate,tuner,epgSource,api"));settingsCategory.push(new SettingsCategoryItem("{{.settings.category.files}}", "update,files.update,temp.path,cache.images,xepg.replace.missing.images")) settingsCategory.push(new SettingsCategoryItem("{{.settings.category.general}}", "xteveAutoUpdate,tuner,epgSource,api"));settingsCategory.push(new SettingsCategoryItem("{{.settings.category.files}}", "update,files.update,temp.path,cache.images,xepg.replace.missing.images"))
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.streaming}}", "buffer,buffer.size.kb,buffer.timeout,user.agent,ffmpeg.path,ffmpeg.options,vlc.path,vlc.options")) settingsCategory.push(new SettingsCategoryItem("{{.settings.category.streaming}}", "buffer,udpxy,buffer.size.kb,buffer.timeout,user.agent,ffmpeg.path,ffmpeg.options,vlc.path,vlc.options"))
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.backup}}", "backup.path,backup.keep")) settingsCategory.push(new SettingsCategoryItem("{{.settings.category.backup}}", "backup.path,backup.keep"))
settingsCategory.push(new SettingsCategoryItem("{{.settings.category.authentication}}", "authentication.web,authentication.pms,authentication.m3u,authentication.xml,authentication.api")) settingsCategory.push(new SettingsCategoryItem("{{.settings.category.authentication}}", "authentication.web,authentication.pms,authentication.m3u,authentication.xml,authentication.api"))
@@ -408,7 +408,7 @@ function changeChannelNumber(element) {
}) })
for (var i = 0; i < channelNumbers.length; i++) { for (var i = 0; i < channelNumbers.length; i++) {
if (channelNumbers.indexOf(newNumber) == -1) { if (channelNumbers.indexOf(newNumber) == -1) {
break break
} }
@@ -422,7 +422,7 @@ function changeChannelNumber(element) {
} }
} }
data[dbID]["x-channelID"] = newNumber.toString() data[dbID]["x-channelID"] = newNumber.toString()
element.value = newNumber element.value = newNumber
@@ -461,7 +461,7 @@ function toggleChannelStatus(id:string) {
var checkbox = (document.getElementById("active") as HTMLInputElement) var checkbox = (document.getElementById("active") as HTMLInputElement)
status = (checkbox).checked status = (checkbox).checked
} }
var ids:string[] = getAllSelectedChannels() var ids:string[] = getAllSelectedChannels()
if (ids.length == 0) { if (ids.length == 0) {
@@ -482,9 +482,9 @@ function toggleChannelStatus(id:string) {
alert(channel["x-name"] + ": Missing XMLTV file / channel") alert(channel["x-name"] + ": Missing XMLTV file / channel")
checkbox.checked = false checkbox.checked = false
} }
channel["x-active"] = false channel["x-active"] = false
} }
break break
@@ -621,9 +621,9 @@ function checkUndo(key:string) {
UNDO[key] = JSON.parse(JSON.stringify(SERVER["xepg"][key])); UNDO[key] = JSON.parse(JSON.stringify(SERVER["xepg"][key]));
} }
break; break;
default: default:
break; break;
} }
@@ -646,9 +646,9 @@ function sortSelect(elem) {
elem.options[i] = tmpAry[i]; elem.options[i] = tmpAry[i];
if(elem.options[i].value == selectedValue) newSelectedIndex = i; if(elem.options[i].value == selectedValue) newSelectedIndex = i;
} }
elem.selectedIndex = newSelectedIndex; // Set new selected index after sorting elem.selectedIndex = newSelectedIndex; // Set new selected index after sorting
return; return;
} }

View File

@@ -372,19 +372,34 @@ class SettingsCategory {
setting.appendChild(tdRight) setting.appendChild(tdRight)
break break
case "udpxy":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.udpxy.title}}" + ":"
var tdRight = document.createElement("TD")
var input = content.createInput("text", "udpxy", data)
input.setAttribute("placeholder", "{{.settings.udpxy.placeholder}}")
input.setAttribute("onchange", "javascript: this.className = 'changed'")
tdRight.appendChild(input)
setting.appendChild(tdLeft)
setting.appendChild(tdRight)
break
} }
return setting return setting
} }
createDescription(settingsKey:string):any { createDescription(settingsKey:string):any {
var description = document.createElement("TR") var description = document.createElement("TR")
var text:string var text:string
switch (settingsKey) { switch (settingsKey) {
case "authentication.web": case "authentication.web":
text = "{{.settings.authenticationWEB.description}}" text = "{{.settings.authenticationWEB.description}}"
break break
@@ -483,10 +498,14 @@ class SettingsCategory {
text = "{{.settings.replaceEmptyImages.description}}" text = "{{.settings.replaceEmptyImages.description}}"
break break
case "udpxy":
text = "{{.settings.udpxy.description}}"
break
default: default:
text = "" text = ""
break break
} }
var tdLeft = document.createElement("TD") var tdLeft = document.createElement("TD")
@@ -499,7 +518,7 @@ class SettingsCategory {
description.appendChild(tdLeft) description.appendChild(tdLeft)
description.appendChild(tdRight) description.appendChild(tdRight)
return description return description
} }
@@ -519,12 +538,12 @@ class SettingsCategoryItem extends SettingsCategory {
createCategory():void { createCategory():void {
var headline = this.createCategoryHeadline(this.headline) var headline = this.createCategoryHeadline(this.headline)
var settingsKeys = this.settingsKeys var settingsKeys = this.settingsKeys
var doc = document.getElementById(this.DocumentID) var doc = document.getElementById(this.DocumentID)
doc.appendChild(headline) doc.appendChild(headline)
// Tabelle für die Kategorie erstellen // Tabelle für die Kategorie erstellen
var table = document.createElement("TABLE") var table = document.createElement("TABLE")
var keys = settingsKeys.split(",") var keys = settingsKeys.split(",")
@@ -565,7 +584,7 @@ function showSettings() {
for (let i = 0; i < settingsCategory.length; i++) { for (let i = 0; i < settingsCategory.length; i++) {
settingsCategory[i].createCategory() settingsCategory[i].createCategory()
} }
} }
function saveSettings() { function saveSettings() {
@@ -627,7 +646,7 @@ function saveSettings() {
break break
} }
} }
var data = new Object() var data = new Object()

View File

@@ -47,9 +47,6 @@ const DBVersion = "2.1.0"
// APIVersion : API Version // APIVersion : API Version
const APIVersion = "1.1.0" const APIVersion = "1.1.0"
// Dev : Aktiviert den Entwicklungsmodus. Für den Webserver werden dann die lokalen Dateien verwendet.
const Dev = false
var homeDirectory = fmt.Sprintf("%s%s.%s%s", src.GetUserHomeDirectory(), string(os.PathSeparator), strings.ToLower(Name), string(os.PathSeparator)) var homeDirectory = fmt.Sprintf("%s%s.%s%s", src.GetUserHomeDirectory(), string(os.PathSeparator), strings.ToLower(Name), string(os.PathSeparator))
var samplePath = fmt.Sprintf("%spath%sto%sxteve%s", string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator)) var samplePath = fmt.Sprintf("%spath%sto%sxteve%s", string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator))
var sampleRestore = fmt.Sprintf("%spath%sto%sfile%s", string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator)) var sampleRestore = fmt.Sprintf("%spath%sto%sfile%s", string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator))
@@ -63,6 +60,9 @@ var debug = flag.Int("debug", 0, ": Debug level [0 - 3] (default: 0)")
var info = flag.Bool("info", false, ": Show system info") var info = flag.Bool("info", false, ": Show system info")
var h = flag.Bool("h", false, ": Show help") var h = flag.Bool("h", false, ": Show help")
// Aktiviert den Entwicklungsmodus. Für den Webserver werden dann die lokalen Dateien verwendet.
var dev = flag.Bool("dev", false, ": Activates the developer mode, the source code must be available. The local files for the web interface are used.")
func main() { func main() {
// Build-Nummer von der Versionsnummer trennen // Build-Nummer von der Versionsnummer trennen
@@ -73,7 +73,6 @@ func main() {
system.Branch = GitHub.Branch system.Branch = GitHub.Branch
system.Build = build[len(build)-1:][0] system.Build = build[len(build)-1:][0]
system.DBVersion = DBVersion system.DBVersion = DBVersion
system.Dev = Dev
system.GitHub = GitHub system.GitHub = GitHub
system.Name = Name system.Name = Name
system.Version = strings.Join(build[0:len(build)-1], ".") system.Version = strings.Join(build[0:len(build)-1], ".")
@@ -122,6 +121,8 @@ func main() {
return return
} }
system.Dev = *dev
// Systeminformationen anzeigen // Systeminformationen anzeigen
if *info { if *info {