summaryrefslogtreecommitdiff
path: root/Sora/Data/Booru/BooruNetworkImageLoader.swift
blob: 800555019b57b67ec838b86edb442cac5f089f84 (plain) (blame)
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
import CoreGraphics
import Foundation
import ImageIO
import NetworkImage

actor BooruNetworkImageLoader: NetworkImageLoader {
  private let domain: String
  private let sendUserAgent: Bool
  private let customUserAgent: String
  private var ongoingTasks: [URL: Task<CGImage, Error>] = [:]

  init(
    domain: String,
    sendUserAgent: Bool,
    customUserAgent: String
  ) {
    self.domain = domain
    self.sendUserAgent = sendUserAgent
    self.customUserAgent = customUserAgent
  }

  func image(from url: URL) async throws -> CGImage {
    if let task = ongoingTasks[url] {
      return try await task.value
    }

    let domain = self.domain
    let sendUserAgent = self.sendUserAgent
    let customUserAgent = self.customUserAgent

    let task = Task<CGImage, Error> {
      guard
        let data = await ImageCacheManager.shared.loadImageData(
          for: url,
          domain: domain,
          sendUserAgent: sendUserAgent,
          customUserAgent: customUserAgent
        )
      else {
        throw URLError(.badServerResponse)
      }

      guard
        let source = CGImageSourceCreateWithData(data as CFData, nil),
        let image = CGImageSourceCreateImageAtIndex(
          source,
          0,
          [kCGImageSourceShouldCache: true] as CFDictionary
        )
      else {
        throw URLError(.cannotDecodeContentData)
      }

      return image
    }

    ongoingTasks[url] = task

    defer { ongoingTasks.removeValue(forKey: url) }

    return try await task.value
  }
}