From a6b089a5aecf5fe27f5d15c340cca037f5278016 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Sun, 21 Mar 2021 19:55:33 +0000 Subject: [PATCH] Separate out model --- app.py | 99 +++---------------------------------------------------- model.py | 70 +++++++++++++++++++++++++++++++++++++++ songdb.py | 64 +++-------------------------------- spike.py | 81 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 154 deletions(-) create mode 100644 model.py create mode 100644 spike.py diff --git a/app.py b/app.py index 86106f3..83fbc06 100755 --- a/app.py +++ b/app.py @@ -1,17 +1,12 @@ #!/usr/bin/python3 import sys -import vlc -from datetime import datetime, timedelta from pydub import AudioSegment -from PyQt5.QtCore import QEvent, Qt -from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow, QMessageBox +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow from PyQt5.QtWidgets import QTableWidgetItem, QFileDialog, QListWidgetItem -from PyQt5.uic import loadUi from threading import Timer -from time import sleep -from timeloop import Timeloop from tinytag import TinyTag from main_window_ui import Ui_MainWindow @@ -19,11 +14,6 @@ from dlg_search_database_ui import Ui_Dialog from songdb import Tracks -import sqlalchemy - -from sqlalchemy.orm import sessionmaker -from sqlalchemy.ext.declarative import declarative_base - class RepeatedTimer: def __init__(self, interval, function, *args, **kwargs): @@ -81,7 +71,7 @@ class Track: return AudioSegment.from_mp3(path) elif path.endswith('.flac'): return AudioSegment.from_file(path, "flac") - except: + except AttributeError: return None def leading_silence(self, audio_segment, silence_threshold=-50.0, @@ -232,92 +222,11 @@ class DbDialog(QDialog): self.ui.listWidget.addItem(t) def listdclick(self, entry): - import ipdb; ipdb.set_trace() print(f"clicked entry id={entry.data(Qt.UserRole)}") + if __name__ == "__main__": app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec()) - - -# tl = Timeloop() -# -# -# -# # @tl.job(interval=timedelta(seconds=1)) -# def update_progress(player, talk_at, silent_at): -# elapsed_time = player.get_time() -# total_time = player.get_length() -# remaining_time = total_time - elapsed_time -# talk_time = remaining_time - (total_time - talk_at) -# silent_time = remaining_time - (total_time - silent_at) -# end_time = (datetime.now() + timedelta( -# milliseconds=remaining_time)).strftime("%H:%M:%S") -# print( -# f"\t{ms_to_mmss(elapsed_time)}/" -# f"{ms_to_mmss(total_time)}\t\t" -# f"Talk in: {ms_to_mmss(talk_time)} " -# f"Silent in: {ms_to_mmss(silent_time)} " -# f"Ends at: {end_time} [{ms_to_mmss(remaining_time)}]" -# , end="\r") -# -# -# # Print name of current song, print name of next song. Play current when -# # return pressed, Pri--current-song-output-lengthnt remaining time every -# # second. When it ends, print name of new current and next song. -# -# -# def test(): -# track = "wibg.mp3" -# segment = AudioSegment.from_mp3(trm.ack) -# print(f"Track: {track}") -# print(f"Leading silence: {ms_to_mmss(leading_silence(segment), -# decimals=1)}") -# talk_at = significant_fade(segment) -# silent_at = trailing_silence(segment) -# print(f"Talkover fade: {ms_to_mmss(talk_at)}") -# print(f"Track silent from: {ms_to_mmss(silent_at)}") -# p = vlc.MediaPlayer("wibg.mp3") -# _ = input("") -# p.play() -# print() -# rt = RepeatedTimer(0.5, update_progress, p, talk_at, silent_at) -# sleep(1) -# while p.is_playing(): -# sleep(1) -# rt.stop() # better in a try/finally block to make sure the program ends! -# print("End") - - #def kae2(self, index): - # print(f"table header click, index={index}") - - #def kae(self, a, b, c): - # self.data.append(f"a={a}, b={b}, c={c}") - - #def mousePressEvent(self, QMouseEvent): - # print("mouse press") - - #def mouseReleaseEvent(self, QMouseEvent): - # print("mouse release") - # # QMessageBox.about( - # # self, - # # "About Sample Editor", - # # "\n".join(self.data) - # # ) - #def eventFilter(self, obj, event): - # # you could be doing different groups of actions - # # for different types of widgets and either filtering - # # the event or not. - # # Here we just check if its one of the layout widgets - # # if self.layout.indexOf(obj) != -1: - # # print(f"event received: {event.type()}") - # if event.type() == QEvent.MouseButtonPress: - # print("Widget click") - # # if I returned True right here, the event - # # would be filtered and not reach the obj, - # # meaning that I decided to handle it myself - - # # regardless, just do the default - # return super().eventFilter(obj, event) diff --git a/model.py b/model.py new file mode 100644 index 0000000..1ffaa3a --- /dev/null +++ b/model.py @@ -0,0 +1,70 @@ +#!/usr/bin/python3 + +import logging +import sqlalchemy + +import pytiger.logging.config + +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Float, DateTime, Integer, String +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.orm import sessionmaker + +# "Constants" +DISPLAY_SQL = False +MYSQL_CONNECT = "mysql+mysqldb://songdb:songdb@localhost/songdb" + +# Instantiate logging +pytiger.logging.config.basic_config(stderr=False, level=logging.INFO) +log = logging.getLogger(__name__) +log.info("Starting") + +# Create session at the global level as per +# https://docs.sqlalchemy.org/en/13/orm/session_basics.html + +# Set up database connection +log.info("Connect to database") +engine = sqlalchemy.create_engine(f"{MYSQL_CONNECT}?charset=utf8", + encoding='utf-8', + echo=DISPLAY_SQL) +Base = declarative_base() +Base.metadata.create_all(engine) + +# Create a Session +Session = sessionmaker(bind=engine) +session = Session() + + +# Database classes +class Tracks(Base): + __tablename__ = 'tracks' + + id = Column(Integer, primary_key=True, autoincrement=True) + title = Column(String(256), index=True) + artist = Column(String(256), index=True) + length = Column(Integer, index=True) + path = Column(String(2048), index=False, nullable=False) + mtime = Column(Float, index=True) + lastplayed = Column(DateTime, index=True, default=None) + + def __repr__(self): + return ( + f"" + ) + + @classmethod + def get_or_create(cls, path): + try: + track = session.query(cls).filter(cls.path == path).one() + except NoResultFound: + track = Tracks() + track.path = path + session.add(track) + return track + + @staticmethod + def search_titles(text): + return session.query(Tracks).filter( + Tracks.title.ilike(f"%{text}%") + ).all() diff --git a/songdb.py b/songdb.py index dc91185..57b7cf6 100755 --- a/songdb.py +++ b/songdb.py @@ -4,76 +4,21 @@ import argparse import hashlib import logging import os -import sqlalchemy import pytiger.logging.config -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import Column, Float, DateTime, Integer, String -from sqlalchemy.orm.exc import NoResultFound -from sqlalchemy.orm import sessionmaker from tinytag import TinyTag +from model import Tracks, session + + # "Constants" ROOT = "/home/kae/music" -DISPLAY_SQL = False -MYSQL_CONNECT = "mysql+mysqldb://songdb:songdb@localhost/songdb" - # Instantiate logging pytiger.logging.config.basic_config(stderr=False, level=logging.INFO) log = logging.getLogger(__name__) log.info("Starting") -# Create session at the global level as per -# https://docs.sqlalchemy.org/en/13/orm/session_basics.html - -# Set up database connection -log.info("Connect to database") -engine = sqlalchemy.create_engine(f"{MYSQL_CONNECT}?charset=utf8", - encoding='utf-8', - echo=DISPLAY_SQL) -Base = declarative_base() -Base.metadata.create_all(engine) - -# Create a Session -Session = sessionmaker(bind=engine) -session = Session() - - -# Database classes -class Tracks(Base): - __tablename__ = 'tracks' - - id = Column(Integer, primary_key=True, autoincrement=True) - title = Column(String(256), index=True) - artist = Column(String(256), index=True) - length = Column(Integer, index=True) - path = Column(String(2048), index=False, nullable=False) - mtime = Column(Float, index=True) - lastplayed = Column(DateTime, index=True, default=None) - - def __repr__(self): - return ( - f"" - ) - - @classmethod - def get_or_create(cls, path): - try: - track = session.query(cls).filter(cls.path == path).one() - except NoResultFound: - track = Tracks() - track.path = path - session.add(track) - return track - - @staticmethod - def search_titles(text): - return session.query(Tracks).filter( - Tracks.title.ilike(f"%{text}%") - ).all() - def main(): "Main loop" @@ -117,11 +62,12 @@ def update_db(): print(f"Unrecognised file type: {path}") session.commit() + print(f"{count} files processed") def md5(path): - "https://stackoverflow.com/questions/3431825/" + "https://stackoverflow.nl9om/questions/3431825/" "generating-an-md5-checksum-of-a-file" hash_md5 = hashlib.md5() diff --git a/spike.py b/spike.py new file mode 100644 index 0000000..5757359 --- /dev/null +++ b/spike.py @@ -0,0 +1,81 @@ + + +# tl = Timeloop() +# +# +# +# # @tl.job(interval=timedelta(seconds=1)) +# def update_progress(player, talk_at, silent_at): +# elapsed_time = player.get_time() +# total_time = player.get_length() +# remaining_time = total_time - elapsed_time +# talk_time = remaining_time - (total_time - talk_at) +# silent_time = remaining_time - (total_time - silent_at) +# end_time = (datetime.now() + timedelta( +# milliseconds=remaining_time)).strftime("%H:%M:%S") +# print( +# f"\t{ms_to_mmss(elapsed_time)}/" +# f"{ms_to_mmss(total_time)}\t\t" +# f"Talk in: {ms_to_mmss(talk_time)} " +# f"Silent in: {ms_to_mmss(silent_time)} " +# f"Ends at: {end_time} [{ms_to_mmss(remaining_time)}]" +# , end="\r") +# +# +# # Print name of current song, print name of next song. Play current when +# # return pressed, Pri--current-song-output-lengthnt remaining time every +# # second. When it ends, print name of new current and next song. +# +# +# def test(): +# track = "wibg.mp3" +# segment = AudioSegment.from_mp3(trm.ack) +# print(f"Track: {track}") +# print(f"Leading silence: {ms_to_mmss(leading_silence(segment), +# decimals=1)}") +# talk_at = significant_fade(segment) +# silent_at = trailing_silence(segment) +# print(f"Talkover fade: {ms_to_mmss(talk_at)}") +# print(f"Track silent from: {ms_to_mmss(silent_at)}") +# p = vlc.MediaPlayer("wibg.mp3") +# _ = input("") +# p.play() +# print() +# rt = RepeatedTimer(0.5, update_progress, p, talk_at, silent_at) +# sleep(1) +# while p.is_playing(): +# sleep(1) +# rt.stop() # better in a try/finally block to make sure the program ends! +# print("End") + + #def kae2(self, index): + # print(f"table header click, index={index}") + + #def kae(self, a, b, c): + # self.data.append(f"a={a}, b={b}, c={c}") + + #def mousePressEvent(self, QMouseEvent): + # print("mouse press") + + #def mouseReleaseEvent(self, QMouseEvent): + # print("mouse release") + # # QMessageBox.about( + # # self, + # # "About Sample Editor", + # # "\n".join(self.data) + # # ) + #def eventFilter(self, obj, event): + # # you could be doing different groups of actions + # # for different types of widgets and either filtering + # # the event or not. + # # Here we just check if its one of the layout widgets + # # if self.layout.indexOf(obj) != -1: + # # print(f"event received: {event.type()}") + # if event.type() == QEvent.MouseButtonPress: + # print("Widget click") + # # if I returned True right here, the event + # # would be filtered and not reach the obj, + # # meaning that I decided to handle it myself + + # # regardless, just do the default + # return super().eventFilter(obj, event)