Exemplo n.º 1
0
 def search_release_offline(self, id_or_title):
     if is_number(id_or_title):
         try:
             return self.search_release_id(id_or_title)
         except Exception as Exc:
             log.error("Not found or Database Exception: %s\n", Exc)
             raise Exc
     else:
         try:
             releases = self._select_simple(
                 ['*'],
                 'release',
                 'discogs_title LIKE "%{}%" OR d_artist LIKE "%{}%"'.format(
                     id_or_title, id_or_title),
                 fetchone=False,
                 orderby='d_artist')
             if releases:
                 log.debug("First found release: {}".format(releases[0]))
                 log.debug("All found releases: {}".format(releases))
                 return releases  # this is a list
             else:
                 return None
         except Exception as Exc:
             log.error("Not found or Database Exception: %s\n", Exc)
             raise Exc
Exemplo n.º 2
0
 def search_release_online(self, id_or_title):
     try:
         if is_number(id_or_title):
             releases = [self.d.release(id_or_title)]
         else:
             releases = self.d.search(id_or_title, type='release')
         # exceptions are only triggerd if trying to access the release obj
         if len(releases) > 0:  # fixes list index error
             log.info("First found release: {}".format(releases[0]))
         log.debug("All found releases: {}".format(releases))
         return releases
     except discogs_client.exceptions.HTTPError as HtErr:
         log.error("%s (HTTPError)", HtErr)
         return None
     except urllib3.exceptions.NewConnectionError as ConnErr:
         log.error("%s (NewConnectionError)", ConnErr)
         return None
     except urllib3.exceptions.MaxRetryError as RetryErr:
         log.error("%s (MaxRetryError)", RetryErr)
         return None
     except requests.exceptions.ConnectionError as ConnErr:
         log.error("%s (ConnectionError)", ConnErr)
         return None
     except gaierror as GaiErr:
         log.error("%s (socket.gaierror)", GaiErr)
         return None
     except TypeError as TypeErr:
         log.error("%s (TypeError)", TypeErr)
         return None
     except Exception as Exc:
         log.error("%s (Exception)", Exc)
         raise Exc
         return None
Exemplo n.º 3
0
 def print_and_return_first_d_release(self, discogs_results, _searchterm, _db_releases):
     ''' formatted output _and return of Discogs release search results'''
     self.first_track_on_release = '' # reset this in any case first
     # only show pages count if it's a Release Title Search
     if not is_number(_searchterm):
         self.cli.p("Found "+str(discogs_results.pages )+" page(s) of results!")
     else:
         self.cli.p("ID: "+discogs_results[0].id+", Title: "+discogs_results[0].title+"")
     for result_item in discogs_results:
         self.cli.p("Checking " + str(result_item.id))
         for dbr in _db_releases:
             if result_item.id == dbr['discogs_id']:
                 self.cli.p("Good, first matching record in your collection is:")
                 release_details = self.collection.prepare_release_info(result_item)
                 tracklist = self.collection.prepare_tracklist_info(
                     result_item.id, result_item.tracklist)
                 print('{}\n'.format(self.cli.join_links_to_str(dbr)))
                 # we need to pass a list in list here. we use tabulate to view
                 self.cli.tab_online_search_results([release_details])
                 self.cli.online_search_results_tracklist(tracklist)
                 self.first_track_on_release = result_item.tracklist[0].position
                 break
         try:
             if result_item.id == dbr['discogs_id']:
                 #return release_details[0]
                 log.info("Compiled Discogs release_details: {}".format(release_details))
                 return release_details
         except UnboundLocalError:
             log.error("Discogs collection was not imported to DiscoBASE. Use 'disco import' command!")
             #raise unb
             raise SystemExit(1)
     return None
