コード例 #1
0
def parse_messages(client,
                   messages: list or types.Message or types.MessageService
                   or types.MessageEmpty,
                   users: dict,
                   chats: dict,
                   replies: int = 1) -> pyrogram_types.Message or list:
    is_list = isinstance(messages, list)
    messages = messages if is_list else [messages]
    parsed_messages = []

    for message in messages:
        if isinstance(message, types.Message):
            entities = parse_entities(message.entities, users)

            forward_from = None
            forward_from_chat = None
            forward_from_message_id = None
            forward_signature = None
            forward_date = None

            forward_header = message.fwd_from  # type: types.MessageFwdHeader

            if forward_header:
                forward_date = forward_header.date

                if forward_header.from_id:
                    forward_from = parse_user(users[forward_header.from_id])
                else:
                    forward_from_chat = parse_channel_chat(
                        chats[forward_header.channel_id])
                    forward_from_message_id = forward_header.channel_post
                    forward_signature = forward_header.post_author

            photo = None
            location = None
            contact = None
            venue = None
            audio = None
            voice = None
            animation = None
            video = None
            video_note = None
            sticker = None
            document = None

            media = message.media

            if media:
                if isinstance(media, types.MessageMediaPhoto):
                    photo = media.photo

                    if isinstance(photo, types.Photo):
                        sizes = photo.sizes
                        photo_sizes = []

                        for size in sizes:
                            if isinstance(
                                    size,
                                (types.PhotoSize, types.PhotoCachedSize)):
                                loc = size.location

                                if isinstance(size, types.PhotoSize):
                                    file_size = size.size
                                else:
                                    file_size = len(size.bytes)

                                if isinstance(loc, types.FileLocation):
                                    photo_size = pyrogram_types.PhotoSize(
                                        file_id=encode(
                                            pack("<iiqqqqi", 2, loc.dc_id,
                                                 photo.id, photo.access_hash,
                                                 loc.volume_id, loc.secret,
                                                 loc.local_id)),
                                        width=size.w,
                                        height=size.h,
                                        file_size=file_size)

                                    photo_sizes.append(photo_size)

                        photo = pyrogram_types.Photo(id=b64encode(
                            pack("<qq", photo.id, photo.access_hash),
                            b"-_").decode().rstrip("="),
                                                     date=photo.date,
                                                     sizes=photo_sizes)
                elif isinstance(media, types.MessageMediaGeo):
                    geo_point = media.geo

                    if isinstance(geo_point, types.GeoPoint):
                        location = pyrogram_types.Location(
                            longitude=geo_point.long, latitude=geo_point.lat)
                elif isinstance(media, types.MessageMediaContact):
                    contact = pyrogram_types.Contact(
                        phone_number=media.phone_number,
                        first_name=media.first_name,
                        last_name=media.last_name or None,
                        vcard=media.vcard or None,
                        user_id=media.user_id or None)
                elif isinstance(media, types.MessageMediaVenue):
                    venue = pyrogram_types.Venue(
                        location=pyrogram_types.Location(
                            longitude=media.geo.long, latitude=media.geo.lat),
                        title=media.title,
                        address=media.address,
                        foursquare_id=media.venue_id or None,
                        foursquare_type=media.venue_type)
                elif isinstance(media, types.MessageMediaDocument):
                    doc = media.document

                    if isinstance(doc, types.Document):
                        attributes = {type(i): i for i in doc.attributes}

                        file_name = getattr(
                            attributes.get(types.DocumentAttributeFilename,
                                           None), "file_name", None)

                        if types.DocumentAttributeAudio in attributes:
                            audio_attributes = attributes[
                                types.DocumentAttributeAudio]

                            if audio_attributes.voice:
                                voice = pyrogram_types.Voice(
                                    file_id=encode(
                                        pack("<iiqq", 3, doc.dc_id, doc.id,
                                             doc.access_hash)),
                                    duration=audio_attributes.duration,
                                    mime_type=doc.mime_type,
                                    file_size=doc.size,
                                    waveform=audio_attributes.waveform,
                                    date=doc.date)
                            else:
                                audio = pyrogram_types.Audio(
                                    file_id=encode(
                                        pack("<iiqq", 9, doc.dc_id, doc.id,
                                             doc.access_hash)),
                                    duration=audio_attributes.duration,
                                    performer=audio_attributes.performer,
                                    title=audio_attributes.title,
                                    mime_type=doc.mime_type,
                                    file_size=doc.size,
                                    thumb=parse_thumb(doc.thumb),
                                    file_name=file_name,
                                    date=doc.date)
                        elif types.DocumentAttributeAnimated in attributes:
                            video_attributes = attributes.get(
                                types.DocumentAttributeVideo, None)

                            animation = pyrogram_types.Animation(
                                file_id=encode(
                                    pack("<iiqq", 10, doc.dc_id, doc.id,
                                         doc.access_hash)),
                                width=getattr(video_attributes, "w", 0),
                                height=getattr(video_attributes, "h", 0),
                                duration=getattr(video_attributes, "duration",
                                                 0),
                                thumb=parse_thumb(doc.thumb),
                                mime_type=doc.mime_type,
                                file_size=doc.size,
                                file_name=file_name,
                                date=doc.date)
                        elif types.DocumentAttributeVideo in attributes:
                            video_attributes = attributes[
                                types.DocumentAttributeVideo]

                            if video_attributes.round_message:
                                video_note = pyrogram_types.VideoNote(
                                    file_id=encode(
                                        pack("<iiqq", 13, doc.dc_id, doc.id,
                                             doc.access_hash)),
                                    length=video_attributes.w,
                                    duration=video_attributes.duration,
                                    thumb=parse_thumb(doc.thumb),
                                    file_size=doc.size,
                                    mime_type=doc.mime_type,
                                    date=doc.date)
                            else:
                                video = pyrogram_types.Video(
                                    file_id=encode(
                                        pack("<iiqq", 4, doc.dc_id, doc.id,
                                             doc.access_hash)),
                                    width=video_attributes.w,
                                    height=video_attributes.h,
                                    duration=video_attributes.duration,
                                    thumb=parse_thumb(doc.thumb),
                                    mime_type=doc.mime_type,
                                    file_size=doc.size,
                                    file_name=file_name,
                                    date=doc.date)
                        elif types.DocumentAttributeSticker in attributes:
                            image_size_attributes = attributes.get(
                                types.DocumentAttributeImageSize, None)
                            sticker_attribute = attributes[
                                types.DocumentAttributeSticker]

                            if isinstance(sticker_attribute.stickerset,
                                          types.InputStickerSetID):
                                try:
                                    set_name = client.send(
                                        functions.messages.GetStickerSet(
                                            sticker_attribute.stickerset)
                                    ).set.short_name
                                except StickersetInvalid:
                                    set_name = None
                            else:
                                set_name = None

                            sticker = pyrogram_types.Sticker(
                                file_id=encode(
                                    pack("<iiqq", 8, doc.dc_id, doc.id,
                                         doc.access_hash)),
                                width=image_size_attributes.w
                                if image_size_attributes else 0,
                                height=image_size_attributes.h
                                if image_size_attributes else 0,
                                thumb=parse_thumb(doc.thumb),
                                # TODO: mask_position
                                set_name=set_name,
                                emoji=sticker_attribute.alt or None,
                                file_size=doc.size,
                                mime_type=doc.mime_type,
                                file_name=file_name,
                                date=doc.date)
                        else:
                            document = pyrogram_types.Document(
                                file_id=encode(
                                    pack("<iiqq", 5, doc.dc_id, doc.id,
                                         doc.access_hash)),
                                thumb=parse_thumb(doc.thumb),
                                file_name=file_name,
                                mime_type=doc.mime_type,
                                file_size=doc.size,
                                date=doc.date)
                else:
                    media = None

            reply_markup = message.reply_markup

            if reply_markup:
                if isinstance(reply_markup, types.ReplyKeyboardForceReply):
                    reply_markup = pyrogram_types.ForceReply.read(reply_markup)
                elif isinstance(reply_markup, types.ReplyKeyboardMarkup):
                    reply_markup = pyrogram_types.ReplyKeyboardMarkup.read(
                        reply_markup)
                elif isinstance(reply_markup, types.ReplyInlineMarkup):
                    reply_markup = pyrogram_types.InlineKeyboardMarkup.read(
                        reply_markup)
                elif isinstance(reply_markup, types.ReplyKeyboardHide):
                    reply_markup = pyrogram_types.ReplyKeyboardRemove.read(
                        reply_markup)
                else:
                    reply_markup = None

            m = pyrogram_types.Message(
                message_id=message.id,
                date=message.date,
                chat=parse_chat(message, users, chats),
                from_user=parse_user(users.get(message.from_id, None)),
                text=Str(message.message) or None if media is None else None,
                caption=Str(message.message) or None
                if media is not None else None,
                entities=entities or None if media is None else None,
                caption_entities=entities or None
                if media is not None else None,
                author_signature=message.post_author,
                forward_from=forward_from,
                forward_from_chat=forward_from_chat,
                forward_from_message_id=forward_from_message_id,
                forward_signature=forward_signature,
                forward_date=forward_date,
                mentioned=message.mentioned,
                media=bool(media) or None,
                edit_date=message.edit_date,
                media_group_id=message.grouped_id,
                photo=photo,
                location=location,
                contact=contact,
                venue=venue,
                audio=audio,
                voice=voice,
                animation=animation,
                video=video,
                video_note=video_note,
                sticker=sticker,
                document=document,
                views=message.views,
                via_bot=parse_user(users.get(message.via_bot_id, None)),
                outgoing=message.out,
                client=proxy(client),
                reply_markup=reply_markup)

            if m.text:
                m.text.init(m._client, m.entities or [])

            if m.caption:
                m.caption.init(m._client, m.caption_entities or [])

            if message.reply_to_msg_id and replies:
                try:
                    m.reply_to_message = client.get_messages(
                        m.chat.id,
                        reply_to_message_ids=message.id,
                        replies=replies - 1)
                except MessageIdsEmpty:
                    pass
        elif isinstance(message, types.MessageService):
            action = message.action

            new_chat_members = None
            left_chat_member = None
            new_chat_title = None
            delete_chat_photo = None
            migrate_to_chat_id = None
            migrate_from_chat_id = None
            group_chat_created = None
            channel_chat_created = None
            new_chat_photo = None

            if isinstance(action, types.MessageActionChatAddUser):
                new_chat_members = [parse_user(users[i]) for i in action.users]
            elif isinstance(action, types.MessageActionChatJoinedByLink):
                new_chat_members = [parse_user(users[message.from_id])]
            elif isinstance(action, types.MessageActionChatDeleteUser):
                left_chat_member = parse_user(users[action.user_id])
            elif isinstance(action, types.MessageActionChatEditTitle):
                new_chat_title = action.title
            elif isinstance(action, types.MessageActionChatDeletePhoto):
                delete_chat_photo = True
            elif isinstance(action, types.MessageActionChatMigrateTo):
                migrate_to_chat_id = action.channel_id
            elif isinstance(action, types.MessageActionChannelMigrateFrom):
                migrate_from_chat_id = action.chat_id
            elif isinstance(action, types.MessageActionChatCreate):
                group_chat_created = True
            elif isinstance(action, types.MessageActionChannelCreate):
                channel_chat_created = True
            elif isinstance(action, types.MessageActionChatEditPhoto):
                photo = action.photo

                if isinstance(photo, types.Photo):
                    sizes = photo.sizes
                    photo_sizes = []

                    for size in sizes:
                        if isinstance(
                                size,
                            (types.PhotoSize, types.PhotoCachedSize)):
                            loc = size.location

                            if isinstance(size, types.PhotoSize):
                                file_size = size.size
                            else:
                                file_size = len(size.bytes)

                            if isinstance(loc, types.FileLocation):
                                photo_size = pyrogram_types.PhotoSize(
                                    file_id=encode(
                                        pack("<iiqqqqi", 2, loc.dc_id,
                                             photo.id, photo.access_hash,
                                             loc.volume_id, loc.secret,
                                             loc.local_id)),
                                    width=size.w,
                                    height=size.h,
                                    file_size=file_size)

                                photo_sizes.append(photo_size)

                    new_chat_photo = pyrogram_types.Photo(id=b64encode(
                        pack("<qq", photo.id, photo.access_hash),
                        b"-_").decode().rstrip("="),
                                                          date=photo.date,
                                                          sizes=photo_sizes)

            m = pyrogram_types.Message(
                message_id=message.id,
                date=message.date,
                chat=parse_chat(message, users, chats),
                from_user=parse_user(users.get(message.from_id, None)),
                service=True,
                new_chat_members=new_chat_members,
                left_chat_member=left_chat_member,
                new_chat_title=new_chat_title,
                new_chat_photo=new_chat_photo,
                delete_chat_photo=delete_chat_photo,
                migrate_to_chat_id=int("-100" + str(migrate_to_chat_id))
                if migrate_to_chat_id else None,
                migrate_from_chat_id=-migrate_from_chat_id
                if migrate_from_chat_id else None,
                group_chat_created=group_chat_created,
                channel_chat_created=channel_chat_created,
                client=proxy(client)
                # TODO: supergroup_chat_created
            )

            if isinstance(action, types.MessageActionPinMessage):
                try:
                    m.pinned_message = client.get_messages(
                        m.chat.id, reply_to_message_ids=message.id, replies=0)
                except MessageIdsEmpty:
                    pass
        else:
            m = pyrogram_types.Message(message_id=message.id,
                                       client=proxy(client),
                                       empty=True)

        parsed_messages.append(m)

    return parsed_messages if is_list else parsed_messages[0]
