def load_cookies(self): try: with open(DATA_PATH + self.cookies_filename) as f: data_str = f.read() self.cookies = json.loads(data_str) except Exception as e: LOG.error(str(e))
def load_user_infos(cls, data): avatar_url = data['avatar'] request = QNetworkRequest(QUrl(avatar_url)) cls.controller.network_manager.get(request) cls.controller.network_manager.network_queue.put(ViewOp.set_login_label_avatar) ViewOp.ui.MY_LIST_WIDGET.empty_layout() ViewOp.ui.COLLECTION_LIST_WIDGET.empty_layout() playlists = cls.controller.api.get_user_playlist() if not cls.controller.api.is_response_ok(playlists): return playlist_num = len(playlists) for playlist in playlists: pid = playlist['id'] w = PlaylistItem() w.set_playlist_item(playlist) w.signal_text_btn_clicked.connect(cls.on_playlist_btn_clicked) if cls.controller.api.is_playlist_mine(playlist): ViewOp.ui.MY_LIST_WIDGET.layout().addWidget(w) if pid == cls.controller.api.favorite_pid: favorite_playlist_detail = cls.controller.api.get_playlist_detail(pid) cls.controller.state["current_pid"] = pid ViewOp.ui.WEBVIEW.load_playlist(favorite_playlist_detail) else: if playlist_num <= 50: app_event_loop = asyncio.get_event_loop() app_event_loop.call_soon(cls.controller.api.get_playlist_detail, pid) else: ViewOp.ui.COLLECTION_LIST_WIDGET.layout().addWidget(w) LOG.info('load user infos finished')
def keyboard_tap_callback(proxy, type_, event, refcon): from AppKit import NSKeyUp, NSEvent if type_ < 0 or type_ > 0x7fffffff: LOG.error('Unkown mac event') run_event_loop() return event try: key_event = NSEvent.eventWithCGEvent_(event) except: LOG.info("mac event cast error") return event if key_event.subtype() == 8: key_code = (key_event.data1() & 0xFFFF0000) >> 16 key_state = (key_event.data1() & 0xFF00) >> 8 if key_code in (16, 19, 20): # 16 for play-pause, 19 for next, 20 for previous if key_state == NSKeyUp: if key_code is 19: ControllerApi.player.play_next() elif key_code is 20: ControllerApi.player.play_last() elif key_code is 16: ControllerApi.player.play_or_pause() return None return event
def http_request(self, method, action, query=None, urlencoded=None, callback=None, timeout=1): try: res = None if method == "GET": res = requests.get(action, headers=self.headers, cookies=self.cookies, timeout=timeout) elif method == "POST": res = requests.post(action, query, headers=self.headers, cookies=self.cookies, timeout=timeout) elif method == "POST_UPDATE": res = requests.post(action, query, headers=self.headers, cookies=self.cookies, timeout=timeout) self.cookies.update(res.cookies.get_dict()) self.save_cookies() content = self.show_progress(res) content_str = content.decode('utf-8') content_dict = json.loads(content_str) return content_dict except Exception as e: LOG.error(str(e)) return {"code": 408}
def run_event_loop(): LOG.info("try to load mac hotkey event loop") import Quartz from AppKit import NSSystemDefined # Set up a tap, with type of tap, location, options and event mask tap = Quartz.CGEventTapCreate( Quartz.kCGSessionEventTap, # Session level is enough for our needs Quartz.kCGHeadInsertEventTap, # Insert wherever, we do not filter Quartz.kCGEventTapOptionDefault, # NSSystemDefined for media keys Quartz.CGEventMaskBit(NSSystemDefined), keyboard_tap_callback, None ) run_loop_source = Quartz.CFMachPortCreateRunLoopSource( None, tap, 0) Quartz.CFRunLoopAddSource( Quartz.CFRunLoopGetCurrent(), run_loop_source, Quartz.kCFRunLoopDefaultMode ) # Enable the tap Quartz.CGEventTapEnable(tap, True) # and run! This won't return until we exit or are terminated. Quartz.CFRunLoopRun() LOG.error('Mac hotkey event loop exit') return []
def http_request(self, method, action, query=None, urlencoded=None, callback=None, timeout=3): LOG.info('method=%s url=%s query=%s' % (method, action, query)) try: res = None if method == "GET": res = requests.get(action, headers=self.headers, cookies=self.cookies, timeout=timeout) elif method == "POST": res = requests.post(action, data=query, headers=self.headers, cookies=self.cookies, timeout=timeout) elif method == "POST_UPDATE": res = requests.post(action, data=query, headers=self.headers, cookies=self.cookies, timeout=timeout) self.cookies.update(res.cookies.get_dict()) content = show_requests_progress(res, self.signal_load_progress) content_str = content.decode('utf-8') content_dict = json.loads(content_str) return content_dict except Exception as e: LOG.error(str(e)) return {"code": 408}
def save_cookies(self): try: with open(DATA_PATH + "cookies.dat", "wb") as f: pickle.dump(self.cookies, f) return True except Exception as e: LOG.error(str(e)) return False
def not_use_cache(*args, **kw): LOG.info("trying to update a playlist cache") data = func(*args, **kw) if data['code'] == 200: cache_data[args[1]] = data else: LOG.info("update playlist cache failed") return None
def __login(self): """登录 在用户登录成功时,会发射("login_success")信号 """ data = {} if self.is_need_captcha is True: captcha_text = str(self.captcha_lineedit.text()) flag, self.captcha_id = self.ne.confirm_captcha( self.captcha_id, captcha_text) if flag is not True: self.hint_label.setText(u'验证码错误') self.show_captcha() return phone_login = False # 0: 网易通行证, 1: 手机号登陆 username = str(self.username_widget.text()) # 包含中文会出错 password = str(self.password_widget.text()) # 2: checked, 1: partial checked is_remember = self.is_remember_chb.checkState() # judget if logining by using phone number if username.isdigit() and len(username) == 11: username = int(username) phone_login = True LOG.info(u"正在使用手机号进行登录") login_data = { 'username': username, 'password': password, 'is_remember': is_remember } if not self.is_autofill: data = self.ne.login(username, password, phone_login) else: data = self.ne.auto_login(username, password, phone_login) if data['code'] == 200: self.hint_label.setText(u'登录成功') self.signal_login_sucess.emit(data) self.close() self.save_login_info(login_data) elif data['code'] == 415: # 需要验证码 self.hint_label.setText(data['message']) LOG.info(u'本次登陆需要验证码') self.captcha_id = data['captchaId'] self.show_captcha() elif data['code'] == 408: self.hint_label.setText(u'网络连接超时') elif data['code'] == 501: self.hint_label.setText(u'用户名错误') elif data['code'] == 502: self.hint_label.setText(u'密码错误') elif data['code'] == 509: self.hint_label.setText(u'你可能正在使用手机号登陆,密码错误几次之后,你可能需要等待几分钟再登录') else: self.hint_label.setText(u'未知错误')
def load_cookies(self): try: with open(DATA_PATH + "cookies.data", "rb") as f: self.cookies = pickle.load(f) requests.session().cookies = self.cookies return True except Exception as e: LOG.error(str(e)) return False
def on_media_status_changed(self, state): if state == QMediaPlayer.EndOfMedia: self.finished.emit() self.stop() if (self._current_index == len(self._music_list) - 1) and (self.playback_mode == 2): self.signal_playlist_finished.emit() LOG.info("播放列表播放完毕") if not self._other_mode: self.play_next()
def __login(self): """登录 在用户登录成功时,会发射("login_success")信号 """ data = {} if self.is_need_captcha is True: captcha_text = str(self.captcha_lineedit.text()) flag, self.captcha_id = self.ne.confirm_captcha(self.captcha_id, captcha_text) if flag is not True: self.hint_label.setText(u'验证码错误') self.show_captcha() return phone_login = False # 0: 网易通行证, 1: 手机号登陆 username = str(self.username_widget.text()) # 包含中文会出错 password = str(self.password_widget.text()) # 2: checked, 1: partial checked is_remember = self.is_remember_chb.checkState() # judget if logining by using phone number if username.isdigit() and len(username) == 11: username = int(username) phone_login = True LOG.info(u"正在使用手机号进行登录") login_data = { 'username': username, 'password': password, 'is_remember': is_remember } if not self.is_autofill: data = self.ne.login(username, password, phone_login) else: data = self.ne.auto_login(username, password, phone_login) if data['code'] == 200: self.hint_label.setText(u'登录成功') self.signal_login_sucess.emit(data) self.close() self.save_login_info(login_data) elif data['code'] == 415: # 需要验证码 self.hint_label.setText(data['message']) LOG.info(u'本次登陆需要验证码') self.captcha_id = data['captchaId'] self.show_captcha() elif data['code'] == 408: self.hint_label.setText(u'网络连接超时') elif data['code'] == 501: self.hint_label.setText(u'用户名错误') elif data['code'] == 502: self.hint_label.setText(u'密码错误') elif data['code'] == 509: self.hint_label.setText(u'你可能正在使用手机号登陆,密码错误几次之后,你可能需要等待几分钟再登录') else: self.hint_label.setText(u'未知错误')
def cache(this, *args, **kw): if len(args) > 1: if not args[1]: # 不使用缓存 cache_data[args[0]] = func(this, *args, **kw) else: if args[0] in cache_data: LOG.info('playlist: ' + cache_data[args[0]]['name'] + ' has been cached') else: cache_data[args[0]] = func(this, *args, **kw) return cache_data[args[0]]
def get_song_detail(self, mid): data = self.ne.song_detail(mid) if not self.is_response_avaible(data): return data LOG.info("music id %d is available" % mid) songs = [] for each in data['songs']: song = self.access_music(each) songs.append(song) return songs
def start(cls, port=12100): try: cls.sock.bind(('0.0.0.0', port)) cls.sock.listen(10) LOG.info("the cli server start at port %d" % port) cls.loop() except Exception as e: LOG.error(str(e)) port += 1 cls.start(port)
def play_specific_song_by_mid(cls, mid): songs = ControllerApi.api.get_song_detail(mid) if not ControllerApi.api.is_response_ok(songs): return False if len(songs) == 0: LOG.info("music id %d is unavailable" % mid) return False ControllerApi.player.play(songs[0]) return True
def post_and_updatecookies(self, url, data): try: res = requests.post(url, data=data, headers=self.headers, cookies=self.cookies) self.cookies.update(res.cookies.get_dict()) requests.session().cookies = self.cookies self.save_cookies() return res.json() except Exception as e: LOG.error(str(e)) return b'{"code": 408}'
def use_cache(*args, **kw): if args[1] in cache_data: LOG.info('playlist: ' + cache_data[args[1]]['name'] + ' has been cached') else: data = func(*args, **kw) if data['code'] == 200: cache_data[args[1]] = data else: LOG.info("cache playlist failed") return None
def post_and_updatecookies(self, url, data): try: res = requests.post(url, data=data, headers=self.headers, cookies=self.cookies) self.cookies.update(res.cookies.get_dict()) requests.session().cookies = self.cookies self.save_cookies() return res.json() except Exception as e: LOG.error(str(e)) return {"code": 408}
def write_json_into_file(data_json, filepath): try: with open(filepath, "w") as f: data_str = json.dumps(data_json, indent=4) f.write(data_str) return True except Exception as e: LOG.error(str(e)) LOG.error("Write json into file failed") return False
def init(controller): """init plugin """ global CONTROLLER LOG.info("NetEase Plugin init") CONTROLLER = controller netease_normalize.ne.signal_load_progress.connect(CONTROLLER.on_web_load_progress) CONTROLLER.api = netease_normalize login_with_local_info()
def get_media_content_from_model(self, music_model): # if music_model['id'] in downloaded mid = music_model['id'] # 判断之前是否播放过,是否已经缓存下来,以后需要改变缓存的算法 for i, each in enumerate(self.__cache_list): if mid == each['id']: LOG.info(music_model['name'] + ' has been cached') return self.__cache_list[i]['content'] return self.cache_music(music_model)
def save_song(self, song_model, filepath): res = requests.get(song_model['url'], stream=True) if res.status_code == 200: print('status code 200') content = show_requests_progress(res, self.signal_download_progress) with open(filepath, 'wb') as f: f.write(content) LOG.info("save song %s successful" % song_model['name']) return True LOG.info("save song %s failed" % song_model['name']) return False
def run_event_loop(player): LOG.info("try to load mac hotkey event loop") import Quartz from AppKit import NSKeyUp, NSSystemDefined, NSEvent def keyboard_tap_callback(proxy, type_, event, refcon): if type_ < 0 or type_ > 0x7fffffff: LOG.error('Unkown mac event') Quartz.CFRunLoopRun() return run_event_loop(ControllerApi.player) try: key_event = NSEvent.eventWithCGEvent_(event) except: LOG.info("mac event cast error") return event if key_event.subtype() == 8: key_code = (key_event.data1() & 0xFFFF0000) >> 16 key_state = (key_event.data1() & 0xFF00) >> 8 if key_code is 16 or key_code is 19 or key_code is 20: # 16 for play-pause, 19 for next, 20 for previous if key_state == NSKeyUp: if key_code is 19: player.play_next() elif key_code is 20: player.play_last() elif key_code is 16: player.play_or_pause() return None return event # Set up a tap, with type of tap, location, options and event mask tap = Quartz.CGEventTapCreate( Quartz.kCGSessionEventTap, # Session level is enough for our needs Quartz.kCGHeadInsertEventTap, # Insert wherever, we do not filter Quartz.kCGEventTapOptionDefault, # NSSystemDefined for media keys Quartz.CGEventMaskBit(NSSystemDefined), keyboard_tap_callback, None ) run_loop_source = Quartz.CFMachPortCreateRunLoopSource( Quartz.kCFAllocatorDefault, tap, 0) Quartz.CFRunLoopAddSource( Quartz.CFRunLoopGetCurrent(), run_loop_source, Quartz.kCFRunLoopDefaultMode ) # Enable the tap Quartz.CGEventTapEnable(tap, True) # and run! This won't return until we exit or are terminated. Quartz.CFRunLoopRun() LOG.error('Mac hotkey exit event ')
def get_playlist_detail(self, pid, cache=True): '''update playlist detail in sqlite if cache is false''' if cache is False: app_event_loop = asyncio.get_event_loop() app_event_loop.run_in_executor( None, partial(self.update_playlist_detail, pid)) if PlaylistDb.exists(pid): LOG.info("Read playlist %d info from sqlite" % (pid)) return PlaylistDb.get_data(pid) else: return self.update_playlist_detail(pid)
def on_error_occured(self, error): self.pause() if error == 2 or error == 5: m = QMessageBox(QMessageBox.Warning, u"错误提示", "第一次运行出现该错误可能是由于缺少解码器,请参考项目主页\ https://github.com/cosven/FeelUOwn 安装依赖。\n 如果不是第一次运行,那就可能是网络已经断开,请检查您的网络连接", QMessageBox.Yes | QMessageBox.No) if m.exec() == QMessageBox.Yes: QApplication.quit() else: LOG.error(u'播放器出现error, 类型为' + str(error)) if error == 3 or error == 1: LOG.error(u'播放器出现错误。可能是网络连接失败,也有可能缺少解码器') return
def play_next(self): index = self.get_next_song_index() if index is not None: if index == 0 and self.playback_mode == 2: self.signal_playlist_finished.emit() LOG.info("播放列表播放完毕") return music_model = self._music_list[index] self._current_index = index self.play(music_model) else: self.signal_playlist_is_empty.emit()
def cache(this, *args, **kw): if len(args) > 1: if not args[1]: # 不使用缓存 data = func(this, *args, **kw) if data['code'] == 200: cache_data[args[0]] = data else: if args[0] in cache_data: LOG.debug('playlist: ' + cache_data[args[0]]['name'] + ' has been cached') else: cache_data[args[0]] = func(this, *args, **kw) return cache_data[args[0]]
def get(self, url): """Load data from the server using a HTTP GET request. :param url: the URL to which the request is sent. :return content: return HTTPResponse Objects, generally speaking, we use READ method. """ request = urllib.request.Request(url, None, self.header) try: response = urllib.request.urlopen(request) return self.show_progress(response) except Exception as e: LOG.error(str(e)) return {'code': 408}
def validate(self): """ check dict keys and data type :return: """ for key in self._model: if key not in self.data: LOG.error(self.data) raise KeyError('data should have key: ' + key) if not isinstance(self.data[key], self._model[key]): raise TypeError('Please check your object type: ', key) return True
def validate(self): """ check dict keys and data type :return: """ for key in self._model: if key not in self.data: LOG.error(self.data) raise KeyError("data should have key: " + key) if not isinstance(self.data[key], self._model[key]): raise TypeError("Please check your object type: ", key) return True
def get(self, url): """Load data from the server using a HTTP GET request. :param url: the URL to which the request is sent. :return content: return HTTPResponse Objects, generally speaking, we use READ method. """ try: res = requests.get(url, headers=self.headers) content = self.show_progress(res) return content except Exception as e: LOG.error(str(e)) return b'{"code": 408}'
def wrapper(player, song_model=None): if song_model is None: return func(player) mid = song_model['id'] music_filename = str(mid) + '.mp3' music_filepath = os.path.join(SONGS_PATH, music_filename) if os.path.exists(music_filepath): LOG.info("play cached song %s" % song_model['name']) else: # async cache song app_event_loop = asyncio.get_event_loop() LOG.info("will download song %s " % song_model['name']) player.save_song(song_model, music_filepath) song_model['url'] = music_filepath return func(player, song_model)
def play_next(self): index = self.get_next_song_index() if index is not None: if index == 0 and self.playback_mode == 2: self.signal_playlist_finished.emit() LOG.info("播放列表播放完毕") return music_model = self._music_list[index] self._current_index = index self.play(music_model) return True else: self.signal_playlist_is_empty.emit() return False
def on_error_occured(self, error): self.setMedia(QMediaContent()) self.pause() if error == QMediaPlayer.FormatError or error == QMediaPlayer.ServiceMissingError: m = QMessageBox( QMessageBox.Warning, u"错误提示", "第一次运行出现该错误可能是由于缺少解码器,请参考项目主页\ https://github.com/cosven/FeelUOwn 安装依赖。\n 如果不是第一次运行,那就可能是网络已经断开,请检查您的网络连接", QMessageBox.Yes | QMessageBox.No) if m.exec() == QMessageBox.Yes: QApplication.quit() else: LOG.error(u'播放器出现error, 类型为' + str(error)) if error == QMediaPlayer.NetworkError: if self._music_error_times >= self._MUSIC_ERROR_MAXIMUM or \ self._current_index < 0 or self._current_index >= len(self._music_list): self._music_error_times = 0 self._app_event_loop.call_later(self._RETRY_LATENCY, self.play_next) LOG.error(u'播放器出现错误:网络连接失败,{}秒后尝试播放下一首'.format( self._RETRY_LATENCY)) else: self._music_error_times += 1 self._app_event_loop.call_later( self._RETRY_LATENCY, self.play, self._music_list[self._current_index]) LOG.error(u'播放器出现错误:网络连接失败, {}秒后重试'.format( self._RETRY_LATENCY)) elif error == QMediaPlayer.ResourceError: LOG.error(u'播放器出现错误:缺少解码器') return
def check_feeluown_release(cls): url = 'https://api.github.com/repos/cosven/FeelUOwn/releases' LOG.info('正在查找新版本...') res = requests.get(url) if res.status_code == 200: releases = res.json() for release in releases: if release['tag_name'] > cls.current_version: title = u'发现新版本 %s hoho' % release['tag_name'] LOG.info(title) content = release['name'] ControllerApi.notify_widget.show_message(title, content) ViewOp.ui.STATUS_BAR.showMessage(title, 5000) break
def on_error_occured(self, error): self.pause() if error == 2 or error == 5: m = QMessageBox( QMessageBox.Warning, u"错误提示", "可能缺少解码器,请参考项目主页\ https://git.oschina.net/zjuysw/NetEaseMusic 安装依赖", QMessageBox.Yes | QMessageBox.No) if m.exec() == QMessageBox.Yes: QApplication.quit() else: LOG.error(u'播放器出现error, 类型为' + str(error)) if error == 3 or error == 1: LOG.error(u'播放器出现错误。可能是网络连接失败,也有可能缺少解码器') return
def save_login_info(self, login_data): if login_data['is_remember']: f = open(self.filename, 'w') if self.is_autofill is not True: # 如果不是自动填充,说明密码时已经没有加密过 password = login_data['password'].encode('utf-8') login_data['password'] = hashlib.md5(password).hexdigest() jsondata = json.dumps(login_data) f.write(jsondata) f.close() else: try: os.remove(self.filename) except Exception as e: LOG.warning(str(e))
def on_error_occured(self, error): self.pause() if error == 2 or error == 5: m = QMessageBox( QMessageBox.Warning, u"错误提示", "第一次运行出现该错误可能是由于缺少解码器,请参考项目主页\ https://github.com/cosven/FeelUOwn 安装依赖。\n 如果不是第一次运行,那就可能是网络已经断开,请检查您的网络连接", QMessageBox.Yes | QMessageBox.No) if m.exec() == QMessageBox.Yes: QApplication.quit() else: LOG.error(u'播放器出现error, 类型为' + str(error)) if error == 3 or error == 1: LOG.error(u'播放器出现错误。可能是网络连接失败,也有可能缺少解码器') return
def init(controller): LOG.info("NetEase Plugin init") ControllerApi.api = netease_normalize user = UserDb.get_last_login_user() if user is not None: netease_normalize.set_uid(user.uid) user_data = user.basic_info if user.cookies is not None: netease_normalize.ne.load_cookies(user.cookies) if netease_normalize.login_by_cookies(): ControllerApi.set_login() ViewOp.load_user_infos(user_data)
def http_request(self, method, action, query=None, urlencoded=None, callback=None, timeout=None): if method == 'GET': res = self.web.get(action) elif method == 'POST': res = self.web.post(action, query) try: # data = res.read() data = res.decode('utf-8') data = json.loads(data) except Exception as e: LOG.info(str(e)) data = res return data
def save_login_info(self, login_data): if login_data['is_remember']: try: f = open(DATA_PATH + self.pw_filename, 'w') if self.is_autofill is not True: # 如果不是自动填充,说明密码时已经没有加密过 password = login_data['password'].encode('utf-8') login_data['password'] = hashlib.md5(password).hexdigest() data_json = json.dumps(login_data) write_json_into_file(data_json, f) except Exception as e: LOG.error(str(e)) else: try: os.remove(DATA_PATH + self.pw_filename) except Exception as e: LOG.warning(str(e))