aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-04-23 02:27:13 -0700
committerFuwn <[email protected]>2025-04-23 02:27:13 -0700
commita01103249958dacbd40391b99c747aa53200b127 (patch)
tree8a5760812e85af326e7ffeef7341e26f91e4261d
parentchore: Add SwiftLint rules (diff)
downloadholobar-a01103249958dacbd40391b99c747aa53200b127.tar.xz
holobar-a01103249958dacbd40391b99c747aa53200b127.zip
style: Format all source files
-rw-r--r--HoloBar/Character.swift12
-rw-r--r--HoloBar/CharacterFetcher.swift209
-rw-r--r--HoloBar/HoloBarApp.swift118
3 files changed, 171 insertions, 168 deletions
diff --git a/HoloBar/Character.swift b/HoloBar/Character.swift
index d16b133..0bad13e 100644
--- a/HoloBar/Character.swift
+++ b/HoloBar/Character.swift
@@ -1,10 +1,10 @@
import Foundation
struct Character: Identifiable {
- let id = UUID()
- let name: String
- let profileURL: URL
- let avatarURL: URL
- let rawName: String
- let affiliation: String
+ let id = UUID()
+ let name: String
+ let profileURL: URL
+ let avatarURL: URL
+ let rawName: String
+ let affiliation: String
}
diff --git a/HoloBar/CharacterFetcher.swift b/HoloBar/CharacterFetcher.swift
index 7ba6854..ff5a059 100644
--- a/HoloBar/CharacterFetcher.swift
+++ b/HoloBar/CharacterFetcher.swift
@@ -2,124 +2,127 @@ import Foundation
import SwiftSoup
class CharacterFetcher: ObservableObject {
- @Published var characters: [Character] = []
+ @Published var characters: [Character] = []
- init() {
- let today = Calendar.current.dateComponents([.month, .day], from: Date())
+ init() {
+ let today = Calendar.current.dateComponents([.month, .day], from: Date())
- if let month = today.month, let day = today.day {
- fetchCharacters(for: month, day: day)
- }
+ if let month = today.month, let day = today.day {
+ fetchCharacters(for: month, day: day)
}
+ }
- func fetchCharacters(for month: Int, day: Int) {
- let urlString = "https://hololist.net/birthday/?birthday_month=\(String(format: "%02d", month))&birthday_day=\(String(format: "%02d", day))"
- guard let url = URL(string: urlString) else { return }
+ func fetchCharacters(for month: Int, day: Int) {
+ let urlString =
+ "https://hololist.net/birthday/?birthday_month=\(String(format: "%02d", month))&birthday_day=\(String(format: "%02d", day))"
+ guard let url = URL(string: urlString) else { return }
- let task = URLSession.shared.dataTask(with: url) { data, _, error in
- guard let data = data, error == nil,
- let html = String(data: data, encoding: .utf8) else { return }
+ let task = URLSession.shared.dataTask(with: url) { data, _, error in
+ guard let data = data, error == nil,
+ let html = String(data: data, encoding: .utf8)
+ else { return }
- DispatchQueue.main.async {
- self.fetchAffiliations(for: self.parseHTML(html: html))
- }
- }
+ DispatchQueue.main.async {
+ self.fetchAffiliations(for: self.parseHTML(html: html))
+ }
+ }
- task.resume()
+ task.resume()
+ }
+
+ private func parseHTML(html: String) -> [Character] {
+ var fetchedCharacters: [Character] = []
+
+ do {
+ let document = try SwiftSoup.parse(html)
+ let characterElements = try document.select("div.d-flex.mb-4.rounded")
+
+ for element in characterElements {
+ if let nameElement = try? element.select("a.line-truncate span").first(),
+ let linkElement = try? element.select("a.line-truncate").first(),
+ let profileHref = try? linkElement.attr("href"),
+ let profileURL = URL(string: profileHref)
+ {
+ let name = try nameElement.text()
+
+ fetchedCharacters
+ .append(
+ Character(
+ name: name,
+ profileURL: profileURL,
+ avatarURL: profileURL, // Avatar URLs are fetched in ``fetchAffiliations``
+ rawName: name,
+ affiliation: ""
+ )
+ )
+ }
+ }
+ } catch {
+ let blankURL = URL(string: "#")!
+
+ fetchedCharacters
+ .append(
+ Character(
+ name: "Error parsing HTML",
+ profileURL: blankURL,
+ avatarURL: blankURL,
+ rawName: "",
+ affiliation: ""
+ )
+ )
}
- private func parseHTML(html: String) -> [Character] {
- var fetchedCharacters: [Character] = []
+ return fetchedCharacters
+ }
+
+ private func fetchAffiliations(for characters: [Character]) {
+ let group = DispatchGroup()
+ var updatedCharacters: [Character] = []
+
+ for character in characters {
+ group.enter()
+
+ let task = URLSession.shared.dataTask(with: character.profileURL) {
+ data,
+ _,
+ error in
+ defer { group.leave() }
+
+ guard let data = data,
+ error == nil,
+ let html = String(data: data, encoding: .utf8)
+ else { return }
do {
- let document = try SwiftSoup.parse(html)
- let characterElements = try document.select("div.d-flex.mb-4.rounded")
-
- for element in characterElements {
- if let nameElement = try? element.select("a.line-truncate span").first(),
- let linkElement = try? element.select("a.line-truncate").first(),
- let profileHref = try? linkElement.attr("href"),
- let profileURL = URL(string: profileHref)
- {
- let name = try nameElement.text()
-
- fetchedCharacters
- .append(
- Character(
- name: name,
- profileURL: profileURL,
- avatarURL: profileURL, // Avatar URLs are fetched in ``fetchAffiliations``
- rawName: name,
- affiliation: ""
- )
- )
- }
- }
- } catch {
- let blankURL = URL(string: "#")!
-
- fetchedCharacters
- .append(
- Character(
- name: "Error parsing HTML",
- profileURL: blankURL,
- avatarURL: blankURL,
- rawName: "",
- affiliation: ""
- )
+ let document = try SwiftSoup.parse(html)
+
+ if let affiliationElement = try? document.select("#affiliation a").first(),
+ let affiliation = try? affiliationElement.text()
+ {
+ updatedCharacters
+ .append(
+ Character(
+ name: "\(character.name) (\(affiliation))",
+ profileURL: character.profileURL,
+ avatarURL: (try? document.select("#left img").first()?.attr("data-src"))
+ .flatMap { URL(string: $0) } ?? character.avatarURL,
+ rawName: character.name,
+ affiliation: affiliation
)
+ )
+ } else {
+ updatedCharacters.append(character)
+ }
+ } catch {
+ updatedCharacters.append(character)
}
+ }
- return fetchedCharacters
+ task.resume()
}
- private func fetchAffiliations(for characters: [Character]) {
- let group = DispatchGroup()
- var updatedCharacters: [Character] = []
-
- for character in characters {
- group.enter()
-
- let task = URLSession.shared.dataTask(with: character.profileURL) {
- data,
- _,
- error in
- defer { group.leave() }
-
- guard let data = data,
- error == nil,
- let html = String(data: data, encoding: .utf8) else { return }
-
- do {
- let document = try SwiftSoup.parse(html)
-
- if let affiliationElement = try? document.select("#affiliation a").first(),
- let affiliation = try? affiliationElement.text()
- {
- updatedCharacters
- .append(
- Character(
- name: "\(character.name) (\(affiliation))",
- profileURL: character.profileURL,
- avatarURL: (try? document.select("#left img").first()?.attr("data-src"))
- .flatMap { URL(string: $0) } ?? character.avatarURL,
- rawName: character.name,
- affiliation: affiliation
- )
- )
- } else {
- updatedCharacters.append(character)
- }
- } catch {
- updatedCharacters.append(character)
- }
- }
-
- task.resume()
- }
-
- group.notify(queue: .main) {
- self.characters = updatedCharacters
- }
+ group.notify(queue: .main) {
+ self.characters = updatedCharacters
}
+ }
}
diff --git a/HoloBar/HoloBarApp.swift b/HoloBar/HoloBarApp.swift
index eac0acd..650495b 100644
--- a/HoloBar/HoloBarApp.swift
+++ b/HoloBar/HoloBarApp.swift
@@ -2,75 +2,75 @@ import SwiftUI
@main
struct HoloBarApp: App {
- @StateObject private var fetcher = CharacterFetcher()
- @State private var showAvatars = false
+ @StateObject private var fetcher = CharacterFetcher()
+ @State private var showAvatars = false
- var body: some Scene {
- MenuBarExtra {
- VStack {
- if fetcher.characters.isEmpty {
- Text("Loading …")
- } else {
- ForEach(fetcher.characters) { character in
- Button(action: {
- NSWorkspace.shared.open(character.profileURL)
- }) {
- HStack {
- if showAvatars {
- AsyncImage(url: character.avatarURL) { phase in
- if let image = phase.image {
- image
- .resizable()
- .scaledToFill()
- } else if phase.error != nil {
- Image(systemName: "person.crop.circle.badge.exclamationmark")
- .resizable()
- .scaledToFit()
- .foregroundStyle(.gray)
- } else {
- Image(systemName: "person.crop.circle")
- .resizable()
- .scaledToFit()
- .foregroundStyle(.gray)
- }
- }
- }
-
- Text(character.name)
- }
- }
+ var body: some Scene {
+ MenuBarExtra {
+ VStack {
+ if fetcher.characters.isEmpty {
+ Text("Loading …")
+ } else {
+ ForEach(fetcher.characters) { character in
+ Button(action: {
+ NSWorkspace.shared.open(character.profileURL)
+ }) {
+ HStack {
+ if showAvatars {
+ AsyncImage(url: character.avatarURL) { phase in
+ if let image = phase.image {
+ image
+ .resizable()
+ .scaledToFill()
+ } else if phase.error != nil {
+ Image(systemName: "person.crop.circle.badge.exclamationmark")
+ .resizable()
+ .scaledToFit()
+ .foregroundStyle(.gray)
+ } else {
+ Image(systemName: "person.crop.circle")
+ .resizable()
+ .scaledToFit()
+ .foregroundStyle(.gray)
}
+ }
}
- Divider()
+ Text(character.name)
+ }
+ }
+ }
+ }
- #if DEBUG
- Button("Simulate Day Change") {
- NotificationCenter.default.post(name: .NSCalendarDayChanged, object: nil)
- }
- #endif
+ Divider()
- Button("\(showAvatars ? "Hide" : "Show") Avatars") {
- showAvatars.toggle()
- }
+ #if DEBUG
+ Button("Simulate Day Change") {
+ NotificationCenter.default.post(name: .NSCalendarDayChanged, object: nil)
+ }
+ #endif
- Button("Refresh", action: refreshCharacters)
- Button("Quit", action: { NSApplication.shared.terminate(nil) })
- }
- .onReceive(NotificationCenter.default.publisher(for: .NSCalendarDayChanged)) { _ in
- refreshCharacters()
- }
- } label: {
- Text("HL")
+ Button("\(showAvatars ? "Hide" : "Show") Avatars") {
+ showAvatars.toggle()
}
+
+ Button("Refresh", action: refreshCharacters)
+ Button("Quit", action: { NSApplication.shared.terminate(nil) })
+ }
+ .onReceive(NotificationCenter.default.publisher(for: .NSCalendarDayChanged)) { _ in
+ refreshCharacters()
+ }
+ } label: {
+ Text("HL")
}
+ }
- private func refreshCharacters() {
- let today = Calendar.current.dateComponents([.month, .day], from: Date())
+ private func refreshCharacters() {
+ let today = Calendar.current.dateComponents([.month, .day], from: Date())
- if let month = today.month, let day = today.day {
- fetcher.characters.removeAll()
- fetcher.fetchCharacters(for: month, day: day)
- }
+ if let month = today.month, let day = today.day {
+ fetcher.characters.removeAll()
+ fetcher.fetchCharacters(for: month, day: day)
}
+ }
}