id3 > mp3, mutagen timestamp to sqlite db, small typing silences
This commit is contained in:
parent
04201fcb1d
commit
3ec08d8446
41
main.py
41
main.py
@ -4,8 +4,8 @@ import sys
|
|||||||
from subprocess import run
|
from subprocess import run
|
||||||
import qdarktheme
|
import qdarktheme
|
||||||
from pyqtgraph import mkBrush
|
from pyqtgraph import mkBrush
|
||||||
from mutagen.id3 import ID3, APIC, error
|
from mutagen.id3 import ID3
|
||||||
from mutagen.mp3 import MP3
|
from mutagen.id3._frames import APIC
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import DBA
|
import DBA
|
||||||
from ui import Ui_MainWindow
|
from ui import Ui_MainWindow
|
||||||
@ -18,9 +18,9 @@ from PyQt5.QtWidgets import (
|
|||||||
QGraphicsPixmapItem,
|
QGraphicsPixmapItem,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
)
|
)
|
||||||
from PyQt5.QtCore import QUrl, QTimer, QEvent, Qt, QModelIndex
|
from PyQt5.QtCore import QUrl, QTimer, Qt
|
||||||
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QAudioProbe
|
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QAudioProbe
|
||||||
from PyQt5.QtGui import QPixmap, QStandardItemModel
|
from PyQt5.QtGui import QCloseEvent, QPixmap
|
||||||
from utils import scan_for_music
|
from utils import scan_for_music
|
||||||
from utils import delete_and_create_library_database
|
from utils import delete_and_create_library_database
|
||||||
from components import PreferencesWindow, AudioVisualizer
|
from components import PreferencesWindow, AudioVisualizer
|
||||||
@ -130,7 +130,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
self.tableView.horizontalHeader().setStretchLastSection(False)
|
self.tableView.horizontalHeader().setStretchLastSection(False)
|
||||||
|
|
||||||
def closeEvent(self, event) -> None:
|
def closeEvent(self, a0: QCloseEvent | None) -> None:
|
||||||
"""Save settings when closing the application"""
|
"""Save settings when closing the application"""
|
||||||
# MusicTable/tableView column widths
|
# MusicTable/tableView column widths
|
||||||
list_of_column_widths = []
|
list_of_column_widths = []
|
||||||
@ -142,7 +142,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
# Save the config
|
# Save the config
|
||||||
with open("config.ini", "w") as configfile:
|
with open("config.ini", "w") as configfile:
|
||||||
self.config.write(configfile)
|
self.config.write(configfile)
|
||||||
super().closeEvent(event)
|
super().closeEvent(a0)
|
||||||
|
|
||||||
def play_audio_file(self) -> None:
|
def play_audio_file(self) -> None:
|
||||||
"""Start playback of tableView.current_song_filepath track & moves playback slider"""
|
"""Start playback of tableView.current_song_filepath track & moves playback slider"""
|
||||||
@ -159,18 +159,17 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.move_slider() # mover
|
self.move_slider() # mover
|
||||||
|
|
||||||
# assign metadata
|
# assign metadata
|
||||||
# FIXME when i change tinytag to something else
|
|
||||||
artist = (
|
artist = (
|
||||||
self.current_song_metadata["artist"][0]
|
self.current_song_metadata["TPE1"][0]
|
||||||
if "artist" in self.current_song_metadata
|
if "artist" in self.current_song_metadata
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
album = (
|
album = (
|
||||||
self.current_song_metadata["album"][0]
|
self.current_song_metadata["TALB"][0]
|
||||||
if "album" in self.current_song_metadata
|
if "album" in self.current_song_metadata
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
title = self.current_song_metadata["title"][0]
|
title = self.current_song_metadata["TIT2"][0]
|
||||||
# edit labels
|
# edit labels
|
||||||
self.artistLabel.setText(artist)
|
self.artistLabel.setText(artist)
|
||||||
self.albumLabel.setText(album)
|
self.albumLabel.setText(album)
|
||||||
@ -226,14 +225,14 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self, song_file_path: str, album_art_path: str
|
self, song_file_path: str, album_art_path: str
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Updates the ID3 tag APIC (album art) for 1 song"""
|
"""Updates the ID3 tag APIC (album art) for 1 song"""
|
||||||
audio = MP3(song_file_path, ID3=ID3)
|
# audio = MP3(song_file_path, ID3=ID3)
|
||||||
|
audio = ID3(song_file_path)
|
||||||
# Remove existing APIC Frames (album art)
|
# Remove existing APIC Frames (album art)
|
||||||
if audio.tags is not None:
|
audio.delall("APIC")
|
||||||
audio.tags.delall("APIC")
|
|
||||||
# Add the album art
|
# Add the album art
|
||||||
with open(album_art_path, "rb") as album_art_file:
|
with open(album_art_path, "rb") as album_art_file:
|
||||||
if album_art_path.endswith(".jpg") or album_art_path.endswith(".jpeg"):
|
if album_art_path.endswith(".jpg") or album_art_path.endswith(".jpeg"):
|
||||||
audio.tags.add(
|
audio.add(
|
||||||
APIC(
|
APIC(
|
||||||
encoding=3, # 3 = utf-8
|
encoding=3, # 3 = utf-8
|
||||||
mime="image/jpeg",
|
mime="image/jpeg",
|
||||||
@ -243,7 +242,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif album_art_path.endswith(".png"):
|
elif album_art_path.endswith(".png"):
|
||||||
audio.tags.add(
|
audio.add(
|
||||||
APIC(
|
APIC(
|
||||||
encoding=3, # 3 = utf-8
|
encoding=3, # 3 = utf-8
|
||||||
mime="image/png",
|
mime="image/png",
|
||||||
@ -270,9 +269,9 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
def update_audio_visualization(self) -> None:
|
def update_audio_visualization(self) -> None:
|
||||||
"""Handles upading points on the pyqtgraph visual"""
|
"""Handles upading points on the pyqtgraph visual"""
|
||||||
self.clear_audio_visualization()
|
self.clear_audio_visualization()
|
||||||
self.y = self.audio_visualizer.get_amplitudes()
|
y = self.audio_visualizer.get_amplitudes()
|
||||||
self.x = [i for i in range(len(self.y))]
|
x = [i for i in range(len(y))]
|
||||||
self.PlotWidget.plot(self.x, self.y, fillLevel=0, fillBrush=mkBrush("b"))
|
self.PlotWidget.plot(x, y, fillLevel=0, fillBrush=mkBrush("b"))
|
||||||
self.PlotWidget.show()
|
self.PlotWidget.show()
|
||||||
|
|
||||||
def clear_audio_visualization(self) -> None:
|
def clear_audio_visualization(self) -> None:
|
||||||
@ -284,7 +283,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# Update the slider
|
# Update the slider
|
||||||
if self.player.state() == QMediaPlayer.PlayingState:
|
if self.player.state() == QMediaPlayer.State.PlayingState:
|
||||||
self.playbackSlider.setMinimum(0)
|
self.playbackSlider.setMinimum(0)
|
||||||
self.playbackSlider.setMaximum(self.player.duration())
|
self.playbackSlider.setMaximum(self.player.duration())
|
||||||
slider_position = self.player.position()
|
slider_position = self.player.position()
|
||||||
@ -310,11 +309,11 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
def on_play_clicked(self) -> None:
|
def on_play_clicked(self) -> None:
|
||||||
"""Updates the Play & Pause buttons when clicked"""
|
"""Updates the Play & Pause buttons when clicked"""
|
||||||
if self.player.state() == QMediaPlayer.PlayingState:
|
if self.player.state() == QMediaPlayer.State.PlayingState:
|
||||||
self.player.pause()
|
self.player.pause()
|
||||||
self.playButton.setText("▶️")
|
self.playButton.setText("▶️")
|
||||||
else:
|
else:
|
||||||
if self.player.state() == QMediaPlayer.PausedState:
|
if self.player.state() == QMediaPlayer.State.PausedState:
|
||||||
self.player.play()
|
self.player.play()
|
||||||
self.playButton.setText("⏸️")
|
self.playButton.setText("⏸️")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from .id3_timestamp_to_datetime import id3_timestamp_to_datetime
|
||||||
from .safe_get import safe_get
|
from .safe_get import safe_get
|
||||||
from .get_album_art import get_album_art
|
from .get_album_art import get_album_art
|
||||||
from .get_id3_tags import get_id3_tags
|
from .get_id3_tags import get_id3_tags
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import DBA
|
import DBA
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from utils import get_id3_tags
|
from utils import get_id3_tags, id3_timestamp_to_datetime, safe_get
|
||||||
from utils import safe_get
|
|
||||||
|
|
||||||
config = ConfigParser()
|
config = ConfigParser()
|
||||||
config.read("config.ini")
|
config.read("config.ini")
|
||||||
@ -40,7 +39,7 @@ def add_files_to_library(files):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
genre = ""
|
genre = ""
|
||||||
try:
|
try:
|
||||||
date = audio["TDRC"].text[0]
|
date = id3_timestamp_to_datetime(audio["TDRC"].text[0])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
date = ""
|
date = ""
|
||||||
try:
|
try:
|
||||||
|
|||||||
11
utils/id3_timestamp_to_datetime.py
Normal file
11
utils/id3_timestamp_to_datetime.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import datetime
|
||||||
|
from mutagen.id3._specs import ID3TimeStamp
|
||||||
|
|
||||||
|
|
||||||
|
def id3_timestamp_to_datetime(timestamp: ID3TimeStamp):
|
||||||
|
"""Turns a mutagen ID3TimeStamp into a format that SQLite can use for Date field"""
|
||||||
|
if len(timestamp.text) == 4: # If only year is provided
|
||||||
|
datetime_obj = datetime.datetime.strptime(timestamp.text, '%Y')
|
||||||
|
else:
|
||||||
|
datetime_obj = datetime.datetime.strptime(timestamp.text, '%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
return datetime_obj.strftime('%Y-%m-%d')
|
||||||
Loading…
x
Reference in New Issue
Block a user