Skip to content

Commit 84c1df9

Browse files
add /logs endpoint
1 parent 3af44d5 commit 84c1df9

File tree

10 files changed

+72
-25
lines changed

10 files changed

+72
-25
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ build
22
.DS_Store
33
*config.json
44
media.*.priv*
5+
docker/data
56

67
# Binaries for programs and plugins
78
*.exe

Makefile

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.PHONY: build test run docker-run docker-build
2-
2+
SHELL := /bin/bash
33
build:
44
cd cmd && go build -o ../build/server
55

@@ -16,7 +16,7 @@ docker-build:
1616
docker buildx build --load --tag plex-webhook-automation-local .
1717
docker-push:
1818
docker buildx build --push --platform linux/amd64 --tag ghcr.io/iloveicedgreentea/plex-webhook-automation:test .
19-
docker-run: docker-build
20-
docker run -p 9999:9999 -e LOG_LEVEL=debug plex-webhook-automation-local
19+
docker-run:
20+
docker run -p 9999:9999 -e LOG_LEVEL=debug -v $(shell pwd)/docker/data:/data plex-webhook-automation-local
2121
run: build
22-
LOG_LEVEL=debug ./build/server
22+
LOG_FILE=false LOG_LEVEL=debug ./build/server

api/handlers.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ import (
1313

1414
var log = logger.GetLogger()
1515

16-
func GenConfigPaths() (string, string){
16+
func GenConfigPaths() (string, string) {
1717
ex, err := os.Executable()
1818
if err != nil {
1919
log.Error(err)
2020
}
2121

2222
exPath := filepath.Dir(ex)
23-
configPath1 := "/config.json" // docker
23+
configPath1 := "/data/config.json" // docker
2424
configPath2 := filepath.Join(exPath, "../config.json") // Fallback path (for local)
2525

2626
log.Debugf("Config paths: %s, %s", configPath1, configPath2)
@@ -51,6 +51,16 @@ func ConfigExists(c *gin.Context) {
5151
c.JSON(200, gin.H{"exists": err == nil})
5252
}
5353

54+
// Route for getting logs
55+
func GetLogs(c *gin.Context) {
56+
logFile, err := os.ReadFile("/data/application.log")
57+
if err != nil {
58+
c.JSON(500, gin.H{"error": "unable to read log file: " + err.Error()})
59+
return
60+
}
61+
c.Data(200, "text/plain", logFile)
62+
}
63+
5464
// GetConfig returns the config for the API
5565
func GetConfig(c *gin.Context) {
5666
path, err := GetConfigPath()

api/routes.go

+2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"github.com/gin-gonic/gin"
55
)
66

7+
// RegisterRoutes registers the routes for the API contained in handlers.go
78
func RegisterRoutes(router *gin.Engine) {
89
router.GET("/config", GetConfig)
910
router.POST("/config", SaveConfig)
11+
router.GET("/logs", GetLogs)
1012
}

changelog.txt

+8-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,11 @@ HDMI Sync automation in testing
2626
*Breaking changes* All config fields are lowercase now
2727

2828
10-9-23
29-
Modify UUID filter to accept comma for multiple
29+
Modify UUID filter to accept comma for multiple
30+
31+
12-sometime-23
32+
* Breaking change - volume must now be /data
33+
* log to a file
34+
* add /logs endpoint
35+
* add prelim jellyfin support
36+
* new name

cmd/main.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package main
22

33
import (
44
"fmt"
5-
5+
"os"
66
"github.com/gin-gonic/gin"
77
"github.com/iloveicedgreentea/go-plex/api"
88
"github.com/iloveicedgreentea/go-plex/internal/config"
@@ -26,6 +26,12 @@ func main() {
2626
###############################
2727
Setups
2828
############################## */
29+
30+
// truncate old logs
31+
err := os.Remove("/data/application.log")
32+
if err != nil && !os.IsNotExist(err) {
33+
panic(err)
34+
}
2935
log := logger.GetLogger()
3036
log.Info("Starting up...")
3137
log.Debug("Starting in debug mode...")
@@ -35,7 +41,7 @@ func main() {
3541
r.Use(noCache())
3642

3743
log.Info("Checking if a config exists...")
38-
_, err := api.GetConfigPath()
44+
_, err = api.GetConfigPath()
3945
if err != nil {
4046
log.Info("Config not found. Creating a new config file...")
4147
err = api.CreateConfig(&gin.Context{})

docker/watch.py

+15-6
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,31 @@
22
import os
33
from hashlib import md5
44

5+
FILEPATH = "/data/config.json"
6+
57
def file_checksum(filepath):
6-
with open(filepath, 'rb') as f:
7-
return md5(f.read()).hexdigest()
8+
"""Return the MD5 checksum of a file. Try until the file exists."""
9+
while True:
10+
try:
11+
with open(filepath, 'rb') as f:
12+
return md5(f.read()).hexdigest()
13+
except FileNotFoundError:
14+
print("File not found, waiting for it to appear.")
15+
time.sleep(5)
16+
continue
817

918
def restart_service():
1019
os.system("supervisorctl restart app")
1120

1221
if __name__ == "__main__":
13-
last_checksum = file_checksum("/config.json")
22+
last_checksum = file_checksum(FILEPATH)
1423

1524
while True:
16-
current_checksum = file_checksum("/config.json")
25+
current_checksum = file_checksum(FILEPATH)
1726

1827
if last_checksum != current_checksum:
19-
print("Configuration file changed, restarting the app.")
28+
print("Watcher Service: Configuration file changed, restarting the app.")
2029
restart_service()
2130
last_checksum = current_checksum
2231

23-
time.sleep(5) # Poll every 5 seconds
32+
time.sleep(3) # Poll every 5 seconds

internal/config/config.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ func init() {
2222
}
2323

2424
exPath := filepath.Dir(ex)
25-
configPath1 := filepath.Join(exPath, "../config.json")
26-
27-
// Fallback path (for Docker)
28-
configPath2 := "/config.json"
25+
// docker path
26+
configPath1 := "/data/config.json"
27+
// local
28+
configPath2 := filepath.Join(exPath, "../config.json")
2929

3030
var found bool
3131

internal/logger/logger.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,25 @@ import (
1010
func GetLogger() *log.Logger {
1111
logger := log.New()
1212

13+
// log to file if LOG_FILE is not false
14+
if os.Getenv("LOG_FILE") != "false" {
15+
// Open a file for logging
16+
file, err := os.OpenFile("/data/application.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
17+
if err != nil {
18+
log.Fatalf("Failed to open log file: %v", err)
19+
}
20+
21+
// Set logger output to the file
22+
logger.SetOutput(file)
23+
}
1324
// log level
1425
if strings.ToLower(os.Getenv("LOG_LEVEL")) == "debug" {
1526
logger.SetLevel(log.DebugLevel)
1627
}
1728
if os.Getenv("SUPER_DEBUG") == "true" {
1829
logger.SetReportCaller(true)
1930
}
20-
31+
2132
logger.SetFormatter(&log.TextFormatter{
2233
TimestampFormat: "01-02-2006 15:04:05", FullTimestamp: true,
2334
})

readme.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,14 @@ Configure this application via the Plex section and it "should work" but no prom
8383
> ℹ If you need help deploying with Docker, refer to the [Docker documentation](https://docs.docker.com/get-docker/).
8484
8585
1) Deploy the latest version `ghcr.io/iloveicedgreentea/plex-webhook-automation:latest`. I recommend running this in an orchestrator like Unraid, Docker-Compose, etc
86-
2) Configure the application via web ui -> `http://(you-server-ip):9999`
86+
2) You must mount a volume to `/data` to persist data
87+
3) Configure the application via web ui -> `http://(you-server-ip):9999`
8788
* can get your player UUID from `https://plex.tv/devices.xml` while logged in
88-
3) Set up Plex to send webhooks to your server IP, `listenPort`, and the handler endpoint of `/plexwebhook`
89+
4) Set up Plex to send webhooks to your server IP, `listenPort`, and the handler endpoint of `/plexwebhook`
8990
* e.g `(your-server-ip):9999/plexwebhook`
90-
3) Whitelist your server IP in Plex so it can call the API without authentication. [Docs](https://support.plex.tv/articles/200890058-authentication-for-local-network-access/)
91-
4) Play a movie and check server logs. It should say what it loaded and you should see whatever options you enabled work
92-
5) The Application will restart within 5 seconds when config is saved in the UI
91+
5) Whitelist your server IP in Plex so it can call the API without authentication. [Docs](https://support.plex.tv/articles/200890058-authentication-for-local-network-access/)
92+
6) Play a movie and check server logs. It should say what it loaded and you should see whatever options you enabled work
93+
6) The Application will restart within 5 seconds when config is saved in the UI
9394

9495
### Non-Docker Setup
9596
I don't recommend this as it is more work and you will need to set up systemd or something to keep it running. I don't provide support for this method but if you know what you are doing, it is very easy to build the binary and run it.

0 commit comments

Comments
 (0)