Run file import in separate thread
This commit is contained in:
parent
e2af6dd7ac
commit
c7f7f25af0
@ -54,6 +54,7 @@ class Config(object):
|
|||||||
NORMALISE_ON_IMPORT = True
|
NORMALISE_ON_IMPORT = True
|
||||||
NOTE_TIME_FORMAT = "%H:%M:%S"
|
NOTE_TIME_FORMAT = "%H:%M:%S"
|
||||||
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
||||||
|
IMPORT_DESTINATION = os.path.join(ROOT, "Singles")
|
||||||
SCROLL_TOP_MARGIN = 3
|
SCROLL_TOP_MARGIN = 3
|
||||||
TESTMODE = True
|
TESTMODE = True
|
||||||
TOD_TIME_FORMAT = "%H:%M:%S"
|
TOD_TIME_FORMAT = "%H:%M:%S"
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import argparse
|
|||||||
import os.path
|
import os.path
|
||||||
import psutil
|
import psutil
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QLineEdit,
|
QLineEdit,
|
||||||
QListWidgetItem,
|
QListWidgetItem,
|
||||||
QMainWindow,
|
QMainWindow,
|
||||||
|
QMessageBox,
|
||||||
)
|
)
|
||||||
|
|
||||||
import dbconfig
|
import dbconfig
|
||||||
@ -420,18 +422,51 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
dlg = QFileDialog()
|
dlg = QFileDialog()
|
||||||
dlg.setFileMode(QFileDialog.ExistingFiles)
|
dlg.setFileMode(QFileDialog.ExistingFiles)
|
||||||
dlg.setViewMode(QFileDialog.Detail)
|
dlg.setViewMode(QFileDialog.Detail)
|
||||||
# TODO: remove hardcoded directory
|
dlg.setDirectory(Config.IMPORT_DESTINATION)
|
||||||
dlg.setDirectory(os.path.join(Config.ROOT, "Singles"))
|
|
||||||
dlg.setNameFilter("Music files (*.flac *.mp3)")
|
dlg.setNameFilter("Music files (*.flac *.mp3)")
|
||||||
|
|
||||||
if dlg.exec_():
|
if dlg.exec_():
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
|
txt: str = ""
|
||||||
|
new_tracks = []
|
||||||
for fname in dlg.selectedFiles():
|
for fname in dlg.selectedFiles():
|
||||||
track = create_track_from_file(session, fname)
|
tags = helpers.get_tags(fname)
|
||||||
# Add to playlist on screen
|
new_tracks.append((fname, tags))
|
||||||
# If we don't specify "repaint=False", playlist will
|
title = tags['title']
|
||||||
# also be saved to database
|
artist = tags['artist']
|
||||||
self.visible_playlist_tab().insert_track(session, track)
|
possible_matches = Tracks.search_titles(session, title)
|
||||||
|
if possible_matches:
|
||||||
|
txt += 'Similar to new track '
|
||||||
|
txt += f'"{title}" by "{artist}":\n'
|
||||||
|
for track in possible_matches:
|
||||||
|
txt += f' "{track.title}" by {track.artist}\n'
|
||||||
|
txt += "\n"
|
||||||
|
# Check whether to proceed if there were potential matches
|
||||||
|
if txt:
|
||||||
|
txt += "Proceed with import?"
|
||||||
|
result = QMessageBox.question(self,
|
||||||
|
"Possible duplicates",
|
||||||
|
txt,
|
||||||
|
QMessageBox.Ok,
|
||||||
|
QMessageBox.Cancel
|
||||||
|
)
|
||||||
|
if result == QMessageBox.Cancel:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Import in separate thread
|
||||||
|
thread = threading.Thread(target=self._import_tracks,
|
||||||
|
args=(session, new_tracks))
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
def _import_tracks(self, session: Session, tracks: list):
|
||||||
|
"""Import passed files"""
|
||||||
|
|
||||||
|
for (fname, tags) in tracks:
|
||||||
|
track = create_track_from_file(session, fname, tags=tags)
|
||||||
|
# Add to playlist on screen
|
||||||
|
# If we don't specify "repaint=False", playlist will
|
||||||
|
# also be saved to database
|
||||||
|
self.visible_playlist_tab().insert_track(session, track)
|
||||||
|
|
||||||
def load_last_playlists(self):
|
def load_last_playlists(self):
|
||||||
"""Load the playlists that we loaded at end of last session"""
|
"""Load the playlists that we loaded at end of last session"""
|
||||||
|
|||||||
@ -38,7 +38,6 @@ def main():
|
|||||||
group.add_argument('-f', '--full-update',
|
group.add_argument('-f', '--full-update',
|
||||||
action="store_true", dest="full_update",
|
action="store_true", dest="full_update",
|
||||||
default=False, help="Update database")
|
default=False, help="Update database")
|
||||||
group.add_argument('-i', '--import', dest="fname", help="Input file")
|
|
||||||
args = p.parse_args()
|
args = p.parse_args()
|
||||||
|
|
||||||
# Run as required
|
# Run as required
|
||||||
@ -50,18 +49,13 @@ def main():
|
|||||||
DEBUG("Full update of database")
|
DEBUG("Full update of database")
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
full_update_db(session)
|
full_update_db(session)
|
||||||
elif args.fname:
|
|
||||||
fname = os.path.realpath(args.fname)
|
|
||||||
with Session() as session:
|
|
||||||
create_track_from_file(session, fname, interactive=True)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
INFO("No action specified")
|
INFO("No action specified")
|
||||||
|
|
||||||
DEBUG("Finished")
|
DEBUG("Finished")
|
||||||
|
|
||||||
|
|
||||||
def create_track_from_file(session, path, normalise=None, interactive=False):
|
def create_track_from_file(session, path, normalise=None, tags=None):
|
||||||
"""
|
"""
|
||||||
Create track in database from passed path, or update database entry
|
Create track in database from passed path, or update database entry
|
||||||
if path already in database.
|
if path already in database.
|
||||||
@ -69,34 +63,14 @@ def create_track_from_file(session, path, normalise=None, interactive=False):
|
|||||||
Return track.
|
Return track.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if interactive:
|
if not tags:
|
||||||
msg = f"Importing {path}"
|
t = get_tags(path)
|
||||||
INFO(msg)
|
else:
|
||||||
INFO("-" * len(msg))
|
t = tags
|
||||||
INFO("Get track info...")
|
|
||||||
t = get_tags(path)
|
|
||||||
title = t['title']
|
|
||||||
artist = t['artist']
|
|
||||||
if interactive:
|
|
||||||
INFO(f" Title: \"{title}\"")
|
|
||||||
INFO(f" Artist: \"{artist}\"")
|
|
||||||
# Check for duplicate
|
|
||||||
if interactive:
|
|
||||||
tracks = Tracks.search_titles(session, title)
|
|
||||||
if tracks:
|
|
||||||
print("Found the following possible matches:")
|
|
||||||
for track in tracks:
|
|
||||||
print(f'"{track.title}" by {track.artist}')
|
|
||||||
response = input("Continue [c] or abort [a]?")
|
|
||||||
if not response:
|
|
||||||
return
|
|
||||||
if response[0].lower() not in ['c', 'y']:
|
|
||||||
return
|
|
||||||
track = Tracks.get_or_create(session, path)
|
track = Tracks.get_or_create(session, path)
|
||||||
track.title = title
|
track.title = t['title']
|
||||||
track.artist = artist
|
track.artist = t['artist']
|
||||||
if interactive:
|
|
||||||
INFO("Parse for start, fade and silence...")
|
|
||||||
audio = get_audio_segment(path)
|
audio = get_audio_segment(path)
|
||||||
track.duration = len(audio)
|
track.duration = len(audio)
|
||||||
track.start_gap = leading_silence(audio)
|
track.start_gap = leading_silence(audio)
|
||||||
@ -108,8 +82,6 @@ def create_track_from_file(session, path, normalise=None, interactive=False):
|
|||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
if normalise or normalise is None and Config.NORMALISE_ON_IMPORT:
|
if normalise or normalise is None and Config.NORMALISE_ON_IMPORT:
|
||||||
if interactive:
|
|
||||||
INFO("Normalise...")
|
|
||||||
# Check type
|
# Check type
|
||||||
ftype = os.path.splitext(path)[1][1:]
|
ftype = os.path.splitext(path)[1][1:]
|
||||||
if ftype not in ['mp3', 'flac']:
|
if ftype not in ['mp3', 'flac']:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user