vk_music 2.0.0 → 2.1.0

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: e42dd22de66cd8bb8d2d0b70686102d4d50078677736b036b7c383470ff31f2a
4
- data.tar.gz: c6d3eb20221b599d48a1e4464b837ef294d926b4bc9fbeb81b348e9ae5c63f90
3
+ metadata.gz: c25c28560c85999aeffe7b23070762fe875600eb32fde5758c5d02041a9d079b
4
+ data.tar.gz: 64b80f5fe01c1e8bf19ef95c6660ccbb5043b5fb07257c8590bb93f08af2b7e1
5
5
  SHA512:
6
- metadata.gz: 515fbb7b67a8a53b0e2bc8ed0ef8f34a4cdda560ad94a4880ff8e9b36fb7d3c023386b6c2fca3d0df59eb19487d5a708d21684ddb3bf25bcbda4b2141506dd63
7
- data.tar.gz: 40eac37ca4af3db6eb0d88a7e93277f923565c013207706e0d29e7b14a18354628d9bdb79b8eb71de753571a29a4ed93bbeb0e3adad697a4cdc6cfed3c9598a0
6
+ metadata.gz: 4bb0b4d69ad1699d760ab30e3e6149b3440318ab7edf2c42e2e17172d18c564f4922fde227089e2dc828658c34689599f93759fa5ea954af350f35747ba32cd2
7
+ data.tar.gz: 4cb018f20a3cae069616cb1f339703b9f9975f7939a1924225d1840562f30c9f759a21386f00729a499193bd11a3af7339e9b9860ed148cb6f6f3bdae834c0ae
@@ -50,28 +50,42 @@ module VkMusic
50
50
  #@!group Loading audios
51
51
 
52
52
  ##
53
- # Search for audio.
53
+ # @!macro [new] find__options
54
+ # @option options [Symbol] :type (:audio) what to search for (you can find available values for this option above).
54
55
  #
55
- # @note some audios might be removed from search.
56
+ # Search for audio or playlist.
57
+ #
58
+ # @note some audios and playlists might be removed from search.
56
59
  #
57
60
  # @todo search in group audios.
58
61
  #
59
- # @overload find(query)
62
+ # Possible values of +type+ option:
63
+ # * +:audio+ - search for audios. Returns up to 50 audios.
64
+ # * +:playlist+ - search for playlists. Returns up to 6 playlists *without* audios (Loaded with +up_to: 0+ option).
65
+ # You can get all the audios of selected playlist calling {Client#playlist} method with gained info.
66
+ #
67
+ # @overload find(query, options)
60
68
  # @param query [String] string to search for.
69
+ # @macro options_hash_param
70
+ # @macro find__options
61
71
  #
62
72
  # @overload find(options)
63
73
  # @macro options_hash_param
64
74
  # @option options [String] :query string to search for.
75
+ # @macro find__options
65
76
  #
66
- # @return [Array<Audio>] array with audios matching given string. Possibly empty.
67
- # Possibly contains audios without download URL.
68
- def find(arg)
77
+ # @return [Array<Audio>, Array<Playlist>] array with audios or playlists matching given string.
78
+ # Possibly empty. Possibly contains audios or playlists without download URL.
79
+ def find(*args)
69
80
  begin
70
- case arg
71
- when String
72
- query = arg
73
- when Hash
74
- query = arg[:query].to_s
81
+ case
82
+ when (args.size == 1 && String === args[0]) ||
83
+ (args.size == 2 && String === args[0] && Hash === args[1])
84
+ options = args[1] || {}
85
+ query = args[0]
86
+ when args.size == 1 && Hash === args[0]
87
+ options = args[0]
88
+ query = options[:query].to_s
75
89
  else
76
90
  raise
77
91
  end
@@ -79,10 +93,21 @@ module VkMusic
79
93
  raise ArgumentError, "Bad arguments", caller
80
94
  end
81
95
 
96
+ options[:type] ||= :audio
97
+
82
98
  uri = URI(Constants::URL::VK[:audios])
83
- uri.query = Utility.hash_to_params({ "act" => "search", "q" => query.to_s })
84
99
 
85
- audios__from_page(uri)
100
+ case options[:type]
101
+ when :audio
102
+ uri.query = Utility.hash_to_params({ "act" => "search", "q" => query })
103
+ audios__from_page(uri)
104
+ when :playlist
105
+ uri.query = Utility.hash_to_params({ "q" => query, "tab" => "global" })
106
+ urls = playlist_urls__from_page(uri)
107
+ urls.map { |url| playlist(url, up_to: 0, with_url: false) }
108
+ else
109
+ raise ArgumentError, "Bad :type option", caller
110
+ end
86
111
  end
87
112
  alias search find
88
113
 
@@ -130,7 +155,7 @@ module VkMusic
130
155
  raise ArgumentError, "Bad arguments", caller
131
156
  end
132
157
 
