vk_music 3.0.1 → 3.1.5

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: 2c51759b83b9c94ae99db4f957e80f9d7e071d998e171813dd33ccb1883d8d5c
4
- data.tar.gz: abd153ed90bc234046c4e38f41870fb66bc38ae390d7755cadce110b54c384bc
3
+ metadata.gz: aec492ae7fcb04bbc070c56a30110424661fdfda1766a70687bc14f476cd7d65
4
+ data.tar.gz: dba67eac6a1fe2563995e27d82f01f63f747fa15d06dd39704f6b3e1dffa54b2
5
5
  SHA512:
6
- metadata.gz: f5476442c461a25f5753cc707238ba01ee9d0cd1a180be23d8d5f7d3f46439a61bfc05106c15396745a62f2a5c8da6590c1c03f83cc0f86f5d10e95026a02505
7
- data.tar.gz: 8aade904f7fe57f4c073686a9aa15173083b6ed86ec30863723573fab391daacc2a6288cb3c47fdb253d806fa3607a5c3c0ee37c152b8a38df158c2145d6ebd2
6
+ metadata.gz: be3afe5a234742fac06fe01a57439ba2f5ca8f8d4ff1a81ea8d74c611f03876adfa41e967dec9598fa62d84bb73f9426d81e7e054f96d7d64c24efe4bfff8427
7
+ data.tar.gz: '09502160a7456174ba2f74841ed749ae34ecf5003e545b3381d43494f372fb064c9363d2e3df9167f6de9ba6ecb7a58a4abafde8ba99888d736e28cdbacd483c'
@@ -1,66 +1,70 @@
1
- PATH
2
- remote: .
3
- specs:
4
- vk_music (3.0.0)
5
- execjs (~> 2.7)
6
- json (~> 2.0)
7
- logger (~> 1.4)
8
- mechanize (~> 2.7)
9
- net-http-persistent (= 2.9.4)
10
-
11
- GEM
12
- remote: https://rubygems.org/
13
- specs:
14
- coderay (1.1.2)
15
- domain_name (0.5.20190701)
16
- unf (>= 0.0.5, < 1.0.0)
17
- execjs (2.7.0)
18
- http-cookie (1.0.3)
19
- domain_name (~> 0.5)
20
- json (2.2.0)
21
- logger (1.4.1)
22
- mechanize (2.7.6)
23
- domain_name (~> 0.5, >= 0.5.1)
24
- http-cookie (~> 1.0)
25
- mime-types (>= 1.17.2)
26
- net-http-digest_auth (~> 1.1, >= 1.1.1)
27
- net-http-persistent (>= 2.5.2)
28
- nokogiri (~> 1.6)
29
- ntlm-http (~> 0.1, >= 0.1.1)
30
- webrobots (>= 0.0.9, < 0.2)
31
- method_source (0.9.2)
32
- mime-types (3.3)
33
- mime-types-data (~> 3.2015)
34
- mime-types-data (3.2019.1009)
35
- mini_portile2 (2.4.0)
36
- minitest (5.13.0)
37
- net-http-digest_auth (1.4.1)
38
- net-http-persistent (2.9.4)
39
- nokogiri (1.10.7-x64-mingw32)
40
- mini_portile2 (~> 2.4.0)
41
- ntlm-http (0.1.1)
42
- pry (0.12.2)
43
- coderay (~> 1.1.0)
44
- method_source (~> 0.9.0)
45
- rake (10.5.0)
46
- unf (0.1.4)
47
- unf_ext
48
- unf_ext (0.0.7.6)
49
- webrobots (0.1.2)
50
- yard (0.9.20)
51
-
52
- PLATFORMS
53
- x64-mingw32
54
-
55
- DEPENDENCIES
56
- bundler (~> 2.0)
57
- logger (~> 1.4)
58
- mechanize (~> 2.7)
59
- minitest (~> 5.0)
60
- pry (~> 0.12.2)
61
- rake (~> 10.0)
62
- vk_music!
63
- yard (~> 0.9)
64
-
65
- BUNDLED WITH
66
- 2.0.2
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vk_music (3.1.5)
5
+ execjs (~> 2.7)
6
+ json (~> 2.0)
7
+ logger (~> 1.4)
8
+ mechanize (~> 2.7)
9
+ net-http-persistent (= 2.9.4)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ coderay (1.1.3)
15
+ domain_name (0.5.20190701)
16
+ unf (>= 0.0.5, < 1.0.0)
17
+ execjs (2.7.0)
18
+ http-cookie (1.0.3)
19
+ domain_name (~> 0.5)
20
+ json (2.3.1)
21
+ logger (1.4.2)
22
+ mechanize (2.7.6)
23
+ domain_name (~> 0.5, >= 0.5.1)
24
+ http-cookie (~> 1.0)
25
+ mime-types (>= 1.17.2)
26
+ net-http-digest_auth (~> 1.1, >= 1.1.1)
27
+ net-http-persistent (>= 2.5.2)
28
+ nokogiri (~> 1.6)
29
+ ntlm-http (~> 0.1, >= 0.1.1)
30
+ webrobots (>= 0.0.9, < 0.2)
31
+ method_source (0.9.2)
32
+ mime-types (3.3.1)
33
+ mime-types-data (~> 3.2015)
34
+ mime-types-data (3.2020.0512)
35
+ mini_portile2 (2.4.0)
36
+ minitest (5.14.1)
37
+ net-http-digest_auth (1.4.1)
38
+ net-http-persistent (2.9.4)
39
+ nokogiri (1.10.10)
40
+ mini_portile2 (~> 2.4.0)
41
+ nokogiri (1.10.10-x64-mingw32)
42
+ mini_portile2 (~> 2.4.0)
43
+ ntlm-http (0.1.1)
44
+ pry (0.12.2)
45
+ coderay (~> 1.1.0)
46
+ method_source (~> 0.9.0)
47
+ rake (13.0.1)
48
+ unf (0.1.4)
49
+ unf_ext
50
+ unf_ext (0.0.7.7)
51
+ unf_ext (0.0.7.7-x64-mingw32)
52
+ webrobots (0.1.2)
53
+ yard (0.9.25)
54
+
55
+ PLATFORMS
56
+ ruby
57
+ x64-mingw32
58
+
59
+ DEPENDENCIES
60
+ bundler (~> 2.0)
61
+ logger (~> 1.4)
62
+ mechanize (~> 2.7)
63
+ minitest (~> 5.0)
64
+ pry (~> 0.12.2)
65
+ rake (~> 13.0)
66
+ vk_music!
67
+ yard (~> 0.9)
68
+
69
+ BUNDLED WITH
70
+ 2.1.4
data/README.md CHANGED
@@ -71,6 +71,13 @@ audios = client.post(url: "https://vk.com/wall-4790861_5453")
71
71
  urls = audios.map(&:url) # URLs for every audio
