Counters updating; store full path; round milliseconds
This commit is contained in:
parent
31cf7ca3e6
commit
28143ced6c
@ -3,6 +3,9 @@ import os
|
|||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
|
AUDIO_SEGMENT_CHUNK_SIZE = 10
|
||||||
|
DBFS_FADE = -12
|
||||||
|
DBFS_SILENCE = -50
|
||||||
DISPLAY_SQL = False
|
DISPLAY_SQL = False
|
||||||
ERRORS_TO = ['kae@midnighthax.com']
|
ERRORS_TO = ['kae@midnighthax.com']
|
||||||
LOG_LEVEL_STDERR = logging.INFO
|
LOG_LEVEL_STDERR = logging.INFO
|
||||||
@ -12,9 +15,10 @@ class Config(object):
|
|||||||
MAIL_SERVER = os.environ.get('MAIL_SERVER') or "woodlands.midnighthax.com"
|
MAIL_SERVER = os.environ.get('MAIL_SERVER') or "woodlands.midnighthax.com"
|
||||||
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
||||||
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
|
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
|
||||||
|
MILLISECOND_SIGFIGS = 1
|
||||||
MYSQL_CONNECT = "mysql+mysqldb://songdb:songdb@localhost/songdb"
|
MYSQL_CONNECT = "mysql+mysqldb://songdb:songdb@localhost/songdb"
|
||||||
ROOT = "/home/kae/music"
|
ROOT = "/home/kae/music"
|
||||||
TIMER_MS = 500
|
TIMER_MS = 1000
|
||||||
|
|
||||||
|
|
||||||
config = Config
|
config = Config
|
||||||
|
|||||||
@ -10,7 +10,6 @@ from log import DEBUG, ERROR
|
|||||||
from PyQt5.QtCore import Qt, QTimer
|
from PyQt5.QtCore import Qt, QTimer
|
||||||
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow
|
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow
|
||||||
from PyQt5.QtWidgets import QTableWidgetItem, QFileDialog, QListWidgetItem
|
from PyQt5.QtWidgets import QTableWidgetItem, QFileDialog, QListWidgetItem
|
||||||
from threading import Timer
|
|
||||||
|
|
||||||
from ui.main_window_ui import Ui_MainWindow
|
from ui.main_window_ui import Ui_MainWindow
|
||||||
from ui.dlg_search_database_ui import Ui_Dialog
|
from ui.dlg_search_database_ui import Ui_Dialog
|
||||||
@ -19,34 +18,9 @@ from config import Config
|
|||||||
from model import Settings, Tracks
|
from model import Settings, Tracks
|
||||||
|
|
||||||
|
|
||||||
class RepeatedTimer:
|
|
||||||
def __init__(self, interval, function, *args, **kwargs):
|
|
||||||
self._timer = None
|
|
||||||
self.interval = interval
|
|
||||||
self.function = function
|
|
||||||
self.args = args
|
|
||||||
self.kwargs = kwargs
|
|
||||||
self.is_running = False
|
|
||||||
self.start()
|
|
||||||
|
|
||||||
def _run(self):
|
|
||||||
self.is_running = False
|
|
||||||
self.start()
|
|
||||||
self.function(*self.args, **self.kwargs)
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
if not self.is_running:
|
|
||||||
self._timer = Timer(self.interval, self._run)
|
|
||||||
self._timer.start()
|
|
||||||
self.is_running = True
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self._timer.cancel()
|
|
||||||
self.is_running = False
|
|
||||||
|
|
||||||
|
|
||||||
class Music:
|
class Music:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.current_track = {
|
self.current_track = {
|
||||||
"player": None,
|
"player": None,
|
||||||
"meta": None
|
"meta": None
|
||||||
@ -106,6 +80,12 @@ class Music:
|
|||||||
|
|
||||||
self.current_track['player'].play()
|
self.current_track['player'].play()
|
||||||
|
|
||||||
|
def playing(self):
|
||||||
|
if self.current_track['player']:
|
||||||
|
return self.current_track['player'].is_playing()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def resume_last(self):
|
def resume_last(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -220,9 +200,17 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
ERROR("Can't set next track")
|
ERROR("Can't set next track")
|
||||||
|
|
||||||
def tick(self):
|
def tick(self):
|
||||||
self.current_time.setText(
|
now = datetime.now()
|
||||||
datetime.strftime(datetime.now(), "%H:%M:%S")
|
self.current_time.setText(now.strftime("%H:%M:%S"))
|
||||||
)
|
if self.music.playing():
|
||||||
|
playtime = self.music.get_current_playtime()
|
||||||
|
self.label_elapsed_timer.setText(ms_to_mmss(playtime))
|
||||||
|
self.label_fade_timer.setText(
|
||||||
|
ms_to_mmss(self.music.get_current_fade_at() - playtime))
|
||||||
|
self.label_silent_timer.setText(
|
||||||
|
ms_to_mmss(self.music.get_current_silence_at() - playtime))
|
||||||
|
self.label_end_timer.setText(
|
||||||
|
ms_to_mmss(self.music.get_current_duration() - playtime))
|
||||||
|
|
||||||
def add_to_playlist(self, track):
|
def add_to_playlist(self, track):
|
||||||
"""
|
"""
|
||||||
@ -292,13 +280,15 @@ class DbDialog(QDialog):
|
|||||||
self.parent().add_to_playlist(track)
|
self.parent().add_to_playlist(track)
|
||||||
|
|
||||||
|
|
||||||
def ms_to_mmss(ms, decimals=0):
|
def ms_to_mmss(ms, decimals=0, negative=False):
|
||||||
if not ms:
|
if not ms:
|
||||||
return "-"
|
return "-"
|
||||||
|
sign = ""
|
||||||
if ms < 0:
|
if ms < 0:
|
||||||
sign = "-"
|
if negative:
|
||||||
else:
|
sign = "-"
|
||||||
sign = ""
|
else:
|
||||||
|
ms = 0
|
||||||
|
|
||||||
minutes, remainder = divmod(ms, 60 * 1000)
|
minutes, remainder = divmod(ms, 60 * 1000)
|
||||||
seconds = remainder / 1000
|
seconds = remainder / 1000
|
||||||
|
|||||||
@ -5,20 +5,13 @@ import hashlib
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pytiger.logging.config
|
from config import Config
|
||||||
|
from log import INFO
|
||||||
from tinytag import TinyTag
|
|
||||||
from pydub import AudioSegment
|
|
||||||
|
|
||||||
from model import Tracks, session
|
from model import Tracks, session
|
||||||
|
from pydub import AudioSegment
|
||||||
|
from tinytag import TinyTag
|
||||||
|
|
||||||
|
INFO("Starting")
|
||||||
# "Constants"
|
|
||||||
ROOT = "/home/kae/music"
|
|
||||||
# Instantiate logging
|
|
||||||
pytiger.logging.config.basic_config(stderr=False, level=logging.INFO)
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
log.info("Starting")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -49,8 +42,8 @@ def get_audio_segment(path):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def leading_silence(audio_segment, silence_threshold=-50.0,
|
def leading_silence(audio_segment, silence_threshold=Config.DBFS_SILENCE,
|
||||||
chunk_size=10):
|
chunk_size=Config.AUDIO_SEGMENT_CHUNK_SIZE):
|
||||||
"""
|
"""
|
||||||
Returns the millisecond/index that the leading silence ends.
|
Returns the millisecond/index that the leading silence ends.
|
||||||
audio_segment - the segment to find silence in
|
audio_segment - the segment to find silence in
|
||||||
@ -71,7 +64,7 @@ def leading_silence(audio_segment, silence_threshold=-50.0,
|
|||||||
return min(trim_ms, len(audio_segment))
|
return min(trim_ms, len(audio_segment))
|
||||||
|
|
||||||
|
|
||||||
def fade_point(audio_segment, fade_threshold=-20.0, chunk_size=10):
|
def fade_point(audio_segment, fade_threshold=Config.DBFS_FADE, chunk_size=Config.AUDIO_SEGMENT_CHUNK_SIZE):
|
||||||
"""
|
"""
|
||||||
Returns the millisecond/index of the point where the fade is down to
|
Returns the millisecond/index of the point where the fade is down to
|
||||||
fade_threshold and doesn't get louder again.
|
fade_threshold and doesn't get louder again.
|
||||||
@ -95,7 +88,7 @@ def fade_point(audio_segment, fade_threshold=-20.0, chunk_size=10):
|
|||||||
|
|
||||||
|
|
||||||
def trailing_silence(audio_segment, silence_threshold=-50.0,
|
def trailing_silence(audio_segment, silence_threshold=-50.0,
|
||||||
chunk_size=10):
|
chunk_size=Config.AUDIO_SEGMENT_CHUNK_SIZE):
|
||||||
return fade_point(audio_segment, silence_threshold, chunk_size)
|
return fade_point(audio_segment, silence_threshold, chunk_size)
|
||||||
|
|
||||||
|
|
||||||
@ -107,22 +100,25 @@ def update_db():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
for root, dirs, files in os.walk(ROOT):
|
for root, dirs, files in os.walk(Config.ROOT):
|
||||||
for f in files:
|
for f in files:
|
||||||
count += 1
|
count += 1
|
||||||
path = os.path.join(root, f)
|
path = os.path.join(root, f)
|
||||||
ext = os.path.splitext(f)[1]
|
ext = os.path.splitext(f)[1]
|
||||||
if ext in [".flac", ".mp3"]:
|
if ext in [".flac", ".mp3"]:
|
||||||
track = Tracks.get_or_create(os.path.relpath(path, ROOT))
|
track = Tracks.get_or_create(path)
|
||||||
tag = TinyTag.get(path)
|
tag = TinyTag.get(path)
|
||||||
audio = get_audio_segment(path)
|
audio = get_audio_segment(path)
|
||||||
|
|
||||||
track.title = tag.title
|
track.title = tag.title
|
||||||
track.artist = tag.artist
|
track.artist = tag.artist
|
||||||
track.duration = int(tag.duration * 1000)
|
track.duration = int(round(
|
||||||
|
tag.duration, Config.MILLISECOND_SIGFIGS) * 1000)
|
||||||
track.start_gap = leading_silence(audio)
|
track.start_gap = leading_silence(audio)
|
||||||
track.fade_at = fade_point(audio)
|
track.fade_at = round(
|
||||||
track.silence_at = trailing_silence(audio)
|
fade_point(audio), Config.MILLISECOND_SIGFIGS) * 1000
|
||||||
|
track.silence_at = round(
|
||||||
|
trailing_silence(audio), Config.MILLISECOND_SIGFIGS) * 1000
|
||||||
track.mtime = os.path.getmtime(path)
|
track.mtime = os.path.getmtime(path)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
@ -132,16 +128,5 @@ def update_db():
|
|||||||
print(f"{count} files processed")
|
print(f"{count} files processed")
|
||||||
|
|
||||||
|
|
||||||
def md5(path):
|
|
||||||
"https://stackoverflow.nl9om/questions/3431825/"
|
|
||||||
"generating-an-md5-checksum-of-a-file"
|
|
||||||
|
|
||||||
hash_md5 = hashlib.md5()
|
|
||||||
with open(path, "rb") as f:
|
|
||||||
for chunk in iter(lambda: f.read(4096), b""):
|
|
||||||
hash_md5.update(chunk)
|
|
||||||
return hash_md5.hexdigest()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user