natalia 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1cd40e71255d902fb12309ee83888b4ea78b322baf87caaaaa8aaafca0d3886
4
- data.tar.gz: de2c722d139e874be4675975a909d745182e73bdf5e41cd6f2542b71e53dc197
3
+ metadata.gz: b2656442ac7d8e82de97e949248c5bef87b51faef371254f8f9800d488f8c813
4
+ data.tar.gz: 2966d8b5a3fd4b2f8e623bfd37b562c8682831391ffa17cdfd68b756b2265e6c
5
5
  SHA512:
6
- metadata.gz: 4f65cc234804d15401dc4902b9dcd87804408cd3c97cfae2c8e17d9044768725781c14d14fdf75b0c467916da795ce5cfaee9b77a4fe548cbb9a5d63684d48dc
7
- data.tar.gz: 583b39aefe55add76fb4af7c25c395ab6e2ab6363fa0e7e81b0a246c957be50087cab8dd48442496d001a2c6e17e16bb61fdb48463e54127335ff829ae8faca7
6
+ metadata.gz: fb91352464023b97cfb10c280b3687467241162e2a518b52b7f4b7dd67543bcf1ef8e439be091fb98dfad89bf28c9a16a79d9badf106e60e33125d853bb807b4
7
+ data.tar.gz: 6d404e9fac70e8b5d5e15d9db794091d73e4c0751356ebab7350077d1e5e2f5bfacd590c43fecbd7ab88a9506131fef647b0a4e5528eb7b22fd92d71c8050dc8
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'nokogiri'
4
+ require 'time'
5
+ require_relative '../utils'
6
+
7
+ module Natalia
8
+ module JLyric
9
+ # sort という概念はないっぽい
10
+ def self.search(keyword, type: :title, sort: :popularity_desc)
11
+ case type
12
+ when :title
13
+ search_by_title(keyword)
14
+ when :artist
15
+ search_by_artist(keyword, sort: sort)
16
+ else
17
+ raise ArgumentError, "unsupported search type `#{type}`"
18
+ end
19
+ end
20
+
21
+ def self.search_by_title(keyword)
22
+ entries = []
23
+ (1..).each do |page|
24
+ response =
25
+ Natalia::Utils.curl_get('https://search2.j-lyric.net/index.php', {
26
+ kt: keyword,
27
+ ct: '2', # kt 検索方法 (0: 前方, 1: 完全, 2: 中間, 3: 後方)
28
+ search: '検索', # 謎
29
+ ex: 'on', # 謎
30
+ ca: '2', # ka 検索方法
31
+ cl: '2', # kl 検索方法
32
+ p: page
33
+ })
34
+ response.value
35
+
36
+ doc = Nokogiri::HTML.parse(response.body)
37
+ table = doc.css('div#bas div#cnt div#mnb > div.bdy')
38
+ break if table.empty?
39
+
40
+ table.each do |body|
41
+ entries << {
42
+ source: self,
43
+ id: body.at_css('p.mid a')['href'].match(%r{/artist/(.+)\.html\z})[1],
44
+ title: body.at_css('p.mid a').content,
45
+ artist: body.css('p.sml')[0].at_css('a').content,
46
+ artist_id: body.css('p.sml')[0].at_css('a')['href'].match(%r{/artist/(.+)/\z})[1]
47
+ }
48
+ end
49
+ end
50
+
51
+ entries
52
+ end
53
+
54
+ def self.search_by_artist(artist_id, sort: :popularity_desc)
55
+ response = Natalia::Utils.curl_get("https://j-lyric.net/artist/#{artist_id}/")
56
+ response.value
57
+
58
+ doc = Nokogiri::HTML.parse(response.body)
59
+ artist_name = doc.at_css('div#mnb div.cnt div.cap h2').content.match(/\A(.+)の歌詞リスト\z/)[1]
60
+ table = doc.css('div#bas div#cnt div#mnb div.bdy[id^=ly]')
61
+
62
+ entries = table.map do |row|
63
+ order, date, popularity = row.css('input[type=hidden]').map {|e| e['value']}
64
+ {
65
+ source: self,
66
+ id: row.at_css('p.ttl a')['href'].match(%r{/artist/(.+)\.html\z})[1],
67
+ title: row.at_css('p.ttl a').content,
68
+ artist: artist_name,
69
+ artist_id: artist_id,
70
+ order: order.to_i,
71
+ date: Time.parse("#{date} JST"),
72
+ popularity: -popularity.to_i
73
+ }
74
+ end.compact
75
+
76
+ case sort
77
+ when :title
78
+ entries.sort_by {|e| e[:order]}
79
+ when :title_desc
80
+ entries.sort_by {|e| -e[:order]}
81
+ when :popularity
82
+ entries.sort_by {|e| e[:popularity]}
83
+ when :popularity_desc
84
+ entries.sort_by {|e| -e[:popularity]}
85
+ when :date
86
+ entries.sort_by {|e| e[:date]}
87
+ when :date_desc
88
+ entries.sort_by {|e| -e[:date].to_i}
89
+ when :artist, :artist_desc
90
+ entries
91
+ else
92
+ raise ArgumentError, "unsupported sort type `#{sort}`"
93
+ end
94
+ end
95
+
96
+ def self.get(id)
97
+ response = Natalia::Utils.curl_get("https://j-lyric.net/artist/#{id}.html")
98
+ response.value
99
+
100
+ doc = Nokogiri::HTML.parse(response.body)
101
+
102
+ smls = doc.css('div#mnb div.lbdy p.sml')
103
+
104
+ ret = {
105
+ source: self,
106
+ id: id,
107
+ title: doc.at_css('div#mnb div.cap h2').content.match(/\A「(.+)」歌詞\z/)[1],
108
+ artist: smls[0].at_css('a').content,
109
+ artist_id: smls[0].at_css('a')['href'].match(%r{/artist/(.+)/\z})[1]
110
+ }
111
+
112
+ smls[1..].each do |e|
113
+ content = e.content
114
+ ret[:lyricist] = content.match(/作詞:(.+)/)[1] if content.start_with?('作詞:')
115
+ ret[:composer] = content.match(/作曲:(.+)/)[1] if content.start_with?('作曲:')
116
+ end
117
+
118
+ ret[:lyrics] = doc.at_css('p#Lyric').children.map do |e|
119
+ e.name == 'br' ? "\n" : e.content
120
+ end.join.strip
121
+
122
+ ret
123
+ end
124
+ end
125
+ end
@@ -24,7 +24,8 @@ module Natalia
24
24
 