Exemplo n.º 4
0
 def add_release(self, release_id):
     start_time = time()
     self.cli.exit_if_offline(self.collection.ONLINE)
     if not is_number(release_id):
         log.error('Not a number')
         return False
     else:
         # setup.py argparser catches non-int, this is for calls from elsewhere
         if self.collection.search_release_id(release_id):
             msg = "Release ID is already existing in DiscoBASE, "
             msg+= "won't add it to your Discogs collection. We don't want dups!"
             self.cli.p(msg)
         else:
             self.cli.p("Asking Discogs if release ID {:d} is valid.".format(
                    release_id))
             result = self.collection.get_d_release(release_id)
             if result:
                 artists = self.collection.d_artists_to_str(result.artists)
                 d_catno = self.collection.d_get_first_catno(result.labels)
                 log.debug(dir(result))
                 self.cli.p("Adding \"{}\" to collection".format(result.title))
                 for folder in self.collection.me.collection_folders:
                     if folder.id == 1:
                         folder.add_release(release_id)
                         last_row_id = self.collection.create_release(result.id,
                                 result.title, artists, d_catno, d_coll = True)
                 if not last_row_id:
                     self.cli.error_not_the_release()
                 log.debug("Discogs release was maybe added to Collection")
                 self.cli.duration_stats(start_time, 'Adding Release to Collection')
                 return True
             else:
                 log.debug("No Discogs release. Returning False")
                 self.cli.duration_stats(start_time, 'Adding Release to Collection')
                 return False
Exemplo n.º 5
0
 def create(self):
     if is_number(self.mix.name_or_id):
         log.error("Mix name can't be a number!")
     else:
         if self.mix.name_existing:
             log.error('Mix "{}" already existing.'.format(self.mix.name))
             raise SystemExit(1)
         self.cli.p('Creating new mix "{}".'.format(self.mix.name))
         answers = self._create_ask_details()
         created_id = self.mix.create(answers['played'], answers['venue'])
         self.cli.p('New mix created with ID {}.'.format(created_id))
         self.view_mixes_list()
Exemplo n.º 6
0
 def __init__(self, db_conn, mix_name_or_id, db_file=False):
     super(Mix, self).__init__(db_conn, db_file)
     # figuring out names and IDs, just logs and sets instance
     # attributes, no exits here!
     self.name_or_id = mix_name_or_id
     self.id_existing = False
     self.name_existing = False
     self.info = []
     self.name = False
     self.created = False
     self.updated = False
     self.played = False
     self.venue = False
     if is_number(mix_name_or_id):
         self.id = mix_name_or_id
         # if it's a mix-id, get mix-name and info
         try:
             self.info = self.get_mix_info()
             self.name = self.info[1]  # info existing or trigger Exception?
             self.id_existing = True
             self.name_existing = True
         except Exception:
             log.info("Mix ID is not existing yet!")
     else:
         self.name = mix_name_or_id
         # if it's a mix-name, get the id unless it's "all"
         # (default value, should only show mix list)
         if not self.name == "all":
             try:
                 mix_id_tuple = self._get_mix_id(self.name)
                 log.debug('MODEL: mix_id_tuple type: %s',
                           type(mix_id_tuple).__name__)
                 self.id = mix_id_tuple[0]
                 self.id_existing = True
                 self.name_existing = True
                 # load basic mix-info from DB
                 try:
                     self.info = self.get_mix_info()
                     self.name = self.info[1]
                 except Exception:
                     log.info("Can't get mix info.")
             except Exception:
                 log.info("Can't get mix-name from ID. "
                          "Mix not existing yet?")
     if self.id_existing:
         self.created = self.info[2]
         self.played = self.info[4]
         self.venue = self.info[5]
     log.debug("MODEL: Mix info is {}.".format(self.info))
     log.debug("MODEL: Name is {}.".format(self.name))
     log.debug("MODEL: Played is {}.".format(self.played))
     log.debug("MODEL: Venue is {}.".format(self.venue))
