<commit_before>"""Utility functions."""

import application, wx, os, os.path, logging, db
from gui.login_frame import LoginFrame
from config import config
from sqlalchemy.orm.exc import NoResultFound
from gmusicapi.exceptions import NotLoggedIn, AlreadyLoggedIn

logger = logging.getLogger(__name__)

def do_login(callback = lambda *args, **kwargs: None, args = [], kwargs = {}):
 """Try to log in, then call callback."""
 def f(callback, *args, **kwargs):
  application.logging_in = False # Free it up so more login attempts can be made if needed.
  return callback(*args, **kwargs)
 if application.logging_in:
  return # Don't try again.
 application.logging_in = True
 args.insert(0, callback)
 try:
  if not application.api.login(config.login['uid'], config.login['pwd'], application.api.FROM_MAC_ADDRESS):
   return LoginFrame(callback = f, args = args, kwargs = kwargs).Show(True)
 except AlreadyLoggedIn:
  pass
 return f(*args, **kwargs)

def load_playlist(playlist):
 """Load a playlist into the database."""
 try:
  p = db.session.query(db.Playlist).filter(db.Playlist.id == playlist['id']).one()
 except NoResultFound:
  p = db.Playlist()
  p.id = playlist['id']
 db.session.add(p)
 p.name = playlist.get('name', 'Untitled Playlist')
 p.description = playlist.get('description', '')
 p.tracks = []
 for t in playlist.get('tracks', []):
  if 'track' in t:
   track = db.to_object(t['track'])
   p.tracks.append(track)
   i = t['id']
   try:
    e = db.session.query(db.PlaylistEntry).filter(db.PlaylistEntry.id == i, db.PlaylistEntry.track == track, db.PlaylistEntry.playlist == p).one()
   except NoResultFound:
    e = db.PlaylistEntry(playlist = p, track = track, id = t['id'])
   db.session.add(e)
 db.session.commit()
 application.frame.add_playlist(p)
 return p

def do_error(message, title = 'Error'):
 return wx.MessageBox(message, title, style = wx.ICON_EXCLAMATION)

def delete_playlist(playlist):
 """Delete a playlist."""
 try:
  if application.api.delete_playlist(playlist.id) == playlist.id:
   for e in playlist.entries:
    db.session.delete(e)
   db.session.delete(playlist)
   if playlist in application.frame.playlists:
    application.frame.playlists_menu.Delete(application.frame.playlists[playlist])
    del application.frame.playlists[playlist]
   db.session.commit()
   return True
  else:
   return False
 except NotLoggedIn:
  do_login(callback = delete_playlist, args = [playlist])
  return True

def format_track(track):
 """Return track printed as the user likes."""
 return config.interface['result_format'].format(**{x: getattr(track, x) for x in dir(track) if not x.startswith('_')})

def load_station(station):
 """Return a Station object from a dictionary."""
 try:
  s = db.session.query(db.Station).filter(db.Station.id == station['id']).one()
 except NoResultFound:
  s = db.Station(id = station['id'])
 db.session.add(s)
 s.name = station.get('name', 'Untitled Radio Station')
 application.frame.add_station(s)
 return s

def clean_library():
 """Remove unwanted files and directories from the media directory."""
 dir = config.storage['media_dir']
 tracks = ['%s.mp3' % t.id for t in db.session.query(db.Track).all()]
 for thing in os.listdir(dir):
  path = os.path.join(dir, thing)
  if os.path.isdir(path):
   os.removedirs(path)
  else:
   if thing not in tracks:
    os.remove(path)

def prune_library():
 """Delete the least recently downloaded tracks in the catalogue."""
 goal = application.library_size - config.storage['max_size'] * (1024 ** 2)
 if goal > 0:
  logger.info('Pruning %.2f mb of data...', goal / (1024 ** 2))
  for r in db.session.query(db.Track).filter(db.Track.last_played != None).order_by(db.Track.last_played.asc()).all():
   if r.downloaded:
    size = os.path.getsize(r.path)
    logger.info('Deleting %s (%.2f mb).', r, size / (1024 ** 2))
    goal -= size
    application.library_size -= size
    os.remove(r.path)
    if goal <= 0:
     logger.info('Done.')
     break
  else:<commit_msg>Now log what is removed by clean_directory.<commit_after>"""Utility functions."""

