This commit is contained in:
tsi-billypom 2025-03-25 16:39:56 -04:00
parent 5c27645666
commit d579a60917
7 changed files with 37 additions and 31 deletions

View File

@ -51,7 +51,6 @@ config.ini db/
- ~~editable lyrics window~~ - ~~editable lyrics window~~
- ~~batch metadata changer (red highlight fields that have differing info)~~ - ~~batch metadata changer (red highlight fields that have differing info)~~
- ~~playlists~~ - ~~playlists~~
- playlist m3u files
- playlist autoexporting - playlist autoexporting
- fix table headers being resized and going out window bounds - fix table headers being resized and going out window bounds
- delete songs from library (del key || right-click delete) - delete songs from library (del key || right-click delete)

16
main.py
View File

@ -188,7 +188,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
lambda: self.player.setPosition(self.playbackSlider.value()) lambda: self.player.setPosition(self.playbackSlider.value())
) # sliderReleased works better than sliderMoved ) # sliderReleased works better than sliderMoved
self.volumeSlider.sliderMoved[int].connect(lambda: self.volume_changed()) self.volumeSlider.sliderMoved[int].connect(lambda: self.volume_changed())
self.speedSlider.sliderReleased.connect( self.speedSlider.sliderMoved.connect(
lambda: self.speed_changed(self.speedSlider.value()) lambda: self.speed_changed(self.speedSlider.value())
) )
self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause
@ -448,7 +448,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.playButton.setText("⏸️") self.playButton.setText("⏸️")
else: else:
self.play_audio_file() self.play_audio_file()
self.playButton.setText("⏸️") self.playButton.setText("👽")
def on_previous_clicked(self) -> None: def on_previous_clicked(self) -> None:
"""""" """"""
@ -490,7 +490,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
def create_playlist(self) -> None: def create_playlist(self) -> None:
"""Creates a database record for a playlist, given a name""" """Creates a database record for a playlist, given a name"""
window = CreatePlaylistWindow(self.playlistCreatedSignal) window = CreatePlaylistWindow(self.playlistCreatedSignal)
window.playlistCreatedSignal.connect(self.add_latest_playlist_to_tree) # type: ignore window.playlistCreatedSignal.connect(self.add_latest_playlist_to_tree) # type: ignore
window.exec_() window.exec_()
def import_playlist(self) -> None: def import_playlist(self) -> None:
@ -562,17 +562,17 @@ if __name__ == "__main__":
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini" Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
) )
cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom"))) cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom")))
debug(f'config file: {cfg_file}') debug(f"config file: {cfg_file}")
debug(f'config path: {cfg_path}') debug(f"config path: {cfg_path}")
# If config path doesn't exist, create it # If config path doesn't exist, create it
if not os.path.exists(cfg_path): if not os.path.exists(cfg_path):
os.makedirs(cfg_path) os.makedirs(cfg_path)
# If the config file doesn't exist, create it from the sample config # If the config file doesn't exist, create it from the sample config
if not os.path.exists(cfg_file): if not os.path.exists(cfg_file):
debug('copying sample config') debug("copying sample config")
# Create config file from sample # Create config file from sample
run(["cp", "sample_config.ini", cfg_file]) run(["cp", "./sample_config.ini", cfg_file])
config = ConfigParser() config = ConfigParser()
config.read(cfg_file) config.read(cfg_file)
db_filepath: str = config.get("db", "database") db_filepath: str = config.get("db", "database")
@ -580,7 +580,7 @@ if __name__ == "__main__":
# If the database location isnt set at the config location, move it # If the database location isnt set at the config location, move it
if not db_filepath.startswith(cfg_path): if not db_filepath.startswith(cfg_path):
new_path = f"{cfg_path}/{db_filepath}" new_path = f"{cfg_path}/{db_filepath}"
debug(f'setting new db-database path: {new_path}') debug(f"setting new db-database path: {new_path}")
config["db"]["database"] = new_path config["db"]["database"] = new_path
# Save the config # Save the config
with open(cfg_file, "w") as configfile: with open(cfg_file, "w") as configfile:

BIN
out.mp3 Normal file

Binary file not shown.

BIN
out2.mp3 Normal file

Binary file not shown.

View File

