Skip to content

Commit 36c27fb

Browse files
committed
Add examples
1 parent c47127f commit 36c27fb

2 files changed

Lines changed: 274 additions & 0 deletions

File tree

examples/player/main.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import os
2+
import platform
3+
import re
4+
import subprocess
5+
import time
6+
7+
import requests
8+
9+
from librespot.audio.decoders import AudioQuality, VorbisOnlyAudioQuality
10+
from librespot.core import Session
11+
from librespot.metadata import TrackId
12+
13+
quality: AudioQuality = AudioQuality.VERY_HIGH
14+
session: Session = None
15+
16+
17+
def clear():
18+
if platform.system() == "Windows":
19+
os.system("cls")
20+
else:
21+
os.system("clear")
22+
23+
24+
def client():
25+
global quality, session
26+
while True:
27+
clear()
28+
splash()
29+
cmd = input("Player >>> ")
30+
args = cmd.split(" ")
31+
if args[0] == "exit" or args[0] == "quit":
32+
return
33+
if (args[0] == "p" or args[0] == "play") and len(args) == 2:
34+
track_uri_search = re.search(
35+
r"^spotify:track:(?P<TrackID>[0-9a-zA-Z]{22})$", args[1])
36+
track_url_search = re.search(
37+
r"^(https?://)?open\.spotify\.com/track/(?P<TrackID>[0-9a-zA-Z]{22})(\?si=.+?)?$",
38+
args[1],
39+
)
40+
if track_uri_search is not None or track_url_search is not None:
41+
track_id_str = (track_uri_search
42+
if track_uri_search is not None else
43+
track_url_search).group("TrackID")
44+
play(track_id_str)
45+
wait()
46+
if args[0] == "q" or args[0] == "quality":
47+
if len(args) == 1:
48+
print("Current Quality: " + quality.name)
49+
wait()
50+
elif len(args) == 2:
51+
if args[1] == "normal" or args[1] == "96":
52+
quality = AudioQuality.NORMAL
53+
elif args[1] == "high" or args[1] == "160":
54+
quality = AudioQuality.HIGH
55+
elif args[1] == "veryhigh" or args[1] == "320":
56+
quality = AudioQuality.VERY_HIGH
57+
print("Set Quality to %s" % quality.name)
58+
wait()
59+
if (args[0] == "s" or args[0] == "search") and len(args) >= 2:
60+
token = session.tokens().get("user-read-email")
61+
resp = requests.get(
62+
"https://api.spotify.com/v1/search",
63+
{
64+
"limit": "5",
65+
"offset": "0",
66+
"q": cmd[2:],
67+
"type": "track"
68+
},
69+
headers={"Authorization": "Bearer %s" % token},
70+
)
71+
i = 1
72+
tracks = resp.json()["tracks"]["items"]
73+
for track in tracks:
74+
print("%d, %s | %s" % (
75+
i,
76+
track["name"],
77+
",".join([artist["name"] for artist in track["artists"]]),
78+
))
79+
i += 1
80+
position = -1
81+
while True:
82+
num_str = input("Select [1-5]: ")
83+
if num_str == "exit" or num_str == "quit":
84+
return
85+
try:
86+
num = int(num_str)
87+
except ValueError:
88+
continue
89+
if num in range(1, 5, 1):
90+
position = num - 1
91+
break
92+
play(tracks[position]["id"])
93+
wait()
94+
95+
96+
def login():
97+
global session
98+
99+
if os.path.isfile("credentials.json"):
100+
try:
101+
session = Session.Builder().stored_file().create()
102+
return
103+
except RuntimeError:
104+
pass
105+
while True:
106+
user_name = input("UserName: ")
107+
password = input("Password: ")
108+
try:
109+
session = Session.Builder().user_pass(user_name, password).create()
110+
return
111+
except RuntimeError:
112+
pass
113+
114+
115+
def play(track_id_str: str):
116+
track_id = TrackId.from_base62(track_id_str)
117+
stream = session.content_feeder().load(track_id,
118+
VorbisOnlyAudioQuality(quality),
119+
False, None)
120+
ffplay = subprocess.Popen(
121+
["ffplay", "-"],
122+
stdin=subprocess.PIPE,
123+
stdout=subprocess.DEVNULL,
124+
stderr=subprocess.DEVNULL,
125+
)
126+
while True:
127+
byte = stream.input_stream.stream().read()
128+
if byte == -1:
129+
return
130+
ffplay.stdin.write(bytes([byte]))
131+
132+
133+
def splash():
134+
print("=================================\n"
135+
"| Librespot-Python Player |\n"
136+
"| |\n"
137+
"| by kokarare1212 |\n"
138+
"=================================\n\n\n")
139+
140+
141+
def main():
142+
login()
143+
client()
144+
145+
146+
def wait(seconds: int = 3):
147+
for i in range(seconds)[::-1]:
148+
print("\rWait for %d second(s)..." % (i + 1), end="")
149+
time.sleep(1)
150+
151+
152+
if __name__ == "__main__":
153+
main()

