Revert "adding cleanup of stale track entries"
This reverts commit 1a2506742f
.
This commit is contained in:
parent
1a2506742f
commit
4b6246096d
|
@ -106,7 +106,6 @@ def scan(
|
||||||
initialize()
|
initialize()
|
||||||
with database_manager() as manager:
|
with database_manager() as manager:
|
||||||
scanner = media_scanner(root=root, db=manager.session)
|
scanner = media_scanner(root=root, db=manager.session)
|
||||||
scanner.cleanup()
|
|
||||||
count = scanner.scan()
|
count = scanner.scan()
|
||||||
logging.info(f"Imported {count} new tracks.")
|
logging.info(f"Imported {count} new tracks.")
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import music_tag
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Callable, Union, Iterable
|
from typing import Callable, Union, Iterable
|
||||||
from sqlalchemy import func, delete
|
from sqlalchemy import func
|
||||||
|
|
||||||
import groove.db
|
import groove.db
|
||||||
import groove.path
|
import groove.path
|
||||||
|
@ -40,31 +40,10 @@ class MediaScanner:
|
||||||
async def _do_import():
|
async def _do_import():
|
||||||
logging.debug("Scanning filesystem (this may take a minute)...")
|
logging.debug("Scanning filesystem (this may take a minute)...")
|
||||||
for path in sources:
|
for path in sources:
|
||||||
if path.exists() and not path.is_dir():
|
asyncio.create_task(self._import_one_track(path))
|
||||||
asyncio.create_task(self._import_one_track(path))
|
|
||||||
asyncio.run(_do_import())
|
asyncio.run(_do_import())
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
def cleanup(self) -> int:
|
|
||||||
"""
|
|
||||||
Check for the existence of every track in the databse.
|
|
||||||
"""
|
|
||||||
async def _del(track):
|
|
||||||
path = self.root / Path(track.relpath)
|
|
||||||
if path.exists():
|
|
||||||
return
|
|
||||||
logging.info(f"Deleting missing track {track.relpath}")
|
|
||||||
self.db.execute(
|
|
||||||
delete(groove.db.track).where(groove.db.track.c.id == track.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _do_cleanup():
|
|
||||||
logging.debug("Locating stale track definitions in the database...")
|
|
||||||
for track in self.db.query(groove.db.track).all():
|
|
||||||
asyncio.create_task(_del(track))
|
|
||||||
asyncio.run(_do_cleanup())
|
|
||||||
self.db.commit()
|
|
||||||
|
|
||||||
def _get_tags(self, path): # pragma: no cover
|
def _get_tags(self, path): # pragma: no cover
|
||||||
tags = music_tag.load_file(path)
|
tags = music_tag.load_file(path)
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Playlist:
|
||||||
@property
|
@property
|
||||||
def info(self):
|
def info(self):
|
||||||
count = len(self.entries)
|
count = len(self.entries)
|
||||||
return f"{self.name}: {self.url} [{count} tracks]\n{self.description}"
|
return f"{self.name}: {self.url} [{count} tracks]\n{self.description}\n"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self) -> str:
|
def url(self) -> str:
|
||||||
|
@ -133,7 +133,7 @@ class Playlist:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_string(self) -> str:
|
def as_string(self) -> str:
|
||||||
text = self.info + self.description
|
text = self.info
|
||||||
for (tracknum, entry) in enumerate(self.entries):
|
for (tracknum, entry) in enumerate(self.entries):
|
||||||
text += f" - {tracknum+1} {entry.artist} - {entry.title}\n"
|
text += f" - {tracknum+1} {entry.artist} - {entry.title}\n"
|
||||||
return text
|
return text
|
||||||
|
|
|
@ -14,11 +14,6 @@ class BasePrompt(Completer):
|
||||||
self._values = []
|
self._values = []
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self._manager = manager
|
self._manager = manager
|
||||||
self._commands = {'help': self.help}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def commands(self):
|
|
||||||
return self._commands
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self):
|
def usage(self):
|
||||||
|
@ -45,7 +40,7 @@ class BasePrompt(Completer):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def values(self):
|
def values(self):
|
||||||
return [k for k in self.commands.keys() if not k.startswith('_')]
|
return self._values
|
||||||
|
|
||||||
def get_completions(self, document, complete_event):
|
def get_completions(self, document, complete_event):
|
||||||
word = document.get_word_before_cursor()
|
word = document.get_word_before_cursor()
|
||||||
|
@ -64,7 +59,7 @@ class BasePrompt(Completer):
|
||||||
def start(self, cmd=''):
|
def start(self, cmd=''):
|
||||||
while True:
|
while True:
|
||||||
if not cmd:
|
if not cmd:
|
||||||
cmd = prompt(f'{self.prompt} ', completer=self, complete_while_typing=True)
|
cmd = prompt(f'{self.prompt} ', completer=self)
|
||||||
if not cmd:
|
if not cmd:
|
||||||
return
|
return
|
||||||
cmd, *parts = cmd.split()
|
cmd, *parts = cmd.split()
|
||||||
|
@ -72,13 +67,6 @@ class BasePrompt(Completer):
|
||||||
return
|
return
|
||||||
cmd = ''
|
cmd = ''
|
||||||
|
|
||||||
def help(self, parts):
|
|
||||||
if not parts:
|
|
||||||
print(self.__doc__)
|
|
||||||
else:
|
|
||||||
print(getattr(self, parts[0]).__doc__)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def default_completer(self, document, complete_event):
|
def default_completer(self, document, complete_event):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ class CommandPrompt(BasePrompt):
|
||||||
session=self.manager.session,
|
session=self.manager.session,
|
||||||
create_ok=True
|
create_ok=True
|
||||||
)
|
)
|
||||||
self.commands['_playlist'].start()
|
res = self.commands['_playlist'].start()
|
||||||
return True
|
return True and res
|
||||||
|
|
||||||
|
|
||||||
def start(): # pragma: no cover
|
def start(): # pragma: no cover
|
||||||
|
|
|
@ -8,14 +8,21 @@ from groove import db
|
||||||
|
|
||||||
|
|
||||||
class _playlist(BasePrompt):
|
class _playlist(BasePrompt):
|
||||||
"""
|
|
||||||
PLAYLIST
|
def __init__(self, parent, manager=None):
|
||||||
"""
|
super().__init__(manager=manager, parent=parent)
|
||||||
|
self._parent = parent
|
||||||
|
self._prompt = ''
|
||||||
|
self._commands = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def prompt(self):
|
def prompt(self):
|
||||||
return f"{self.parent.playlist}\n{self.parent.playlist.slug}> "
|
return f"{self.parent.playlist}\n{self.parent.playlist.slug}> "
|
||||||
|
|
||||||
|
@property
|
||||||
|
def values(self):
|
||||||
|
return self.commands.keys()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def commands(self):
|
def commands(self):
|
||||||
if not self._commands:
|
if not self._commands:
|
||||||
|
@ -24,20 +31,9 @@ class _playlist(BasePrompt):
|
||||||
'delete': self.delete,
|
'delete': self.delete,
|
||||||
'add': self.add,
|
'add': self.add,
|
||||||
'edit': self.edit,
|
'edit': self.edit,
|
||||||
'help': self.help
|
|
||||||
}
|
}
|
||||||
return self._commands
|
return self._commands
|
||||||
|
|
||||||
def _add_track(self, text):
|
|
||||||
sess = self.parent.manager.session
|
|
||||||
try:
|
|
||||||
track = sess.query(db.track).filter(db.track.c.relpath == text).one()
|
|
||||||
self.parent.playlist.create_entries([track])
|
|
||||||
except NoResultFound:
|
|
||||||
print("No match for '{text}'")
|
|
||||||
return
|
|
||||||
return text
|
|
||||||
|
|
||||||
def process(self, cmd, *parts):
|
def process(self, cmd, *parts):
|
||||||
res = True
|
res = True
|
||||||
if cmd in self.commands:
|
if cmd in self.commands:
|
||||||
|
@ -70,6 +66,16 @@ class _playlist(BasePrompt):
|
||||||
return True
|
return True
|
||||||
self._add_track(text)
|
self._add_track(text)
|
||||||
|
|
||||||
|
def _add_track(self, text):
|
||||||
|
sess = self.parent.manager.session
|
||||||
|
try:
|
||||||
|
track = sess.query(db.track).filter(db.track.c.relpath == text).one()
|
||||||
|
self.parent.playlist.create_entries([track])
|
||||||
|
except NoResultFound:
|
||||||
|
print("No match for '{text}'")
|
||||||
|
return
|
||||||
|
return text
|
||||||
|
|
||||||
def delete(self, parts):
|
def delete(self, parts):
|
||||||
res = prompt(
|
res = prompt(
|
||||||
'Type DELETE to permanently delete the playlist '
|
'Type DELETE to permanently delete the playlist '
|
||||||
|
|
0
test/fixtures/themes/alt_theme/static
vendored
0
test/fixtures/themes/alt_theme/static
vendored
|
@ -38,10 +38,6 @@ def test_scanner(monkeypatch, in_memory_db, media):
|
||||||
# replace the filesystem glob with the test fixture generator
|
# replace the filesystem glob with the test fixture generator
|
||||||
monkeypatch.setattr(scanner.MediaScanner, 'find_sources', MagicMock(return_value=media()))
|
monkeypatch.setattr(scanner.MediaScanner, 'find_sources', MagicMock(return_value=media()))
|
||||||
|
|
||||||
# pretend things exist
|
|
||||||
monkeypatch.setattr(scanner.Path, 'exists', MagicMock(return_value=True))
|
|
||||||
monkeypatch.setattr(scanner.Path, 'is_dir', MagicMock(return_value=False))
|
|
||||||
|
|
||||||
def mock_loader(path):
|
def mock_loader(path):
|
||||||
return {
|
return {
|
||||||
'artist': 'foo',
|
'artist': 'foo',
|
||||||
|
|
|
@ -16,10 +16,6 @@ def response_factory(responses):
|
||||||
return MagicMock(side_effect=responses + ([''] * 10))
|
return MagicMock(side_effect=responses + ([''] * 10))
|
||||||
|
|
||||||
|
|
||||||
def test_commands(cmd_prompt):
|
|
||||||
assert cmd_prompt.commands.keys() == cmd_prompt.commands.keys()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('inputs, expected', [
|
@pytest.mark.parametrize('inputs, expected', [
|
||||||
(['stats'], 'Database contains 4 playlists'), # match the db fixture
|
(['stats'], 'Database contains 4 playlists'), # match the db fixture
|
||||||
])
|
])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user