| 1236 | } |
| 1237 | |
| 1238 | func buildFileMapFromTorrents(torrents []qbt.Torrent, filesByHash map[string]qbt.TorrentFiles) (*buildFileMapResult, error) { |
| 1239 | tfm := NewTorrentFileMap() |
| 1240 | scanRoots := make(map[string]struct{}) |
| 1241 | skippedRoots := make(map[string]struct{}) |
| 1242 | stableMissingFiles := 0 |
| 1243 | |
| 1244 | for i := range torrents { |
| 1245 | torrent := torrents[i] |
| 1246 | savePath := filepath.Clean(torrent.SavePath) |
| 1247 | hasAbsSavePath := savePath != "" && filepath.IsAbs(savePath) |
| 1248 | files, ok := filesByHash[canonicalizeHash(torrent.Hash)] |
| 1249 | hasFiles := ok && len(files) > 0 |
| 1250 | |
| 1251 | if !hasFiles { |
| 1252 | if isTransientTorrentStateForOrphanScan(torrent.State) { |
| 1253 | if hasAbsSavePath { |
| 1254 | skippedRoots[savePath] = struct{}{} |
| 1255 | } |
| 1256 | continue |
| 1257 | } |
| 1258 | |
| 1259 | stableMissingFiles++ |
| 1260 | continue |
| 1261 | } |
| 1262 | |
| 1263 | if !hasAbsSavePath { |
| 1264 | continue |
| 1265 | } |
| 1266 | |
| 1267 | scanRoots[savePath] = struct{}{} |
| 1268 | for _, f := range files { |
| 1269 | tfm.Add(normalizePath(filepath.Join(savePath, f.Name))) |
| 1270 | } |
| 1271 | |
| 1272 | // Auto TMM can update save_path to the category root without moving the |
| 1273 | // payload. content_path still reflects the real on-disk location. |
| 1274 | actualSavePath := actualSavePathFromContentPath(savePath, torrent.ContentPath, files) |
| 1275 | if actualSavePath != "" && actualSavePath != savePath { |
| 1276 | scanRoots[actualSavePath] = struct{}{} |
| 1277 | for _, f := range files { |
| 1278 | tfm.Add(normalizePath(filepath.Join(actualSavePath, f.Name))) |
| 1279 | } |
| 1280 | } |
| 1281 | } |
| 1282 | |
| 1283 | if stableMissingFiles > 0 { |
| 1284 | return nil, fmt.Errorf("%d stable torrents returned no files - partial data detected", stableMissingFiles) |
| 1285 | } |
| 1286 | |
| 1287 | skippedRootList := sortedRoots(skippedRoots) |
| 1288 | scanRootList := filterScanRootsCoveredBySkippedRoots(sortedRoots(scanRoots), skippedRootList) |
| 1289 | |
| 1290 | return &buildFileMapResult{ |
| 1291 | fileMap: tfm, |
| 1292 | scanRoots: scanRootList, |
| 1293 | skippedRoots: skippedRootList, |
| 1294 | torrentCount: len(torrents), |
| 1295 | }, nil |