153 lines
3.8 KiB
Ruby
153 lines
3.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ArtistURL < ApplicationRecord
|
|
normalize :url, :normalize_url
|
|
|
|
validates :url, presence: true, uniqueness: { scope: :artist_id }
|
|
validate :validate_url_format
|
|
validate :validate_url_is_not_duplicate
|
|
belongs_to :artist, :touch => true
|
|
|
|
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.search(params, current_user)
|
|
q = search_attributes(params, [:id, :created_at, :updated_at, :url, :is_active, :artist], current_user: current_user)
|
|
q = q.urls_match(params[:url_matches])
|
|
|
|
case params[:order]
|
|
when /\A(id|artist_id|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.urls_match(urls)
|
|
urls = Array.wrap(urls).flat_map(&:split)
|
|
return all if urls.empty?
|
|
|
|
urls.map do |url|
|
|
url_matches(url)
|
|
end.reduce(&:or)
|
|
end
|
|
|
|
def self.url_matches(url)
|
|
if url.blank?
|
|
all
|
|
elsif url =~ %r{\A/(.*)/\z}
|
|
where_regex(:url, $1)
|
|
elsif url.include?("*")
|
|
where_ilike(:url, url)
|
|
elsif url =~ %r{\Ahttps?://}i
|
|
profile_url = Source::URL.profile_url(url) || Source::Extractor.find(url).profile_url || normalize_url(url)
|
|
where(url: profile_url)
|
|
else
|
|
where_ilike(:url, "*#{url}*")
|
|
end
|
|
end
|
|
|
|
def domain
|
|
parsed_url&.domain.to_s
|
|
end
|
|
|
|
def site_name
|
|
parsed_url&.site_name.to_s
|
|
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
|
|
when %r{blogimg\.jp}i, %r{image\.blog\.livedoor\.jp}i
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
# The sort order of sites in artist URL lists.
|
|
def priority
|
|
sites = %w[
|
|
Pixiv Twitter
|
|
Anifty ArtStation Baraag BCY Booth Deviant\ Art Hentai\ Foundry Fantia Furaffinity Foundation Lofter Nico\ Seiga Nijie Pawoo Fanbox Pixiv\ Sketch Plurk Tinami Tumblr Weibo
|
|
Ask.fm Facebook FC2 Gumroad Instagram Ko-fi Livedoor Mihuashi Mixi.jp Patreon Piapro.jp Picarto Privatter Sakura.ne.jp Stickam Skeb Twitch Youtube
|
|
Amazon Circle.ms DLSite Doujinshi.org Erogamescape Mangaupdates Melonbooks Toranoana Wikipedia
|
|
]
|
|
|
|
sites.index(site_name) || 1000
|
|
end
|
|
|
|
def self.normalize_url(url)
|
|
Source::URL.parse(url)&.profile_url || Danbooru::URL.parse(url)&.to_normalized_s || url
|
|
end
|
|
|
|
def url=(url)
|
|
super(url)
|
|
@parsed_url = Source::URL.parse(url)
|
|
end
|
|
|
|
def parsed_url
|
|
@parsed_url ||= Source::URL.parse(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 => e
|
|
errors.add(:url, "'#{uri}' is malformed: #{e}")
|
|
end
|
|
|
|
def validate_url_is_not_duplicate
|
|
artists = ArtistFinder.find_artists(url).without(artist)
|
|
|
|
artists.each do |a|
|
|
warnings.add(:base, "Duplicate of [[#{a.name}]]")
|
|
end
|
|
end
|
|
|
|
def self.available_includes
|
|
[:artist]
|
|
end
|
|
end
|