mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-04 20:46:37 +08:00
refactor: split modules and harden scraping workflows
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
)
|
||||
|
||||
func (s *ScannerService) probeCloudMediaAsync(task cloudMediaProbeTask) {
|
||||
defer func() {
|
||||
s.cloudMediaProbeMu.Lock()
|
||||
delete(s.cloudMediaProbing, task.path)
|
||||
s.cloudMediaProbeMu.Unlock()
|
||||
}()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
probe, err := s.probeCloudFileMetadata(ctx, task.typ, task.ref)
|
||||
if err != nil {
|
||||
if s.log != nil {
|
||||
s.log.Debug("cloud media async probe failed", zap.String("provider", task.typ), zap.String("path", task.path), zap.Error(err))
|
||||
}
|
||||
s.cloudMediaProbeMu.Lock()
|
||||
if s.cloudMediaProbeBackoff == nil {
|
||||
s.cloudMediaProbeBackoff = make(map[string]time.Time)
|
||||
}
|
||||
s.cloudMediaProbeBackoff[task.path] = time.Now().Add(cloudMediaProbeFailureBackoff)
|
||||
s.cloudMediaProbeMu.Unlock()
|
||||
return
|
||||
}
|
||||
updates := probeResultUpdates(probe)
|
||||
if len(updates) == 0 {
|
||||
return
|
||||
}
|
||||
if err := s.repo.DB.WithContext(ctx).Model(&model.Media{}).Where("path = ?", task.path).Updates(updates).Error; err != nil {
|
||||
if s.log != nil {
|
||||
s.log.Debug("update cloud media track metadata failed", zap.String("path", task.path), zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
s.cloudMediaProbeMu.Lock()
|
||||
delete(s.cloudMediaProbeBackoff, task.path)
|
||||
s.cloudMediaProbeMu.Unlock()
|
||||
if s.hub != nil {
|
||||
s.hub.Publish("scan", map[string]any{
|
||||
"path": task.path,
|
||||
"cloud": true,
|
||||
"track_probed": true,
|
||||
"duration_sec": probe.DurationSec,
|
||||
"video_codec": probe.VideoCodec,
|
||||
"audio_codec": probe.AudioCodec,
|
||||
"width": probe.Width,
|
||||
"height": probe.Height,
|
||||
"probe_message": "云盘媒体轨道元数据已后台补齐",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ScannerService) ffprobeWorkerCount() int {
|
||||
if s == nil || s.cfg == nil {
|
||||
return 1
|
||||
}
|
||||
return normalizeFFprobeMaxConcurrent(s.cfg.App.FFprobeMaxConcurrent)
|
||||
}
|
||||
|
||||
func (s *ScannerService) cloudScanWorkerCount() int {
|
||||
if s == nil || s.cfg == nil {
|
||||
return 4
|
||||
}
|
||||
return normalizeCloudScanMaxConcurrent(s.cfg.App.CloudScanMaxConcurrent)
|
||||
}
|
||||
|
||||
func normalizeCloudScanMaxConcurrent(n int) int {
|
||||
if n <= 0 {
|
||||
return 1
|
||||
}
|
||||
if n > 16 {
|
||||
return 16
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (s *ScannerService) probeCloudFileMetadata(ctx context.Context, typ, ref string) (*ProbeResult, error) {
|
||||
if s == nil || s.probe == nil || s.storage == nil {
|
||||
return nil, errors.New("cloud probe unavailable")
|
||||
}
|
||||
link, err := s.storage.CloudResolve(ctx, typ, ref, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.probe.ProbeHTTP(ctx, link.URL, link.Headers)
|
||||
}
|
||||
|
||||
func probeResultUpdates(probe *ProbeResult) map[string]any {
|
||||
updates := map[string]any{}
|
||||
if probe == nil {
|
||||
return updates
|
||||
}
|
||||
if probe.DurationSec > 0 {
|
||||
updates["duration_sec"] = probe.DurationSec
|
||||
}
|
||||
if probe.Width > 0 {
|
||||
updates["width"] = probe.Width
|
||||
}
|
||||
if probe.Height > 0 {
|
||||
updates["height"] = probe.Height
|
||||
}
|
||||
if strings.TrimSpace(probe.VideoCodec) != "" {
|
||||
updates["video_codec"] = probe.VideoCodec
|
||||
}
|
||||
if strings.TrimSpace(probe.AudioCodec) != "" {
|
||||
updates["audio_codec"] = probe.AudioCodec
|
||||
}
|
||||
if probe.Container != "" {
|
||||
updates["container"] = probe.Container
|
||||
}
|
||||
return updates
|
||||
}
|
||||
Reference in New Issue
Block a user