From a7ed81fa6c07afbdb417ac03b16f55ea80c33247 Mon Sep 17 00:00:00 2001 From: Ceylo Date: Fri, 27 Dec 2024 14:23:13 +0100 Subject: [PATCH] Display folders and allow navigating them --- FAKit/Sources/FAKit/FAUserGalleryLike.swift | 14 +- .../FAPages/FAUserGalleryLikePage.swift | 67 ++- .../FAPagesTests/FAJournalsPageTests.swift | 10 +- .../FAUserGalleryLikePageTests.swift | 114 ++--- ....furaffinity.net:favorites:tiaamaito:.html | 124 +++--- ...w.furaffinity.net:gallery:furrycount:.html | 52 ++- ...ww.furaffinity.net:gallery:tiaamaito:.html | 389 +++++++++--------- ...ww.furaffinity.net:journals:tiaamaito.html | 256 ++++++------ ...www.furaffinity.net:scraps:tiaamaito:.html | 52 ++- FurAffinity/Helper Views/RemoteView.swift | 2 +- .../Helpers/FASession+CanvasPreview.swift | 45 ++ FurAffinity/User/UserGalleryLikeView.swift | 36 +- 12 files changed, 630 insertions(+), 531 deletions(-) diff --git a/FAKit/Sources/FAKit/FAUserGalleryLike.swift b/FAKit/Sources/FAKit/FAUserGalleryLike.swift index 84e9e0f..ba114df 100644 --- a/FAKit/Sources/FAKit/FAUserGalleryLike.swift +++ b/FAKit/Sources/FAKit/FAUserGalleryLike.swift @@ -10,25 +10,32 @@ import FAPages /// The representation for a gallery-like page (gallery, scraps, favorites) public struct FAUserGalleryLike: Sendable, Equatable { + public typealias FolderGroup = FAFolderGroup + public typealias Folder = FAFolder + public let displayAuthor: String public let previews: [FASubmissionPreview] public let nextPageUrl: URL? + public let folderGroups: [FolderGroup] public init( displayAuthor: String, previews: [FASubmissionPreview], - nextPageUrl: URL? + nextPageUrl: URL?, + folderGroups: [FolderGroup] ) { self.displayAuthor = displayAuthor self.previews = previews self.nextPageUrl = nextPageUrl + self.folderGroups = folderGroups } public func appending(_ gallery: Self) -> Self { .init( displayAuthor: displayAuthor, previews: previews + gallery.previews, - nextPageUrl: gallery.nextPageUrl + nextPageUrl: gallery.nextPageUrl, + folderGroups: folderGroups ) } } @@ -40,7 +47,8 @@ extension FAUserGalleryLike { previews: page.previews .compactMap { $0 } .map { FASubmissionPreview($0) }, - nextPageUrl: page.nextPageUrl + nextPageUrl: page.nextPageUrl, + folderGroups: page.folderGroups ) } } diff --git a/FAKit/Sources/FAPages/FAUserGalleryLikePage.swift b/FAKit/Sources/FAPages/FAUserGalleryLikePage.swift index d11f5b8..8046577 100644 --- a/FAKit/Sources/FAPages/FAUserGalleryLikePage.swift +++ b/FAKit/Sources/FAPages/FAUserGalleryLikePage.swift @@ -8,16 +8,35 @@ import Foundation @preconcurrency import SwiftSoup -public enum FAFolderItem: Sendable, Equatable { - case section(title: String) - case folder(title: String, url: URL) +public struct FAFolderGroup: Sendable, Hashable, Identifiable { + public let title: String? + public let folders: [FAFolder] + public let id = UUID() + + public init(title: String?, folders: [FAFolder]) { + self.title = title + self.folders = folders + } +} + +public struct FAFolder: Sendable, Hashable, Identifiable { + public let title: String + public let url: URL + public let isActive: Bool + public let id = UUID() + + public init(title: String, url: URL, isActive: Bool) { + self.title = title + self.url = url + self.isActive = isActive + } } public struct FAUserGalleryLikePage: Sendable { public let previews: [FASubmissionsPage.Submission?] public let displayAuthor: String public let nextPageUrl: URL? - public let folderItems: [FAFolderItem] + public let folderGroups: [FAFolderGroup] } extension FAUserGalleryLikePage { @@ -55,16 +74,16 @@ extension FAUserGalleryLikePage { self.nextPageUrl = nil } - let folderItemsQuery = "div#page-galleryscraps div#columnpage div.sidebar div.folder-list div.user-folders" + let folderItemsQuery = "div#page-galleryscraps div#columnpage div div.folder-list div.user-folders" let userItems = try siteContentNode.select(folderItemsQuery) - self.folderItems = try Self.parseFolderItems(from: userItems, currentUrl: url) + self.folderGroups = try Self.parseFolderGroups(from: userItems, currentUrl: url) } catch { logger.error("\(#file, privacy: .public) - \(error, privacy: .public)") return nil } } - static func parseFolderItems(from node: SwiftSoup.Elements, currentUrl: URL) throws -> [FAFolderItem] { + static func parseFolderGroups(from node: SwiftSoup.Elements, currentUrl: URL) throws -> [FAFolderGroup] { enum Error: Swift.Error { case unexpectedStructure } @@ -77,8 +96,12 @@ extension FAUserGalleryLikePage { } } - func parseFolder(in liNode: SwiftSoup.Element) throws -> FAFolderItem { - let title = try liNode.text() + func parseFolder(in liNode: SwiftSoup.Element) throws -> FAFolder { + var title = try liNode.text() + if title.starts(with: "❯❯ ") { + title = String(title.dropFirst(3)) + } + let isActive = liNode.hasClass("active") let url: URL if let linkNode = try? liNode.select("a").first() { let urlStr = try linkNode.attr("href") @@ -86,24 +109,32 @@ extension FAUserGalleryLikePage { } else { url = currentUrl } - return .folder(title: title, url: url) + return .init(title: title, url: url, isActive: isActive) } - var folderItems = [FAFolderItem]() + var folderGroups = [FAFolderGroup]() + var unfinishedFolderGroupTitle: String? + for child in node[0].children() { if child.tagName() == "div" && child.hasClass("container-item-top") { - let title = try child.text() - folderItems.append(.section(title: title)) - } else if child.tagName() == "div" && child.hasClass("default-folders") { - folderItems.append(contentsOf: try child.select("li").map(parseFolder)) - } else if child.tagName() == "ul" { - folderItems.append(contentsOf: try child.select("li").map(parseFolder)) + unfinishedFolderGroupTitle = try child.text() + } else if (child.tagName() == "div" && child.hasClass("default-folders")) || child.tagName() == "ul" { + // HTML structure is modified on mobile and first item is missing + if unfinishedFolderGroupTitle == nil && folderGroups.isEmpty { + unfinishedFolderGroupTitle = "Gallery Folders" + } + let folders = try child.select("li").map(parseFolder) + folderGroups.append(.init( + title: unfinishedFolderGroupTitle.take(), + folders: folders + )) } else { let html = (try? child.html()) ?? "" logger.error("Unhandled tag \(child.tagName(), privacy: .public) in \(html, privacy: .public)") throw Error.unexpectedStructure } } - return folderItems + + return folderGroups } } diff --git a/FAKit/Tests/FAPagesTests/FAJournalsPageTests.swift b/FAKit/Tests/FAPagesTests/FAJournalsPageTests.swift index 7462884..40382c4 100644 --- a/FAKit/Tests/FAPagesTests/FAJournalsPageTests.swift +++ b/FAKit/Tests/FAPagesTests/FAJournalsPageTests.swift @@ -27,19 +27,19 @@ struct FAJournalsPageTests { #expect(page.journals.count == 25) #expect(page.journals.prefix(5) == [ .init(id: 10954574, title: "I'll resume posting art!", - datetime: "Sep 14, 2024 03:17 AM", naturalDatetime: "a month ago", + datetime: "Sep 14, 2024 04:17 AM", naturalDatetime: "3 months ago", url: URL(string: "https://www.furaffinity.net/journal/10954574/")!), .init(id: 10893232, title: "fullbody commissions (CLOSED)", - datetime: "Jun 23, 2024 07:14 PM", naturalDatetime: "3 months ago", + datetime: "Jun 23, 2024 08:14 PM", naturalDatetime: "6 months ago", url: URL(string: "https://www.furaffinity.net/journal/10893232/")!), .init(id: 10877414, title: "Pride themed group YCH closed!!", - datetime: "Jun 1, 2024 03:03 AM", naturalDatetime: "4 months ago", + datetime: "Jun 1, 2024 04:03 AM", naturalDatetime: "7 months ago", url: URL(string: "https://www.furaffinity.net/journal/10877414/")!), .init(id: 10815815, title: "Change on commissions!", - datetime: "Mar 2, 2024 03:13 AM", naturalDatetime: "7 months ago", + datetime: "Mar 2, 2024 04:13 AM", naturalDatetime: "10 months ago", url: URL(string: "https://www.furaffinity.net/journal/10815815/")!), .init(id: 10691323, title: "Follow me on BlueSky! (and other places)", - datetime: "Sep 20, 2023 02:50 AM", naturalDatetime: "a year ago", + datetime: "Sep 20, 2023 03:50 AM", naturalDatetime: "a year ago", url: URL(string: "https://www.furaffinity.net/journal/10691323/")!), ]) } diff --git a/FAKit/Tests/FAPagesTests/FAUserGalleryLikePageTests.swift b/FAKit/Tests/FAPagesTests/FAUserGalleryLikePageTests.swift index 79b0e5a..5e8595b 100644 --- a/FAKit/Tests/FAPagesTests/FAUserGalleryLikePageTests.swift +++ b/FAKit/Tests/FAPagesTests/FAUserGalleryLikePageTests.swift @@ -9,45 +9,51 @@ import XCTest @testable import FAPages final class FAUserGalleryLikePageTests: XCTestCase { - let tiaamaitoFolders: [FAFolderItem] = [ - .section(title: "Gallery Folders"), - .folder(title: "❯❯ Main Gallery", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/")!), - .folder(title: "Scraps", url: URL(string: "https://www.furaffinity.net/scraps/tiaamaito/")!), - .section(title: "Personal"), - .folder(title: "Chuvareu", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147920/Chuvareu")!), - .folder(title: "Chuvareu Comic (archieved)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/292599/Chuvareu-Comic-archieved")!), - .folder(title: "Bakemono Family", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/418988/Bakemono-Family")!), - .folder(title: "chars as animals", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/456419/chars-as-animals")!), - .folder(title: "the tiniest lord", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566887/the-tiniest-lord")!), - .folder(title: "Ribbon Pooch & Co", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566888/Ribbon-Pooch-Co")!), - .folder(title: "Kijani", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566890/Kijani")!), - .folder(title: "Digital Pack", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566891/Digital-Pack")!), - .section(title: "Closed Species"), - .folder(title: "Sushi Dogs", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566883/Sushi-Dogs")!), - .folder(title: "Griffia", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566884/Griffia")!), - .folder(title: "Memory Keepers", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/720355/Memory-Keepers")!), - .section(title: "for Sale"), - .folder(title: "P2U", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/473101/P2U")!), - .folder(title: "Adopts", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/473103/Adopts")!), - .folder(title: "Traditional Pieces", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/495402/Traditional-Pieces")!), - .folder(title: "Other", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/547857/Other")!), - .folder(title: "Art Prints", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/684620/Art-Prints")!), - .section(title: "Patreon"), - .folder(title: "2016", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/135452/2016")!), - .folder(title: "2017", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/297815/2017")!), - .folder(title: "2018", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/459438/2018")!), - .folder(title: "2019", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/613283/2019")!), - .folder(title: "2020", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/754413/2020")!), - .folder(title: "2021", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/937613/2021")!), - .section(title: "Commissions"), - .folder(title: "standard (cell shading)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147923/standard-cell-shading")!), - .folder(title: "clear (soft shading)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147924/clear-soft-shading")!), - .folder(title: "basic (base colors)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147925/basic-base-colors")!), - .folder(title: "reference sheet", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147927/reference-sheet")!), - .folder(title: "YCH", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147928/YCH")!), - .folder(title: "telegram stickers", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/415109/telegram-stickers")!), - .folder(title: "special", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/578261/special")!), - .folder(title: "old works", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147929/old-works")!), + let tiaamaitoFolders: [FAFolderGroup] = [ + .init(title: "Gallery Folders", folders: [ + .init(title: "Main Gallery", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/")!, isActive: true), + .init(title: "Scraps", url: URL(string: "https://www.furaffinity.net/scraps/tiaamaito/")!, isActive: false) + ]), + .init(title: "Personal", folders: [ + .init(title: "Chuvareu", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147920/Chuvareu")!, isActive: false), + .init(title: "Chuvareu Comic (archieved)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/292599/Chuvareu-Comic-archieved")!, isActive: false), + .init(title: "Bakemono Family", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/418988/Bakemono-Family")!, isActive: false), + .init(title: "chars as animals", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/456419/chars-as-animals")!, isActive: false), + .init(title: "the tiniest lord", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566887/the-tiniest-lord")!, isActive: false), + .init(title: "Ribbon Pooch & Co", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566888/Ribbon-Pooch-Co")!, isActive: false), + .init(title: "Kijani", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566890/Kijani")!, isActive: false), + .init(title: "Digital Pack", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566891/Digital-Pack")!, isActive: false), + ]), + .init(title: "Closed Species", folders: [ + .init(title: "Sushi Dogs", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566883/Sushi-Dogs")!, isActive: false), + .init(title: "Griffia", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/566884/Griffia")!, isActive: false), + .init(title: "Memory Keepers", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/720355/Memory-Keepers")!, isActive: false), + ]), + .init(title: "for Sale", folders: [ + .init(title: "P2U", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/473101/P2U")!, isActive: false), + .init(title: "Adopts", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/473103/Adopts")!, isActive: false), + .init(title: "Traditional Pieces", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/495402/Traditional-Pieces")!, isActive: false), + .init(title: "Other", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/547857/Other")!, isActive: false), + .init(title: "Art Prints", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/684620/Art-Prints")!, isActive: false), + ]), + .init(title: "Patreon", folders: [ + .init(title: "2016", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/135452/2016")!, isActive: false), + .init(title: "2017", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/297815/2017")!, isActive: false), + .init(title: "2018", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/459438/2018")!, isActive: false), + .init(title: "2019", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/613283/2019")!, isActive: false), + .init(title: "2020", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/754413/2020")!, isActive: false), + .init(title: "2021", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/937613/2021")!, isActive: false), + ]), + .init(title: "Commissions", folders: [ + .init(title: "standard (cell shading)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147923/standard-cell-shading")!, isActive: false), + .init(title: "clear (soft shading)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147924/clear-soft-shading")!, isActive: false), + .init(title: "basic (base colors)", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147925/basic-base-colors")!, isActive: false), + .init(title: "reference sheet", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147927/reference-sheet")!, isActive: false), + .init(title: "YCH", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147928/YCH")!, isActive: false), + .init(title: "telegram stickers", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/415109/telegram-stickers")!, isActive: false), + .init(title: "special", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/578261/special")!, isActive: false), + .init(title: "old works", url: URL(string: "https://www.furaffinity.net/gallery/tiaamaito/folder/147929/old-works")!, isActive: false), + ]) ] func testFirstGalleryPage_72itemsParsed() async throws { @@ -59,11 +65,11 @@ final class FAUserGalleryLikePageTests: XCTestCase { XCTAssertEqual(page.displayAuthor, "tiaamaito") let preview = FASubmissionsPage.Submission( - sid: 58689926, - url: URL(string: "https://www.furaffinity.net/view/58689926/")!, - thumbnailUrl: URL(string: "https://t.furaffinity.net/58689926@400-1730507414.jpg")!, - thumbnailWidthOnHeightRatio: 1.73507, - title: "🧸 Fandom Pins Kickstarter ✨", + sid: 59265003, + url: URL(string: "https://www.furaffinity.net/view/59265003/")!, + thumbnailUrl: URL(string: "https://t.furaffinity.net/59265003@300-1734913553.jpg")!, + thumbnailWidthOnHeightRatio: 1.4705901, + title: "CM - Houseboat", author: "tiaamaito", displayAuthor: "tiaamaito" ) @@ -72,7 +78,7 @@ final class FAUserGalleryLikePageTests: XCTestCase { URL(string: "https://www.furaffinity.net/gallery/tiaamaito/2/")!, page.nextPageUrl ) - XCTAssertEqual(tiaamaitoFolders, page.folderItems) + XCTAssertEqual(tiaamaitoFolders, page.folderGroups) } func testEmptyGalleryPage_parsedWithNoContent() async throws { @@ -83,7 +89,7 @@ final class FAUserGalleryLikePageTests: XCTestCase { XCTAssertEqual(page.previews.count, 0) XCTAssertEqual(page.displayAuthor, "Furrycount") XCTAssertEqual(page.nextPageUrl, nil) - XCTAssertEqual(page.folderItems, []) + XCTAssertEqual(page.folderGroups, []) } func testScrapsPage_72itemsParsed() async throws { @@ -108,7 +114,7 @@ final class FAUserGalleryLikePageTests: XCTestCase { URL(string: "https://www.furaffinity.net/scraps/tiaamaito/2/")!, page.nextPageUrl ) - XCTAssertEqual(page.folderItems.count, 38) + XCTAssertEqual(page.folderGroups.count, 6) } func testFavoritesPage_72itemsParsed() async throws { @@ -120,19 +126,19 @@ final class FAUserGalleryLikePageTests: XCTestCase { XCTAssertEqual(page.displayAuthor, "tiaamaito") let preview = FASubmissionsPage.Submission( - sid: 58678021, - url: URL(string: "https://www.furaffinity.net/view/58678021/")!, - thumbnailUrl: URL(string: "https://t.furaffinity.net/58678021@400-1730425229.jpg")!, - thumbnailWidthOnHeightRatio: 2.021366, - title: "Reward - Oooo Spooky Month πŸ‘»", + sid: 59039707, + url: URL(string: "https://www.furaffinity.net/view/59039707/")!, + thumbnailUrl: URL(string: "https://t.furaffinity.net/59039707@300-1733178293.jpg")!, + thumbnailWidthOnHeightRatio: 1.081205, + title: "WI - Comfort/No Hurt", author: "shiroganeryo", displayAuthor: "ShiroganeRyo" ) XCTAssertEqual(preview, page.previews[0]) XCTAssertEqual( - URL(string: "https://www.furaffinity.net/favorites/tiaamaito/1523944993/next")!, + URL(string: "https://www.furaffinity.net/favorites/tiaamaito/1528468491/next")!, page.nextPageUrl ) - XCTAssertEqual(page.folderItems, []) + XCTAssertEqual(page.folderGroups, []) } } diff --git a/FAKit/Tests/FAPagesTests/data/www.furaffinity.net:favorites:tiaamaito:.html b/FAKit/Tests/FAPagesTests/data/www.furaffinity.net:favorites:tiaamaito:.html index 716512b..d244f2a 100644 --- a/FAKit/Tests/FAPagesTests/data/www.furaffinity.net:favorites:tiaamaito:.html +++ b/FAKit/Tests/FAPagesTests/data/www.furaffinity.net:favorites:tiaamaito:.html @@ -26,11 +26,11 @@ - - + + - + @@ -39,15 +39,15 @@ - + - + - - + + @@ -56,7 +56,7 @@ - + @@ -94,7 +94,7 @@
- Furrycount + Furrycount

