vk_music 3.1.3 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.example +3 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.rubocop.yml +56 -0
- data/Gemfile +38 -10
- data/Gemfile.lock +78 -24
- data/LICENSE.txt +0 -0
- data/README.md +111 -94
- data/Rakefile +12 -22
- data/bin/console +18 -24
- data/lib/vk_music.rb +32 -18
- data/lib/vk_music/audio.rb +111 -187
- data/lib/vk_music/client.rb +187 -615
- data/lib/vk_music/playlist.rb +44 -97
- data/lib/vk_music/request.rb +13 -0
- data/lib/vk_music/request/audios.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/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 +43 -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 +106 -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 +51 -0
- data/lib/vk_music/utility/wall_loader.rb +25 -0
- data/lib/vk_music/version.rb +8 -5
- data/lib/vk_music/web_parser.rb +9 -0
- data/lib/vk_music/web_parser/audios.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 +58 -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/bin/setup
DELETED
data/lib/vk_music/constants.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
module VkMusic
|
2
|
-
##
|
3
|
-
# Constants.
|
4
|
-
module Constants
|
5
|
-
##
|
6
|
-
# Default web user agent.
|
7
|
-
DEFAULT_USER_AGENT = "" # Using empty user agent confuses VK and it returnes MP3
|
8
|
-
|
9
|
-
##
|
10
|
-
# Different URLs
|
11
|
-
module URL
|
12
|
-
##
|
13
|
-
# Hash with URLs to VK pages which are used by library.
|
14
|
-
VK = {
|
15
|
-
scheme: "https",
|
16
|
-
host: "m.vk.com",
|
17
|
-
home: "https://m.vk.com",
|
18
|
-
profile: "https://m.vk.com/id0",
|
19
|
-
feed: "https://m.vk.com/feed",
|
20
|
-
audios: "https://m.vk.com/audio",
|
21
|
-
login: "https://m.vk.com/login",
|
22
|
-
login_action: "https://login.vk.com",
|
23
|
-
wall: "https://m.vk.com/wall",
|
24
|
-
audio_unavailable: "https://m.vk.com/mp3/audio_api_unavailable.mp3",
|
25
|
-
profile_audios: "https://m.vk.com/audios"
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
##
|
30
|
-
# Regular expressions
|
31
|
-
module Regex
|
32
|
-
##
|
33
|
-
# VK user or group ID.
|
34
|
-
VK_ID_STR = /^-?\d+$/
|
35
|
-
##
|
36
|
-
# VK user or group ID.
|
37
|
-
VK_ID = /-?\d+/
|
38
|
-
##
|
39
|
-
# VK prefixed user or group ID.
|
40
|
-
VK_PREFIXED_ID_STR = /^(?:id|club|group|public|event)(\d+)$/
|
41
|
-
##
|
42
|
-
# VK custom ID regular expression.
|
43
|
-
VK_CUSTOM_ID = /^\w+$/
|
44
|
-
##
|
45
|
-
# VK URL regular expression.
|
46
|
-
VK_URL = /(?:https?:\/\/)?(?:m\.|www\.)?vk\.com\/([\w\-]+)/
|
47
|
-
##
|
48
|
-
# +href+ attribute with VK ID regular expression.
|
49
|
-
VK_HREF_ID_CONTAINING = /(?:audios|photo|write|owner_id=|friends\?id=)(-?\d+)/
|
50
|
-
##
|
51
|
-
# VK audios page regular expression.
|
52
|
-
VK_AUDIOS_URL_POSTFIX = /^audios(-?\d+)$/
|
53
|
-
##
|
54
|
-
# Playlist URL regular expression.
|
55
|
-
VK_PLAYLIST_URL_POSTFIX = /.*(?:audio_playlist|album\/)(-?\d+)_(\d+)(?:(?:(?:.*(?=&access_hash=)&access_hash=)|\/|%2F|_)([\da-z]+))?/
|
56
|
-
##
|
57
|
-
# Post URL regular expression #1.
|
58
|
-
VK_POST_URL_POSTFIX = /.*post(-?\d+)_(\d+)/
|
59
|
-
##
|
60
|
-
# Post URL regular expression #2.
|
61
|
-
VK_WALL_URL_POSTFIX = /.*wall(-?\d+)_(\d+)/
|
62
|
-
##
|
63
|
-
# Audios block ID
|
64
|
-
VK_BLOCK_URL = /(?:section=recoms_block&type=|act=block&block=)([a-zA-Z\d]+)/
|
65
|
-
end
|
66
|
-
|
67
|
-
##
|
68
|
-
# Names used in VK login form.
|
69
|
-
VK_LOGIN_FORM_NAMES = {
|
70
|
-
username: "email",
|
71
|
-
password: "pass"
|
72
|
-
}
|
73
|
-
|
74
|
-
##
|
75
|
-
# Maximum amount of audios in VK playlist.
|
76
|
-
MAXIMUM_PLAYLIST_SIZE = 10000
|
77
|
-
end
|
78
|
-
end
|
data/lib/vk_music/exceptions.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module VkMusic
|
2
|
-
##
|
3
|
-
# Exceptions.
|
4
|
-
module Exceptions
|
5
|
-
##
|
6
|
-
# General class for all the errors.
|
7
|
-
class VkMusicError < RuntimeError; end
|
8
|
-
##
|
9
|
-
# Failed to login.
|
10
|
-
class LoginError < VkMusicError; end
|
11
|
-
##
|
12
|
-
# Failed to get request. _Only_ thrown when Mechanize failed to load page
|
13
|
-
class RequestError < VkMusicError; end
|
14
|
-
##
|
15
|
-
# Parse error. Request is OK, but something went wrong while parsing reply.
|
16
|
-
# It might be missing playlist/post as well.
|
17
|
-
class ParseError < VkMusicError; end
|
18
|
-
end
|
19
|
-
|
20
|
-
include Exceptions
|
21
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
module VkMusic
|
2
|
-
##
|
3
|
-
# Module containing link decoding utilities.
|
4
|
-
module LinkDecoder
|
5
|
-
##
|
6
|
-
# JS code which creates function to unmask audio URL.
|
7
|
-
js_code = <<~HEREDOC
|
8
|
-
function vk_unmask_link(link, vk_id) {
|
9
|
-
|
10
|
-
// Utility functions to unmask
|
11
|
-
|
12
|
-
var audioUnmaskSource = function (encrypted) {
|
13
|
-
if (encrypted.indexOf('audio_api_unavailable') != -1) {
|
14
|
-
var parts = encrypted.split('?extra=')[1].split('#');
|
15
|
-
|
16
|
-
var handled_anchor = '' === parts[1] ? '' : handler(parts[1]);
|
17
|
-
|
18
|
-
var handled_part = handler(parts[0]);
|
19
|
-
|
20
|
-
if (typeof handled_anchor != 'string' || !handled_part) {
|
21
|
-
// if (typeof handled_anchor != 'string') console.warn('Handled_anchor type: ' + typeof handled_anchor);
|
22
|
-
// if (!handled_part) console.warn('Handled_part: ' + handled_part);
|
23
|
-
return encrypted;
|
24
|
-
}
|
25
|
-
|
26
|
-
handled_anchor = handled_anchor ? handled_anchor.split(String.fromCharCode(9)) : [];
|
27
|
-
|
28
|
-
for (var func_key, splited_anchor, l = handled_anchor.length; l--;) {
|
29
|
-
splited_anchor = handled_anchor[l].split(String.fromCharCode(11));
|
30
|
-
func_key = splited_anchor.splice(0, 1, handled_part)[0];
|
31
|
-
if (!utility_object[func_key]) {
|
32
|
-
// console.warn('Was unable to find key: ' + func_key);
|
33
|
-
return encrypted;
|
34
|
-
}
|
35
|
-
handled_part = utility_object[func_key].apply(null, splited_anchor)
|
36
|
-
}
|
37
|
-
|
38
|
-
if (handled_part && 'http' === handled_part.substr(0, 4)) return handled_part;
|
39
|
-
// else console.warn('Failed unmasking: ' + handled_part);
|
40
|
-
} else {
|
41
|
-
// console.warn('Bad link: ' + encrypted);
|
42
|
-
}
|
43
|
-
return encrypted;
|
44
|
-
}
|
45
|
-
|
46
|
-
var handler = function (part) {
|
47
|
-
if (!part || part.length % 4 == 1) return !1;
|
48
|
-
for (var t, i, o = 0, s = 0, a = ''; i = part.charAt(s++);) {
|
49
|
-
i = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN0PQRSTUVWXYZO123456789+/='.indexOf(i)
|
50
|
-
~i && (t = o % 4 ? 64 * t + i : i, o++ % 4) && (a += String.fromCharCode(255 & t >> (-2 * o & 6)));
|
51
|
-
}
|
52
|
-
return a;
|
53
|
-
}
|
54
|
-
|
55
|
-
var utility_object = {
|
56
|
-
i: function(e, t) {
|
57
|
-
return utility_object.s(e, t ^ vk_id);
|
58
|
-
},
|
59
|
-
s: function(e, t) {
|
60
|
-
var n = e.length;
|
61
|
-
if (n) {
|
62
|
-
var i = r_func(e, t),
|
63
|
-
o = 0;
|
64
|
-
for (e = e.split(''); ++o < n;)
|
65
|
-
e[o] = e.splice(i[n - 1 - o], 1, e[o])[0];
|
66
|
-
e = e.join('')
|
67
|
-
}
|
68
|
-
return e;
|
69
|
-
}
|
70
|
-
};
|
71
|
-
|
72
|
-
var r_func = function (e, t) {
|
73
|
-
var n = e.length,
|
74
|
-
i = [];
|
75
|
-
if (n) {
|
76
|
-
var o = n;
|
77
|
-
for (t = Math.abs(t); o--;)
|
78
|
-
t = (n * (o + 1) ^ t + o) % n,
|
79
|
-
i[o] = t;
|
80
|
-
}
|
81
|
-
return i;
|
82
|
-
}
|
83
|
-
|
84
|
-
return audioUnmaskSource(link);
|
85
|
-
}
|
86
|
-
HEREDOC
|
87
|
-
|
88
|
-
##
|
89
|
-
# JS context with unmasking link.
|
90
|
-
@@js_context = ExecJS.compile(js_code)
|
91
|
-
|
92
|
-
##
|
93
|
-
# Unmask audio download URL.
|
94
|
-
# @param link [String] encoded link to audio. Usually looks like "https://m.vk.com/mp3/audio_api_unavailable.mp3?extra=...".
|
95
|
-
# @param client_id [Integer] ID of user which got this link. ID is required for decoding.
|
96
|
-
# @return [String] audio download URL, which can be used only from current IP.
|
97
|
-
def self.unmask_link(link, client_id)
|
98
|
-
VkMusic.debug("Unmasking link.")
|
99
|
-
@@js_context.call("vk_unmask_link", link.to_s, client_id.to_i)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
data/lib/vk_music/utility/log.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
module VkMusic
|
2
|
-
##
|
3
|
-
# @!group Logger
|
4
|
-
|
5
|
-
##
|
6
|
-
# Default logger
|
7
|
-
@@logger = Logger.new(defined?($LOG_FILE) ? $LOGFILE : STDOUT,
|
8
|
-
formatter: Proc.new do |severity, datetime, progname, msg|
|
9
|
-
"[#{datetime}] #{severity}#{progname ? " - #{progname}" : ""}:\t #{msg}\n"
|
10
|
-
end
|
11
|
-
)
|
12
|
-
@@logger.level = $DEBUG ? Logger::DEBUG : Logger::INFO
|
13
|
-
|
14
|
-
##
|
15
|
-
# Setup new logger.
|
16
|
-
# @param new_logger [Logger, nil]
|
17
|
-
def self.logger=(new_logger)
|
18
|
-
@@logger = new_logger
|
19
|
-
end
|
20
|
-
##
|
21
|
-
# Access current logger.
|
22
|
-
# @return [Logger, nil]
|
23
|
-
def self.logger
|
24
|
-
@@logger
|
25
|
-
end
|
26
|
-
|
27
|
-
##
|
28
|
-
# Log message.
|
29
|
-
def self.log(severity, message = nil, progname = nil)
|
30
|
-
@@logger.log(severity, message, progname) if @@logger
|
31
|
-
end
|
32
|
-
|
33
|
-
##
|
34
|
-
# Log warn message.
|
35
|
-
def self.warn(message = nil, progname = nil)
|
36
|
-
@@logger.log(Logger::WARN, message, progname)
|
37
|
-
end
|
38
|
-
##
|
39
|
-
# Log info message.
|
40
|
-
def self.info(message = nil, progname = nil)
|
41
|
-
@@logger.log(Logger::INFO, message, progname)
|
42
|
-
end
|
43
|
-
##
|
44
|
-
# Log debug message.
|
45
|
-
def self.debug(message = nil, progname = nil)
|
46
|
-
@@logger.log(Logger::DEBUG, message, progname)
|
47
|
-
end
|
48
|
-
|
49
|
-
##
|
50
|
-
# @!endgroup
|
51
|
-
end
|