Exemplo n.º 7
0
 def _get_mix_id(self, mixname):  # should only be called from __init__
     log.info('MODEL: Getting mix_id via mix name "%s". '
              'Only returns first match', mixname)
     if is_number(mixname):
         log.info("MODEL: mix name is a number, won't try to fetch from DB")
         return mixname
     else:
         self.cur.execute(
             'SELECT mix_id FROM mix WHERE name LIKE ?',
             ("%{}%".format(mixname), )
         )
         row = self.cur.fetchone()
         if row:
             log.info("MODEL: Found mix ID: {}".format(row["mix_id"]))
             return row
         else:
             log.info("MODEL: Can't fetch mix ID by name")
             return row
Exemplo n.º 8
0
    def search_release(self, _searchterm): # online or offline search is decided in this method
        if self.collection.ONLINE:
            if is_number(_searchterm):
                self.cli.p('Searchterm is a number, trying to add Release ID to collection...')
                if not self.add_release(int(_searchterm)):
                    log.warning("Release wasn't added to Collection, continuing anyway.")

            db_releases = self.collection.get_all_db_releases()
            self.cli.p('Searching Discogs for Release ID or Title: {}'.format(_searchterm))
            search_results = self.collection.search_release_online(_searchterm)
            # SEARCH RESULTS OUTPUT HAPPENS HERE
            compiled_results_list = self.print_and_return_first_d_release(
                  search_results, _searchterm, db_releases)
            if compiled_results_list == None:
                self.cli.error_not_the_release()
                m = 'Try altering your search terms!'
                log.info(m)
                print(m)
                raise SystemExit(1)
            return compiled_results_list

        else:
            self.cli.p('Searching database for ID or Title: {}'.format(_searchterm))
            search_results = self.collection.search_release_offline(_searchterm)
            if not search_results:
                self.cli.p('Nothing found.')
                return False
            else:
                #if len(search_results) == 1:
                #    self.cli.p('Found release: {} - {}'.format(search_results[0][3],
                #                                          search_results[0][1]))
                #    return search_results
                #else:
                self.cli.p('Found releases:')
                for cnt,release in enumerate(search_results):
                    self.cli.p('({}) {} - {}'.format(cnt, release[3], release[1]))
                #num_search_results = [[cnt,rel] for cnt,rel in enumerate(search_results)]
                #print(num_search_results)
                answ = self.cli.ask('Which release? (0) ')
                if answ == '':
                    answ = 0
                else:
                    answ = int(answ)
                return [search_results[answ]]
Exemplo n.º 9
0
 def trim_table_fields(self, tuple_table, cut_pos=16, exclude=[]):
     """this method puts \n after a configured amount of characters
     into _all_ fields of a sqlite row objects tuple list"""
     log.info(
         'VIEW: Trimming table field width to max {} chars'.format(cut_pos))
     # first convert list of tuples to list of lists:
     table_nl = [dict(row) for row in tuple_table]
     # now put newlines if longer than cut_pos chars
     for i, row in enumerate(table_nl):
         for key, field in row.items():
             cut_pos_space = False  # reset cut_pos_space on each field cycle
             if (not is_number(field) and field is not None
                     and not key in exclude):
                 if len(field) > cut_pos:
                     cut_pos_space = field.find(" ", cut_pos)
                     log.debug(
                         "cut_pos_space index (next space after cut_pos): %s",
                         cut_pos_space)
                     # don't edit if no space following (almost at end)
                     if cut_pos_space == -1:
                         edited_field = field
                     else:
                         edited_field = field[
                             0:cut_pos_space] + "\n" + field[cut_pos_space +
                                                             1:]
                     log.debug("string from 0 to cut_pos_space: {}".format(
                         field[0:cut_pos_space]))
                     log.debug(
                         "string from cut_pos_space to end: {}".format(
                             field[cut_pos_space:]))
                     log.debug("the final string:")
                     log.debug("{}".format(edited_field))
                     log.debug("")
                     table_nl[i][key] = edited_field
     log.debug("table_nl has {} lines".format(len(table_nl)))
     return table_nl
