Merge pull request #5147 from nonamethanks/furaffinity-support
Add furaffinity support
This commit is contained in:
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
@@ -56,6 +56,8 @@ jobs:
|
|||||||
DANBOORU_BARAAG_CLIENT_ID: ${{ secrets.DANBOORU_BARAAG_CLIENT_ID }}
|
DANBOORU_BARAAG_CLIENT_ID: ${{ secrets.DANBOORU_BARAAG_CLIENT_ID }}
|
||||||
DANBOORU_BARAAG_CLIENT_SECRET: ${{ secrets.DANBOORU_BARAAG_CLIENT_SECRET }}
|
DANBOORU_BARAAG_CLIENT_SECRET: ${{ secrets.DANBOORU_BARAAG_CLIENT_SECRET }}
|
||||||
DANBOORU_FANTIA_SESSION_ID: ${{ secrets.DANBOORU_FANTIA_SESSION_ID }}
|
DANBOORU_FANTIA_SESSION_ID: ${{ secrets.DANBOORU_FANTIA_SESSION_ID }}
|
||||||
|
DANBOORU_FURAFFINITY_COOKIE_A: ${{ secrets.DANBOORU_FURAFFINITY_COOKIE_A }}
|
||||||
|
DANBOORU_FURAFFINITY_COOKIE_B: ${{ secrets.DANBOORU_FURAFFINITY_COOKIE_B }}
|
||||||
DANBOORU_TINAMI_SESSION_ID: ${{ secrets.DANBOORU_TINAMI_SESSION_ID }}
|
DANBOORU_TINAMI_SESSION_ID: ${{ secrets.DANBOORU_TINAMI_SESSION_ID }}
|
||||||
DANBOORU_DISCORD_WEBHOOK_ID: ${{ secrets.DANBOORU_DISCORD_WEBHOOK_ID }}
|
DANBOORU_DISCORD_WEBHOOK_ID: ${{ secrets.DANBOORU_DISCORD_WEBHOOK_ID }}
|
||||||
DANBOORU_DISCORD_WEBHOOK_SECRET: ${{ secrets.DANBOORU_DISCORD_WEBHOOK_SECRET }}
|
DANBOORU_DISCORD_WEBHOOK_SECRET: ${{ secrets.DANBOORU_DISCORD_WEBHOOK_SECRET }}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ module Source
|
|||||||
Source::Extractor::Fantia,
|
Source::Extractor::Fantia,
|
||||||
Source::Extractor::Booth,
|
Source::Extractor::Booth,
|
||||||
Source::Extractor::Anifty,
|
Source::Extractor::Anifty,
|
||||||
|
Source::Extractor::Furaffinity,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Should return true if the extractor is configured correctly. Return false
|
# Should return true if the extractor is configured correctly. Return false
|
||||||
|
|||||||
73
app/logical/source/extractor/furaffinity.rb
Normal file
73
app/logical/source/extractor/furaffinity.rb
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Source::Extractor
|
||||||
|
class Furaffinity < Source::Extractor
|
||||||
|
def self.enabled?
|
||||||
|
# https://www.furaffinity.net/controls/settings/
|
||||||
|
# For this strategy to work properly, in the above settings "Enable Adult Artwork" must be set to "General, Mature, Adult".
|
||||||
|
Danbooru.config.furaffinity_cookie_a.present? && Danbooru.config.furaffinity_cookie_b.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def match?
|
||||||
|
Source::URL::Furaffinity === parsed_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_urls
|
||||||
|
if parsed_url.image_url?
|
||||||
|
[parsed_url.to_s]
|
||||||
|
else
|
||||||
|
download_button = html_response&.css(".submission-content .auto_link .button").to_a.find { |el| el.text == "Download" }
|
||||||
|
partial_image = download_button&.[]("href")
|
||||||
|
return [] unless partial_image.present?
|
||||||
|
[URI.join("https://d.furaffinity.net", partial_image).to_s].compact
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def page_url
|
||||||
|
parsed_url.page_url || parsed_referer&.page_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def tags
|
||||||
|
tags = html_response&.css(".tags").to_a.map!(&:text).compact.uniq
|
||||||
|
tags.map {|tag| [tag, "https://www.furaffinity.net/search/@keywords #{tag}"] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def artist_name
|
||||||
|
html_response&.at(".submission-id-sub-container a")&.text || parsed_url.username || parsed_referer&.username
|
||||||
|
end
|
||||||
|
|
||||||
|
def profile_url
|
||||||
|
parsed_url.profile_url || parsed_referer&.profile_url || profile_url_from_page
|
||||||
|
end
|
||||||
|
|
||||||
|
def profile_url_from_page
|
||||||
|
slug = html_response&.at(".submission-id-avatar a")&.[](:href)
|
||||||
|
return unless slug.present?
|
||||||
|
Source::URL.parse(URI.join("https://www.furaffinity.net/", slug)).profile_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def artist_commentary_title
|
||||||
|
html_response&.at(".submission-title")&.text&.strip
|
||||||
|
end
|
||||||
|
|
||||||
|
def artist_commentary_desc
|
||||||
|
html_response&.at(".submission-content .section-body")&.to_html
|
||||||
|
end
|
||||||
|
|
||||||
|
def dtext_artist_commentary_desc
|
||||||
|
DText.from_html(artist_commentary_desc)&.strip
|
||||||
|
end
|
||||||
|
|
||||||
|
def html_response
|
||||||
|
return nil unless page_url.present?
|
||||||
|
response = http.cache(1.minute).get(page_url)
|
||||||
|
|
||||||
|
return nil unless response.status == 200
|
||||||
|
response.parse
|
||||||
|
end
|
||||||
|
|
||||||
|
def http
|
||||||
|
Danbooru::Http.new.cookies(a: Danbooru.config.furaffinity_cookie_a, b: Danbooru.config.furaffinity_cookie_b, sfw: 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -49,6 +49,7 @@ module Source
|
|||||||
Source::URL::TwitPic,
|
Source::URL::TwitPic,
|
||||||
Source::URL::Weibo,
|
Source::URL::Weibo,
|
||||||
Source::URL::Anifty,
|
Source::URL::Anifty,
|
||||||
|
Source::URL::Furaffinity,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Parse a URL into a subclass of Source::URL, or raise an exception if the URL is not a valid HTTP or HTTPS URL.
|
# Parse a URL into a subclass of Source::URL, or raise an exception if the URL is not a valid HTTP or HTTPS URL.
|
||||||
|
|||||||
45
app/logical/source/url/furaffinity.rb
Normal file
45
app/logical/source/url/furaffinity.rb
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Source::URL::Furaffinity < Source::URL
|
||||||
|
attr_reader :work_id, :username, :filename
|
||||||
|
|
||||||
|
def self.match?(url)
|
||||||
|
url.domain == "furaffinity.net"
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse
|
||||||
|
case [host, *path_segments]
|
||||||
|
|
||||||
|
# https://www.furaffinity.net/view/46821705/
|
||||||
|
# https://www.furaffinity.net/view/46802202/ (scrap)
|
||||||
|
in _, "view", /^\d+$/ => work_id
|
||||||
|
@work_id = work_id
|
||||||
|
|
||||||
|
# https://d.furaffinity.net/art/iwbitu/1650222955/1650222955.iwbitu_yubi.jpg
|
||||||
|
in _, "art", username, subdir, filename
|
||||||
|
@username = username
|
||||||
|
@filename = filename
|
||||||
|
|
||||||
|
# https://www.furaffinity.net/gallery/iwbitu
|
||||||
|
# https://www.furaffinity.net/scraps/iwbitu/2/?
|
||||||
|
# https://www.furaffinity.net/gallery/iwbitu/folder/133763/Regular-commissions
|
||||||
|
in _, ("gallery" | "user" | "favorites" | "scraps" | "journals"), username, *pages
|
||||||
|
@username = username
|
||||||
|
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_url?
|
||||||
|
@filename.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def page_url
|
||||||
|
"https://www.furaffinity.net/view/#{work_id}" if work_id.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def profile_url
|
||||||
|
"https://www.furaffinity.net/user/#{username}" if username.present?
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -95,7 +95,7 @@ class ArtistURL < ApplicationRecord
|
|||||||
def priority
|
def priority
|
||||||
sites = %w[
|
sites = %w[
|
||||||
Pixiv Twitter
|
Pixiv Twitter
|
||||||
Anifty ArtStation Baraag BCY Booth Deviant\ Art Hentai\ Foundry Fantia Foundation Lofter Nico\ Seiga Nijie Pawoo Fanbox Pixiv\ Sketch Plurk Tinami Tumblr Weibo
|
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
|
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
|
Amazon Circle.ms DLSite Doujinshi.org Erogamescape Mangaupdates Melonbooks Toranoana Wikipedia
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -333,6 +333,17 @@ module Danbooru
|
|||||||
def fantia_session_id
|
def fantia_session_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Your Furaffinity "a" cookie. Login to Furaffinity then use the
|
||||||
|
# devtools to find the "a" cookie.
|
||||||
|
# !!WARNING!! logging out of furaffinity will expire this cookie too!
|
||||||
|
def furaffinity_cookie_a
|
||||||
|
end
|
||||||
|
|
||||||
|
# Your Furaffinity "b" cookie. Login to Furaffinity then use the
|
||||||
|
# devtools to find the "b" cookie.
|
||||||
|
def furaffinity_cookie_b
|
||||||
|
end
|
||||||
|
|
||||||
# A list of tags that should be removed when a post is replaced. Regexes allowed.
|
# A list of tags that should be removed when a post is replaced. Regexes allowed.
|
||||||
def post_replacement_tag_removals
|
def post_replacement_tag_removals
|
||||||
%w[replaceme .*_sample resized upscaled downscaled md5_mismatch
|
%w[replaceme .*_sample resized upscaled downscaled md5_mismatch
|
||||||
|
|||||||
45
test/unit/sources/furaffinity_test.rb
Normal file
45
test/unit/sources/furaffinity_test.rb
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
module Sources
|
||||||
|
class FuraffinityTest < ActiveSupport::TestCase
|
||||||
|
context "A furaffinity post" do
|
||||||
|
strategy_should_work(
|
||||||
|
"https://www.furaffinity.net/view/46821705/",
|
||||||
|
image_urls: ["https://d.furaffinity.net/art/iwbitu/1650222955/1650222955.iwbitu_yubi.jpg"],
|
||||||
|
profile_url: "https://www.furaffinity.net/user/iwbitu",
|
||||||
|
page_url: "https://www.furaffinity.net/view/46821705",
|
||||||
|
artist_name: "iwbitu",
|
||||||
|
artist_commentary_title: "Yubi",
|
||||||
|
artist_commentary_desc: /little gift doodle for/
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "A furaffinity image" do
|
||||||
|
strategy_should_work(
|
||||||
|
"https://d.furaffinity.net/art/iwbitu/1650222955/1650222955.iwbitu_yubi.jpg",
|
||||||
|
image_urls: ["https://d.furaffinity.net/art/iwbitu/1650222955/1650222955.iwbitu_yubi.jpg"],
|
||||||
|
profile_url: "https://www.furaffinity.net/user/iwbitu",
|
||||||
|
artist_name: "iwbitu",
|
||||||
|
page_url: nil,
|
||||||
|
artist_commentary_title: nil
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "An adult age-restricted furaffinity post" do
|
||||||
|
strategy_should_work(
|
||||||
|
"https://www.furaffinity.net/view/46590097/",
|
||||||
|
image_urls: ["https://d.furaffinity.net/art/iwbitu/1648803766/1648803766.iwbitu_nyopu_tori.jpg"],
|
||||||
|
profile_url: "https://www.furaffinity.net/user/iwbitu",
|
||||||
|
page_url: "https://www.furaffinity.net/view/46590097",
|
||||||
|
artist_name: "iwbitu",
|
||||||
|
tags: [],
|
||||||
|
artist_commentary_title: "Nyopu and Tori",
|
||||||
|
artist_commentary_desc: /UwU/
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "A deleted or non-existing furaffinity post" do
|
||||||
|
strategy_should_work("https://www.furaffinity.net/view/3404111", deleted: true, profile_url: nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user