From 90ce42a537d8301c7ad66e637315933624475e98 Mon Sep 17 00:00:00 2001 From: Albert Yi Date: Mon, 25 Feb 2019 14:44:45 -0800 Subject: [PATCH] add support for nico seiga manga (fixes #4060) --- app/logical/nico_seiga_api_client.rb | 39 ++++++++++ app/logical/nico_seiga_manga_api_client.rb | 58 +++++++++++++++ app/logical/sources/strategies.rb | 3 +- app/logical/sources/strategies/nico_seiga.rb | 34 +-------- .../sources/strategies/nico_seiga_manga.rb | 71 +++++++++++++++++++ test/unit/sources/nico_seiga_manga_test.rb | 23 ++++++ test/unit/sources/nico_seiga_test.rb | 7 ++ 7 files changed, 201 insertions(+), 34 deletions(-) create mode 100644 app/logical/nico_seiga_manga_api_client.rb create mode 100644 app/logical/sources/strategies/nico_seiga_manga.rb create mode 100644 test/unit/sources/nico_seiga_manga_test.rb diff --git a/app/logical/nico_seiga_api_client.rb b/app/logical/nico_seiga_api_client.rb index aa2dfe69a..e2dbca0af 100644 --- a/app/logical/nico_seiga_api_client.rb +++ b/app/logical/nico_seiga_api_client.rb @@ -1,8 +1,47 @@ +# http://seiga.nicovideo.jp/api/manga/info?id=376206 +# http://api.search.nicovideo.jp/api/v2/manga/contents/search? + class NicoSeigaApiClient extend Memoist BASE_URL = "http://seiga.nicovideo.jp/api" attr_reader :illust_id + def self.agent + mech = Mechanize.new + mech.redirect_ok = false + mech.keep_alive = false + + session = Cache.get("nico-seiga-session") + if session + cookie = Mechanize::Cookie.new("user_session", session) + cookie.domain = ".nicovideo.jp" + cookie.path = "/" + mech.cookie_jar.add(cookie) + else + mech.get("https://account.nicovideo.jp/login") do |page| + page.form_with(:id => "login_form") do |form| + form["mail_tel"] = Danbooru.config.nico_seiga_login + form["password"] = Danbooru.config.nico_seiga_password + end.click_button + end + session = mech.cookie_jar.cookies.select{|c| c.name == "user_session"}.first + if session + Cache.put("nico-seiga-session", session.value, 1.week) + else + raise "Session not found" + end + end + + # This cookie needs to be set to allow viewing of adult works + cookie = Mechanize::Cookie.new("skip_fetish_warning", "1") + cookie.domain = "seiga.nicovideo.jp" + cookie.path = "/" + mech.cookie_jar.add(cookie) + + mech.redirect_ok = true + mech + end + def initialize(illust_id:, user_id: nil) @illust_id = illust_id @user_id = user_id diff --git a/app/logical/nico_seiga_manga_api_client.rb b/app/logical/nico_seiga_manga_api_client.rb new file mode 100644 index 000000000..7649dd139 --- /dev/null +++ b/app/logical/nico_seiga_manga_api_client.rb @@ -0,0 +1,58 @@ +class NicoSeigaMangaApiClient + extend Memoist + BASE_URL = "http://seiga.nicovideo.jp/api" + attr_reader :theme_id + + def initialize(theme_id) + @theme_id = theme_id + end + + def user_id + theme_info_xml["response"]["theme"]["user_id"].to_i + end + + def title + theme_info_xml["response"]["theme"]["title"] + end + + def desc + theme_info_xml["response"]["theme"]["description"] + end + + def moniker + artist_xml["response"]["user"]["nickname"] + end + + def image_ids + theme_data_xml["response"]["image_list"]["image"].map {|x| x["id"]} + end + + def tags + theme_info_xml["response"]["theme"]["tag_list"]["tag"].map {|x| x["name"]} + end + + def theme_data_xml + uri = "#{BASE_URL}/theme/data?theme_id=#{theme_id}" + body = NicoSeigaApiClient.agent.get(uri).body + Hash.from_xml(body) + end + memoize :theme_data_xml + + def theme_info_xml + uri = "#{BASE_URL}/theme/info?id=#{theme_id}" + body = NicoSeigaApiClient.agent.get(uri).body + Hash.from_xml(body) + end + memoize :theme_info_xml + + def artist_xml + uri = "#{BASE_URL}/user/info?id=#{user_id}" + body, code = HttpartyCache.get(uri) + if code == 200 + Hash.from_xml(body) + else + raise "nico seiga api call failed (code=#{code}, body=#{body})" + end + end + memoize :artist_xml +end diff --git a/app/logical/sources/strategies.rb b/app/logical/sources/strategies.rb index 89d55aa3e..b8bdba71a 100644 --- a/app/logical/sources/strategies.rb +++ b/app/logical/sources/strategies.rb @@ -3,7 +3,8 @@ module Sources def self.all return [ Strategies::Pixiv, - Strategies::NicoSeiga, + Strategies::NicoSeigaManga, # must come before NicoSeiga + Strategies::NicoSeiga, Strategies::Twitter, Strategies::Stash, # must come before DeviantArt Strategies::DeviantArt, diff --git a/app/logical/sources/strategies/nico_seiga.rb b/app/logical/sources/strategies/nico_seiga.rb index a5534321c..d62cadf5e 100644 --- a/app/logical/sources/strategies/nico_seiga.rb +++ b/app/logical/sources/strategies/nico_seiga.rb @@ -153,39 +153,7 @@ module Sources memoize :page def agent - mech = Mechanize.new - mech.redirect_ok = false - mech.keep_alive = false - - session = Cache.get("nico-seiga-session") - if session - cookie = Mechanize::Cookie.new("user_session", session) - cookie.domain = ".nicovideo.jp" - cookie.path = "/" - mech.cookie_jar.add(cookie) - else - mech.get("https://account.nicovideo.jp/login") do |page| - page.form_with(:id => "login_form") do |form| - form["mail_tel"] = Danbooru.config.nico_seiga_login - form["password"] = Danbooru.config.nico_seiga_password - end.click_button - end - session = mech.cookie_jar.cookies.select{|c| c.name == "user_session"}.first - if session - Cache.put("nico-seiga-session", session.value, 1.month) - else - raise "Session not found" - end - end - - # This cookie needs to be set to allow viewing of adult works - cookie = Mechanize::Cookie.new("skip_fetish_warning", "1") - cookie.domain = "seiga.nicovideo.jp" - cookie.path = "/" - mech.cookie_jar.add(cookie) - - mech.redirect_ok = true - mech + NicoSeigaApiClient.agent end memoize :agent end diff --git a/app/logical/sources/strategies/nico_seiga_manga.rb b/app/logical/sources/strategies/nico_seiga_manga.rb new file mode 100644 index 000000000..59705fc8a --- /dev/null +++ b/app/logical/sources/strategies/nico_seiga_manga.rb @@ -0,0 +1,71 @@ +module Sources + module Strategies + class NicoSeigaManga < Base + PAGE_URL = %r!\Ahttps?://seiga\.nicovideo\.jp/watch/mg(\d+)!i + + def domains + ["nicoseiga.jp", "nicovideo.jp"] + end + + def site_name + "Nico Seiga (manga)" + end + + def image_urls + api_client.image_ids.map do |image_id| + "https://seiga.nicovideo.jp/image/source/#{image_id}" + end + end + + def page_url + [url, referer_url].each do |x| + if x =~ PAGE_URL + return x + end + end + + return super + end + + def canonical_url + image_url + end + + def profile_url + if url =~ PROFILE + return url + end + + "http://seiga.nicovideo.jp/user/illust/#{api_client.user_id}" + end + + def artist_name + api_client.moniker + end + + def artist_commentary_title + api_client.title + end + + def artist_commentary_desc + api_client.desc + end + + def headers + super.merge( + "Referer" => "https://seiga.nicovideo.jp" + ) + end + + def theme_id + if page_url =~ PAGE_URL + return $1 + end + end + + def api_client + NicoSeigaMangaApiClient.new(theme_id) + end + end + end +end diff --git a/test/unit/sources/nico_seiga_manga_test.rb b/test/unit/sources/nico_seiga_manga_test.rb new file mode 100644 index 000000000..fe5bdc3b8 --- /dev/null +++ b/test/unit/sources/nico_seiga_manga_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +module Sources + class NicoSeigaTest < ActiveSupport::TestCase + context "The source site for nico seiga" do + setup do + @site = Sources::Strategies.find("http://seiga.nicovideo.jp/watch/mg316708", "http://seiga.nicovideo.jp/watch/mg316708") + end + + should "find the image urls" do + assert_equal(["https://seiga.nicovideo.jp/image/source/8100968", "https://seiga.nicovideo.jp/image/source/8100969", "https://seiga.nicovideo.jp/image/source/8100970", "https://seiga.nicovideo.jp/image/source/8100971", "https://seiga.nicovideo.jp/image/source/8100972", "https://seiga.nicovideo.jp/image/source/8100973", "https://seiga.nicovideo.jp/image/source/8100974", "https://seiga.nicovideo.jp/image/source/8100975"], @site.image_urls) + end + + should "find the page url" do + assert_equal("http://seiga.nicovideo.jp/watch/mg316708", @site.page_url) + end + + should "find the artist name" do + assert_not_nil(@site.artist_name) + end + end + end +end diff --git a/test/unit/sources/nico_seiga_test.rb b/test/unit/sources/nico_seiga_test.rb index 59a9c491e..e7d33c068 100644 --- a/test/unit/sources/nico_seiga_test.rb +++ b/test/unit/sources/nico_seiga_test.rb @@ -6,6 +6,7 @@ module Sources setup do @site_1 = Sources::Strategies.find("http://lohas.nicoseiga.jp/o/910aecf08e542285862954017f8a33a8c32a8aec/1433298801/4937663") @site_2 = Sources::Strategies.find("http://seiga.nicovideo.jp/seiga/im4937663") + @site_3 = Sources::Strategies.find("http://seiga.nicovideo.jp/watch/mg376206") end should "get the profile" do @@ -59,6 +60,12 @@ module Sources assert_match(full_image_url, site.image_url) assert_match(full_image_url, site.canonical_url) end + + context "for a manga page" do + should "not try to find the image url" do + assert_nil(@site_3.image_url) + end + end end end end