Compare commits
43 Commits
v2.0.0.000
...
2.0.3.0030
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11453c6053 | ||
|
|
81e8ae33d7 | ||
|
|
f3be0fca47 | ||
|
|
1c1c89cd74 | ||
|
|
3d73dba422 | ||
|
|
c6e74fe11c | ||
|
|
18dba46c02 | ||
|
|
efa55b39a9 | ||
|
|
717fa68b7e | ||
|
|
878531ff79 | ||
|
|
792fd9a373 | ||
|
|
a1ec0287ef | ||
|
|
a79e824ef8 | ||
|
|
c843f424fe | ||
|
|
5c6637c048 | ||
|
|
1062e072d6 | ||
|
|
d831a099f0 | ||
|
|
a06baef4d3 | ||
|
|
f9d1a45bbd | ||
|
|
8a4fb8ba30 | ||
|
|
28dad4932b | ||
|
|
1769b1e6db | ||
|
|
30ab13f871 | ||
|
|
0f37835206 | ||
|
|
67fe80b4fd | ||
|
|
96e10ff51d | ||
|
|
d550beaa01 | ||
|
|
00ec32456c | ||
|
|
b3600f8a14 | ||
|
|
849493a802 | ||
|
|
3730d1187d | ||
|
|
2a06bf6b01 | ||
|
|
c389b990b4 | ||
|
|
56f3e3389b | ||
|
|
50e6ed274e | ||
|
|
8490187d31 | ||
|
|
4dc9dfabf2 | ||
|
|
5fc5f773d3 | ||
|
|
c9bc4aedbc | ||
|
|
51bab26d59 | ||
|
|
0063dcc523 | ||
|
|
23dd3ef08c | ||
|
|
9b84982bab |
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Please only useful feature request.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.DS_Store
|
||||
demo
|
||||
compiler
|
||||
files
|
||||
update_xteve*.sh
|
||||
|
||||
42
README.md
42
README.md
@@ -65,10 +65,11 @@ Thanks to @alturismo and @LeeD for creating the Docker Images.
|
||||
**Created by alturismo:**
|
||||
[xTeVe](https://hub.docker.com/r/alturismo/xteve)
|
||||
[xTeVe / Guide2go](https://hub.docker.com/r/alturismo/xteve_guide2go)
|
||||
[xTeVe / Guide2go / owi2plex](https://hub.docker.com/r/alturismo/xteve_g2g_owi)
|
||||
|
||||
Including:
|
||||
- Guide2go: XMLTV grabber for Schedules Direct
|
||||
|
||||
- owi2plex: XMLTV file grabber for Enigma receivers
|
||||
|
||||
**Created by LeeD:**
|
||||
[xTeVe / Guide2go / Zap2XML](https://hub.docker.com/r/dnsforge/xteve)
|
||||
@@ -82,19 +83,50 @@ Including:
|
||||
|
||||
---
|
||||
|
||||
### xTeVe Beta branch
|
||||
New features and bug fixes are only available in beta brunch. Only after successful testing, they are merged into the master branch.
|
||||
|
||||
**It is not recommended to use the beta version in a production system.**
|
||||
|
||||
With the command line argument `branch` the Git Branch can be changed. xTeVe must be started via the terminal.
|
||||
|
||||
#### Switch from master to beta branch:
|
||||
```
|
||||
xteve -branch beta
|
||||
|
||||
...
|
||||
[xTeVe] GitHub: https://github.com/xteve-project
|
||||
[xTeVe] Git Branch: beta [xteve-project]
|
||||
...
|
||||
```
|
||||
|
||||
#### Switch from beta to master branch:
|
||||
```
|
||||
xteve -branch master
|
||||
|
||||
...
|
||||
[xTeVe] GitHub: https://github.com/xteve-project
|
||||
[xTeVe] Git Branch: master [xteve-project]
|
||||
...
|
||||
```
|
||||
|
||||
When the branch is changed, an update is only performed if there is a new version and the update function is activated in the settings.
|
||||
|
||||
---
|
||||
|
||||
## Build from source code [Go / Golang]
|
||||
|
||||
#### Requirements
|
||||
* Go (go1.12.4 or newer)
|
||||
* [Go](https://golang.org) (go1.12.4 or newer)
|
||||
|
||||
#### Dependancys
|
||||
#### Dependencies
|
||||
* [go-ssdp](https://github.com/koron/go-ssdp)
|
||||
* [websocket](https://github.com/gorilla/websocket)
|
||||
* [osext](https://github.com/kardianos/osext)
|
||||
|
||||
#### Build
|
||||
1. Download source code
|
||||
2. Install dependancys
|
||||
2. Install dependencies
|
||||
```
|
||||
go get github.com/koron/go-ssdp
|
||||
go get github.com/gorilla/websocket
|
||||
@@ -108,7 +140,7 @@ go build xteve.go
|
||||
---
|
||||
|
||||
## Fork without pull request :mega:
|
||||
When creating a fork, the xTeVe GitHub account must be changed from the sorce code or the update function disabled.
|
||||
When creating a fork, the xTeVe GitHub account must be changed from the source code or the update function disabled.
|
||||
Future updates of the xteve-project would update your fork. :wink:
|
||||
|
||||
xteve.go - Line: 29
|
||||
|
||||
47
changelog-beta.md
Normal file
47
changelog-beta.md
Normal file
@@ -0,0 +1,47 @@
|
||||
#### 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
|
||||
```diff
|
||||
+ Add support for "video/m2ts" video streams (Pull request #14)
|
||||
```
|
||||
#### 2.0.1.0011-beta
|
||||
```diff
|
||||
+ Original group title is shown in the Mapping Editor
|
||||
```
|
||||
##### Fixes
|
||||
- incorrect original-air-date
|
||||
|
||||
#### 2.0.1.0010-beta
|
||||
```diff
|
||||
+ Set timestamp to <episode-num system="original-air-date">
|
||||
```
|
||||
|
||||
#### 2.0.0.0008-beta
|
||||
##### Fixes
|
||||
- Pull request #6 [Error in http/https detection] window.location.protocol return "https:", not "https://"
|
||||
|
||||
#### 2.0.0.0007-beta
|
||||
```diff
|
||||
+ Buffer HLS: Add VOD tag from M3U8
|
||||
+ CLI: Add new arguments [-restore]
|
||||
+ CLI: Add new arguments [-info]
|
||||
```
|
||||
##### Fixes
|
||||
- Missing images with caching for localhost URL
|
||||
|
||||
|
||||
#### 2.0.0.0001-beta
|
||||
```diff
|
||||
+ Wizard: Add HTML input placeholder (M3U, XMLTV)
|
||||
+ Wizard: Alert by empty value (M3U, XMLTV)
|
||||
+ Image caching: Ignore invalid image URLs
|
||||
```
|
||||
@@ -299,6 +299,8 @@ tbody {
|
||||
|
||||
#content_table input[type=text]{
|
||||
width: 80%;
|
||||
min-width: 35px;
|
||||
max-width: 60px;
|
||||
border: 0px;
|
||||
background-color: #333;
|
||||
margin-left: 5px;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
h1 {
|
||||
color: green;
|
||||
}
|
||||
@@ -63,6 +63,7 @@ var WizardItem = /** @class */ (function (_super) {
|
||||
break;
|
||||
case "m3u":
|
||||
var input = content.createInput("text", key, "");
|
||||
input.setAttribute("placeholder", "{{.wizard.m3u.placeholder}}");
|
||||
input.setAttribute("class", "wizard");
|
||||
input.id = key;
|
||||
doc.appendChild(input);
|
||||
@@ -70,6 +71,7 @@ var WizardItem = /** @class */ (function (_super) {
|
||||
break;
|
||||
case "xmltv":
|
||||
var input = content.createInput("text", key, "");
|
||||
input.setAttribute("placeholder", "{{.wizard.xmltv.placeholder}}");
|
||||
input.setAttribute("class", "wizard");
|
||||
input.id = key;
|
||||
doc.appendChild(input);
|
||||
@@ -117,6 +119,11 @@ function saveWizard() {
|
||||
case "text":
|
||||
name = config[i].name;
|
||||
value = config[i].value;
|
||||
if (value.length == 0) {
|
||||
var msg = name.toUpperCase() + ": " + "{{.alert.missingInput}}";
|
||||
alert(msg);
|
||||
return;
|
||||
}
|
||||
wizard[name] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -583,7 +583,7 @@ var ShowContent = /** @class */ (function (_super) {
|
||||
return;
|
||||
break;
|
||||
case "log":
|
||||
var input = this.createInput("button", menuKey, "{{.button.resetlogs}}");
|
||||
var input = this.createInput("button", menuKey, "{{.button.resetLogs}}");
|
||||
input.setAttribute("onclick", 'javascript: resetLogs();');
|
||||
interaction.appendChild(input);
|
||||
var wrapper = document.createElement("DIV");
|
||||
@@ -1252,6 +1252,7 @@ function openPopUp(dataType, element) {
|
||||
input.setAttribute("readonly", "true");
|
||||
}
|
||||
content.appendRow("{{.mapping.channelName.title}}", input);
|
||||
content.description(data["name"]);
|
||||
// Aktualisierung des Kanalnamens
|
||||
if (data.hasOwnProperty("_uuid.key")) {
|
||||
if (data["_uuid.key"] != "") {
|
||||
@@ -1287,6 +1288,9 @@ function openPopUp(dataType, element) {
|
||||
var input = content.createInput("text", dbKey, data[dbKey]);
|
||||
input.setAttribute("onchange", "javascript: this.className = 'changed'");
|
||||
content.appendRow("{{.mapping.m3uGroupTitle.title}}", input);
|
||||
if (data["group-title"] != undefined) {
|
||||
content.description(data["group-title"]);
|
||||
}
|
||||
// XMLTV Datei
|
||||
var dbKey = "x-xmltv-file";
|
||||
var xmlFile = data[dbKey];
|
||||
|
||||
@@ -16,7 +16,7 @@ var Server = /** @class */ (function () {
|
||||
case "http:":
|
||||
this.protocol = "ws://";
|
||||
break;
|
||||
case "https://":
|
||||
case "https:":
|
||||
this.protocol = "wss://";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -23,11 +23,12 @@
|
||||
}
|
||||
},
|
||||
"confirm":{
|
||||
"restore": "All data will be replaced with those from the backup.Should the files be restored?"
|
||||
"restore": "All data will be replaced with those from the backup. Should the files be restored?"
|
||||
},
|
||||
"alert": {
|
||||
"fileLoadingError": "File couldn't be loaded",
|
||||
"invalidChannelNumber": "Invalid channel number"
|
||||
"invalidChannelNumber": "Invalid channel number",
|
||||
"missingInput": "Missing input"
|
||||
},
|
||||
"button":{
|
||||
"back": "Back",
|
||||
@@ -44,7 +45,7 @@
|
||||
"search": "Search",
|
||||
"update": "Update",
|
||||
"craeteAccount": "Create Account",
|
||||
"resetlogs": "Reset Logs",
|
||||
"resetLogs": "Reset Logs",
|
||||
"uploadLogo": "Upload Logo"
|
||||
},
|
||||
"filter": {
|
||||
@@ -242,7 +243,7 @@
|
||||
},
|
||||
"password": {
|
||||
"title": "Password",
|
||||
"placeholder": "Passoword",
|
||||
"placeholder": "Password",
|
||||
"description": ""
|
||||
},
|
||||
"confirm": {
|
||||
@@ -319,7 +320,7 @@
|
||||
},
|
||||
"streamBuffering": {
|
||||
"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"
|
||||
"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"
|
||||
},
|
||||
"bufferSize": {
|
||||
"title": "Buffer Size",
|
||||
@@ -381,10 +382,12 @@
|
||||
},
|
||||
"m3u": {
|
||||
"title": "M3U Playlist",
|
||||
"placeholder": "File path or URL of the M3U",
|
||||
"description": "Local or remote playlists"
|
||||
},
|
||||
"xmltv": {
|
||||
"title": "XMLTV File",
|
||||
"placeholder": "File path or URL of the XMLTV",
|
||||
"description": "Local or remote XMLTV file"
|
||||
}
|
||||
},
|
||||
|
||||
109
src/backup.go
109
src/backup.go
@@ -2,6 +2,7 @@ package src
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -124,35 +125,44 @@ func xteveBackup() (archiv string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func xteveRestore(input string) (newWebURL string, err error) {
|
||||
func xteveRestore(archive string) (newWebURL string, err error) {
|
||||
|
||||
var newPort, oldPort string
|
||||
var newPort, oldPort, backupVersion, tmpRestore string
|
||||
|
||||
// Base64 Json String in base64 umwandeln
|
||||
b64data := input[strings.IndexByte(input, ',')+1:]
|
||||
|
||||
// Base64 in bytes umwandeln und speichern
|
||||
sDec, err := b64.StdEncoding.DecodeString(b64data)
|
||||
tmpRestore = System.Folder.Temp + "restore" + string(os.PathSeparator)
|
||||
|
||||
err = checkFolder(tmpRestore)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var archive = System.Folder.Temp + "restore.zip"
|
||||
|
||||
err = writeByteToFile(archive, sDec)
|
||||
// Zip Archiv in tmp entpacken
|
||||
err = extractZIP(archive, tmpRestore)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Zip Archiv entpacken
|
||||
// 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
|
||||
}
|
||||
|
||||
// Zip Archiv in den Config Ordner entpacken
|
||||
err = extractZIP(archive, System.Folder.Config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Neue Config laden um den Port zu überprüfen
|
||||
newConfig, err := loadJSONFileToMap(System.Folder.Config + "settings.json")
|
||||
// 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
|
||||
@@ -187,5 +197,78 @@ func xteveRestore(input string) (newWebURL string, err error) {
|
||||
var url = System.URLBase + "/web/"
|
||||
newWebURL = strings.Replace(url, ":"+oldPort, ":"+newPort, 1)
|
||||
|
||||
os.RemoveAll(tmpRestore)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func xteveRestoreFromWeb(input string) (newWebURL string, err error) {
|
||||
|
||||
// Base64 Json String in base64 umwandeln
|
||||
b64data := input[strings.IndexByte(input, ',')+1:]
|
||||
|
||||
// Base64 in bytes umwandeln und speichern
|
||||
sDec, err := b64.StdEncoding.DecodeString(b64data)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var archive = System.Folder.Temp + "restore.zip"
|
||||
|
||||
err = writeByteToFile(archive, sDec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newWebURL, err = xteveRestore(archive)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// XteveRestoreFromCLI : Wiederherstellung über die Kommandozeile
|
||||
func XteveRestoreFromCLI(archive string) (err error) {
|
||||
|
||||
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()
|
||||
|
||||
fmt.Print("All data will be replaced with those from the backup. Should the files be restored? [yes|no]:")
|
||||
|
||||
fmt.Scanln(&confirm)
|
||||
|
||||
switch strings.ToLower(confirm) {
|
||||
|
||||
case "yes":
|
||||
break
|
||||
|
||||
case "no":
|
||||
return
|
||||
|
||||
default:
|
||||
fmt.Println("Invalid input")
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
if len(System.Folder.Config) > 0 {
|
||||
|
||||
err = checkFilePermission(System.Folder.Config)
|
||||
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))
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
playlist.Streams[streamID] = stream
|
||||
BufferInformation.Store(playlistID, playlist)
|
||||
|
||||
go connectToStreamingServer(streamID, playlist)
|
||||
go connectToStreamingServer(streamID, playlistID)
|
||||
|
||||
showInfo(fmt.Sprintf("Streaming Status:Playlist: %s - Tuner: %d / %d", playlist.PlaylistName, len(playlist.Streams), playlist.Tuner))
|
||||
|
||||
@@ -219,6 +219,10 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
|
||||
for { // Loop 1: Warten bis das erste Segment durch den Buffer heruntergeladen wurde
|
||||
|
||||
if p, ok := BufferInformation.Load(playlistID); ok {
|
||||
|
||||
var playlist = p.(Playlist)
|
||||
|
||||
if stream, ok := playlist.Streams[streamID]; ok {
|
||||
|
||||
if stream.Status == false {
|
||||
@@ -377,6 +381,8 @@ func bufferingStream(playlistID, streamingURL, channelName string, w http.Respon
|
||||
|
||||
}
|
||||
|
||||
} // Ende BufferInformation
|
||||
|
||||
} // Ende Loop 1
|
||||
|
||||
}
|
||||
@@ -507,7 +513,11 @@ func clientConnection(stream ThisStream) (status bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func connectToStreamingServer(streamID int, playlist Playlist) {
|
||||
func connectToStreamingServer(streamID int, playlistID string) {
|
||||
|
||||
if p, ok := BufferInformation.Load(playlistID); ok {
|
||||
|
||||
var playlist = p.(Playlist)
|
||||
|
||||
var timeOut = 0
|
||||
var debug string
|
||||
@@ -548,11 +558,11 @@ func connectToStreamingServer(streamID int, playlist Playlist) {
|
||||
|
||||
var stream = playlist.Streams[streamID]
|
||||
|
||||
if c, ok := BufferClients.Load(stream.PlaylistID + stream.MD5); ok {
|
||||
if c, ok := BufferClients.Load(playlistID + stream.MD5); ok {
|
||||
|
||||
var clients = c.(ClientConnection)
|
||||
clients.Error = err
|
||||
BufferClients.Store(stream.PlaylistID+stream.MD5, clients)
|
||||
BufferClients.Store(playlistID+stream.MD5, clients)
|
||||
|
||||
}
|
||||
|
||||
@@ -568,7 +578,7 @@ func connectToStreamingServer(streamID int, playlist Playlist) {
|
||||
}
|
||||
|
||||
// M3U8 Segmente
|
||||
InitBuffer:
|
||||
InitBuffer:
|
||||
defaultSegment()
|
||||
|
||||
if len(m3u8Segments) > 30 {
|
||||
@@ -650,7 +660,7 @@ InitBuffer:
|
||||
|
||||
addErrorToStream(err)
|
||||
|
||||
killClientConnection(streamID, stream.PlaylistID, true)
|
||||
killClientConnection(streamID, playlistID, true)
|
||||
clientConnection(stream)
|
||||
|
||||
return
|
||||
@@ -709,7 +719,7 @@ InitBuffer:
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
|
||||
showInfo("Content type:" + contentType)
|
||||
showInfo("Content Type:" + contentType)
|
||||
showInfo("Streaming Status:" + httpStatusInfo)
|
||||
showInfo("Error with this URL:" + currentURL)
|
||||
|
||||
@@ -722,7 +732,7 @@ InitBuffer:
|
||||
BufferInformation.Store(playlist.PlaylistID, playlist)
|
||||
addErrorToStream(err)
|
||||
|
||||
killClientConnection(streamID, stream.PlaylistID, true)
|
||||
killClientConnection(streamID, playlistID, true)
|
||||
clientConnection(stream)
|
||||
resp.Body.Close()
|
||||
|
||||
@@ -754,7 +764,7 @@ InitBuffer:
|
||||
showDebug(debug, 1)
|
||||
|
||||
showInfo("Streaming Status:" + "HTTP Response Status [" + strconv.Itoa(resp.StatusCode) + "] " + http.StatusText(resp.StatusCode))
|
||||
showInfo("Content type:" + contentType)
|
||||
showInfo("Content Type:" + contentType)
|
||||
|
||||
} else {
|
||||
|
||||
@@ -790,7 +800,7 @@ InitBuffer:
|
||||
}
|
||||
|
||||
// Video Stream (TS)
|
||||
case "video/mpeg", "video/mp4", "video/mp2t", "application/octet-stream":
|
||||
case "video/mpeg", "video/mp4", "video/mp2t", "video/m2ts", "application/octet-stream", "binary/octet-stream", "application/mp2t":
|
||||
|
||||
var fileSize int
|
||||
|
||||
@@ -891,6 +901,8 @@ InitBuffer:
|
||||
|
||||
stream.Status = true
|
||||
playlist.Streams[streamID] = stream
|
||||
BufferInformation.Store(playlistID, playlist)
|
||||
|
||||
tmpSegment++
|
||||
|
||||
tmpFile = fmt.Sprintf("%s%d.ts", tmpFolder, tmpSegment)
|
||||
@@ -931,7 +943,7 @@ InitBuffer:
|
||||
|
||||
// Umbekanntes Format
|
||||
default:
|
||||
showInfo("Content type:" + resp.Header.Get("Content-Type"))
|
||||
showInfo("Content Type:" + resp.Header.Get("Content-Type"))
|
||||
err = errors.New("Streaming error")
|
||||
ShowError(err, 4003)
|
||||
|
||||
@@ -986,6 +998,8 @@ InitBuffer:
|
||||
|
||||
} // Ende for loop
|
||||
|
||||
} // Ende BufferInformation
|
||||
|
||||
}
|
||||
|
||||
func parseM3U8(stream *ThisStream) (err error) {
|
||||
@@ -1027,7 +1041,7 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
|
||||
line = strings.Trim(line, "\r\n")
|
||||
|
||||
var parameters = []string{"#EXT-X-VERSION:", "#EXT-X-MEDIA-SEQUENCE:", "#EXT-X-STREAM-INF:", "#EXTINF:"}
|
||||
var parameters = []string{"#EXT-X-VERSION:", "#EXT-X-PLAYLIST-TYPE:", "#EXT-X-MEDIA-SEQUENCE:", "#EXT-X-STREAM-INF:", "#EXTINF:"}
|
||||
|
||||
for _, parameter := range parameters {
|
||||
|
||||
@@ -1043,6 +1057,9 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
segment.Version = version
|
||||
}
|
||||
|
||||
case "#EXT-X-PLAYLIST-TYPE:":
|
||||
segment.PlaylistType = value
|
||||
|
||||
case "#EXT-X-MEDIA-SEQUENCE:":
|
||||
n, err := strconv.ParseInt(value, 10, 64)
|
||||
if err == nil {
|
||||
@@ -1194,6 +1211,11 @@ func parseM3U8(stream *ThisStream) (err error) {
|
||||
noNewSegment = false
|
||||
stream.LastSequence = segment.Sequence
|
||||
|
||||
// Stream ist vom Typ VOD. Es muss das erste Segment der M3U8 Playlist verwendet werden.
|
||||
if strings.ToUpper(segment.PlaylistType) == "VOD" {
|
||||
break
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if segment.Sequence > stream.LastSequence {
|
||||
|
||||
@@ -83,6 +83,11 @@ func Init() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(System.Flag.Restore) > 0 {
|
||||
// Einstellungen werden über CLI wiederhergestellt. Weitere Initialisierung ist nicht notwendig.
|
||||
return
|
||||
}
|
||||
|
||||
System.File.XML = getPlatformFile(fmt.Sprintf("%s%s.xml", System.Folder.Data, System.AppName))
|
||||
System.File.M3U = getPlatformFile(fmt.Sprintf("%s%s.m3u", System.Folder.Data, System.AppName))
|
||||
|
||||
@@ -104,7 +109,7 @@ func Init() (err error) {
|
||||
|
||||
// Überprüfen ob xTeVe als root läuft
|
||||
if os.Geteuid() == 0 {
|
||||
showWarning(2010)
|
||||
showWarning(2110)
|
||||
}
|
||||
|
||||
if System.Flag.Debug > 0 {
|
||||
@@ -113,6 +118,7 @@ func Init() (err error) {
|
||||
}
|
||||
|
||||
showInfo(fmt.Sprintf("Version:%s Build: %s", System.Version, System.Build))
|
||||
showInfo(fmt.Sprintf("Database Version:%s", System.DBVersion))
|
||||
showInfo(fmt.Sprintf("System IP Addresses:IPv4: %d | IPv6: %d", len(System.IPAddressesV4), len(System.IPAddressesV6)))
|
||||
showInfo("Hostname:" + System.Hostname)
|
||||
showInfo(fmt.Sprintf("System Folder:%s", getPlatformPath(System.Folder.Config)))
|
||||
@@ -160,9 +166,6 @@ func Init() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// DLNA Server starten
|
||||
go SSDP()
|
||||
|
||||
// Branch festlegen
|
||||
System.Branch = Settings.Branch
|
||||
|
||||
@@ -193,6 +196,13 @@ func Init() (err error) {
|
||||
|
||||
}
|
||||
|
||||
// DLNA Server starten
|
||||
err = SSDP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// HTML Datein laden
|
||||
loadHTMLMap()
|
||||
|
||||
return
|
||||
|
||||
69
src/data.go
69
src/data.go
@@ -37,17 +37,25 @@ func updateServerSettings(request RequestStruct) (settings SettingsStrcut, err e
|
||||
reloadData = true
|
||||
|
||||
case "update":
|
||||
// Die Formatierung der Uhrzeit überprüfen (0000 - 2359)
|
||||
for _, i := range newSettings[key].([]interface{}) {
|
||||
// Leerzeichen aus den Werten entfernen und Formatierung der Uhrzeit überprüfen (0000 - 2359)
|
||||
var newUpdateTimes []string
|
||||
|
||||
_, err := time.Parse("1504", i.(string))
|
||||
for _, v := range value.([]interface{}) {
|
||||
|
||||
v = strings.Replace(v.(string), " ", "", -1)
|
||||
|
||||
_, err := time.Parse("1504", v.(string))
|
||||
if err != nil {
|
||||
ShowError(err, 1012)
|
||||
return Settings, err
|
||||
}
|
||||
|
||||
newUpdateTimes = append(newUpdateTimes, v.(string))
|
||||
|
||||
}
|
||||
|
||||
value = newUpdateTimes
|
||||
|
||||
case "cache.images":
|
||||
cacheImages = true
|
||||
|
||||
@@ -358,6 +366,7 @@ func saveFilter(request RequestStruct) (settings SettingsStrcut, err error) {
|
||||
var filterMap = make(map[int64]interface{})
|
||||
var newData = make(map[int64]interface{})
|
||||
var defaultFilter FilterStruct
|
||||
var newFilter = false
|
||||
|
||||
defaultFilter.Active = true
|
||||
defaultFilter.CaseSensitive = false
|
||||
@@ -381,6 +390,7 @@ func saveFilter(request RequestStruct) (settings SettingsStrcut, err error) {
|
||||
if dataID == -1 {
|
||||
|
||||
// Neuer Filter
|
||||
newFilter = true
|
||||
dataID = createNewID()
|
||||
filterMap[dataID] = jsonToMap(mapToJSON(defaultFilter))
|
||||
|
||||
@@ -389,15 +399,28 @@ func saveFilter(request RequestStruct) (settings SettingsStrcut, err error) {
|
||||
// Filter aktualisieren / löschen
|
||||
for key, value := range data.(map[string]interface{}) {
|
||||
|
||||
var oldData = filterMap[dataID].(map[string]interface{})
|
||||
oldData[key] = value
|
||||
|
||||
// Filter löschen
|
||||
if _, ok := data.(map[string]interface{})["delete"]; ok {
|
||||
|
||||
delete(filterMap, dataID)
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -438,8 +461,39 @@ func saveXEpgMapping(request RequestStruct) (err error) {
|
||||
|
||||
Data.XEPG.Channels = request.EpgMapping
|
||||
|
||||
if System.ScanInProgress == 0 {
|
||||
|
||||
cleanupXEPG()
|
||||
buildXEPG(true)
|
||||
|
||||
} 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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cleanupXEPG()
|
||||
buildXEPG(false)
|
||||
|
||||
System.BackgroundProcess = false
|
||||
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -604,6 +658,7 @@ func saveWizard(request RequestStruct) (nextStep int, err error) {
|
||||
}
|
||||
|
||||
buildXEPG(false)
|
||||
System.ScanInProgress = 0
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ func getLineupStatus() (jsonContent []byte, err error) {
|
||||
lineupStatus.ScanInProgress = System.ScanInProgress
|
||||
lineupStatus.ScanPossible = 0
|
||||
lineupStatus.Source = "Cable"
|
||||
lineupStatus.SourceList = []string{"IPTV", "Cable"}
|
||||
lineupStatus.SourceList = []string{"Cable"}
|
||||
|
||||
jsonContent, err = json.MarshalIndent(lineupStatus, "", " ")
|
||||
|
||||
|
||||
@@ -6,24 +6,41 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getCacheImageURL(url string) (cacheImageURL string) {
|
||||
func getCacheImageURL(imageURL string) (cacheImageURL string) {
|
||||
|
||||
url = strings.Trim(url, "\r\n")
|
||||
if Settings.CacheImages == false {
|
||||
return imageURL
|
||||
}
|
||||
|
||||
var urlMD5 = getMD5(url)
|
||||
var fileExtension = filepath.Ext(url)
|
||||
imageURL = strings.Trim(imageURL, "\r\n")
|
||||
|
||||
p, err := url.Parse(imageURL)
|
||||
if err != nil {
|
||||
// URL konnte nicht geparst werden, die ursprüngliche image url wird zurückgegeben
|
||||
showInfo(fmt.Sprintf("Image Caching:Image URL: %s", imageURL))
|
||||
showWarning(4101)
|
||||
return imageURL
|
||||
}
|
||||
var urlMD5 = getMD5(imageURL)
|
||||
var fileExtension = filepath.Ext(p.Path)
|
||||
|
||||
if len(fileExtension) == 0 {
|
||||
// Keine Dateierweiterung vorhanden, die ursprüngliche image url wird zurückgegeben
|
||||
return imageURL
|
||||
}
|
||||
|
||||
if indexOfString(urlMD5+fileExtension, Data.Cache.ImagesFiles) == -1 {
|
||||
Data.Cache.ImagesFiles = append(Data.Cache.ImagesFiles, urlMD5+fileExtension)
|
||||
}
|
||||
|
||||
if Settings.CacheImages == false || System.ImageCachingInProgress == 1 {
|
||||
return url
|
||||
if System.ImageCachingInProgress == 1 {
|
||||
return imageURL
|
||||
}
|
||||
|
||||
if indexOfString(urlMD5+fileExtension, Data.Cache.ImagesCache) != -1 {
|
||||
@@ -32,15 +49,15 @@ func getCacheImageURL(url string) (cacheImageURL string) {
|
||||
|
||||
} else {
|
||||
|
||||
if strings.Contains(url, System.Domain+"/images/") == false {
|
||||
if strings.Contains(imageURL, System.Domain+"/images/") == false {
|
||||
|
||||
if indexOfString(url, Data.Cache.ImagesURLS) == -1 {
|
||||
Data.Cache.ImagesURLS = append(Data.Cache.ImagesURLS, url)
|
||||
if indexOfString(imageURL, Data.Cache.ImagesURLS) == -1 {
|
||||
Data.Cache.ImagesURLS = append(Data.Cache.ImagesURLS, imageURL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cacheImageURL = url
|
||||
cacheImageURL = imageURL
|
||||
|
||||
}
|
||||
|
||||
@@ -57,10 +74,10 @@ func cachingImages() {
|
||||
|
||||
showInfo("Image Caching:Images are cached")
|
||||
|
||||
for _, url := range Data.Cache.ImagesURLS {
|
||||
for _, imageURL := range Data.Cache.ImagesURLS {
|
||||
|
||||
if len(url) > 0 {
|
||||
cacheImage(url)
|
||||
if len(imageURL) > 0 {
|
||||
cacheImage(imageURL)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -94,16 +111,16 @@ func cachingImages() {
|
||||
return
|
||||
}
|
||||
|
||||
func cacheImage(url string) {
|
||||
func cacheImage(imageURL string) {
|
||||
|
||||
var debug string
|
||||
var urlMD5 = getMD5(url)
|
||||
var fileExtension = filepath.Ext(url)
|
||||
var urlMD5 = getMD5(imageURL)
|
||||
var fileExtension = filepath.Ext(imageURL)
|
||||
|
||||
debug = fmt.Sprintf("Image Caching:File: %s Download: %s", urlMD5+fileExtension, url)
|
||||
debug = fmt.Sprintf("Image Caching:File: %s Download: %s", urlMD5+fileExtension, imageURL)
|
||||
showDebug(debug, 1)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
resp, err := http.Get(imageURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
99
src/info.go
Normal file
99
src/info.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package src
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ShowSystemInfo : Systeminformationen anzeigen
|
||||
func ShowSystemInfo() {
|
||||
|
||||
fmt.Print("Creating the information takes a moment...")
|
||||
err := buildDatabaseDVR()
|
||||
if err != nil {
|
||||
ShowError(err, 0)
|
||||
return
|
||||
}
|
||||
|
||||
buildXEPG(false)
|
||||
|
||||
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("GitHub: %s/%s | Git update = %t", System.GitHub.User, System.GitHub.Repo, System.GitHub.Update))
|
||||
fmt.Println(fmt.Sprintf("Folder (config): %s", 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)))
|
||||
|
||||
println()
|
||||
fmt.Println(fmt.Sprintf("IPv4 Addresses:"))
|
||||
|
||||
for i, ipv4 := range System.IPAddressesV4 {
|
||||
|
||||
switch count := i; {
|
||||
|
||||
case count < 10:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
case count < 100:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
println()
|
||||
fmt.Println(fmt.Sprintf("IPv6 Addresses:"))
|
||||
|
||||
for i, ipv4 := range System.IPAddressesV6 {
|
||||
|
||||
switch count := i; {
|
||||
|
||||
case count < 10:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
case count < 100:
|
||||
fmt.Println(fmt.Sprintf(" %d. %s", count, ipv4))
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
println("---")
|
||||
|
||||
fmt.Println("Settings [General]")
|
||||
fmt.Println(fmt.Sprintf("xTeVe Update: %t", Settings.XteveAutoUpdate))
|
||||
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))
|
||||
|
||||
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("Replace EPG Image: %t", Settings.XepgReplaceMissingImages))
|
||||
|
||||
println("---")
|
||||
|
||||
fmt.Println("Settings [Streaming]")
|
||||
fmt.Println(fmt.Sprintf("Buffer: %t", Settings.Buffer))
|
||||
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))
|
||||
|
||||
println("---")
|
||||
|
||||
fmt.Println("Settings [Backup]")
|
||||
fmt.Println(fmt.Sprintf("Folder (backup): %s", Settings.BackupPath))
|
||||
fmt.Println(fmt.Sprintf("Backup Keep: %d", Settings.BackupKeep))
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package m3u
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -12,6 +14,7 @@ func MakeInterfaceFromM3U(byteStream []byte) (allChannels []interface{}, err err
|
||||
|
||||
var content = string(byteStream)
|
||||
var channelName string
|
||||
var uuids []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)
|
||||
|
||||
p = strings.Replace(p, `"`, "", -1)
|
||||
var parameter = strings.Split(p, "=")
|
||||
var parameter = strings.SplitN(p, "=", 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 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.value"] = value
|
||||
//os.Exit(0)
|
||||
break
|
||||
|
||||
}
|
||||
@@ -161,107 +170,13 @@ func MakeInterfaceFromM3U(byteStream []byte) (allChannels []interface{}, err err
|
||||
return
|
||||
}
|
||||
|
||||
// MakeInterfaceFromM3U2 :
|
||||
func MakeInterfaceFromM3U2(byteStream []byte) (allChannels []interface{}, err error) {
|
||||
var content = string(byteStream)
|
||||
//var allChannels = make([]interface{}, 0)
|
||||
func indexOfString(element string, data []string) int {
|
||||
|
||||
var channels = strings.Split(content, "#EXTINF")
|
||||
|
||||
var parseMetaData = func(metaData string) map[string]string {
|
||||
var values string // Save all values in a key
|
||||
var channel = make(map[string]string)
|
||||
|
||||
var exceptForParameter = `[a-z-A-Z=]*(".*?")`
|
||||
//var exceptForChannelName = `(,[^.$\n]*|,[^.$\r]*)`
|
||||
var exceptForChannelName = `(,[^\n]*|,[^\r]*)`
|
||||
|
||||
var exceptForStreamingURL = `(\n.*?\n|\r.*?\r|\n.*?\z|\r.*?\z)`
|
||||
//var exceptForStreamingURL = `^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?`
|
||||
|
||||
// Parse all parameters
|
||||
p := regexp.MustCompile(exceptForParameter)
|
||||
var parameter = p.FindAllString(metaData, -1)
|
||||
//fmt.Println(parameter)
|
||||
for _, i := range parameter {
|
||||
var remove = i
|
||||
i = strings.Replace(i, `"`, "", -1)
|
||||
if strings.Contains(i, "=") {
|
||||
var item = strings.Split(i, "=")
|
||||
switch strings.Contains(item[0], "tvg") {
|
||||
case true:
|
||||
channel[strings.ToLower(item[0])] = item[1]
|
||||
case false:
|
||||
channel[item[0]] = item[1]
|
||||
}
|
||||
|
||||
switch strings.Contains(item[1], "://") {
|
||||
case false:
|
||||
values = values + item[1] + " "
|
||||
}
|
||||
|
||||
}
|
||||
metaData = strings.Replace(metaData, remove, "", 1)
|
||||
}
|
||||
|
||||
// Parse channel name (after the comma)
|
||||
n := regexp.MustCompile(exceptForChannelName)
|
||||
var name = n.FindAllString(metaData, 1)
|
||||
//name[len(name) - 1] = strings.Replace(name[len(name) - 1], `\r`, "", -1)
|
||||
|
||||
var channelName string
|
||||
if len(name) == 0 {
|
||||
if v, ok := channel["tvg-name"]; ok {
|
||||
channelName = v
|
||||
}
|
||||
} else {
|
||||
channelName = name[len(name)-1][1:len(name[len(name)-1])]
|
||||
}
|
||||
|
||||
channelName = strings.Replace(channelName, `"`, "", -1)
|
||||
|
||||
var replacer = strings.NewReplacer("\n", "", "\r", "")
|
||||
channel["name"] = replacer.Replace(channelName)
|
||||
|
||||
values = values + channelName + " "
|
||||
|
||||
// Parse streaming URL
|
||||
u := regexp.MustCompile(exceptForStreamingURL)
|
||||
var streamingURL = u.FindAllString(metaData, -1)
|
||||
var url = strings.Replace(streamingURL[0], "\n", "", -1)
|
||||
url = strings.Replace(url, "\r", "", -1)
|
||||
url = strings.Trim(url, "\r\n")
|
||||
channel["url"] = url
|
||||
|
||||
channel["_values"] = values
|
||||
|
||||
// Search for a unique ID
|
||||
|
||||
for key, value := range channel {
|
||||
if !strings.Contains(strings.ToLower(key), "tvg-id") {
|
||||
if strings.Contains(strings.ToLower(key), "id") {
|
||||
channel["_uuid.key"] = key
|
||||
channel["_uuid.value"] = value
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return channel
|
||||
}
|
||||
|
||||
if strings.Contains(channels[0], "#EXTM3U") {
|
||||
|
||||
for _, thisStream := range channels {
|
||||
if !strings.Contains(thisStream, "#EXTM3U") {
|
||||
var channel = parseMetaData(thisStream)
|
||||
allChannels = append(allChannels, channel)
|
||||
for k, v := range data {
|
||||
if element == v {
|
||||
return k
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
err = errors.New("No valid m3u file")
|
||||
}
|
||||
|
||||
return
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ func filterThisStream(s interface{}) (status bool) {
|
||||
|
||||
for _, filter := range Data.Filter {
|
||||
|
||||
if filter.Rule == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
var group, name, search string
|
||||
var exclude, include string
|
||||
var match = false
|
||||
|
||||
@@ -12,6 +12,10 @@ import (
|
||||
|
||||
func showInfo(str string) {
|
||||
|
||||
if System.Flag.Info == true {
|
||||
return
|
||||
}
|
||||
|
||||
var max = 22
|
||||
var msg = strings.SplitN(str, ":", 2)
|
||||
var length = len(msg[0])
|
||||
@@ -240,7 +244,9 @@ func getErrMsg(errCode int) (errMsg string) {
|
||||
case 1012:
|
||||
errMsg = fmt.Sprintf("Invalid formatting of the time")
|
||||
case 1013:
|
||||
errMsg = fmt.Sprintf("Invalid settings file (%s), file must be at least version %s", System.File.Settings, 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:
|
||||
errMsg = fmt.Sprintf("Data could not be saved, invalid keyword")
|
||||
@@ -351,6 +357,8 @@ func getErrMsg(errCode int) (errMsg string) {
|
||||
// Caching
|
||||
case 4100:
|
||||
errMsg = fmt.Sprintf("Unknown content type for downloaded image")
|
||||
case 4101:
|
||||
errMsg = fmt.Sprintf("Invalid URL, original URL is used for this image")
|
||||
|
||||
// API
|
||||
case 5000:
|
||||
|
||||
51
src/ssdp.go
51
src/ssdp.go
@@ -11,24 +11,26 @@ import (
|
||||
)
|
||||
|
||||
// SSDP : SSPD / DLNA Server
|
||||
func SSDP() {
|
||||
func SSDP() (err error) {
|
||||
|
||||
showInfo(fmt.Sprintf("SSDP / DLNA:%t", Settings.SSDP))
|
||||
|
||||
if Settings.SSDP == false {
|
||||
if Settings.SSDP == false || System.Flag.Info == true {
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
showInfo(fmt.Sprintf("SSDP / DLNA:%t", Settings.SSDP))
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
|
||||
ad, err := ssdp.Advertise(
|
||||
"upnp:"+System.AppName, // send as "ST"
|
||||
System.DeviceID+"::upnp:"+System.AppName, // send as "USN"
|
||||
System.URLBase+"/device.xml", // send as "LOCATION"
|
||||
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"
|
||||
|
||||
if err != nil {
|
||||
ShowError(err, 000)
|
||||
return
|
||||
}
|
||||
|
||||
// Debug SSDP
|
||||
@@ -36,27 +38,27 @@ func SSDP() {
|
||||
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
|
||||
}
|
||||
|
||||
var aliveTick <-chan time.Time
|
||||
var ai = 10
|
||||
go func(adv *ssdp.Advertiser) {
|
||||
|
||||
if ai > 0 {
|
||||
aliveTick = time.Tick(time.Duration(ai) * time.Second)
|
||||
} else {
|
||||
aliveTick = make(chan time.Time)
|
||||
}
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
|
||||
loop:
|
||||
aliveTick := time.Tick(300 * time.Second)
|
||||
|
||||
loop:
|
||||
for {
|
||||
|
||||
select {
|
||||
|
||||
case <-aliveTick:
|
||||
ad.Alive()
|
||||
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
|
||||
|
||||
@@ -64,6 +66,7 @@ loop:
|
||||
|
||||
}
|
||||
|
||||
ad.Bye()
|
||||
ad.Close()
|
||||
}(ad)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ type ThisStream struct {
|
||||
type Segment struct {
|
||||
Duration float64
|
||||
Info bool
|
||||
PlaylistType string
|
||||
Sequence int64
|
||||
URL string
|
||||
Version int
|
||||
|
||||
@@ -11,10 +11,12 @@ type SystemStruct struct {
|
||||
APIVersion string
|
||||
AppName string
|
||||
ARCH string
|
||||
BackgroundProcess bool
|
||||
Branch string
|
||||
Build string
|
||||
Compatibility string
|
||||
ConfigurationWizard bool
|
||||
DBVersion string
|
||||
Dev bool
|
||||
DeviceID string
|
||||
Domain string
|
||||
@@ -33,7 +35,9 @@ type SystemStruct struct {
|
||||
Flag struct {
|
||||
Branch string
|
||||
Debug int
|
||||
Info bool
|
||||
Port string
|
||||
Restore string
|
||||
SSDP bool
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ func loadSettings() (settings SettingsStrcut, err error) {
|
||||
defaults["buffer.size.kb"] = 1024
|
||||
defaults["buffer.timeout"] = 500
|
||||
defaults["cache.images"] = false
|
||||
defaults["epgSource"] = "XEPG"
|
||||
defaults["epgSource"] = "PMS"
|
||||
defaults["files"] = dataMap
|
||||
defaults["files.update"] = true
|
||||
defaults["filter"] = make(map[string]interface{})
|
||||
@@ -133,7 +133,7 @@ func loadSettings() (settings SettingsStrcut, err error) {
|
||||
defaults["update"] = []string{"0000"}
|
||||
defaults["user.agent"] = System.Name
|
||||
defaults["uuid"] = createUUID()
|
||||
defaults["version"] = System.Version
|
||||
defaults["version"] = System.DBVersion
|
||||
defaults["xteveAutoUpdate"] = true
|
||||
defaults["temp.path"] = System.Folder.Temp
|
||||
|
||||
@@ -159,6 +159,8 @@ func loadSettings() (settings SettingsStrcut, err error) {
|
||||
showInfo(fmt.Sprintf("Git Branch:Switching Git Branch to -> %s", settings.Branch))
|
||||
}
|
||||
|
||||
settings.Version = System.DBVersion
|
||||
|
||||
err = saveSettings(settings)
|
||||
|
||||
return
|
||||
|
||||
@@ -189,7 +189,7 @@ checkVersion:
|
||||
var newFilterMap = convertToNewFilter(oldFilter)
|
||||
settingsMap["filter"] = newFilterMap
|
||||
|
||||
settingsMap["version"] = "1.9.0"
|
||||
settingsMap["version"] = "2.0.0"
|
||||
|
||||
err = saveMapToJSONFile(System.File.Settings, settingsMap)
|
||||
if err != nil {
|
||||
@@ -203,7 +203,7 @@ checkVersion:
|
||||
return
|
||||
}
|
||||
|
||||
case "1.9.0":
|
||||
case "2.0.0":
|
||||
// Falls es in einem späteren Update Änderungen an der Datenbank gibt, geht es hier weiter
|
||||
|
||||
break
|
||||
|
||||
81
src/webUI.go
81
src/webUI.go
File diff suppressed because one or more lines are too long
@@ -34,8 +34,20 @@ func StartWebserver() (err error) {
|
||||
|
||||
showInfo("DVR IP:" + System.IPAddress + ":" + Settings.Port)
|
||||
|
||||
var ips = len(System.IPAddressesV4) + len(System.IPAddressesV6) - 1
|
||||
switch ips {
|
||||
|
||||
case 0:
|
||||
showHighlight(fmt.Sprintf("Web Interface:%s://%s:%s/web/", System.ServerProtocol.WEB, System.IPAddress, Settings.Port))
|
||||
|
||||
case 1:
|
||||
showHighlight(fmt.Sprintf("Web Interface:%s://%s:%s/web/ | xTeVe is also available via the other %d IP.", System.ServerProtocol.WEB, System.IPAddress, Settings.Port, ips))
|
||||
|
||||
default:
|
||||
showHighlight(fmt.Sprintf("Web Interface:%s://%s:%s/web/ | xTeVe is also available via the other %d IP's.", System.ServerProtocol.WEB, System.IPAddress, Settings.Port, len(System.IPAddressesV4)+len(System.IPAddressesV6)-1))
|
||||
|
||||
}
|
||||
|
||||
if err = http.ListenAndServe(":"+port, nil); err != nil {
|
||||
ShowError(err, 1001)
|
||||
return
|
||||
@@ -147,7 +159,8 @@ func Stream(w http.ResponseWriter, r *http.Request) {
|
||||
showInfo("Streaming URL:" + streamInfo.URL)
|
||||
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.")
|
||||
|
||||
}
|
||||
|
||||
@@ -192,6 +205,7 @@ func xTeVe(w http.ResponseWriter, r *http.Request) {
|
||||
// XMLTV Datei
|
||||
if strings.Contains(path, "xmltv/") {
|
||||
|
||||
w.Header().Set("Content-Type", "application/xml")
|
||||
requestType = "xml"
|
||||
|
||||
file = System.Folder.Data + getFilenameFromPath(path)
|
||||
@@ -302,6 +316,8 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
setGlobalDomain(r.Host)
|
||||
|
||||
for {
|
||||
|
||||
err = conn.ReadJSON(&request)
|
||||
@@ -447,7 +463,7 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
file, errNew := xteveBackup()
|
||||
err = errNew
|
||||
if err == nil {
|
||||
response.OpenLink = System.URLBase + "/download/" + file
|
||||
response.OpenLink = fmt.Sprintf("%s://%s/download/%s", System.ServerProtocol.WEB, System.Domain, file)
|
||||
}
|
||||
|
||||
case "xteveRestore":
|
||||
@@ -457,9 +473,10 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if len(request.Base64) > 0 {
|
||||
|
||||
newWebURL, err := xteveRestore(request.Base64)
|
||||
newWebURL, err := xteveRestoreFromWeb(request.Base64)
|
||||
if err != nil {
|
||||
ShowError(err, 000)
|
||||
response.Alert = err.Error()
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
@@ -528,7 +545,6 @@ func WS(w http.ResponseWriter, r *http.Request) {
|
||||
response.Settings = Settings
|
||||
}
|
||||
|
||||
setGlobalDomain(r.Host)
|
||||
response = setDefaultResponseData(response, true)
|
||||
if System.ConfigurationWizard == true {
|
||||
response.ConfigurationWizard = System.ConfigurationWizard
|
||||
@@ -582,10 +598,14 @@ func Web(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if getFilenameFromPath(requestFile) == "html" {
|
||||
|
||||
if len(Data.Streams.All) == 0 && System.ScanInProgress == 0 {
|
||||
if System.ScanInProgress == 0 {
|
||||
|
||||
if len(Settings.Files.M3U) == 0 && len(Settings.Files.HDHR) == 0 {
|
||||
System.ConfigurationWizard = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch System.ConfigurationWizard {
|
||||
|
||||
case true:
|
||||
@@ -867,8 +887,6 @@ func API(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
case "status":
|
||||
|
||||
fmt.Println("-----------------------------")
|
||||
os.Exit(0)
|
||||
response.VersionXteve = System.Version
|
||||
response.VersionAPI = System.APIVersion
|
||||
response.StreamsActive = int64(len(Data.Streams.Active))
|
||||
|
||||
48
src/xepg.go
48
src/xepg.go
@@ -174,9 +174,7 @@ func createXEPGMapping() {
|
||||
return
|
||||
}
|
||||
|
||||
if len(Data.XMLTV.Files) == 0 {
|
||||
return
|
||||
}
|
||||
if len(Data.XMLTV.Files) > 0 {
|
||||
|
||||
for i := len(Data.XMLTV.Files) - 1; i >= 0; i-- {
|
||||
|
||||
@@ -221,6 +219,17 @@ func createXEPGMapping() {
|
||||
|
||||
}
|
||||
|
||||
Data.XMLTV.Mapping = tmpMap
|
||||
tmpMap = make(map[string]interface{})
|
||||
|
||||
} else {
|
||||
|
||||
if System.ConfigurationWizard == false {
|
||||
showWarning(1007)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Auswahl für den Dummy erstellen
|
||||
var dummy = make(map[string]interface{})
|
||||
var times = []string{"30", "60", "90", "120"}
|
||||
@@ -236,11 +245,8 @@ func createXEPGMapping() {
|
||||
|
||||
}
|
||||
|
||||
Data.XMLTV.Mapping = tmpMap
|
||||
Data.XMLTV.Mapping["xTeVe Dummy"] = dummy
|
||||
|
||||
tmpMap = make(map[string]interface{})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -300,7 +306,6 @@ func createXEPGDatabase() (err error) {
|
||||
}
|
||||
|
||||
if len(xepgChannel.XChannelID) == 0 {
|
||||
fmt.Println(mapToJSON(xepgChannel))
|
||||
delete(Data.XEPG.Channels, id)
|
||||
}
|
||||
|
||||
@@ -310,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 {
|
||||
|
||||
var channelExists = false // Entscheidet ob ein Kanal neu zu Datenbank hinzugefügt werden soll.
|
||||
@@ -325,7 +336,7 @@ func createXEPGDatabase() (err error) {
|
||||
Data.Cache.Streams.Active = append(Data.Cache.Streams.Active, m3uChannel.Name)
|
||||
|
||||
// XEPG Datenbank durchlaufen um nach dem Kanal zu suchen.
|
||||
for xepg, dxc := range Data.XEPG.Channels {
|
||||
for xepg, dxc := range xepgChannels {
|
||||
|
||||
var xepgChannel XEPGChannelStruct
|
||||
err = json.Unmarshal([]byte(mapToJSON(dxc)), &xepgChannel)
|
||||
@@ -361,6 +372,7 @@ func createXEPGDatabase() (err error) {
|
||||
//os.Exit(0)
|
||||
|
||||
switch channelExists {
|
||||
|
||||
case true:
|
||||
// Bereits vorhandener Kanal
|
||||
var xepgChannel XEPGChannelStruct
|
||||
@@ -583,7 +595,12 @@ func createXMLTVFile() (err error) {
|
||||
var xepgXML XMLTV
|
||||
|
||||
xepgXML.Generator = System.Name
|
||||
|
||||
if System.Branch == "master" {
|
||||
xepgXML.Source = fmt.Sprintf("%s - %s", System.Name, System.Version)
|
||||
} else {
|
||||
xepgXML.Source = fmt.Sprintf("%s - %s.%s", System.Name, System.Version, System.Build)
|
||||
}
|
||||
|
||||
var tmpProgram = &XMLTV{}
|
||||
|
||||
@@ -749,7 +766,9 @@ func createDummyProgram(xepgChannel XEPGChannelStruct) (dummyXMLTV XMLTV) {
|
||||
epg.Poster = append(epg.Poster, poster)
|
||||
}
|
||||
|
||||
if xepgChannel.XCategory != "Movie" {
|
||||
epg.EpisodeNum = append(epg.EpisodeNum, &EpisodeNum{Value: epgStartTime.Format("2006-01-02 15:04:05"), System: "original-air-date"})
|
||||
}
|
||||
|
||||
epg.New = &New{Value: ""}
|
||||
|
||||
@@ -812,10 +831,19 @@ func getEpisodeNum(program *Program, xmltvProgram *Program, xepgChannel XEPGChan
|
||||
|
||||
program.EpisodeNum = xmltvProgram.EpisodeNum
|
||||
|
||||
if len(xepgChannel.XCategory) > 0 {
|
||||
if len(xepgChannel.XCategory) > 0 && xepgChannel.XCategory != "Movie" {
|
||||
|
||||
if len(xmltvProgram.EpisodeNum) == 0 {
|
||||
program.EpisodeNum = append(program.EpisodeNum, &EpisodeNum{Value: time.Now().Format("2006-01-02"), System: "original-air-date"})
|
||||
|
||||
var timeLayout = "20060102150405"
|
||||
|
||||
t, err := time.Parse(timeLayout, strings.Split(xmltvProgram.Start, " ")[0])
|
||||
if err == nil {
|
||||
program.EpisodeNum = append(program.EpisodeNum, &EpisodeNum{Value: t.Format("2006-01-02 15:04:05"), System: "original-air-date"})
|
||||
} else {
|
||||
ShowError(err, 0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class WizardItem extends WizardCategory {
|
||||
|
||||
case "m3u":
|
||||
var input = content.createInput("text", key, "")
|
||||
input.setAttribute("placeholder", "{{.wizard.m3u.placeholder}}")
|
||||
input.setAttribute("class", "wizard")
|
||||
input.id = key
|
||||
doc.appendChild(input)
|
||||
@@ -72,6 +73,7 @@ class WizardItem extends WizardCategory {
|
||||
|
||||
case "xmltv":
|
||||
var input = content.createInput("text", key, "")
|
||||
input.setAttribute("placeholder", "{{.wizard.xmltv.placeholder}}")
|
||||
input.setAttribute("class", "wizard")
|
||||
input.id = key
|
||||
doc.appendChild(input)
|
||||
@@ -140,6 +142,12 @@ function saveWizard() {
|
||||
name = (config[i] as HTMLInputElement).name
|
||||
value = (config[i] as HTMLInputElement).value
|
||||
|
||||
if (value.length == 0) {
|
||||
var msg = name.toUpperCase() + ": " + "{{.alert.missingInput}}"
|
||||
alert(msg)
|
||||
return
|
||||
}
|
||||
|
||||
wizard[name] = value
|
||||
break
|
||||
}
|
||||
|
||||
@@ -714,7 +714,7 @@ class ShowContent extends Content {
|
||||
break
|
||||
|
||||
case "log":
|
||||
var input = this.createInput("button", menuKey, "{{.button.resetlogs}}")
|
||||
var input = this.createInput("button", menuKey, "{{.button.resetLogs}}")
|
||||
input.setAttribute("onclick", 'javascript: resetLogs();')
|
||||
interaction.appendChild(input)
|
||||
|
||||
@@ -1530,6 +1530,8 @@ function openPopUp(dataType, element) {
|
||||
}
|
||||
content.appendRow("{{.mapping.channelName.title}}", input)
|
||||
|
||||
content.description(data["name"])
|
||||
|
||||
// Aktualisierung des Kanalnamens
|
||||
if (data.hasOwnProperty("_uuid.key")) {
|
||||
if (data["_uuid.key"] != "") {
|
||||
@@ -1570,6 +1572,10 @@ function openPopUp(dataType, element) {
|
||||
input.setAttribute("onchange", "javascript: this.className = 'changed'")
|
||||
content.appendRow("{{.mapping.m3uGroupTitle.title}}", input)
|
||||
|
||||
if (data["group-title"] != undefined) {
|
||||
content.description(data["group-title"])
|
||||
}
|
||||
|
||||
// XMLTV Datei
|
||||
var dbKey:string = "x-xmltv-file"
|
||||
var xmlFile = data[dbKey]
|
||||
|
||||
@@ -24,7 +24,7 @@ class Server {
|
||||
case "http:":
|
||||
this.protocol = "ws://"
|
||||
break
|
||||
case "https://":
|
||||
case "https:":
|
||||
this.protocol = "wss://"
|
||||
break
|
||||
}
|
||||
|
||||
44
xteve.go
44
xteve.go
@@ -39,7 +39,10 @@ var GitHub = GitHubStruct{Branch: "master", User: "xteve-project", Repo: "xTeVe-
|
||||
const Name = "xTeVe"
|
||||
|
||||
// Version : Version, die Build Nummer wird in der main func geparst.
|
||||
const Version = "2.0.0.0000"
|
||||
const Version = "2.0.3.0030"
|
||||
|
||||
// DBVersion : Datanbank Version
|
||||
const DBVersion = "2.0.0"
|
||||
|
||||
// APIVersion : API Version
|
||||
const APIVersion = "1.1.0"
|
||||
@@ -49,12 +52,15 @@ const Dev = false
|
||||
|
||||
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 sampleRestore = fmt.Sprintf("%spath%sto%sfile%s", string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator), string(os.PathSeparator))
|
||||
|
||||
var configFolder = flag.String("config", "", ": Config Folder ["+samplePath+"] (default: "+homeDirectory+")")
|
||||
var port = flag.String("port", "", ": Server port [34400] (default: 34400)")
|
||||
var restore = flag.String("restore", "", ": Restore from backup ["+sampleRestore+"xteve_backup.zip]")
|
||||
|
||||
var gitBranch = flag.String("branch", "", ": Git Branch [master|beta] (default: master)")
|
||||
var debug = flag.Int("debug", 0, ": Debug level [0 - 3] (default: 0)")
|
||||
var info = flag.Bool("info", false, ": Show system info")
|
||||
var h = flag.Bool("h", false, ": Show help")
|
||||
|
||||
func main() {
|
||||
@@ -66,6 +72,7 @@ func main() {
|
||||
system.APIVersion = APIVersion
|
||||
system.Branch = GitHub.Branch
|
||||
system.Build = build[len(build)-1:][0]
|
||||
system.DBVersion = DBVersion
|
||||
system.Dev = Dev
|
||||
system.GitHub = GitHub
|
||||
system.Name = Name
|
||||
@@ -115,6 +122,22 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// Systeminformationen anzeigen
|
||||
if *info {
|
||||
|
||||
system.Flag.Info = true
|
||||
|
||||
err := src.Init()
|
||||
if err != nil {
|
||||
src.ShowError(err, 0)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
src.ShowSystemInfo()
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// Webserver Port
|
||||
if len(*port) > 0 {
|
||||
system.Flag.Port = *port
|
||||
@@ -138,6 +161,25 @@ func main() {
|
||||
system.Folder.Config = *configFolder
|
||||
}
|
||||
|
||||
// Backup wiederherstellen
|
||||
if len(*restore) > 0 {
|
||||
|
||||
system.Flag.Restore = *restore
|
||||
|
||||
err := src.Init()
|
||||
if err != nil {
|
||||
src.ShowError(err, 0)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
err = src.XteveRestoreFromCLI(*restore)
|
||||
if err != nil {
|
||||
src.ShowError(err, 0)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
err := src.Init()
|
||||
if err != nil {
|
||||
src.ShowError(err, 0)
|
||||
|
||||
Reference in New Issue
Block a user