node build fixed

This commit is contained in:
ra_ma
2025-09-20 14:08:38 +01:00
parent c6ebbe069d
commit 3d298fa434
1516 changed files with 535727 additions and 2 deletions

View File

@@ -0,0 +1,197 @@
package report
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
)
type ClickLog struct {
Timestamp time.Time `json:"timestamp"`
Element string `json:"element"`
PageURL string `json:"pageUrl"`
Text *string `json:"text"`
ClassName *string `json:"className"`
}
type NetworkLog struct {
Type string `json:"type"`
Method string `json:"method"`
URL string `json:"url"`
PageURL string `json:"pageUrl"`
Status int `json:"status"`
Duration int `json:"duration"`
DataPreview string `json:"dataPreview"`
Body string `json:"body"`
Timestamp time.Time `json:"timestamp"`
}
type ReactQueryLog struct {
Type string `json:"type"`
PageURL string `json:"pageUrl"`
Status string `json:"status"`
Hash string `json:"hash"`
Error interface{} `json:"error"`
DataPreview string `json:"dataPreview"`
DataType string `json:"dataType"`
Timestamp time.Time `json:"timestamp"`
}
type ConsoleLog struct {
Type string `json:"type"`
Content string `json:"content"`
PageURL string `json:"pageUrl"`
Timestamp time.Time `json:"timestamp"`
}
type UnlockedLocalFile struct {
Path string `json:"path"`
MediaId int `json:"mediaId"`
}
type IssueReport struct {
CreatedAt time.Time `json:"createdAt"`
UserAgent string `json:"userAgent"`
AppVersion string `json:"appVersion"`
OS string `json:"os"`
Arch string `json:"arch"`
ClickLogs []*ClickLog `json:"clickLogs,omitempty"`
NetworkLogs []*NetworkLog `json:"networkLogs,omitempty"`
ReactQueryLogs []*ReactQueryLog `json:"reactQueryLogs,omitempty"`
ConsoleLogs []*ConsoleLog `json:"consoleLogs,omitempty"`
UnlockedLocalFiles []*UnlockedLocalFile `json:"unlockedLocalFiles,omitempty"`
ScanLogs []string `json:"scanLogs,omitempty"`
ServerLogs string `json:"serverLogs,omitempty"`
ServerStatus string `json:"status,omitempty"`
}
func NewIssueReport(userAgent, appVersion, _os, arch string, logsDir string, isAnimeLibraryIssue bool, serverStatus interface{}, toRedact []string) (ret *IssueReport, err error) {
ret = &IssueReport{
CreatedAt: time.Now(),
UserAgent: userAgent,
AppVersion: appVersion,
OS: _os,
Arch: arch,
ClickLogs: make([]*ClickLog, 0),
NetworkLogs: make([]*NetworkLog, 0),
ReactQueryLogs: make([]*ReactQueryLog, 0),
ConsoleLogs: make([]*ConsoleLog, 0),
UnlockedLocalFiles: make([]*UnlockedLocalFile, 0),
ScanLogs: make([]string, 0),
ServerLogs: "",
ServerStatus: "",
}
// Get all log files in the directory
entries, err := os.ReadDir(logsDir)
if err != nil {
return nil, fmt.Errorf("failed to read log directory: %w", err)
}
var serverLogFiles []os.FileInfo
var scanLogFiles []os.FileInfo
for _, file := range entries {
if strings.HasPrefix(file.Name(), "seanime-") {
info, err := file.Info()
if err != nil {
continue
}
serverLogFiles = append(serverLogFiles, info)
}
if strings.Contains(file.Name(), "-scan") {
info, err := file.Info()
if err != nil {
continue
}
// Check if file is newer than 1 day
if time.Since(info.ModTime()).Hours() < 24 {
scanLogFiles = append(scanLogFiles, info)
}
}
}
userPathPattern := regexp.MustCompile(`(?i)(/home/|/Users/|C:\\Users\\)([^/\\]+)`)
if serverStatus != nil {
serverStatusMarshaled, err := json.Marshal(serverStatus)
if err == nil {
// pretty print the json
var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, serverStatusMarshaled, "", " ")
if err == nil {
ret.ServerStatus = prettyJSON.String()
for _, redact := range toRedact {
ret.ServerStatus = strings.ReplaceAll(ret.ServerStatus, redact, "[REDACTED]")
}
ret.ServerStatus = userPathPattern.ReplaceAllString(ret.ServerStatus, "${1}[REDACTED]")
}
}
}
if len(serverLogFiles) > 0 {
sort.Slice(serverLogFiles, func(i, j int) bool {
return serverLogFiles[i].ModTime().After(serverLogFiles[j].ModTime())
})
// Get the most recent log file
latestLog := serverLogFiles[0]
latestLogPath := filepath.Join(logsDir, latestLog.Name())
latestLogContent, err := os.ReadFile(latestLogPath)
if err != nil {
return nil, fmt.Errorf("failed to read log file: %w", err)
}
latestLogContent = userPathPattern.ReplaceAll(latestLogContent, []byte("${1}[REDACTED]"))
for _, redact := range toRedact {
latestLogContent = bytes.ReplaceAll(latestLogContent, []byte(redact), []byte("[REDACTED]"))
}
ret.ServerLogs = string(latestLogContent)
}
if isAnimeLibraryIssue {
if len(scanLogFiles) > 0 {
for _, file := range scanLogFiles {
scanLogPath := filepath.Join(logsDir, file.Name())
scanLogContent, err := os.ReadFile(scanLogPath)
if err != nil {
continue
}
scanLogContent = userPathPattern.ReplaceAll(scanLogContent, []byte("${1}[REDACTED]"))
if len(scanLogContent) == 0 {
ret.ScanLogs = append(ret.ScanLogs, "EMPTY")
} else {
ret.ScanLogs = append(ret.ScanLogs, string(scanLogContent))
}
}
}
}
return
}
func (ir *IssueReport) AddClickLogs(clickLogs []*ClickLog) {
ir.ClickLogs = append(ir.ClickLogs, clickLogs...)
}
func (ir *IssueReport) AddNetworkLogs(networkLogs []*NetworkLog) {
ir.NetworkLogs = append(ir.NetworkLogs, networkLogs...)
}
func (ir *IssueReport) AddReactQueryLogs(reactQueryLogs []*ReactQueryLog) {
ir.ReactQueryLogs = append(ir.ReactQueryLogs, reactQueryLogs...)
}
func (ir *IssueReport) AddConsoleLogs(consoleLogs []*ConsoleLog) {
ir.ConsoleLogs = append(ir.ConsoleLogs, consoleLogs...)
}

