Skip to content

Commit 9b30941

Browse files
Merge pull request #85 from marcelGoerentz/add_parsing_for_kodi_styled_URL
Add parsing for kodi styled url and enhance the web client
2 parents fcf1e3a + 29e7ee1 commit 9b30941

29 files changed

+423
-398
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ node_modules/
1010
*.exe
1111
*.js
1212
__debug*
13+
**/.idea

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,14 @@ services:
115115
ports:
116116
- 34400:34400
117117
environment:
118-
- PUID=1001
119-
- PGID=1001
118+
- PUID=1000
119+
- PGID=1000
120120
- TZ=America/Los_Angeles
121121
volumes:
122122
- ./data/conf:/home/threadfin/conf
123123
- ./data/temp:/tmp/threadfin:rw
124124
restart: unless-stopped
125-
networks:{}
125+
networks: {}
126126
```
127127
128128
* Docker compose example with gluetun (VPN)

src/m3u.go

+2
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ func buildM3U(groups []string) (m3u string, err error) {
237237
stream, err = createStreamingURL(channel.FileM3UID, channel.XChannelID, channel.XName, channel.URL, channel.BackupChannel1URL, channel.BackupChannel2URL, channel.BackupChannel3URL)
238238
if err == nil {
239239
m3u = m3u + parameter + stream + "\n"
240+
} else {
241+
ShowError(err, 1205)
240242
}
241243

242244
}

src/provider.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package src
33
import (
44
"fmt"
55
"io"
6-
"log"
76
"net/http"
87
"net/url"
98
"strings"
@@ -298,7 +297,9 @@ func getProviderData(fileType, fileID string) (err error) {
298297
}
299298

300299
func downloadFileFromServer(providerURL string, proxyUrl string) (filename string, body []byte, err error) {
301-
log.Println("PROXY URL: ", proxyUrl)
300+
if proxyUrl != "" {
301+
ShowInfo("PROXY URL: " + proxyUrl)
302+
}
302303

303304
_, err = url.ParseRequestURI(providerURL)
304305
if err != nil {

src/screen.go

+2
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ func getErrMsg(errCode int) (errMsg string) {
300300
errMsg = "Steaming URL could not be found in any playlist"
301301
case 1204:
302302
errMsg = "Streaming was stopped by third party transcoder (FFmpeg)"
303+
case 1205:
304+
errMsg = "Streaming URL could not be parst"
303305

304306
// Warnings
305307
case 2000:

src/stream.go

+11-12
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,15 @@ import (
1515

1616
// Stream repräsentiert einen einzelnen Stream
1717
type Stream struct {
18+
*StreamInfo
1819
mu sync.Mutex
19-
Name string
2020
Clients map[string]*Client
2121
Buffer BufferInterface
2222
ErrorChan chan ErrorInfo
2323
Ctx context.Context
2424
Cancel context.CancelFunc
2525

2626
Folder string
27-
URL string
28-
BackupChannel1URL string
29-
BackupChannel2URL string
30-
BackupChannel3URL string
3127
UseBackup bool
3228
BackupNumber int
3329
DoAutoReconnect bool
@@ -82,15 +78,11 @@ func CreateStream(streamInfo *StreamInfo, fileSystem avfs.VFS, errorChan chan Er
8278
}
8379

8480
stream := &Stream{
85-
Name: streamInfo.Name,
81+
StreamInfo: streamInfo,
8682
Buffer: buffer,
8783
ErrorChan: errorChan,
8884
Ctx: ctx,
8985
Cancel: cancel,
90-
URL: streamInfo.URL,
91-
BackupChannel1URL: streamInfo.BackupChannel1URL,
92-
BackupChannel2URL: streamInfo.BackupChannel2URL,
93-
BackupChannel3URL: streamInfo.BackupChannel3URL,
9486
Folder: folder,
9587
Clients: make(map[string]*Client),
9688
BackupNumber: 0,
@@ -118,7 +110,9 @@ func CreateTunerLimitReachedStream() *Stream {
118110
stream := &Stream{
119111
Clients: make(map[string]*Client),
120112
Buffer: buffer,
121-
Name: "Tuner limit reached",
113+
StreamInfo: &StreamInfo{
114+
Name: "Tuner limit reached",
115+
},
122116
Ctx: ctx,
123117
Cancel: cancel,
124118
DoAutoReconnect: false,
@@ -227,7 +221,12 @@ func (s *Stream) StopStream(streamID string) {
227221
}
228222

229223
func (s *Stream) RemoveClientFromStream(streamID, clientID string) {
230-
s.Buffer.(*StreamBuffer).PipeWriter.Close()
224+
var pipeWriter *io.PipeWriter
225+
switch buffer := s.Buffer.(type) {
226+
case *ThirdPartyBuffer:
227+
pipeWriter = buffer.PipeWriter
228+
}
229+
pipeWriter.Close()
231230
if client, exists := s.Clients[clientID]; exists {
232231
CloseClientConnection(client.w)
233232
delete(s.Clients, clientID)

src/streamManager.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ func (sm *StreamManager) StopAllStreams() {
232232
/*
233233
ServeStream will ensure that the clients is getting the stream requested
234234
*/
235-
func (sm *StreamManager) ServeStream(streamInfo StreamInfo, w http.ResponseWriter, r *http.Request) {
235+
func (sm *StreamManager) ServeStream(streamInfo *StreamInfo, w http.ResponseWriter, r *http.Request) {
236236

237237
if sm.LockAgainstNewStreams {
238238
return
@@ -243,7 +243,7 @@ func (sm *StreamManager) ServeStream(streamInfo StreamInfo, w http.ResponseWrite
243243
sm.FileSystem = InitBufferVFS(Settings.StoreBufferInRAM)
244244
}
245245

246-
clientID, playlistID := sm.StartStream(&streamInfo)
246+
clientID, playlistID := sm.StartStream(streamInfo)
247247
if clientID == "" || playlistID == "" {
248248
return
249249
}

src/struct-system.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ type DataStruct struct {
125125
Images *imgcache.ImageCache
126126
PMS map[string]string
127127

128-
StreamingURLS map[string]StreamInfo
128+
StreamingURLS map[string]*StreamInfo
129129
XMLTV map[string]XMLTV
130130

131131
Streams struct {
@@ -258,6 +258,7 @@ type StreamInfo struct {
258258
BackupChannel2URL string `json:"backup_channel_2_url"`
259259
BackupChannel3URL string `json:"backup_channel_3_url"`
260260
URLid string `json:"urlID"`
261+
HTTP_HEADER map[string]string
261262
}
262263

263264
// Notification : Notifikationen im Webinterface

src/system.go

+28-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
"net/url"
78
"os"
89
"reflect"
910
"strings"
@@ -345,20 +346,41 @@ func setDeviceID() {
345346
}
346347

347348
// Provider Streaming-URL zu Threadfin Streaming-URL konvertieren
348-
func createStreamingURL(playlistID, channelNumber, channelName, url string, backup_url_1 string, backup_url_2 string, backup_url_3 string) (streamingURL string, err error) {
349+
func createStreamingURL(playlistID, channelNumber, channelName, url_string string, backup_url_1 string, backup_url_2 string, backup_url_3 string) (streamingURL string, err error) {
349350

350-
var streamInfo StreamInfo
351+
var streamInfo = &StreamInfo{}
351352

352353
if len(Data.Cache.StreamingURLS) == 0 {
353-
Data.Cache.StreamingURLS = make(map[string]StreamInfo)
354+
Data.Cache.StreamingURLS = make(map[string]*StreamInfo)
354355
}
355356

356-
var urlID = getMD5(fmt.Sprintf("%s-%s", playlistID, url))
357+
var urlID = getMD5(fmt.Sprintf("%s-%s", playlistID, url_string))
357358

358359
if s, ok := Data.Cache.StreamingURLS[urlID]; ok {
359360
streamInfo = s
360361
} else {
361-
streamInfo.URL = url
362+
streamInfo.HTTP_HEADER = make(map[string]string)
363+
u, err := url.Parse(url_string)
364+
if err != nil {
365+
return "", err
366+
}
367+
if u.Path == "" {
368+
return "", fmt.Errorf("no path in the url")
369+
}
370+
splittedPath := strings.Split(u.Path, "|")
371+
if len(splittedPath) > 1 {
372+
headers := strings.Split(splittedPath[1], "&")
373+
for _, value := range headers {
374+
pair := strings.Split(value, "=")
375+
if len(pair) < 2 {
376+
break
377+
}
378+
streamInfo.HTTP_HEADER[pair[0]] = pair[1]
379+
}
380+
streamInfo.URL = strings.Join([]string{u.Scheme + "://", u.Host, splittedPath[0]}, "")
381+
} else {
382+
streamInfo.URL = url_string
383+
}
362384
streamInfo.BackupChannel1URL = backup_url_1
363385
streamInfo.BackupChannel2URL = backup_url_2
364386
streamInfo.BackupChannel3URL = backup_url_3
@@ -375,7 +397,7 @@ func createStreamingURL(playlistID, channelNumber, channelName, url string, back
375397
return
376398
}
377399

378-
func getStreamInfo(urlID string) (streamInfo StreamInfo, err error) {
400+
func getStreamInfo(urlID string) (streamInfo *StreamInfo, err error) {
379401

380402
if len(Data.Cache.StreamingURLS) == 0 {
381403

src/thirdPartyBuffer.go

+20-6
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (sb *ThirdPartyBuffer) SetBufferConfig() {
8888
// - error: An error object if an error occurs, otherwise nil.
8989
func (sb *ThirdPartyBuffer) RunBufferCommand(stream *Stream) error {
9090
sb.Stream = stream
91-
args := PrepareBufferArguments(sb.Options, stream.URL)
91+
args := sb.PrepareBufferArguments()
9292

9393
cmd := exec.Command(sb.Path, args...)
9494
debug := fmt.Sprintf("%s:%s %s", strings.ToUpper(Settings.Buffer), sb.Path, args)
@@ -112,16 +112,30 @@ func (sb *ThirdPartyBuffer) RunBufferCommand(stream *Stream) error {
112112
}
113113

114114
// PrepareBufferArguments replaces the [URL] placeholder in the buffer options with the actual stream URL
115-
func PrepareBufferArguments(options, streamURL string) []string {
115+
func (sb *ThirdPartyBuffer) PrepareBufferArguments() []string {
116116
args := []string{}
117-
u, err := url.Parse(streamURL)
117+
u, err := url.Parse(sb.Stream.URL)
118118
if err != nil {
119119
return []string{}
120120
}
121-
for i, a := range strings.Split(options, " ") {
122-
a = strings.Replace(a, "[URL]", streamURL, 1)
121+
if u.Path == "" {
122+
return []string{}
123+
}
124+
for i, a := range strings.Split(sb.Options, " ") {
125+
a = strings.Replace(a, "[URL]", sb.Stream.URL, 1)
123126
if i == 0 && len(Settings.UserAgent) != 0 && Settings.Buffer == "ffmpeg" && u.Scheme != "rtp" {
124-
args = append(args, "-user_agent", Settings.UserAgent)
127+
if sb.Stream.HTTP_HEADER != nil {
128+
var builder strings.Builder
129+
for key, val := range sb.Stream.HTTP_HEADER {
130+
builder.WriteString(key)
131+
builder.WriteString(": ")
132+
builder.WriteString(val)
133+
builder.WriteString("\r\n")
134+
}
135+
args = append(args, "-headers", builder.String())
136+
} else {
137+
args = append(args, "-user_agent", Settings.UserAgent)
138+
}
125139
}
126140
args = append(args, a)
127141
}

src/webserver.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -257,18 +257,18 @@ func stream(w http.ResponseWriter, r *http.Request) {
257257
if Settings.ForceHttpsToUpstream {
258258
var u *url.URL
259259
u, err = url.Parse(streamInfo.URL)
260-
setProtocol(&streamInfo, u, err)
260+
setProtocol(streamInfo, u, err)
261261
if streamInfo.BackupChannel1URL != "" {
262262
u, err = url.Parse(streamInfo.BackupChannel1URL)
263-
setProtocol(&streamInfo, u, err)
263+
setProtocol(streamInfo, u, err)
264264
}
265265
if streamInfo.BackupChannel1URL != "" {
266266
u, err = url.Parse(streamInfo.BackupChannel2URL)
267-
setProtocol(&streamInfo, u, err)
267+
setProtocol(streamInfo, u, err)
268268
}
269269
if streamInfo.BackupChannel1URL != "" {
270270
u, err = url.Parse(streamInfo.BackupChannel3URL)
271-
setProtocol(&streamInfo, u, err)
271+
setProtocol(streamInfo, u, err)
272272
}
273273
}
274274

@@ -657,7 +657,7 @@ func WS(w http.ResponseWriter, r *http.Request) {
657657
// Reset cache for urls.json
658658
var filename = getPlatformFile(System.Folder.Config + "urls.json")
659659
saveMapToJSONFile(filename, make(map[string]StreamInfo))
660-
Data.Cache.StreamingURLS = make(map[string]StreamInfo)
660+
Data.Cache.StreamingURLS = make(map[string]*StreamInfo)
661661

662662
err = saveFiles(request, "m3u")
663663
if err == nil {

src/xepg.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ func cleanupXEPG() {
12441244
sourceIDs = append(sourceIDs, source)
12451245
}
12461246

1247-
ShowInfo("XEPG: Cleanup database")
1247+
ShowInfo("XEPG:Cleanup database")
12481248
Data.XEPG.XEPGCount = 0
12491249

12501250
for id, dxc := range Data.XEPG.Channels {

threadfin.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ var GitHub = GitHubStruct{Branch: "master", User: "marcelGoerentz", Repo: "Threa
4646
const Name = "Threadfin"
4747

4848
// Version : Major, Minor, Patch, Build
49-
const Version = "1.8.1.0"
49+
const Version = "1.8.2.0"
5050

5151
// DBVersion : Database version
5252
const DBVersion = "0.5.0"

web/public/configuration.html

+11-14
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@
55
<meta charset="utf-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Threadfin</title>
8-
<link
9-
rel="stylesheet"
10-
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
11-
/>
12-
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
8+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
9+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
1310
<link rel="stylesheet" href="css/screen.css" type="text/css">
1411
<link rel="stylesheet" href="css/base.css" type="text/css">
1512
</head>
1613

17-
<body onload="javascript: readyForConfiguration(0);">
14+
<body onload="readyForConfiguration(0);">
1815

1916
<div id="loading" class="modal fade">
2017
<div class="modal-dialog loader"></div>
@@ -46,16 +43,16 @@ <h1 id="head-text" class="center">Configuration</h1>
4643

4744
</div>
4845
<div id="box-footer">
49-
<input id="next" class="" type="button" name="next" value="Next" onclick="javascript: saveWizard();">
46+
<input id="next" class="" type="button" name="next" value="Next" onclick="saveWizard();">
5047
</div>
5148
</div>
52-
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
53-
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.10/clipboard.min.js"></script>
54-
<script language="javascript" type="text/javascript" src="js/configuration_ts.js"></script>
55-
<script language="javascript" type="text/javascript" src="js/network_ts.js"></script>
56-
<script language="javascript" type="text/javascript" src="js/menu_ts.js"></script>
57-
<script language="javascript" type="text/javascript" src="js/settings_ts.js"></script>
58-
<script language="javascript" type="text/javascript" src="js/base_ts.js"></script>
49+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
50+
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.11/clipboard.min.js" integrity="sha512-7O5pXpc0oCRrxk8RUfDYFgn0nO1t+jLuIOQdOMRp4APB7uZ4vSjspzp5y6YDtDs4VzUSTbWzBFZ/LKJhnyFOKw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
51+
<script language="javascript" type="text/javascript" src="js/configuration.js"></script>
52+
<script language="javascript" type="text/javascript" src="js/network.js"></script>
53+
<script language="javascript" type="text/javascript" src="js/menu.js"></script>
54+
<script language="javascript" type="text/javascript" src="js/settings.js"></script>
55+
<script language="javascript" type="text/javascript" src="js/base.js"></script>
5956
</body>
6057

6158
</html>

web/public/create-first-user.html

+5-8
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
<meta charset="utf-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Threadfin</title>
8-
<link
9-
rel="stylesheet"
10-
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
11-
/>
12-
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
8+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
9+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
1310
<link rel="stylesheet" href="css/screen.css" type="text/css">
1411
<link rel="stylesheet" href="css/base.css" type="text/css">
1512
</head>
@@ -42,13 +39,13 @@ <h5>{{.account.confirm.title}}:</h5>
4239
</div>
4340

4441
<div id="box-footer">
45-
<input id="submit" class="" type="button" value="{{.button.craeteAccount}}" onclick="javascript: login();">
42+
<input id="submit" class="" type="button" value="{{.button.createAccount}}" onclick="login();">
4643
</div>
4744

4845

4946
</div>
50-
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
51-
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.10/clipboard.min.js"></script>
47+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
48+
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.11/clipboard.min.js" integrity="sha512-7O5pXpc0oCRrxk8RUfDYFgn0nO1t+jLuIOQdOMRp4APB7uZ4vSjspzp5y6YDtDs4VzUSTbWzBFZ/LKJhnyFOKw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
5249
<script language="javascript" type="text/javascript" src="js/network.js"></script>
5350
<script language="javascript" type="text/javascript" src="js/authentication.js"></script>
5451
</body>

0 commit comments

Comments
 (0)