@ -1,38 +1,46 @@
import DBA import DBA
import logging import os
from logging import debug
from utils import get_id3_tags, id3_timestamp_to_datetime from utils import get_id3_tags, id3_timestamp_to_datetime
from PyQt5.QtCore import pyqtSignal
from configparser import ConfigParser from configparser import ConfigParser
from pathlib import Path from pathlib import Path
from appdirs import user_config_dir from appdirs import user_config_dir
import platform
config = ConfigParser()
cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
)
config.read(cfg_file)
def add_files_to_library(files, progress_callback=None): def add_files_to_library(files, progress_callback=None):
"""Adds audio file(s) to the sqllite db
files = list() of fully qualified paths to audio file(s)
Returns a list of dictionaries of metadata
""" """
logging.info("started function") Adds audio file(s) to the sqllite db
Args:
files: list() of fully qualified paths to audio file(s)
progress_callback: emit data for user feedback
Returns:
True on success, else False
"""
config = ConfigParser()
cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
)
config.read(cfg_file)
if not files: if not files:
return [] return False
extensions = config.get("settings", "extensions").split(",") extensions = config.get("settings", "extensions").split(",")
insert_data = [] # To store data for batch insert insert_data = [] # To store data for batch insert
for filepath in files: for filepath in files:
if any(filepath.lower().endswith(ext) for ext in extensions): if any(filepath.lower().endswith(ext) for ext in extensions):
if progress_callback: if progress_callback:
progress_callback.emit(filepath) progress_callback.emit(filepath)
# if "microsoft-standard" in platform.uname().release:
# filename = filepath.split(r"\\")[-1]
# filepath = os.path.join(filepath)
# else:
filename = filepath.split("/")[-1] filename = filepath.split("/")[-1]
audio = get_id3_tags(filepath) audio = get_id3_tags(filepath)
try: try:
title = audio["TIT2"].text[0] title = audio["TIT2"].text[0]
except KeyError as e: except KeyError:
title = filename title = filename
try: try:
artist = audio["TPE1"].text[0] artist = audio["TPE1"].text[0]
@ -75,7 +83,7 @@ def add_files_to_library(files, progress_callback=None):
) )
# Check if batch size is reached # Check if batch size is reached
if len(insert_data) >= 1000: if len(insert_data) >= 1000:
logging.info(f"inserting a LOT of songs: {len(insert_data)}") debug(f"inserting a LOT of songs: {len(insert_data)}")
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.executemany( db.executemany(
"INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", "INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
@ -86,9 +94,9 @@ def add_files_to_library(files, progress_callback=None):
# continue adding files if we havent reached big length # continue adding files if we havent reached big length
continue continue
# Insert any remaining data # Insert any remaining data
logging.info("i check for insert data") debug("i check for insert data")
if insert_data: if insert_data:
logging.info(f"inserting some songs: {len(insert_data)}") debug(f"inserting some songs: {len(insert_data)}")
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.executemany( db.executemany(
"INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", "INSERT OR IGNORE INTO song (filepath, title, album, artist, track_number, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",

View File

@ -2,12 +2,11 @@
# https://github.com/ravenkls/MilkPlayer/blob/master/audio/fft_analyser.py # https://github.com/ravenkls/MilkPlayer/blob/master/audio/fft_analyser.py
import time import time
import os
from PyQt5 import QtCore from PyQt5 import QtCore
from pydub import AudioSegment from pydub import AudioSegment
import numpy as np import numpy as np
from scipy.ndimage.filters import gaussian_filter1d from scipy.ndimage.filters import gaussian_filter1d
from logging import info from logging import debug
class FFTAnalyser(QtCore.QThread): class FFTAnalyser(QtCore.QThread):
@ -66,9 +65,9 @@ class FFTAnalyser(QtCore.QThread):
if not data.size: if not data.size:
return return
for n, f in enumerate(np.arange(0, 1, point_range), start=1): for i, freq in enumerate(np.arange(0, 1, point_range), start=1):
# get the amps which are in between the frequency range # get the amps which are in between the frequency range
amps = data[(f - point_range < data[:, 0]) & (data[:, 0] < f)] amps = data[(freq - point_range < data[:, 0]) & (data[:, 0] < freq)]
if not amps.size: if not amps.size:
point_samples.append(0) point_samples.append(0)
else: else:
@ -76,7 +75,7 @@ class FFTAnalyser(QtCore.QThread):
amps.max() amps.max()
* ( * (
(1 + self.sensitivity / 10 + (self.sensitivity - 1) / 10) (1 + self.sensitivity / 10 + (self.sensitivity - 1) / 10)
** (n / 50) ** (i / 50)
) )
) )

BIN
uwish.mp3 Normal file

Binary file not shown.