20 Commits

Author SHA1 Message Date
marmei
72eb7fb599 v2.1.0.0100 2019-10-11 17:59:11 +02:00
marmei
4b969b8cee Merge branch 'beta' 2019-10-11 17:54:06 +02:00
marmei
3d9266dabe XEPG performance 2019-10-11 17:53:20 +02:00
marmei
48218cda50 Update changelog-beta.md 2019-10-04 2019-10-04 19:52:44 +02:00
marmei
dc42afcd05 New beta 2019-10-04 19:39:54 +02:00
marmei
20e5e1b545 Buffer RTSP performance 2019-10-04 19:39:20 +02:00
Aaron Chi
11dd830110 fix #34 2019-10-04 17:08:16 +08:00
marmei
7c87d1d5bd Wrong CVLC path 2019-09-27 22:20:19 +02:00
marmei
6cdd44357b update changelog-beta.md 2019-09-27 19:55:36 +02:00
marmei
ad992eb615 Add FFmpeg and VLC support 2019-09-27 19:24:31 +02:00
marmei
11453c6053 v2.0.3.0030 2019-09-07 12:51:21 +02:00
marmei
81e8ae33d7 Merge branch 'Bugs_in_2.0.2' 2019-09-07 12:07:55 +02:00
marmei
f3be0fca47 Wrong warning (root) 2019-09-05 19:37:55 +02:00
marmei
1c1c89cd74 Update changelog-beta.md 2019-09-04 2019-09-04 21:16:04 +02:00
marmei
3d73dba422 Code removed #1 2019-09-04 20:16:11 +02:00
marmei
c6e74fe11c Interception of repeated save 2019-09-04 20:12:26 +02:00
marmei
18dba46c02 Bug #16 1 2019-09-01 00:24:06 +02:00
marmei
efa55b39a9 Bug #16 0 2019-08-31 20:39:39 +02:00
marmei
717fa68b7e Add an error message if the filter rule is empty.
Set the streaming status to active only once.
2019-08-28 17:56:15 +02:00
marmei
878531ff79 IPTV removed as a source 2019-08-28 16:49:41 +02:00
26 changed files with 1471 additions and 560 deletions

View File

