275 lines
6.7 KiB
Ruby
275 lines
6.7 KiB
Ruby
# typed: false
|
|
class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
|
VERSION_0 = Domain::Fa::Parser::Page::VERSION_0
|
|
VERSION_1 = Domain::Fa::Parser::Page::VERSION_1
|
|
VERSION_2 = Domain::Fa::Parser::Page::VERSION_2
|
|
|
|
def initialize(elem, page_version)
|
|
@elem = elem
|
|
@page_version = page_version
|
|
end
|
|
|
|
# https://webcache.googleusercontent.com/search?q=cache:L85loB7VJXwJ:https://forums.furaffinity.net/threads/question-about-the-username-prefix.1655691/&cd=10&hl=en&ct=clnk&gl=us
|
|
PREFIXES = [
|
|
"~", # regular user
|
|
"!", # suspended
|
|
"-", # banned (permanent)
|
|
"@", # admin
|
|
"∞", # deceased
|
|
]
|
|
|
|
def name
|
|
@name ||=
|
|
begin
|
|
elem =
|
|
case @page_version
|
|
when VERSION_0, VERSION_1
|
|
elem = @elem.css(".addpad.lead b")
|
|
when VERSION_2
|
|
@elem.css("userpage-nav-user-details username")
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
|
|
name = elem&.first&.text&.strip
|
|
|
|
if name
|
|
if @elem.css("userpage-nav-header img.userIcon.type-admin").first
|
|
# in newer versions of FA user pages, admins have no '@' prefix,
|
|
# but rather an indicator image icon
|
|
if PREFIXES.include?(name[0])
|
|
raise("invalid prefix for admin user name: #{name}")
|
|
end
|
|
name
|
|
elsif PREFIXES.include?(name[0])
|
|
name[1..]
|
|
else
|
|
if @elem.css("img.userIcon.faplus-icon")
|
|
# FA+ users have no prefix
|
|
name
|
|
else
|
|
raise("invalid prefix for name: #{name}")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def account_status
|
|
@account_status ||=
|
|
begin
|
|
if @elem.css("userpage-nav-header img.userIcon.type-admin").first
|
|
:admin
|
|
else
|
|
elem =
|
|
case @page_version
|
|
when VERSION_2
|
|
@elem.css("userpage-nav-user-details username")
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
name = elem&.first&.text&.strip || ""
|
|
|
|
case name[0]
|
|
when "~"
|
|
:active
|
|
when "!"
|
|
:suspended
|
|
when "-"
|
|
:banned
|
|
when "∞"
|
|
:deceased
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def full_name
|
|
@full_name ||= elem_after_text_match(main_about.children, /Full/).text.strip
|
|
end
|
|
|
|
def artist_type
|
|
@artist_type ||=
|
|
elem_after_text_match(main_about.children, /Type/).try(:text).try(:strip)
|
|
end
|
|
|
|
def profile_thumb_url
|
|
@profile_thumb_url ||=
|
|
case @page_version
|
|
when VERSION_0
|
|
@elem.css(".addpad.alt1 a img.avatar").first.try(:[], "src")
|
|
when VERSION_2
|
|
@elem.css("userpage-nav-avatar a.current img").first.try(:[], "src")
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
end
|
|
|
|
def registered_since
|
|
@registered_since ||=
|
|
case @page_version
|
|
when VERSION_0, VERSION_1
|
|
elem_after_text_match(main_about.children, /Registered/).text.strip
|
|
when VERSION_2
|
|
date_str =
|
|
@elem
|
|
.css("username span")
|
|
.find { |elem| elem&.text&.strip == "Registered:" }
|
|
&.next_sibling
|
|
&.text
|
|
&.strip
|
|
DateTime.parse(date_str) if date_str
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
end
|
|
|
|
def mood
|
|
@mood ||= elem_after_text_match(main_about.children, /mood/).text.strip
|
|
end
|
|
|
|
def profile_html
|
|
@profile_html ||= main_about.inner_html.force_encoding("utf-8")
|
|
end
|
|
|
|
def num_pageviews
|
|
@num_pageviews ||= stat_value(:pvs, 0)
|
|
end
|
|
|
|
def num_submissions
|
|
@num_submissions ||= stat_value(:subs, 1)
|
|
end
|
|
|
|
def num_comments_recieved
|
|
@num_comments_recieved ||= stat_value(:crec, 3)
|
|
end
|
|
|
|
def num_comments_given
|
|
@num_comments_given ||= stat_value(:cgiv, 4)
|
|
end
|
|
|
|
def num_journals
|
|
@num_journals ||= stat_value(:njr, 5)
|
|
end
|
|
|
|
def num_favorites
|
|
@num_favorites ||= stat_value(:nfav, 2)
|
|
end
|
|
|
|
def recent_fav_fa_ids
|
|
@recent_favs ||=
|
|
case @page_version
|
|
when VERSION_2
|
|
@elem
|
|
.css("#gallery-latest-favorites")
|
|
.first
|
|
&.css("figure a")
|
|
&.map do |elem|
|
|
href = elem["href"]
|
|
%r{/view/(\d+)}.match(href)[1]&.to_i ||
|
|
raise("invalid url: #{href}")
|
|
end || []
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
end
|
|
|
|
RecentUser =
|
|
Struct.new(:name, :url_name) do
|
|
def to_a
|
|
[name, url_name]
|
|
end
|
|
end
|
|
|
|
def recent_watchers
|
|
@recent_watchers ||= recent_users_for_section("Recent Watchers")
|
|
end
|
|
|
|
def recent_watching
|
|
@recent_watching ||= recent_users_for_section("Recently Watched")
|
|
end
|
|
|
|
private
|
|
|
|
def recent_users_for_section(section_name)
|
|
case @page_version
|
|
when VERSION_2
|
|
section_elem =
|
|
@elem
|
|
.css(".userpage-section-left")
|
|
.find do |elem|
|
|
elem.css(".section-header h2")&.first&.text&.strip == section_name
|
|
end
|
|
|
|
section_elem = section_elem.css(".section-body").first
|
|
section_elem
|
|
.css("a")
|
|
.map do |link_elem|
|
|
href = link_elem["href"]
|
|
url_name =
|
|
%r{/user/(.+)/}.match(href)&.[](1) || raise("invalid url: #{href}")
|
|
name = link_elem.css(".artist_name").first.text.strip
|
|
RecentUser.new(name, url_name)
|
|
end
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
end
|
|
|
|
def stat_value(legacy_name, redux_idx)
|
|
legacy_map =
|
|
if false # old mode?
|
|
{ pvs: 2, subs: 5, crec: 8, cgiv: 11, njr: 14, nfav: 17 }
|
|
else
|
|
{ pvs: 2, subs: 6, crec: 10, cgiv: 14, njr: 18, nfav: 22 }
|
|
end
|
|
|
|
value =
|
|
case @page_version
|
|
when VERSION_0, VERSION_1
|
|
statistics.children[legacy_map[legacy_name] || raise].text.strip.to_i
|
|
when VERSION_2
|
|
statistics.css(".highlight")[redux_idx]&.next_sibling&.text&.strip&.to_i
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
|
|
# FA databases can be a little weird
|
|
if value >= (2**32 - 1)
|
|
0
|
|
else
|
|
value
|
|
end
|
|
end
|
|
|
|
def statistics
|
|
@statistics ||=
|
|
case @page_version
|
|
when VERSION_0, VERSION_1
|
|
@elem.css(".ldot table tr:last-child td").first
|
|
when VERSION_2
|
|
@elem
|
|
.css(".userpage-layout-right-col-content .userpage-section-right")
|
|
.find do |child|
|
|
child.css(".section-header h2")&.first&.text&.strip == "Stats"
|
|
end
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
end
|
|
|
|
def main_about
|
|
@main_about ||=
|
|
case @page_version
|
|
when VERSION_0, VERSION_1
|
|
@elem.css(".alt1.addpad .ldot").first
|
|
when VERSION_2
|
|
@elem.css(".section-body.userpage-profile").first
|
|
else
|
|
unimplemented_version!
|
|
end
|
|
end
|
|
end
|