vk_music 3.1.7 → 4.1.0
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 +4 -4
- data/.env.example +3 -0
- data/.github/workflows/ruby.yml +35 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.rubocop.yml +56 -0
- data/Gemfile +38 -10
- data/Gemfile.lock +124 -70
- data/LICENSE.txt +0 -0
- data/README.md +121 -94
- data/Rakefile +15 -22
- data/bin/console +18 -24
- data/lib/vk_music.rb +32 -18
- data/lib/vk_music/audio.rb +112 -187
- data/lib/vk_music/client.rb +193 -677
- data/lib/vk_music/playlist.rb +44 -97
- data/lib/vk_music/request.rb +13 -0
- data/lib/vk_music/request/artist.rb +24 -0
- data/lib/vk_music/request/audios_reload.rb +29 -0
- data/lib/vk_music/request/base.rb +75 -0
- data/lib/vk_music/request/login.rb +35 -0
- data/lib/vk_music/request/my_page.rb +21 -0
- data/lib/vk_music/request/playlist.rb +31 -0
- data/lib/vk_music/request/playlist_section.rb +35 -0
- data/lib/vk_music/request/post.rb +22 -0
- data/lib/vk_music/request/profile.rb +24 -0
- data/lib/vk_music/request/search.rb +34 -0
- data/lib/vk_music/request/wall_section.rb +34 -0
- data/lib/vk_music/utility.rb +8 -78
- data/lib/vk_music/utility/artist_loader.rb +17 -0
- data/lib/vk_music/utility/artist_url_parser.rb +22 -0
- data/lib/vk_music/utility/audio_data_parser.rb +37 -0
- data/lib/vk_music/utility/audio_items_parser.rb +18 -0
- data/lib/vk_music/utility/audio_node_parser.rb +59 -0
- data/lib/vk_music/utility/audios_from_ids_loader.rb +21 -0
- data/lib/vk_music/utility/audios_ids_getter.rb +25 -0
- data/lib/vk_music/utility/audios_loader.rb +37 -0
- data/lib/vk_music/utility/data_type_guesser.rb +48 -0
- data/lib/vk_music/utility/duration_parser.rb +17 -0
- data/lib/vk_music/utility/last_profile_post_loader.rb +26 -0
- data/lib/vk_music/utility/link_decoder.rb +107 -0
- data/lib/vk_music/utility/node_text_children_reader.rb +14 -0
- data/lib/vk_music/utility/playlist_loader.rb +30 -0
- data/lib/vk_music/utility/playlist_node_parser.rb +21 -0
- data/lib/vk_music/utility/playlist_section_loader.rb +29 -0
- data/lib/vk_music/utility/playlist_url_parser.rb +32 -0
- data/lib/vk_music/utility/post_loader.rb +23 -0
- data/lib/vk_music/utility/post_url_parser.rb +24 -0
- data/lib/vk_music/utility/profile_id_resolver.rb +58 -0
- data/lib/vk_music/utility/wall_loader.rb +25 -0
- data/lib/vk_music/version.rb +7 -5
- data/lib/vk_music/web_parser.rb +9 -0
- data/lib/vk_music/web_parser/artist.rb +16 -0
- data/lib/vk_music/web_parser/audios_reload.rb +20 -0
- data/lib/vk_music/web_parser/base.rb +27 -0
- data/lib/vk_music/web_parser/login.rb +13 -0
- data/lib/vk_music/web_parser/my_page.rb +19 -0
- data/lib/vk_music/web_parser/playlist.rb +33 -0
- data/lib/vk_music/web_parser/playlist_section.rb +53 -0
- data/lib/vk_music/web_parser/post.rb +15 -0
- data/lib/vk_music/web_parser/profile.rb +33 -0
- data/lib/vk_music/web_parser/search.rb +56 -0
- data/lib/vk_music/web_parser/wall_section.rb +53 -0
- data/vk_music.gemspec +36 -40
- metadata +63 -77
- data/.travis.yml +0 -7
- data/bin/setup +0 -8
- data/lib/vk_music/constants.rb +0 -78
- data/lib/vk_music/exceptions.rb +0 -21
- data/lib/vk_music/link_decoder.rb +0 -102
- data/lib/vk_music/utility/log.rb +0 -51
data/lib/vk_music/playlist.rb
CHANGED
@@ -1,97 +1,44 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# @return [Integer, nil] owner
|
12
|
-
attr_reader :owner_id
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# @return [String] playlist
|
18
|
-
attr_reader :
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# @
|
32
|
-
def
|
33
|
-
|
34
|
-
@
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
def to_a
|
46
|
-
@list.dup
|
47
|
-
end
|
48
|
-
|
49
|
-
##
|
50
|
-
# @!visibility private
|
51
|
-
def each(&block)
|
52
|
-
@list.each(&block)
|
53
|
-
end
|
54
|
-
##
|
55
|
-
# @return [Integer] amount of audios. This can be less than real size as not all audios might be loaded.
|
56
|
-
def length
|
57
|
-
@list.length
|
58
|
-
end
|
59
|
-
alias size length
|
60
|
-
##
|
61
|
-
# Access audios from playlist.
|
62
|
-
# @param index [Integer] index of audio (starting from 0).
|
63
|
-
# @return [Audio, nil] audio or +nil+ if out of range.
|
64
|
-
def [](index)
|
65
|
-
@list[index]
|
66
|
-
end
|
67
|
-
##
|
68
|
-
# @return [Boolean] whether no audios loaded for this playlist.
|
69
|
-
def empty?
|
70
|
-
@list.empty?
|
71
|
-
end
|
72
|
-
|
73
|
-
##
|
74
|
-
# Initialize new playlist.
|
75
|
-
#
|
76
|
-
# @param list [Array] list of audios in playlist.
|
77
|
-
# @param id [Integer, nil]
|
78
|
-
# @param owner_id [Integer, nil]
|
79
|
-
# @param access_hash [String, nil]
|
80
|
-
# @param title [String]
|
81
|
-
# @param subtitle [String, nil]
|
82
|
-
# @param real_size [Integer, nil]
|
83
|
-
def initialize(list, id: nil, owner_id: nil, access_hash: nil, title: "", subtitle: nil, real_size: nil)
|
84
|
-
raise ArgumentError unless list.is_a?(Array)
|
85
|
-
# Saving list
|
86
|
-
@list = list.dup
|
87
|
-
|
88
|
-
# Setting up attributes
|
89
|
-
@id = id
|
90
|
-
@owner_id = owner_id
|
91
|
-
@access_hash = access_hash
|
92
|
-
@title = title
|
93
|
-
@subtitle = subtitle
|
94
|
-
@real_size = real_size
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
# Class representing VK playlist
|
5
|
+
class Playlist
|
6
|
+
extend Forwardable
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
# @return [Integer, nil] playlist ID
|
10
|
+
attr_reader :id
|
11
|
+
# @return [Integer, nil] playlist owner ID
|
12
|
+
attr_reader :owner_id
|
13
|
+
# @return [String, nil] access hash which should be part of link for some playlists
|
14
|
+
attr_reader :access_hash
|
15
|
+
# @return [String] playlist title
|
16
|
+
attr_reader :title
|
17
|
+
# @return [String, nil] playlist subtitle. May be empty
|
18
|
+
attr_reader :subtitle
|
19
|
+
# @return [Integer, nil] real size of playlist or +nil+ if unknown
|
20
|
+
attr_reader :real_size
|
21
|
+
# @return [Array] audios array
|
22
|
+
attr_reader :audios
|
23
|
+
|
24
|
+
# Initialize new playlist
|
25
|
+
# @param audios [Array] list of audios in playlist
|
26
|
+
# @param id [Integer, nil]
|
27
|
+
# @param owner_id [Integer, nil]
|
28
|
+
# @param access_hash [String, nil]
|
29
|
+
# @param title [String]
|
30
|
+
# @param subtitle [String, nil]
|
31
|
+
# @param real_size [Integer, nil]
|
32
|
+
def initialize(audios, id: nil, owner_id: nil, access_hash: nil, title: '', subtitle: nil, real_size: nil)
|
33
|
+
@audios = audios.dup
|
34
|
+
@id = id
|
35
|
+
@owner_id = owner_id
|
36
|
+
@access_hash = access_hash
|
37
|
+
@title = title.to_s.strip
|
38
|
+
@subtitle = subtitle
|
39
|
+
@real_size = real_size
|
40
|
+
end
|
41
|
+
|
42
|
+
def_delegators :@audios, :each, :length, :size, :[], :empty?
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
# Bunch of different web requests
|
5
|
+
module Request
|
6
|
+
# VK root URL
|
7
|
+
VK_ROOT = 'https://m.vk.com'
|
8
|
+
public_constant :VK_ROOT
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require_relative 'request/base'
|
13
|
+
Dir[File.join(__dir__, 'request', '*.rb')].each { |file| require_relative file }
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Artist audios page request
|
6
|
+
class Artist < Base
|
7
|
+
# Initialize new request
|
8
|
+
# @param name [String]
|
9
|
+
# @param client_id [Integer]
|
10
|
+
def initialize(name, client_id)
|
11
|
+
@client_id = client_id
|
12
|
+
super("#{VK_ROOT}/artist/#{name}/top_audios", {}, 'GET', {})
|
13
|
+
end
|
14
|
+
|
15
|
+
def_delegators :@parser, :audios
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def after_call
|
20
|
+
@parser = WebParser::Artist.new(@response, client_id: @client_id)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Audios reload
|
6
|
+
class AudiosReload < Base
|
7
|
+
# Initialize new request
|
8
|
+
# @param ids [Array<String>]
|
9
|
+
# @param client_id [Integer]
|
10
|
+
def initialize(ids, client_id)
|
11
|
+
@client_id = client_id
|
12
|
+
super(
|
13
|
+
"#{VK_ROOT}/audio",
|
14
|
+
{ act: 'reload_audio', ids: ids.join(','), utf8: true },
|
15
|
+
'GET',
|
16
|
+
{}
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def_delegators :@parser, :audios
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def after_call
|
25
|
+
@parser = WebParser::AudiosReload.new(@response.body, client_id: @client_id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Base class for most of requests
|
6
|
+
class Base
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# @return [String]
|
10
|
+
attr_reader :path
|
11
|
+
# @return [Hash]
|
12
|
+
attr_reader :data
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :method
|
15
|
+
# @return [Hash]
|
16
|
+
attr_reader :headers
|
17
|
+
# @return [Mechanize::File?]
|
18
|
+
attr_reader :response
|
19
|
+
|
20
|
+
# Initialize new request
|
21
|
+
# @param path [String]
|
22
|
+
# @param data [Hash]
|
23
|
+
# @param method [String]
|
24
|
+
# @param headers [Hash]
|
25
|
+
def initialize(path, data = {}, method = 'GET', headers = {})
|
26
|
+
@path = path
|
27
|
+
@data = data
|
28
|
+
@method = method.upcase
|
29
|
+
@headers = headers
|
30
|
+
|
31
|
+
@response = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param agent [Mechanize]
|
35
|
+
# @return [self]
|
36
|
+
def call(agent)
|
37
|
+
before_call
|
38
|
+
|
39
|
+
log
|
40
|
+
@response = case method
|
41
|
+
when 'GET' then get(agent)
|
42
|
+
when 'POST' then post(agent)
|
43
|
+
else raise(ArgumentError, "unsupported method #{method}")
|
44
|
+
end
|
45
|
+
|
46
|
+
after_call
|
47
|
+
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def log
|
54
|
+
VkMusic.log.debug('request') do
|
55
|
+
"#{method} to '#{path}', with data: #{data}, headers: #{headers}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get(agent)
|
60
|
+
uri = URI(path)
|
61
|
+
uri.query = URI.encode_www_form(data)
|
62
|
+
agent.get(uri, [], nil, headers)
|
63
|
+
end
|
64
|
+
|
65
|
+
def post(agent)
|
66
|
+
uri = URI(path)
|
67
|
+
agent.post(uri, data, headers)
|
68
|
+
end
|
69
|
+
|
70
|
+
def before_call; end
|
71
|
+
|
72
|
+
def after_call; end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Logging in request
|
6
|
+
class Login < Base
|
7
|
+
# Initialize new request
|
8
|
+
def initialize
|
9
|
+
super("#{VK_ROOT}/login", {}, 'GET', {})
|
10
|
+
@success = false
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Boolean]
|
14
|
+
def success?
|
15
|
+
!!@success
|
16
|
+
end
|
17
|
+
|
18
|
+
# Send login form
|
19
|
+
def send_form(login, password, agent)
|
20
|
+
form = @parser.login_form
|
21
|
+
form['email'] = login
|
22
|
+
form['pass'] = password
|
23
|
+
page = agent.submit(form)
|
24
|
+
|
25
|
+
@success = (page.uri.to_s == 'https://m.vk.com/feed')
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def after_call
|
31
|
+
@parser = WebParser::Login.new(@response)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Logging in request
|
6
|
+
class MyPage < Base
|
7
|
+
# Initialize new request
|
8
|
+
def initialize
|
9
|
+
super("#{VK_ROOT}/id0", {}, 'GET', {})
|
10
|
+
end
|
11
|
+
|
12
|
+
def_delegators :@parser, :id, :name
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def after_call
|
17
|
+
@parser = WebParser::MyPage.new(@response)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Playlist in web-mobile request
|
6
|
+
class Playlist < Base
|
7
|
+
# Initialize new request
|
8
|
+
# @param owner_id [Integer]
|
9
|
+
# @param playlist_id [Integer]
|
10
|
+
# @param access_hash [String, nil]
|
11
|
+
# @param client_id [Integer]
|
12
|
+
def initialize(owner_id, playlist_id, access_hash, client_id)
|
13
|
+
@client_id = client_id
|
14
|
+
super(
|
15
|
+
"#{VK_ROOT}/audio",
|
16
|
+
{ act: "audio_playlist#{owner_id}_#{playlist_id}", access_hash: access_hash },
|
17
|
+
'GET',
|
18
|
+
{}
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def_delegators :@parser, :audios, :title, :subtitle, :real_size
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def after_call
|
27
|
+
@parser = WebParser::Playlist.new(@response.body)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Playlist in web-mobile request
|
6
|
+
class PlaylistSection < Base
|
7
|
+
# Initialize new request
|
8
|
+
# @param owner_id [Integer]
|
9
|
+
# @param playlist_id [Integer]
|
10
|
+
# @param access_hash [String, nil]
|
11
|
+
# @param offset [Integer]
|
12
|
+
# @param client_id [Integer]
|
13
|
+
def initialize(owner_id, playlist_id, access_hash, offset, client_id)
|
14
|
+
@client_id = client_id
|
15
|
+
super(
|
16
|
+
"#{VK_ROOT}/audio",
|
17
|
+
{
|
18
|
+
act: 'load_section', type: 'playlist', offset: offset, utf8: true,
|
19
|
+
owner_id: owner_id, playlist_id: playlist_id, access_hash: access_hash.to_s
|
20
|
+
},
|
21
|
+
'GET',
|
22
|
+
{}
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def_delegators :@parser, :audios, :title, :subtitle, :real_size, :more?
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def after_call
|
31
|
+
@parser = WebParser::PlaylistSection.new(@response, client_id: @client_id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# Post page
|
6
|
+
class Post < Base
|
7
|
+
# Initialize new request
|
8
|
+
def initialize(owner_id, post_id, client_id)
|
9
|
+
@client_id = client_id
|
10
|
+
super("#{VK_ROOT}/wall#{owner_id}_#{post_id}", {}, 'GET', {})
|
11
|
+
end
|
12
|
+
|
13
|
+
def_delegators :@parser, :audios
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def after_call
|
18
|
+
@parser = WebParser::Post.new(@response, client_id: @client_id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VkMusic
|
4
|
+
module Request
|
5
|
+
# User or group page
|
6
|
+
class Profile < Base
|
7
|
+
# Initialize new request
|
8
|
+
def initialize(profile_id: nil, profile_custom_path: nil)
|
9
|
+
profile_path =
|
10
|
+
profile_custom_path ||
|
11
|
+
"#{profile_id.negative? ? 'club' : 'id'}#{profile_id.abs}"
|
12
|
+
super("#{VK_ROOT}/#{profile_path}", {}, 'GET', {})
|
13
|
+
end
|
14
|
+
|
15
|
+
def_delegators :@parser, :id, :last_post_id
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def after_call
|
20
|
+
@parser = WebParser::Profile.new(@response)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|