Merge pull request #5043 from nonamethanks/fantia-support

Add Fantia support
This commit is contained in:
evazion
2022-03-10 15:21:03 -06:00
committed by GitHub
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

View File

@@ -109,8 +109,8 @@ class ArtistURL < ApplicationRecord
def priority
sites = %w[
Pixiv Twitter
ArtStation baraag.net BCY Deviant\ Art Hentai\ Foundry Foundation Nico\ Seiga Nijie pawoo.net Pixiv\ Fanbox Pixiv\ Sketch Plurk Tinami Tumblr
Ask.fm Booth.pm Facebook Fantia FC2 Gumroad Instagram Ko-fi Livedoor Lofter Mihuashi Mixi.jp Patreon Piapro.jp Picarto Privatter Sakura.ne.jp Stickam Skeb Twitch Weibo Youtube
ArtStation Baraag BCY Deviant\ Art Hentai\ Foundry Fantia Foundation Lofter Nico\ Seiga Nijie Pawoo Pixiv\ Fanbox Pixiv\ Sketch Plurk Tinami Tumblr Weibo
Ask.fm Booth.pm 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
]