class AlarmWorker(Worker): def __init__(self, holder): super().__init__(holder) self._config = Config() self._player = MusicPlayer() self._load_alarms() self._time_pattern = re.compile('^([012]\d):(\d\d)$') self._old_time_str = '' self._alarm_is_playing = False def on_connect(self, client, userdata, flags): super().on_connect(client, userdata, flags) client.subscribe(ALARM_TOPIC_SUBSCRIBE) def on_message(self, client, userdata, msg): super().on_message(client, userdata, msg) payload = msg.payload.decode('UTF-8') if msg.topic.startswith(ALARM_TOPIC_ROOT): command = msg.topic.rsplit("/", 1)[-1] if command == 'add': alarm_time = payload if alarm_time != '': rst = self._time_pattern.match(alarm_time) if rst is not None: hour = int(rst.group(1)) minute = int(rst.group(2)) if hour < 24 and minute < 60: alarm = self._find_alarm(alarm_time) if alarm is None: self._alarms.append(Alarm(alarm_time)) else: alarm.enable() self._save_alarms() elif command == 'stop': self._stop_alarm() elif command == 'delete': alarm_time = payload alarm = self._find_alarm(alarm_time) if alarm is not None: self._alarms.remove(alarm) print('delete:', self._alarms) client.publish(msg.topic + '/reply', payload='ok', qos=1) self._save_alarms() else: client.publish(msg.topic + '/reply', payload='Alarm not exist!', qos=1) elif command == 'enable': alarm_time = payload alarm = self._find_alarm(alarm_time) if alarm is not None: alarm.enable() client.publish(msg.topic + '/reply', payload='ok', qos=1) self._save_alarms() else: client.publish(msg.topic + '/reply', payload='Alarm not exist!', qos=1) elif command == 'disable': alarm_time = payload alarm = self._find_alarm(alarm_time) if alarm is not None: alarm.disable() client.publish(msg.topic + '/reply', payload='ok', qos=1) self._save_alarms() else: client.publish(msg.topic + '/reply', payload='Alarm not exist!', qos=1) elif command == 'list_alarm': alarm_list = self._get_alarm_list() print('list:', '{}:{}'.format(payload, ','.join(alarm_list))) client.publish(msg.topic + '/reply', payload='{}:{}'.format(payload, ','.join(alarm_list)), qos=1, retain=True) elif command == 'alarm_at_once': self._play_alarm() def _play_alarm(self): #self._stop_alarm() self._holder.pause_music_players(self) mp3_list = self._get_alarm_mp3_list() mp3_file = random.choice(mp3_list) print('Playing: {}'.format(mp3_file)) self._player.play(mp3_file) # 好像这个音量被 music_worker 干扰了 # 设置不起作用,get_volume 返回 -1! #self._player.set_volume(100) #print('Alarm volume:', self._player.get_volume()) self._alarm_is_playing = True def _stop_alarm(self): self._player.stop() def _get_alarm_list(self): return sorted(['{}{}'.format(alarm.alarm_time, '' if alarm.enabled else ' 已停用') for alarm in self._alarms]) def _find_alarm(self, alarm_time): for alarm in self._alarms: if alarm.alarm_time == alarm_time: return alarm return None def _save_alarms(self): with open(ALARM_SAVE_FILE, 'wb') as f: pickle.dump(self._alarms, f) def _load_alarms(self): self._alarms = [] if os.path.isfile(ALARM_SAVE_FILE): try: with open(ALARM_SAVE_FILE, 'rb')as f: self._alarms = pickle.load(f) except: self._alarms = [] def update(self): super().update() current_time_str = datetime.now().strftime('%H:%M') for alarm in self._alarms: if alarm.enabled: if alarm.alarm_time != self._old_time_str and alarm.alarm_time == current_time_str: self._play_alarm() break self._old_time_str = current_time_str if self._alarm_is_playing: if not self._player.is_playing(): self._alarm_is_playing = False self._holder.resume_music_players(self) def _get_alarm_mp3_list(self): mp3_list = glob.glob('{}/*.mp3'.format(self._config.alarm_mp3_folder)) return mp3_list def pause(self): self._player.pause() def resume(self): self._player.resume()
class MusicWorker(Worker): def __init__(self, holder): super().__init__(holder) random.seed() self._config = Config() self._player = MusicPlayer() self._load_config() def on_connect(self, client, userdata, flags): super().on_connect(client, userdata, flags) client.subscribe(MUSIC_TOPIC_SUBSCRIBE) def on_message(self, client, userdata, msg): super().on_message(client, userdata, msg) payload = msg.payload.decode('UTF-8') if msg.topic.startswith(MUSIC_TOPIC_ROOT): command = msg.topic.rsplit("/", 1)[-1] if command == 'play': mp3_file = payload result = self._play_music(mp3_file) client.publish(msg.topic + '/reply', payload=result, qos=1) elif command == 'stop': self._stop_music() elif command == 'play_random_one': self._play_random_one() elif command == 'list_music': mp3_list = self._get_mp3_list() file_list = [mp3.rsplit('/', 1)[-1] for mp3 in mp3_list] client.publish(msg.topic + '/reply', payload='{}:{}'.format(payload, ','.join(file_list)), qos=1, retain=True) elif command == 'get_volume': volume = self._get_volume() client.publish(msg.topic + '/reply', payload='{}'.format(volume), qos=1, retain=True) elif command == 'set_volume': result = self._set_volume(payload) client.publish(msg.topic + '/reply', payload=result, qos=1) if result == 'ok': client.publish(MUSIC_TOPIC_ROOT + 'get_volume/reply', payload='{}'.format(payload), qos=1, retain=True) def _play_music(self, mp3_file=None, remote_command=True): self._stop_music() result = 'ok' if mp3_file is None or len(mp3_file) == 0: self._player.play(SAFE_MP3) result = 'ok' elif remote_command: if mp3_file.find('..') != -1 or mp3_file.find( '/') != -1 or mp3_file.find('\\') != -1: # bad guy self._player.play(SAFE_MP3) result = 'File not exist!' else: full_path = '{}/{}'.format(self._config.mp3_folder, mp3_file) if os.path.isfile(full_path): self._player.play(full_path) result = 'ok' else: self._player.play(SAFE_MP3) result = 'File not exist!' else: self._player.play(mp3_file) result = 'ok' return result def _stop_music(self): self._player.stop() def _get_mp3_list(self): mp3_list = glob.glob('{}/*.[mM][pP]3'.format(self._config.mp3_folder)) return mp3_list def _play_random_one(self): mp3_list = self._get_mp3_list() mp3_file = random.choice(mp3_list) print('Playing: {}'.format(mp3_file)) self._play_music(mp3_file, remote_command=False) def _get_volume(self): return self._player.get_volume() def _set_volume(self, volume): v = -1 try: v = int(volume) except: pass if v >= 0 and v <= 100: self._player.set_volume(v) self._music_config.volume = v self._save_config() return 'ok' else: return 'volume is valid!' def _save_config(self): with open(MUSIC_SAVE_FILE, 'wb') as f: pickle.dump(self._music_config, f) def _load_config(self): self._music_config = None if os.path.isfile(MUSIC_SAVE_FILE): try: with open(MUSIC_SAVE_FILE, 'rb') as f: self._music_config = pickle.load(f) except: pass if self._music_config is None: self._music_config = MusicConfig() print('Volume:', self._music_config.volume) self._player.set_volume(self._music_config.volume) def pause(self): self._player.pause() # 为了解决 alarm 设置不了音量的问题 # 也不彻底,先这样了! self._player.set_volume(100) def resume(self): self._player.resume() # 为了解决 alarm 设置不了音量的问题 # 也不彻底,先这样了! self._player.set_volume(self._music_config.volume)