View File

@@ -0,0 +1,95 @@
package report
import (
"fmt"
"github.com/rs/zerolog"
"github.com/samber/lo"
"github.com/samber/mo"
"runtime"
"seanime/internal/constants"
"seanime/internal/database/models"
"seanime/internal/library/anime"
)
type Repository struct {
logger *zerolog.Logger
savedIssueReport mo.Option[*IssueReport]
}
func NewRepository(logger *zerolog.Logger) *Repository {
return &Repository{
logger: logger,
savedIssueReport: mo.None[*IssueReport](),
}
}
type SaveIssueReportOptions struct {
LogsDir string `json:"logsDir"`
UserAgent string `json:"userAgent"`
ClickLogs []*ClickLog `json:"clickLogs"`
NetworkLogs []*NetworkLog `json:"networkLogs"`
ReactQueryLogs []*ReactQueryLog `json:"reactQueryLogs"`
ConsoleLogs []*ConsoleLog `json:"consoleLogs"`
LocalFiles []*anime.LocalFile `json:"localFiles"`
Settings *models.Settings `json:"settings"`
DebridSettings *models.DebridSettings `json:"debridSettings"`
IsAnimeLibraryIssue bool `json:"isAnimeLibraryIssue"`
ServerStatus interface{} `json:"serverStatus"`
}
func (r *Repository) SaveIssueReport(opts SaveIssueReportOptions) error {
var toRedact []string
if opts.Settings != nil {
toRedact = opts.Settings.GetSensitiveValues()
}
if opts.DebridSettings != nil {
toRedact = append(toRedact, opts.DebridSettings.GetSensitiveValues()...)
}
toRedact = lo.Filter(toRedact, func(s string, _ int) bool {
return s != ""
})
issueReport, err := NewIssueReport(
opts.UserAgent,
constants.Version,
runtime.GOOS,
runtime.GOARCH,
opts.LogsDir,
opts.IsAnimeLibraryIssue,
opts.ServerStatus,
toRedact,
)
if err != nil {
return fmt.Errorf("failed to create issue report: %w", err)
}
issueReport.ClickLogs = opts.ClickLogs
issueReport.NetworkLogs = opts.NetworkLogs
issueReport.ReactQueryLogs = opts.ReactQueryLogs
issueReport.ConsoleLogs = opts.ConsoleLogs
if opts.IsAnimeLibraryIssue {
for _, localFile := range opts.LocalFiles {
if localFile.Locked {
continue
}
issueReport.UnlockedLocalFiles = append(issueReport.UnlockedLocalFiles, &UnlockedLocalFile{
Path: localFile.Path,
MediaId: localFile.MediaId,
})
}
}
r.savedIssueReport = mo.Some(issueReport)
return nil
}
func (r *Repository) GetSavedIssueReport() (*IssueReport, bool) {
if r.savedIssueReport.IsAbsent() {
return nil, false
}
return r.savedIssueReport.MustGet(), true
}