summaryrefslogtreecommitdiff
path: root/Sora/Data/Booru/BooruPostXMLParser.swift
blob: 5149e051dffaa9f093ba383686b8f13a103a25d8 (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
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
125
126
127
import Foundation

class BooruPostXMLParser: NSObject, XMLParserDelegate {
  private var posts: [BooruPost] = []
  private var currentPost: BooruPost?
  private var parser: XMLParser

  init(data: Data) {
    parser = XMLParser(data: data)

    super.init()

    parser.delegate = self
  }

  func parse() -> [BooruPost] {
    parser.parse()

    return posts
  }

  func parser(
    _: XMLParser,
    didStartElement elementName: String,
    namespaceURI _: String?,
    qualifiedName _: String?,
    attributes attributeDict: [String: String] = [:]
  ) {
    if elementName == "post" {
      guard let id = attributeDict["id"],
        let heightStr = attributeDict["height"],
        let height = Int(heightStr),
        let score = attributeDict["score"],
        let fileUrl = attributeDict["file_url"],
        let parentId = attributeDict["parent_id"],
        let sampleUrl = attributeDict["sample_url"],
        let sampleWidthStr = attributeDict["sample_width"],
        let sampleWidth = Int(sampleWidthStr),
        let sampleHeightStr = attributeDict["sample_height"],
        let sampleHeight = Int(sampleHeightStr),
        let previewUrl = attributeDict["preview_url"],
        let rating = attributeDict["rating"],
        let tags = attributeDict["tags"],
        let widthStr = attributeDict["width"],
        let width = Int(widthStr),
        let change = attributeDict["change"],
        let md5 = attributeDict["md5"],
        let creatorId = attributeDict["creator_id"],
        let hasChildrenStr = attributeDict["has_children"],
        let createdAt = attributeDict["created_at"],
        let status = attributeDict["status"],
        let source = attributeDict["source"],
        let previewWidthStr = attributeDict["preview_width"],
        let previewWidth = Int(previewWidthStr),
        let previewHeightStr = attributeDict["preview_height"],
        let previewHeight = Int(previewHeightStr)
      else {
        return
      }

      let hasNotesStr = attributeDict["has_notes"] ?? "false"
      let hasCommentsStr = attributeDict["has_comments"] ?? "false"

      currentPost = BooruPost(
        id: id,
        height: height,
        score: score,
        fileURL: URL(string: fileUrl)!,
        parentID: parentId,
        sampleURL: URL(string: sampleUrl)!,
        sampleWidth: sampleWidth,
        sampleHeight: sampleHeight,
        previewURL: URL(string: previewUrl)!,
        rating: rating,
        tags: tags.components(separatedBy: " ").filter { !$0.isEmpty },
        width: width,
        change: change,
        md5: md5,
        creatorID: creatorId,
        hasChildren: hasChildrenStr == "true",
        createdAt: parseCreatedAt(createdAt)!,
        status: status,
        source: source,
        hasNotes: hasNotesStr == "true",
        hasComments: hasCommentsStr == "true",
        previewWidth: previewWidth,
        previewHeight: previewHeight
      )
    }
  }

  func parser(
    _: XMLParser,
    didEndElement elementName: String,
    namespaceURI _: String?,
    qualifiedName _: String?
  ) {
    if elementName == "post", let post = currentPost {
      posts.append(post)

      currentPost = nil
    }
  }

  #if DEBUG
    func parser(_: XMLParser, parseErrorOccurred parseError: any Error) {
      print("parser: \(parseError)")
    }
  #endif

  func parseCreatedAt(_ input: String) -> Date? {
    let dateFormatter = DateFormatter()

    dateFormatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
    dateFormatter.locale = Locale(identifier: "en_US_POSIX")

    if let date = dateFormatter.date(from: input) {
      return date
    }

    if let timestamp = Double(input) {
      return Date(timeIntervalSince1970: timestamp)
    }

    return nil
  }
}