vkpymusic 1.0.0__tar.gz
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.
- vkpymusic-1.0.0/LICENSE +21 -0
- vkpymusic-1.0.0/MANIFEST.in +1 -0
- vkpymusic-1.0.0/PKG-INFO +89 -0
- vkpymusic-1.0.0/README.md +67 -0
- vkpymusic-1.0.0/requirements.txt +1 -0
- vkpymusic-1.0.0/setup.cfg +4 -0
- vkpymusic-1.0.0/setup.py +29 -0
- vkpymusic-1.0.0/vkpymusic/Client.py +14 -0
- vkpymusic-1.0.0/vkpymusic/Music.py +42 -0
- vkpymusic-1.0.0/vkpymusic/MusicService.py +261 -0
- vkpymusic-1.0.0/vkpymusic/TokenReceiver.py +158 -0
- vkpymusic-1.0.0/vkpymusic/__init__.py +4 -0
- vkpymusic-1.0.0/vkpymusic.egg-info/PKG-INFO +89 -0
- vkpymusic-1.0.0/vkpymusic.egg-info/SOURCES.txt +15 -0
- vkpymusic-1.0.0/vkpymusic.egg-info/dependency_links.txt +1 -0
- vkpymusic-1.0.0/vkpymusic.egg-info/requires.txt +1 -0
- vkpymusic-1.0.0/vkpymusic.egg-info/top_level.txt +1 -0
vkpymusic-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 EDEXADE
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include LICENSE requirements.txt
|
vkpymusic-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: vkpymusic
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A short description of your library
|
|
5
|
+
Home-page: https://github.com/issamansur/vkpymusic
|
|
6
|
+
Author: Issa Mansur (EDEXADE)
|
|
7
|
+
Author-email: issa_mansur@mail.ru
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: vk music python downloader api
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
|
|
21
|
+
# Description
|
|
22
|
+
## VKpyMusic
|
|
23
|
+
### is a Python library that provides a simple interface for interacting with the VKontakte (VK) music service API. The library allows developers to easily perform operations related to music and other functionalities available through the VK API.
|
|
24
|
+
|
|
25
|
+
# Installation
|
|
26
|
+
### You can install VKpyMusic using the pip package manager. Open your command prompt or terminal and execute the following command:
|
|
27
|
+
|
|
28
|
+
### Console:
|
|
29
|
+
```
|
|
30
|
+
pip install vkpymusic
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
# Usage
|
|
34
|
+
### To get started with VKpyMusic, you will need a valid VK access token and user agent, which provides access to the VK music service API. But if you don't have them, it's okay - we have our own class to get it.
|
|
35
|
+
|
|
36
|
+
## Example usage of VKpyMusic for receive token and user agent:
|
|
37
|
+
### Python:
|
|
38
|
+
```
|
|
39
|
+
from vkpymusic import TokenReceiver
|
|
40
|
+
|
|
41
|
+
login = input(" Enter login: ")
|
|
42
|
+
password = input("Enter password: ")
|
|
43
|
+
|
|
44
|
+
tokenReceiver = TokenReceiver(login, password)
|
|
45
|
+
|
|
46
|
+
if tokenReceiver.auth():
|
|
47
|
+
tokenReceiver.get_token()
|
|
48
|
+
tokenReceiver.save_to_config()
|
|
49
|
+
```
|
|
50
|
+
## Create an Service instance with your access token and user agent:
|
|
51
|
+
### Python:
|
|
52
|
+
```
|
|
53
|
+
from vkpymusic.MusicService import Service
|
|
54
|
+
|
|
55
|
+
service = Service.parse_config()
|
|
56
|
+
```
|
|
57
|
+
## Or you can do like this
|
|
58
|
+
### Python:
|
|
59
|
+
```
|
|
60
|
+
service = Service("<your_token>", "<your_client>")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Get information about the current user
|
|
64
|
+
### Python:
|
|
65
|
+
```
|
|
66
|
+
user_songs = service.get_songs_by_userid(7);
|
|
67
|
+
print(user_info)
|
|
68
|
+
```
|
|
69
|
+
# Search for tracks by query
|
|
70
|
+
### Python:
|
|
71
|
+
```
|
|
72
|
+
tracks = service.search('Coldplay')
|
|
73
|
+
print(tracks)
|
|
74
|
+
```
|
|
75
|
+
# Documentation
|
|
76
|
+
### Detailed documentation and usage examples for VKpyMusic can be found on the official project page on GitHub:
|
|
77
|
+
## https://github.com/issamansur/vkpymusic
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Contributions and Support
|
|
81
|
+
### If you have any suggestions for improving VKpyMusic or if you find any issues, please create a new issue on the GitHub project page. We welcome your pull requests and are here to assist you with any problems you encounter.
|
|
82
|
+
|
|
83
|
+
# License
|
|
84
|
+
### VKpyMusic is distributed under the MIT license. For detailed information about the license, see the LICENSE file.
|
|
85
|
+
|
|
86
|
+
# Authors
|
|
87
|
+
### VKpyMusic is developed by the @issamansur or/and 'EDEXADE, inc.' development team.
|
|
88
|
+
|
|
89
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Description
|
|
2
|
+
## VKpyMusic
|
|
3
|
+
### is a Python library that provides a simple interface for interacting with the VKontakte (VK) music service API. The library allows developers to easily perform operations related to music and other functionalities available through the VK API.
|
|
4
|
+
|
|
5
|
+
# Installation
|
|
6
|
+
### You can install VKpyMusic using the pip package manager. Open your command prompt or terminal and execute the following command:
|
|
7
|
+
|
|
8
|
+
### Console:
|
|
9
|
+
```
|
|
10
|
+
pip install vkpymusic
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
# Usage
|
|
14
|
+
### To get started with VKpyMusic, you will need a valid VK access token and user agent, which provides access to the VK music service API. But if you don't have them, it's okay - we have our own class to get it.
|
|
15
|
+
|
|
16
|
+
## Example usage of VKpyMusic for receive token and user agent:
|
|
17
|
+
### Python:
|
|
18
|
+
```
|
|
19
|
+
from vkpymusic import TokenReceiver
|
|
20
|
+
|
|
21
|
+
login = input(" Enter login: ")
|
|
22
|
+
password = input("Enter password: ")
|
|
23
|
+
|
|
24
|
+
tokenReceiver = TokenReceiver(login, password)
|
|
25
|
+
|
|
26
|
+
if tokenReceiver.auth():
|
|
27
|
+
tokenReceiver.get_token()
|
|
28
|
+
tokenReceiver.save_to_config()
|
|
29
|
+
```
|
|
30
|
+
## Create an Service instance with your access token and user agent:
|
|
31
|
+
### Python:
|
|
32
|
+
```
|
|
33
|
+
from vkpymusic.MusicService import Service
|
|
34
|
+
|
|
35
|
+
service = Service.parse_config()
|
|
36
|
+
```
|
|
37
|
+
## Or you can do like this
|
|
38
|
+
### Python:
|
|
39
|
+
```
|
|
40
|
+
service = Service("<your_token>", "<your_client>")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Get information about the current user
|
|
44
|
+
### Python:
|
|
45
|
+
```
|
|
46
|
+
user_songs = service.get_songs_by_userid(7);
|
|
47
|
+
print(user_info)
|
|
48
|
+
```
|
|
49
|
+
# Search for tracks by query
|
|
50
|
+
### Python:
|
|
51
|
+
```
|
|
52
|
+
tracks = service.search('Coldplay')
|
|
53
|
+
print(tracks)
|
|
54
|
+
```
|
|
55
|
+
# Documentation
|
|
56
|
+
### Detailed documentation and usage examples for VKpyMusic can be found on the official project page on GitHub:
|
|
57
|
+
## https://github.com/issamansur/vkpymusic
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Contributions and Support
|
|
61
|
+
### If you have any suggestions for improving VKpyMusic or if you find any issues, please create a new issue on the GitHub project page. We welcome your pull requests and are here to assist you with any problems you encounter.
|
|
62
|
+
|
|
63
|
+
# License
|
|
64
|
+
### VKpyMusic is distributed under the MIT license. For detailed information about the license, see the LICENSE file.
|
|
65
|
+
|
|
66
|
+
# Authors
|
|
67
|
+
### VKpyMusic is developed by the @issamansur or/and 'EDEXADE, inc.' development team.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests==2.31.0
|
vkpymusic-1.0.0/setup.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="vkpymusic",
|
|
8
|
+
version="1.0.0",
|
|
9
|
+
description="A short description of your library",
|
|
10
|
+
long_description=long_description,
|
|
11
|
+
long_description_content_type="text/markdown",
|
|
12
|
+
license="MIT",
|
|
13
|
+
keywords="vk music python downloader api",
|
|
14
|
+
author="Issa Mansur (EDEXADE)",
|
|
15
|
+
author_email="issa_mansur@mail.ru",
|
|
16
|
+
url="https://github.com/issamansur/vkpymusic",
|
|
17
|
+
download_url="",
|
|
18
|
+
packages=find_packages(),
|
|
19
|
+
classifiers=[
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.6",
|
|
23
|
+
"Programming Language :: Python :: 3.7",
|
|
24
|
+
"Programming Language :: Python :: 3.8",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
],
|
|
28
|
+
install_requires=["requests==2.31.0"],
|
|
29
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class Client:
|
|
2
|
+
def __init__(self, user_agent, client_id, client_secret):
|
|
3
|
+
self.user_agent = user_agent
|
|
4
|
+
self.client_id = client_id
|
|
5
|
+
self.client_secret = client_secret
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
KateMobile = Client(
|
|
9
|
+
user_agent='KateMobileAndroid/56 lite-460 (Android 4.4.2; SDK 19; x86; unknown Android SDK built for x86; en)',
|
|
10
|
+
client_id='2685278',
|
|
11
|
+
client_secret='lxhD8OD7dMsqtXIm5IUY'
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
clients = {'Kate': KateMobile}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Music:
|
|
5
|
+
def __init__(self, title, artist, duration, track_id, owner_id, url=""):
|
|
6
|
+
self.title = title
|
|
7
|
+
self.artist = artist
|
|
8
|
+
self.duration = duration
|
|
9
|
+
self.track_id = track_id
|
|
10
|
+
self.owner_id = owner_id
|
|
11
|
+
self.url = url
|
|
12
|
+
|
|
13
|
+
def __str__(self):
|
|
14
|
+
return f"{self.title} - {self.artist}"
|
|
15
|
+
|
|
16
|
+
def to_dict(self) -> dict:
|
|
17
|
+
return self.__dict__
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def safe(cls, music):
|
|
21
|
+
def safe_format(string):
|
|
22
|
+
safe_string = re.sub(r"[^A-zА-я0-9+\s]", "", string)
|
|
23
|
+
return safe_string
|
|
24
|
+
|
|
25
|
+
title = safe_format(music.title)
|
|
26
|
+
artist = safe_format(music.artist)
|
|
27
|
+
safeMusic = cls(
|
|
28
|
+
title, artist, music.duration, music.track_id, music.owner_id, music.url
|
|
29
|
+
)
|
|
30
|
+
return safeMusic
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def from_json(cls, item):
|
|
34
|
+
title = str(item["title"])
|
|
35
|
+
artist = str(item["artist"])
|
|
36
|
+
duration = int(item["duration"])
|
|
37
|
+
track_id = str(item["id"])
|
|
38
|
+
owner_id = str(item["owner_id"])
|
|
39
|
+
url = str(item["url"])
|
|
40
|
+
|
|
41
|
+
music = cls(title, artist, duration, track_id, owner_id, url)
|
|
42
|
+
return music
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import os, configparser
|
|
2
|
+
import requests, json
|
|
3
|
+
|
|
4
|
+
from .Music import Music
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def log(message):
|
|
8
|
+
print(f"[vkpymusic -> Service]: {message}")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Service:
|
|
12
|
+
def __init__(self, user_agent: str, token: str):
|
|
13
|
+
self.user_agent = user_agent
|
|
14
|
+
self.__token = token
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def parse_config(cls, filename: str = "config_vk.ini"):
|
|
18
|
+
"""
|
|
19
|
+
Create an instance of Service from config.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
filename (str): Filename of config (default value = "config_vk.ini").
|
|
23
|
+
"""
|
|
24
|
+
dirname = os.path.dirname(__file__)
|
|
25
|
+
configfile_path = os.path.join(dirname, filename)
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
config = configparser.ConfigParser()
|
|
29
|
+
config.read(configfile_path, encoding="utf-8")
|
|
30
|
+
|
|
31
|
+
user_agent = config["VK"]["user_agent"]
|
|
32
|
+
token = config["VK"]["token_for_audio"]
|
|
33
|
+
|
|
34
|
+
return Service(user_agent, token)
|
|
35
|
+
except Exception as e:
|
|
36
|
+
log(f"ERROR in parse_config() -> {e}")
|
|
37
|
+
|
|
38
|
+
# GET_AUDIOS_BY_TEXT
|
|
39
|
+
|
|
40
|
+
def __get_response_for_search_by_text(
|
|
41
|
+
self, text: str, count: int
|
|
42
|
+
) -> requests.Response:
|
|
43
|
+
session = requests.session()
|
|
44
|
+
session.headers.update({"User-Agent": self.user_agent})
|
|
45
|
+
response = session.post(
|
|
46
|
+
"https://api.vk.com/method/audio.search",
|
|
47
|
+
data=[
|
|
48
|
+
("access_token", self.__token),
|
|
49
|
+
("https", 1),
|
|
50
|
+
("lang", "ru"),
|
|
51
|
+
("extended", 1),
|
|
52
|
+
("v", "5.131"),
|
|
53
|
+
("q", text),
|
|
54
|
+
("autocomplete", 1),
|
|
55
|
+
("sort", 0),
|
|
56
|
+
("count", count),
|
|
57
|
+
],
|
|
58
|
+
)
|
|
59
|
+
session.close()
|
|
60
|
+
return response
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def __get_musics_from_response(response: requests.Response) -> list[Music]:
|
|
64
|
+
response = json.loads(response.content.decode("utf-8"))
|
|
65
|
+
try:
|
|
66
|
+
items = response["response"]["items"]
|
|
67
|
+
except Exception as e:
|
|
68
|
+
raise Exception(f"ERROR in get_musics_from_response() -> {e}")
|
|
69
|
+
|
|
70
|
+
musics: list[Music] = []
|
|
71
|
+
for item in items:
|
|
72
|
+
music = Music.from_json(item)
|
|
73
|
+
musics.append(music)
|
|
74
|
+
return musics
|
|
75
|
+
|
|
76
|
+
def get_songs_by_text(self, text: str, count: int = 3) -> list[Music]:
|
|
77
|
+
"""
|
|
78
|
+
Search songs by query.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
text (str): Text of query. Can be title of song or author, etc.
|
|
82
|
+
count (int): Count of results (default value = 3 songs).
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
list[Music]: List of founded songs. Len(list) <= count.
|
|
86
|
+
"""
|
|
87
|
+
log(f'Request by text: "{text}" в количестве {count}')
|
|
88
|
+
response = self.__get_response_for_search_by_text(text, count)
|
|
89
|
+
try:
|
|
90
|
+
musics = self.__get_musics_from_response(response)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
log(f"ERROR in get_songs_by_text() / search() -> {e}")
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
if len(musics) == 0:
|
|
96
|
+
log("No results found ._.")
|
|
97
|
+
else:
|
|
98
|
+
log("Results:")
|
|
99
|
+
i = 1
|
|
100
|
+
for music in musics:
|
|
101
|
+
print(f"{i}) {music}")
|
|
102
|
+
i += 1
|
|
103
|
+
return musics
|
|
104
|
+
|
|
105
|
+
def search(self, text: str, count: int = 3) -> list[Music]:
|
|
106
|
+
"""
|
|
107
|
+
Search songs by query. (Same as 'get_songs_by_text()')
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
text (str): Text of query. Can be title of song or author, etc.
|
|
111
|
+
count (int): Count of results (default value = 3 songs).
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
list[Music]: List of founded songs. Len(list) <= count.
|
|
115
|
+
"""
|
|
116
|
+
return self.get_songs_by_text(text, count)
|
|
117
|
+
|
|
118
|
+
# GET_AUDIOS_BY_USER_ID
|
|
119
|
+
|
|
120
|
+
def __get_response_by_userid(
|
|
121
|
+
self, user_id: str or int, count: int, offset: int
|
|
122
|
+
) -> requests.Response:
|
|
123
|
+
session = requests.session()
|
|
124
|
+
session.headers.update({"User-Agent": self.user_agent})
|
|
125
|
+
response = session.post(
|
|
126
|
+
"https://api.vk.com/method/audio.get",
|
|
127
|
+
data=[
|
|
128
|
+
("access_token", self.__token),
|
|
129
|
+
("https", 1),
|
|
130
|
+
("lang", "ru"),
|
|
131
|
+
("extended", 1),
|
|
132
|
+
("v", "5.131"),
|
|
133
|
+
("owner_id", user_id),
|
|
134
|
+
("count", count),
|
|
135
|
+
("offset", offset),
|
|
136
|
+
],
|
|
137
|
+
)
|
|
138
|
+
session.close()
|
|
139
|
+
return response
|
|
140
|
+
|
|
141
|
+
def get_songs_by_userid(
|
|
142
|
+
self, user_id: str or int, count: int = 100, offset: int = 0
|
|
143
|
+
) -> list[Music]:
|
|
144
|
+
"""
|
|
145
|
+
Search songs by id (of user VK).
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
user_id (str or int): id of user VK. NOT USERNAME! ID after vk.com/id*******
|
|
149
|
+
count (int): Count of results (default value = 100 songs (MAX)).
|
|
150
|
+
offset (int): Set offset of results/ For example, if u need 101-200 -> count = 100, offset = 100.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
list[Music]: List of founded songs. Len(list) <= count.
|
|
154
|
+
"""
|
|
155
|
+
user_id = int(user_id)
|
|
156
|
+
print(f"Request by user: {user_id}")
|
|
157
|
+
response = self.__get_response_by_userid(user_id, count, offset)
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
musics = self.__get_musics_from_response(response[0])
|
|
161
|
+
except Exception as e:
|
|
162
|
+
log(f"ERROR in get_songs_by_userid() -> {e}")
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
if len(musics) == 0:
|
|
166
|
+
log("No results found ._.")
|
|
167
|
+
else:
|
|
168
|
+
log("Results:")
|
|
169
|
+
i = 1
|
|
170
|
+
for music in musics:
|
|
171
|
+
print(f"{i}) {music}")
|
|
172
|
+
i += 1
|
|
173
|
+
return musics
|
|
174
|
+
|
|
175
|
+
# GET_COUNT
|
|
176
|
+
|
|
177
|
+
def __get_response_for_count(self, user_id: str or int) -> requests.Response:
|
|
178
|
+
session = requests.session()
|
|
179
|
+
session.headers.update({"User-Agent": self.user_agent})
|
|
180
|
+
response = session.post(
|
|
181
|
+
"https://api.vk.com/method/audio.getCount",
|
|
182
|
+
data=[
|
|
183
|
+
("access_token", self.__token),
|
|
184
|
+
("https", 1),
|
|
185
|
+
("lang", "ru"),
|
|
186
|
+
("extended", 1),
|
|
187
|
+
("v", "5.131"),
|
|
188
|
+
("owner_id", user_id),
|
|
189
|
+
],
|
|
190
|
+
)
|
|
191
|
+
return response
|
|
192
|
+
|
|
193
|
+
def get_count_by_user_id(self, user_id: str or int) -> int:
|
|
194
|
+
"""
|
|
195
|
+
Get count of all user's songs.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
user_id (str or int): id of user VK. NOT USERNAME! ID after vk.com/id*******
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
int: count of all user's songs.
|
|
202
|
+
"""
|
|
203
|
+
user_id = int(user_id)
|
|
204
|
+
print(f"Request by user: {user_id}")
|
|
205
|
+
response = self.__get_response_for_count(user_id)
|
|
206
|
+
data = json.loads(response.content.decode("utf-8"))
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
songs_count = int(data["response"])
|
|
210
|
+
except Exception as e:
|
|
211
|
+
log(f"ERROR in get_count_by_user_id() -> {e}")
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
log(f"Count of user's songs: {songs_count}")
|
|
215
|
+
return songs_count
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
def save_music(music: Music) -> str:
|
|
219
|
+
"""
|
|
220
|
+
Save song to '{workDirectory}\\Music\\{songname}.mp3'.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
music (Music): 'Music' object obtained from methods of the 'Service'.
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
str: relative path of downloaded music.
|
|
227
|
+
"""
|
|
228
|
+
music = Music.safe(music)
|
|
229
|
+
file_name_mp3 = f"{music}.mp3"
|
|
230
|
+
url = music.url
|
|
231
|
+
|
|
232
|
+
if url == "":
|
|
233
|
+
log("Url no found")
|
|
234
|
+
return
|
|
235
|
+
|
|
236
|
+
response = requests.get(url=url)
|
|
237
|
+
if response.status_code == 200:
|
|
238
|
+
if not os.path.exists("Music"):
|
|
239
|
+
os.makedirs(f"Music")
|
|
240
|
+
log("Folder 'Music' was created")
|
|
241
|
+
|
|
242
|
+
file_path = os.path.join("Music", file_name_mp3)
|
|
243
|
+
|
|
244
|
+
if not os.path.exists(file_path):
|
|
245
|
+
if "index.m3u8" in url:
|
|
246
|
+
log("ERROR in save_music() -> .m3u8 detected!")
|
|
247
|
+
return
|
|
248
|
+
else:
|
|
249
|
+
log(f"File with name {file_name_mp3} exists. Overwrite it? (Y/n)")
|
|
250
|
+
|
|
251
|
+
res = input().lower()
|
|
252
|
+
if res.lower() != "y" and res.lower() != "yes":
|
|
253
|
+
return
|
|
254
|
+
|
|
255
|
+
response.close()
|
|
256
|
+
log(f"Downloading {music}...")
|
|
257
|
+
with open(file_path, "wb") as output_file:
|
|
258
|
+
output_file.write(response.content)
|
|
259
|
+
|
|
260
|
+
log(f"Success! Music was downloaded in '{file_path}'")
|
|
261
|
+
return file_path
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import os, json, requests
|
|
2
|
+
from .Client import clients
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TokenReceiver:
|
|
6
|
+
def __init__(self, login, password, client="Kate"):
|
|
7
|
+
self.__login = str(login)
|
|
8
|
+
self.__password = str(password)
|
|
9
|
+
|
|
10
|
+
if client in clients:
|
|
11
|
+
self.client = clients[client]
|
|
12
|
+
else:
|
|
13
|
+
self.client = client["Kate"]
|
|
14
|
+
self.__token = None
|
|
15
|
+
|
|
16
|
+
def __request_auth(self, code=None, captcha=None):
|
|
17
|
+
session = requests.session()
|
|
18
|
+
session.headers.update({"User-Agent": self.client.user_agent})
|
|
19
|
+
query_params = [
|
|
20
|
+
("grant_type", "password"),
|
|
21
|
+
("client_id", self.client.client_id),
|
|
22
|
+
("client_secret", self.client.client_secret),
|
|
23
|
+
("username", self.__login),
|
|
24
|
+
("password", self.__password),
|
|
25
|
+
("scope", "audio,offline"),
|
|
26
|
+
("2fa_supported", 1),
|
|
27
|
+
("force_sms", 1),
|
|
28
|
+
("v", 5.131),
|
|
29
|
+
]
|
|
30
|
+
if captcha:
|
|
31
|
+
query_params.append(("captcha_sid", captcha[0]))
|
|
32
|
+
query_params.append(("captcha_key", captcha[1]))
|
|
33
|
+
if code:
|
|
34
|
+
query_params.append(("code", code))
|
|
35
|
+
|
|
36
|
+
request = session.post("https://oauth.vk.com/token", data=query_params)
|
|
37
|
+
session.close()
|
|
38
|
+
return request
|
|
39
|
+
|
|
40
|
+
def __request_code(self, sid):
|
|
41
|
+
session = requests.session()
|
|
42
|
+
session.headers.update({"User-Agent": self.client.user_agent})
|
|
43
|
+
query_params = [("sid", str(sid)), ("v", "5.131")]
|
|
44
|
+
response: requests.Response = session.post(
|
|
45
|
+
"https://api.vk.com/method/auth.validatePhone",
|
|
46
|
+
data=query_params,
|
|
47
|
+
allow_redirects=True,
|
|
48
|
+
)
|
|
49
|
+
session.close()
|
|
50
|
+
|
|
51
|
+
response_json = json.loads(response.content.decode("utf-8"))
|
|
52
|
+
|
|
53
|
+
# right_response_json = {
|
|
54
|
+
# "response": {
|
|
55
|
+
# "type": "general",
|
|
56
|
+
# "sid": {str(sid)},
|
|
57
|
+
# "delay": 60,
|
|
58
|
+
# "libverify_support": False,
|
|
59
|
+
# "validation_type": "sms",
|
|
60
|
+
# "validation_resend": "sms"
|
|
61
|
+
# }
|
|
62
|
+
# }
|
|
63
|
+
|
|
64
|
+
return response_json
|
|
65
|
+
|
|
66
|
+
def auth(self) -> bool:
|
|
67
|
+
"""
|
|
68
|
+
Performs authorization using the available login and password. If necessary, interactively accepts a code from SMS or captcha.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
bool: Boolean value indicating whether authorization was successful or not.
|
|
72
|
+
"""
|
|
73
|
+
response_auth: requests.Response = self.__request_auth()
|
|
74
|
+
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
|
|
75
|
+
|
|
76
|
+
while "error" in response_auth_json:
|
|
77
|
+
error = response_auth_json["error"]
|
|
78
|
+
|
|
79
|
+
if error == "need_captcha":
|
|
80
|
+
captcha_sid: str = response_auth_json["captcha_sid"]
|
|
81
|
+
captcha_img: str = response_auth_json["captcha_img"]
|
|
82
|
+
|
|
83
|
+
print("Are you bot? You need enter captcha")
|
|
84
|
+
os.startfile(captcha_img)
|
|
85
|
+
captcha_key: str = input("Captcha: ")
|
|
86
|
+
response_auth = self.__request_auth(captcha=(captcha_sid, captcha_key))
|
|
87
|
+
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
|
|
88
|
+
|
|
89
|
+
elif error == "need_validation":
|
|
90
|
+
sid = response_auth_json["validation_sid"]
|
|
91
|
+
|
|
92
|
+
# response2: requests.Response =
|
|
93
|
+
self.__request_code(sid)
|
|
94
|
+
|
|
95
|
+
# response2_json = json.loads(response2.content.decode('utf-8'))
|
|
96
|
+
print(
|
|
97
|
+
"SMS with a confirmation code has been sent to your phone! The code is valid for a few minutes!"
|
|
98
|
+
)
|
|
99
|
+
code = input("Code: ")
|
|
100
|
+
response_auth = self.__request_auth(code=code)
|
|
101
|
+
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
|
|
102
|
+
|
|
103
|
+
elif error == "invalid_client":
|
|
104
|
+
print("Неверный логин или пароль")
|
|
105
|
+
return False
|
|
106
|
+
else:
|
|
107
|
+
self.__login
|
|
108
|
+
self.__password
|
|
109
|
+
error(response_auth_json)
|
|
110
|
+
return False
|
|
111
|
+
if "access_token" in response_auth_json:
|
|
112
|
+
access_token = response_auth_json["access_token"]
|
|
113
|
+
print("Токен получен!")
|
|
114
|
+
self.__token = access_token
|
|
115
|
+
return True
|
|
116
|
+
self.__on_error(response_auth_json)
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
def get_token(self):
|
|
120
|
+
"""
|
|
121
|
+
Prints token in console (if authorisation was succesful)
|
|
122
|
+
"""
|
|
123
|
+
token = self.__token
|
|
124
|
+
if not token:
|
|
125
|
+
print('Please, first call the method "auth"')
|
|
126
|
+
return
|
|
127
|
+
print(token)
|
|
128
|
+
|
|
129
|
+
def save_to_config(self):
|
|
130
|
+
"""
|
|
131
|
+
Save token and user agent data in config (if authorisation was succesful).
|
|
132
|
+
"""
|
|
133
|
+
token: str = self.__token
|
|
134
|
+
if not token:
|
|
135
|
+
print('Please, first call the method "auth"')
|
|
136
|
+
return
|
|
137
|
+
if os.path.isfile("config_vk.ini"):
|
|
138
|
+
print('File already exist! Enter "OK" for rewriting it')
|
|
139
|
+
if input().lower() != "ok":
|
|
140
|
+
return
|
|
141
|
+
with open(self.create_path("config_vk.ini"), "w") as output_file:
|
|
142
|
+
output_file.write("[VK]\n")
|
|
143
|
+
output_file.write(f"user_agent={self.client.user_agent}\n")
|
|
144
|
+
output_file.write(f"token_for_audio={token}")
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def create_path(filename: str) -> str:
|
|
148
|
+
dirname = os.path.dirname(__file__)
|
|
149
|
+
path = os.path.join(dirname, filename)
|
|
150
|
+
return path
|
|
151
|
+
|
|
152
|
+
@staticmethod
|
|
153
|
+
def __on_error(response):
|
|
154
|
+
print("Unexpected error! Logs was saved in file - vtm_error.txt")
|
|
155
|
+
print("Please, create an issue in repository for solving this problem")
|
|
156
|
+
with open(TokenReceiver.create_path("vktoken.error.log"), "a") as output_file:
|
|
157
|
+
output_file.write("Error!\n")
|
|
158
|
+
output_file.write(str(response))
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: vkpymusic
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A short description of your library
|
|
5
|
+
Home-page: https://github.com/issamansur/vkpymusic
|
|
6
|
+
Author: Issa Mansur (EDEXADE)
|
|
7
|
+
Author-email: issa_mansur@mail.ru
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: vk music python downloader api
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
|
|
21
|
+
# Description
|
|
22
|
+
## VKpyMusic
|
|
23
|
+
### is a Python library that provides a simple interface for interacting with the VKontakte (VK) music service API. The library allows developers to easily perform operations related to music and other functionalities available through the VK API.
|
|
24
|
+
|
|
25
|
+
# Installation
|
|
26
|
+
### You can install VKpyMusic using the pip package manager. Open your command prompt or terminal and execute the following command:
|
|
27
|
+
|
|
28
|
+
### Console:
|
|
29
|
+
```
|
|
30
|
+
pip install vkpymusic
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
# Usage
|
|
34
|
+
### To get started with VKpyMusic, you will need a valid VK access token and user agent, which provides access to the VK music service API. But if you don't have them, it's okay - we have our own class to get it.
|
|
35
|
+
|
|
36
|
+
## Example usage of VKpyMusic for receive token and user agent:
|
|
37
|
+
### Python:
|
|
38
|
+
```
|
|
39
|
+
from vkpymusic import TokenReceiver
|
|
40
|
+
|
|
41
|
+
login = input(" Enter login: ")
|
|
42
|
+
password = input("Enter password: ")
|
|
43
|
+
|
|
44
|
+
tokenReceiver = TokenReceiver(login, password)
|
|
45
|
+
|
|
46
|
+
if tokenReceiver.auth():
|
|
47
|
+
tokenReceiver.get_token()
|
|
48
|
+
tokenReceiver.save_to_config()
|
|
49
|
+
```
|
|
50
|
+
## Create an Service instance with your access token and user agent:
|
|
51
|
+
### Python:
|
|
52
|
+
```
|
|
53
|
+
from vkpymusic.MusicService import Service
|
|
54
|
+
|
|
55
|
+
service = Service.parse_config()
|
|
56
|
+
```
|
|
57
|
+
## Or you can do like this
|
|
58
|
+
### Python:
|
|
59
|
+
```
|
|
60
|
+
service = Service("<your_token>", "<your_client>")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Get information about the current user
|
|
64
|
+
### Python:
|
|
65
|
+
```
|
|
66
|
+
user_songs = service.get_songs_by_userid(7);
|
|
67
|
+
print(user_info)
|
|
68
|
+
```
|
|
69
|
+
# Search for tracks by query
|
|
70
|
+
### Python:
|
|
71
|
+
```
|
|
72
|
+
tracks = service.search('Coldplay')
|
|
73
|
+
print(tracks)
|
|
74
|
+
```
|
|
75
|
+
# Documentation
|
|
76
|
+
### Detailed documentation and usage examples for VKpyMusic can be found on the official project page on GitHub:
|
|
77
|
+
## https://github.com/issamansur/vkpymusic
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Contributions and Support
|
|
81
|
+
### If you have any suggestions for improving VKpyMusic or if you find any issues, please create a new issue on the GitHub project page. We welcome your pull requests and are here to assist you with any problems you encounter.
|
|
82
|
+
|
|
83
|
+
# License
|
|
84
|
+
### VKpyMusic is distributed under the MIT license. For detailed information about the license, see the LICENSE file.
|
|
85
|
+
|
|
86
|
+
# Authors
|
|
87
|
+
### VKpyMusic is developed by the @issamansur or/and 'EDEXADE, inc.' development team.
|
|
88
|
+
|
|
89
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
requirements.txt
|
|
5
|
+
setup.py
|
|
6
|
+
vkpymusic/Client.py
|
|
7
|
+
vkpymusic/Music.py
|
|
8
|
+
vkpymusic/MusicService.py
|
|
9
|
+
vkpymusic/TokenReceiver.py
|
|
10
|
+
vkpymusic/__init__.py
|
|
11
|
+
vkpymusic.egg-info/PKG-INFO
|
|
12
|
+
vkpymusic.egg-info/SOURCES.txt
|
|
13
|
+
vkpymusic.egg-info/dependency_links.txt
|
|
14
|
+
vkpymusic.egg-info/requires.txt
|
|
15
|
+
vkpymusic.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests==2.31.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vkpymusic
|