Files
danbooru/app/logical/sources/strategies/art_station.rb
BrokenEagle 2d88569fac Fixes issues with Artstation source strategy
The reason that the download was failing was not because the 4k size
didn't exist, but because the Artstation had no way to handle image
cover URLs. This caused it to pass nil to the download function.

Additionally, there was no way to get the preview URL size, i.e. the
smallest available image for an Arstation image URL.

- Adds support for cover URLs
- Adds support for preview URL size
2020-05-24 00:38:54 +00:00

148 lines
4.4 KiB
Ruby

# Page URLs:
#
# * https://www.artstation.com/artwork/04XA4
# * https://www.artstation.com/artwork/cody-from-sf
# * https://sa-dui.artstation.com/projects/DVERn
#
# Profile URLs:
#
# * https://www.artstation.com/artist/sa-dui
# * https://www.artstation.com/sa-dui
# * https://sa-dui.artstation.com/
# * https://hosi_na.artstation.com
#
# Image URLs
#
# * https://cdna.artstation.com/p/assets/images/images/005/804/224/large/titapa-khemakavat-sa-dui-srevere.jpg?1493887236
# * https://cdnb.artstation.com/p/assets/images/images/014/410/217/smaller_square/bart-osz-bartosz1812041.jpg?1543866276
# * https://cdna.artstation.com/p/assets/images/images/007/253/680/4k/ina-wong-demon-girl-done-ttd-comp.jpg?1504793833
#
# * https://cdna.artstation.com/p/assets/covers/images/007/262/828/small/monica-kyrie-1.jpg?1504865060
module Sources::Strategies
class ArtStation < Base
PROJECT1 = %r!\Ahttps?://www\.artstation\.com/artwork/(?<project_id>[a-z0-9-]+)/?\z!i
PROJECT2 = %r!\Ahttps?://(?<artist_name>[\w-]+)\.artstation\.com/projects/(?<project_id>[a-z0-9-]+)/?\z!i
PROJECT = Regexp.union(PROJECT1, PROJECT2)
ARTIST1 = %r{\Ahttps?://(?<artist_name>[\w-]+)(?<!www)\.artstation\.com/?\z}i
ARTIST2 = %r{\Ahttps?://www\.artstation\.com/artist/(?<artist_name>[\w-]+)/?\z}i
ARTIST3 = %r{\Ahttps?://www\.artstation\.com/(?<artist_name>[\w-]+)/?\z}i
ARTIST = Regexp.union(ARTIST1, ARTIST2, ARTIST3)
ASSET = %r!\Ahttps?://cdn\w*\.artstation\.com/p/assets/(?<type>images|covers)/images/(?<id>\d+/\d+/\d+)/(?<size>[^/]+)/(?<filename>.+)\z!i
attr_reader :json
def domains
["artstation.com"]
end
def site_name
"ArtStation"
end
def image_urls
@image_urls ||= image_urls_sub.map { |asset| asset_url(asset, :largest) }
end
def preview_urls
@preview_urls ||= image_urls_sub.map { |asset| asset_url(asset, :smallest) }
end
def page_url
return nil if project_id.blank?
if artist_name.present?
"https://#{artist_name}.artstation.com/projects/#{project_id}"
else
"https://www.artstation.com/artwork/#{project_id}"
end
end
def profile_url
return nil if artist_name.blank?
"https://www.artstation.com/#{artist_name}"
end
def artist_name
artist_name_from_url || api_response.dig(:user, :username)
end
def artist_commentary_title
api_response[:title]
end
def artist_commentary_desc
api_response[:description]
end
def dtext_artist_commentary_desc
ActionView::Base.full_sanitizer.sanitize(artist_commentary_desc)
end
def tags
api_response[:tags].to_a.map do |tag|
[tag, "https://www.artstation.com/search?q=" + CGI.escape(tag)]
end
end
def normalized_for_artist_finder?
profile_url.present? && url == profile_url
end
def image_urls_sub
if url.match?(ASSET)
return [url]
end
api_response[:assets]
.to_a
.select { |asset| asset[:asset_type] == "image" }
.map { |asset| asset[:image_url] }
end
# these are de facto private methods but are public for testing
# purposes
def artist_name_from_url
urls.map { |url| url[PROJECT, :artist_name] || url[ARTIST, :artist_name] }.compact.first
end
def project_id
urls.map { |url| url[PROJECT, :project_id] }.compact.first
end
def api_response
return {} if project_id.blank?
resp = Danbooru::Http.cache(1.minute).get("https://www.artstation.com/projects/#{project_id}.json")
return {} if resp.code != 200
resp.parse.with_indifferent_access
end
memoize :api_response
def image_url_sizes(type, id, filename)
[
"https://cdn.artstation.com/p/assets/#{type}/images/#{id}/original/#{filename}",
"https://cdn.artstation.com/p/assets/#{type}/images/#{id}/4k/#{filename}",
"https://cdn.artstation.com/p/assets/#{type}/images/#{id}/large/#{filename}",
"https://cdn.artstation.com/p/assets/#{type}/images/#{id}/medium/#{filename}",
"https://cdn.artstation.com/p/assets/#{type}/images/#{id}/small/#{filename}",
]
end
def asset_url(url, size)
return url unless url =~ ASSET
urls = image_url_sizes($~[:type], $~[:id], $~[:filename])
if size == :smallest
urls = urls.reverse()
end
chosen_url = urls.find { |url| http_exists?(url, headers) }
chosen_url || url
end
end
end