def get_next_neighbour(self, p_node_name_now : str, p_mpdj_data : MPDJData, p_play_data : PlayData, p_mpd_connection : MPDConnection) -> str: """Returns the next neighbour, according to a random choice weighted by songs in collected divided by 1 plays of songs in this node.""" random.seed() neighbour_node_names = p_mpdj_data.get_neighbours_for_node_name(p_node_name_now) # If node does not have any neighbours, we will select a random one from the set # of all neighbours. if len(neighbour_node_names) < 1: print('No neighbours for {} considering all nodes as next'.format(p_node_name_now)) neighbour_node_names = p_mpdj_data.get_song_selection_names() if len(neighbour_node_names) > 1 and p_play_data.previous_node in neighbour_node_names: neighbour_node_names.remove(p_play_data.previous_node) nodes_with_song_count_not_zero = self.get_possible_next_neighbours(p_node_name_now, p_mpdj_data, p_play_data, p_mpd_connection) node_weights = calculate_node_weight_with_song_play_count( p_play_data, list(nodes_with_song_count_not_zero.values())) choice = random.choices(population=[*nodes_with_song_count_not_zero], weights=node_weights,k=1) return choice[0]
def new_mpdj(self): """Creates a new mpdj data to work on (empties all the data currently loaded)""" self.mpdj_data = MPDJData() self.mpdj_data.add_function_to_call_on_change(inform_about_changes_in_mpdj) self.path_of_current_file = '' self.changes_happened_since_last_save = False self.inform_update_listener()
def get_next_neighbour(self, p_node_name_now : str, p_mpdj_data : MPDJData, p_play_data : PlayData, p_mpd_connection : MPDConnection) -> str: """Return the next node by selecting the one with minimal average play count. When more than on has minimal play count, the next one will be on of those with minimum play count, selected randomly.""" random.seed() neighbour_node_names = p_mpdj_data.get_neighbours_for_node_name(p_node_name_now) print (neighbour_node_names) candidates_with_minimal_average_play_count = list() min_average = math.inf if p_play_data.previous_node and p_play_data.previous_node in neighbour_node_names: neighbour_node_names.remove(p_play_data.previous_node) for node_name in neighbour_node_names: node = p_mpdj_data.song_selections[node_name] songs_of_node = node.get_songs(p_mpd_connection) song_count = len(songs_of_node) if song_count == 0: continue playcount = reduce(lambda x,y: x+y, (map(lambda song: p_play_data.get_play_count_of_song_value(song['file'], 'file'), songs_of_node))) play_count_average = float(playcount) / float (song_count) print ("Node: {}: {}".format(node_name,play_count_average)) if play_count_average < min_average: candidates_with_minimal_average_play_count = list() min_average = play_count_average if play_count_average <= min_average: candidates_with_minimal_average_play_count.append(node_name) print (candidates_with_minimal_average_play_count) choice = random.choice(candidates_with_minimal_average_play_count) print (choice) return choice
def get_possible_next_neighbours(self, p_node_name_now : str, p_mpdj_data : MPDJData, p_play_data : PlayData, p_mpd_connection : MPDConnection): """Returns those neighbors who could be selected as next neighbors. Dependent of p_node_name_now, p_mpdj_data, p_play_data and p_mpd_connection.""" neighbours_in_graph = p_mpdj_data.get_neighbours_for_node_name(p_node_name_now) if len(neighbours_in_graph) < 1: print('No neighbours for {} considering all nodes as next'.format(p_node_name_now)) neighbours_in_graph = p_mpdj_data.get_song_selection_names() if len(neighbours_in_graph) > 1 and p_play_data.previous_node in neighbours_in_graph: neighbours_in_graph.remove(p_play_data.previous_node) neighbours_with_song_count_not_zero = dict() for node in neighbours_in_graph: songs_in_node = p_mpdj_data.get_song_selection_by_name(node).get_songs(p_mpd_connection) if len(songs_in_node) == 0: sys.stderr.write('Node {} has now songs, ignoring it.'.format(node)) sys.stderr.flush() continue neighbours_with_song_count_not_zero[node] = songs_in_node return neighbours_with_song_count_not_zero
def __init__(self, pHost, pPort): ''' Constructor ''' self.mpdj_data = MPDJData() self.mpd_connection = MPDConnection(pHost, pPort) self.keep_running = True self.play_data = PlayData() self.node_selector = NodeSelectionMinimalAveragePlaycountWeightedProbabilities( ) self.song_selector = SongSelectorMinimalPlayCount()
def __init__(self): """ Virtually private constructor. """ if GlobalProperties.__instance is not None: raise Exception("This class is a singleton!") if os.path.isfile('./path_of_file'): self.load_config_from_file() else: GlobalProperties.__instance = self # The momentary connection we are using. self.mpd_connection = MPDConnection('localhost', '6600') self.mpd_connection.connect() # The momentary MPDJ data. self.mpdj_data = MPDJData() self.mpdj_data.add_function_to_call_on_change(inform_about_changes_in_mpdj) # The update listeners which are informed about changes. self.update_listeners = [] # The path of the file which we are working on self._path_of_current_file = '' # Indicates changes since the last save or load operation. self._changes_happened_since_last_save = False # Edit connections so the graph the graph simulates an undirected graph # self.edit_both_directions = True # The current opened windows. self.opened_windows = list()
def get_next_neighbour(self, p_node_now : str, p_mpdj_data : MPDJData, p_play_data : PlayData, p_mpd_connection : MPDConnection) -> str: """Returns the node with the minimum playcount, not weighted at all.""" random.seed() neighbour_nodes = p_mpdj_data.get_neighbours_for_node_name(p_node_now) min_node_play_count = math.inf next_node_candidates = [] for node in neighbour_nodes: node_play_count = p_play_data.node_play_count[node] if node_play_count < min_node_play_count: min_node_play_count = node_play_count next_node_candidates = [] if node_play_count <= min_node_play_count: next_node_candidates.append(node) if p_play_data.previous_node and p_play_data in next_node_candidates: next_node_candidates.remove(p_play_data.previous_node.get_name()) return random.choice(next_node_candidates)
class GlobalProperties(): """This singleton contains stuff, which needs to be accessible from everywhere in mpdj.""" __instance = None @staticmethod def get_instance(): """Static access method.""" if GlobalProperties.__instance is None: GlobalProperties() return GlobalProperties.__instance @property def changes_happened_since_last_save(self): """Indicates if changes happened since last save.""" return self._changes_happened_since_last_save @changes_happened_since_last_save.setter def changes_happened_since_last_save(self, p_new_value): self._changes_happened_since_last_save = p_new_value @changes_happened_since_last_save.deleter def changes_happened_since_last_save(self): del self._changes_happened_since_last_save @property def path_of_current_file(self): """The currently opened file.""" if not hasattr(self, '_path_of_current_file'): self._path_of_current_file = '' return self._path_of_current_file @path_of_current_file.setter def path_of_current_file(self,p_new_path): self._path_of_current_file = p_new_path @path_of_current_file.deleter def path_of_current_file(self): del self._path_of_current_file def add_listener(self, p_listener): """Adds a listener so if anything changes the listener will be informed.""" self.update_listeners.append(p_listener) def load_config_from_file(self): """This sould load a config from a config file. Not implemented, yet.""" #TODO def inform_update_listener(self): """This method inform all added listeners about changes.""" for update_listener in self.update_listeners: update_listener.update() def save_mpdj_data_to_file(self, p_file_name): """Write the momentary MPDJ-data to p_file_name.""" with open(p_file_name, 'w') as save_file: save_file.write(jsonpickle.encode(self.mpdj_data)) self.changes_happened_since_last_save = False self.path_of_current_file = p_file_name self.inform_update_listener() def load_mpdjdata_from_file(self, p_file_name): """Loads a mpdj file, overwrite the momentary MPDJ-data.""" with open(p_file_name, 'r') as load_file: self.mpdj_data = jsonpickle.decode(load_file.read()) self.mpdj_data.add_function_to_call_on_change(inform_about_changes_in_mpdj) self.changes_happened_since_last_save = False self.path_of_current_file = p_file_name self.inform_update_listener() def new_mpdj(self): """Creates a new mpdj data to work on (empties all the data currently loaded)""" self.mpdj_data = MPDJData() self.mpdj_data.add_function_to_call_on_change(inform_about_changes_in_mpdj) self.path_of_current_file = '' self.changes_happened_since_last_save = False self.inform_update_listener() def __init__(self): """ Virtually private constructor. """ if GlobalProperties.__instance is not None: raise Exception("This class is a singleton!") if os.path.isfile('./path_of_file'): self.load_config_from_file() else: GlobalProperties.__instance = self # The momentary connection we are using. self.mpd_connection = MPDConnection('localhost', '6600') self.mpd_connection.connect() # The momentary MPDJ data. self.mpdj_data = MPDJData() self.mpdj_data.add_function_to_call_on_change(inform_about_changes_in_mpdj) # The update listeners which are informed about changes. self.update_listeners = [] # The path of the file which we are working on self._path_of_current_file = '' # Indicates changes since the last save or load operation. self._changes_happened_since_last_save = False # Edit connections so the graph the graph simulates an undirected graph # self.edit_both_directions = True # The current opened windows. self.opened_windows = list()