Exemplo n.º 10
0
    def trim_table_fields(self, tuple_table, cut_pos=16, exclude=[]):
        """this method puts \n after a configured amount of characters
        into _all_ fields of a sqlite row objects tuple list"""
        log.info("VIEW: Trimming table field width "
                 "to max {} chars".format(cut_pos))
        # First convert list of tuples to list of dicts:
        table_nl = [dict(row) for row in tuple_table]
        # Now put newlines if longer than cut_pos chars
        for i, row in enumerate(table_nl):
            for key, field in row.items():
                if (
                    not is_number(field)
                    and field is not None
                    and key not in exclude
                ):
                    field_length = len(field)
                    if field_length < cut_pos:  # Exit early on short fields
                        continue
                    log.debug("String to be cut: {}".format(field))
                    possible_cuts = int(field_length / cut_pos)
                    log.debug("possible_cuts: {}".format(possible_cuts))
                    edited_field = ''
                    prev_cut_pos_space = 0
                    loops = range(1, possible_cuts + 1)
                    log.debug("We will loop {} time(s)".format(len(loops)))

                    # Run as often as cut possibilities exist
                    for cycle in loops:
                        log.debug("Cycle {}/{}".format(cycle, len(loops)))
                        # In each cycle we'll put \n _roughly_around_here_.
                        curr_cut_pos = cut_pos * cycle
                        log.debug("cur_cut_pos: %s", curr_cut_pos)
                        cut_pos_space = field.find(" ", curr_cut_pos)
                        log.debug("Next space after curr_cut_pos is at %s",
                                  cut_pos_space)
                        # If no is space following (almost at end),
                        # don't append newline, just append as-is!
                        if cut_pos_space == -1:
                            log.debug("No more space following. "
                                      "Add part and break loop!")
                            edited_field += field[prev_cut_pos_space:]
                            break
                        else:
                            log.debug("Add part and continue loop "
                                      "(if a cycle left)")
                            edited_field += field[prev_cut_pos_space:cut_pos_space] + "\n"
                        log.debug("From previous cut pos to current: {}".format(
                            field[prev_cut_pos_space:cut_pos_space])
                        )
                        log.debug("")
                        # Save pos for next cycle and skip the space itself,
                        # we don't want following lines to start with a space!
                        prev_cut_pos_space = cut_pos_space + 1

                    if field_length > cut_pos_space and cut_pos_space != -1:
                        log.debug(
                            "Loop done, appending remaining chars: "
                            "{} to {}".format(cut_pos_space, field_length)
                        )
                        # Add 1 to pos, we don't want a leading space.
                        edited_field += field[cut_pos_space + 1:]

                    log.debug("FINAL with newlines:")
                    log.debug("{}".format(edited_field))
                    log.debug("")
                    table_nl[i][key] = edited_field
        log.debug("table_nl has {} lines".format(len(table_nl)))
        return table_nl
Exemplo n.º 11
0
    def _add_track(self, _release_id, _release_title, _track_no, _pos):
        if not _track_no:
            track_to_add = self.cli.ask_for_track()
        else:
            log.debug("_track_no was given, value is {}".format(_track_no))
            track_to_add = _track_no
        if _pos == None:
            log.debug("_pos was None, setting to 0")
            _pos = 0
        log.debug("This is _pos: {}".format(_pos))
        log.debug("This is track_to_add: {}".format(track_to_add))
        log.debug("This is _release_id: %s", _release_id)
        log.debug("This is _release_title: %s", _release_title)
        if self.mix.id_existing:
            last_track = self.mix.get_last_track()
            log.debug("Currently last track in mix is: %s", last_track[0])
            current_id = False
            if _pos:
                # a position to squeeze in the track was given
                # get current tracks >= pos
                tracks_to_shift = self.mix.get_tracks_from_position(_pos)
                if self.cli.really_add_track(track_to_add, _release_title,
                                             self.mix.id, _pos):
                    current_id = self.mix.add_track(_release_id,
                                                    track_to_add, track_pos = _pos)
                    # all good? reorder tracks
                    if current_id:
                        log.info("Add track to mix successful, now reordering ...")
                        self.mix.reorder_tracks_squeeze_in(_pos, tracks_to_shift)
                else:
                    print("Track not added.")
                    return True
            elif is_number(last_track[0]):
                # no position was given, tracks already mix
                if self.cli.really_add_track(track_to_add, _release_title,
                                             self.mix.id, last_track[0]+1):

                    current_id = self.mix.add_track(_release_id,
                                                    track_to_add, track_pos = last_track[0] + 1)
                else:
                    print("Track not added.")
                    return True
            else:
                # no position and it's the first track ever added
                if self.cli.really_add_track(track_to_add, _release_title,
                                             self.mix.id, 1):

                    current_id = self.mix.add_track(_release_id,
                                                    track_to_add, track_pos = 1)
                else:
                    print("Track not added.")
                    return True
            # FIXME untested if this is actually a proper sanity check
            log.debug("Value of current_id in add_offline_track: {}".format(current_id))
            if current_id:
                self.view()
                #return True
            else:
                log.error("Add track to DB failed!")
                #return False
        else:
            self.cli.p("Mix ID {} is not existing yet.".format(self.mix.id))
            return False
