summaryrefslogtreecommitdiff
path: root/Sora/Data/Booru/BooruPostXMLParser.swift
blob: 79827aa46244a809154760175bff1c6df76e6c38 (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
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
  }
}