import application, wx, os, os.path, logging, db
from gui.login_frame import LoginFrame
from config import config
from sqlalchemy.orm.exc import NoResultFound
from gmusicapi.exceptions import NotLoggedIn, AlreadyLoggedIn

logger = logging.getLogger(__name__)

def do_login(callback = lambda *args, **kwargs: None, args = [], kwargs = {}):
 """Try to log in, then call callback."""
 def f(callback, *args, **kwargs):
  application.logging_in = False # Free it up so more login attempts can be made if needed.
  return callback(*args, **kwargs)
 if application.logging_in:
  return # Don't try again.
 application.logging_in = True
 args.insert(0, callback)
 try:
  if not application.api.login(config.login['uid'], config.login['pwd'], application.api.FROM_MAC_ADDRESS):
   return LoginFrame(callback = f, args = args, kwargs = kwargs).Show(True)
 except AlreadyLoggedIn:
  pass
 return f(*args, **kwargs)

def load_playlist(playlist):
 """Load a playlist into the database."""
 try:
  p = db.session.query(db.Playlist).filter(db.Playlist.id == playlist['id']).one()
 except NoResultFound:
  p = db.Playlist()
  p.id = playlist['id']
 db.session.add(p)
 p.name = playlist.get('name', 'Untitled Playlist')
 p.description = playlist.get('description', '')
 p.tracks = []
 for t in playlist.get('tracks', []):
  if 'track' in t:
   track = db.to_object(t['track'])
   p.tracks.append(track)
   i = t['id']
   try:
    e = db.session.query(db.PlaylistEntry).filter(db.PlaylistEntry.id == i, db.PlaylistEntry.track == track, db.PlaylistEntry.playlist == p).one()
   except NoResultFound:
    e = db.PlaylistEntry(playlist = p, track = track, id = t['id'])
   db.session.add(e)
 db.session.commit()
 application.frame.add_playlist(p)
 return p

def do_error(message, title = 'Error'):
 return wx.MessageBox(message, title, style = wx.ICON_EXCLAMATION)

def delete_playlist(playlist):
 """Delete a playlist."""
 try:
  if application.api.delete_playlist(playlist.id) == playlist.id:
   for e in playlist.entries:
    db.session.delete(e)
   db.session.delete(playlist)
   if playlist in application.frame.playlists:
    application.frame.playlists_menu.Delete(application.frame.playlists[playlist])
    del application.frame.playlists[playlist]
   db.session.commit()
   return True
  else:
   return False
 except NotLoggedIn:
  do_login(callback = delete_playlist, args = [playlist])
  return True

def format_track(track):
 """Return track printed as the user likes."""
 return config.interface['result_format'].format(**{x: getattr(track, x) for x in dir(track) if not x.startswith('_')})

def load_station(station):
 """Return a Station object from a dictionary."""
 try:
  s = db.session.query(db.Station).filter(db.Station.id == station['id']).one()
 except NoResultFound:
  s = db.Station(id = station['id'])
 db.session.add(s)
 s.name = station.get('name', 'Untitled Radio Station')
 application.frame.add_station(s)
 return s

def clean_library():
 """Remove unwanted files and directories from the media directory."""
 dir = config.storage['media_dir']
 tracks = ['%s.mp3' % t.id for t in db.session.query(db.Track).all()]
 for thing in os.listdir(dir):
  path = os.path.join(dir, thing)
  if os.path.isdir(path):
   logger.info('Removing directory %s.', path)
   os.removedirs(path)
  else:
   if thing not in tracks:
    logger.info('Removing file %s.', path)
    os.remove(path)

def prune_library():
 """Delete the least recently downloaded tracks in the catalogue."""
 goal = application.library_size - config.storage['max_size'] * (1024 ** 2)
 if goal > 0:
  logger.info('Pruning %.2f mb of data...', goal / (1024 ** 2))
  for r in db.session.query(db.Track).filter(db.Track.last_played != None).order_by(db.Track.last_played.asc()).all():
   if r.downloaded:
    size = os.path.getsize(r.path)
    logger.info('Deleting %s (%.2f mb).', r, size / (1024 ** 2))
    goal -= size
    application.library_size -= size
    os.remove(r.path)
    if goal <= 0:
     logger.info('Done.')
     break
  else:
{'fraction_non_alphanumeric': 0.15074441687344914, 'fraction_numerical': 0.005210918114143921, 'mean_word_length': 4.2928430728824685, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3779706', 'n_tokens_mistral': 2695, 'n_tokens_neox': 2646, 'n_words': 689}