Add Fantia support

Also fixes a regression in 74fdeef10c
that stopped mastodon urls from being given the right priority.
This commit is contained in:
nonamethanks
2022-03-10 17:35:04 +01:00
parent 43a665a66d
commit a6549bc6fe
10 changed files with 431 additions and 2 deletions

View File

@@ -46,6 +46,8 @@ module ArtistFinder
"facebook.com", # https://www.facebook.com/LuutenantsLoot
"fantia.jp", # http://fantia.jp/no100
"fantia.jp/fanclubs", # https://fantia.jp/fanclubs/1711
"fantia.jp/posts", # https://fantia.jp/posts/20000
"fantia.jp/products", # https://fantia.jp/products/10000
"fav.me", # http://fav.me/d9y1njg
/blog-imgs-\d+(?:-origin)?\.fc2\.com/i,
%r{blog\.fc2\.com(/\w)+/?}i, # http://blog71.fc2.com/a/abk00/file/20080220194219.jpg

View File

@@ -23,6 +23,7 @@ module Source
Source::URL::ArtStation,
Source::URL::DeviantArt,
Source::URL::Fanbox,
Source::URL::Fantia,
Source::URL::Foundation,
Source::URL::HentaiFoundry,
Source::URL::Lofter,

View File

@@ -0,0 +1,90 @@
# frozen_string_literal: true
# Unparsed:
# https://fantia.jp/asanagi
class Source::URL::Fantia < Source::URL
attr_reader :full_image_url
def self.match?(url)
url.domain == "fantia.jp"
end
def parse
case [host, *path_segments]
# posts:
# https://c.fantia.jp/uploads/post/file/1070093/main_16faf0b1-58d8-4aac-9e86-b243063eaaf1.jpeg (sample)
# https://c.fantia.jp/uploads/post/file/1070093/16faf0b1-58d8-4aac-9e86-b243063eaaf1.jpeg
# https://cc.fantia.jp/uploads/post_content_photo/file/4563389/main_a9763427-3ccd-4e51-bcde-ff5e1ce0aa56.jpg?Key-Pair-Id=APKAIOCKYZS7WKBB6G7A&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9jYy5mYW50aWEuanAvdXBsb2Fkcy9wb3N0X2NvbnRlbnRfcGhvdG8vZmlsZS80NTYzMzg5L21haW5fYTk3NjM0MjctM2NjZC00ZTUxLWJjZGUtZmY1ZTFjZTBhYTU2LmpwZyIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTY0NjkxMzk3OH19fV19&Signature=jyW5ankfO9uCHlKkozYU9RPpO3jzKTW2HuyXgS81i~cRgrXcI9orYU0IXuiit~0TznIyXbB7F~6Z790t7lX948PYAb9luYIREJC2u7pRMP3OBbsANbbFE0o4VR-6O3ZKbYQ4aG~ofVEZfiFVGoKoVtdJxj0bBNQV29eeFylGQATkFmywne1YMtJMqDirRBFMIatqNuunGsiWCQHqLYNHCeS4dZXlOnV8JQq0u1rPkeAQBmDCStFMA5ywjnWTfSZK7RN6RXKCAsMTXTl5X~I6EZASUPoGQy2vHUj5I-veffACg46jpvqTv6mLjQEw8JG~JLIOrZazKZR9O2kIoLNVGQ__
# from file download: https://cc.fantia.jp/uploads/post_content/file/1830956/cbcdfcbe_20220224_120_040_100.png?Key-Pair-Id=APKAIOCKYZS7WKBB6G7A&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9jYy5mYW50aWEuanAvdXBsb2Fkcy9wb3N0X2NvbnRlbnQvZmlsZS8xODMwOTU2L2NiY2RmY2JlXzIwMjIwMjI0XzEyMF8wNDBfMTAwLnBuZyIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTY0NjkxNDU4Nn19fV19&Signature=d1nw8gs9vcshIAeEH4oESm9-7z6y4A7MfoIRRvtUtV9iqTNA8KM0ORuCI7NwEoYc1VHsxy9ByeuSBpNaJoknnc3TOmHFhVRcLn~OWpnWqiHEPpMcSEG7uGlorysjEPmYYRGHjE7LJYcWiiJxjZ~fSBbYzxxwsjroPm-fyGUtNhdJWEMNp52vHe5P9KErb7M8tP01toekGdOqO-pkWm1t9xm2Tp5P7RWcbtQPOixgG4UgOhE0f3LVwHGHYJV~-lB5RjrDbTTO3ezVi7I7ybZjjHotVUK5MbHHmXzC1NqI-VN3vHddTwTbTK9xEnPMR27NHSlho3-O18WcNs1YgKD48w__
#
# products:
# https://c.fantia.jp/uploads/product/image/249638/main_fd5aef8f-c217-49d0-83e8-289efb33dfc4.jpg
# https://c.fantia.jp/uploads/product_image/file/219407/main_bd7419c2-2450-4c53-a28a-90101fa466ab.jpg (sample)
# https://c.fantia.jp/uploads/product_image/file/219407/bd7419c2-2450-4c53-a28a-90101fa466ab.jpg
in _, "uploads", image_type, ("file" | "image"), image_id, /(?:\w+_)?([\w-]+\.\w+)/ => file
# post_id/product_id == image_id only for the first image in a post/product
case image_type
when "post"
@post_id = image_id
@full_image_url = "https://c.fantia.jp/uploads/post/file/#{@post_id}/#{$1}"
when "product"
@product_id = image_id
@full_image_url = "https://c.fantia.jp/uploads/product/image/#{@product_id}/#{$1}"
when "product_image"
@full_image_url = "https://c.fantia.jp/uploads/product_image/file/#{image_id}/#{$1}"
else
@full_image_url = original_url
end
# https://fantia.jp/posts/1143951/download/1830956
in _, "posts", post_id, "download", image_id
@post_id = post_id
@download_id = image_id
# https://fantia.jp/posts/1148334
in _, "posts", /\d+/ => post_id
@post_id = post_id
# https://fantia.jp/products/249638
in _, "products", /\d+/ => product_id
@product_id = product_id
# https://fantia.jp/fanclubs/64496
# https://fantia.jp/fanclubs/1654/posts
in _, "fanclubs", /\d+/ => fanclub_id, *rest
@fanclub_id = fanclub_id
else
end
end
def image_url?
@full_image_url.present?
end
def downloadable?
@download_id.present?
end
def page_url
if @post_id.present?
"https://fantia.jp/posts/#{@post_id}"
elsif @product_id.present?
"https://fantia.jp/products/#{@product_id}"
end
end
def work_id
@post_id || @product_id
end
def work_type
if @post_id.present?
"post"
elsif @product_id.present?
"product"
end
end
end

