· 5 years ago · Nov 07, 2020, 09:00 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, QMediaService
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
109 def connect_db(self):
110
111 con = sqlite3.connect(self.DB_NAME)
112 cur = con.cursor()
113
114 self.tracks = cur.execute(f"""
115 SELECT *
116 FROM Tracks
117 WHERE id in (SELECT id from {self.playlists[self.cur_playlist]} )
118 """).fetchall()
119
120 self.liked_tracks = cur.execute("""
121 SELECT id
122 FROM Liked
123 """).fetchall()
124 con.close()
125 self.cur_ind = 0
126
127 def update_ui(self):
128
129 self.cur_id, self.cur_artist_name, self.cur_track_name, \
130 self.cur_song_avatar, self.cur_track = self.tracks[self.cur_ind]
131 self.track_name.setText(self.cur_track_name)
132 self.artist_name.setText(self.cur_artist_name)
133
134 if (self.tracks[self.cur_ind][0],) in self.liked_tracks:
135 self.like_btn.setIcon(QIcon(QPixmap("icons/liked.png")))
136 else:
137 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png")))
138 self.cur_qplaylist = QMediaPlaylist()
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 self.mediaPlayer.stateChanged.connect(self.is_media_ended)
151
152 # self.mediaPlayer: QMediaPlayer
153 # self.mediaPlayer.setPlaylist(QMediaPlaylist())
154
155 self.song_avatar.setText(self.cur_song_avatar) # NONE
156 # TODO обложка трека из байтов
157 # self.song_avatar.setPixmap(QPixmap(self.cur_song_avatar))
158
159 def is_media_ended(self):
160 if self.mediaPlayer.state() == 0: # переключение на следующий трек
161 self.next_track()
162
163 def apply_styles(self):
164
165 self.setStyleSheet(MAIN_WINDOW_STYLES)
166 # стили кнопок переключения треков
167 self.play_btn.setStyleSheet(DEFAULT_BTN_STYLES)
168
169 self.next_btn.setStyleSheet(DEFAULT_BTN_STYLES)
170
171 self.prev_btn.setStyleSheet(DEFAULT_BTN_STYLES)
172
173 self.like_btn.setStyleSheet(LIKE_BTN_STYLES)
174
175 self.volume_slider.setStyleSheet(DEFAULT_SLIDER_STYLES)
176
177 # стили для view widget
178 # self.view_window.setStyleSheet(DEFAULT_WIDGET_STYLES)
179
180 self.song_avatar.setStyleSheet(SONG_AVATAR_STYLES)
181
182 self.artist_name.setStyleSheet(ARTIST_NAME_STYLES)
183 self.track_name.setStyleSheet(TRACK_NAME_STYLES)
184
185 # SETTING UP ICONS
186
187 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png"))) # unliked btn icon
188 self.like_btn.setIconSize(QSize(40, 40))
189
190 self.add_new_track_btn.setIcon(QIcon(QPixmap("icons/add.png"))) # add ADD btn icon
191 self.add_new_track_btn.setIconSize(QSize(30, 30))
192
193 self.delete_cur_track_btn.setIcon(QIcon(QPixmap("icons/delete.png"))) # add DELETE btn icon
194 self.delete_cur_track_btn.setIconSize(QSize(30, 30))
195
196 self.menu_btn.setIcon(QIcon(QPixmap("icons/menu.png"))) # add DELETE btn icon
197 self.menu_btn.setIconSize(QSize(40, 40))
198
199 self.stackedWidget.setStyleSheet(STACKED_WIDGET_STYLES)
200 self.page_3.setStyleSheet("""background:transparent""") # прозрачный фон для виджета кнопки меню
201
202 # добавление теней
203
204 shadow = [self.create_shadow() for _ in range(7)]
205
206 self.add_new_track_btn.setGraphicsEffect(shadow[0])
207 self.like_btn.setGraphicsEffect(shadow[1])
208 self.play_btn.setGraphicsEffect(shadow[2])
209 self.next_btn.setGraphicsEffect(shadow[3])
210 self.prev_btn.setGraphicsEffect(shadow[4])
211 self.menu_btn.setGraphicsEffect(shadow[5])
212 self.delete_cur_track_btn.setGraphicsEffect(shadow[6])
213
214 def create_shadow(self):
215 shadow = QGraphicsDropShadowEffect()
216 shadow.setBlurRadius(15)
217 shadow.setOffset(4, 2)
218 c = QColor(0, 0, 0)
219 c.setAlpha(100)
220 shadow.setColor(c)
221 return shadow
222
223 def add_new_track(self):
224
225 fname = QFileDialog.getOpenFileName(self, 'Выбрать трек', '')[0]
226
227 with open(fname, "rb") as track_bytes:
228 track_bytes = track_bytes.read()
229 artist_name = fname.split("/")[-1].split('.mp3')[0].split("-")[0]
230 track_name = fname.split("/")[-1].split('.mp3')[0].split("-")[1]
231
232 con = sqlite3.connect(self.DB_NAME)
233 cur = con.cursor()
234 args = (artist_name, track_name, track_bytes)
235
236 cur.execute("""
237 INSERT INTO Tracks(artist_name, track_name, track)
238 VALUES(?,
239 ?,
240 ?)
241 """, args).fetchall()
242 con.commit()
243 con.close()
244 self.connect_db()
245
246 def delete_cur_track(self):
247 con = sqlite3.connect(self.DB_NAME)
248 cur = con.cursor()
249 cur.execute(f"""
250 DELETE FROM {self.playlists[self.cur_playlist]}
251 where id = ?
252 """, (self.cur_id,)).fetchall()
253 con.commit()
254 con.close()
255 self.connect_db()
256 self.update_ui()
257
258 def play_track(self):
259 if self.IS_PLAY:
260 self.play_btn.setText("▶")
261 self.IS_PLAY = False
262 self.was_paused = True
263 self.mediaPlayer.pause()
264 else:
265 self.play_btn.setText("| |")
266 self.IS_PLAY = True
267 self.mediaPlayer.play()
268
269 def next_track(self):
270
271 self.cur_ind += 1
272 if self.cur_ind >= len(self.tracks):
273 self.cur_ind = 0
274
275 self.was_paused = False
276 self.update_ui()
277 if self.IS_PLAY:
278 self.mediaPlayer.play()
279
280 def prev_track(self):
281 self.cur_ind -= 1
282 if self.cur_ind < 0:
283 self.cur_ind = len(self.tracks) - 1
284
285 self.was_paused = False
286 self.update_ui()
287 if self.IS_PLAY:
288 self.mediaPlayer.play()
289
290 def like_track(self):
291 con = sqlite3.connect(self.DB_NAME)
292 cur = con.cursor()
293
294 if (self.cur_id,) in self.liked_tracks:
295
296 cur.execute("""
297 DELETE from Liked
298 where id = ?
299 """, (self.cur_id,))
300 else:
301
302 cur.execute("""
303 INSERT INTO Liked VALUES(?)
304 """, (self.cur_id,))
305 con.commit()
306 self.liked_tracks = cur.execute("""
307 SELECT id
308 FROM Liked
309 """).fetchall()
310 con.close()
311
312 if (self.cur_id,) in self.liked_tracks:
313 self.like_btn.setIcon(QIcon(QPixmap("icons/liked.png")))
314 else:
315 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png")))
316
317 def eventFilter(self, obj, event):
318 if obj is self.like_btn:
319 if event.type() == QtCore.QEvent.HoverEnter:
320 if (self.cur_ind + 1,) in self.liked_tracks:
321 self.like_btn.setIcon(QIcon(QPixmap("icons/H-liked.png")))
322 else:
323 self.like_btn.setIcon(QIcon(QPixmap("icons/H-unliked.png")))
324
325 elif event.type() == QtCore.QEvent.HoverLeave:
326 if (self.cur_ind + 1,) in self.liked_tracks:
327 self.like_btn.setIcon(QIcon(QPixmap("icons/liked.png")))
328 else:
329 self.like_btn.setIcon(QIcon(QPixmap("icons/unliked.png")))
330
331 elif obj is self.add_new_track_btn:
332 if event.type() == QtCore.QEvent.HoverEnter:
333 self.add_new_track_btn.setIcon(QIcon(QPixmap("icons/H-add.png")))
334 elif event.type() == QtCore.QEvent.HoverLeave:
335 self.add_new_track_btn.setIcon(QIcon(QPixmap("icons/add.png")))
336
337 elif obj is self.delete_cur_track_btn:
338 if event.type() == QtCore.QEvent.HoverEnter:
339 self.delete_cur_track_btn.setIcon(QIcon(QPixmap("icons/H-delete.png")))
340 elif event.type() == QtCore.QEvent.HoverLeave:
341 self.delete_cur_track_btn.setIcon(QIcon(QPixmap("icons/delete.png")))
342 elif obj is self.menu_btn:
343 if event.type() == QtCore.QEvent.HoverEnter:
344 self.menu_btn.setIcon(QIcon(QPixmap("icons/H-menu.png")))
345 elif event.type() == QtCore.QEvent.HoverLeave:
346 self.menu_btn.setIcon(QIcon(QPixmap("icons/menu.png")))
347 elif obj is self.menu.close_menu_btn:
348 if event.type() == QtCore.QEvent.HoverEnter:
349 self.menu.close_menu_btn.setIcon(QIcon(QPixmap("icons/H-back.png")))
350 elif event.type() == QtCore.QEvent.HoverLeave:
351 self.menu.close_menu_btn.setIcon(QIcon(QPixmap("icons/back.png")))
352
353 return super().eventFilter(obj, event)
354
355 def change_volume(self):
356 self.mediaPlayer.setVolume(self.volume_slider.value())
357
358 def open_menu(self):
359 self.menu_isopen = True
360 self.stackedWidget.setCurrentIndex(2)
361
362 def close_menu(self):
363 self.menu_isopen = False
364 self.stackedWidget.setCurrentIndex(0)
365
366 def change_playlist(self):
367 con = sqlite3.connect(self.DB_NAME)
368 cur = con.cursor()
369
370 tracks = cur.execute(f"""
371 SELECT *
372 FROM Tracks
373 WHERE id in (SELECT id from {self.playlists[self.menu.playlists.currentItem().text()]} )
374 """).fetchall() # mb id - 1
375 con.close()
376 if tracks:
377 self.cur_playlist = self.menu.playlists.currentItem().text()
378
379 else:
380 pass
381 # TODO self.menu.playlists.currentItem().setFlags(Qt.NoItemFlags) # disable item
382
383 self.play_btn.setText("▶")
384 self.IS_PLAY = False
385
386 self.connect_db()
387 self.update_ui()
388
389 def create_playlist(self):
390
391 playlist_name, ok_pressed = QInputDialog.getText(self, "Создание нового плейлиста",
392 "Введите название плейлиста:")
393
394 if ok_pressed:
395 t = ""
396 cap = 0
397 for i in playlist_name:
398 if i.isalpha():
399 t += i if cap else i.upper()
400 cap = 1
401 else:
402 cap = 0
403
404 playlist_name = "".join(t)
405 if playlist_name in self.playlists:
406 QMessageBox.warning(self, "Внимание!", "Плейлист с таким названием уже существует!")
407 else:
408
409 con = sqlite3.connect(self.DB_NAME)
410 cur = con.cursor()
411 cur.execute(f"""
412 CREATE TABLE IF NOT EXISTS {playlist_name} (
413 id integer NOT NULL,
414 FOREIGN KEY (id) REFERENCES Tracks (id)
415 );
416 """)
417 con.commit()
418 con.close()
419 self.menu.playlists.addItem(playlist_name)
420 self.playlists[playlist_name] = playlist_name
421 # TODO добавление треков в новые плейлисты
422
423 def keyPressEvent(self, event):
424 if event.key() == Qt.Key_Delete and self.menu_isopen:
425
426 if self.menu.playlists.currentItem().text() in ["Все треки", "Понравившиеся"]:
427 QMessageBox.warning(self, "Внимание!", "Нельзя удалить этот плейлист!")
428 else:
429 ok_pressed = QMessageBox.question(self, "Внимание!", "Вы точно хотите удалить плейлист?")
430 if ok_pressed:
431 pl_name = self.menu.playlists.currentItem().text()
432 con = sqlite3.connect(self.DB_NAME)
433 cur = con.cursor()
434 cur.execute(f"""
435 DROP TABLE IF EXISTS {pl_name}
436 """).fetchall()
437 con.commit()
438 con.close()
439 self.menu.playlists.takeItem(self.menu.playlists.currentRow())
440 self.connect_db()
441 self.update_ui()
442
443
444def except_hook(cls, exception, traceback):
445 sys.__excepthook__(cls, exception, traceback)
446
447
448if __name__ == "__main__":
449 app = QApplication(sys.argv)
450 main = Main()
451 main.show()
452 sys.excepthook = except_hook
453 sys.exit(app.exec())
454
455# "Я.Музычка с приколами"
456# # Created by Sergey Yaksanov at 28.10.2020
457# Copyright © 2020 Yakser. All rights reserved.
458