25
25
  def self.search(keyword, type: :title, sort: :popularity_desc)
26
26
  sort = SORT_MAP[sort]
27
- raise ArgumentError, 'invalid sort type' unless sort
27
+ raise ArgumentError, "unsupported sort type `#{sort}`" unless sort
28
+ raise ArgumentError, "unsupported search type `#{type}`" unless KIND_MAP.key?(type)
28
29
 
29
30
  response = Natalia::Utils.curl_post('https://mspxy.joysound.com/Common/ContentsList') do |request|
30
31
  request.content_type = 'application/x-www-form-urlencoded; charset=UTF-8'
@@ -19,8 +19,8 @@ module Natalia
19
19
  # @param [String] keyword キーワード(タイトル検索)、ID(それ以外)
20
20
  def self.search(keyword, type: :title, sort: :popularity_desc)
21
21
  sort = SORT_MAP[sort]
22
- raise ArgumentError, 'invalid sort type' unless sort
23
- raise ArgumentError, 'type must be :title, :artist, :lyricist, :composer, or :arranger' unless %i[title artist lyricist composer arranger].include?(type)
22
+ raise ArgumentError, "unsupported sort type `#{sort}`" unless sort
23
+ raise ArgumentError, "unsupported search type `#{type}`" unless %i[title artist lyricist composer arranger].include?(type)
24
24
 
25
25
  entries = []
26
26
  (type == :title ? 1.. : [1]).each do |page|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Natalia
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
data/lib/natalia.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'natalia/services/j_lyric'
3
4
  require_relative 'natalia/services/joysound'
4
5
  require_relative 'natalia/services/utamap'
5
6
  require_relative 'natalia/version'
@@ -44,6 +45,7 @@ module Natalia
44
45
  # 信頼できるソース順に並べる
45
46
  SERVICES = [
46
47
  Natalia::Utamap,
48
+ Natalia::JLyric,
47
49
  Natalia::Joysound
48
50
  ].freeze
49
51
 
@@ -51,6 +53,9 @@ module Natalia
51
53
  entries = []
52
54
  SERVICES.each do |service|
53
55
  entries += service.search(keyword, type: :title, sort: sort)
56
+ rescue StandardError
57
+ warn "Failed to search by #{service}"
58
+ warn $!.full_message
54
59
  end
55
60
  entries.map {|entry| Song.new(entry)}
56
61
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: natalia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ishotihadus
@@ -37,6 +37,7 @@ files:
37
37
  - README.md
38
38
  - Rakefile
39
39
  - lib/natalia.rb
40
+ - lib/natalia/services/j_lyric.rb
40
41
  - lib/natalia/services/joysound.rb
41
42
  - lib/natalia/services/utamap.rb
42
43
  - lib/natalia/utils.rb