mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-08 14:26:37 +08:00
refactor: split modules and harden scraping workflows
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
)
|
||||
|
||||
func (s *STRMService) upsertGeneratedRecord(ctx context.Context, media model.Media, filePath, playURL, mediaType string) error {
|
||||
protocol := ""
|
||||
if u, err := url.Parse(playURL); err == nil {
|
||||
protocol = strings.ToLower(u.Scheme)
|
||||
}
|
||||
if protocol == "" {
|
||||
protocol = "http"
|
||||
}
|
||||
record := model.STRMRecord{
|
||||
Title: media.Title,
|
||||
URL: playURL,
|
||||
FilePath: filePath,
|
||||
Protocol: protocol,
|
||||
MediaID: media.ID,
|
||||
MediaType: mediaType,
|
||||
SeasonNum: media.SeasonNum,
|
||||
EpisodeNum: media.EpisodeNum,
|
||||
}
|
||||
var existing model.STRMRecord
|
||||
err := s.repo.DB.WithContext(ctx).Where("media_id = ? AND file_path = ?", media.ID, filePath).First(&existing).Error
|
||||
if err == nil {
|
||||
existing.Title = record.Title
|
||||
existing.URL = record.URL
|
||||
existing.Protocol = record.Protocol
|
||||
existing.MediaType = record.MediaType
|
||||
existing.SeasonNum = record.SeasonNum
|
||||
existing.EpisodeNum = record.EpisodeNum
|
||||
return s.repo.DB.WithContext(ctx).Save(&existing).Error
|
||||
}
|
||||
return s.repo.DB.WithContext(ctx).Create(&record).Error
|
||||
}
|
||||
|
||||
func (s *STRMService) cleanupStaleGeneratedSTRM(ctx context.Context, outputDir string, expected map[string]struct{}) (int, error) {
|
||||
outputDir = filepath.Clean(strings.TrimSpace(outputDir))
|
||||
if outputDir == "" || outputDir == "." {
|
||||
return 0, nil
|
||||
}
|
||||
cleaned, err := removeStaleSTRMFiles(outputDir, expected)
|
||||
if err != nil {
|
||||
return cleaned, err
|
||||
}
|
||||
recordsCleaned, err := s.removeStaleSTRMRecords(ctx, outputDir, expected)
|
||||
return cleaned + recordsCleaned, err
|
||||
}
|
||||
|
||||
func removeStaleSTRMFiles(outputDir string, expected map[string]struct{}) (int, error) {
|
||||
cleaned := 0
|
||||
err := filepath.WalkDir(outputDir, func(path string, entry fs.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return nil
|
||||
}
|
||||
if entry.IsDir() || strings.ToLower(filepath.Ext(path)) != ".strm" {
|
||||
return nil
|
||||
}
|
||||
cleanPath := filepath.Clean(path)
|
||||
if _, ok := expected[cleanPath]; ok {
|
||||
return nil
|
||||
}
|
||||
if err := os.Remove(cleanPath); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
cleaned++
|
||||
return nil
|
||||
})
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return cleaned, err
|
||||
}
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
func (s *STRMService) removeStaleSTRMRecords(ctx context.Context, outputDir string, expected map[string]struct{}) (int, error) {
|
||||
if s == nil || s.repo == nil || s.repo.DB == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var records []model.STRMRecord
|
||||
if err := s.repo.DB.WithContext(ctx).Find(&records).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rootAbs, err := filepath.Abs(outputDir)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
cleaned := 0
|
||||
for i := range records {
|
||||
filePath := filepath.Clean(strings.TrimSpace(records[i].FilePath))
|
||||
if filePath == "" {
|
||||
continue
|
||||
}
|
||||
fileAbs, err := filepath.Abs(filePath)
|
||||
if err != nil || !pathWithin(fileAbs, rootAbs) {
|
||||
continue
|
||||
}
|
||||
if _, ok := expected[filePath]; ok {
|
||||
continue
|
||||
}
|
||||
if err := s.repo.DB.WithContext(ctx).Delete(&records[i]).Error; err != nil {
|
||||
return cleaned, err
|
||||
}
|
||||
cleaned++
|
||||
}
|
||||
return cleaned, nil
|
||||
}
|
||||
Reference in New Issue
Block a user