コード例 #2
0
    def download_media(self,
                       message: pyrogram_types.Message or str,
                       file_name: str = "",
                       block: bool = True,
                       progress: callable = None,
                       progress_args: tuple = None):
        """Use this method to download the media from a Message.

        Args:
            message (:obj:`Message <pyrogram.Message>` | ``str``):
                Pass a Message containing the media, the media itself (message.audio, message.video, ...) or
                the file id as string.

            file_name (``str``, *optional*):
                A custom *file_name* to be used instead of the one provided by Telegram.
                By default, all files are downloaded in the *downloads* folder in your working directory.
                You can also specify a path for downloading files in a custom location: paths that end with "/"
                are considered directories. All non-existent folders will be created automatically.

            block (``bool``, *optional*):
                Blocks the code execution until the file has been downloaded.
                Defaults to True.

            progress (``callable``):
                Pass a callback function to view the download progress.
                The function must take *(client, current, total, \*args)* as positional arguments (look at the section
                below for a detailed description).

            progress_args (``tuple``):
                Extra custom arguments for the progress callback function. Useful, for example, if you want to pass
                a chat_id and a message_id in order to edit a message with the updated progress.

        Other Parameters:
            client (:obj:`Client <pyrogram.Client>`):
                The Client itself, useful when you want to call other API methods inside the callback function.

            current (``int``):
                The amount of bytes downloaded so far.

            total (``int``):
                The size of the file.

            *args (``tuple``, *optional*):
                Extra custom arguments as defined in the *progress_args* parameter.
                You can either keep *\*args* or add every single extra argument in your function signature.

        Returns:
            On success, the absolute path of the downloaded file as string is returned, None otherwise.

        Raises:
            :class:`Error <pyrogram.Error>`
        """
        if isinstance(message, pyrogram_types.Message):
            if message.photo:
                media = message.photo[-1]
            elif message.audio:
                media = message.audio
            elif message.document:
                media = message.document
            elif message.video:
                media = message.video
            elif message.voice:
                media = message.voice
            elif message.video_note:
                media = message.video_note
            elif message.sticker:
                media = message.sticker
            elif message.gif:
                media = message.gif
            else:
                return
        elif isinstance(message,
                        (pyrogram_types.PhotoSize, pyrogram_types.Audio,
                         pyrogram_types.Document, pyrogram_types.Video,
                         pyrogram_types.Voice, pyrogram_types.VideoNote,
                         pyrogram_types.Sticker, pyrogram_types.GIF)):
            media = message
        elif isinstance(message, str):
            media = pyrogram_types.Document(file_id=message,
                                            file_size=0,
                                            mime_type="")
        else:
            return

        done = Event()
        path = [None]

        self.download_queue.put(
            (media, file_name, done, progress, progress_args, path))

        if block:
            done.wait()

        return path[0]
