Files
danbooru/app/models/artist_url.rb
evazion 7b60a476e5 sources: add artist profile links to fetch source data box.
Add site icons linking to all the artist's sites in the fetch source
data box.

Some artist entries have a large number of URLs. Various heuristics are
applied to try to present the most useful URLs first. Dead URLs and
redundant URLs (Pixiv stacc and Twitter intent URLs) are filtered out.
Remaining URLs are sorted first by site (to put sites like Pixiv and
Twitter first), then by URL (to break ties when an artist has multiple
accounts on the same site).

Some sites have shitty hard-to-read icons. It can't be helped. The icons
are the official favicons of each site.
2021-02-26 01:24:30 -06:00

161 lines
4.6 KiB
Ruby

class ArtistUrl < ApplicationRecord
before_validation :initialize_normalized_url, on: :create
before_validation :normalize
validates :url, presence: true, uniqueness: { scope: :artist_id }
validate :validate_url_format
belongs_to :artist, :touch => true
scope :url_matches, ->(url) { url_attribute_matches(:url, url) }
scope :normalized_url_matches, ->(url) { url_attribute_matches(:normalized_url, url) }
scope :active, -> { where(is_active: true) }
def self.parse_prefix(url)
prefix, url = url.match(/\A(-)?(.*)/)[1, 2]
is_active = prefix.nil?
[is_active, url]
end
def self.normalize(url)
if url.nil?
nil
else
url = url.sub(%r!^https://!, "http://")
url = url.sub(%r!^http://blog-imgs-\d+\.fc2!, "http://blog.fc2")
url = url.sub(%r!^http://blog-imgs-\d+-\w+\.fc2!, "http://blog.fc2")
url = url.sub(%r!^http://blog\d*\.fc2\.com/(?:\w/){,3}(\w+)!, "http://\\1.blog.fc2.com")
url = url.sub(%r!^http://pictures.hentai-foundry.com//!, "http://pictures.hentai-foundry.com/")
# the strategy won't always work for twitter because it looks for a status
url = url.downcase if url =~ %r!^https?://(?:mobile\.)?twitter\.com!
url = Sources::Strategies.find(url).normalize_for_artist_finder
# XXX the Pixiv strategy should implement normalize_for_artist_finder and return the correct url directly.
url = url.sub(%r!\Ahttps?://www\.pixiv\.net/(?:en/)?users/(\d+)\z!i, 'https://www.pixiv.net/member.php?id=\1')
url = url.gsub(/\/+\Z/, "")
url = url.gsub(%r!^https://!, "http://")
url + "/"
end
end
def self.search(params = {})
q = search_attributes(params, :id, :created_at, :updated_at, :url, :normalized_url, :is_active, :artist)
q = q.url_matches(params[:url_matches])
q = q.normalized_url_matches(params[:normalized_url_matches])
case params[:order]
when /\A(id|artist_id|url|normalized_url|is_active|created_at|updated_at)(?:_(asc|desc))?\z/i
dir = $2 || :desc
q = q.order($1 => dir).order(id: :desc)
else
q = q.apply_default_order(params)
end
q
end
def self.url_attribute_matches(attr, url)
if url.blank?
all
elsif url =~ %r!\A/(.*)/\z!
where_regex(attr, $1)
elsif url.include?("*")
where_ilike(attr, url)
else
where(attr => normalize(url))
end
end
def domain
uri = Addressable::URI.parse(normalized_url)
uri.domain
end
def site_name
source = Sources::Strategies.find(normalized_url)
source.site_name
end
# A secondary URL is an artist URL that we don't normally want to display,
# usually because it's redundant with the primary profile URL.
def secondary_url?
case url
when %r!pixiv\.net/stacc!i
true
when %r!pixiv\.net/fanbox!i
true
when %r!twitter\.com/intent!i
true
when %r!lohas\.nicoseiga\.jp!i
true
when %r!(?:www|com|dic)\.nicovideo\.jp!i
true
when %r!pawoo\.net/web/accounts!i
true
when %r!www\.artstation\.com!i
true
else
false
end
end
# The sort order of sites in artist URL lists.
def priority
sites = %w[
Pixiv Twitter
ArtStation Deviant\ Art Nico\ Seiga Nijie pawoo.net Pixiv\ Fanbox Pixiv\ Sketch Tinami Tumblr
Booth.pm Facebook Fantia FC2 Gumroad Instagram Lofter Patreon Privatter Skeb Weibo Youtube
Circle.ms DLSite Melonbooks Toranoana
]
sites.index(site_name) || 1000
end
def normalize
# Perform some normalization with Addressable on the URL itself
# - Converts scheme and hostname to downcase
# - Converts unicode hostname to Punycode
uri = Addressable::URI.parse(url)
uri.site = uri.normalized_site
self.url = uri.to_s
self.normalized_url = self.class.normalize(url)
rescue Addressable::URI::InvalidURIError
# Don't bother normalizing the URL if there is errors
end
def initialize_normalized_url
self.normalized_url = url
end
def to_s
if is_active?
url
else
"-#{url}"
end
end
def validate_scheme(uri)
errors.add(:url, "'#{uri}' must begin with http:// or https:// ") unless uri.scheme.in?(%w[http https])
end
def validate_hostname(uri)
errors.add(:url, "'#{uri}' has a hostname '#{uri.host}' that does not contain a dot") unless uri.host&.include?('.')
end
def validate_url_format
uri = Addressable::URI.parse(url)
validate_scheme(uri)
validate_hostname(uri)
rescue Addressable::URI::InvalidURIError => error
errors.add(:url, "'#{uri}' is malformed: #{error}")
end
def self.available_includes
[:artist]
end
end