diff --git a/app/logical/sources/strategies.rb b/app/logical/sources/strategies.rb index 2c0982f2c..5f68e7153 100644 --- a/app/logical/sources/strategies.rb +++ b/app/logical/sources/strategies.rb @@ -10,7 +10,8 @@ module Sources Strategies::ArtStation, Strategies::Nijie, Strategies::Pawoo, - Strategies::Moebooru + Strategies::Moebooru, + Strategies::HentaiFoundry ] end diff --git a/app/logical/sources/strategies/hentai_foundry.rb b/app/logical/sources/strategies/hentai_foundry.rb new file mode 100644 index 000000000..6b2d2fda0 --- /dev/null +++ b/app/logical/sources/strategies/hentai_foundry.rb @@ -0,0 +1,112 @@ +# Image URLs +# +# * https://pictures.hentai-foundry.com/a/Afrobull/795025/Afrobull-795025-kuroeda.png +# +# Page URLs +# +# * https://www.hentai-foundry.com/pictures/user/Afrobull/795025/kuroeda +# * https://www.hentai-foundry.com/pictures/user/Afrobull/795025o +# +# Preview URLs +# +# * https://thumbs.hentai-foundry.com/thumb.php?pid=795025&size=350 +# +# Profile URLs +# +# * https://www.hentai-foundry.com/user/kajinman/profile +# * https://www.hentai-foundry.com/pictures/user/kajinman +# * https://www.hentai-foundry.com/pictures/user/kajinman/scraps +# * https://www.hentai-foundry.com/user/J-likes-to-draw/profile + +module Sources + module Strategies + class HentaiFoundry < Base + BASE_URL = %r!\Ahttps?://(?:www\.)?hentai-foundry\.com!i + PAGE_URL = %r!#{BASE_URL}/pictures/user/(?[\w-]+)/(?\d+)(?:/[\w-]*)?(\?[\w=]*)?\z!i + PROFILE_URL = %r!#{BASE_URL}/(?:pictures/)?user/(?[\w-]+)(?:/[a-z]*)?\z!i + IMAGE_URL = %r!\Ahttps?://pictures\.hentai-foundry\.com/\w/(?[\w-]+)/(?\d+)/[\w-]+\.\w+\z!i + + def domains + ["hentai-foundry.com"] + end + + def site_name + "Hentai Foundry" + end + + def image_urls + image = page&.search("#picBox img") + + return [] unless image + + image.to_a.map { |img| URI.join(page_url, img["src"]).to_s } + end + + def preview_urls + image_urls.map do + "https://thumbs.hentai-foundry.com/thumb.php?pid=#{illust_id}&size=250" + end + end + + def page_url + return nil if illust_id.blank? || artist_name.blank? + "https://www.hentai-foundry.com/pictures/user/#{artist_name}/#{illust_id}" + end + + def page + return nil if page_url.blank? + + doc = Cache.get("hentai-foundry:#{page_url}", 1.minute) do + HTTParty.get("#{page_url}?enterAgree=1").body + end + + Nokogiri::HTML(doc) + end + + def tags + tags = page&.search(".boxbody [rel='tag']") || [] + + tags.map do |tag| + [tag.text, URI.join(page_url, tag.attr("href")).to_s] + end + end + + def artist_name + urls.map { |url| url[PROFILE_URL, :artist_name] || url[PAGE_URL, :artist_name] || url[IMAGE_URL, :artist_name] }.compact.first + end + + def canonical_url + image_url + end + + def profile_url + return nil if artist_name.blank? + "https://www.hentai-foundry.com/user/#{artist_name}" + end + + def artist_commentary_title + page&.search("#picBox .imageTitle")&.text + end + + def artist_commentary_desc + page&.search("#descriptionBox .picDescript")&.to_html + end + + def dtext_artist_commentary_desc + DText.from_html(artist_commentary_desc).gsub(/\A[[:space:]]+|[[:space:]]+\z/, "").gsub(/\n+/, "\n") + end + + def normalizable_for_artist_finder? + artist_name.present? + end + + def normalized_for_artist_finder? + url =~ PROFILE_URL + end + + def illust_id + url[PAGE_URL, :illust_id] || url[IMAGE_URL, :illust_id] + end + end + end +end diff --git a/test/unit/sources/hentai_foundry_test.rb b/test/unit/sources/hentai_foundry_test.rb new file mode 100644 index 000000000..22fb39ec4 --- /dev/null +++ b/test/unit/sources/hentai_foundry_test.rb @@ -0,0 +1,89 @@ +require 'test_helper' + +module Sources + class HentaiFoundryTest < ActiveSupport::TestCase + context "The source for a hentai foundry picture" do + setup do + @image_1 = Sources::Strategies.find("https://www.hentai-foundry.com/pictures/user/Afrobull/795025/kuroeda") + @image_2 = Sources::Strategies.find("https://pictures.hentai-foundry.com/a/Afrobull/795025/Afrobull-795025-kuroeda.png") + end + + should "get the illustration id" do + assert_equal("795025", @image_1.illust_id) + assert_equal("795025", @image_2.illust_id) + end + + should "get the artist name" do + assert_equal("Afrobull", @image_1.artist_name) + assert_equal("Afrobull", @image_2.artist_name) + end + + should "get the artist commentary title" do + assert_equal("kuroeda", @image_1.artist_commentary_title) + assert_equal("kuroeda", @image_2.artist_commentary_title) + end + + should "get profile url" do + assert_equal("https://www.hentai-foundry.com/user/Afrobull", @image_1.profile_url) + assert_equal("https://www.hentai-foundry.com/user/Afrobull", @image_2.profile_url) + end + + should "get the image url" do + assert_equal("https://pictures.hentai-foundry.com/a/Afrobull/795025/Afrobull-795025-kuroeda.png", @image_1.image_url) + assert_equal("https://pictures.hentai-foundry.com/a/Afrobull/795025/Afrobull-795025-kuroeda.png", @image_2.image_url) + end + + should "get the canonical url" do + assert_equal("https://pictures.hentai-foundry.com/a/Afrobull/795025/Afrobull-795025-kuroeda.png", @image_1.canonical_url) + assert_equal("https://pictures.hentai-foundry.com/a/Afrobull/795025/Afrobull-795025-kuroeda.png", @image_2.canonical_url) + end + + should "download an image" do + assert_downloaded(1_349_887, @image_1.image_url) + assert_downloaded(1_349_887, @image_2.image_url) + end + + should "get the tags" do + assert_equal([["elf", "https://www.hentai-foundry.com/search/index?query=elf&search_in=keywords"]], @image_1.tags) + assert_equal([["elf", "https://www.hentai-foundry.com/search/index?query=elf&search_in=keywords"]], @image_2.tags) + end + + should "find the correct artist" do + @artist = FactoryBot.create(:artist, name: "Afrobull", url_string: @image_1.url) + assert_equal([@artist], @image_1.artists) + assert_equal([@artist], @image_2.artists) + end + end + + context "An artist profile url" do + setup do + @site = Sources::Strategies.find("https://www.hentai-foundry.com/user/Afrobull/profile") + end + + should "get the profile url" do + assert_equal("https://www.hentai-foundry.com/user/Afrobull", @site.profile_url) + end + + should "get the artist name" do + assert_equal("Afrobull", @site.artist_name) + end + + should "get the normalized url" do + assert_equal("https://www.hentai-foundry.com/user/Afrobull", @site.normalize_for_artist_finder) + end + end + + context "A deleted picture" do + setup do + @image = Sources::Strategies.find("https://www.hentai-foundry.com/pictures/user/faustsketcher/279498") + @artist = FactoryBot.create(:artist, name: "faustsketcher", url_string: @image.url) + end + + should "still find the artist name" do + assert_equal("faustsketcher", @image.artist_name) + assert_equal("https://www.hentai-foundry.com/user/faustsketcher", @image.profile_url) + assert_equal([@artist], @image.artists) + end + end + end +end