· 5 years ago · Nov 07, 2020, 08:24 PM
1import sys
2import sqlite3
3from PyQt5.QtCore import QSize, Qt
4
5from PyQt5 import QtCore
6from PyQt5.QtGui import QPixmap, QIcon, QColor
7from PyQt5.QtMultimedia import QMediaPlayer, QMediaPlaylist
8from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QWidget, QListWidget, QListWidgetItem, QInputDialog, \
9 QDialog, QPushButton, QGraphicsDropShadowEffect, QSlider, QMessageBox
10from PyQt5 import uic, QtMultimedia
11from Main_styles import *
12
13
14class MenuWidget(QWidget): # виджет меню с плейлистами
15 def __init__(self):
16 super().__init__()
17 uic.loadUi('menuUI.ui', self)
18 self.playlists: QListWidget
19 self.playlists.addItem("Все треки")
20 self.playlists.addItem("Понравившиеся")
21
22 self.playlists.itemAt(0, 0).setSelected(True)
23
24 self.playlists.setStyleSheet(PLAYLISTS_STYLES)
25
26 self.close_menu_btn.setIcon(QIcon(QPixmap("icons/back.png")))
27 self.close_menu_btn.setIconSize(QSize(25, 25))
28
29 self.cur_playlist = "Все треки"
30
31
32class TracksSelectionWidget(QWidget):
33 def __init__(self):
34 super().__init__()
35 uic.loadUi('select-tracksUI.ui', self)
36
37
38class Main(QMainWindow):
39 def __init__(self):
40 super().__init__()
41 uic.loadUi('mainUI.ui', self)
42 self.setWindowIcon(QIcon('icons/app-ico.png'))
43 self.setWindowTitle('Я.Музычка с приколами')
44 self.setup_player()
45
46 self.IS_PLAY = False
47 self.was_paused = False
48 self.menu_isopen = False
49 self.DB_NAME = "Tracks.db"
50
51 self.like_btn.installEventFilter(self)
52 self.menu_btn.installEventFilter(self)
53 self.add_new_track_btn.installEventFilter(self)
54 self.delete_cur_track_btn.installEventFilter(self)
55
56 self.play_btn.clicked.connect(self.play_track)
57 self.next_btn.clicked.connect(self.next_track)
58 self.prev_btn.clicked.connect(self.prev_track)
59
60 self.volume_slider.valueChanged.connect(self.change_volume)
61 self.volume_slider.setMaximum(100)
62 self.volume_slider.setMinimum(0)
63 self.volume_slider.setValue(10)
64
65 self.like_btn.clicked.connect(self.like_track)
66
67 self.add_new_track_btn.clicked.connect(self.add_new_track) # add new track into DB
68
69 self.delete_cur_track_btn.clicked.connect(self.delete_cur_track) # delete current track from DB
70
71 self.menu = MenuWidget()
72 self.menu.close_menu_btn.clicked.connect(self.close_menu)
73
74 self.stackedWidget.addWidget(self.menu)
75 self.menu_btn.clicked.connect(self.open_menu)
76 self.menu.close_menu_btn.installEventFilter(self)
77
78 self.menu.create_playlist_btn.clicked.connect(self.create_playlist)
79
80 self.cur_playlist = self.menu.cur_playlist
81 self.menu.playlists.currentItemChanged.connect(self.change_playlist)
82
83 self.playlists = {
84 "Все треки": "Tracks",
85 "Понравившиеся": "Liked"}
86 con = sqlite3.connect(self.DB_NAME)
87 cur = con.cursor()
88 pl_names = cur.execute("SELECT name FROM sqlite_master WHERE type='table';").fetchall()[3:]
89 con.close()
90 for playlist_name in pl_names:
91 playlist_name = playlist_name[0]
92 if playlist_name not in self.playlists:
93 self.menu.playlists.addItem(playlist_name)
94 self.playlists[playlist_name] = playlist_name
95
96 self.apply_styles()
97 self.connect_db()
98 self.update_ui()
99
100 def setup_player(self):
101
102 self.mediaPlayer = QtMultimedia.QMediaPlayer(self)
103 self._buffer = QtCore.QBuffer()
104 self._buffer.close()
105
106 self.mediaPlayer.setVolume(10)
107
108 def connect_db(self):
109
110 con = sqlite3.connect(self.DB_NAME)
111 cur = con.cursor()
112 # TODO берем айди только из текущего плейлиста и ищем треки с таким айди в общем плейлисте
113 # TODO пустой плейлист с понравившейся музыкой, исправть баг
114
115 self.tracks = cur.execute(f"""
116 SELECT *
117 FROM Tracks
118 WHERE id in (SELECT id from {self.playlists[self.cur_playlist]} )
119 """).fetchall()
120
121 self.liked_tracks = cur.execute("""
122 SELECT id
123 FROM Liked
124 """).fetchall()
125 con.close()
126 self.cur_ind = 0
127
128 def update_ui(self):
129
130 self.cur_id, self.cur_artist_name, self.cur_track_name, \
131 self.cur_song_avatar, self.cur_track = self.tracks[self.cur_ind]
132 self.track_name.setText(self.cur_track_name)
133 self.artist_name.setText(self.cur_artist_name)
134
135 if (self.tracks[self.cur_ind][0],) in self.liked_tracks:
136 self.like_btn.setIcon(QIcon(QPixmap("icons/liked.png")))
137 else:
138 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png")))
139
140 # if not self.IS_PLAY:
141 temp = open("temp", "wb")
142 temp.write(self.cur_track)
143 temp = open("temp", "rb")
144
145 self._buffer.close()
146 self._buffer.setData(temp.read())
147 if self._buffer.open(QtCore.QIODevice.ReadOnly):
148 self.mediaPlayer.setMedia(
149 QtMultimedia.QMediaContent(), self._buffer)
150
151 # self.mediaPlayer: QMediaPlayer
152 # self.mediaPlayer.setPlaylist(QMediaPlaylist())
153
154 self.song_avatar.setText(self.cur_song_avatar) # NONE
155 # TODO обложка трека из байтов
156 # self.song_avatar.setPixmap(QPixmap(self.cur_song_avatar))
157
158 def apply_styles(self):
159
160 self.setStyleSheet(MAIN_WINDOW_STYLES)
161 # стили кнопок переключения треков
162 self.play_btn.setStyleSheet(DEFAULT_BTN_STYLES)
163
164 self.next_btn.setStyleSheet(DEFAULT_BTN_STYLES)
165
166 self.prev_btn.setStyleSheet(DEFAULT_BTN_STYLES)
167
168 self.like_btn.setStyleSheet(LIKE_BTN_STYLES)
169
170 self.volume_slider.setStyleSheet(DEFAULT_SLIDER_STYLES)
171
172 # стили для view widget
173 # self.view_window.setStyleSheet(DEFAULT_WIDGET_STYLES)
174
175 self.song_avatar.setStyleSheet(SONG_AVATAR_STYLES)
176
177 self.artist_name.setStyleSheet(ARTIST_NAME_STYLES)
178 self.track_name.setStyleSheet(TRACK_NAME_STYLES)
179
180 # SETTING UP ICONS
181
182 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png"))) # unliked btn icon
183 self.like_btn.setIconSize(QSize(40, 40))
184
185 self.add_new_track_btn.setIcon(QIcon(QPixmap("icons/add.png"))) # add ADD btn icon
186 self.add_new_track_btn.setIconSize(QSize(30, 30))
187
188 self.delete_cur_track_btn.setIcon(QIcon(QPixmap("icons/delete.png"))) # add DELETE btn icon
189 self.delete_cur_track_btn.setIconSize(QSize(30, 30))
190
191 self.menu_btn.setIcon(QIcon(QPixmap("icons/menu.png"))) # add DELETE btn icon
192 self.menu_btn.setIconSize(QSize(40, 40))
193
194 self.stackedWidget.setStyleSheet(STACKED_WIDGET_STYLES)
195 self.page_3.setStyleSheet("""background:transparent""") # прозрачный фон для виджета кнопки меню
196
197 # добавление теней
198
199 shadow = [self.create_shadow() for _ in range(7)]
200
201 self.add_new_track_btn.setGraphicsEffect(shadow[0])
202 self.like_btn.setGraphicsEffect(shadow[1])
203 self.play_btn.setGraphicsEffect(shadow[2])
204 self.next_btn.setGraphicsEffect(shadow[3])
205 self.prev_btn.setGraphicsEffect(shadow[4])
206 self.menu_btn.setGraphicsEffect(shadow[5])
207 self.delete_cur_track_btn.setGraphicsEffect(shadow[6])
208
209 def create_shadow(self):
210 shadow = QGraphicsDropShadowEffect()
211 shadow.setBlurRadius(15)
212 shadow.setOffset(4, 2)
213 c = QColor(0, 0, 0)
214 c.setAlpha(100)
215 shadow.setColor(c)
216 return shadow
217
218 def add_new_track(self):
219
220 fname = QFileDialog.getOpenFileName(self, 'Выбрать трек', '')[0]
221
222 with open(fname, "rb") as track_bytes:
223 track_bytes = track_bytes.read()
224 artist_name = fname.split("/")[-1].split('.mp3')[0].split("-")[0]
225 track_name = fname.split("/")[-1].split('.mp3')[0].split("-")[1]
226
227 con = sqlite3.connect(self.DB_NAME)
228 cur = con.cursor()
229 args = (artist_name, track_name, track_bytes)
230
231 cur.execute("""
232 INSERT INTO Tracks(artist_name, track_name, track)
233 VALUES(?,
234 ?,
235 ?)
236 """, args).fetchall()
237 con.commit()
238 con.close()
239 self.connect_db()
240
241 def delete_cur_track(self):
242 con = sqlite3.connect(self.DB_NAME)
243 cur = con.cursor()
244 cur.execute(f"""
245 DELETE FROM {self.playlists[self.cur_playlist]}
246 where id = ?
247 """, (self.cur_id,)).fetchall()
248 con.commit()
249 con.close()
250 self.connect_db()
251 self.update_ui()
252
253 def play_track(self):
254 if self.IS_PLAY:
255 self.play_btn.setText("▶")
256 self.IS_PLAY = False
257 self.was_paused = True
258 self.mediaPlayer.pause()
259 else:
260 self.play_btn.setText("| |")
261 self.IS_PLAY = True
262
263 # if self.was_paused:
264 #
265 # #mixer.music.unpause() # TODO MIXER
266 #
267 # else:
268 # #mixer.music.play() # TODO MIXER
269 self.mediaPlayer.play()
270
271 def next_track(self):
272
273 self.cur_ind += 1
274 if self.cur_ind >= len(self.tracks):
275 self.cur_ind = 0
276
277 self.was_paused = False
278 self.update_ui()
279 if self.IS_PLAY:
280 self.mediaPlayer.play()
281
282 def prev_track(self):
283 self.cur_ind -= 1
284 if self.cur_ind < 0:
285 self.cur_ind = len(self.tracks) - 1
286
287 self.was_paused = False
288 self.update_ui()
289 if self.IS_PLAY:
290 self.mediaPlayer.play()
291
292 def like_track(self):
293 con = sqlite3.connect(self.DB_NAME)
294 cur = con.cursor()
295
296 if (self.cur_id,) in self.liked_tracks:
297
298 cur.execute("""
299 DELETE from Liked
300 where id = ?
301 """, (self.cur_id,))
302 else:
303
304 cur.execute("""
305 INSERT INTO Liked VALUES(?)
306 """, (self.cur_id,))
307 con.commit()
308 self.liked_tracks = cur.execute("""
309 SELECT id
310 FROM Liked
311 """).fetchall()
312 con.close()
313
314 if (self.cur_id,) in self.liked_tracks:
315 self.like_btn.setIcon(QIcon(QPixmap("icons/liked.png")))
316 else:
317 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png")))
318
319 def eventFilter(self, obj, event):
320 if obj is self.like_btn:
321 if event.type() == QtCore.QEvent.HoverEnter:
322 if (self.cur_ind + 1,) in self.liked_tracks:
323 self.like_btn.setIcon(QIcon(QPixmap("icons/H-liked.png")))
324 else:
325 self.like_btn.setIcon(QIcon(QPixmap("icons/H-unliked.png")))
326
327 elif event.type() == QtCore.QEvent.HoverLeave:
328 if (self.cur_ind + 1,) in self.liked_tracks:
329 self.like_btn.setIcon(QIcon(QPixmap("icons/liked.png")))
330 else:
331 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png")))
332
333 elif obj is self.add_new_track_btn:
334 if event.type() == QtCore.QEvent.HoverEnter:
335 self.add_new_track_btn.setIcon(QIcon(QPixmap("icons/H-add.png")))
336 elif event.type() == QtCore.QEvent.HoverLeave:
337 self.add_new_track_btn.setIcon(QIcon(QPixmap("icons/add.png")))
338
339 elif obj is self.delete_cur_track_btn:
340 if event.type() == QtCore.QEvent.HoverEnter:
341 self.delete_cur_track_btn.setIcon(QIcon(QPixmap("icons/H-delete.png")))
342 elif event.type() == QtCore.QEvent.HoverLeave:
343 self.delete_cur_track_btn.setIcon(QIcon(QPixmap("icons/delete.png")))
344 elif obj is self.menu_btn:
345 if event.type() == QtCore.QEvent.HoverEnter:
346 self.menu_btn.setIcon(QIcon(QPixmap("icons/H-menu.png")))
347 elif event.type() == QtCore.QEvent.HoverLeave:
348 self.menu_btn.setIcon(QIcon(QPixmap("icons/menu.png")))
349 elif obj is self.menu.close_menu_btn:
350 if event.type() == QtCore.QEvent.HoverEnter:
351 self.menu.close_menu_btn.setIcon(QIcon(QPixmap("icons/H-back.png")))
352 elif event.type() == QtCore.QEvent.HoverLeave:
353 self.menu.close_menu_btn.setIcon(QIcon(QPixmap("icons/back.png")))
354
355 return super().eventFilter(obj, event)
356
357 def change_volume(self):
358 self.mediaPlayer.setVolume(self.volume_slider.value())
359
360 def open_menu(self):
361 self.menu_isopen = True
362 self.stackedWidget.setCurrentIndex(2)
363
364 def close_menu(self):
365 self.menu_isopen = False
366 self.stackedWidget.setCurrentIndex(0)
367
368 def change_playlist(self):
369 con = sqlite3.connect(self.DB_NAME)
370 cur = con.cursor()
371
372 tracks = cur.execute(f"""
373 SELECT *
374 FROM Tracks
375 WHERE id in (SELECT id from {self.playlists[self.menu.playlists.currentItem().text()]} )
376 """).fetchall() # mb id - 1
377 con.close()
378 if tracks:
379 self.cur_playlist = self.menu.playlists.currentItem().text()
380
381 else:
382 pass
383 # TODO self.menu.playlists.currentItem().setFlags(Qt.NoItemFlags) # disable item
384
385 self.play_btn.setText("▶")
386 self.IS_PLAY = False
387
388 self.connect_db()
389 self.update_ui()
390
391 def create_playlist(self):
392
393 playlist_name, ok_pressed = QInputDialog.getText(self, "Создание нового плейлиста",
394 "Введите название плейлиста:")
395
396 if ok_pressed:
397 t = ""
398 cap = 0
399 for i in playlist_name:
400 if i.isalpha():
401 t += i if cap else i.upper()
402 cap = 1
403 else:
404 cap = 0
405
406 playlist_name = "".join(t)
407 if playlist_name in self.playlists:
408 QMessageBox.warning(self, "Внимание!", "Плейлист с таким названием уже существует!")
409 else:
410
411 con = sqlite3.connect(self.DB_NAME)
412 cur = con.cursor()
413 cur.execute(f"""
414 CREATE TABLE IF NOT EXISTS {playlist_name} (
415 id integer NOT NULL,
416 FOREIGN KEY (id) REFERENCES Tracks (id)
417 );
418 """)
419 con.commit()
420 con.close()
421 self.menu.playlists.addItem(playlist_name)
422 self.playlists[playlist_name] = playlist_name
423 # TODO добавление треков в новые плейлисты
424
425 def keyPressEvent(self, event):
426 if event.key() == Qt.Key_Delete and self.menu_isopen:
427
428 if self.menu.playlists.currentItem().text() in ["Все треки", "Понравившиеся"]:
429 QMessageBox.warning(self, "Внимание!", "Нельзя удалить этот плейлист!")
430 else:
431 ok_pressed = QMessageBox.question(self, "Внимание!", "Вы точно хотите удалить плейлист?")
432 if ok_pressed:
433 pl_name = self.menu.playlists.currentItem().text()
434 con = sqlite3.connect(self.DB_NAME)
435 cur = con.cursor()
436 cur.execute(f"""
437 DROP TABLE IF EXISTS {pl_name}
438 """).fetchall()
439 con.commit()
440 con.close()
441 self.menu.playlists.takeItem(self.menu.playlists.currentRow())
442 self.connect_db()
443 self.update_ui()
444
445
446def except_hook(cls, exception, traceback):
447 sys.__excepthook__(cls, exception, traceback)
448
449
450if __name__ == "__main__":
451 app = QApplication(sys.argv)
452 main = Main()
453 main.show()
454 sys.excepthook = except_hook
455 sys.exit(app.exec())
456
457# "Я.Музычка с приколами"
458# # Created by Sergey Yaksanov at 28.10.2020
459# Copyright © 2020 Yakser. All rights reserved.
460