Furrycount

Userpage | Notes | @@ -188,8 +188,9 @@

- 150S - 10J + 190S + 1C + 12J
@@ -259,13 +260,14 @@

Trouble Tickets

  • - 150S - 10J + 190S + 1C + 12J
  • - Furrycount + Furrycount
  • @@ -364,15 +366,7 @@

    Security

    - - - -
    +
    - 61111 Users online — - 2631 guests, - 11695 registered - and 46785 other - + 80923 Users online — + 3452 guests, + 15654 registered + and 61817 other +
    Limit bot activity to periods with less than 10k registered users online. @@ -713,7 +707,7 @@

    © 2005-2024 Frost Dragon Art LLC
    - Server Time: Nov 3, 2024 05:38 AM
    + Server Time: Dec 26, 2024 02:06 PM @@ -723,8 +717,8 @@

    + Server Local Time: Dec 26, 2024 02:06 PM
    + Page generated in 0.029 seconds [ 13.1% PHP, 86.9% SQL ] (24 queries) --> @@ -739,9 +733,9 @@

    - + - - + + @@ -51,7 +51,7 @@ - + @@ -89,7 +89,7 @@
    - Furrycount + Furrycount

    Furrycount

    Userpage | Notes | @@ -183,8 +183,9 @@

    - 150S - 10J + 190S + 1C + 12J
    @@ -254,13 +255,14 @@

    Trouble Tickets

  • - 150S - 10J + 190S + 1C + 12J
  • - Furrycount + Furrycount
  • @@ -359,15 +361,7 @@

    Security

    - - - -
    +
    - 60920 Users online — - 2664 guests, - 11666 registered - and 46590 other - + 80923 Users online — + 3452 guests, + 15654 registered + and 61817 other +
    Limit bot activity to periods with less than 10k registered users online. @@ -551,7 +545,7 @@

    © 2005-2024 Frost Dragon Art LLC
    - Server Time: Nov 3, 2024 05:37 AM
    + Server Time: Dec 26, 2024 02:06 PM @@ -561,8 +555,8 @@

    + Server Local Time: Dec 26, 2024 02:06 PM
    + Page generated in 0.012 seconds [ 23.1% PHP, 76.9% SQL ] (24 queries) --> @@ -577,9 +571,9 @@

    - + - - + + @@ -57,7 +57,7 @@ - + @@ -95,7 +95,7 @@
    - Furrycount + Furrycount

    Furrycount

    Userpage | Notes | @@ -189,8 +189,9 @@

    - 150S - 10J + 190S + 1C + 12J
    @@ -260,13 +261,14 @@

    Trouble Tickets

  • - 150S - 10J + 190S + 1C + 12J
  • - Furrycount + Furrycount
  • @@ -365,15 +367,7 @@

    Security

    - - - -
    +
    + @@ -798,7 +793,7 @@

    Commissions

    @@ -839,11 +834,11 @@

    Commissions

    - 60749 Users online — - 2670 guests, - 11669 registered - and 46410 other - + 84212 Users online — + 3426 guests, + 15859 registered + and 64927 other +
    Limit bot activity to periods with less than 10k registered users online. @@ -851,7 +846,7 @@

    Commissions

    © 2005-2024 Frost Dragon Art LLC
    - Server Time: Nov 3, 2024 05:36 AM
    + Server Time: Dec 26, 2024 02:28 PM @@ -861,8 +856,8 @@

    Commissions

    + Server Local Time: Dec 26, 2024 02:28 PM
    + Page generated in 0.014 seconds [ 27.4% PHP, 72.6% SQL ] (24 queries) --> @@ -877,9 +872,9 @@

    Commissions

    - + - - + + @@ -40,7 +40,7 @@ - + @@ -78,7 +78,7 @@
    - Furrycount + Furrycount

    Furrycount

    Userpage | Notes | @@ -172,8 +172,9 @@

    - 148S - 9J + 190S + 1C + 12J
    @@ -243,13 +244,14 @@

    Trouble Tickets

  • - 148S - 9J + 190S + 1C + 12J
  • - Furrycount + Furrycount
  • @@ -379,7 +381,7 @@

    - πŸ‘‘ the tiniest lord | Registered: Nov 26, 2008 07:40 + πŸ‘‘ the tiniest lord | Registered: Nov 26, 2008 08:40
    @@ -437,103 +439,103 @@

    @@ -553,10 +555,10 @@

    I'll resume posting art!

    - Posted a month ago + Posted 3 months ago
    -