@@ -1,3 +1,29 @@
#### 2.0.3.0042-beta
**Version 2.0.3.0042 changes the settings.json.**
Settings from the current beta can not be used for the current master version 2.0.3
- New default options for VLC and FFmpeg
- VLC and FFmpeg log entries in the xTeVe log
- Less CPU load with VLC and FFmpeg
#### 2.0.3.0035-beta
```diff
+ FFmpeg support
+ VLC support
```
**Version 2.0.3.0035 changes the settings.json.**
Settings from the current beta can not be used for the current master version 2.0.3
#### 2.0.2.0024-beta
```diff
+ Improved monitoring of the buffer process
+ Update the XEPG database a bit faster
```
##### Fixes
- Error message if filter rule is missing
- Channels are lost when saving again (Mapping)
- Plex log, invalid source: IPTV
#### 2.0.1.0012-beta #### 2.0.1.0012-beta
```diff ```diff
+ Add support for "video/m2ts" video streams (Pull request #14) + Add support for "video/m2ts" video streams (Pull request #14)

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")); 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.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

@@ -127,7 +127,7 @@ var Content = /** @class */ (function () {
var cell = new Cell(); var cell = new Cell();
cell.child = true; cell.child = true;
cell.childType = "P"; cell.childType = "P";
if (SERVER["settings"]["buffer"] == true) { if (SERVER["settings"]["buffer"] != "-") {
cell.value = data[key]["tuner"]; cell.value = data[key]["tuner"];
} }
else { else {
@@ -901,7 +901,7 @@ function openPopUp(dataType, element) {
input.setAttribute("placeholder", "{{.playlist.fileM3U.placeholder}}"); input.setAttribute("placeholder", "{{.playlist.fileM3U.placeholder}}");
content.appendRow("{{.playlist.fileM3U.title}}", input); content.appendRow("{{.playlist.fileM3U.title}}", input);
// Tuner // Tuner
if (SERVER["settings"]["buffer"] == true) { if (SERVER["settings"]["buffer"] != "-") {
var text = new Array(); var text = new Array();
var values = new Array(); var values = new Array();
for (var i = 1; i <= 100; i++) { for (var i = 1; i <= 100; i++) {
@@ -971,7 +971,7 @@ function openPopUp(dataType, element) {
input.setAttribute("placeholder", "{{.playlist.fileHDHR.placeholder}}"); input.setAttribute("placeholder", "{{.playlist.fileHDHR.placeholder}}");
content.appendRow("{{.playlist.fileHDHR.title}}", input); content.appendRow("{{.playlist.fileHDHR.title}}", input);
// Tuner // Tuner
if (SERVER["settings"]["buffer"] == true) { if (SERVER["settings"]["buffer"] != "-") {
var text = new Array(); var text = new Array();
var values = new Array(); var values = new Array();
for (var i = 1; i <= 100; i++) { for (var i = 1; i <= 100; i++) {

View File

@@ -85,6 +85,50 @@ var SettingsCategory = /** @class */ (function () {
setting.appendChild(tdLeft); setting.appendChild(tdLeft);
setting.appendChild(tdRight); setting.appendChild(tdRight);
break; break;
case "ffmpeg.path":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.ffmpegPath.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "ffmpeg.path", data);
input.setAttribute("placeholder", "{{.settings.ffmpegPath.placeholder}}");
input.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(input);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
case "ffmpeg.options":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.ffmpegOptions.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "ffmpeg.options", data);
input.setAttribute("placeholder", "{{.settings.ffmpegOptions.placeholder}}");
input.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(input);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
case "vlc.path":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.vlcPath.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "vlc.path", data);
input.setAttribute("placeholder", "{{.settings.vlcPath.placeholder}}");
input.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(input);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
case "vlc.options":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.vlcOptions.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createInput("text", "vlc.options", data);
input.setAttribute("placeholder", "{{.settings.vlcOptions.placeholder}}");
input.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(input);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
// Checkboxen // Checkboxen
case "authentication.web": case "authentication.web":
var tdLeft = document.createElement("TD"); var tdLeft = document.createElement("TD");
@@ -185,17 +229,6 @@ var SettingsCategory = /** @class */ (function () {
setting.appendChild(tdLeft); setting.appendChild(tdLeft);
setting.appendChild(tdRight); setting.appendChild(tdRight);
break; break;
case "buffer":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.streamBuffering.title}}" + ":";
var tdRight = document.createElement("TD");
var input = content.createCheckbox(settingsKey);
input.checked = data;
input.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(input);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
case "api": case "api":
var tdLeft = document.createElement("TD"); var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.api.title}}" + ":"; tdLeft.innerHTML = "{{.settings.api.title}}" + ":";
@@ -260,6 +293,18 @@ var SettingsCategory = /** @class */ (function () {
setting.appendChild(tdLeft); setting.appendChild(tdLeft);
setting.appendChild(tdRight); setting.appendChild(tdRight);
break; break;
case "buffer":
var tdLeft = document.createElement("TD");
tdLeft.innerHTML = "{{.settings.streamBuffering.title}}" + ":";
var tdRight = document.createElement("TD");
var text = ["{{.settings.streamBuffering.info_false}}", "xTeVe: ({{.settings.streamBuffering.info_xteve}})", "FFmpeg: ({{.settings.streamBuffering.info_ffmpeg}})", "VLC: ({{.settings.streamBuffering.info_vlc}})"];
var values = ["-", "xteve", "ffmpeg", "vlc"];
var select = content.createSelect(text, values, data, settingsKey);
select.setAttribute("onchange", "javascript: this.className = 'changed'");
tdRight.appendChild(select);
setting.appendChild(tdLeft);
setting.appendChild(tdRight);
break;
} }
return setting; return setting;
}; };
@@ -308,6 +353,18 @@ var SettingsCategory = /** @class */ (function () {
case "user.agent": case "user.agent":
text = "{{.settings.userAgent.description}}"; text = "{{.settings.userAgent.description}}";
break; break;
case "ffmpeg.path":
text = "{{.settings.ffmpegPath.description}}";
break;
case "ffmpeg.options":
text = "{{.settings.ffmpegOptions.description}}";
break;
case "vlc.path":
text = "{{.settings.vlcPath.description}}";
break;
case "vlc.options":
text = "{{.settings.vlcOptions.description}}";
break;
case "epgSource": case "epgSource":
text = "{{.settings.epgSource.description}}"; text = "{{.settings.epgSource.description}}";
break; break;

View File

@@ -307,7 +307,7 @@
"description": "Updates all playlists, tuner and XMLTV files at startup." "description": "Updates all playlists, tuner and XMLTV files at startup."
}, },
"cacheImages": { "cacheImages": {
"title": "Image caching", "title": "Image Caching",
"description": "All images from the XMLTV file are cached, allowing faster rendering of the grid in the client.<br>Downloading the images may take a while and will be done in the background." "description": "All images from the XMLTV file are cached, allowing faster rendering of the grid in the client.<br>Downloading the images may take a while and will be done in the background."
}, },
"replaceEmptyImages": { "replaceEmptyImages": {
@@ -320,7 +320,32 @@
}, },
"streamBuffering": { "streamBuffering": {
"title": "Stream Buffer", "title": "Stream Buffer",
"description": "- The stream is passed from xTeVe to Plex / Emby / M3U Player<br>- Small jerking of the streams can be compensated<br>- HLS / M3U8 support<br>- Re-streaming<br>- Separate tuner limit for each playlist" "description": "Functions of the buffer:<br>- The stream is passed from xTeVe, FFmpeg or VLC to Plex, Emby or M3U Player<br>- Small jerking of the streams can be compensated<br>- HLS / M3U8 support<br>- RTP / RTPS support (only FFmpeg or VLC)<br>- Re-streaming<br>- Separate tuner limit for each playlist",
"info_false": "No Buffer (Client connects to the streaming server)",
"info_xteve": "xTeVe connects to the streaming server",
"info_ffmpeg": "FFmpeg connects to the streaming server",
"info_vlc": "VLC connects to the streaming server"
},
"ffmpegPath": {
"title": "FFmpeg Binary Path",
"description": "Path to FFmpeg binary.",
"placeholder": "/path/to/ffmpeg"
},
"ffmpegOptions": {
"title": "FFmpeg Options",
"description": "FFmpeg options.<br>Only change if you know what you are doing.<br>Leave blank to set default settings.",
"placeholder": "Leave blank to set default settings"
},
"vlcPath": {
"title": "VLC / CVLC Binary Path",
"description": "Path to VLC / CVLC binary.",
"placeholder": "/path/to/cvlc"
},
"vlcOptions": {
"title": "VLC / CVLC Options",
"description": "VLC / CVLC options.<br>Only change if you know what you are doing.<br>Leave blank to set default settings.",
"placeholder": "Leave blank to set default settings"
}, },
"bufferSize": { "bufferSize": {
"title": "Buffer Size", "title": "Buffer Size",
@@ -332,8 +357,8 @@
"placeholder": "100" "placeholder": "100"
}, },
"userAgent": { "userAgent": {
"title": "User agent", "title": "User Agent",
"description": "User Agent for HTTP requests", "description": "User Agent for HTTP requests. Only used if xTeVe is selected as the buffer.",
"placeholder": "xTeVe" "placeholder": "xTeVe"
}, },
"backupPath": { "backupPath": {

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,10 @@ func Init() (err error) {
System.DVRLimit = 480 System.DVRLimit = 480
System.Compatibility = "1.4.4" System.Compatibility = "1.4.4"
// FFmpeg Default Einstellungen
System.FFmpeg.DefaultOptions = "-hide_banner -loglevel error -i [URL] -c copy -f mpegts pipe:1"
System.VLC.DefaultOptions = "-I dummy [URL] --sout #std{mux=ts,access=file,dst=-}"
// Default Logeinträge, wird später von denen aus der settings.json überschrieben. Muss gemacht werden, damit die ersten Einträge auch im Log (webUI aangezeigt werden) // Default Logeinträge, wird später von denen aus der settings.json überschrieben. Muss gemacht werden, damit die ersten Einträge auch im Log (webUI aangezeigt werden)
Settings.LogEntriesRAM = 500 Settings.LogEntriesRAM = 500
@@ -109,7 +113,7 @@ func Init() (err error) {
// Überprüfen ob xTeVe als root läuft // Überprüfen ob xTeVe als root läuft
if os.Geteuid() == 0 { if os.Geteuid() == 0 {
showWarning(2010) showWarning(2110)
} }
if System.Flag.Debug > 0 { if System.Flag.Debug > 0 {
@@ -133,7 +137,6 @@ func Init() (err error) {
// Bedingte Update Änderungen durchführen // Bedingte Update Änderungen durchführen
err = conditionalUpdateChanges() err = conditionalUpdateChanges()
if err != nil { if err != nil {
ShowError(err, 0)
return return
} }

View File

@@ -24,6 +24,8 @@ func updateServerSettings(request RequestStruct) (settings SettingsStrcut, err e
var createXEPGFiles = false var createXEPGFiles = false
var debug string var debug string
// -vvv [URL] --sout '#transcode{vcodec=mp4v, acodec=mpga} :standard{access=http, mux=ogg}'
for key, value := range newSettings { for key, value := range newSettings {
if _, ok := oldSettings[key]; ok { if _, ok := oldSettings[key]; ok {
@@ -94,6 +96,17 @@ func updateServerSettings(request RequestStruct) (settings SettingsStrcut, err e
return return
} }
case "ffmpeg.path", "vlc.path":
var path = value.(string)
if len(path) > 0 {
err = checkFile(path)
if err != nil {
return
}
}
} }
oldSettings[key] = value oldSettings[key] = value
@@ -138,6 +151,33 @@ func updateServerSettings(request RequestStruct) (settings SettingsStrcut, err e
} }
// Buffer Einstellungen überprüfen
if len(Settings.FFmpegOptions) == 0 {
Settings.FFmpegOptions = System.FFmpeg.DefaultOptions
}
if len(Settings.VLCOptions) == 0 {
Settings.VLCOptions = System.VLC.DefaultOptions
}
switch Settings.Buffer {
case "ffmpeg":
if len(Settings.FFmpegPath) == 0 {
err = errors.New(getErrMsg(2020))
return
}
case "vlc":
if len(Settings.VLCPath) == 0 {
err = errors.New(getErrMsg(2021))
return
}
}
err = saveSettings(Settings) err = saveSettings(Settings)
if err == nil { if err == nil {
@@ -366,6 +406,7 @@ func saveFilter(request RequestStruct) (settings SettingsStrcut, 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{})
var defaultFilter FilterStruct var defaultFilter FilterStruct
var newFilter = false
defaultFilter.Active = true defaultFilter.Active = true
defaultFilter.CaseSensitive = false defaultFilter.CaseSensitive = false
@@ -389,6 +430,7 @@ func saveFilter(request RequestStruct) (settings SettingsStrcut, err error) {
if dataID == -1 { if dataID == -1 {
// Neuer Filter // Neuer Filter
newFilter = true
dataID = createNewID() dataID = createNewID()
filterMap[dataID] = jsonToMap(mapToJSON(defaultFilter)) filterMap[dataID] = jsonToMap(mapToJSON(defaultFilter))
@@ -397,15 +439,28 @@ func saveFilter(request RequestStruct) (settings SettingsStrcut, err error) {
// Filter aktualisieren / löschen // Filter aktualisieren / löschen
for key, value := range data.(map[string]interface{}) { for key, value := range data.(map[string]interface{}) {
var oldData = filterMap[dataID].(map[string]interface{})
oldData[key] = value
// Filter löschen // Filter löschen
if _, ok := data.(map[string]interface{})["delete"]; ok { if _, ok := data.(map[string]interface{})["delete"]; ok {
delete(filterMap, dataID) delete(filterMap, dataID)
break break
}
if filter, ok := data.(map[string]interface{})["filter"].(string); ok {
if len(filter) == 0 {
err = errors.New(getErrMsg(1014))
if newFilter == true {
delete(filterMap, dataID)
}
return
}
}
if oldData, ok := filterMap[dataID].(map[string]interface{}); ok {
oldData[key] = value
} }
} }
@@ -446,8 +501,60 @@ func saveXEpgMapping(request RequestStruct) (err error) {
Data.XEPG.Channels = request.EpgMapping Data.XEPG.Channels = request.EpgMapping
cleanupXEPG() if System.ScanInProgress == 0 {
buildXEPG(true)
System.ScanInProgress = 1
cleanupXEPG()
//buildXEPG(true)
go func() {
createXMLTVFile()
createM3UFile()
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
go cachingImages()
System.ScanInProgress = 0
}()
} else {
// 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 {
return
}
System.BackgroundProcess = true
for {
time.Sleep(time.Duration(1) * time.Second)
if System.ScanInProgress == 0 {
break
}
}
System.ScanInProgress = 1
cleanupXEPG()
//buildXEPG(false)
createXMLTVFile()
createM3UFile()
showInfo("XEPG:" + fmt.Sprintf("Ready to use"))
go cachingImages()
System.ScanInProgress = 0
System.BackgroundProcess = false
}()
}
return return
} }
@@ -612,6 +719,7 @@ func saveWizard(request RequestStruct) (nextStep int, err error) {
} }
buildXEPG(false) buildXEPG(false)
System.ScanInProgress = 0
} }

View File

@@ -95,7 +95,7 @@ func getLineupStatus() (jsonContent []byte, err error) {
lineupStatus.ScanInProgress = System.ScanInProgress lineupStatus.ScanInProgress = System.ScanInProgress
lineupStatus.ScanPossible = 0 lineupStatus.ScanPossible = 0
lineupStatus.Source = "Cable" lineupStatus.Source = "Cable"
lineupStatus.SourceList = []string{"IPTV", "Cable"} lineupStatus.SourceList = []string{"Cable"}
jsonContent, err = json.MarshalIndent(lineupStatus, "", " ") jsonContent, err = json.MarshalIndent(lineupStatus, "", " ")

View File

@@ -85,7 +85,7 @@ func ShowSystemInfo() {
println("---") println("---")
fmt.Println("Settings [Streaming]") fmt.Println("Settings [Streaming]")
fmt.Println(fmt.Sprintf("Buffer: %t", Settings.Buffer)) fmt.Println(fmt.Sprintf("Buffer: %s", Settings.Buffer))
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

@@ -2,6 +2,8 @@ package m3u
import ( import (
"errors" "errors"
"fmt"
"log"
"net/url" "net/url"
"regexp" "regexp"
"strings" "strings"
@@ -12,6 +14,7 @@ func MakeInterfaceFromM3U(byteStream []byte) (allChannels []interface{}, err err
var content = string(byteStream) var content = string(byteStream)
var channelName string var channelName string
var uuids []string
var parseMetaData = func(channel string) (stream map[string]string) { var parseMetaData = func(channel string) (stream map[string]string) {
@@ -53,7 +56,7 @@ func MakeInterfaceFromM3U(byteStream []byte) (allChannels []interface{}, err err
line = strings.Replace(line, p, "", 1) line = strings.Replace(line, p, "", 1)
p = strings.Replace(p, `"`, "", -1) p = strings.Replace(p, `"`, "", -1)
var parameter = strings.Split(p, "=") var parameter = strings.SplitN(p, "=", 2)
if len(parameter) == 2 { if len(parameter) == 2 {
@@ -120,9 +123,15 @@ func MakeInterfaceFromM3U(byteStream []byte) (allChannels []interface{}, err err
if strings.Contains(strings.ToLower(key), "id") { if strings.Contains(strings.ToLower(key), "id") {
if indexOfString(value, uuids) != -1 {
log.Println(fmt.Sprintf("Channel: %s - %s = %s ", stream["name"], key, value))
break
}
uuids = append(uuids, value)
stream["_uuid.key"] = key stream["_uuid.key"] = key
stream["_uuid.value"] = value stream["_uuid.value"] = value
//os.Exit(0)
break break
} }
@@ -160,3 +169,14 @@ func MakeInterfaceFromM3U(byteStream []byte) (allChannels []interface{}, err err
return return
} }
func indexOfString(element string, data []string) int {
for k, v := range data {
if element == v {
return k
}
}
return -1
}

View File

@@ -43,6 +43,10 @@ func filterThisStream(s interface{}) (status bool) {
for _, filter := range Data.Filter { for _, filter := range Data.Filter {
if filter.Rule == "" {
continue
}
var group, name, search string var group, name, search string
var exclude, include string var exclude, include string
var match = false var match = false

View File

@@ -245,6 +245,8 @@ func getErrMsg(errCode int) (errMsg string) {
errMsg = fmt.Sprintf("Invalid formatting of the time") errMsg = fmt.Sprintf("Invalid formatting of the time")
case 1013: case 1013:
errMsg = fmt.Sprintf("Invalid settings file (settings.json), file must be at least version %s", System.Compatibility) 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")
case 1020: case 1020:
errMsg = fmt.Sprintf("Data could not be saved, invalid keyword") errMsg = fmt.Sprintf("Data could not be saved, invalid keyword")
@@ -252,12 +254,13 @@ func getErrMsg(errCode int) (errMsg string) {
// Datenbank Update // Datenbank Update
case 1030: case 1030:
errMsg = fmt.Sprintf("Invalid settings file (%s)", System.File.Settings) 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.")
// M3U Parser // M3U Parser
case 1050: case 1050:
errMsg = fmt.Sprintf("Invalid duration specification in the M3U8 playlist.") errMsg = fmt.Sprintf("Invalid duration specification in the M3U8 playlist.")
// M3U Parser
case 1060: case 1060:
errMsg = fmt.Sprintf("Invalid characters found in the tvg parameters, streams with invalid parameters were skipped.") errMsg = fmt.Sprintf("Invalid characters found in the tvg parameters, streams with invalid parameters were skipped.")
@@ -266,6 +269,8 @@ func getErrMsg(errCode int) (errMsg string) {
errMsg = fmt.Sprintf("Folder could not be created.") errMsg = fmt.Sprintf("Folder could not be created.")
case 1071: case 1071:
errMsg = fmt.Sprintf("File could not be created") errMsg = fmt.Sprintf("File could not be created")
case 1072:
errMsg = fmt.Sprintf("File not found")
// Backup // Backup
case 1090: case 1090:
@@ -290,6 +295,8 @@ func getErrMsg(errCode int) (errMsg string) {
errMsg = fmt.Sprintf("Steaming URL could not be found in any playlist") errMsg = fmt.Sprintf("Steaming URL could not be found in any playlist")
case 1203: case 1203:
errMsg = fmt.Sprintf("Steaming URL could not be found in any playlist") errMsg = fmt.Sprintf("Steaming URL could not be found in any playlist")
case 1204:
errMsg = fmt.Sprintf("Streaming was stopped by third party transcoder (FFmpeg / VLC)")
// Warnings // Warnings
case 2000: case 2000:
@@ -306,6 +313,10 @@ func getErrMsg(errCode int) (errMsg string) {
errMsg = fmt.Sprintf("There are no channels mapped, use the mapping menu to assign EPG data to the channels.") errMsg = fmt.Sprintf("There are no channels mapped, use the mapping menu to assign EPG data to the channels.")
case 2010: case 2010:
errMsg = fmt.Sprintf("No valid streaming URL") errMsg = fmt.Sprintf("No valid streaming URL")
case 2020:
errMsg = fmt.Sprintf("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.")
case 2099: case 2099:
errMsg = fmt.Sprintf("Updates have been disabled by the developer") errMsg = fmt.Sprintf("Updates have been disabled by the developer")
@@ -345,6 +356,8 @@ func getErrMsg(errCode int) (errMsg string) {
errMsg = fmt.Sprintf("This error message comes from the provider") errMsg = fmt.Sprintf("This error message comes from the provider")
case 4005: case 4005:
errMsg = fmt.Sprintf("Temporary buffer files could not be deleted") errMsg = fmt.Sprintf("Temporary buffer files could not be deleted")
case 4006:
errMsg = fmt.Sprintf("Server connection timeout")
// Buffer (M3U8) // Buffer (M3U8)
case 4050: case 4050:
@@ -368,7 +381,7 @@ func getErrMsg(errCode int) (errMsg string) {
case 6002: case 6002:
errMsg = fmt.Sprintf("Update failed") errMsg = fmt.Sprintf("Update failed")
case 6003: case 6003:
errMsg = fmt.Sprintf("Server not available") errMsg = fmt.Sprintf("Update server not available")
case 6004: case 6004:
errMsg = fmt.Sprintf("xTeVe update available") errMsg = fmt.Sprintf("xTeVe update available")

View File

@@ -108,3 +108,147 @@ type BandwidthCalculation struct {
Stop time.Time Stop time.Time
TimeDiff float64 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)
}
}
*/

View File

@@ -11,6 +11,7 @@ type SystemStruct struct {
APIVersion string APIVersion string
AppName string AppName string
ARCH string ARCH string
BackgroundProcess bool
Branch string Branch string
Build string Build string
Compatibility string Compatibility string
@@ -21,6 +22,16 @@ type SystemStruct struct {
Domain string Domain string
DVRLimit int DVRLimit int
FFmpeg struct {
DefaultOptions string
Path string
}
VLC struct {
DefaultOptions string
Path string
}
File struct { File struct {
Authentication string Authentication string
M3U string M3U string
@@ -241,11 +252,15 @@ type SettingsStrcut struct {
BackupKeep int `json:"backup.keep"` BackupKeep int `json:"backup.keep"`
BackupPath string `json:"backup.path"` BackupPath string `json:"backup.path"`
Branch string `json:"git.branch,omitempty"` Branch string `json:"git.branch,omitempty"`
Buffer bool `json:"buffer"` Buffer string `json:"buffer"`
BufferSize int `json:"buffer.size.kb"` BufferSize int `json:"buffer.size.kb"`
BufferTimeout float64 `json:"buffer.timeout"` BufferTimeout float64 `json:"buffer.timeout"`
CacheImages bool `json:"cache.images"` CacheImages bool `json:"cache.images"`
EpgSource string `json:"epgSource"` EpgSource string `json:"epgSource"`
FFmpegOptions string `json:"ffmpeg.options"`
FFmpegPath string `json:"ffmpeg.path"`
VLCOptions string `json:"vlc.options"`
VLCPath string `json:"vlc.path"`
FileM3U []string `json:"file,omitempty"` // Beim Wizard wird die M3U in ein Slice gespeichert FileM3U []string `json:"file,omitempty"` // Beim Wizard wird die M3U in ein Slice gespeichert
FileXMLTV []string `json:"xmltv,omitempty"` // Altes Speichersystem der Provider XML Datei Slice (Wird für die Umwandlung auf das neue benötigt) FileXMLTV []string `json:"xmltv,omitempty"` // Altes Speichersystem der Provider XML Datei Slice (Wird für die Umwandlung auf das neue benötigt)

View File

@@ -25,11 +25,15 @@ type RequestStruct struct {
AuthenticationXML *bool `json:"authentication.xml,omitempty"` AuthenticationXML *bool `json:"authentication.xml,omitempty"`
BackupKeep *int `json:"backup.keep,omitempty"` BackupKeep *int `json:"backup.keep,omitempty"`
BackupPath *string `json:"backup.path,omitempty"` BackupPath *string `json:"backup.path,omitempty"`
Buffer *bool `json:"buffer,omitempty"` Buffer *string `json:"buffer,omitempty"`
BufferSize *int `json:"buffer.size.kb, omitempty"` BufferSize *int `json:"buffer.size.kb, omitempty"`
BufferTimeout *float64 `json:"buffer.timeout,omitempty"` BufferTimeout *float64 `json:"buffer.timeout,omitempty"`
CacheImages *bool `json:"cache.images,omitempty"` CacheImages *bool `json:"cache.images,omitempty"`
EpgSource *string `json:"epgSource,omitempty"` EpgSource *string `json:"epgSource,omitempty"`
FFmpegOptions *string `json:"ffmpeg.options,omitempty"`
FFmpegPath *string `json:"ffmpeg.path,omitempty"`
VLCOptions *string `json:"vlc.options,omitempty"`
VLCPath *string `json:"vlc.path,omitempty"`
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"`

View File

@@ -113,11 +113,13 @@ func loadSettings() (settings SettingsStrcut, err error) {
defaults["authentication.xml"] = false defaults["authentication.xml"] = false
defaults["backup.keep"] = 10 defaults["backup.keep"] = 10
defaults["backup.path"] = System.Folder.Backup defaults["backup.path"] = System.Folder.Backup
defaults["buffer"] = false defaults["buffer"] = "-"
defaults["buffer.size.kb"] = 1024 defaults["buffer.size.kb"] = 1024
defaults["buffer.timeout"] = 500 defaults["buffer.timeout"] = 500
defaults["cache.images"] = false defaults["cache.images"] = false
defaults["epgSource"] = "PMS" defaults["epgSource"] = "PMS"
defaults["ffmpeg.options"] = System.FFmpeg.DefaultOptions
defaults["vlc.options"] = System.VLC.DefaultOptions
defaults["files"] = dataMap defaults["files"] = dataMap
defaults["files.update"] = true defaults["files.update"] = true
defaults["filter"] = make(map[string]interface{}) defaults["filter"] = make(map[string]interface{})
@@ -159,10 +161,27 @@ func loadSettings() (settings SettingsStrcut, err error) {
showInfo(fmt.Sprintf("Git Branch:Switching Git Branch to -> %s", settings.Branch)) showInfo(fmt.Sprintf("Git Branch:Switching Git Branch to -> %s", settings.Branch))
} }
if len(settings.FFmpegPath) == 0 {
settings.FFmpegPath = searchFileInOS("ffmpeg")
}
if len(settings.VLCPath) == 0 {
settings.VLCPath = searchFileInOS("cvlc")
}
settings.Version = System.DBVersion settings.Version = System.DBVersion
err = saveSettings(settings) err = saveSettings(settings)
// Warung wenn FFmpeg nicht gefunden wurde
if len(Settings.FFmpegPath) == 0 && Settings.Buffer == "ffmpeg" {
showWarning(2020)
}
if len(Settings.VLCPath) == 0 && Settings.Buffer == "vlc" {
showWarning(2021)
}
return return
} }

View File

@@ -10,8 +10,11 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
"os" "os"
"os/exec"
"os/user" "os/user"
"path/filepath" "path/filepath"
"runtime"
"strings"
"text/template" "text/template"
) )
@@ -42,13 +45,25 @@ func checkFolder(path string) (err error) {
return nil return nil
} }
// Prüft ob die datei im Dateisystem existiert // Prüft ob die Datei im Dateisystem existiert
func checkFile(filename string) (err error) { func checkFile(filename string) (err error) {
var file = getPlatformFile(filename) var file = getPlatformFile(filename)
if _, err = os.Stat(file); os.IsNotExist(err) { if _, err = os.Stat(file); os.IsNotExist(err) {
return return err
}
fi, err := os.Stat(file)
if err != nil {
return err
}
switch mode := fi.Mode(); {
case mode.IsDir():
err = fmt.Errorf("%s: %s", file, getErrMsg(1072))
case mode.IsRegular():
break
} }
return return
@@ -77,6 +92,7 @@ func GetUserHomeDirectory() (userHomeDirectory string) {
return return
} }
// Prüft Dateiberechtigung
func checkFilePermission(dir string) (err error) { func checkFilePermission(dir string) (err error) {
var filename = dir + "permission.test" var filename = dir + "permission.test"
@@ -115,6 +131,34 @@ func removeOldSystemData() {
os.RemoveAll(System.Folder.Temp) os.RemoveAll(System.Folder.Temp)
} }
// Sucht eine Datei im OS
func searchFileInOS(file string) (path string) {
switch runtime.GOOS {
case "linux", "darwin", "freebsd":
var args = file
var cmd = exec.Command("which", strings.Split(args, " ")...)
out, err := cmd.CombinedOutput()
if err == nil {
var slice = strings.Split(strings.Replace(string(out), "\r\n", "\n", -1), "\n")
if len(slice) > 0 {
path = strings.Trim(slice[0], "\r\n")
}
}
default:
return
}
return
}
// //
func removeChildItems(dir string) error { func removeChildItems(dir string) error {
@@ -276,6 +320,22 @@ func resolveHostIP() (err error) {
} }
if len(System.IPAddress) == 0 {
switch len(System.IPAddressesV4) {
case 0:
if len(System.IPAddressesV6) > 0 {
System.IPAddress = System.IPAddressesV6[0]
}
default:
System.IPAddress = System.IPAddressesV4[0]
}
}
System.Hostname, err = os.Hostname() System.Hostname, err = os.Hostname()
if err != nil { if err != nil {
return return

View File

@@ -41,8 +41,8 @@ func BinaryUpdate() (err error) {
resp, err := http.Get(gitInfo) resp, err := http.Get(gitInfo)
if err != nil { if err != nil {
ShowError(err, 0) ShowError(err, 6003)
return err return nil
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
@@ -169,6 +169,13 @@ checkVersion:
if settingsVersion, ok := settingsMap["version"].(string); ok { if settingsVersion, ok := settingsMap["version"].(string); ok {
if settingsVersion > System.DBVersion {
showInfo("Settings DB Version:" + settingsVersion)
showInfo("System DB Version:" + System.DBVersion)
err = errors.New(getErrMsg(1031))
return
}
// Letzte Kompatible Version (1.4.4) // Letzte Kompatible Version (1.4.4)
if settingsVersion < System.Compatibility { if settingsVersion < System.Compatibility {
err = errors.New(getErrMsg(1013)) err = errors.New(getErrMsg(1013))
@@ -204,10 +211,37 @@ checkVersion:
} }
case "2.0.0": case "2.0.0":
if oldBuffer, ok := settingsMap["buffer"].(bool); ok {
var newBuffer string
switch oldBuffer {
case true:
newBuffer = "xteve"
case false:
newBuffer = "-"
}
settingsMap["buffer"] = newBuffer
settingsMap["version"] = "2.1.0"
err = saveMapToJSONFile(System.File.Settings, settingsMap)
if err != nil {
return
}
goto checkVersion
} else {
err = errors.New(getErrMsg(1030))
return
}
case "2.1.0":
// Falls es in einem späteren Update Änderungen an der Datenbank gibt, geht es hier weiter // Falls es in einem späteren Update Änderungen an der Datenbank gibt, geht es hier weiter
break break
} }
} else { } else {

File diff suppressed because one or more lines are too long

View File

@@ -129,20 +129,31 @@ func Stream(w http.ResponseWriter, r *http.Request) {
return return
} }
if strings.Index(streamInfo.URL, "rtsp://") != -1 || strings.Index(streamInfo.URL, "rtp://") != -1 { switch Settings.Buffer {
err = errors.New("RTSP and RTP streams are not supported")
ShowError(err, 2004)
showInfo("Streaming URL:" + streamInfo.URL) case "-":
http.Redirect(w, r, streamInfo.URL, 302) showInfo(fmt.Sprintf("Buffer:false", Settings.Buffer))
case "xteve":
if strings.Index(streamInfo.URL, "rtsp://") != -1 || strings.Index(streamInfo.URL, "rtp://") != -1 {
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)
showInfo("Streaming Info:URL was passed to the client")
return
}
showInfo(fmt.Sprintf("Buffer:true [%s]", Settings.Buffer))
default:
showInfo(fmt.Sprintf("Buffer:true [%s]", Settings.Buffer))
showInfo("Streaming Info:URL was passed to the client")
return
} }
showInfo(fmt.Sprintf("Buffer:%t", Settings.Buffer)) if Settings.Buffer != "-" {
if Settings.Buffer == true {
showInfo(fmt.Sprintf("Buffer Size:%d KB", Settings.BufferSize)) showInfo(fmt.Sprintf("Buffer Size:%d KB", Settings.BufferSize))
} }
@@ -152,16 +163,16 @@ func Stream(w http.ResponseWriter, r *http.Request) {
// Prüfen ob der Buffer verwendet werden soll // Prüfen ob der Buffer verwendet werden soll
switch Settings.Buffer { switch Settings.Buffer {
case true: case "-":
bufferingStream(streamInfo.PlaylistID, streamInfo.URL, streamInfo.Name, w, r)
case false:
showInfo("Streaming URL:" + streamInfo.URL) showInfo("Streaming URL:" + streamInfo.URL)
http.Redirect(w, r, streamInfo.URL, 302) http.Redirect(w, r, streamInfo.URL, 302)
showInfo("Streaming Info:URL was passed to the client.") 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.") showInfo("Streaming Info:xTeVe is no longer involved, the client connects directly to the streaming server.")
default:
bufferingStream(streamInfo.PlaylistID, streamInfo.URL, streamInfo.Name, w, r)
} }
return return

View File

@@ -306,7 +306,6 @@ func createXEPGDatabase() (err error) {
} }
if len(xepgChannel.XChannelID) == 0 { if len(xepgChannel.XChannelID) == 0 {
fmt.Println(mapToJSON(xepgChannel))
delete(Data.XEPG.Channels, id) delete(Data.XEPG.Channels, id)
} }
@@ -316,6 +315,12 @@ func createXEPGDatabase() (err error) {
} }
var xepgChannels = make(map[string]interface{})
for k, v := range Data.XEPG.Channels {
xepgChannels[k] = v
}
for _, dsa := range Data.Streams.Active { for _, dsa := range Data.Streams.Active {
var channelExists = false // Entscheidet ob ein Kanal neu zu Datenbank hinzugefügt werden soll. var channelExists = false // Entscheidet ob ein Kanal neu zu Datenbank hinzugefügt werden soll.
@@ -331,7 +336,7 @@ func createXEPGDatabase() (err error) {
Data.Cache.Streams.Active = append(Data.Cache.Streams.Active, m3uChannel.Name) Data.Cache.Streams.Active = append(Data.Cache.Streams.Active, m3uChannel.Name)
// XEPG Datenbank durchlaufen um nach dem Kanal zu suchen. // XEPG Datenbank durchlaufen um nach dem Kanal zu suchen.
for xepg, dxc := range Data.XEPG.Channels { for xepg, dxc := range xepgChannels {
var xepgChannel XEPGChannelStruct var xepgChannel XEPGChannelStruct
err = json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel) err = json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
@@ -367,6 +372,7 @@ func createXEPGDatabase() (err error) {
//os.Exit(0) //os.Exit(0)
switch channelExists { switch channelExists {
case true: case true:
// Bereits vorhandener Kanal // Bereits vorhandener Kanal
var xepgChannel XEPGChannelStruct var xepgChannel XEPGChannelStruct

View File

@@ -23,7 +23,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")) 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.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"))

View File

@@ -147,7 +147,7 @@ class Content {
var cell:Cell = new Cell() var cell:Cell = new Cell()
cell.child = true cell.child = true
cell.childType = "P" cell.childType = "P"
if (SERVER["settings"]["buffer"] == true) { if (SERVER["settings"]["buffer"] != "-") {
cell.value = data[key]["tuner"] cell.value = data[key]["tuner"]
} else { } else {
cell.value = "-" cell.value = "-"
@@ -1113,7 +1113,7 @@ function openPopUp(dataType, element) {
content.appendRow("{{.playlist.fileM3U.title}}", input) content.appendRow("{{.playlist.fileM3U.title}}", input)
// Tuner // Tuner
if (SERVER["settings"]["buffer"] == true) { if (SERVER["settings"]["buffer"] != "-") {
var text:string[] = new Array() var text:string[] = new Array()
var values:string[] = new Array() var values:string[] = new Array()
@@ -1192,7 +1192,7 @@ function openPopUp(dataType, element) {
content.appendRow("{{.playlist.fileHDHR.title}}", input) content.appendRow("{{.playlist.fileHDHR.title}}", input)
// Tuner // Tuner
if (SERVER["settings"]["buffer"] == true) { if (SERVER["settings"]["buffer"] != "-") {
var text:string[] = new Array() var text:string[] = new Array()
var values:string[] = new Array() var values:string[] = new Array()

View File

@@ -89,6 +89,62 @@ class SettingsCategory {
setting.appendChild(tdRight) setting.appendChild(tdRight)
break break
case "ffmpeg.path":
var tdLeft = document.createElement("TD")
tdLeft.innerHTML = "{{.settings.ffmpegPath.title}}" + ":"
var tdRight = document.createElement("TD")
var input = content.createInput("text", "ffmpeg.path", data)
input.setAttribute("placeholder", "{{.settings.ffmpegPath.placeholder}}")
input.setAttribute("onchange", "javascript: this.className = 'changed'")
tdRight.appendChild(input)
setting.appendChild(tdLeft)
setting.appendChild(tdRight)
break
case "ffmpeg.options":
var tdLeft = document.createElement("TD")
tdLeft.innerHTML = "{{.settings.ffmpegOptions.title}}" + ":"
var tdRight = document.createElement("TD")
var input = content.createInput("text", "ffmpeg.options", data)
input.setAttribute("placeholder", "{{.settings.ffmpegOptions.placeholder}}")
input.setAttribute("onchange", "javascript: this.className = 'changed'")
tdRight.appendChild(input)
setting.appendChild(tdLeft)
setting.appendChild(tdRight)
break
case "vlc.path":
var tdLeft = document.createElement("TD")
tdLeft.innerHTML = "{{.settings.vlcPath.title}}" + ":"
var tdRight = document.createElement("TD")
var input = content.createInput("text", "vlc.path", data)
input.setAttribute("placeholder", "{{.settings.vlcPath.placeholder}}")
input.setAttribute("onchange", "javascript: this.className = 'changed'")
tdRight.appendChild(input)
setting.appendChild(tdLeft)
setting.appendChild(tdRight)
break
case "vlc.options":
var tdLeft = document.createElement("TD")
tdLeft.innerHTML = "{{.settings.vlcOptions.title}}" + ":"
var tdRight = document.createElement("TD")
var input = content.createInput("text", "vlc.options", data)
input.setAttribute("placeholder", "{{.settings.vlcOptions.placeholder}}")
input.setAttribute("onchange", "javascript: this.className = 'changed'")
tdRight.appendChild(input)
setting.appendChild(tdLeft)
setting.appendChild(tdRight)
break
// Checkboxen // Checkboxen
case "authentication.web": case "authentication.web":
var tdLeft = document.createElement("TD") var tdLeft = document.createElement("TD")
@@ -216,20 +272,6 @@ class SettingsCategory {
setting.appendChild(tdRight) setting.appendChild(tdRight)
break break
case "buffer":
var tdLeft = document.createElement("TD")
tdLeft.innerHTML = "{{.settings.streamBuffering.title}}" + ":"
var tdRight = document.createElement("TD")
var input = content.createCheckbox(settingsKey)
input.checked = data
input.setAttribute("onchange", "javascript: this.className = 'changed'")
tdRight.appendChild(input)
setting.appendChild(tdLeft)
setting.appendChild(tdRight)
break
case "api": case "api":
var tdLeft = document.createElement("TD") var tdLeft = document.createElement("TD")
tdLeft.innerHTML = "{{.settings.api.title}}" + ":" tdLeft.innerHTML = "{{.settings.api.title}}" + ":"
@@ -314,6 +356,22 @@ class SettingsCategory {
setting.appendChild(tdRight) setting.appendChild(tdRight)
break break
case "buffer":
var tdLeft = document.createElement("TD")
tdLeft.innerHTML = "{{.settings.streamBuffering.title}}" + ":"
var tdRight = document.createElement("TD")
var text:any[] = ["{{.settings.streamBuffering.info_false}}", "xTeVe: ({{.settings.streamBuffering.info_xteve}})", "FFmpeg: ({{.settings.streamBuffering.info_ffmpeg}})", "VLC: ({{.settings.streamBuffering.info_vlc}})"]
var values:any[] = ["-", "xteve", "ffmpeg", "vlc"]
var select = content.createSelect(text, values, data, settingsKey)
select.setAttribute("onchange", "javascript: this.className = 'changed'")
tdRight.appendChild(select)
setting.appendChild(tdLeft)
setting.appendChild(tdRight)
break
} }
return setting return setting
@@ -381,6 +439,22 @@ class SettingsCategory {
text = "{{.settings.userAgent.description}}" text = "{{.settings.userAgent.description}}"
break break
case "ffmpeg.path":
text = "{{.settings.ffmpegPath.description}}"
break
case "ffmpeg.options":
text = "{{.settings.ffmpegOptions.description}}"
break
case "vlc.path":
text = "{{.settings.vlcPath.description}}"
break
case "vlc.options":
text = "{{.settings.vlcOptions.description}}"
break
case "epgSource": case "epgSource":
text = "{{.settings.epgSource.description}}" text = "{{.settings.epgSource.description}}"
break break

View File

@@ -35,14 +35,14 @@ var GitHub = GitHubStruct{Branch: "master", User: "xteve-project", Repo: "xTeVe-
Update: Automatic updates from the GitHub repository [true|false] Update: Automatic updates from the GitHub repository [true|false]
*/ */
// Name : Programname // Name : Programmname
const Name = "xTeVe" const Name = "xTeVe"
// Version : Version, die Build Nummer wird in der main func geparst. // Version : Version, die Build Nummer wird in der main func geparst.
const Version = "2.0.2.0020" const Version = "2.1.0.0100"
// DBVersion : Datanbank Version // DBVersion : Datanbank Version
const DBVersion = "2.0.0" const DBVersion = "2.1.0"
// APIVersion : API Version // APIVersion : API Version
const APIVersion = "1.1.0" const APIVersion = "1.1.0"