maimai_net 0.0.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.
@@ -0,0 +1,108 @@
1
+ module MaimaiNet
2
+ # constant group that defines maimai server region
3
+ #
4
+ # @note any of modules defined in here can't be included nor modified any further.
5
+ module Region
6
+ module Base
7
+ def self.append_features(cls)
8
+ super
9
+ cls.const_set :WEBSITE_BASE, cls.const_get(:BASE_HOST) + '/maimai-mobile'
10
+ end
11
+ end
12
+
13
+ # maimai DX Japan Server constants
14
+ module Japan
15
+ BASE_HOST = URI('https://maimaidx.jp')
16
+ include Base
17
+ LOGIN_PAGE_PROC = ->(site){
18
+ site.host == WEBSITE_BASE.host && (
19
+ site.path == WEBSITE_BASE.path ||
20
+ site.path == WEBSITE_BASE.path + '/'
21
+ )
22
+ }
23
+ end
24
+
25
+ # maimai DX Asia Server constants
26
+ module Asia
27
+ BASE_HOST = URI('https://maimaidx-eng.com')
28
+ include Base
29
+ LOGIN_PAGE_PROC = ->(site){
30
+ site.host.end_with?('.am-all.net') &&
31
+ site.path.split('/').first(3).join('/') == '/common_auth/login'
32
+ }
33
+ LOGIN_ERROR_PROC = ->(site, body) {
34
+ LOGIN_PAGE_PROC.call(site) &&
35
+ %r{<([\S]+)(?:\s+[^>]+)?>Error</\1>}i.match?(body)
36
+ }
37
+ end
38
+
39
+ class << self
40
+ include ModuleExt::MethodCache
41
+
42
+ # @return [Array<Symbol>] list of available regions
43
+ cache_method :list do
44
+ regions.keys.freeze
45
+ end
46
+
47
+ # @return [Hash{Symbol => Module}] mapping of region key and its respective module
48
+ cache_method :regions do
49
+ constants.map do |k|
50
+ mod = const_get(k)
51
+ [k.downcase, mod]
52
+ end.sort_by(&:object_id).select do |name, mod|
53
+ mod.is_a?(Module) && mod < Base
54
+ end.to_h.freeze
55
+ end
56
+
57
+ # @return [Hash{Symbol => Hash{Symbol => Object}}] mapping of region properties in Hash-friendly format.
58
+ cache_method :infos do
59
+ regions.map do |k, mod|
60
+ d = mod.constants.map do |ck| [ck.downcase, mod.const_get(ck)] end.to_h
61
+ [k, d]
62
+ end.to_h.freeze
63
+ end
64
+
65
+ # guess server region based on provided URL.
66
+ #
67
+ # Conditions for a url considered as the server region are either:
68
+ # - uri is either exact component or sublevel of provided server's website uri.
69
+ # - uri should match server's internal login page.
70
+ #
71
+ # @param uri [String, URI] URL to check it's region
72
+ # @return [Symbol] region name for given url.
73
+ # @return [nil] none of the region matches.
74
+ cache_method :guess # do |uri|
75
+ def guess(uri)
76
+ return method(__method__).call(URI(uri)) unless URI::Generic === uri
77
+
78
+ infos.select do |k, data|
79
+ (
80
+ %i(scheme userinfo host port).all? do |k|
81
+ data[:website_base].public_send(k) == uri.public_send(k)
82
+ end && (
83
+ uri.path == data[:website_base].path ||
84
+ uri.path.start_with?(data[:website_base].path + '/')
85
+ )
86
+ ) || (
87
+ data[:login_page_proc].call(uri)
88
+ )
89
+ end.keys.shift
90
+ end
91
+
92
+ private :regions
93
+ end
94
+ ensure
95
+ # Freeze all modules and prevent from inclusion
96
+ mods = constants.map do |k| const_get(k) end
97
+ mods << self
98
+
99
+ private_constant :Base
100
+
101
+ mods.each do |mod|
102
+ %i(append_features prepend_features).each do |meth|
103
+ mod.define_singleton_method meth do |cls| end
104
+ end
105
+ mod.freeze
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,147 @@
1
+ module MaimaiNet
2
+ module UserOption
3
+ Option = Struct.new(:name, :choices, :selected) do
4
+ def select(value)
5
+ new_selected = choices.find do |choice|
6
+ choice.match?(value)
7
+ end
8
+
9
+ fail ArgumentError, "invalid value selected" if new_selected.nil?
10
+ self.selected = new_selected
11
+ end
12
+
13
+ alias pick select
14
+
15
+ def selected_id
16
+ self.selected.value
17
+ end
18
+
19
+ def to_a
20
+ [self.name, self.selected_id]
21
+ end
22
+
23
+ def to_h
24
+ Hash[*to_a]
25
+ end
26
+
27
+ alias to_ary to_a
28
+ alias to_hash to_h
29
+ end
30
+
31
+ Choice = Struct.new(:group, :value, :description) do
32
+ @symbol_alias_hooks = {
33
+ full: [],
34
+ partial: [],
35
+ }.freeze
36
+
37
+ def initialize(*args)
38
+ super
39
+
40
+ @alias_symbol = symbol_alias_of
41
+ @alias_value = value_alias_of
42
+ end
43
+
44
+ attr_reader :alias_symbol, :alias_value
45
+
46
+ def matches
47
+ description_value = !@alias_value.nil? ? description : nil
48
+ [self.value, description_value, @alias_symbol, @alias_value].compact.uniq
49
+ end
50
+
51
+ def match?(value)
52
+ matches.include?(value)
53
+ end
54
+
55
+ private
56
+ def symbol_alias_of
57
+ return if /^[-]?(?:0|[1-9]+[0-9]*)(?:[.][0-9]+)?$/.match?(description)
58
+
59
+ hooks = self.class.instance_variable_get(:@symbol_alias_hooks)
60
+ fully_replaced = false
61
+ value = description.dup
62
+ group_name = (String === self.group ? self.group : self.group.name).dup.freeze
63
+ value.dup.yield_self do |temp_value|
64
+ hooks[:full].each do |hook|
65
+ hook.call(group_name, temp_value)
66
+ fully_replaced |= temp_value != value
67
+ break if fully_replaced
68
+ end
69
+
70
+ value.replace temp_value if fully_replaced
71
+ end
72
+
73
+ value.dup.yield_self do |temp_value|
74
+ hooks[:partial].each do |hook|
75
+ hook.call(group_name, temp_value)
76
+ end
77
+
78
+ value.replace temp_value if temp_value != value
79
+ end unless fully_replaced
80
+
81
+ if /^[\x20-\x7f]+$/.match?(value) then
82
+ value.downcase.scan(/[a-z0-9]+/).join('_').to_sym
83
+ end
84
+ end
85
+
86
+ def value_alias_of
87
+ case description
88
+ when /^[-]?(?:0|[1-9]+[0-9]*)$/; Integer($&)
89
+ when /^[-]?(?:0|[1-9]+[0-9]*)(?:[.][0-9]+)?$/; Float($&)
90
+ end
91
+ end
92
+
93
+ def self.add_symbol_hook(key, func)
94
+ @symbol_alias_hooks.fetch(key)
95
+ .push(func)
96
+
97
+ self
98
+ end
99
+
100
+ add_symbol_hook :partial, ->(group, value) {
101
+ value.gsub! /['×・]/, ''
102
+ }
103
+ add_symbol_hook :partial, ->(group, value) {
104
+ value.gsub! /[&~]/ do |sym| ((sym.ord & ~0xff00) + 0x20).chr end
105
+ }
106
+ add_symbol_hook :partial, ->(group, value) {
107
+ value.gsub! /[(]([a-z]+)[)]/i, ' \1 '
108
+ }
109
+ add_symbol_hook :partial, ->(group, value) {
110
+ value.gsub! /[(](?:[a-z]*[+\-♦])[)]/i, {
111
+ '(+)' => ' increase ',
112
+ '(-)' => ' decrease ',
113
+ '(MAX-)' => ' decrease ',
114
+ '(♦)' => ' grade ',
115
+ }
116
+ }
117
+ add_symbol_hook :partial, ->(group, value) {
118
+ value.gsub! /(\d+)-(\w+)/ do sprintf('-%s%s', $1, $2) end
119
+ }
120
+ add_symbol_hook :partial, ->(group, value) {
121
+ value.gsub! /[\u2460-\u2473]/ do |sym| " #{(sym.ord - 0x2460) + 1}" end
122
+ }
123
+ add_symbol_hook :partial, ->(group, value) {
124
+ value.gsub! 'でらっくスコア', 'DX Score '
125
+ }
126
+
127
+ conversion = {
128
+ '⇔' => 'Mirror',
129
+ '⇅' => 'Flip',
130
+ '↻' => 'Rotate',
131
+ }
132
+ translation = {
133
+ 'デフォルト' => 'Default',
134
+ 'シンプル' => 'Simple',
135
+ 'クラシック' => 'Classic',
136
+ 'でらっくす' => 'Deluxe',
137
+ 'スプラッシュ' => 'Splash',
138
+ }
139
+ {}.merge(conversion, translation).tap do |convert_map|
140
+ pattern = Regexp.union(convert_map.keys)
141
+ add_symbol_hook :full, ->(group, value) {
142
+ value.gsub! pattern, convert_map
143
+ }
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,9 @@
1
+ module MaimaiNet
2
+ module Util
3
+ def self.extend_object(cls)
4
+ super
5
+ end
6
+ end
7
+
8
+ extend Util
9
+ end
@@ -0,0 +1,3 @@
1
+ module MaimaiNet
2
+ VERSION = -'0.0.1'
3
+ end
data/lib/maimai_net.rb ADDED
@@ -0,0 +1,14 @@
1
+ module MaimaiNet
2
+ require 'maimai_net/version'
3
+ require 'maimai_net/error'
4
+
5
+ require 'maimai_net/module_ext'
6
+ require 'maimai_net/util'
7
+ require 'maimai_net/constants'
8
+ require 'maimai_net/core_ext'
9
+ require 'maimai_net/refines'
10
+
11
+ require 'maimai_net/region'
12
+ require 'maimai_net/client'
13
+ require 'maimai_net/user_option'
14
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'lib/maimai_net/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "maimai_net"
5
+ spec.version = MaimaiNet::VERSION
6
+ spec.authors = [
7
+ %(Rei Hakurei),
8
+ ]
9
+ spec.email = %w(contact@bloom-juery.net)
10
+
11
+ spec.summary = %q(Parses maimai-net into readable data.)
12
+ spec.homepage = 'https://github.com/ReiFan49/rb.maimai-net'
13
+ spec.license = 'BSD-3-Clause-Clear'
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
15
+
16
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = spec.homepage
20
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ begin
25
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ rescue Errno::ENOENT
29
+ spec.files = Dir.glob('lib/**/*.rb', base: File.expand_path('..', __FILE__))
30
+ end
31
+ spec.bindir = "exe"
32
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
+ spec.require_paths = ["lib"]
34
+
35
+ spec.add_development_dependency 'rake'
36
+ spec.add_development_dependency 'rspec', '~> 3.0'
37
+ spec.add_development_dependency 'byebug'
38
+
39
+ spec.add_runtime_dependency 'nokogiri', '~> 1.13'
40
+ spec.add_runtime_dependency 'faraday', '~> 2.0'
41
+ spec.add_runtime_dependency 'faraday-follow_redirects'
42
+
43
+ spec.add_runtime_dependency 'http-cookie', '~> 1.0.0'
44
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: maimai_net
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Rei Hakurei
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-09-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.13'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.13'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faraday-follow_redirects
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: http-cookie
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.0.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.0.0
111
+ description:
112
+ email:
113
+ - contact@bloom-juery.net
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".github/workflows/gem.yml"
119
+ - ".gitignore"
120
+ - ".rspec"
121
+ - Gemfile
122
+ - LICENSE
123
+ - README.md
124
+ - Rakefile
125
+ - bin/console
126
+ - bin/setup
127
+ - lib/maimai_net.rb
128
+ - lib/maimai_net/client.rb
129
+ - lib/maimai_net/constants.rb
130
+ - lib/maimai_net/core_ext.rb
131
+ - lib/maimai_net/error.rb
132
+ - lib/maimai_net/faraday_ext/cookie_jar.rb
133
+ - lib/maimai_net/model-typing.rb
134
+ - lib/maimai_net/model.rb
135
+ - lib/maimai_net/module_ext.rb
136
+ - lib/maimai_net/page-debug.rb
137
+ - lib/maimai_net/page-html_helper.rb
138
+ - lib/maimai_net/page-player_data_helper.rb
139
+ - lib/maimai_net/page-track_result_helper.rb
140
+ - lib/maimai_net/page.rb
141
+ - lib/maimai_net/refines.rb
142
+ - lib/maimai_net/region.rb
143
+ - lib/maimai_net/user_option.rb
144
+ - lib/maimai_net/util.rb
145
+ - lib/maimai_net/version.rb
146
+ - maimai-net.gemspec
147
+ homepage: https://github.com/ReiFan49/rb.maimai-net
148
+ licenses:
149
+ - BSD-3-Clause-Clear
150
+ metadata:
151
+ homepage_uri: https://github.com/ReiFan49/rb.maimai-net
152
+ source_code_uri: https://github.com/ReiFan49/rb.maimai-net
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: 2.7.0
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubygems_version: 3.1.6
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: Parses maimai-net into readable data.
172
+ test_files: []