133
- options[:up_to] ||= Constants::MAXIMUM_PLAYLIST_SIZE
158
+ options[:up_to] ||= Constants::MAXIMUM_PLAYLIST_SIZE
134
159
  options[:with_url] = true if options[:with_url].nil?
135
160
 
136
161
  if options[:with_url]
@@ -350,8 +375,8 @@ module VkMusic
350
375
  rescue Exception => error
351
376
  raise Exceptions::ParseError, "Unable to get user or group ID. Custom ID: #{str}. Error: #{error.message}", caller
352
377
  end
353
- else
354
- raise Exceptions::ParseError, "Unable to convert \"#{str}\" into ID", caller
378
+ else
379
+ raise Exceptions::ParseError, "Unable to convert \"#{str}\" into ID", caller
355
380
  end
356
381
  id
357
382
  end
@@ -565,9 +590,9 @@ module VkMusic
565
590
  footer_node = first_page.at_css(".audioPlaylist__footer")
566
591
  if footer_node
567
592
  footer_match = footer_node.text.strip.match(/^\d+/)
568
- playlist_size = footer_match ? footer_match[0].to_i : 0
593
+ real_size = footer_match ? footer_match[0].to_i : 0
569
594
  else
570
- playlist_size = 0
595
+ real_size = 0
571
596
  end
572
597
  rescue Exception => error
573
598
  raise Exceptions::ParseError, error.message, caller
@@ -577,7 +602,7 @@ module VkMusic
577
602
  first_page_audios = audios__from_page(first_page)
578
603
 
579
604
  # Check whether need to make additional requests
580
- options[:up_to] = playlist_size if (options[:up_to] < 0 || options[:up_to] > playlist_size)
605
+ options[:up_to] = real_size if (options[:up_to] < 0 || options[:up_to] > real_size)
581
606
  list = first_page_audios[0, options[:up_to]]
582
607
  while list.length < options[:up_to] do
583
608
  playlist_page = load__page__playlist(owner_id, playlist_id, access_hash, offset: list.length)
@@ -590,6 +615,7 @@ module VkMusic
590
615
  :access_hash => access_hash,
591
616
  :title => title,
592
617
  :subtitle => subtitle,
618
+ :real_size => real_size
593
619
  })
594
620
  end
595
621
 
@@ -608,8 +634,8 @@ module VkMusic
608
634
  raise Exceptions::ParseError, error.message, caller
609
635
  end
610
636
 
611
- total_count = first_data["totalCount"]
612
- options[:up_to] = total_count if (options[:up_to] < 0 || options[:up_to] > total_count)
637
+ real_size = first_data["totalCount"]
638
+ options[:up_to] = real_size if (options[:up_to] < 0 || options[:up_to] > real_size)
613
639
  list = first_data_audios[0, options[:up_to]]
614
640
  while list.length < options[:up_to] do
615
641
  json = load__json__playlist_section(owner_id, playlist_id, access_hash,
@@ -625,9 +651,20 @@ module VkMusic
625
651
  :access_hash => first_data["access_hash"],
626
652
  :title => CGI.unescapeHTML(first_data["title"].to_s),
627
653
  :subtitle => CGI.unescapeHTML(first_data["subtitle"].to_s),
654
+ :real_size => real_size
628
655
  })
629
656
  end
630
657
 
658
+ # Found playlist on *global* search page
659
+ def playlist_urls__from_page(obj)
660
+ page = obj.class == Mechanize::Page ? obj : load__page(obj)
661
+ begin
662
+ page.css(".AudioSerp__foundGlobal .AudioPlaylistSlider .al_playlist").map { |elem| elem.attribute("href").to_s }
663
+ rescue Exception => error
664
+ raise Exceptions::ParseError, error.message, caller
665
+ end
666
+ end
667
+
631
668
  # Load audios from wall using JSON request.
632
669
  def wall__json(owner_id, post_id, options)
633
670
  if options[:up_to] < 0 || options[:up_to] > 91
@@ -24,7 +24,8 @@ module VkMusic
24
24
  login: "https://m.vk.com/login",
25
25
  login_action: "https://login.vk.com",
26
26
  wall: "https://m.vk.com/wall",
27
- audio_unavailable: "https://m.vk.com/mp3/audio_api_unavailable.mp3"
27
+ audio_unavailable: "https://m.vk.com/mp3/audio_api_unavailable.mp3",
28
+ profile_audios: "https://m.vk.com/audios",
28
29
  }
29
30
 
30
31
  end
@@ -63,7 +64,7 @@ module VkMusic
63
64
 
64
65
  ##
65
66
  # Playlist URL regular expression.
66
- VK_PLAYLIST_URL_POSTFIX = /.*audio_playlist(-?\d+)_(\d+)(?:(?:(?:&access_hash=)|\/|%2F)([\da-z]+))?/
67
+ VK_PLAYLIST_URL_POSTFIX = /.*audio_playlist(-?\d+)_(\d+)(?:(?:(?:.*(?=&access_hash=)&access_hash=)|\/|%2F)([\da-z]+))?/
67
68
 
