aboutsummaryrefslogtreecommitdiff
path: root/tasks/anisync.task.go
blob: bf650f38090de974b1ba2faa2824313d2b17246b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package tasks

import (
	"metachan/entities"
	"metachan/enums"
	"metachan/repositories"
	"metachan/services"
	"metachan/utils/logger"
	"time"
)

func AniSync() error {
	logger.Infof("AniSync", "Starting Anime Sync - Fetching full anime details")

	mappings, err := repositories.GetAllMappings()
	if err != nil {
		logger.Errorf("AniSync", "Failed to fetch anime mappings: %v", err)
		return err
	}

	total := len(mappings)
	logger.Infof("AniSync", "Found %d anime mappings", total)

	itemsToSync := 0
	for _, mapping := range mappings {
		if mapping.MAL == 0 {
			continue
		}
		_, err := repositories.GetAnime(enums.MAL, mapping.MAL)
		if err == nil {
			continue
		}
		itemsToSync++
	}

	logger.Infof("AniSync", "Found %d anime to sync (%d already synced)", itemsToSync, total-itemsToSync)

	synced := 0
	skipped := 0
	startTime := time.Now()
	processed := 0

	for _, mapping := range mappings {
		if mapping.MAL == 0 {
			skipped++
			continue
		}

		_, err := repositories.GetAnime(enums.MAL, mapping.MAL)
		if err == nil {
			skipped++
			continue
		}

		progress, eta := calculateProgress(processed+1, itemsToSync, startTime)

		logger.Infof("AniSync", "[%d/%d] Synchronising MAL ID %d - %.1f%% | ETA: %v", processed+1, itemsToSync, mapping.MAL, progress, eta)

		_, err = services.GetAnime(&mapping)
		if err != nil {
			logger.Warnf("AniSync", "Failed to sync anime MAL ID %d: %v", mapping.MAL, err)
			continue
		}

		synced++
		processed++
	}

	return nil
}

// ResumeAnimeSync is called on startup to resume any interrupted sync and refresh stale entries.
func ResumeAnimeSync() {
	go func() {
		mappings, err := repositories.GetAllMappings()
		if err != nil {
			logger.Errorf("AniSync", "Resume: failed to fetch mappings: %v", err)
			return
		}

		stubs, err := repositories.GetAllAnimeStubs()
		if err != nil {
			logger.Errorf("AniSync", "Resume: failed to fetch anime stubs: %v", err)
			return
		}

		sevenDaysAgo := time.Now().Add(-7 * 24 * time.Hour)
		updatedAt := make(map[int]time.Time, len(stubs))
		enrichedAt := make(map[int]*time.Time, len(stubs))
		for _, s := range stubs {
			updatedAt[s.MALID] = s.UpdatedAt
			enrichedAt[s.MALID] = s.EnrichedAt
		}

		var toProcess []entities.Mapping
		for _, m := range mappings {
			if m.MAL == 0 {
				continue
			}
			t, exists := updatedAt[m.MAL]
			if !exists || t.Before(sevenDaysAgo) || enrichedAt[m.MAL] == nil {
				toProcess = append(toProcess, m)
			}
		}

		if len(toProcess) == 0 {
			return
		}

		logger.Infof("AniSync", "Resume: %d anime to sync (missing or stale)", len(toProcess))
		startTime := time.Now()

		for i, m := range toProcess {
			progress, eta := calculateProgress(i+1, len(toProcess), startTime)
			logger.Infof("AniSync", "[Resume %d/%d] MAL ID %d - %.1f%% | ETA: %v", i+1, len(toProcess), m.MAL, progress, eta)

			if _, err := services.GetAnime(&m); err != nil {
				logger.Warnf("AniSync", "Resume: failed to sync MAL ID %d: %v", m.MAL, err)
			}
		}

		logger.Successf("AniSync", "Resume complete: synced %d anime", len(toProcess))
	}()
}