def encode(self, *, major: int = None, minor: int = None): major = major if major is not None else self.MAJOR minor = minor if minor is not None else self.MINOR buffer = BytesIO() file_type = self.file_type if self.url: file_type |= WEB_LOCATION_FLAG if self.file_reference: file_type |= FILE_REFERENCE_FLAG buffer.write(struct.pack("<ii", file_type, self.dc_id)) if self.url: buffer.write(String(self.url)) if self.file_reference: buffer.write(Bytes(self.file_reference)) buffer.write(struct.pack("<qq", self.media_id, self.access_hash)) if self.file_type in PHOTO_TYPES: buffer.write(struct.pack("<q", self.volume_id)) if major >= 4: buffer.write(struct.pack("<i", self.thumbnail_source)) if self.thumbnail_source == ThumbnailSource.LEGACY: buffer.write(struct.pack("<qi", self.secret, self.local_id)) elif self.thumbnail_source == ThumbnailSource.THUMBNAIL: buffer.write(struct.pack( "<iii", self.thumbnail_file_type, ord(self.thumbnail_size), self.local_id )) elif self.thumbnail_source in (ThumbnailSource.CHAT_PHOTO_SMALL, ThumbnailSource.CHAT_PHOTO_BIG): buffer.write(struct.pack( "<qqi", self.chat_id, self.chat_access_hash, self.local_id )) elif self.thumbnail_source == ThumbnailSource.STICKER_SET_THUMBNAIL: buffer.write(struct.pack( "<qqi", self.sticker_set_id, self.sticker_set_access_hash, self.local_id )) elif file_type in DOCUMENT_TYPES: buffer.write(struct.pack("<ii", minor, major)) buffer.write(struct.pack("<bb", minor, major)) return b64_encode(rle_encode(buffer.getvalue()))
def decode(file_id: str): decoded = rle_decode(b64_decode(file_id)) # region read version # File id versioning. Major versions lower than 4 don't have a minor version major = decoded[-1] if major < 4: minor = 0 buffer = BytesIO(decoded[:-1]) else: minor = decoded[-2] buffer = BytesIO(decoded[:-2]) # endregion file_type, dc_id = struct.unpack("<ii", buffer.read(8)) # region media type flags # Check for flags existence has_web_location = bool(file_type & WEB_LOCATION_FLAG) has_file_reference = bool(file_type & FILE_REFERENCE_FLAG) # Remove flags to restore the actual type id value file_type &= ~WEB_LOCATION_FLAG file_type &= ~FILE_REFERENCE_FLAG # endregion try: file_type = FileType(file_type) except ValueError: raise ValueError( f"Unknown file_type {file_type} of file_id {file_id}") if has_web_location: url = String.read(buffer) access_hash, = struct.unpack("<q", buffer.read(8)) return FileId(major=major, minor=minor, file_type=file_type, dc_id=dc_id, url=url, access_hash=access_hash) file_reference = Bytes.read(buffer) if has_file_reference else b"" media_id, access_hash = struct.unpack("<qq", buffer.read(16)) if file_type in PHOTO_TYPES: volume_id, = struct.unpack("<q", buffer.read(8)) thumbnail_source, = (0, ) if major < 4 else struct.unpack( "<i", buffer.read(4)) try: thumbnail_source = ThumbnailSource(thumbnail_source) except ValueError: raise ValueError( f"Unknown thumbnail_source {thumbnail_source} of file_id {file_id}" ) if thumbnail_source == ThumbnailSource.LEGACY: secret, local_id = struct.unpack("<qi", buffer.read(12)) return FileId(major=major, minor=minor, file_type=file_type, dc_id=dc_id, file_reference=file_reference, media_id=media_id, access_hash=access_hash, volume_id=volume_id, thumbnail_source=thumbnail_source, secret=secret, local_id=local_id) if thumbnail_source == ThumbnailSource.THUMBNAIL: thumbnail_file_type, thumbnail_size, local_id = struct.unpack( "<iii", buffer.read(12)) thumbnail_size = chr(thumbnail_size) return FileId(major=major, minor=minor, file_type=file_type, dc_id=dc_id, file_reference=file_reference, media_id=media_id, access_hash=access_hash, volume_id=volume_id, thumbnail_source=thumbnail_source, thumbnail_file_type=thumbnail_file_type, thumbnail_size=thumbnail_size, local_id=local_id) if thumbnail_source in (ThumbnailSource.CHAT_PHOTO_SMALL, ThumbnailSource.CHAT_PHOTO_BIG): chat_id, chat_access_hash, local_id = struct.unpack( "<qqi", buffer.read(20)) return FileId(major=major, minor=minor, file_type=file_type, dc_id=dc_id, file_reference=file_reference, media_id=media_id, access_hash=access_hash, volume_id=volume_id, thumbnail_source=thumbnail_source, chat_id=chat_id, chat_access_hash=chat_access_hash, local_id=local_id) if thumbnail_source == ThumbnailSource.STICKER_SET_THUMBNAIL: sticker_set_id, sticker_set_access_hash, local_id = struct.unpack( "<qqi", buffer.read(20)) return FileId(major=major, minor=minor, file_type=file_type, dc_id=dc_id, file_reference=file_reference, media_id=media_id, access_hash=access_hash, volume_id=volume_id, thumbnail_source=thumbnail_source, sticker_set_id=sticker_set_id, sticker_set_access_hash=sticker_set_access_hash, local_id=local_id) if file_type in DOCUMENT_TYPES: return FileId(major=major, minor=minor, file_type=file_type, dc_id=dc_id, file_reference=file_reference, media_id=media_id, access_hash=access_hash)