Add skeb support
This commit is contained in:
@@ -15,7 +15,8 @@ module Sources
|
|||||||
Strategies::Moebooru,
|
Strategies::Moebooru,
|
||||||
Strategies::HentaiFoundry,
|
Strategies::HentaiFoundry,
|
||||||
Strategies::Weibo,
|
Strategies::Weibo,
|
||||||
Strategies::Newgrounds
|
Strategies::Newgrounds,
|
||||||
|
Strategies::Skeb
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -90,8 +90,6 @@ module Sources
|
|||||||
"Patreon"
|
"Patreon"
|
||||||
when /privatter\.net\z/i
|
when /privatter\.net\z/i
|
||||||
"Privatter"
|
"Privatter"
|
||||||
when /skeb\.jp\z/i
|
|
||||||
"Skeb"
|
|
||||||
when /tinami\.com\z/i
|
when /tinami\.com\z/i
|
||||||
"Tinami"
|
"Tinami"
|
||||||
when /toranoana\.(jp|shop)\z/i
|
when /toranoana\.(jp|shop)\z/i
|
||||||
|
|||||||
107
app/logical/sources/strategies/skeb.rb
Normal file
107
app/logical/sources/strategies/skeb.rb
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# Image URLS
|
||||||
|
## Non-watermarked:
|
||||||
|
# * https://skeb.imgix.net/requests/199886_0?bg=%23fff&auto=format&w=800&s=5a6a908ab964fcdfc4713fad179fe715
|
||||||
|
## Watermarked:
|
||||||
|
# * https://skeb.imgix.net/requests/73290_0?bg=%23fff&auto=format&txtfont=bold&txtshad=70&txtclr=BFFFFFFF&txtalign=middle%2Ccenter&txtsize=150&txt=SAMPLE&w=800&s=4843435cff85d623b1f657209d131526
|
||||||
|
## Full Size (found in commissioner_upload):
|
||||||
|
# * https://skeb.imgix.net/requests/53269_1?bg=%23fff&fm=png&dl=53269.png&w=1.0&h=1.0&s=44588ea9c41881049e392adb1df21cce
|
||||||
|
#
|
||||||
|
# The signature is required and tied to the parameters. Doesn't seem like it's possible to reverse engineer it to remove the watermark, unfortunately.
|
||||||
|
#
|
||||||
|
# Page URLS
|
||||||
|
# * https://skeb.jp/@OrvMZ/works/3 (non-watermarked)
|
||||||
|
# * https://skeb.jp/@OrvMZ/works/1 (separated request and client's message after delivery. We can't get the latter)
|
||||||
|
# * https://skeb.jp/@asanagi/works/16 (age-restricted, watermarked)
|
||||||
|
# * https://skeb.jp/@asanagi/works/6 (private, returns 404)
|
||||||
|
#
|
||||||
|
# Profile URLS
|
||||||
|
# Since skeb forces login through twitter, usernames are the same as twitter
|
||||||
|
# * https://skeb.jp/@asanagi
|
||||||
|
|
||||||
|
module Sources
|
||||||
|
module Strategies
|
||||||
|
class Skeb < Base
|
||||||
|
PROFILE_URL = %r{https?://(?:www\.)?skeb\.jp/@(?<artist_name>\w+)}i
|
||||||
|
|
||||||
|
PAGE_URL = %r{#{PROFILE_URL}/works/(?<illust_id>\d+)}i
|
||||||
|
|
||||||
|
IMAGE_URL = %r{https?://(?:www\.)?skeb\.imgix\.net/requests/[\d_]+\?.*}i
|
||||||
|
|
||||||
|
def domains
|
||||||
|
["skeb.jp"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def match?
|
||||||
|
return false if parsed_url.nil?
|
||||||
|
parsed_url.domain.in?(domains) || parsed_url.host == "skeb.imgix.net"
|
||||||
|
end
|
||||||
|
|
||||||
|
def site_name
|
||||||
|
"Skeb"
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_urls
|
||||||
|
if url =~ IMAGE_URL
|
||||||
|
[url]
|
||||||
|
elsif page.present?
|
||||||
|
[page.text[/window\.__NUXT__=.*,preview_url:"(.*?)",/, 1].gsub("\\u002F", "/")]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def page_url
|
||||||
|
urls.map { |u| u if u =~ PAGE_URL }.compact.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_for_source
|
||||||
|
page_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def page
|
||||||
|
return if page_url.blank?
|
||||||
|
response = http.cache(1.minute).get(page_url)
|
||||||
|
return nil unless response.status == 200
|
||||||
|
# The status check is required for private commissions, which return 404
|
||||||
|
|
||||||
|
response.parse
|
||||||
|
end
|
||||||
|
|
||||||
|
def profile_url
|
||||||
|
return nil if artist_name.blank?
|
||||||
|
"https://skeb.jp/@#{artist_name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def artist_name
|
||||||
|
url[PROFILE_URL, :artist_name]
|
||||||
|
end
|
||||||
|
|
||||||
|
def display_name
|
||||||
|
page&.at("title")&.text&.match(/.*by (.*?) \| skeb/i).to_a[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def other_names
|
||||||
|
[display_name].compact.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def artist_commentary_desc
|
||||||
|
# skeb "titles" are not needed: it's just the first few characters of the description
|
||||||
|
return if page.blank?
|
||||||
|
page.at("[property='og:description']")["content"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def client_response
|
||||||
|
return if page.blank?
|
||||||
|
page.text[/window\.__NUXT__=.*,thanks:"(.*?)",/, 1]&.gsub(/\\n/, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def dtext_artist_commentary_desc
|
||||||
|
if client_response.present? && artist_commentary_desc.present?
|
||||||
|
"h5. Original Request:\n#{artist_commentary_desc}\n\nh5. Client Response:\n#{client_response}"
|
||||||
|
else
|
||||||
|
artist_commentary_desc
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
75
test/unit/sources/skeb_test.rb
Normal file
75
test/unit/sources/skeb_test.rb
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Sources
|
||||||
|
class SkebTest < ActiveSupport::TestCase
|
||||||
|
context "The source for a skeb picture" do
|
||||||
|
setup do
|
||||||
|
@site = Sources::Strategies.find("https://skeb.jp/@kai_chiisame/works/6")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "get the artist name" do
|
||||||
|
assert_equal("kai_chiisame", @site.artist_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "get the artist commentary" do
|
||||||
|
commentary = <<~COMM.chomp
|
||||||
|
初めまして、先日アピールを頂きましたのでリクエストさせて頂きます。
|
||||||
|
|
||||||
|
〇キャラ
|
||||||
|
東方の東風谷早苗さん
|
||||||
|
|
||||||
|
〇内容
|
||||||
|
・水着や薄着などの若干セクシーめ・肌色多めな方向性で、細部は絵師さんにお任せ
|
||||||
|
・念のためNSFW指定にしましたがエロでなくていいです
|
||||||
|
|
||||||
|
ご検討お願いします。
|
||||||
|
COMM
|
||||||
|
|
||||||
|
assert_equal(commentary, @site.artist_commentary_desc)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "get profile url" do
|
||||||
|
assert_equal("https://skeb.jp/@kai_chiisame", @site.profile_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "get the image url" do
|
||||||
|
assert_equal("https://skeb.imgix.net/requests/229088_2?bg=%23fff&auto=format&w=800&s=9cac8b76c0838f2df4f19ebc41c1ae0a", @site.image_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "get the canonical url" do
|
||||||
|
assert_equal("https://skeb.jp/@kai_chiisame/works/6", @site.canonical_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "find the correct artist" do
|
||||||
|
artist = FactoryBot.create(:artist, name: "kai_chiisame", url_string: @site.url)
|
||||||
|
assert_equal([artist], @site.artists)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not fail" do
|
||||||
|
assert_nothing_raised { @site.to_h }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "A private or non-existent skeb url" do
|
||||||
|
setup do
|
||||||
|
@site = Sources::Strategies.find("https://skeb.jp/@kai_chiisame/works/2")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not raise anything" do
|
||||||
|
assert_nothing_raised { @site.to_h }
|
||||||
|
end
|
||||||
|
|
||||||
|
should "still find the right artist" do
|
||||||
|
artist = FactoryBot.create(:artist, name: "kai_chiisame", url_string: @site.url)
|
||||||
|
assert_equal([artist], @site.artists)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "normalizing for source" do
|
||||||
|
should "avoid normalizing unnormalizable urls" do
|
||||||
|
bad_source = "https://skeb.imgix.net/requests/229088_2?bg=%23fff&auto=format&w=800&s=9cac8b76c0838f2df4f19ebc41c1ae0a"
|
||||||
|
assert_equal(bad_source, Sources::Strategies.normalize_source(bad_source))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user