examples/server/main.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import os
2+
import re
3+
import socket
4+
import threading
5+
6+
from librespot.audio.decoders import AudioQuality, VorbisOnlyAudioQuality
7+
from librespot.core import Session
8+
from librespot.metadata import TrackId
9+
10+
session: Session
11+
sock: socket
12+
13+
14+
def handler(client: socket.socket, address: str):
15+
req_raw = client.recv(1024 * 1024)
16+
if len(req_raw) == 0:
17+
return
18+
req_arr = req_raw.split(b"\r\n")
19+
req_http_raw = req_arr[0]
20+
req_header_str = req_raw.split(b"\r\n\r\n")[0]
21+
req_body_str = req_raw.split(b"\r\n\r\n")[1]
22+
req_http_arr = req_http_raw.split(b" ")
23+
req_method = req_http_arr[0]
24+
req_uri = req_http_arr[1]
25+
req_http_version = req_http_arr[2]
26+
req_header = {}
27+
for header in req_header_str.split(b"\r\n"):
28+
try:
29+
key, value = header.split(b": ")
30+
except ValueError:
31+
continue
32+
else:
33+
req_header[key.decode().lower()] = value.decode()
34+
status, headers, content, manually = response(client, req_uri.decode(),
35+
req_header, req_body_str)
36+
if not manually:
37+
client.send(req_http_version + b" " + status.encode() + b"\r\n")
38+
client.send(b"Access-Control-Allow-Origin: *\r\n")
39+
for header in headers:
40+
client.send(header.encode() + "\r\n")
41+
client.send(b"\r\n")
42+
client.send(content)
43+
client.close()
44+
45+
46+
class HttpCode:
47+
http_200 = "200 OK"
48+
http_204 = "204 No Content"
49+
http_400 = "400 Bad Request"
50+
http_403 = "403 Forbidden"
51+
http_404 = "404 Not Found"
52+
http_500 = "500 Internal Server Error"
53+
54+
55+
def main():
56+
global session, sock
57+
session = None
58+
if os.path.isfile("credentials.json"):
59+
try:
60+
session = Session.Builder().stored_file().create()
61+
except RuntimeError:
62+
pass
63+
if session is None or not session.is_valid():
64+
username = input("Username: ")
65+
password = input("Password: ")
66+
session = Session.Builder().user_pass(username, password).create()
67+
if not session.is_valid():
68+
return
69+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
70+
sock.bind(("127.0.0.1", 8080))
71+
sock.listen(5)
72+
while True:
73+
threading.Thread(target=handler, args=sock.accept()).start()
74+
75+
76+
def response(client: socket.socket, uri: str, header: dict,
77+
body: bytes) -> tuple[str, list, bytes, bool]:
78+
if re.search(r"^/audio/track/([0-9a-zA-Z]{22})$", uri) is not None:
79+
track_id_search = re.search(
80+
r"^/audio/track/(?P<TrackID>[0-9a-zA-Z]{22})$", uri)
81+
track_id_str = track_id_search.group("TrackID")
82+
track_id = TrackId.from_base62(track_id_str)
83+
stream = session.content_feeder().load(
84+
track_id, VorbisOnlyAudioQuality(AudioQuality.VERY_HIGH), False,
85+
None)
86+
start = 0
87+
end = stream.input_stream.stream().size()
88+
if header.get("range") is not None:
89+
range_search = re.search(
90+
"^bytes=(?P<start>[0-9]+?)-(?P<end>[0-9]+?)$",
91+
header.get("range"))
92+
if range_search is not None:
93+
start = int(range_search.group("start"))
94+
end = (int(range_search.group("end"))
95+
if int(range_search.group("end")) <=
96+
stream.input_stream.stream().size() else
97+
stream.input_stream.stream().size())
98+
stream.input_stream.stream().skip(start)
99+
client.send(b"HTTP/1.0 200 OK\r\n")
100+
client.send(b"Access-Control-Allow-Origin: *\r\n")
101+
client.send(b"Content-Length: " +
102+
(str(stream.input_stream.stream().size()).encode() if
103+
stream.input_stream.stream().size() == end else "{}-{}/{}"
104+
.format(start, end,
105+
stream.input_stream.stream().size()).encode()) +
106+
b"\r\n")
107+
client.send(b"Content-Type: audio/ogg\r\n")
108+
client.send(b"\r\n")
109+
while True:
110+
if (stream.input_stream.stream().pos() >=
111+
stream.input_stream.stream().size()):
112+
break
113+
byte = stream.input_stream.stream().read()
114+
client.send(bytes([byte]))
115+
return "", [], b"", True
116+
else:
117+
return HttpCode.http_404, [], HttpCode.http_404.encode(), False
118+
119+
120+
if __name__ == "__main__":
121+
main()

0 commit comments

Comments
 (0)