コード例 #3
0
ファイル: utils.py プロジェクト: libofeng/pyrogram
def parse_message(client,
                  message: types.Message,
                  users: dict,
                  chats: dict,
                  replies: int = 1) -> pyrogram_types.Message:
    entities = parse_entities(message.entities, users)

    forward_from = None
    forward_from_chat = None
    forward_from_message_id = None
    forward_signature = None
    forward_date = None

    forward_header = message.fwd_from  # type: types.MessageFwdHeader

    if forward_header:
        forward_date = forward_header.date

        if forward_header.from_id:
            forward_from = parse_user(users[forward_header.from_id])
        else:
            forward_from_chat = parse_channel_chat(
                chats[forward_header.channel_id])
            forward_from_message_id = forward_header.channel_post
            forward_signature = forward_header.post_author

    photo = None
    location = None
    contact = None
    venue = None
    audio = None
    voice = None
    video = None
    video_note = None
    sticker = None
    document = None

    media = message.media

    if media:
        if isinstance(media, types.MessageMediaPhoto):
            photo = media.photo

            if isinstance(photo, types.Photo):
                sizes = photo.sizes
                photo_sizes = []

                for size in sizes:
                    if isinstance(size,
                                  (types.PhotoSize, types.PhotoCachedSize)):
                        loc = size.location

                        if isinstance(size, types.PhotoSize):
                            file_size = size.size
                        else:
                            file_size = len(size.bytes)

                        if isinstance(loc, types.FileLocation):
                            photo_size = pyrogram_types.PhotoSize(
                                file_id=encode(
                                    pack("<iiqqqqi", 2, loc.dc_id, photo.id,
                                         photo.access_hash, loc.volume_id,
                                         loc.secret, loc.local_id)),
                                width=size.w,
                                height=size.h,
                                file_size=file_size,
                                date=photo.date)

                            photo_sizes.append(photo_size)

                photo = photo_sizes
        elif isinstance(media, types.MessageMediaGeo):
            geo_point = media.geo

            if isinstance(geo_point, types.GeoPoint):
                location = pyrogram_types.Location(longitude=geo_point.long,
                                                   latitude=geo_point.lat)
        elif isinstance(media, types.MessageMediaContact):
            contact = pyrogram_types.Contact(phone_number=media.phone_number,
                                             first_name=media.first_name,
                                             last_name=media.last_name or None,
                                             user_id=media.user_id or None)
        elif isinstance(media, types.MessageMediaVenue):
            venue = pyrogram_types.Venue(location=pyrogram_types.Location(
                longitude=media.geo.long, latitude=media.geo.lat),
                                         title=media.title,
                                         address=media.address,
                                         foursquare_id=media.venue_id or None)
        elif isinstance(media, types.MessageMediaDocument):
            doc = media.document

            if isinstance(doc, types.Document):
                attributes = {type(i): i for i in doc.attributes}

                file_name = getattr(
                    attributes.get(types.DocumentAttributeFilename, None),
                    "file_name", None)

                if types.DocumentAttributeAudio in attributes:
                    audio_attributes = attributes[types.DocumentAttributeAudio]

                    if audio_attributes.voice:
                        voice = pyrogram_types.Voice(
                            file_id=encode(
                                pack("<iiqq", 3, doc.dc_id, doc.id,
                                     doc.access_hash)),
                            duration=audio_attributes.duration,
                            mime_type=doc.mime_type,
                            file_size=doc.size,
                            thumb=parse_thumb(doc.thumb),
                            file_name=file_name,
                            date=doc.date)
                    else:
                        audio = pyrogram_types.Audio(
                            file_id=encode(
                                pack("<iiqq", 9, doc.dc_id, doc.id,
                                     doc.access_hash)),
                            duration=audio_attributes.duration,
                            performer=audio_attributes.performer,
                            title=audio_attributes.title,
                            mime_type=doc.mime_type,
                            file_size=doc.size,
                            thumb=parse_thumb(doc.thumb),
                            file_name=file_name,
                            date=doc.date)
                elif types.DocumentAttributeAnimated in attributes:
                    document = pyrogram_types.Document(file_id=encode(
                        pack("<iiqq", 10, doc.dc_id, doc.id, doc.access_hash)),
                                                       thumb=parse_thumb(
                                                           doc.thumb),
                                                       file_name=file_name,
                                                       mime_type=doc.mime_type,
                                                       file_size=doc.size,
                                                       date=doc.date)
                elif types.DocumentAttributeVideo in attributes:
                    video_attributes = attributes[types.DocumentAttributeVideo]

                    if video_attributes.round_message:
                        video_note = pyrogram_types.VideoNote(
                            file_id=encode(
                                pack("<iiqq", 13, doc.dc_id, doc.id,
                                     doc.access_hash)),
                            length=video_attributes.w,
                            duration=video_attributes.duration,
                            thumb=parse_thumb(doc.thumb),
                            file_size=doc.size,
                            file_name=file_name,
                            mime_type=doc.mime_type,
                            date=doc.date)
                    else:
                        video = pyrogram_types.Video(
                            file_id=encode(
                                pack("<iiqq", 4, doc.dc_id, doc.id,
                                     doc.access_hash)),
                            width=video_attributes.w,
                            height=video_attributes.h,
                            duration=video_attributes.duration,
                            thumb=parse_thumb(doc.thumb),
                            mime_type=doc.mime_type,
                            file_size=doc.size,
                            file_name=file_name,
                            date=doc.date)
                elif types.DocumentAttributeSticker in attributes:
                    image_size_attributes = attributes.get(
                        types.DocumentAttributeImageSize, None)
                    sticker_attribute = attributes[
                        types.DocumentAttributeSticker]

                    if isinstance(sticker_attribute.stickerset,
                                  types.InputStickerSetID):
                        try:
                            set_name = client.send(
                                functions.messages.GetStickerSet(
                                    sticker_attribute.stickerset)
                            ).set.short_name
                        except StickersetInvalid:
                            set_name = None
                    else:
                        set_name = None

                    sticker = pyrogram_types.Sticker(
                        file_id=encode(
                            pack("<iiqq", 8, doc.dc_id, doc.id,
                                 doc.access_hash)),
                        width=image_size_attributes.w
                        if image_size_attributes else 0,
                        height=image_size_attributes.h
                        if image_size_attributes else 0,
                        thumb=parse_thumb(doc.thumb),
                        # TODO: mask_position
                        set_name=set_name,
                        emoji=sticker_attribute.alt or None,
                        file_size=doc.size,
                        mime_type=doc.mime_type,
                        file_name=file_name,
                        date=doc.date)
                else:
                    document = pyrogram_types.Document(file_id=encode(
                        pack("<iiqq", 5, doc.dc_id, doc.id, doc.access_hash)),
                                                       thumb=parse_thumb(
                                                           doc.thumb),
                                                       file_name=file_name,
                                                       mime_type=doc.mime_type,
                                                       file_size=doc.size,
                                                       date=doc.date)
        else:
            media = None

    reply_markup = message.reply_markup

    if reply_markup:
        if isinstance(reply_markup, types.ReplyKeyboardForceReply):
            reply_markup = pyrogram_types.ForceReply.read(reply_markup)
        elif isinstance(reply_markup, types.ReplyKeyboardMarkup):
            reply_markup = pyrogram_types.ReplyKeyboardMarkup.read(
                reply_markup)
        elif isinstance(reply_markup, types.ReplyInlineMarkup):
            reply_markup = pyrogram_types.InlineKeyboardMarkup.read(
                reply_markup)
        elif isinstance(reply_markup, types.ReplyKeyboardHide):
            reply_markup = pyrogram_types.ReplyKeyboardRemove.read(
                reply_markup)
        else:
            reply_markup = None

    m = pyrogram_types.Message(
        message_id=message.id,
        date=message.date,
        chat=parse_chat(message, users, chats),
        from_user=parse_user(users.get(message.from_id, None)),
        text=message.message or None if media is None else None,
        caption=message.message or None if media is not None else None,
        entities=entities or None if media is None else None,
        caption_entities=entities or None if media is not None else None,
        author_signature=message.post_author,
        forward_from=forward_from,
        forward_from_chat=forward_from_chat,
        forward_from_message_id=forward_from_message_id,
        forward_signature=forward_signature,
        forward_date=forward_date,
        edit_date=message.edit_date,
        media_group_id=message.grouped_id,
        photo=photo,
        location=location,
        contact=contact,
        venue=venue,
        audio=audio,
        voice=voice,
        video=video,
        video_note=video_note,
        sticker=sticker,
        document=document,
        views=message.views,
        via_bot=parse_user(users.get(message.via_bot_id, None)),
        outgoing=message.out,
        client=proxy(client),
        reply_markup=reply_markup)

    if message.reply_to_msg_id and replies:
        m.reply_to_message = client.get_messages(m.chat.id,
                                                 message.reply_to_msg_id,
                                                 replies=replies - 1)

    return m