Exemplo n.º 12
0
    def edit_ask_details(self, orig_data, edit_questions):
        # collect answers from user input
        answers = {}
        for db_field, question in edit_questions:
            # some special treatments for track_pos handling...
            if db_field == 'track_pos':
                answers['track_pos'] = self.ask(
                    question.format(orig_data['track_pos']))
                if answers['track_pos'] == '':
                    log.info("Answer was empty, dropping item from update.")
                    del (answers['track_pos'])
                elif not is_number(answers['track_pos']):
                    while not is_number(answers['track_pos']):
                        log.warning("Answer was not a number, asking again.")
                        if answers['track_pos'] == '':
                            del (answers['track_pos'])
                            break
                        else:
                            answers['track_pos'] = self.ask(
                                question.format(orig_data['track_pos']))
                else:
                    move_to = int(answers['track_pos'])
                    if move_to < orig_data['track_pos']:
                        mvmsg = 'Note: Tracks new position will be right _before_ '
                        mvmsg += 'current track {}'.format(move_to)
                        log.debug(mvmsg)
                        print(mvmsg)
                    elif move_to > orig_data['track_pos']:
                        mvmsg = 'Note: Tracks new position will be right _after_ '
                        mvmsg += 'current track {}'.format(move_to)
                        log.debug(mvmsg)
                        print(mvmsg)
            elif db_field == 'trans_rating':
                allowed = ['++', '+', '~', '-', '--']
                answers['trans_rating'] = self.ask(
                    question.format(orig_data['trans_rating']))
                if answers['trans_rating'] == '':
                    log.info("Answer was empty, dropping item from update.")
                    del (answers['trans_rating'])
                else:
                    while not answers['trans_rating'] in allowed:
                        log.warning(
                            "Please use one of the following: ++, +, ~, -, --")
                        if answers['trans_rating'] == '':
                            del (answers['trans_rating'])
                            break
                        else:
                            answers['trans_rating'] = self.ask(
                                question.format(orig_data['trans_rating']))
            elif db_field == 'name':
                # initial user question
                answers['name'] = self.ask(question.format(orig_data['name']))
                # sanity checking loop
                while answers['name'] == orig_data['name']:
                    log.warning("Just press enter if you want to leave as-is.")
                    answers['name'] = self.ask(
                        question.format(orig_data['name']))
                # after loop we know that existing and new are different
                # if answer is empty, leave as-is (no empty mixname allowed)
                if answers['name'] == '':
                    log.info("Answer was empty, dropping item from update.")
                    del (answers['name'])
            else:
                answers[db_field] = self.ask(
                    question.format(orig_data[db_field]))
                if answers[db_field] == "":
                    log.info("Answer was empty, dropping item from update.")
                    del (answers[db_field])

        log.debug("CTRL: _edit_ask_details: answers dict: {}".format(answers))
        return answers