-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #28 from mejgun/fork-and-templates
2.0
- Loading branch information
Showing
39 changed files
with
1,626 additions
and
879 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
bin/ | ||
all.md5 | ||
ytproxy | ||
log.txt | ||
config.json | ||
all.md5 | ||
config.jsonc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,11 @@ | ||
### What is this repository for? ### | ||
|
||
This is part of another project: https://github.com/mesb1/xupnpd_youtube | ||
This is yt-dlp based video restreamer, part of another project: https://github.com/mesb1/xupnpd_youtube | ||
|
||
### Build ### | ||
|
||
`cd src && go build` | ||
`cd cmd && go build` | ||
|
||
### Options ### | ||
|
||
Run with `--help` | ||
|
||
### Exit codes ### | ||
|
||
- 0 - OK | ||
- 1 - config read/parse error | ||
- 2 - logger create error | ||
- 3 - extractor create error | ||
- 4 - streamer create error | ||
- 5 - web server error | ||
- 6 - links cache error | ||
|
||
### Config explained ### | ||
do not copypaste, comments are not allowed in this json. | ||
use config.default.json instead. | ||
|
||
```jsonc | ||
{ | ||
// web server listen port | ||
"port": 8080, | ||
// restreamer config | ||
"streamer": { | ||
// show errors in headers (insecure) | ||
"error-headers": false, | ||
// do not strictly check video headers | ||
"ignore-missing-headers": false, | ||
// do not check video server certificate (insecure) | ||
"ignore-ssl-errors": false, | ||
// video file that will be shown on errors | ||
"error-video": "corrupted.mp4", | ||
// audio file that will be played on errors | ||
// dwnlded here youtu.be/_b8KPiT1PxI (suggest your options) | ||
"error-audio": "failed.m4a", | ||
// how to set streamer's user-agent | ||
// request - set from user's request (old default) | ||
// extractor - set from extractor on app start (default) | ||
// config - set from config | ||
"set-user-agent": "extractor", | ||
// custom user agent used if "set-user-agent" set to "config" | ||
"user-agent": "Mozilla", | ||
// proxy for restreamer | ||
// empty - no proxy | ||
// "env" - read proxy from environment variables (e.g. HTTP_PROXY="http://127.0.0.1:3128") | ||
// proxy url - e.g. "socks5://127.0.0.1:9999" | ||
"proxy": "env", | ||
// min TLS version: "TLS 1.3", "TLS 1.2", etc. | ||
"min-tls-version": "TLS 1.2 " | ||
}, | ||
// media extractor config | ||
"extractor": { | ||
// file path | ||
"path": "yt-dlp", | ||
// arguments for extractor | ||
// args separator is ",,", not space | ||
// {{.HEIGHT}} will be replaced with requested height (360/480/720) | ||
// {{.URL}} will be replace with requested url | ||
// also you can use {{.FORMAT}} - requested format (now - only mp4 or m4a) | ||
"mp4": "-f,,(mp4)[height<={{.HEIGHT}}],,-g,,{{.URL}}", | ||
// same for m4a | ||
"m4a": "-f,,(m4a),,-g,,{{.URL}}", | ||
// args for getting user-agent | ||
"get-user-agent": "--dump-user-agent", | ||
// custom options list to extractor, like proxy, etc. | ||
// same rules as mp4/m4a | ||
// HEIGHT/URL/.. templates also can be used | ||
"custom-options": [ | ||
"--option1,,value1", | ||
"--option2", | ||
"value2", | ||
"--option3", | ||
"very long value 3" | ||
] | ||
}, | ||
// logger config | ||
"log": { | ||
// log level | ||
// debug/info/warning/error/nothing | ||
"level": "info", | ||
// log destination | ||
// stdout/file/both | ||
"output": "stdout", | ||
// filename if writing to file | ||
"filename": "log.txt" | ||
}, | ||
// links cache config | ||
"cache": { | ||
// links expire time | ||
// time units are "s", "m", "h", e.g. "1h10m10s", "10h", "1s" | ||
// "0s" will disable cache | ||
"expire-time": "3h" | ||
} | ||
} | ||
Run with `--help` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,16 @@ | ||
#!/bin/bash | ||
|
||
set -e | ||
|
||
BinDir="bin" | ||
Md5File="all.md5" | ||
FilePrefix="yt-proxy" | ||
|
||
date >${Md5File} | ||
mkdir -p ${BinDir} || exit | ||
rm ${BinDir}/${FilePrefix}* -rf || exit | ||
cd src || exit | ||
go run ../build.go || exit | ||
cd ../$BinDir || exit | ||
for i in $(ls -1 *); do | ||
md5sum $i >>../${Md5File} || exit | ||
done | ||
mkdir -p ${BinDir} | ||
rm ${BinDir}/${FilePrefix}* -rf | ||
cd cmd | ||
go run ../build.go ${FilePrefix} | ||
cd ../$BinDir | ||
md5sum -b ${FilePrefix}* >${Md5File} | ||
cd .. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module ytproxy | ||
|
||
go 1.22.6 | ||
|
||
replace lib => ../lib | ||
|
||
require lib v0.0.0-00010101000000-000000000000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"net/http" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
|
||
app "lib/app" | ||
cache "lib/cache" | ||
config "lib/config" | ||
extractor "lib/extractor" | ||
logger "lib/logger" | ||
streamer "lib/streamer" | ||
) | ||
|
||
const appVersion = "2.0.0" | ||
|
||
type flagsT struct { | ||
version bool | ||
config string | ||
} | ||
|
||
const ( | ||
NoError = iota | ||
SomeError | ||
) | ||
|
||
func parseCLIFlags() flagsT { | ||
var f flagsT | ||
flag.BoolVar(&f.version, "version", false, "prints current yt-proxy version") | ||
flag.StringVar(&f.config, "config", "config.jsonc", "config file path") | ||
flag.Parse() | ||
return f | ||
} | ||
|
||
func main() { | ||
flags := parseCLIFlags() | ||
if flags.version { | ||
os.Stdout.WriteString(fmt.Sprintf("%s\n", appVersion)) | ||
os.Exit(NoError) | ||
} | ||
startApp(flags.config) | ||
} | ||
|
||
func startApp(conf_file string) { | ||
conf, def, opts, log, err := readConfig(conf_file) | ||
if err != nil { | ||
os.Stderr.WriteString(fmt.Sprintf("Config read error: %s\n", err)) | ||
os.Exit(SomeError) | ||
} | ||
app := app.New( | ||
logger.NewLayer(log, "App"), | ||
def, opts) | ||
|
||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | ||
log.LogInfo("Bad request", r.RemoteAddr, r.RequestURI) | ||
log.LogDebug("Bad request", r) | ||
http.NotFound(w, r) | ||
}) | ||
http.HandleFunc("/play/", func(w http.ResponseWriter, r *http.Request) { | ||
log.LogInfo("Play request", r.RemoteAddr, r.RequestURI) | ||
log.LogDebug("User request", r) | ||
app.Run(w, r) | ||
log.LogInfo("Player disconnected", r.RemoteAddr) | ||
}) | ||
s := &http.Server{ | ||
Addr: fmt.Sprintf("%s:%d", conf.Host, conf.PortInt), | ||
} | ||
go signalsCatcher(conf_file, log, app, s) | ||
|
||
log.LogInfo("Starting web server", "host", conf.Host, "port", conf.PortInt) | ||
if err = s.ListenAndServe(); err == http.ErrServerClosed { | ||
log.LogInfo("HTTP server closed") | ||
os.Exit(NoError) | ||
} else { | ||
log.LogError("HTTP server", err) | ||
log.Close() | ||
os.Exit(SomeError) | ||
} | ||
} | ||
|
||
func readConfig(conf_file string) (config.ConfigT, app.Option, []app.Option, | ||
logger.T, error) { | ||
conf, err := config.Read(conf_file) | ||
if err != nil { | ||
return config.ConfigT{}, app.Option{}, nil, nil, err | ||
} | ||
|
||
log, err := logger.New(conf.Log) | ||
if err != nil { | ||
return config.ConfigT{}, app.Option{}, nil, nil, err | ||
} | ||
|
||
defapp, err := getNewApp(log, config.SubConfigT{ | ||
ConfigT: config.ConfigT{ | ||
Streamer: conf.Streamer, | ||
Extractor: conf.Extractor, | ||
Cache: conf.Cache, | ||
}, | ||
Name: "default", | ||
}) | ||
if err != nil { | ||
return config.ConfigT{}, app.Option{}, nil, nil, err | ||
} | ||
|
||
opts := make([]app.Option, 0) | ||
for _, v := range conf.SubConfig { | ||
opt, err := getNewApp(log, v) | ||
if err != nil { | ||
return config.ConfigT{}, app.Option{}, nil, nil, err | ||
} | ||
opts = append(opts, opt) | ||
} | ||
return conf, defapp, opts, log, nil | ||
} | ||
|
||
func signalsCatcher(conf_file string, log logger.T, app *app.AppLogic, s *http.Server) { | ||
sigint := make(chan os.Signal, 1) | ||
signal.Notify(sigint, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) | ||
for { | ||
switch <-sigint { | ||
case syscall.SIGHUP: | ||
log.LogWarning("Config reloading") | ||
_, def, opts, lognew, err := readConfig(conf_file) | ||
if err != nil { | ||
log.LogError("Config reload error", err) | ||
} else { | ||
app.ReloadConfig(logger.NewLayer(lognew, "App"), def, opts) | ||
log = lognew | ||
} | ||
case syscall.SIGINT: | ||
fallthrough | ||
case syscall.SIGTERM: | ||
log.LogWarning("Exiting") | ||
app.Shutdown() | ||
if err := s.Shutdown(context.Background()); err != nil { | ||
// Error from closing listeners, or context timeout: | ||
log.LogError("HTTP server Shutdown", err) | ||
} | ||
return | ||
} | ||
} | ||
} | ||
|
||
func getNewApp(log logger.T, v config.SubConfigT) (app.Option, error) { | ||
texts := [3]string{ | ||
"Extractor", | ||
"Cache", | ||
"Streamer", | ||
} | ||
|
||
newname := func(name string) string { | ||
return fmt.Sprintf("[%s] %s", v.Name, name) | ||
} | ||
nameerr := func(name string, err error) error { | ||
return fmt.Errorf("%s: %s", newname(name), err) | ||
} | ||
xtr, err := extractor.New(v.Extractor, | ||
logger.NewLayer(log, newname(texts[0]))) | ||
if err != nil { | ||
return app.Option{}, nameerr(texts[0], err) | ||
} | ||
cch, err := cache.New(v.Cache, | ||
logger.NewLayer(log, newname(texts[1]))) | ||
if err != nil { | ||
return app.Option{}, nameerr(texts[1], err) | ||
} | ||
strm, err := streamer.New(v.Streamer, | ||
logger.NewLayer(log, newname(texts[2])), xtr) | ||
if err != nil { | ||
return app.Option{}, nameerr(texts[2], err) | ||
} | ||
return app.Option{ | ||
Name: v.Name, | ||
Sites: v.Sites, | ||
X: xtr, | ||
S: strm, | ||
C: cch, | ||
L: logger.NewLayer(log, fmt.Sprintf("[%s] app", v.Name)), | ||
}, nil | ||
} |
Oops, something went wrong.