def stop(self): if self.__state == TorrentState.Stopping: return Logger().write(LogVerbosity.Info, 'Torrent stopping') self.__set_state(TorrentState.Stopping) EventManager.deregister_event(self._user_file_selected_id) self.engine.stop() Logger().write(LogVerbosity.Debug, 'Torrent engines stopped') self.peer_processor.stop() self.peer_manager.stop() self.tracker_manager.stop() self.network_manager.stop() self.metadata_manager.stop() self.stream_manager.stop() self.message_processor.stop() self.download_manager.stop() self.data_manager.stop() self.cache_manager.stop() Logger().write(LogVerbosity.Debug, 'Torrent managers stopped') for file in self.files: file.close() self.files = [] self.media_file = None self.finish() EventManager.throw_event(EventType.TorrentStopped, []) Logger().write(LogVerbosity.Important, 'Torrent stopped')
def set_media_file(self, path): if "x265" in path.lower(): self.abort("HVEC x265 files not supported") return self.media_file = [x for x in self.files if x.path == path][0] Logger().write( LogVerbosity.Info, "Media file: " + str(self.media_file.name) + ", " + str(self.media_file.start_byte) + " - " + str(self.media_file.end_byte) + "/" + str(self.total_size)) self.data_manager.set_piece_info(self.piece_length, self.piece_hashes) self.cache_manager.init(self.piece_length, self.media_file.length, self.media_file.start_byte) self.__set_state(TorrentState.Downloading) self.left = self.data_manager.get_piece_by_offset( self.media_file.end_byte ).end_byte - self.data_manager.get_piece_by_offset( self.media_file.start_byte).start_byte Logger().write( LogVerbosity.Info, "To download: " + str(self.left) + " (" + str(self.left - self.media_file.length) + " overhead), piece length: " + str(self.piece_length)) EventManager.throw_event(EventType.TorrentMediaFileSet, [self.media_file.name])
def try_find_in_shows(self, media_data): # Try to get next episode from shows list season, epi = try_parse_season_episode(media_data.title) if season == 0 or epi == 0: Logger().write(LogVerbosity.Debug, "No next episode of show, season/epi not parsed") return show = ShowController.get_by_id_internal(media_data.id) next_epi = [ x for x in show["episodes"] if x["season"] == season and x["episode"] == epi + 1 ] if len(next_epi) == 0: Logger().write( LogVerbosity.Debug, "No next episode of show, request returned no results for next epi" ) return Logger().write(LogVerbosity.Info, "Found next episode: " + next_epi[0]["title"]) self.next_id = media_data.id self.next_season = season self.next_episode = epi + 1 self.next_type = "Show" self.next_title = media_data.title.replace( "E" + self.add_leading_zero(epi), "E" + self.add_leading_zero(epi + 1)) self.next_path = next_epi[0]["torrents"]["0"]["url"] self.next_img = media_data.image
def check_wifi(self): if self.pi: proc = subprocess.Popen(["iwgetid"], stdout=PIPE, universal_newlines=True) out, err = proc.communicate() if ":" not in out: return network_ssid = out.split(":")[1] proc = subprocess.Popen(["iwlist", "wlan0", "scan"], stdout=PIPE, universal_newlines=True) out, err = proc.communicate() cells = out.split("Cell ") cell_lines = [x for x in cells if network_ssid in x] if len(cell_lines) != 0: network_lines = cell_lines[0] for line in network_lines.split("\n"): if "Quality" in line: fields = line.split(" ") for field in fields: field.replace(" ", "") if len(field) <= 2: continue key_value = field.split("=") if len(key_value) == 1: key_value = field.split(":") if key_value[0] == "Quality": value_max = key_value[1].split("/") new_val = float(value_max[0]) / float( value_max[1]) * 100 if self.quality != new_val: if self.quality == 0: Logger().write( LogVerbosity.Debug, "Wifi quality: " + str(new_val)) self.quality = new_val else: proc = subprocess.Popen(["Netsh", "WLAN", "show", "interfaces"], stdout=PIPE, universal_newlines=True) out, err = proc.communicate() lines = out.split("\n") for line in lines: if "Signal" in line: split = line.split(":") new_val = float(split[1].replace("%", "")) if self.quality != new_val: if self.quality == 0: Logger().write(LogVerbosity.Debug, "Wifi quality: " + str(new_val)) self.quality = new_val return True
def from_bytes(data): if not check_minimal_bytes_length(data, 8): return None msg = TrackerResponseMessage() offset = 0 msg.peers = list() msg.error = None try: offset, msg.message_type = read_integer(data, offset) offset, msg.transaction_id = read_integer(data, offset) if msg.message_type == 3: msg.error = str(data[offset:len(data)]) Logger().write(LogVerbosity.Important, "Tracker error message: " + msg.error) else: offset, msg.interval = read_integer(data, offset) offset, msg.leechers = read_integer(data, offset) offset, msg.seeders = read_integer(data, offset) bytes_left = len(data) - offset total_peers = int(bytes_left / 6) for index in range(total_peers): msg.peers.append(uri_from_bytes(data[offset:offset + 6])) offset += 6 except Exception as e: Logger().write( LogVerbosity.Important, "Error in tacker message: " + str(e) + ". Message: " + str(data)) return None return msg
def set_device_state(self, home): if home: self.last_seen = current_time() self.last_home_state = True if not self.home_state: self.home_state = True Logger().write(LogVerbosity.Info, "Device " + self.name + " came home") return if not home and not self.home_state: # still not home return if self.last_home_state: # Now not home, last state was home. Start timing self.last_home_state = False self.timeout_start_time = current_time() return else: # Now not home, last state was also not home. Check timeout if current_time( ) - self.timeout_start_time > self.gone_interval * 1000: self.home_state = False Logger().write(LogVerbosity.Info, "Device " + self.name + " left home")
def stop(self): if self.state == PeerState.Stopped: return self.state = PeerState.Stopping Logger().write(LogVerbosity.All, str(self.id) + ' Peer stopping') if self.peer_state_task is not None: self.peer_state_task.join() if self.state == PeerState.Stopped: return self.connection_manager.disconnect() self.download_manager.stop() self.extension_manager.stop() self.metadata_manager.stop() self.state = PeerState.Stopped self.peer_start_task.join() self.protocol_logger = None super().stop() self.finish() Logger().write(LogVerbosity.Debug, str(self.id) + ' Peer stopped: ' + self.stop_reason)
def from_file(cls, id, file_path): torrent = Torrent(id, file_path) torrent.from_magnet = False try: file = open(file_path, 'rb') except IOError: Logger().write(LogVerbosity.Important, "Torrent file could not be opened: " + file_path) return False, torrent try: meta_info = Bencode.bdecode(file.read()) except BTFailure: Logger().write(LogVerbosity.Important, "Invalid torrent file") return False, torrent if b'info' not in meta_info: Logger().write(LogVerbosity.Important, "Invalid bencoded torrent dictionary") return False, torrent info = meta_info[b'info'] torrent.parse_torrent_file(meta_info) torrent.info_hash = InfoHash.from_info_dict(info) return True, torrent
def from_torrent_url(cls, id, uri): torrent = Torrent(id, uri) torrent.from_magnet = False try: request = urllib.request.Request(urllib.parse.unquote_plus(uri), None, headers) file = urllib.request.urlopen(request).read() except: Logger().write( LogVerbosity.Important, "Error downloading torrent file: " + urllib.parse.unquote_plus(uri)) return False, torrent try: meta_info = Bencode.bdecode(file) except BTFailure: Logger().write(LogVerbosity.Important, "Invalid torrent file") return False, torrent if b'info' not in meta_info: Logger().write(LogVerbosity.Important, "Invalid bencoded torrent dictionary") return False, torrent info = meta_info[b'info'] torrent.parse_torrent_file(meta_info) torrent.info_hash = InfoHash.from_info_dict(info) return True, torrent
def __request(self, command): Logger().write(LogVerbosity.Debug, "TV manager sending command: " + command) result = subprocess.check_output( 'echo "' + command + '" | cec-client -s -d ' + self.debug_level, shell=True).decode("utf8") Logger().write(LogVerbosity.Debug, "TV manager result: " + str(result))
def check(self): for pending in list(self.awaiting_messages): if current_time() - pending.send_at > 10000: Logger().write(LogVerbosity.All, "DHT message timeout") self.node_timeout_handler(pending.message.ip, pending.message.port) pending.on_timeout() self.awaiting_messages.remove(pending) for received in list(self.received_messages): if isinstance(received.message, QueryDHTMessage): self.query_handler(received.ip, received.port, received.message) self.received_messages.remove(received) continue elif isinstance(received.message, ResponseDHTMessage): pending = [ x for x in self.awaiting_messages if x.message.message.transaction_id == received.message.transaction_id ] if len(pending) == 0: Logger().write(LogVerbosity.All, "DHT response for no request (timed out?)") self.received_messages.remove(received) continue Logger().write(LogVerbosity.All, "DHT message response") pending[0].on_response(received.message) # answer to request self.received_messages.remove(received) self.awaiting_messages.remove(pending[0])
def requeue(self, start_position): Logger().write(LogVerbosity.All, "Starting download queue queuing") start_time = current_time() left = 0 self.queue.clear() for piece in self.torrent.data_manager.get_pieces_after_index( start_position): if piece.written: continue if piece.start_byte > self.torrent.media_file.end_byte or piece.end_byte < self.torrent.media_file.start_byte: continue piece.reset() self.queue.append(piece) left += piece.length first = "none" length = len(self.queue) if length > 0: first = str(self.queue[0].index) self.queue_log = "length: " + str(length) + ", first: " + first self.slow_peer_piece_offset = 15000000 // self.torrent.data_manager.piece_length # TODO Setting Logger().write( LogVerbosity.Debug, "Queueing took " + str(current_time() - start_time) + "ms for " + str(len(self.queue)) + " items") self.torrent.left = left if self.torrent.left > 0 and self.torrent.state == TorrentState.Done: self.torrent.restart_downloading() self.update_priority(True)
def add_to_bucket(self, bucket, new_node): if bucket.full(): questionable_nodes = bucket.questionable_nodes() if len(questionable_nodes) != 0: task = PingTask(self.dht_engine, self.dht_engine.own_node.byte_id, questionable_nodes[0].ip, questionable_nodes[0].port) task.on_complete = lambda: self.add_to_bucket( bucket, new_node ) # when the ping returns the node is either bad or no longer questionable task.execute() return if bucket.fits(self.dht_engine.own_node.int_id): Logger().write(LogVerbosity.All, "DHT: Bucket is full, splitting") new_range = (bucket.end - bucket.start) // 2 new_bucket = Bucket(bucket.start, bucket.start + new_range) split_nodes = bucket.split() for node in split_nodes: new_bucket.add_node(node) self.buckets.append(new_bucket) self.add_node(new_node) else: Logger().write(LogVerbosity.All, "DHT: Skipping adding of node, bucket is full") else: bucket.add_node(new_node) Logger().write( LogVerbosity.All, "DHT: Node " + str(new_node.int_id) + " added to bucket")
def try_find_in_torrent(self, media_data, torrent): season, epi = try_parse_season_episode(torrent.media_file.path) if season == 0 or epi == 0: Logger().write(LogVerbosity.Debug, "No next episode found, season/epi not parsed") return # Try to get next episode from same torrent for file in torrent.files: if not is_media_file(file.path): continue s, e = try_parse_season_episode(file.path) if s == season and e == epi + 1: Logger().write(LogVerbosity.Info, "Found next episode: " + file.path) self.next_season = s self.next_episode = epi + 1 self.next_type = "Torrent" self.next_title = torrent.media_file.name.replace( "E" + self.add_leading_zero(epi), "E" + self.add_leading_zero(epi + 1)) self.next_path = torrent.uri self.next_media_file = file.name return
def write_header_with_content(self, socket, status, start, end, length, path): response_header = HttpHeader() Logger().write( LogVerbosity.Debug, self.name + " stream requested: " + str(start) + "-" + str(end)) response_header.status_code = status response_header.content_length = end - start + 1 response_header.set_range(start, end, length) filename, file_extension = os.path.splitext(path.lower()) if file_extension not in StreamListener.mime_mapping: Logger().write( LogVerbosity.Info, self.name + " unknown video type: " + str(file_extension) + ", defaulting to mp4") response_header.mime_type = StreamListener.mime_mapping[".mp4"] else: response_header.mime_type = StreamListener.mime_mapping[ file_extension] Logger().write( LogVerbosity.Info, self.name + " return header: " + response_header.to_string()) try: socket.send(response_header.to_string().encode()) return True except (ConnectionAbortedError, ConnectionResetError, OSError): Logger().write( LogVerbosity.Info, "Connection closed 2 during sending of response header") socket.close() return False
def check_presence(self): if not self.pi: return while self.running: for device in self.device_states: result = subprocess.call('sudo arping -q -c1 -W 1 ' + device.ip + ' > /dev/null', shell=True) device.set_device_state(result == 0) if self.anyone_home and len( [x for x in self.device_states if x.home_state]) == 0: # left self.anyone_home = False Logger().write(LogVerbosity.Info, "Everybody left home") if self.on_leaving_home is not None: self.on_leaving_home() elif not self.anyone_home and len( [x for x in self.device_states if x.home_state]) > 0: # returned self.anyone_home = True Logger().write(LogVerbosity.Info, "Someone came home") if self.on_coming_home is not None: self.on_coming_home() time.sleep(self.check_interval)
def check_peer_state(self): zero_speed_checks = 0 while self.state == PeerState.Started: if current_time() - self.connection_manager.connected_on < 20000: time.sleep(1) continue if not self.torrent.peer_manager.should_stop_peers(): time.sleep(1) continue if self.counter.total == 0: Logger().write(LogVerbosity.Info, str(self.id) + " stopping not downloading peer") self.stop_async( "Not downloading" ) # Stop since we haven't downloaded anything since connecting return if self.counter.value == 0: zero_speed_checks += 1 if zero_speed_checks >= 10: Logger().write( LogVerbosity.Info, str(self.id) + " stopping currently not downloading peer") self.stop_async( "Not recently downloading" ) # Stop since we haven't downloaded anything in the last 10 seconds return else: zero_speed_checks = 0 time.sleep(1)
def on_init(client_name, key): Logger().write(LogVerbosity.Info, "Init slave: " + client_name) if key != SecureSettings.get_string("master_key"): Logger().write(LogVerbosity.Info, "Slave authentication failed") disconnect() return False slave = APIController.slaves.get_slave(client_name) if slave is not None: if slave.connected: Logger().write( LogVerbosity.Info, "Slave " + str(client_name) + " connected twice?") disconnect() return False else: Logger().write(LogVerbosity.Info, "Slave " + str(client_name) + " reconnected") slave.reconnect(request.sid) APIController.slaves.changed() return True client = WebsocketClient(request.sid, current_time()) client.authenticated = True APIController.slaves.add_slave( SlaveClient(APIController.next_id(), client_name, client)) return client.authenticated
def instantiate_vlc(self): parameters = self.get_instance_parameters() Logger().write(LogVerbosity.Debug, "VLC parameters: " + str(parameters)) self.__vlc_instance = vlc.Instance("cvlc", *parameters) Logger().write(LogVerbosity.Info, "VLC version " + libvlc_get_version().decode('utf8'))
def check_migration(self): database, cursor = self.connect() cursor.execute( "CREATE TABLE IF NOT EXISTS Version (version_number INTEGER)") cursor.execute("SELECT version_number FROM Version") db_version_rows = cursor.fetchall() db_version = 0 if len(db_version_rows) != 0: db_version = db_version_rows[0][0] else: cursor.execute("INSERT INTO Version (version_number) VALUES(0)") database.commit() if db_version > self.current_version: Logger().write(LogVerbosity.Important, "DB version higher than software, can't process") raise Exception("DB version invalid") changed = False while db_version != self.current_version: Logger().write( LogVerbosity.Info, "Database version " + str(db_version) + ", latest is " + str(self.current_version) + ". Upgrading") self.upgrade(database, cursor, db_version) db_version += 1 changed = True database.close() if changed: Logger().write(LogVerbosity.Info, "Database upgrade completed")
def on_response(self, request_id, args): Logger().write(LogVerbosity.Debug, "Client response for id " + str(request_id) + ": " + str(args)) requests = [x for x in self.requests if x.request_id == request_id] if len(requests) == 0: Logger().write(LogVerbosity.Debug, "No pending request found for id " + str(request_id)) return requests[0].set(args)
def on_response(request_id, response): Logger().write(LogVerbosity.Debug, "UI client response for id " + str(request_id) + ": " + str(response)) requests = [x for x in SlaveClientController.requests if x.request_id == request_id] if len(requests) == 0: Logger().write(LogVerbosity.Debug, "No pending request found for id " + str(request_id)) return requests[0].set(response)
def update(self): big_buffer_but_not_consequetive = self.torrent.bytes_total_in_buffer - self.torrent.bytes_ready_in_buffer > Settings.get_int("important_only_start_threshold") queued_high_priority_piece_timeout_while_downloading = len([x for x in self.torrent.download_manager.queue[0: 10] if x.max_priority_set_time != 0 and current_time() - x.max_priority_set_time > 10000]) > 0 and self.torrent.network_manager.average_download_counter.value > 200000 if (big_buffer_but_not_consequetive or queued_high_priority_piece_timeout_while_downloading) and self.torrent.download_manager.download_mode == DownloadMode.Full: Logger().write(LogVerbosity.Info, "Entering ImportantOnly download mode: " + write_size(self.torrent.bytes_total_in_buffer) + " in buffer total") self.torrent.download_manager.download_mode = DownloadMode.ImportantOnly elif self.torrent.bytes_total_in_buffer - self.torrent.bytes_ready_in_buffer < Settings.get_int("important_only_stop_threshold") and self.torrent.download_manager.download_mode == DownloadMode.ImportantOnly: Logger().write(LogVerbosity.Info, "Leaving ImportantOnly download mode") self.torrent.download_manager.download_mode = DownloadMode.Full
def get_device_groups(self): if not self.check_state(): return [] Logger().write(LogVerbosity.All, "Get device groups") groups_commands = self.api(self.gateway.get_groups()) result = self.api(groups_commands) Logger().write(LogVerbosity.All, "Get device groups: " + str([x.raw for x in result])) return [DeviceGroup(group.id, group.name, group.state, group.dimmer, len(group.member_ids)) for group in result]
def get_subtitles(self, size, file_length, file_name, first_64k, last_64k): result_raw = RequestFactory.make_request( "https://rest.opensubtitles.org/search/moviebytesize-" + str(size) + "/moviehash-" + str(self.get_hash(size, first_64k, last_64k)) + "/sublanguageid-eng", "GET", useragent="mediaplayerjk") if not result_raw: Logger().write(LogVerbosity.Info, "Failed to get subtitles") return [] result = json.loads(result_raw.decode('utf8')) paths = [] results_correct_name = [ x for x in result if x['MovieReleaseName'] in file_name ] Logger().write( LogVerbosity.Debug, "Subs with correct name (" + file_name + "): " + str(len(results_correct_name))) added = 0 for sub in results_correct_name: path = self.download_sub(sub) paths.append(path) added += 1 if added == 2: break results_correct_size = [ x for x in result if abs(int(x['MovieTimeMS']) - file_length) < 10 ] Logger().write( LogVerbosity.Debug, "Subs with correct size (" + str(file_length) + "): " + str(len(results_correct_size))) added = 0 for sub in results_correct_size: path = self.download_sub(sub) paths.append(path) added += 1 if added == 2: break results_other = [ x for x in result if x not in results_correct_size and x not in results_correct_name ] Logger().write(LogVerbosity.Debug, "Subs other: " + str(len(results_other))) added = 0 for sub in results_other: path = self.download_sub(sub) paths.append(path) added += 1 if added == 2: break return paths
def shelly(): ip = request.args.get("ip") state = "on" if request.args.get("state") == "true" else "off" Logger().write(LogVerbosity.Info, "Set shelly " + ip + " to " + state) result = RequestFactory.make_request("http://" + ip + "?state=" + state) if result is not None: Logger().write(LogVerbosity.Info, result) return "OK"
def on_torrent_stopped(): time.sleep(2) gc.collect() time.sleep(1) obj = objgraph.by_type('MediaPlayer.Torrents.Torrent.Torrent.Torrent') if len(obj) != 0: Logger().write(LogVerbosity.Important, "Torrent not disposed!") else: Logger().write(LogVerbosity.Info, "Torrent disposed")
def update_priority(self, full=False): if not self.init: return True if self.torrent.state == TorrentState.Done: if self.queue: self.queue = [] self.queue_log = "" return True start_time = current_time() amount = 100 if full: amount = len(self.torrent.data_manager._pieces) start = self.torrent.stream_position if full: start = self.torrent.media_file.start_piece( self.torrent.piece_length) pieces_to_look_at = self.torrent.data_manager.get_pieces_by_index_range( start, start + amount) for piece in pieces_to_look_at: piece.priority = self.prioritize_piece_index(piece.index) if piece.priority > 100 and piece.max_priority_set_time == 0: piece.max_priority_set_time = current_time() else: piece.max_priority_set_time = 0 if full: self.queue = sorted(self.queue, key=lambda x: x.priority, reverse=True) first = "none" length = len(self.queue) if length > 0: first = str(self.queue[0].index) self.queue_log = "length: " + str(length) + ", first: " + first if self.queue: piece = self.queue[0] Logger().write( LogVerbosity.Debug, "Highest prio: " + str(piece.index) + ": " + str(piece.priority) + "%, " + str(len([x for x in piece.blocks.values() if not x.done])) + " block left, took " + str(current_time() - start_time) + "ms, full: " + str(full)) else: Logger().write(LogVerbosity.Debug, "No prio: queue empty") self.prio = True return True
def __run(self): try: self.started = True self.target(*self.args) ThreadManager().remove_thread(self) self.finish() Logger().write(LogVerbosity.All, "Thread " + self.thread_name + " done") except Exception as e: Logger().write_error(e, "Exception in thread " + self.thread_name) ThreadManager().remove_thread(self) self.finish()
def on_unsubscribe(topic): authenticated = [ x for x in UIWebsocketController.clients if x.sid == request.sid ][0].authenticated if not authenticated: Logger().write(LogVerbosity.Info, "Unauthenticated socket request for unsubscribing") return Logger().write(LogVerbosity.Info, "UI client unsubscribing from " + topic) leave_room(topic)