View File

@@ -24,6 +24,7 @@ module Sources
Strategies::Foundation,
Strategies::Plurk,
Strategies::TwitPic,
Strategies::Fantia,
]
end

View File

@@ -0,0 +1,171 @@
# frozen_string_literal: true
module Sources::Strategies
class Fantia < Base
def self.enabled?
Danbooru.config.fantia_session_id.present?
end
def match?
Source::URL::Fantia === parsed_url
end
def site_name
parsed_url.site_name
end
def image_urls
return [parsed_url.full_image_url] if parsed_url.image_url?
return [image_from_downloadable(parsed_url)] if parsed_url.downloadable?
images = images_for_post.presence || images_for_product.presence || []
full_images = images.compact.map do |image|
parsed = Source::URL.parse(image)
if parsed&.image_url?
parsed.full_image_url
elsif parsed&.downloadable?
image_from_downloadable(parsed)
else
image
end
end
full_images.compact.uniq
end
def image_from_downloadable(url)
resp = http.head(url)
return url if resp.status != 200
resp.uri.to_s
end
def images_for_post
return [] unless api_response.present?
images = [api_response.dig("post", "thumb_micro")]
api_response.dig("post", "post_contents").to_a.map do |content|
next if content["visible_status"] != "visible"
case content["category"]
when "photo_gallery"
content["post_content_photos"].to_a.map { |i| images << i.dig("url", "original") }
when "file"
images << image_from_downloadable("https://www.fantia.jp/#{content["download_uri"]}")
when "blog"
begin
sub_json = JSON.parse(content["comment"])
rescue Json::ParserError
sub_json = {}
end
sub_json["ops"].to_a.map { |js| images << js.dig("insert", "fantiaImage", "url") }
end
end
images
end
def images_for_product
html_response&.css(".product-gallery-item .img-fluid").to_a.map do |element|
element["src"] unless element["src"] =~ %r{/fallback/}
end.compact
end
def page_url
parsed_url.page_url || parsed_referer&.page_url
end
def tags
case work_type
when "post"
api_response&.dig("post", "tags").to_a.map do |tag|
[tag["name"], "https://fantia.jp/posts?tag=#{tag["name"]}"]
end
when "product"
html_response&.css(".product-category a").to_a.map do |element|
tag_name = element.text.delete_prefix("#")
[tag_name, "https://fantia.jp/products?product_category=##{tag_name}"]
end
else
[]
end
end
def other_names
case work_type
when "post"
[api_response&.dig("post", "fanclub", "creator_name")].compact
when "product"
[html_response&.at(".fanclub-name a")&.text].compact
end
end
def profile_url
case work_type
when "post"
fanclub_id = api_response&.dig("post", "fanclub", "id")
return unless fanclub_id.present?
"https://fantia.jp/fanclubs/#{fanclub_id}"
when "product"
href = html_response&.at(".fanclub-name a")&.[]("href")
return unless href.present?
URI.join("https://fantia.jp/", href).to_s
end
end
def artist_commentary_title
case work_type
when "post"
api_response&.dig("post", "title")
when "product"
html_response&.at(".product-title")&.text
end
end
def artist_commentary_desc
case work_type
when "post"
api_response&.dig("post", "comment")
when "product"
html_response&.at(".product-description")&.text
end
end
def dtext_artist_commentary_desc
DText.from_html(artist_commentary_desc)
end
def normalize_for_source
page_url
end
def work_type
parsed_url.work_type || parsed_referer&.work_type
end
def work_id
parsed_url.work_id || parsed_referer&.work_id
end
def api_response
return {} unless work_type == "post"
api_url = "https://fantia.jp/api/v1/posts/#{work_id}"
response = http.cache(1.minute).get(api_url)
return {} unless response.status == 200
JSON.parse(response)
rescue JSON::ParserError
{}
end
def html_response
return nil unless work_type == "product"
response = http.cache(1.minute).get("https://fantia.jp/products/#{work_id}")
return nil unless response.status == 200
response.parse
end
def http
Danbooru::Http.new.cookies(_session_id: Danbooru.config.fantia_session_id)
end
end
end