72
72
  ```
73
73
 
74
+ ### Recommended audios and etc
75
+ You can load audios from recommended sections, novices and VK charts:
76
+
77
+ ```ruby
78
+ audios = client.block(url: "https://m.vk.com/audio?act=block&block=PUlQVA8GR0R3W0tMF2teRGpJUVQPGVpfdF1YRwMGXUpkXktMF2tYUWRHS0IXDlpKZFpcVA8FFg")
79
+ ```
80
+
74
81
 
75
82
  ## Development
76
83
 
@@ -7,4 +7,18 @@ require "vk_music"
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
9
  require "pry"
10
+
11
+ print "Login (leave this empty if no login required): "
12
+ username = STDIN.gets.chomp
13
+
14
+ unless username.empty?
15
+ print "Password: "
16
+ password = STDIN.gets.chomp
17
+ puts
18
+
19
+ $client = VkMusic::Client.new(username: username, password: password)
20
+ puts "You can now access client at $client"
21
+ end
22
+ puts
23
+
10
24
  Pry.start
@@ -120,6 +120,7 @@ module VkMusic
120
120
  @owner_id = owner_id
121
121
  @secret_1 = secret_1
122
122
  @secret_2 = secret_2
123
+ @secret_1 = @secret_2 if @secret_1.nil? || @secret_1.empty?
123
124
  @artist = artist.strip
124
125
  @title = title.strip
125
126
  @duration = duration
@@ -81,7 +81,7 @@ module VkMusic
81
81
  raise Exceptions::ParseError
82
82
  end
83
83
  raise ArgumentError unless owner_id && playlist_id
84
- use_web = up_to > 200 if use_web.nil?
84
+ use_web ||= (up_to <= 200)
85
85
  if use_web
86
86
  playlist_web(owner_id, playlist_id, access_hash, up_to: up_to)
87
87
  else
@@ -196,6 +196,7 @@ module VkMusic
196
196
  end
197
197
  end
198
198
  alias_method :from_id, :get_urls
199
+
199
200
  ##
200
201
  # Update download URLs of audios.
201
202
  # @param audios [Array<Audio>]
@@ -207,6 +208,25 @@ module VkMusic
207
208
  end
208
209
  end
209
210
 
211
+ ##
212
+ # Retrieve audios from recommendations or alike pages.
213
+ # Specify either +url+ or +block_id+.
214
+ # @param url [String] URL.
215
+ # @param block_id [String] ID of block.
216
+ # @return [Array<Audio>] array of audios attached to post. Most of audios will
217
+ # already have download URLs, but there might be audios which can't be resolved.
218
+ def block(url: nil, block_id: nil)
219
+ begin
220
+ block_id = url.match(Constants::Regex::VK_BLOCK_URL).captures.first if url
221
+ rescue
222
+ raise Exceptions::ParseError
223
+ end
224
+
225
+ uri = URI(Constants::URL::VK[:audios])
226
+ uri.query = Utility.hash_to_params({ "act" => "block", "block" => block_id })
227
+ audios_from_page(uri)
228
+ end
229
+
210
230
  ##
211
231
  # @!endgroup
212
232
 
@@ -447,26 +467,7 @@ module VkMusic
447
467
  # @param up_to [Integer] if less than 0, all audios will be loaded.
448
468
  # @return [Playlist]
449
469
  def playlist_web(owner_id, playlist_id, access_hash = nil, up_to: -1)
450
- # Load first page and get info
451
- first_page = load_page_playlist(owner_id, playlist_id, access_hash, offset: 0)
452
- begin
453
- # Parse out essential data
454
- title = first_page.at_css(".audioPlaylist__title").text.strip
455
- subtitle = first_page.at_css(".audioPlaylist__subtitle").text.strip
456
-
457
- footer_node = first_page.at_css(".audioPlaylist__footer")
458
- if footer_node
459
- footer_match = footer_node.text.strip.match(/^\d+/)
460
- real_size = footer_match ? footer_match[0].to_i : 0
461
- else
462
- real_size = 0
463
- end
464
- rescue
465
- raise Exceptions::ParseError
466
- end
467
- # Now we can be sure we are on correct page and have essential data.
468
-
469
- first_page_audios = audios_from_page(first_page)
470
+ first_page_audios, title, subtitle, real_size = playlist_first_page_web(owner_id, playlist_id, access_hash || "")
470
471
 
471
472
  # Check whether need to make additional requests
472
473
  up_to = real_size if (up_to < 0 || up_to > real_size)
@@ -494,18 +495,16 @@ module VkMusic
494
495
  # @param up_to [Integer] if less than 0, all audios will be loaded.
495
496
  # @return [Playlist]
496
497
  def playlist_json(owner_id, playlist_id, access_hash, up_to: -1)
497
- # Trying to parse out audios
498
- first_json = load_json_playlist_section(owner_id, playlist_id, access_hash, offset: 0)
499
- begin
500
- first_data = first_json["data"][0]
501
- first_data_audios = audios_from_data(first_data["list"])
502
- rescue
503
- raise Exceptions::ParseError
498
+ if playlist_id == -1
499
+ first_audios, title, subtitle, real_size = playlist_first_page_json(owner_id, playlist_id, access_hash || "")
500
+ else
501
+ first_audios, title, subtitle, real_size = playlist_first_page_web(owner_id, playlist_id, access_hash || "")
504
502
  end
503
+ # NOTE: We need to load first page from web to be able to unmask links in future
505
504
 
506
- real_size = first_data["totalCount"]
505
+ # Check whether need to make additional requests
507
506
  up_to = real_size if (up_to < 0 || up_to > real_size)
508
- list = first_data_audios.first(up_to)
507
+ list = first_audios.first(up_to)
509
508
  while list.length < up_to do
510
509
  json = load_json_playlist_section(owner_id, playlist_id, access_hash, offset: list.length)
511
510
  audios = begin
@@ -518,11 +517,11 @@ module VkMusic
518
517
 
519
518
  begin
520
519
  Playlist.new(list,
521
- id: first_data["id"],
522
- owner_id: first_data["owner_id"],
523
- access_hash: first_data["access_hash"],
524
- title: CGI.unescapeHTML(first_data["title"].to_s),
525
- subtitle: CGI.unescapeHTML(first_data["subtitle"].to_s),
520
+ id: playlist_id,
521
+ owner_id: owner_id,
522
+ access_hash: access_hash,
523
+ title: title,
524
+ subtitle: subtitle,
526
525
  real_size: real_size
527
526
  )
528
527
  rescue
@@ -530,6 +529,59 @@ module VkMusic
530
529
  end
531
530
  end
532
531
 
532
+ ##
533
+ # Load playlist first page in web and return essential data.
534
+ # @note not suitable for user audios
535
+ # @param owner_id [Integer]
536
+ # @param playlist_id [Integer]
537
+ # @param access_hash [String, nil]
538
+ # @return [Array<Array, String, String, Integer>] array with audios from first page, title, subtitle and playlist real size.
539
+ def playlist_first_page_web(owner_id, playlist_id, access_hash)
540
+ first_page = load_page_playlist(owner_id, playlist_id, access_hash, offset: 0)
541
+ begin
542
+ # Parse out essential data
543
+ title = first_page.at_css(".audioPlaylist__title").text.strip
544
+ subtitle = first_page.at_css(".audioPlaylist__subtitle").text.strip
545
+
546
+ footer_node = first_page.at_css(".audioPlaylist__footer")
547
+ if footer_node
548
+ footer_text = footer_node.text.strip
549
+ footer_text.gsub!(/\s/, "") # Removing all whitespace to get rid of delimiters ('1 042 audios')
550
+ footer_match = footer_text.match(/^\d+/)
551
+ real_size = footer_match ? footer_match[0].to_i : 0
552
+ else
553
+ real_size = 0
554
+ end
555
+
556
+ first_audios = audios_from_page(first_page)
557
+ rescue
558
+ raise Exceptions::ParseError
559
+ end
560
+ [first_audios, title, subtitle, real_size]
561
+ end
562
+
563
+ ##
564
+ # Load playlist first page in JSON and return essential data.
565
+ # @param owner_id [Integer]
566
+ # @param playlist_id [Integer]
567
+ # @param access_hash [String, nil]
568
+ # @return [Array<Array, String, String, Integer>] array with audios from first page, title, subtitle and playlist real size.
569
+ def playlist_first_page_json(owner_id, playlist_id, access_hash)
570
+ first_json = load_json_playlist_section(owner_id, playlist_id, access_hash, offset: 0)
571
+ begin
572
+ first_data = first_json["data"][0]
573
+ first_data_audios = audios_from_data(first_data["list"])
574
+ rescue
575
+ raise Exceptions::ParseError
576
+ end
577
+
578
+ real_size = first_data["totalCount"]
579
+ title = CGI.unescapeHTML(first_data["title"].to_s)
580
+ subtitle = CGI.unescapeHTML(first_data["subtitle"].to_s)
581
+
582
+ [first_data_audios, title, subtitle, real_size]
583
+ end
584
+
533
585
  ##
534
586
  # Found playlist URLs on *global* search page.
535
587
  # @param obj [Mechanize::Page, String, URI]
@@ -22,7 +22,7 @@ module VkMusic
22
22
  login_action: "https://login.vk.com",
23
23
  wall: "https://m.vk.com/wall",
24
24
  audio_unavailable: "https://m.vk.com/mp3/audio_api_unavailable.mp3",
25
- profile_audios: "https://m.vk.com/audios",
25
+ profile_audios: "https://m.vk.com/audios"
26
26
  }
27
27
  end
28
28
 
@@ -52,13 +52,16 @@ module VkMusic
52
52
  VK_AUDIOS_URL_POSTFIX = /^audios(-?\d+)$/
53
53
  ##
54
54
  # Playlist URL regular expression.
55
- VK_PLAYLIST_URL_POSTFIX = /.*(?:audio_playlist|album\/)(-?\d+)_(\d+)(?:(?:(?:.*(?=&access_hash=)&access_hash=)|\/|%2F|_)([\da-z]+))?/
55
+ VK_PLAYLIST_URL_POSTFIX = /.*(?:audio_playlist|album\/|playlist\/)(-?\d+)_(\d+)(?:(?:(?:.*(?=&access_hash=)&access_hash=)|\/|%2F|_)([\da-z]+))?/
56
56
  ##
57
57
  # Post URL regular expression #1.
58
58
  VK_POST_URL_POSTFIX = /.*post(-?\d+)_(\d+)/
59
59
  ##
60
60
  # Post URL regular expression #2.
61
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]+)/
62
65
  end
63
66
 
64
67
  ##
@@ -29,6 +29,8 @@ module VkMusic
29
29
  :playlist
30
30
  when Constants::Regex::VK_WALL_URL_POSTFIX, Constants::Regex::VK_POST_URL_POSTFIX
31
31
  :post
32
+ when Constants::Regex::VK_BLOCK_URL
33
+ :block
32
34
  when Constants::Regex::VK_URL
33
35
  :audios
34
36
  else
@@ -1,5 +1,5 @@
1
1
  module VkMusic
2
2
  ##
3
3
  # Library version.
4
- VERSION = "3.0.1"
4
+ VERSION = "3.1.5"
5
5
  end
@@ -1,40 +1,40 @@
1
- lib = File.expand_path("lib", __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "vk_music/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "vk_music"
7
- spec.version = VkMusic::VERSION
8
- spec.authors = ["Fizvlad"]
9
- spec.email = ["fizvlad@mail.ru"]
10
-
11
- spec.summary = "Provides interface to work with VK music via HTTP requests"
12
- spec.description = "Library to work with audios on popular Russian social network vk.com. VK disabled their public API for audios, so it is now necessary to use parsers instead."
13
- spec.homepage = "https://github.com/fizvlad/vk-music-rb"
14
- spec.license = "MIT"
15
-
16
- spec.required_ruby_version = ">=2.3.1"
17
-
18
-
19
- spec.metadata["homepage_uri"] = spec.homepage
20
- spec.metadata["source_code_uri"] = "https://github.com/fizvlad/vk-music-rb"
21
- spec.metadata["changelog_uri"] = "https://github.com/fizvlad/vk-music-rb/releases"
22
-
23
- # Specify which files should be added to the gem when it is released.
24
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
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
- spec.require_paths = ["lib"]
29
-
30
- spec.add_development_dependency "bundler", "~> 2.0"
31
- spec.add_development_dependency "rake", "~> 10.0"
32
- spec.add_development_dependency "yard", "~>0.9"
33
- spec.add_development_dependency "minitest", "~> 5.0"
34
-
35
- spec.add_runtime_dependency "logger", "~>1.4"
36
- spec.add_runtime_dependency "mechanize", "~>2.7"
37
- spec.add_runtime_dependency "net-http-persistent", "2.9.4" # Required for mechanize. Future versions cause error.
38
- spec.add_runtime_dependency "execjs", "~>2.7"
39
- spec.add_runtime_dependency "json", "~>2.0"
40
- end
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "vk_music/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "vk_music"
7
+ spec.version = VkMusic::VERSION
8
+ spec.authors = ["Fizvlad"]
9
+ spec.email = ["fizvlad@mail.ru"]
10
+
11
+ spec.summary = "Provides interface to work with VK music via HTTP requests"
12
+ spec.description = "Library to work with audios on popular Russian social network vk.com. VK disabled their public API for audios, so it is now necessary to use parsers instead."
13
+ spec.homepage = "https://github.com/fizvlad/vk-music-rb"
14
+ spec.license = "MIT"
15
+
16
+ spec.required_ruby_version = ">=2.3.1"
17
+
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/fizvlad/vk-music-rb"
21
+ spec.metadata["changelog_uri"] = "https://github.com/fizvlad/vk-music-rb/releases"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
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
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 2.0"
31
+ spec.add_development_dependency "rake", "~> 13.0"
32
+ spec.add_development_dependency "yard", "~>0.9"
33
+ spec.add_development_dependency "minitest", "~> 5.0"
34
+
35
+ spec.add_runtime_dependency "logger", "~>1.4"
36
+ spec.add_runtime_dependency "mechanize", "~>2.7"
37
+ spec.add_runtime_dependency "net-http-persistent", "2.9.4" # Required for mechanize. Future versions cause error.
38
+ spec.add_runtime_dependency "execjs", "~>2.7"
39
+ spec.add_runtime_dependency "json", "~>2.0"
40
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vk_music
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fizvlad
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-12 00:00:00.000000000 Z
11
+ date: 2020-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: yard
43
43
  requirement: !ruby/object:Gem::Requirement