68
69
  ##
69
70
  # Post URL regular expression #1.
@@ -24,11 +24,17 @@ module VkMusic
24
24
  ##
25
25
  # @return [String, nil] playlist subtitle. May be empty.
26
26
  attr_reader :subtitle
27
+
28
+ ##
29
+ # @return [Integer, nil] real size of playlist or +nil+ if unknown.
30
+ attr_reader :real_size
27
31
 
28
32
  ##
29
33
  # @return [String] playlist description in Russian.
30
34
  def to_s
31
- (@subtitle ? "#{@subtitle} - " : "") + "#{@title} (#{self.length} аудиозаписей)"
35
+ (@subtitle && !@subtitle.empty? ? "#{@subtitle} - " : "") +
36
+ @title +
37
+ (@real_size ? "(#{self.length} из #{@real_size} аудиозаписей загружено)" : " (#{self.length} аудиозаписей)")
32
38
  end
33
39
 
34
40
  ##
@@ -77,11 +83,12 @@ module VkMusic
77
83
  #
78
84
  # @param list [Array] list of audios in playlist.
79
85
  #
80
- # @option options [Integer] :id
81
- # @option options [Integer] :owner_id
82
- # @option options [String] :access_hash
86
+ # @option options [Integer, nil] :id
87
+ # @option options [Integer, nil] :owner_id
88
+ # @option options [String, nil] :access_hash
83
89
  # @option options [String] :title
84
- # @option options [String] :subtitle
90
+ # @option options [String, nil] :subtitle
91
+ # @option options [Integer, nil] :real_size
85
92
  def initialize(list, options = {})
86
93
  raise ArgumentError, "Bad arguments", caller unless list.class == Array
87
94
  # Saving list
@@ -93,6 +100,7 @@ module VkMusic
93
100
  @access_hash = Utility.unless_nil_to String, options[:access_hash]
94
101
  @title = options[:title].to_s
95
102
  @subtitle = Utility.unless_nil_to String, options[:subtitle]
103
+ @real_size = Utility.unless_nil_to Integer, options[:real_size]
96
104
  end
97
105
 
98
106
  end
@@ -39,8 +39,8 @@ module VkMusic
39
39
  :post
40
40
  when Constants::Regex::VK_URL
41
41
  :audios
42
- else
43
- :find
42
+ else
43
+ :find
44
44
  end
45
45
  end
46
46
 
@@ -36,8 +36,20 @@ class TestVkMusic < MiniTest::Test
36
36
 
37
37
  def test_find_bad_arg
38
38
  assert_raises(ArgumentError) do
39
- CLIENT.search("Good music", query: "or not")
39
+ CLIENT.search("Good music", "or not")
40
40
  end
41
41
  end
42
+
43
+ def test_find_playlist
44
+ results = CLIENT.find("OST", type: :playlist)
45
+ refute_empty(results, "There must be lot of playlists")
46
+ assert_empty(results[0], "Album must be empty")
47
+ refute_equal(0, results[0].real_size, "Album must actually have some audios")
48
+ end
49
+
50
+ def test_find_unexisting_playlist
51
+ results = CLIENT.find("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", type: :playlist)
52
+ assert_empty(results, "There must be no results for such query")
53
+ end
42
54
 
43
55
  end
@@ -18,6 +18,12 @@ class TestVkMusic < MiniTest::Test
18
18
  refute_empty(pl[-1].url, "Audio must have download url")
19
19
  end
20
20
 
21
+ def test_big_url
22
+ pl = CLIENT.playlist("https://m.vk.com/audio?act=audio_playlist256492540_83617715&from=search_owned_playlist&access_hash=b8d408241bcfb60583&back_url=%2Faudios-39786657%3Fq%3Dmashup%26tab%3Downed&back_hash=76ef9186ac6f248a27")
23
+ refute_empty(pl, "This playlist must not be empty")
24
+ assert_instance_of(VkMusic::Audio, pl[0], "Playlist members must be of class Audio")
25
+ end
26
+
21
27
  def test_playlist_small_with_options
22
28
  pl = CLIENT.playlist(owner_id: -37661843, playlist_id: 1, access_hash: "0e420c32c8b69e6637", with_url: false)
23
29
  refute_empty(pl, "This playlist must not be empty")
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
2
2
  s.name = "vk_music"
3
3
  s.summary = "Provides interface to work with VK music via HTTP requests"
4
4
  s.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."
5
- s.version = "2.0.0"
5
+ s.version = "2.1.0"
6
6
  s.author = "Kuznetsov Vladislav"
7
7
  s.email = "fizvlad@mail.ru"
8
8
  s.homepage = "https://github.com/fizvlad/vk-music-rb"
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: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kuznetsov Vladislav
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-08 00:00:00.000000000 Z
11
+ date: 2019-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mechanize