natalia 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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