Exemplo n.º 1
0
def get_bottom_post_list(api, board):
    api._goto_board(board, end=True)

    last_screen = api.connect_core.get_screen_queue()[-1]

    # print(last_screen)

    bottom_screen = [
        line for line in last_screen.split('\n') if '★' in line[:8]
    ]
    bottom_length = len(bottom_screen)
    # bottom_screen = '\n'.join(bottom_screen)
    # print(bottom_screen)

    if bottom_length == 0:
        log.log(api.config, log.level.INFO, i18n.CatchBottomPostSuccess)
        return list()

    cmd_list = list()
    cmd_list.append(command.QueryPost)
    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit([
            i18n.CatchPost,
            i18n.Success,
        ],
                                screens.Target.QueryPost,
                                break_detect=True,
                                refresh=False,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.PostDeleted,
            i18n.Success,
        ],
                                screens.Target.InBoard,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit(i18n.NoSuchBoard,
                                screens.Target.MainMenu_Exiting,
                                exceptions_=exceptions.NoSuchBoard(
                                    api.config, board)),
    ]

    result = list()
    for _ in range(0, bottom_length):
        api.connect_core.send(cmd, target_list)
        last_screen = api.connect_core.get_screen_queue()[-1]

        lock_post, post_author, post_title, post_aid, post_web, post_money, list_date, push_number, post_index = \
            _api_util.parse_query_post(
                api,
                last_screen)

        current_post = api.get_post(board, post_aid=post_aid, query=True)

        # print(current_post.aid)
        # print(current_post.title)
        # print('==========================')

        result.append(current_post)

        cmd_list = list()
        cmd_list.append(command.Enter)
        cmd_list.append(command.Up)
        cmd_list.append(command.QueryPost)
        cmd = ''.join(cmd_list)

    log.log(api.config, log.level.INFO, i18n.CatchBottomPostSuccess)

    return list(reversed(result))
Exemplo n.º 2
0
def get_post(api,
             board: str,
             post_aid: str = None,
             post_index: int = 0,
             search_type: int = 0,
             search_condition: str = None,
             search_list: list = None,
             query: bool = False) -> data_type.PostInfo:
    api._goto_board(board)

    cmd_list = list()

    if post_aid is not None:
        cmd_list.append('#' + post_aid)

    elif post_index != 0:
        if search_condition is not None:
            if search_type == data_type.post_search_type.KEYWORD:
                cmd_list.append('/')
            elif search_type == data_type.post_search_type.AUTHOR:
                cmd_list.append('a')
            elif search_type == data_type.post_search_type.PUSH:
                cmd_list.append('Z')
            elif search_type == data_type.post_search_type.MARK:
                cmd_list.append('G')
            elif search_type == data_type.post_search_type.MONEY:
                cmd_list.append('A')

            cmd_list.append(search_condition)
            cmd_list.append(command.Enter)

        if search_list is not None:
            for search_type_, search_condition_ in search_list:

                if search_type_ == data_type.post_search_type.KEYWORD:
                    cmd_list.append('/')
                elif search_type_ == data_type.post_search_type.AUTHOR:
                    cmd_list.append('a')
                elif search_type_ == data_type.post_search_type.PUSH:
                    cmd_list.append('Z')
                elif search_type_ == data_type.post_search_type.MARK:
                    cmd_list.append('G')
                elif search_type_ == data_type.post_search_type.MONEY:
                    cmd_list.append('A')

                cmd_list.append(search_condition_)
                cmd_list.append(command.Enter)

        cmd_list.append(str(max(1, post_index - 100)))
        cmd_list.append(command.Enter)
        cmd_list.append(str(post_index))

    cmd_list.append(command.Enter)
    cmd_list.append(command.QueryPost)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit([
            i18n.CatchPost,
            i18n.Success,
        ],
                                screens.Target.QueryPost,
                                break_detect=True,
                                refresh=False,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.PostDeleted,
            i18n.Success,
        ],
                                screens.Target.InBoard,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit(i18n.NoSuchBoard,
                                screens.Target.MainMenu_Exiting,
                                exceptions_=exceptions.NoSuchBoard(
                                    api.config, board)),
    ]

    index = api.connect_core.send(cmd, target_list)
    ori_screen = api.connect_core.get_screen_queue()[-1]

    post_author = None
    post_title = None
    if index < 0 or index == 1:
        # 文章被刪除
        log.log(api.config, log.level.DEBUG, i18n.PostDeleted)

        log.show_value(api.config, log.level.DEBUG, 'OriScreen', ori_screen)

        cursor_line = [
            line for line in ori_screen.split('\n')
            if line.startswith(api.cursor)
        ]

        if len(cursor_line) != 1:
            raise exceptions.UnknownError(ori_screen)

        cursor_line = cursor_line[0]
        log.show_value(api.config, log.level.DEBUG, 'CursorLine', cursor_line)

        pattern = re.compile('[\d]+\/[\d]+')
        pattern_result = pattern.search(cursor_line)
        if pattern_result is None:
            list_date = None
        else:
            list_date = pattern_result.group(0)
            list_date = list_date[-5:]

        pattern = re.compile('\[[\w]+\]')
        pattern_result = pattern.search(cursor_line)
        if pattern_result is not None:
            post_del_status = data_type.post_delete_status.AUTHOR
        else:
            pattern = re.compile('<[\w]+>')
            pattern_result = pattern.search(cursor_line)
            post_del_status = data_type.post_delete_status.MODERATOR

        # > 79843     9/11 -             □ (本文已被吃掉)<
        # > 76060     8/28 -             □ (本文已被刪除) [weida7332]
        # print(f'O=>{CursorLine}<')
        if pattern_result is not None:
            post_author = pattern_result.group(0)[1:-1]
        else:
            post_author = None
            post_del_status = data_type.post_delete_status.UNKNOWN

        log.show_value(api.config, log.level.DEBUG, 'ListDate', list_date)
        log.show_value(api.config, log.level.DEBUG, 'PostAuthor', post_author)
        log.show_value(api.config, log.level.DEBUG, 'post_del_status',
                       post_del_status)

        return data_type.PostInfo(board=board,
                                  author=post_author,
                                  list_date=list_date,
                                  delete_status=post_del_status,
                                  format_check=True)

    elif index == 0:

        lock_post, post_author, post_title, post_aid, post_web, post_money, list_date, push_number, post_index = \
            _api_util.parse_query_post(
                api,
                ori_screen)

        if lock_post:
            post = data_type.PostInfo(board=board,
                                      aid=post_aid,
                                      index=post_index,
                                      author=post_author,
                                      title=post_title,
                                      web_url=post_web,
                                      money=post_money,
                                      list_date=list_date,
                                      format_check=True,
                                      push_number=push_number,
                                      lock=True)

            return post

    if query:
        post = data_type.PostInfo(board=board,
                                  aid=post_aid,
                                  index=post_index,
                                  author=post_author,
                                  title=post_title,
                                  web_url=post_web,
                                  money=post_money,
                                  list_date=list_date,
                                  format_check=True,
                                  push_number=push_number)
        return post

    origin_post, has_control_code = _api_util.get_content(api)

    if origin_post is None:
        post = data_type.PostInfo(board=board,
                                  aid=post_aid,
                                  index=post_index,
                                  author=post_author,
                                  title=post_title,
                                  web_url=post_web,
                                  money=post_money,
                                  list_date=list_date,
                                  control_code=has_control_code,
                                  format_check=False,
                                  push_number=push_number,
                                  unconfirmed=api.Unconfirmed)
        return post

    # print('=' * 20)
    # print(origin_post)
    # print('=' * 20)

    content_start = '───────────────────────────────────────'
    content_end = list()
    content_end.append('--\n※ 發信站: 批踢踢實業坊')
    content_end.append('--\n※ 發信站: 批踢踢兔(ptt2.cc)')
    content_end.append('--\n※ 發信站: 新批踢踢(ptt2.twbbs.org.tw)')

    post_author_pattern_new = re.compile('作者  (.+) 看板')
    post_author_pattern_old = re.compile('作者  (.+)')
    board_pattern = re.compile('看板  (.+)')

    post_date = None
    post_content = list()
    ip = None
    location = None
    push_list = list()

    # 格式確認,亂改的我也沒辦法Q_Q
    origin_post_lines = origin_post.split('\n')

    author_line = origin_post_lines[0]

    if board.lower() == 'allpost':
        board_line = author_line[author_line.find(')') + 1:]
        pattern_result = board_pattern.search(board_line)
        if pattern_result is not None:
            board_temp = post_author = pattern_result.group(0)
            board_temp = board_temp[2:].strip()
            if len(board_temp) > 0:
                board = board_temp
                log.show_value(api.config, log.level.DEBUG, i18n.Board, board)
    pattern_result = post_author_pattern_new.search(author_line)
    if pattern_result is not None:
        post_author = pattern_result.group(0)
        post_author = post_author[:post_author.rfind(')') + 1]
    else:
        pattern_result = post_author_pattern_old.search(author_line)
        if pattern_result is None:
            log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                           i18n.Author)
            post = data_type.PostInfo(
                board=board,
                aid=post_aid,
                index=post_index,
                author=post_author,
                date=post_date,
                title=post_title,
                web_url=post_web,
                money=post_money,
                content=post_content,
                ip=ip,
                push_list=push_list,
                list_date=list_date,
                control_code=has_control_code,
                format_check=False,
                location=location,
                push_number=push_number,
                origin_post=origin_post,
                unconfirmed=api.Unconfirmed,
            )
            return post
        post_author = pattern_result.group(0)
        post_author = post_author[:post_author.rfind(')') + 1]
    post_author = post_author[4:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Author, post_author)

    post_title_pattern = re.compile('標題  (.+)')

    title_line = origin_post_lines[1]
    pattern_result = post_title_pattern.search(title_line)
    if pattern_result is None:
        log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                       i18n.Title)

        post = data_type.PostInfo(board=board,
                                  aid=post_aid,
                                  index=post_index,
                                  author=post_author,
                                  date=post_date,
                                  title=post_title,
                                  web_url=post_web,
                                  money=post_money,
                                  content=post_content,
                                  ip=ip,
                                  push_list=push_list,
                                  list_date=list_date,
                                  control_code=has_control_code,
                                  format_check=False,
                                  location=location,
                                  push_number=push_number,
                                  origin_post=origin_post,
                                  unconfirmed=api.Unconfirmed)
        return post
    post_title = pattern_result.group(0)
    post_title = post_title[4:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Title, post_title)

    post_date_pattern = re.compile('時間  .{24}')
    date_line = origin_post_lines[2]
    pattern_result = post_date_pattern.search(date_line)
    if pattern_result is None:
        log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                       i18n.Date)
        post = data_type.PostInfo(
            board=board,
            aid=post_aid,
            index=post_index,
            author=post_author,
            date=post_date,
            title=post_title,
            web_url=post_web,
            money=post_money,
            content=post_content,
            ip=ip,
            push_list=push_list,
            list_date=list_date,
            control_code=has_control_code,
            format_check=False,
            location=location,
            push_number=push_number,
            origin_post=origin_post,
            unconfirmed=api.Unconfirmed,
        )
        return post
    post_date = pattern_result.group(0)
    post_date = post_date[4:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Date, post_date)

    content_fail = True
    if content_start not in origin_post:
        # print('Type 1')
        content_fail = True
    else:
        post_content = origin_post
        post_content = post_content[post_content.find(content_start) +
                                    len(content_start) + 1:]
        # print('Type 2')
        # print(f'PostContent [{PostContent}]')
        for EC in content_end:
            # + 3 = 把 --\n 拿掉
            # print(f'EC [{EC}]')
            if EC in post_content:
                content_fail = False

                post_content = post_content[:post_content.rfind(EC) + 3]
                origin_post_lines = origin_post[origin_post.find(EC):]
                # post_content = post_content.strip()
                origin_post_lines = origin_post_lines.split('\n')
                break

    if content_fail:
        log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                       i18n.Content)
        post = data_type.PostInfo(
            board=board,
            aid=post_aid,
            index=post_index,
            author=post_author,
            date=post_date,
            title=post_title,
            web_url=post_web,
            money=post_money,
            content=post_content,
            ip=ip,
            push_list=push_list,
            list_date=list_date,
            control_code=has_control_code,
            format_check=False,
            location=location,
            push_number=push_number,
            origin_post=origin_post,
            unconfirmed=api.Unconfirmed,
        )
        return post

    log.show_value(api.config, log.level.DEBUG, i18n.Content, post_content)

    info_lines = [
        line for line in origin_post_lines
        if line.startswith('※') or line.startswith('◆')
    ]

    pattern = re.compile('[\d]+\.[\d]+\.[\d]+\.[\d]+')
    pattern_p2 = re.compile('[\d]+-[\d]+-[\d]+-[\d]+')
    for line in reversed(info_lines):
        log.show_value(api.config, log.level.DEBUG, 'IP Line', line)

        # type 1
        # ※ 編輯: CodingMan (111.243.146.98 臺灣)
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.243.146.98 (臺灣)

        # type 2
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 116.241.32.178
        # ※ 編輯: kill77845 (114.136.55.237), 12/08/2018 16:47:59

        # type 3
        # ※ 發信站: 批踢踢實業坊(ptt.cc)
        # ◆ From: 211.20.78.69
        # ※ 編輯: JCC             來自: 211.20.78.69         (06/20 10:22)
        # ※ 編輯: JCC (118.163.28.150), 12/03/2015 14:25:35

        pattern_result = pattern.search(line)
        if pattern_result is not None:
            ip = pattern_result.group(0)
            location_temp = line[line.find(ip) + len(ip):].strip()
            location_temp = location_temp.replace('(', '')
            location_temp = location_temp[:location_temp.rfind(')')]
            location_temp = location_temp.strip()
            # print(f'=>[{LocationTemp}]')
            if ' ' not in location_temp and len(location_temp) > 0:
                location = location_temp
                log.show_value(api.config, log.level.DEBUG, 'Location',
                               location)
            break

        pattern_result = pattern_p2.search(line)
        if pattern_result is not None:
            ip = pattern_result.group(0)
            ip = ip.replace('-', '.')
            # print(f'IP -> [{IP}]')
            break
    if api.config.host == data_type.host_type.PTT1:
        if ip is None:
            log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                           'IP')
            post = data_type.PostInfo(
                board=board,
                aid=post_aid,
                index=post_index,
                author=post_author,
                date=post_date,
                title=post_title,
                web_url=post_web,
                money=post_money,
                content=post_content,
                ip=ip,
                push_list=push_list,
                list_date=list_date,
                control_code=has_control_code,
                format_check=False,
                location=location,
                push_number=push_number,
                origin_post=origin_post,
                unconfirmed=api.Unconfirmed,
            )
            return post
    log.show_value(api.config, log.level.DEBUG, 'IP', ip)

    push_author_pattern = re.compile('[推|噓|→] [\w| ]+:')
    push_date_pattern = re.compile('[\d]+/[\d]+ [\d]+:[\d]+')
    push_ip_pattern = re.compile('[\d]+\.[\d]+\.[\d]+\.[\d]+')

    push_list = list()

    for line in origin_post_lines:
        if line.startswith('推'):
            push_type = data_type.push_type.PUSH
        elif line.startswith('噓 '):
            push_type = data_type.push_type.BOO
        elif line.startswith('→ '):
            push_type = data_type.push_type.ARROW
        else:
            continue

        result = push_author_pattern.search(line)
        if result is None:
            # 不符合推文格式
            continue
        push_author = result.group(0)[2:-1].strip()
        log.show_value(api.config, log.level.DEBUG, [
            i18n.Push,
            i18n.ID,
        ], push_author)

        result = push_date_pattern.search(line)
        if result is None:
            continue
        push_date = result.group(0)
        log.show_value(api.config, log.level.DEBUG, [
            i18n.Push,
            i18n.Date,
        ], push_date)

        push_ip = None
        result = push_ip_pattern.search(line)
        if result is not None:
            push_ip = result.group(0)
            log.show_value(api.config, log.level.DEBUG, [
                i18n.Push,
                'IP',
            ], push_ip)

        push_content = line[line.find(push_author) + len(push_author):]
        # PushContent = PushContent.replace(PushDate, '')

        if api.config.host == data_type.host_type.PTT1:
            push_content = push_content[:push_content.rfind(push_date)]
        else:
            # → CodingMan:What is Ptt?                                       推 10/04 13:25
            push_content = push_content[:push_content.rfind(push_date) - 2]
        if push_ip is not None:
            push_content = push_content.replace(push_ip, '')
        push_content = push_content[push_content.find(':') + 1:].strip()
        log.show_value(api.config, log.level.DEBUG, [
            i18n.Push,
            i18n.Content,
        ], push_content)

        current_push = data_type.PushInfo(push_type, push_author, push_content,
                                          push_ip, push_date)
        push_list.append(current_push)

    post = data_type.PostInfo(
        board=board,
        aid=post_aid,
        index=post_index,
        author=post_author,
        date=post_date,
        title=post_title,
        web_url=post_web,
        money=post_money,
        content=post_content,
        ip=ip,
        push_list=push_list,
        list_date=list_date,
        control_code=has_control_code,
        format_check=True,
        location=location,
        push_number=push_number,
        origin_post=origin_post,
        unconfirmed=api.Unconfirmed,
    )
    return post
Exemplo n.º 3
0
def get_post(api,
             board: str,
             post_aid: str = None,
             post_index: int = 0,
             search_type: int = 0,
             search_condition: str = None,
             search_list: list = None,
             query: bool = False) -> data_type.PostInfo:

    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('qs')
    cmd_list.append(board)
    cmd_list.append(command.Enter)
    cmd_list.append(command.Ctrl_C * 2)
    cmd_list.append(command.Space)

    if post_aid is not None:
        cmd_list.append('#' + post_aid)

    elif post_index != 0:
        if search_condition is not None:
            if search_type == data_type.post_search_type.KEYWORD:
                cmd_list.append('/')
            elif search_type == data_type.post_search_type.AUTHOR:
                cmd_list.append('a')
            elif search_type == data_type.post_search_type.PUSH:
                cmd_list.append('Z')
            elif search_type == data_type.post_search_type.MARK:
                cmd_list.append('G')
            elif search_type == data_type.post_search_type.MONEY:
                cmd_list.append('A')

            cmd_list.append(search_condition)
            cmd_list.append(command.Enter)

        if search_list is not None:
            for search_type_, search_condition_ in search_list:

                if search_type_ == data_type.post_search_type.KEYWORD:
                    cmd_list.append('/')
                elif search_type_ == data_type.post_search_type.AUTHOR:
                    cmd_list.append('a')
                elif search_type_ == data_type.post_search_type.PUSH:
                    cmd_list.append('Z')
                elif search_type_ == data_type.post_search_type.MARK:
                    cmd_list.append('G')
                elif search_type_ == data_type.post_search_type.MONEY:
                    cmd_list.append('A')

                cmd_list.append(search_condition_)
                cmd_list.append(command.Enter)

        cmd_list.append(str(post_index))

    cmd_list.append(command.Enter)
    cmd_list.append(command.QueryPost)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit([
            i18n.CatchPost,
            i18n.Success,
        ],
                                screens.Target.QueryPost,
                                break_detect=True,
                                refresh=False,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.PostDeleted,
            i18n.Success,
        ],
                                screens.Target.InBoard,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit(i18n.NoSuchBoard,
                                screens.Target.MainMenu_Exiting,
                                exceptions_=exceptions.NoSuchBoard(
                                    api.config, board)),
    ]

    index = api.connect_core.send(cmd, target_list)
    ori_screen = api.connect_core.get_screen_queue()[-1]

    post_author = None
    post_title = None
    if index < 0 or index == 1:
        # 文章被刪除
        log.log(api.config, log.level.DEBUG, i18n.PostDeleted)

        log.show_value(api.config, log.level.DEBUG, 'OriScreen', ori_screen)

        cursor_line = [
            line for line in ori_screen.split('\n')
            if line.startswith(api.cursor)
        ]

        if len(cursor_line) != 1:
            raise exceptions.UnknownError(ori_screen)

        cursor_line = cursor_line[0]
        log.show_value(api.config, log.level.DEBUG, 'CursorLine', cursor_line)

        pattern = re.compile('[\d]+\/[\d]+')
        pattern_result = pattern.search(cursor_line)
        if pattern_result is None:
            list_date = None
        else:
            list_date = pattern_result.group(0)
            list_date = list_date[-5:]

        pattern = re.compile('\[[\w]+\]')
        pattern_result = pattern.search(cursor_line)
        if pattern_result is not None:
            post_del_status = data_type.post_delete_status.AUTHOR
        else:
            pattern = re.compile('<[\w]+>')
            pattern_result = pattern.search(cursor_line)
            post_del_status = data_type.post_delete_status.MODERATOR

        # > 79843     9/11 -             □ (本文已被吃掉)<
        # > 76060     8/28 -             □ (本文已被刪除) [weida7332]
        # print(f'O=>{CursorLine}<')
        if pattern_result is not None:
            post_author = pattern_result.group(0)[1:-1]
        else:
            post_author = None
            post_del_status = data_type.post_delete_status.UNKNOWN

        log.show_value(api.config, log.level.DEBUG, 'ListDate', list_date)
        log.show_value(api.config, log.level.DEBUG, 'PostAuthor', post_author)
        log.show_value(api.config, log.level.DEBUG, 'post_del_status',
                       post_del_status)

        return data_type.PostInfo(board=board,
                                  author=post_author,
                                  list_date=list_date,
                                  delete_status=post_del_status,
                                  format_check=True)

    elif index == 0:

        lock_post = False
        try:
            cursor_line = [
                line for line in ori_screen.split('\n')
                if line.strip().startswith(api.cursor)
            ][0]
        except Exception as e:
            print(api.cursor)
            print(ori_screen)
            raise e

        post_author = cursor_line
        if '□' in post_author:
            post_author = post_author[:post_author.find('□')].strip()
        elif 'R:' in post_author:
            post_author = post_author[:post_author.find('R:')].strip()
        elif ' 轉 ' in post_author:
            post_author = post_author[:post_author.find('轉')].strip()
        elif ' 鎖 ' in post_author:
            post_author = post_author[:post_author.find('鎖')].strip()
            lock_post = True
        post_author = post_author[post_author.rfind(' '):].strip()

        post_title = cursor_line
        if ' □ ' in post_title:
            post_title = post_title[post_title.find('□') + 1:].strip()
        elif ' R:' in post_title:
            post_title = post_title[post_title.find('R:'):].strip()
        elif ' 轉 ' in post_title:
            # print(f'[{PostTitle}]=========>')
            post_title = post_title[post_title.find('轉') + 1:].strip()
            post_title = f'Fw: {post_title}'
            # print(f'=========>[{PostTitle}]')
        elif ' 鎖 ' in post_title:
            post_title = post_title[post_title.find('鎖') + 1:].strip()

        ori_screen_temp = ori_screen[ori_screen.find('┌──────────'):]
        ori_screen_temp = ori_screen_temp[:ori_screen_temp.
                                          find('└─────────────')]

        aid_line = [
            line for line in ori_screen.split('\n')
            if line.startswith('│ 文章代碼(AID)')
        ]

        if len(aid_line) == 1:
            aid_line = aid_line[0]
            pattern = re.compile('#[\w|-]+')
            pattern_result = pattern.search(aid_line)
            post_aid = pattern_result.group(0)[1:]

        pattern = re.compile('文章網址: https:[\S]+html')
        pattern_result = pattern.search(ori_screen_temp)
        if pattern_result is None:
            post_web = None
        else:
            post_web = pattern_result.group(0)[6:]

        pattern = re.compile('這一篇文章值 [\d]+ Ptt幣')
        pattern_result = pattern.search(ori_screen_temp)
        if pattern_result is None:
            # 特殊文章無價格
            post_money = -1
        else:
            post_money = pattern_result.group(0)[7:]
            post_money = post_money[:post_money.find(' ')]
            post_money = int(post_money)

        pattern = re.compile('[\d]+\/[\d]+')
        pattern_result = pattern.search(cursor_line)
        if pattern_result is None:
            list_date = None
        else:
            list_date = pattern_result.group(0)
            list_date = list_date[-5:]
        # print(list_date)

        # >  7485   9 8/09 CodingMan    □ [閒聊] PTT Library 更新
        # > 79189 M 1 9/17 LittleCalf   □ [公告] 禁言退文公告
        # >781508 +爆 9/17 jodojeda     □ [新聞] 國人吃魚少 學者:應把吃魚當成輕鬆愉快
        # >781406 +X1 9/17 kingofage111 R: [申請] ReDmango 請辭Gossiping板主職務

        if post_index == 0:
            pattern = re.compile('[\d]+')
            pattern_result = pattern.search(cursor_line)
            if pattern_result is not None:
                post_index = int(pattern_result.group(0))

        push_number = cursor_line
        # print(f'2>{push_number}<')
        push_number = push_number[7:10]
        # print(push_number)
        push_number = push_number.split(' ')
        # print(PushNumber)
        push_number = list(filter(None, push_number))
        # print(PushNumber)

        if len(push_number) == 0:
            push_number = None
        else:
            push_number = push_number[-1]
            # print(PushNumber)

            if push_number.startswith('+') or push_number.startswith('~'):
                push_number = push_number[1:]
                # print(PushNumber)
            if push_number.lower().startswith('m'):
                push_number = push_number[1:]
                # print(PushNumber)
            if push_number.lower().startswith('!'):
                push_number = push_number[1:]

            if push_number.lower().startswith('s'):
                push_number = push_number[1:]

            if push_number.lower().startswith('='):
                push_number = push_number[1:]

            if len(push_number) == 0:
                push_number = None

        # print(PushNumber)
        log.show_value(api.config, log.level.DEBUG, 'PostAuthor', post_author)
        log.show_value(api.config, log.level.DEBUG, 'PostTitle', post_title)
        log.show_value(api.config, log.level.DEBUG, 'PostAID', post_aid)
        log.show_value(api.config, log.level.DEBUG, 'PostWeb', post_web)
        log.show_value(api.config, log.level.DEBUG, 'PostMoney', post_money)
        log.show_value(api.config, log.level.DEBUG, 'ListDate', list_date)
        log.show_value(api.config, log.level.DEBUG, 'PushNumber', push_number)

        if lock_post:
            post = data_type.PostInfo(
                board=board,
                aid=post_aid,
                index=post_index,
                author=post_author,
                title=post_title,
                web_url=post_web,
                money=post_money,
                list_date=list_date,
                format_check=True,
                push_number=push_number,
                lock=True,
            )
            return post

    if query:
        post = data_type.PostInfo(
            board=board,
            aid=post_aid,
            index=post_index,
            author=post_author,
            title=post_title,
            web_url=post_web,
            money=post_money,
            list_date=list_date,
            format_check=True,
            push_number=push_number,
        )
        return post

    origin_post, has_control_code = _api_util.get_content(api)

    if origin_post is None:
        post = data_type.PostInfo(
            board=board,
            aid=post_aid,
            index=post_index,
            author=post_author,
            title=post_title,
            web_url=post_web,
            money=post_money,
            list_date=list_date,
            control_code=has_control_code,
            format_check=False,
            push_number=push_number,
            unconfirmed=api.Unconfirmed,
        )
        return post

    # print('=' * 20)
    # print(origin_post)
    # print('=' * 20)

    content_start = '───────────────────────────────────────'
    content_end = []
    content_end.append('--\n※ 發信站: 批踢踢實業坊')
    content_end.append('--\n※ 發信站: 批踢踢兔(ptt2.cc)')
    content_end.append('--\n※ 發信站: 新批踢踢(ptt2.twbbs.org.tw)')

    post_author_pattern_new = re.compile('作者  (.+) 看板')
    post_author_pattern_old = re.compile('作者  (.+)')
    board_pattern = re.compile('看板  (.+)')

    post_date = None
    post_content = []
    ip = None
    location = None
    push_list = []

    # 格式確認,亂改的我也沒辦法Q_Q
    origin_post_lines = origin_post.split('\n')

    author_line = origin_post_lines[0]

    if board.lower() == 'allpost':
        board_line = author_line[author_line.find(')') + 1:]
        pattern_result = board_pattern.search(board_line)
        if pattern_result is not None:
            board_temp = post_author = pattern_result.group(0)
            board_temp = board_temp[2:].strip()
            if len(board_temp) > 0:
                board = board_temp
                log.show_value(api.config, log.level.DEBUG, i18n.Board, board)
    pattern_result = post_author_pattern_new.search(author_line)
    if pattern_result is not None:
        post_author = pattern_result.group(0)
        post_author = post_author[:post_author.rfind(')') + 1]
    else:
        pattern_result = post_author_pattern_old.search(author_line)
        if pattern_result is None:
            log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                           i18n.Author)
            post = data_type.PostInfo(
                board=board,
                aid=post_aid,
                index=post_index,
                author=post_author,
                date=post_date,
                title=post_title,
                web_url=post_web,
                money=post_money,
                content=post_content,
                ip=ip,
                push_list=push_list,
                list_date=list_date,
                control_code=has_control_code,
                format_check=False,
                location=location,
                push_number=push_number,
                origin_post=origin_post,
                unconfirmed=api.Unconfirmed,
            )
            return post
        post_author = pattern_result.group(0)
        post_author = post_author[:post_author.rfind(')') + 1]
    post_author = post_author[4:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Author, post_author)

    post_title_pattern = re.compile('標題  (.+)')

    title_line = origin_post_lines[1]
    pattern_result = post_title_pattern.search(title_line)
    if pattern_result is None:
        log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                       i18n.Title)
        post = data_type.PostInfo(
            board=board,
            aid=post_aid,
            index=post_index,
            author=post_author,
            date=post_date,
            title=post_title,
            web_url=post_web,
            money=post_money,
            content=post_content,
            ip=ip,
            push_list=push_list,
            list_date=list_date,
            control_code=has_control_code,
            format_check=False,
            location=location,
            push_number=push_number,
            origin_post=origin_post,
            unconfirmed=api.Unconfirmed,
        )
        return post
    post_title = pattern_result.group(0)
    post_title = post_title[4:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Title, post_title)

    post_date_pattern = re.compile('時間  (.+)')
    date_line = origin_post_lines[2]
    pattern_result = post_date_pattern.search(date_line)
    if pattern_result is None:
        log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                       i18n.Date)
        post = data_type.PostInfo(
            board=board,
            aid=post_aid,
            index=post_index,
            author=post_author,
            date=post_date,
            title=post_title,
            web_url=post_web,
            money=post_money,
            content=post_content,
            ip=ip,
            push_list=push_list,
            list_date=list_date,
            control_code=has_control_code,
            format_check=False,
            location=location,
            push_number=push_number,
            origin_post=origin_post,
            unconfirmed=api.Unconfirmed,
        )
        return post
    post_date = pattern_result.group(0)
    post_date = post_date[4:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Date, post_date)

    content_fail = True
    if content_start not in origin_post:
        # print('Type 1')
        content_fail = True
    else:
        post_content = origin_post
        post_content = post_content[post_content.find(content_start) +
                                    len(content_start) + 1:]
        # print('Type 2')
        # print(f'PostContent [{PostContent}]')
        for EC in content_end:
            # + 3 = 把 --\n 拿掉
            # print(f'EC [{EC}]')
            if EC in post_content:
                content_fail = False

                post_content = post_content[:post_content.rfind(EC) + 3]
                origin_post_lines = origin_post[origin_post.find(EC):]
                # post_content = post_content.strip()
                origin_post_lines = origin_post_lines.split('\n')
                break

    if content_fail:
        log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                       i18n.Content)
        post = data_type.PostInfo(
            board=board,
            aid=post_aid,
            index=post_index,
            author=post_author,
            date=post_date,
            title=post_title,
            web_url=post_web,
            money=post_money,
            content=post_content,
            ip=ip,
            push_list=push_list,
            list_date=list_date,
            control_code=has_control_code,
            format_check=False,
            location=location,
            push_number=push_number,
            origin_post=origin_post,
            unconfirmed=api.Unconfirmed,
        )
        return post

    log.show_value(api.config, log.level.DEBUG, i18n.Content, post_content)

    info_lines = [
        line for line in origin_post_lines
        if line.startswith('※') or line.startswith('◆')
    ]

    pattern = re.compile('[\d]+\.[\d]+\.[\d]+\.[\d]+')
    pattern_p2 = re.compile('[\d]+-[\d]+-[\d]+-[\d]+')
    for line in reversed(info_lines):
        log.show_value(api.config, log.level.DEBUG, 'IP Line', line)

        # type 1
        # ※ 編輯: CodingMan (111.243.146.98 臺灣)
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.243.146.98 (臺灣)

        # type 2
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 116.241.32.178
        # ※ 編輯: kill77845 (114.136.55.237), 12/08/2018 16:47:59

        # type 3
        # ※ 發信站: 批踢踢實業坊(ptt.cc)
        # ◆ From: 211.20.78.69
        # ※ 編輯: JCC             來自: 211.20.78.69         (06/20 10:22)
        # ※ 編輯: JCC (118.163.28.150), 12/03/2015 14:25:35

        pattern_result = pattern.search(line)
        if pattern_result is not None:
            ip = pattern_result.group(0)
            location_temp = line[line.find(ip) + len(ip):].strip()
            location_temp = location_temp.replace('(', '')
            location_temp = location_temp[:location_temp.rfind(')')]
            location_temp = location_temp.strip()
            # print(f'=>[{LocationTemp}]')
            if ' ' not in location_temp and len(location_temp) > 0:
                location = location_temp
                log.show_value(api.config, log.level.DEBUG, 'Location',
                               location)
            break

        pattern_result = pattern_p2.search(line)
        if pattern_result is not None:
            ip = pattern_result.group(0)
            ip = ip.replace('-', '.')
            # print(f'IP -> [{IP}]')
            break
    if api.config.host == data_type.host_type.PTT1:
        if ip is None:
            log.show_value(api.config, log.level.DEBUG, i18n.SubstandardPost,
                           'IP')
            post = data_type.PostInfo(
                board=board,
                aid=post_aid,
                index=post_index,
                author=post_author,
                date=post_date,
                title=post_title,
                web_url=post_web,
                money=post_money,
                content=post_content,
                ip=ip,
                push_list=push_list,
                list_date=list_date,
                control_code=has_control_code,
                format_check=False,
                location=location,
                push_number=push_number,
                origin_post=origin_post,
                unconfirmed=api.Unconfirmed,
            )
            return post
    log.show_value(api.config, log.level.DEBUG, 'IP', ip)

    push_author_pattern = re.compile('[推|噓|→] [\w| ]+:')
    push_date_pattern = re.compile('[\d]+/[\d]+ [\d]+:[\d]+')
    push_ip_pattern = re.compile('[\d]+\.[\d]+\.[\d]+\.[\d]+')

    push_list = []

    for line in origin_post_lines:
        if line.startswith('推'):
            push_type = data_type.push_type.PUSH
        elif line.startswith('噓 '):
            push_type = data_type.push_type.BOO
        elif line.startswith('→ '):
            push_type = data_type.push_type.ARROW
        else:
            continue

        result = push_author_pattern.search(line)
        if result is None:
            # 不符合推文格式
            continue
        push_author = result.group(0)[2:-1].strip()
        log.show_value(api.config, log.level.DEBUG, [
            i18n.Push,
            i18n.ID,
        ], push_author)

        result = push_date_pattern.search(line)
        if result is None:
            continue
        push_date = result.group(0)
        log.show_value(api.config, log.level.DEBUG, [
            i18n.Push,
            i18n.Date,
        ], push_date)

        push_ip = None
        result = push_ip_pattern.search(line)
        if result is not None:
            push_ip = result.group(0)
            log.show_value(api.config, log.level.DEBUG, [
                i18n.Push,
                'IP',
            ], push_ip)

        push_content = line[line.find(push_author) + len(push_author):]
        # PushContent = PushContent.replace(PushDate, '')

        if api.config.host == data_type.host_type.PTT1:
            push_content = push_content[:push_content.rfind(push_date)]
        else:
            # → CodingMan:What is Ptt?                                       推 10/04 13:25
            push_content = push_content[:push_content.rfind(push_date) - 2]
        if push_ip is not None:
            push_content = push_content.replace(push_ip, '')
        push_content = push_content[push_content.find(':') + 1:].strip()
        log.show_value(api.config, log.level.DEBUG, [
            i18n.Push,
            i18n.Content,
        ], push_content)

        current_push = data_type.PushInfo(push_type, push_author, push_content,
                                          push_ip, push_date)
        push_list.append(current_push)

    post = data_type.PostInfo(
        board=board,
        aid=post_aid,
        index=post_index,
        author=post_author,
        date=post_date,
        title=post_title,
        web_url=post_web,
        money=post_money,
        content=post_content,
        ip=ip,
        push_list=push_list,
        list_date=list_date,
        control_code=has_control_code,
        format_check=True,
        location=location,
        push_number=push_number,
        origin_post=origin_post,
        unconfirmed=api.Unconfirmed,
    )
    return post
Exemplo n.º 4
0
def login(api, ptt_id, password, kick_other_login):
    if api._login_status:
        api.logout()

    api.config.kick_other_login = kick_other_login

    def kick_other_loginDisplayMsg():
        if api.config.kick_other_login:
            return i18n.kick_other_login
        return i18n.Notkick_other_login

    def kick_other_loginResponse(Screen):
        if api.config.kick_other_login:
            return 'y' + command.Enter
        return 'n' + command.Enter

    api._mailbox_full = False

    def mailbox_full():
        log.log(api.config, log.level.INFO, i18n.MailBoxFull)
        api._mailbox_full = True

    if len(password) > 8:
        password = password[:8]

    ptt_id = ptt_id.strip()
    password = password.strip()

    api._ID = ptt_id
    api._Password = password

    api.config.kick_other_login = kick_other_login

    api.connect_core.connect()

    log.show_value(api.config, log.level.INFO, [i18n.login, i18n.ID], ptt_id)

    target_list = [
        connect_core.TargetUnit(
            # i18n.HasNewMailGotoMainMenu,
            i18n.MailBox,
            screens.Target.InMailBox,
            # 加個進去 A 選單再出來的動作,讓畫面更新最底下一行
            response=command.GoMainMenu + 'A' + command.Right + command.Left,
            break_detect=True),
        connect_core.TargetUnit(i18n.loginSuccess,
                                screens.Target.MainMenu,
                                break_detect=True),
        connect_core.TargetUnit(
            i18n.GoMainMenu,
            '【看板列表】',
            response=command.GoMainMenu,
        ),
        connect_core.TargetUnit(i18n.ErrorIDPW,
                                '密碼不對',
                                break_detect=True,
                                exceptions_=exceptions.WrongIDorPassword()),
        connect_core.TargetUnit(i18n.LoginTooOften,
                                '登入太頻繁',
                                break_detect=True,
                                exceptions_=exceptions.LoginTooOften()),
        connect_core.TargetUnit(
            i18n.SystemBusyTryLater,
            '系統過載',
            break_detect=True,
        ),
        connect_core.TargetUnit(
            i18n.DelWrongPWRecord,
            '您要刪除以上錯誤嘗試的記錄嗎',
            response='y' + command.Enter,
        ),
        connect_core.TargetUnit(
            i18n.PostNotFinish,
            '請選擇暫存檔 (0-9)[0]',
            response=command.Enter,
        ),
        connect_core.TargetUnit(
            i18n.PostNotFinish,
            '有一篇文章尚未完成',
            response='Q' + command.Enter,
        ),
        connect_core.TargetUnit(
            i18n.SigningUnPleaseWait,
            '登入中,請稍候',
        ),
        connect_core.TargetUnit(
            kick_other_loginDisplayMsg,
            '您想刪除其他重複登入的連線嗎',
            response=kick_other_loginResponse,
        ),
        connect_core.TargetUnit(i18n.AnyKeyContinue,
                                '任意鍵',
                                response=command.Enter),
        connect_core.TargetUnit(
            i18n.SigningUpdate,
            '正在更新與同步線上使用者及好友名單',
        ),
        connect_core.TargetUnit(
            i18n.GoMainMenu,
            '【分類看板】',
            response=command.GoMainMenu,
        ),
    ]

    cmd_list = []
    cmd_list.append(ptt_id)
    cmd_list.append(command.Enter)
    cmd_list.append(password)
    cmd_list.append(command.Enter)

    cmd = ''.join(cmd_list)

    index = api.connect_core.send(
        cmd,
        target_list,
        screen_timeout=api.config.screen_long_timeout,
        refresh=False,
        secret=True)
    ori_screen = api.connect_core.get_screen_queue()[-1]
    if index == 0:

        current_capacity, max_capacity = _api_util.get_mailbox_capacity(api)

        log.log(api.config, log.level.INFO, i18n.HasNewMailGotoMainMenu)

        if current_capacity > max_capacity:
            api._mailbox_full = True
            log.log(api.config, log.level.INFO, i18n.MailBoxFull)

        if api._mailbox_full:
            log.log(api.config, log.level.INFO,
                    i18n.UseMailboxAPIWillLogoutAfterExecution)

        target_list = [
            connect_core.TargetUnit(i18n.loginSuccess,
                                    screens.Target.MainMenu,
                                    break_detect=True)
        ]

        cmd = command.GoMainMenu + 'A' + command.Right + command.Left

        index = api.connect_core.send(
            cmd,
            target_list,
            screen_timeout=api.config.screen_long_timeout,
            secret=True)
        ori_screen = api.connect_core.get_screen_queue()[-1]

    if target_list[index].get_display_msg() != i18n.loginSuccess:
        print(ori_screen)
        raise exceptions.LoginError()

    if '> (' in ori_screen:
        api.cursor = data_type.Cursor.NEW
        log.log(api.config, log.level.DEBUG, i18n.NewCursor)
    else:
        api.cursor = data_type.Cursor.OLD
        log.log(api.config, log.level.DEBUG, i18n.OldCursor)

    if api.cursor not in screens.Target.InBoardWithCursor:
        screens.Target.InBoardWithCursor.append('\n' + api.cursor)

    if len(screens.Target.MainMenu) == len(screens.Target.CursorToGoodbye):
        if api.cursor == '>':
            screens.Target.CursorToGoodbye.append('> (G)oodbye')
        else:
            screens.Target.CursorToGoodbye.append('●(G)oodbye')

    api._unregistered_user = True
    if '(T)alk' in ori_screen:
        api._unregistered_user = False
    if '(P)lay' in ori_screen:
        api._unregistered_user = False
    if '(N)amelist' in ori_screen:
        api._unregistered_user = False

    if api._unregistered_user:
        # print(ori_screen)
        log.log(api.config, log.level.INFO, i18n.UnregisteredUserCantUseAllAPI)

    api._login_status = True
Exemplo n.º 5
0
def throw_waterball(api: object, target_id: str, content: str) -> None:
    max_length = 50

    water_ball_list = list()
    temp_start_index = 0
    temp_end_index = temp_start_index + 1

    while temp_end_index <= len(content):
        temp = ''
        last_temp = None
        while len(temp.encode('big5-uao', 'ignore')) < max_length:
            temp = content[temp_start_index:temp_end_index]

            if not len(temp.encode('big5-uao', 'ignore')) < max_length:
                break
            elif content.endswith(temp) and temp_start_index != 0:
                break
            elif temp.endswith('\n'):
                break
            elif last_temp == temp:
                break

            temp_end_index += 1
            last_temp = temp

        water_ball_list.append(temp.strip())

        temp_start_index = temp_end_index
        temp_end_index = temp_start_index + 1
    water_ball_list = filter(None, water_ball_list)

    for waterball in water_ball_list:

        if api._LastThrowWaterBallTime != 0:
            current_time = time.time()
            while (current_time - api._LastThrowWaterBallTime) < 3.2:
                time.sleep(0.1)
                current_time = time.time()

        log.show_value(
            api.config,
            log.level.INFO,
            i18n.WaterBall,
            waterball
        )

        target_list = [
            connect_core.TargetUnit(
                i18n.SetCallStatus,
                '您的呼叫器目前設定為關閉',
                response='y' + command.Enter,
            ),
            # 對方已落跑了
            connect_core.TargetUnit(
                i18n.SetCallStatus,
                '◆ 糟糕! 對方已落跑了',
                exceptions_=exceptions.UserOffline(target_id)
            ),
            connect_core.TargetUnit(
                [
                    i18n.Throw,
                    target_id,
                    i18n.WaterBall
                ],
                '丟 ' + target_id + ' 水球:',
                response=waterball + command.Enter * 2 +
                command.GoMainMenu,
            ),
            connect_core.TargetUnit(
                [
                    i18n.Throw,
                    i18n.WaterBall,
                    i18n.Success
                ],
                screens.Target.MainMenu,
                break_detect=True
            )
        ]

        cmd_list = list()
        cmd_list.append(command.GoMainMenu)
        cmd_list.append('T')
        cmd_list.append(command.Enter)
        cmd_list.append('U')
        cmd_list.append(command.Enter)
        if '【好友列表】' in api.connect_core.get_screen_queue()[-1]:
            cmd_list.append('f')
        cmd_list.append('s')
        cmd_list.append(target_id)
        cmd_list.append(command.Enter)
        cmd_list.append('w')

        cmd = ''.join(cmd_list)

        api.connect_core.send(
            cmd,
            target_list,
            screen_timeout=api.config.screen_long_timeout
        )
        api._LastThrowWaterBallTime = time.time()
Exemplo n.º 6
0
def mail(api, ptt_id: str, title: str, content: str, sign_file) -> None:
    # log.showValue(
    #     api.config,
    #     log.level.INFO,
    #     [
    #         i18n.PTT,
    #         i18n.Msg
    #     ],
    #     i18n.MarkPost
    # )

    CmdList = []
    CmdList.append(command.GoMainMenu)
    CmdList.append('M')
    CmdList.append(command.Enter)
    CmdList.append('S')
    CmdList.append(command.Enter)
    CmdList.append(ptt_id)
    CmdList.append(command.Enter)

    Cmd = ''.join(CmdList)

    TargetList = [
        connect_core.TargetUnit([i18n.Start, i18n.SendMail],
                                '主題:',
                                break_detect=True),
        connect_core.TargetUnit(i18n.NoSuchUser,
                                '【電子郵件】',
                                exceptions_=exceptions.NoSuchUser(ptt_id)),
    ]

    api.connect_core.send(Cmd,
                          TargetList,
                          screen_timeout=api.config.screen_long_timeout)

    CmdList = []
    CmdList.append(title)
    CmdList.append(command.Enter)
    CmdList.append(content)
    CmdList.append(command.Ctrl_X)

    Cmd = ''.join(CmdList)

    if sign_file == 0:
        SingFileSelection = i18n.NoSignatureFile
    else:
        SingFileSelection = i18n.Select + ' ' + \
                            str(sign_file) + 'th ' + i18n.SignatureFile

    TargetList = [
        connect_core.TargetUnit(i18n.AnyKeyContinue, '任意鍵', break_detect=True),
        connect_core.TargetUnit(
            i18n.SaveFile,
            '確定要儲存檔案嗎',
            response='s' + command.Enter,
            # Refresh=False,
        ),
        connect_core.TargetUnit(i18n.SelfSaveDraft,
                                '是否自存底稿',
                                response='y' + command.Enter),
        connect_core.TargetUnit(SingFileSelection,
                                '選擇簽名檔',
                                response=str(sign_file) + command.Enter),
        connect_core.TargetUnit(SingFileSelection,
                                'x=隨機',
                                response=str(sign_file) + command.Enter),
    ]

    api.connect_core.send(Cmd,
                          TargetList,
                          screen_timeout=api.config.screen_post_timeout)

    log.show_value(api.config, log.level.INFO, i18n.SendMail, i18n.Success)
Exemplo n.º 7
0
def get_board_list(api) -> list:

    # log.showValue(
    #     api.config,
    #     log.level.INFO,
    #     [
    #         i18n.PTT,
    #         i18n.Msg
    #     ],
    #     i18n.MarkPost
    # )

    cmd_list = list()
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('F')
    cmd_list.append(command.Enter)
    cmd_list.append('y')
    cmd_list.append('$')
    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            i18n.BoardList,
            screens.Target.InBoardList,
            break_detect=True
        )
    ]

    api.connect_core.send(
        cmd,
        target_list,
        screen_timeout=api.config.screen_long_timeout
    )
    ori_screen = api.connect_core.get_screen_queue()[-1]

    max_no = 0
    for line in ori_screen.split('\n'):
        if '◎' not in line and '●' not in line:
            continue

        if line.startswith(api.cursor):
            line = line[len(api.cursor):]

        # print(f'->{line}<')
        if '◎' in line:
            front_part = line[:line.find('◎')]
        else:
            front_part = line[:line.find('●')]
        front_part_list = [x for x in front_part.split(' ')]
        front_part_list = list(filter(None, front_part_list))
        # print(f'FrontPartList =>{FrontPartList}<=')
        max_no = int(front_part_list[0].rstrip(')'))

    log.show_value(
        api.config,
        log.level.DEBUG,
        'MaxNo',
        max_no
    )

    if api.config.log_level == log.level.INFO:
        pb = progressbar.ProgressBar(
            max_value=max_no,
            redirect_stdout=True
        )

    cmd_list = list()
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('F')
    cmd_list.append(command.Enter)
    cmd_list.append('y')
    cmd_list.append('0')
    cmd = ''.join(cmd_list)

    board_list = list()
    while True:

        api.connect_core.send(
            cmd,
            target_list,
            screen_timeout=api.config.screen_long_timeout
        )

        ori_screen = api.connect_core.get_screen_queue()[-1]
        # print(OriScreen)
        for line in ori_screen.split('\n'):
            if '◎' not in line and '●' not in line:
                continue

            if line.startswith(api.cursor):
                line = line[len(api.cursor):]

            # print(f'->{line}<')

            if '◎' in line:
                front_part = line[:line.find('◎')]
            else:
                front_part = line[:line.find('●')]
            front_part_list = [x for x in front_part.split(' ')]
            front_part_list = list(filter(None, front_part_list))
            # print(f'FrontPartList =>{FrontPartList}<=')
            no = int(front_part_list[0].rstrip(')'))
            # print(f'No  =>{no}<=')
            # print(f'LastNo =>{LastNo}<=')

            log.show_value(
                api.config,
                log.level.DEBUG,
                'Board NO',
                no
            )

            board_name = front_part_list[1]
            if board_name.startswith('ˇ'):
                board_name = board_name[1:]

            log.show_value(
                api.config,
                log.level.DEBUG,
                'Board Name',
                board_name
            )

            board_list.append(board_name)

            if api.config.log_level == log.level.INFO:
                pb.update(no)

        if no >= max_no:
            break
        cmd = command.Ctrl_F

    if api.config.log_level == log.level.INFO:
        pb.finish()

    return board_list
Exemplo n.º 8
0
def post(
        api: object,
        board: str,
        title: str,
        content: str,
        post_type: int,
        sign_file) -> None:
    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('qs')
    cmd_list.append(board)
    cmd_list.append(command.Enter)
    cmd_list.append(command.Ctrl_C * 2)
    cmd_list.append(command.Space)
    cmd_list.append(command.Ctrl_P)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            i18n.HasPostPermission,
            '發表文章於【',
            break_detect=True,
        ),
        connect_core.TargetUnit(
            i18n.NoPermission,
            '使用者不可發言',
            break_detect=True,
        ),
        connect_core.TargetUnit(
            i18n.NoPermission,
            '無法發文: 未達看板要求權限',
            break_detect=True
        ),
    ]
    index = api.connect_core.send(cmd, target_list)
    if index < 0:
        screens.show(api.config, api.connect_core.get_screen_queue())
        raise exceptions.UnknownError(i18n.UnknownError)
    if index == 1 or index == 2:
        raise exceptions.NoPermission(i18n.NoPermission)

    screens.show(api.config, api.connect_core.get_screen_queue())

    cmd_list = []
    cmd_list.append(str(post_type))
    cmd_list.append(command.Enter)
    cmd_list.append(str(title))
    cmd_list.append(command.Enter)
    cmd_list.append(command.Ctrl_Y * 40)
    cmd_list.append(str(content))
    cmd_list.append(command.Ctrl_X)
    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            i18n.AnyKeyContinue,
            '任意鍵繼續',
            break_detect=True,
        ),
        connect_core.TargetUnit(
            i18n.SaveFile,
            '確定要儲存檔案嗎',
            response='s' + command.Enter,
        ),
        connect_core.TargetUnit(
            i18n.SelectSignature,
            'x=隨機',
            response=str(sign_file) + command.Enter,
        ),
    ]
    index = api.connect_core.send(
        cmd,
        target_list,
        screen_timeout=api.config.screen_post_timeout
    )
Exemplo n.º 9
0
def markPost(api, mark_type: int, board: str, post_aid: str, post_index: int,
             search_type: int, search_condition: str) -> None:

    log.show_value(api.config, log.level.INFO, [i18n.PTT, i18n.Msg],
                   i18n.MarkPost)

    check_value.check(api.config,
                      int,
                      'mark_type',
                      mark_type,
                      value_class=data_type.mark_type)
    check_value.check(api.config, str, 'Board', board)
    if post_aid is not None:
        check_value.check(api.config, str, 'PostAID', post_aid)
    check_value.check(api.config, int, 'PostIndex', post_index)
    check_value.check(api.config,
                      int,
                      'SearchType',
                      search_type,
                      value_class=data_type.post_search_type)
    if search_condition is not None:
        check_value.check(api.config, str, 'SearchCondition', search_condition)

    if len(board) == 0:
        raise ValueError(log.merge([i18n.Board, i18n.ErrorParameter, board]))

    if post_index != 0 and isinstance(post_aid, str):
        raise ValueError(
            log.merge(
                ['PostIndex', 'PostAID', i18n.ErrorParameter, i18n.BothInput]))

    if post_index == 0 and post_aid is None:
        raise ValueError(
            log.merge(['PostIndex', 'PostAID', i18n.ErrorParameter]))

    if search_condition is not None and search_type == 0:
        raise ValueError(log.merge([
            'SearchType',
            i18n.ErrorParameter,
        ]))

    if search_type == data_type.post_search_type.PUSH:
        try:
            S = int(search_condition)
        except ValueError:
            raise ValueError(
                log.merge([
                    'SearchCondition',
                    i18n.ErrorParameter,
                ]))

        if not (-100 <= S <= 110):
            raise ValueError(
                log.merge([
                    'SearchCondition',
                    i18n.ErrorParameter,
                ]))

    if post_aid is not None and search_condition is not None:
        raise ValueError(
            log.merge([
                'PostAID',
                'SearchCondition',
                i18n.ErrorParameter,
                i18n.BothInput,
            ]))

    if post_index != 0:
        NewestIndex = api._get_newest_index(data_type.index_type.BBS,
                                            board=board,
                                            search_type=search_type,
                                            search_condition=search_condition)
        check_value.check_index(api.config,
                                'PostIndex',
                                post_index,
                                max_value=NewestIndex)

    if mark_type == data_type.mark_type.UNCONFIRMED:
        # 批踢踢兔沒有待證文章功能 QQ
        if api.config.host == data_type.host_type.PTT2:
            raise exceptions.HostNotSupport(lib_util.get_current_func_name())

    api._check_board(board, check_moderator=True)

    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('qs')
    cmd_list.append(board)
    cmd_list.append(command.Enter)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            i18n.AnyKeyContinue,
            '任意鍵',
            response=' ',
        ),
        connect_core.TargetUnit([
            '動畫播放中',
        ],
                                '互動式動畫播放中',
                                response=command.Ctrl_C,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            '進板成功',
        ],
                                screens.Target.InBoard,
                                break_detect=True,
                                log_level=log.level.DEBUG),
    ]

    index = api.connect_core.send(cmd, target_list)

    cmd_list = []
    if post_aid is not None:
        cmd_list.append('#' + post_aid)

    elif post_index != 0:
        if search_condition is not None:
            if search_type == data_type.post_search_type.KEYWORD:
                cmd_list.append('/')
            elif search_type == data_type.post_search_type.AUTHOR:
                cmd_list.append('a')
            elif search_type == data_type.post_search_type.PUSH:
                cmd_list.append('Z')
            elif search_type == data_type.post_search_type.MARK:
                cmd_list.append('G')
            elif search_type == data_type.post_search_type.MONEY:
                cmd_list.append('A')

            cmd_list.append(search_condition)
            cmd_list.append(command.Enter)

        cmd_list.append(str(post_index))

    cmd_list.append(command.Enter)

    if mark_type == data_type.mark_type.S:
        cmd_list.append('L')
    elif mark_type == data_type.mark_type.D:
        cmd_list.append('t')
    elif mark_type == data_type.mark_type.DeleteD:
        cmd_list.append(command.Ctrl_D)
    elif mark_type == data_type.mark_type.M:
        cmd_list.append('m')
    elif mark_type == data_type.mark_type.UNCONFIRMED:
        cmd_list.append(command.Ctrl_E + 'S')

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit([i18n.DelAllMarkPost],
                                '刪除所有標記',
                                response='y' + command.Enter,
                                log_level=log.level.INFO),
        connect_core.TargetUnit([
            i18n.Mark,
            i18n.Success,
        ],
                                screens.Target.InBoard,
                                break_detect=True,
                                log_level=log.level.INFO),
    ]

    index = api.connect_core.send(cmd, target_list)
Exemplo n.º 10
0
def reply_post(
        api,
        reply_type: int,
        board: str,
        content: str,
        sign_file,
        post_aid: str,
        post_index: int) ->None:

    # log.showValue(
    #     api.config,
    #     log.level.INFO,
    #     [
    #         i18n.PTT,
    #         i18n.Msg
    #     ],
    #     i18n.MarkPost
    # )

    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('qs')
    cmd_list.append(board)
    cmd_list.append(command.Enter)
    cmd_list.append(command.Ctrl_C * 2)
    cmd_list.append(command.Space)

    if post_aid is not None:
        cmd_list.append('#' + post_aid)
    elif post_index != 0:
        cmd_list.append(str(post_index))
    cmd_list.append(command.Enter * 2)
    cmd_list.append('r')

    if reply_type == data_type.reply_type.BOARD:
        reply_target_unit = connect_core.TargetUnit(
            i18n.ReplyBoard,
            '▲ 回應至',
            log_level=log.level.INFO,
            response='F' + command.Enter
        )
    elif reply_type == data_type.reply_type.MAIL:
        reply_target_unit = connect_core.TargetUnit(
            i18n.ReplyMail,
            '▲ 回應至',
            log_level=log.level.INFO,
            response='M' + command.Enter
        )
    elif reply_type == data_type.reply_type.BOARD_MAIL:
        reply_target_unit = connect_core.TargetUnit(
            i18n.ReplyBoard_Mail,
            '▲ 回應至',
            log_level=log.level.INFO,
            response='B' + command.Enter
        )

    cmd = ''.join(cmd_list)
    target_list = [
        connect_core.TargetUnit(
            i18n.AnyKeyContinue,
            '任意鍵繼續',
            break_detect=True,
        ),
        connect_core.TargetUnit(
            i18n.NoResponse,
            '◆ 很抱歉, 此文章已結案並標記, 不得回應',
            log_level=log.level.INFO,
            exceptions_=exceptions.NoResponse()
        ),
        connect_core.TargetUnit(
            i18n.ForcedWrite,
            '(E)繼續編輯 (W)強制寫入',
            log_level=log.level.INFO,
            response='W' + command.Enter
        ),
        connect_core.TargetUnit(
            i18n.SelectSignature,
            '請選擇簽名檔',
            response=str(sign_file) + command.Enter,
        ),
        connect_core.TargetUnit(
            i18n.SaveFile,
            '確定要儲存檔案嗎',
            response='s' + command.Enter,
        ),
        connect_core.TargetUnit(
            i18n.EditPost,
            '編輯文章',
            log_level=log.level.INFO,
            response=str(content) + command.Enter + command.Ctrl_X
        ),
        connect_core.TargetUnit(
            i18n.QuoteOriginal,
            '請問要引用原文嗎',
            log_level=log.level.DEBUG,
            response='Y' + command.Enter
        ),
        connect_core.TargetUnit(
            i18n.UseTheOriginalTitle,
            '採用原標題[Y/n]?',
            log_level=log.level.DEBUG,
            response='Y' + command.Enter
        ),
        reply_target_unit,
        connect_core.TargetUnit(
            i18n.SelfSaveDraft,
            '已順利寄出,是否自存底稿',
            log_level=log.level.DEBUG,
            response='Y' + command.Enter
        ),
    ]

    api.connect_core.send(
        cmd,
        target_list,
        screen_timeout=api.config.screen_long_timeout
    )

    log.log(
        api.config,
        log.level.INFO,
        i18n.RespondSuccess
    )
Exemplo n.º 11
0
def del_post(
        api,
        board_info,
        board,
        post_aid: str = None,
        post_index: int = 0) -> None:

    check_author = True
    for moderator in board_info.moderators:
        if api._ID.lower() == moderator.lower():
            check_author = False
            break

    post_info = api.get_post(board, post_aid=post_aid, post_index=post_index, query=True)
    if post_info.delete_status != data_type.post_delete_status.NOT_DELETED:
        if post_aid is not None:
            raise exceptions.DeletedPost(board, post_aid)
        else:
            raise exceptions.DeletedPost(board, post_index)

    if check_author:
        if api._ID.lower() != post_info.author.lower():
            raise exceptions.NoPermission(i18n.NoPermission)

    api._goto_board(board)

    cmd_list = list()

    if post_aid is not None:
        cmd_list.append('#' + post_aid)
    elif post_index != 0:
        cmd_list.append(str(post_index))
    cmd_list.append(command.Enter)
    cmd_list.append('d')

    cmd = ''.join(cmd_list)

    api.confirm = False

    def confirm_delete_handler(screen):
        api.confirm = True

    target_list = [
        connect_core.TargetUnit(
            i18n.AnyKeyContinue,
            '請按任意鍵繼續',
            response=' '),
        connect_core.TargetUnit(
            i18n.ConfirmDelete,
            '請確定刪除(Y/N)?[N]',
            response='y' + command.Enter,
            max_match=1,
            handler=confirm_delete_handler),
        connect_core.TargetUnit(
            i18n.DeleteSuccess,
            screens.Target.InBoard,
            break_detect=True),
    ]

    index = api.connect_core.send(
        cmd,
        target_list)

    # last_screen = api.connect_core.get_screen_queue()[-1]
    # print(api.confirm)
    # print(last_screen)
    # print(index)

    if index == 1:
        if not api.confirm:
            raise exceptions.NoPermission(i18n.NoPermission)

    if index == -1:
        if post_aid is not None:
            raise exceptions.NoSuchPost(board, post_aid)
        else:
            raise exceptions.NoSuchPost(board, post_index)
Exemplo n.º 12
0
def mail(api,
         ptt_id: str,
         title: str,
         content: str,
         sign_file,
         backup: bool = True) -> None:
    cmd_list = list()
    # 回到主選單
    cmd_list.append(command.GoMainMenu)
    # 私人信件區
    cmd_list.append('M')
    cmd_list.append(command.Enter)
    # 站內寄信
    cmd_list.append('S')
    cmd_list.append(command.Enter)
    # 輸入 id
    cmd_list.append(ptt_id)
    cmd_list.append(command.Enter)

    cmd = ''.join(cmd_list)

    # 定義如何根據情況回覆訊息
    target_list = [
        connect_core.TargetUnit([i18n.Start, i18n.SendMail],
                                '主題:',
                                break_detect=True),
        connect_core.TargetUnit(i18n.NoSuchUser,
                                '【電子郵件】',
                                exceptions_=exceptions.NoSuchUser(ptt_id))
    ]

    api.connect_core.send(cmd,
                          target_list,
                          screen_timeout=api.config.screen_long_timeout)

    cmd_list = list()
    # 輸入標題
    cmd_list.append(title)
    cmd_list.append(command.Enter)
    # 輸入內容
    cmd_list.append(content)
    # 儲存檔案
    cmd_list.append(command.Ctrl_X)

    cmd = ''.join(cmd_list)

    # 根據簽名檔調整顯示訊息
    if sign_file == 0:
        sing_file_selection = i18n.NoSignatureFile
    else:
        sing_file_selection = i18n.Select + ' ' + \
                              str(sign_file) + 'th ' + i18n.SignatureFile
    # 定義如何根據情況回覆訊息
    target_list = [
        connect_core.TargetUnit(i18n.AnyKeyContinue, '任意鍵', break_detect=True),
        connect_core.TargetUnit(
            i18n.SaveFile,
            '確定要儲存檔案嗎',
            response='s' + command.Enter,
        ),
        connect_core.TargetUnit(
            i18n.SelfSaveDraft if backup else i18n.NotSelfSaveDraft,
            '是否自存底稿',
            response=('y' if backup else 'n') + command.Enter),
        connect_core.TargetUnit(sing_file_selection,
                                '選擇簽名檔',
                                response=str(sign_file) + command.Enter),
        connect_core.TargetUnit(sing_file_selection,
                                'x=隨機',
                                response=str(sign_file) + command.Enter),
    ]

    # 送出訊息
    api.connect_core.send(cmd,
                          target_list,
                          screen_timeout=api.config.screen_post_timeout)

    log.show_value(api.config, log.level.INFO, i18n.SendMail, i18n.Success)
Exemplo n.º 13
0
def get_mail(api,
             index,
             search_type: int = 0,
             search_condition: str = None,
             search_list: list = None) -> data_type.MailInfo:
    cmd_list = list()
    # 回到主選單
    cmd_list.append(command.GoMainMenu)
    # 進入信箱
    cmd_list.append(command.Ctrl_Z)
    cmd_list.append('m')

    # 處理條件整理出指令
    _cmd_list, normal_newest_index = _api_util.get_search_condition_cmd(
        api, data_type.index_type.MAIL, search_type, search_condition,
        search_list, None)
    cmd_list.extend(_cmd_list)

    # 前進至目標信件位置
    cmd_list.append(str(index))
    cmd_list.append(command.Enter)
    cmd = ''.join(cmd_list)

    # 有時候會沒有最底下一列,只好偵測游標是否出現
    if api.cursor == data_type.Cursor.NEW:
        space_length = 6 - len(api.cursor) - len(str(index))
    else:
        space_length = 5 - len(api.cursor) - len(str(index))
    fast_target = f"{api.cursor}{' ' * space_length}{index}"

    # 定義如何根據情況回覆訊息
    target_list = [
        connect_core.TargetUnit(i18n.MailBox,
                                screens.Target.InMailBox,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit(i18n.MailBox,
                                fast_target,
                                break_detect=True,
                                log_level=log.level.DEBUG)
    ]

    # 送出訊息
    api.connect_core.send(cmd, target_list)

    # 取得信件全文
    origin_mail, _ = _api_util.get_content(api, post_mode=False)

    # 使用表示式分析信件作者
    pattern_result = mail_author_pattern.search(origin_mail)
    if pattern_result is None:
        mail_author = None
    else:
        mail_author = pattern_result.group(0)[2:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Author, mail_author)

    # 使用表示式分析信件標題
    pattern_result = mail_title_pattern.search(origin_mail)
    if pattern_result is None:
        mail_title = None
    else:
        mail_title = pattern_result.group(0)[2:].strip()

    log.show_value(api.config, log.level.DEBUG, i18n.Title, mail_title)

    # 使用表示式分析信件日期
    pattern_result = mail_date_pattern.search(origin_mail)
    if pattern_result is None:
        mail_date = None
    else:
        mail_date = pattern_result.group(0)[2:].strip()
    log.show_value(api.config, log.level.DEBUG, i18n.Date, mail_date)

    # 從全文拿掉信件開頭作為信件內文
    mail_content = origin_mail[origin_mail.find(content_start) +
                               len(content_start) + 1:]

    # 紅包偵測
    red_envelope = False
    if content_end not in origin_mail and 'Ptt幣的大紅包喔' in origin_mail:
        mail_content = mail_content.strip()
        red_envelope = True
    else:

        mail_content = mail_content[:mail_content.rfind(content_end) + 3]

    log.show_value(api.config, log.level.DEBUG, i18n.Content, mail_content)

    if red_envelope:
        mail_ip = None
        mail_location = None
    else:
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.242.182.114
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.104.127.126 (臺灣)

        # 非紅包開始解析 ip 與 地區

        ip_line_list = origin_mail.split('\n')
        ip_line = [x for x in ip_line_list if x.startswith(content_end[3:])]

        if len(ip_line) == 0:
            # 沒 ip 就沒地區
            mail_ip = None
            mail_location = None
        else:
            ip_line = ip_line[0]

            result = ip_pattern.search(ip_line)
            if result is None:
                ip_line = [
                    x for x in ip_line_list if x.startswith(content_ip_old)
                ]

                if len(ip_line) == 0:
                    mail_ip = None
                else:
                    ip_line = ip_line[0]
                    result = ip_pattern.search(ip_line)
                    mail_ip = result.group(0)
            else:
                mail_ip = result.group(0)

            log.show_value(api.config, log.level.DEBUG, [
                i18n.MailBox,
                'IP',
            ], mail_ip)

            location = ip_line[ip_line.find(mail_ip) + len(mail_ip):].strip()
            if len(location) == 0:
                mail_location = None
            else:
                # print(location)
                mail_location = location[1:-1]

                log.show_value(api.config, log.level.DEBUG, [
                    i18n.MailBox,
                    'location',
                ], mail_location)

    mail_result = data_type.MailInfo(origin_mail=origin_mail,
                                     author=mail_author,
                                     title=mail_title,
                                     date=mail_date,
                                     content=mail_content,
                                     ip=mail_ip,
                                     location=mail_location,
                                     is_red_envelope=red_envelope)

    return mail_result
Exemplo n.º 14
0
def bucket(api: object, board: str, bucket_days: int, reason: str,
           ptt_id: str) -> None:
    api._goto_board(board)

    cmd_list = list()
    cmd_list.append('i')
    cmd_list.append(command.Ctrl_P)
    cmd_list.append('w')
    cmd_list.append(command.Enter)
    cmd_list.append('a')
    cmd_list.append(command.Enter)
    cmd_list.append(ptt_id)
    cmd_list.append(command.Enter)
    cmd = ''.join(cmd_list)

    cmd_list = list()
    cmd_list.append(str(bucket_days))
    cmd_list.append(command.Enter)
    cmd_list.append(reason)
    cmd_list.append(command.Enter)
    cmd_list.append('y')
    cmd_list.append(command.Enter)
    cmd_part2 = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            [
                i18n.bucket,
                i18n.Fail,
            ],
            '◆ 使用者之前已被禁言',
            exceptions_=exceptions.UserHasPreviouslyBeenBanned()),
        connect_core.TargetUnit(
            i18n.InputBucketDays_Reason,
            '請以數字跟單位(預設為天)輸入期限',
            response=cmd_part2,
        ),
        connect_core.TargetUnit(
            [
                i18n.bucket,
                i18n.Success,
            ],
            '其它鍵結束',
            response=command.Enter,
        ),
        connect_core.TargetUnit(
            [
                i18n.bucket,
                i18n.Success,
            ],
            '權限設定系統',
            response=command.Enter,
        ),
        connect_core.TargetUnit(
            [
                i18n.bucket,
                i18n.Success,
            ],
            '任意鍵',
            response=command.Space,
        ),
        connect_core.TargetUnit([
            i18n.bucket,
            i18n.Success,
        ],
                                screens.Target.InBoard,
                                break_detect=True),
    ]

    api.connect_core.send(cmd, target_list)
Exemplo n.º 15
0
def get_content(api, post_mode: bool = True):
    api.Unconfirmed = False

    def is_unconfirmed_handler(screen):
        api.Unconfirmed = True

    if post_mode:
        cmd = command.Enter * 2
    else:
        cmd = command.Enter

    target_list = [
        # 待證實文章
        connect_core.TargetUnit(i18n.UnconfirmedPost,
                                '本篇文章內容經站方授權之板務管理人員判斷有尚待證實之處',
                                response=' ',
                                handler=is_unconfirmed_handler),
        connect_core.TargetUnit([
            i18n.BrowsePost,
            i18n.Done,
        ],
                                screens.Target.PostEnd,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.BrowsePost,
        ],
                                screens.Target.InPost,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.PostNoContent,
        ],
                                screens.Target.PostNoContent,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        # 動畫文章
        connect_core.TargetUnit([
            i18n.AnimationPost,
        ],
                                screens.Target.Animation,
                                response=command.GoMainMenu_TypeQ,
                                break_detect_after_send=True),
    ]

    line_from_pattern = re.compile('[\d]+~[\d]+')

    content_start = '───────────────────────────────────────'
    content_end = list()
    content_end.append('--\n※ 發信站: 批踢踢實業坊')
    content_end.append('--\n※ 發信站: 批踢踢兔(ptt2.cc)')
    content_end.append('--\n※ 發信站: 新批踢踢(ptt2.twbbs.org.tw)')

    has_control_code = False
    control_code_mode = False
    push_start = False
    content_start_exist = False
    content_start_jump = False
    content_start_jump_set = False

    first_page = True
    origin_post = list()
    stop_dict = dict()

    while True:
        index = api.connect_core.send(cmd, target_list)
        if index == 3 or index == 4:
            return None, False

        last_screen = api.connect_core.get_screen_queue()[-1]
        lines = last_screen.split('\n')
        last_line = lines[-1]
        lines.pop()
        last_screen = '\n'.join(lines)

        if content_start in last_screen and not content_start_exist:
            content_start_exist = True

        if content_start_exist:
            if not content_start_jump_set:
                if content_start not in last_screen:
                    content_start_jump = True
                    content_start_jump_set = True
            else:
                content_start_jump = False

        pattern_result = line_from_pattern.search(last_line)
        if pattern_result is None:
            control_code_mode = True
            has_control_code = True
        else:
            last_read_line_list = pattern_result.group(0).split('~')
            last_read_line_a_temp = int(last_read_line_list[0])
            last_read_line_b_temp = int(last_read_line_list[1])
            if control_code_mode:
                last_read_line_a = last_read_line_a_temp - 1
                last_read_line_b = last_read_line_b_temp - 1
            control_code_mode = False

        if first_page:
            first_page = False
            origin_post.append(last_screen)
        else:
            # print(LastScreen)
            # print(f'last_read_line_a_temp [{last_read_line_a_temp}]')
            # print(f'last_read_line_b_temp [{last_read_line_b_temp}]')
            # print(f'last_read_line_a {last_read_line_a}')
            # print(f'last_read_line_b {last_read_line_b}')
            # print(f'GetLineB {last_read_line_a_temp - last_read_line_a}')
            # print(f'GetLineA {last_read_line_b_temp - last_read_line_b}')
            # print(f'show line {last_read_line_b_temp - last_read_line_a_temp + 1}')
            if not control_code_mode:

                if last_read_line_a_temp in stop_dict:
                    new_content_part = '\n'.join(
                        lines[-stop_dict[last_read_line_a_temp]:])
                    stop_dict = dict()
                else:
                    get_line_b = last_read_line_b_temp - last_read_line_b
                    if get_line_b > 0:
                        # print('Type 1')
                        # print(f'Type 1 line_dis [{line_dis}]')
                        # print(f'Type 1 get_line_b [{get_line_b}]')
                        # print('index', index)
                        new_content_part = '\n'.join(lines[-get_line_b:])
                        if index == 1 and len(
                                new_content_part) == get_line_b - 1:
                            # print(1)
                            new_content_part = '\n'.join(
                                lines[-(get_line_b * 2):])
                        elif origin_post:
                            # print(2)
                            last_line_temp = origin_post[-1].strip()
                            try_line = lines[-(get_line_b + 1)].strip()

                            if not last_line_temp.endswith(try_line):
                                # print(3)
                                # print('=====' * 20)
                                # print('== last line [', last_line_temp, ']')
                                # print('== try_line [', try_line, ']')
                                new_content_part = try_line + '\n' + new_content_part
                        stop_dict = dict()
                    else:
                        # 駐足現象,LastReadLineB跟上一次相比並沒有改變
                        if (last_read_line_b_temp + 1) not in stop_dict:
                            stop_dict[last_read_line_b_temp + 1] = 1
                        stop_dict[last_read_line_b_temp + 1] += 1

                        get_line_a = last_read_line_a_temp - last_read_line_a

                        if get_line_a > 0:
                            # print(f'Type 2 get_line_a [{get_line_a}]')
                            new_content_part = '\n'.join(lines[-get_line_a:])
                        else:
                            new_content_part = '\n'.join(lines)

            else:
                new_content_part = lines[-1]

            origin_post.append(new_content_part)
            log.show_value(api.config, log.level.DEBUG, 'NewContentPart',
                           new_content_part)

        if index == 1:
            if content_start_jump and len(new_content_part) == 0:
                # print(f'!!!GetLineB {GetLineB}')
                get_line_b += 1
                new_content_part = '\n'.join(lines[-get_line_b:])
                # print(f'!!!NewContentPart {NewContentPart}')
                origin_post.pop()
                origin_post.append(new_content_part)
            break

        if not control_code_mode:
            last_read_line_a = last_read_line_a_temp
            last_read_line_b = last_read_line_b_temp

        for EC in content_end:
            if EC in last_screen:
                push_start = True
                break

        if not push_start:
            cmd = command.Down
        else:
            cmd = command.Right

    # print(api.Unconfirmed)
    origin_post = '\n'.join(origin_post)
    # OriginPost = [line.strip() for line in OriginPost.split('\n')]
    # OriginPost = '\n'.join(OriginPost)

    log.show_value(api.config, log.level.DEBUG, 'OriginPost', origin_post)

    return origin_post, has_control_code
Exemplo n.º 16
0
def get_board_info(api, board: str, get_post_kind: bool,
                   call_by_others: bool) -> None:
    if call_by_others:
        log_level = log.level.DEBUG
    else:
        log_level = log.level.INFO

    api._goto_board(board, refresh=True)

    ori_screen = api.connect_core.get_screen_queue()[-1]
    # print(ori_screen)

    nuser = None
    for line in ori_screen.split('\n'):
        if '編號' not in line:
            continue
        if '日 期' not in line:
            continue
        if '人氣' not in line:
            continue

        nuser = line
        break

    if nuser is None:
        raise exceptions.NoSuchBoard(api.config, board)

    # print('------------------------')
    # print('nuser', nuser)
    # print('------------------------')
    if '[靜]' in nuser:
        online_user = 0
    else:
        if '編號' not in nuser or '人氣' not in nuser:
            raise exceptions.NoSuchBoard(api.config, board)
        pattern = re.compile('[\d]+')
        r = pattern.search(nuser)
        if r is None:
            raise exceptions.NoSuchBoard(api.config, board)
        # 減一是把自己本身拿掉
        online_user = int(r.group(0)) - 1

    log.show_value(api.config, log.level.DEBUG, '人氣', online_user)

    target_list = [
        connect_core.TargetUnit(i18n.ReadingBoardInfo,
                                '任意鍵繼續',
                                break_detect=True,
                                log_level=log_level),
    ]

    api.connect_core.send('i', target_list)

    ori_screen = api.connect_core.get_screen_queue()[-1]
    # print(ori_screen)

    p = re.compile('《(.+)》看板設定')
    r = p.search(ori_screen)
    if r is not None:
        boardname = r.group(0)[1:-5].strip()
    log.show_value(api.config, log.level.DEBUG, '看板名稱', boardname)

    if boardname.lower() != board.lower():
        raise exceptions.NoSuchBoard(api.config, board)

    p = re.compile('中文敘述: (.+)')
    r = p.search(ori_screen)
    if r is not None:
        chinese_des = r.group(0)[5:].strip()
    log.show_value(api.config, log.level.DEBUG, '中文敘述', chinese_des)

    p = re.compile('板主名單: (.+)')
    r = p.search(ori_screen)
    if r is not None:
        moderator_line = r.group(0)[5:].strip()
        if '(無)' in moderator_line:
            moderators = list()
        else:
            moderators = moderator_line.split('/')
            for moderator in moderators.copy():
                check = True
                for c in moderator:
                    if len(c.encode('big5')) > 1:
                        check = False
                        break
                if not check:
                    moderators.remove(moderator)

    log.show_value(api.config, log.level.DEBUG, '板主名單', moderators)

    open_status = ('公開狀態(是否隱形): 公開' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '公開狀態', open_status)

    into_top_ten_when_hide = ('隱板時 可以 進入十大排行榜' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '隱板時可以進入十大排行榜',
                   into_top_ten_when_hide)

    non_board_members_post = ('開放 非看板會員發文' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '非看板會員發文',
                   non_board_members_post)

    reply_post = ('開放 回應文章' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '回應文章', reply_post)

    self_del_post = ('開放 自刪文章' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '自刪文章', self_del_post)

    push_post = ('開放 推薦文章' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '推薦文章', push_post)

    boo_post = ('開放 噓文' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '噓文', boo_post)

    # 限制 快速連推文章, 最低間隔時間: 5 秒
    # 開放 快速連推文章

    fast_push = ('開放 快速連推文章' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '快速連推文章', fast_push)

    if not fast_push:
        p = re.compile('最低間隔時間: [\d]+')
        r = p.search(ori_screen)
        if r is not None:
            min_interval = r.group(0)[7:].strip()
            min_interval = int(min_interval)
        else:
            min_interval = 0
        log.show_value(api.config, log.level.DEBUG, '最低間隔時間', min_interval)
    else:
        min_interval = 0

    # 推文時 自動 記錄來源 IP
    # 推文時 不會 記錄來源 IP
    push_record_ip = ('推文時 自動 記錄來源 IP' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '記錄來源 IP', push_record_ip)

    # 推文時 對齊 開頭
    # 推文時 不用對齊 開頭
    push_aligned = ('推文時 對齊 開頭' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '對齊開頭', push_aligned)

    # 板主 可 刪除部份違規文字
    moderator_can_del_illegal_content = ('板主 可 刪除部份違規文字' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '板主可刪除部份違規文字',
                   moderator_can_del_illegal_content)

    # 轉錄文章 會 自動記錄,且 需要 發文權限
    tran_post_auto_recorded_and_require_post_permissions = (
        '轉錄文章 會 自動記錄,且 需要 發文權限' in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '轉錄文章 會 自動記錄,且 需要 發文權限',
                   tran_post_auto_recorded_and_require_post_permissions)

    cool_mode = ('未 設為冷靜模式' not in ori_screen)
    log.show_value(api.config, log.level.DEBUG, '冷靜模式', cool_mode)

    require18 = ('禁止 未滿十八歲進入' in ori_screen)

    log.show_value(api.config, log.level.DEBUG, '禁止未滿十八歲進入', require18)

    p = re.compile('登入次數 [\d]+ 次以上')
    r = p.search(ori_screen)
    if r is not None:
        require_login_time = r.group(0).split(' ')[1]
        require_login_time = int(require_login_time)
    else:
        require_login_time = 0
    log.show_value(api.config, log.level.DEBUG, '發文限制登入次數', require_login_time)

    p = re.compile('退文篇數 [\d]+ 篇以下')
    r = p.search(ori_screen)
    if r is not None:
        require_illegal_post = r.group(0).split(' ')[1]
        require_illegal_post = int(require_illegal_post)
    else:
        require_illegal_post = 0
    log.show_value(api.config, log.level.DEBUG, '發文限制退文篇數',
                   require_illegal_post)

    kind_list = None
    if get_post_kind:

        api._goto_board(board)

        # Go certain board, then post to get post type info
        cmd_list = list()
        cmd_list.append(command.Ctrl_P)
        cmd = ''.join(cmd_list)

        target_list = [
            connect_core.TargetUnit(i18n.NoPermission,
                                    '無法發文: 未達看板要求權限',
                                    break_detect=True),
            connect_core.TargetUnit(i18n.Done, '或不選)', break_detect=True)
        ]

        index = api.connect_core.send(cmd, target_list)

        if index == 0:
            raise exceptions.NoPermission(i18n.NoPermission)
            # no post permission

        ori_screen = api.connect_core.get_screen_queue()[-1]
        screen_lines = ori_screen.split('\n')

        for i in screen_lines:
            if '種類:' in i:
                type_pattern = re.compile('\d\.([^\ ]*)')
                # 0 is not present any type that the key hold None object
                kind_list = type_pattern.findall(i)
                break

        # Clear post status
        cmd_list = list()
        cmd_list.append(command.Ctrl_C)
        cmd_list.append(command.Ctrl_C)
        cmd = ''.join(cmd_list)

        target_list = [
            connect_core.TargetUnit(i18n.Done,
                                    screens.Target.InBoard,
                                    break_detect=True)
        ]
        api.connect_core.send(cmd, target_list)

    board_info = data_type.BoardInfo(
        boardname, online_user, chinese_des, moderators, open_status,
        into_top_ten_when_hide, non_board_members_post, reply_post,
        self_del_post, push_post, boo_post, fast_push, min_interval,
        push_record_ip, push_aligned, moderator_can_del_illegal_content,
        tran_post_auto_recorded_and_require_post_permissions, cool_mode,
        require18, require_login_time, require_illegal_post, kind_list)
    return board_info
Exemplo n.º 17
0
def get_post_index(
        api,
        board: str,
        aid: str) -> int:
    api._goto_board(board)

    cmd_list = list()
    cmd_list.append('#')
    cmd_list.append(aid)
    cmd_list.append(command.Enter)

    cmd = ''.join(cmd_list)

    no_such_post = i18n.NoSuchPost
    no_such_post = i18n.replace(no_such_post, board, aid)

    target_list = [
        connect_core.TargetUnit(
            no_such_post,
            '找不到這個文章代碼',
            log_level=log.level.DEBUG,
            exceptions_=exceptions.NoSuchPost(board, aid)
        ),
        # 此狀態下無法使用搜尋文章代碼(AID)功能
        connect_core.TargetUnit(
            i18n.CanNotUseSearchPostCodeF,
            '此狀態下無法使用搜尋文章代碼(AID)功能',
            exceptions_=exceptions.CanNotUseSearchPostCode()
        ),
        connect_core.TargetUnit(
            i18n.NoPost,
            '沒有文章...',
            exceptions_=exceptions.NoSuchPost(board, aid)
        ),
        connect_core.TargetUnit(
            i18n.Success,
            screens.Target.InBoard,
            break_detect=True,
            log_level=log.level.DEBUG
        ),
        connect_core.TargetUnit(
            i18n.Success,
            screens.Target.InBoardWithCursor,
            break_detect=True,
            log_level=log.level.DEBUG
        ),
        connect_core.TargetUnit(
            i18n.NoSuchBoard,
            screens.Target.MainMenu_Exiting,
            exceptions_=exceptions.NoSuchBoard(api.config, board)
            # BreakDetect=True,
        )
    ]

    index = api.connect_core.send(
        cmd,
        target_list
    )
    ori_screen = api.connect_core.get_screen_queue()[-1]
    if index < 0:
        # print(OriScreen)
        raise exceptions.NoSuchBoard(api.config, board)

    # if index == 5:
    #     print(OriScreen)
    #     raise exceptions.NoSuchBoard(api.config, Board)

    # print(index)
    # print(OriScreen)
    screen_list = ori_screen.split('\n')

    line = [x for x in screen_list if x.startswith(api.cursor)]
    line = line[0]
    last_line = screen_list[screen_list.index(line) - 1]
    # print(LastLine)
    # print(line)

    if '編號' in last_line and '人氣:' in last_line:
        index = line[1:].strip()
        index_fix = False
    else:
        index = last_line.strip()
        index_fix = True
    while '  ' in index:
        index = index.replace('  ', ' ')
    index_list = index.split(' ')
    index = index_list[0]
    if index == '★':
        return 0
    index = int(index)
    if index_fix:
        index += 1
    # print(Index)
    return index
Exemplo n.º 18
0
def get_user(api, ptt_id: str) -> data_type.UserInfo:
    cmd_list = list()
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('T')
    cmd_list.append(command.Enter)
    cmd_list.append('Q')
    cmd_list.append(command.Enter)
    cmd_list.append(ptt_id)
    cmd_list.append(command.Enter)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            [
                i18n.GetUser,
                i18n.Success,
            ],
            screens.Target.AnyKey,
            break_detect=True),
        connect_core.TargetUnit(
            [
                i18n.GetUser,
                i18n.Fail,
            ],
            screens.Target.InTalk,
            break_detect=True),
    ]

    index = api.connect_core.send(
        cmd,
        target_list)
    ori_screen = api.connect_core.get_screen_queue()[-1]
    if index == 1:
        raise exceptions.NoSuchUser(ptt_id)
    # PTT1
    # 《ID暱稱》CodingMan (專業程式 BUG 製造機)《經濟狀況》小康 ($73866)
    # 《登入次數》1118 次 (同天內只計一次) 《有效文章》15 篇 (退:0)
    # 《目前動態》閱讀文章     《私人信箱》最近無新信件
    # 《上次上站》10/06/2019 17:29:49 Sun  《上次故鄉》111.251.231.184
    # 《 五子棋 》 0 勝  0 敗  0 和 《象棋戰績》 0 勝  0 敗  0 和

    # https://github.com/Truth0906/PTTLibrary

    # 強大的 PTT 函式庫
    # 提供您 快速 穩定 完整 的 PTT API

    # 提供專業的 PTT 機器人諮詢服務

    # PTT2
    # 《ID暱稱》CodingMan (專業程式 BUG 製造機)《經濟狀況》家徒四壁 ($0)
    # 《登入次數》8 次 (同天內只計一次)  《有效文章》0 篇
    # 《目前動態》看板列表     《私人信箱》最近無新信件
    # 《上次上站》10/06/2019 17:27:55 Sun  《上次故鄉》111.251.231.184
    # 《 五子棋 》 0 勝  0 敗  0 和 《象棋戰績》 0 勝  0 敗  0 和

    # 《個人名片》CodingMan 目前沒有名片

    # print(ori_screen)

    # data = lib_util.get_sub_string_list(ori_screen, '》', ['《', '\n'])
    data = parse_user_page(ori_screen)
    if len(data) < 10:
        print('\n'.join(data))
        print(len(data))
        raise exceptions.ParseError(ori_screen)

    # print('\n=> '.join(data))

    ptt_id = data[0]
    money = data[1]
    login_time = int(data[2])

    temp = re.findall(r'\d+', data[3])
    legal_post = int(temp[0])

    # PTT2 沒有退文
    if api.config.host == data_type.host_type.PTT1:
        illegal_post = int(temp[1])
    else:
        illegal_post = -1

    status = data[4]
    mail = data[5]
    last_login = data[6]
    last_ip = data[7]
    five_chess = data[8]
    chess = data[9]

    signature_file = '\n'.join(ori_screen.split('\n')[6:-1])

    log.show_value(api.config, log.level.DEBUG, 'ptt_id', ptt_id)
    log.show_value(api.config, log.level.DEBUG, 'money', money)
    log.show_value(api.config, log.level.DEBUG, 'login_time', login_time)
    log.show_value(api.config, log.level.DEBUG, 'legal_post', legal_post)
    log.show_value(api.config, log.level.DEBUG, 'illegal_post', illegal_post)
    log.show_value(api.config, log.level.DEBUG, 'status', status)
    log.show_value(api.config, log.level.DEBUG, 'mail', mail)
    log.show_value(api.config, log.level.DEBUG, 'last_login', last_login)
    log.show_value(api.config, log.level.DEBUG, 'last_ip', last_ip)
    log.show_value(api.config, log.level.DEBUG, 'five_chess', five_chess)
    log.show_value(api.config, log.level.DEBUG, 'chess', chess)
    log.show_value(api.config, log.level.DEBUG,
                   'signature_file', signature_file)

    user = data_type.UserInfo(
        ptt_id,
        money,
        login_time,
        legal_post,
        illegal_post,
        status,
        mail,
        last_login,
        last_ip,
        five_chess,
        chess,
        signature_file)
    return user
Exemplo n.º 19
0
def get_mail(api, index) -> data_type.MailInfo:
    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append(command.Ctrl_Z)
    cmd_list.append('m')
    cmd_list.append(str(index))
    cmd_list.append(command.Enter)
    # cmd_list.append(command.Enter)
    cmd = ''.join(cmd_list)

    fast_target = ''
    for i in range(0, 5):
        space = ' ' * i
        fast_target = f'{api.cursor}{space}{index}'

        if api.cursor == data_type.Cursor.NEW:
            if len(fast_target) == 6:
                break
        else:
            if len(fast_target) == 5:
                break

    target_list = [
        connect_core.TargetUnit(i18n.MailBox,
                                screens.Target.InMailBox,
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit(i18n.MailBox,
                                fast_target,
                                break_detect=True,
                                log_level=log.level.DEBUG)
    ]

    api.connect_core.send(
        cmd,
        target_list,
    )
    # last_screen = api.connect_core.get_screen_queue()[-1]
    # print(last_screen)

    origin_mail, _ = _api_util.get_content(api, post_mode=False)
    # print(origin_mail)

    mail_author_pattern = re.compile('作者  (.+)')
    pattern_result = mail_author_pattern.search(origin_mail)
    mail_author = pattern_result.group(0)[2:].strip()
    log.show_value(api.config, log.level.DEBUG, i18n.Author, mail_author)

    mail_title_pattern = re.compile('標題  (.+)')
    pattern_result = mail_title_pattern.search(origin_mail)
    mail_title = pattern_result.group(0)[2:].strip()
    log.show_value(api.config, log.level.DEBUG, i18n.Title, mail_title)

    mail_date_pattern = re.compile('時間  (.+)')
    pattern_result = mail_date_pattern.search(origin_mail)
    mail_date = pattern_result.group(0)[2:].strip()
    log.show_value(api.config, log.level.DEBUG, i18n.Date, mail_date)

    content_start = '───────────────────────────────────────'
    content_end = '--\n※ 發信站: 批踢踢實業坊(ptt.cc)'

    mail_content = origin_mail[origin_mail.find(content_start) +
                               len(content_start) + 1:]

    red_envelope = False
    if content_end not in origin_mail and 'Ptt幣的大紅包喔' in origin_mail:
        mail_content = mail_content.strip()
        red_envelope = True
    else:

        mail_content = mail_content[:mail_content.rfind(content_end) + 3]

    log.show_value(api.config, log.level.DEBUG, i18n.Content, mail_content)

    if red_envelope:
        mail_ip = None
        mail_location = None
    else:
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.242.182.114
        # ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.104.127.126 (臺灣)

        ip_line = origin_mail.split('\n')
        ip_line = [x for x in ip_line if x.startswith(content_end[3:])][0]
        # print(ip_line)

        pattern = re.compile('[\d]+\.[\d]+\.[\d]+\.[\d]+')
        result = pattern.search(ip_line)
        mail_ip = result.group(0)
        log.show_value(api.config, log.level.DEBUG, [
            i18n.MailBox,
            'IP',
        ], mail_ip)

        location = ip_line[ip_line.find(mail_ip) + len(mail_ip):].strip()
        if len(location) == 0:
            mail_location = None
        else:
            # print(location)
            mail_location = location[1:-1]

            log.show_value(api.config, log.level.DEBUG, [
                i18n.MailBox,
                'location',
            ], mail_location)

    mail_result = data_type.MailInfo(origin_mail=origin_mail,
                                     author=mail_author,
                                     title=mail_title,
                                     date=mail_date,
                                     content=mail_content,
                                     ip=mail_ip,
                                     location=mail_location,
                                     red_envelope=red_envelope)

    return mail_result
Exemplo n.º 20
0
def get_favourite_board(api) -> list:

    cmd_list = list()
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('F')
    cmd_list.append(command.Enter)
    cmd_list.append('0')
    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            i18n.FavouriteBoardList,
            '選擇看板',
            break_detect=True
        )
    ]

    board_list = list()
    favourite_board_list = list()
    while True:

        api.connect_core.send(
            cmd,
            target_list
        )

        ori_screen = api.connect_core.get_screen_queue()[-1]
        # print(OriScreen)
        screen_buf = ori_screen
        screen_buf = [x for x in screen_buf.split('\n')][3:][:-1]
        screen_buf[0] = '  ' + screen_buf[0][1:]
        screen_buf = [x for x in screen_buf]

        min_len = 47

        # for line in ScreenBuf:
        #     print(line[:MinLen - len(line)])
        #     print(len(line))
        for i, line in enumerate(screen_buf):
            if len(screen_buf[i]) == 0:
                continue
            if len(screen_buf[i]) <= min_len:
                # print(f'[{ScreenBuf[i]}]')
                screen_buf[i] = screen_buf[i] + \
                    (' ' * ((min_len + 1) - len(screen_buf[i])))
        screen_buf = [x[10:min_len - len(x)].strip() for x in screen_buf]
        screen_buf = list(filter(None, screen_buf))

        for i, line in enumerate(screen_buf):
            # print(i)
            # 16 = line.find('◎')
            linebuff = line[:16].strip()

            board_type = linebuff[-2:]
            board = linebuff[:-2].strip()
            if board.startswith('ˇ'):
                board = board[1:]

            board_title = line[17:].strip()
            # print(line)
            # print('\t' + Type)
            # print('\t' + Board)
            # print('\t' + BoardTitle)

            if board in board_list:
                return favourite_board_list
            board_list.append(board)
            #
            # print('board', board)
            # print('board_type', board_type)
            # print('board_title', board_title)

            f_board = data_type.FavouriteBoard(
                board,
                board_type,
                board_title
            )
            favourite_board_list.append(f_board)

        # print(len(FavouriteBoardList))
        # print(len(screen_buf))
        if len(screen_buf) < 20:
            break

        cmd = command.Ctrl_F

    # ScreenBuf = '\n'.join(ScreenBuf)
    # print(ScreenBuf)
    # print(len(FavouriteBoardList))
    return favourite_board_list
Exemplo n.º 21
0
def get_newest_index(
        api,
        index_type: int,
        board: str = None,
        # BBS
        search_type: int = 0,
        search_condition: str = None,
        search_list: list = None) -> int:
    if index_type == data_type.index_type.BBS:

        check_value.check(api.config, str, 'Board', board)

        api._check_board(board)

        check_value.check(api.config,
                          int,
                          'SearchType',
                          search_type,
                          value_class=data_type.post_search_type)
        if search_condition is not None:
            check_value.check(api.config, str, 'SearchCondition',
                              search_condition)

        if search_list is not None:
            check_value.check(api.config, list, 'search_list', search_list)
        check_value.check(api.config, int, 'SearchType', search_type)

        api._goto_board(board)

        cmd_list = list()

        normal_newest_index = -1
        if search_condition is not None:

            normal_newest_index = get_newest_index(api,
                                                   index_type,
                                                   board=board)

            if search_type == data_type.post_search_type.KEYWORD:
                cmd_list.append('/')
            elif search_type == data_type.post_search_type.AUTHOR:
                cmd_list.append('a')
            elif search_type == data_type.post_search_type.PUSH:
                cmd_list.append('Z')
            elif search_type == data_type.post_search_type.MARK:
                cmd_list.append('G')
            elif search_type == data_type.post_search_type.MONEY:
                cmd_list.append('A')

            cmd_list.append(search_condition)
            cmd_list.append(command.Enter)

        if search_list is not None:

            if normal_newest_index == -1:
                normal_newest_index = get_newest_index(api,
                                                       index_type,
                                                       board=board)

            for search_type_, search_condition_ in search_list:

                if search_type_ == data_type.post_search_type.KEYWORD:
                    cmd_list.append('/')
                elif search_type_ == data_type.post_search_type.AUTHOR:
                    cmd_list.append('a')
                elif search_type_ == data_type.post_search_type.PUSH:
                    cmd_list.append('Z')
                elif search_type_ == data_type.post_search_type.MARK:
                    cmd_list.append('G')
                elif search_type_ == data_type.post_search_type.MONEY:
                    cmd_list.append('A')

                cmd_list.append(search_condition_)
                cmd_list.append(command.Enter)

        cmd_list.append('1')
        cmd_list.append(command.Enter)
        cmd_list.append('$')

        cmd = ''.join(cmd_list)

        target_list = [
            connect_core.TargetUnit(i18n.NoPost,
                                    '沒有文章...',
                                    break_detect=True,
                                    log_level=log.level.DEBUG),
            connect_core.TargetUnit(i18n.Success,
                                    screens.Target.InBoard,
                                    break_detect=True,
                                    log_level=log.level.DEBUG),
            connect_core.TargetUnit(i18n.Success,
                                    screens.Target.InBoardWithCursor,
                                    break_detect=True,
                                    log_level=log.level.DEBUG),
            connect_core.TargetUnit(i18n.NoSuchBoard,
                                    screens.Target.MainMenu_Exiting,
                                    exceptions_=exceptions.NoSuchBoard(
                                        api.config, board)),
        ]
        index = api.connect_core.send(cmd, target_list)
        if index < 0:
            # OriScreen = api.connect_core.getScreenQueue()[-1]
            # print(OriScreen)
            raise exceptions.NoSuchBoard(api.config, board)

        if index == 0:
            return 0

        newest_index = _get_newest_index(api)

        if normal_newest_index == newest_index:
            raise exceptions.NoSearchResult()

    elif index_type == data_type.index_type.WEB:
        # web
        _NewestIndex = None
        newest_index = 0
        _url = 'https://www.ptt.cc/bbs/'
        url = _url + board
        r = requests.get(url, cookies={'over18': '1'})

        if r.status_code != requests.codes.ok:
            raise exceptions.NoSuchBoard(api.config, board)
        soup = BeautifulSoup(r.text, 'html.parser')

        for index, data in enumerate(
                soup.select('div.btn-group.btn-group-paging a')):
            text = data.text
            herf = data.get('href')
            if '上頁' in text:
                _NewestIndex = herf.split('index')[1].split('.')[0]
                # print("_NewestIndex: " + _NewestIndex)
                _NewestIndex = int(_NewestIndex)

        if _NewestIndex is None:
            raise exceptions.UnknownError('')
        newest_index = (_NewestIndex) + 1

    elif index_type == data_type.index_type.MAIL:

        cmd_list = list()
        cmd_list.append(command.GoMainMenu)
        cmd_list.append(command.Ctrl_Z)
        cmd_list.append('m')
        cmd_list.append(command.Ctrl_F * 50)

        cmd = ''.join(cmd_list)

        target_list = [
            connect_core.TargetUnit(
                i18n.MailBox,
                screens.Target.InMailBox,
                break_detect=True,
                # log_level=log.level.DEBUG
            ),
            connect_core.TargetUnit(i18n.NoMail,
                                    screens.Target.CursorToGoodbye,
                                    break_detect=True,
                                    log_level=log.level.DEBUG),
        ]

        def get_index(api):
            current_capacity, _ = _api_util.get_mailbox_capacity(api)
            last_screen = api.connect_core.get_screen_queue()[-1]
            cursor_line = [
                x for x in last_screen.split('\n')
                if x.strip().startswith(api.cursor)
            ][0]
            # print(cursor_line)
            list_index = int(re.compile('(\d+)').search(cursor_line).group(0))
            if list_index > current_capacity:
                newest_index = list_index
            else:
                newest_index = current_capacity

            return newest_index

        for _ in range(3):
            index = api.connect_core.send(
                cmd,
                target_list,
            )

            if index == 0:
                newest_index = get_index(api)
                break
            newest_index = 0

    return newest_index
Exemplo n.º 22
0
def push(
        api,
        board: str,
        push_type: int,
        push_content: str,
        post_aid: str,
        post_index: int) -> None:

    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('qs')
    cmd_list.append(board)
    cmd_list.append(command.Enter)
    cmd_list.append(command.Ctrl_C * 2)
    cmd_list.append(command.Space)

    if post_aid is not None:
        cmd_list.append('#' + post_aid)
    elif post_index != 0:
        cmd_list.append(str(post_index))
    cmd_list.append(command.Enter)
    cmd_list.append(command.Push)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            i18n.HasPushPermission,
            '您覺得這篇',
            log_level=log.level.DEBUG,
            break_detect=True
        ),
        connect_core.TargetUnit(
            i18n.OnlyArrow,
            '加註方式',
            log_level=log.level.DEBUG,
            break_detect=True
        ),
        connect_core.TargetUnit(
            i18n.NoFastPush,
            '禁止快速連續推文',
            log_level=log.level.INFO,
            break_detect=True,
            exceptions_=exceptions.NoFastPush()
        ),
        connect_core.TargetUnit(
            i18n.NoFastPush,
            '禁止短時間內大量推文',
            log_level=log.level.INFO,
            break_detect=True,
            exceptions_=exceptions.NoFastPush()
        ),
        connect_core.TargetUnit(
            i18n.NoPermission,
            '使用者不可發言',
            log_level=log.level.INFO,
            break_detect=True,
            exceptions_=exceptions.NoPermission(i18n.NoPermission)
        ),
        connect_core.TargetUnit(
            i18n.NoPush,
            '◆ 抱歉, 禁止推薦',
            log_level=log.level.INFO,
            break_detect=True,
            exceptions_=exceptions.NoPush()
        ),
    ]

    index = api.connect_core.send(
        cmd,
        target_list
    )

    if index == -1:
        if post_aid is not None:
            raise exceptions.NoSuchPost(board, post_aid)
        else:
            raise exceptions.NoSuchPost(board, post_index)

    cmd_list = []

    if index == 0:
        push_option_line = api.connect_core.get_screen_queue()[-1]
        push_option_line = push_option_line.split('\n')[-1]
        log.show_value(api.config, log.level.DEBUG,
                      'Push option line', push_option_line)

        enable_push = '值得推薦' in push_option_line
        enable_boo = '給它噓聲' in push_option_line
        enable_arrow = '只加→註解' in push_option_line

        log.show_value(api.config, log.level.DEBUG, 'Push', enable_push)
        log.show_value(api.config, log.level.DEBUG, 'Boo', enable_boo)
        log.show_value(api.config, log.level.DEBUG, 'Arrow', enable_arrow)

        if push_type == data_type.push_type.PUSH and not enable_push:
            push_type = data_type.push_type.ARROW
        elif push_type == data_type.push_type.BOO and not enable_boo:
            push_type = data_type.push_type.ARROW
        elif push_type == data_type.push_type.ARROW and not enable_arrow:
            push_type = data_type.push_type.PUSH

        cmd_list.append(str(push_type))
    # elif index == 1:
    #     push_type = data_type.push_type.ARROW

    cmd_list.append(push_content)
    cmd_list.append(command.Enter)
    cmd_list.append('y')
    cmd_list.append(command.Enter)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit(
            [
                i18n.Push,
                i18n.Success,
            ],
            screens.Target.InBoard,
            break_detect=True,
            log_level=log.level.DEBUG
        ),
    ]

    api.connect_core.send(
        cmd,
        target_list
    )
Exemplo n.º 23
0
def get_waterball(api, operate_type:int) -> list:

    if operate_type == data_type.waterball_operate_type.NOTHING:
        water_ball_operate_type = 'R'
    elif operate_type == data_type.waterball_operate_type.CLEAR:
        water_ball_operate_type = 'C' + command.Enter + 'Y'
    elif operate_type == data_type.waterball_operate_type.MAIL:
        water_ball_operate_type = 'M'

    target_list = [
        connect_core.TargetUnit(
            i18n.NoWaterball,
            '◆ 暫無訊息記錄',
            break_detect=True,
            log_level=log.level.DEBUG
        ),
        connect_core.TargetUnit(
            [
                i18n.BrowseWaterball,
                i18n.Done,
            ],
            screens.Target.WaterBallListEnd,
            response=command.Left + water_ball_operate_type +
                     command.Enter + command.GoMainMenu,
            break_detect_after_send=True,
            log_level=log.level.DEBUG
        ),
        connect_core.TargetUnit(
            [
                i18n.BrowseWaterball,
            ],
            screens.Target.InWaterBallList,
            break_detect=True,
            log_level=log.level.DEBUG
        ),
    ]

    cmd_list = [command.GoMainMenu, 'T', command.Enter, 'D', command.Enter]

    cmd = ''.join(cmd_list)

    line_from_pattern = re.compile('[\d]+~[\d]+')
    to_water_ball_target_pattern = re.compile('To [\w]+:')
    from_water_ball_target_pattern = re.compile('★[\w]+ ')
    water_ball_date_pattern = re.compile(
        '\[[\d]+/[\d]+/[\d]+ [\d]+:[\d]+:[\d]+\]')

    all_waterball = list()
    first_page = True
    while True:
        index = api.connect_core.send(
            cmd,
            target_list,
            # screen_timeout=1
        )
        log.show_value(
            api.config,
            log.level.DEBUG,
            'index',
            index
        )
        if index == 0:
            return []

        ori_screen = api.connect_core.get_screen_queue()[-1]
        lines = ori_screen.split('\n')
        last_line = lines[-1]
        lines.pop()
        lines = list(filter(None, lines))
        ori_screen = '\n'.join(lines)

        # print('=' * 50)
        # print(OriScreen)
        # print('=' * 50)
        # ScreenTemp = OriScreen
        log.show_value(
            api.config,
            log.level.DEBUG,
            'OriScreen',
            ori_screen
        )

        log.show_value(
            api.config,
            log.level.DEBUG,
            'LastLine',
            last_line
        )
        if last_line.startswith('★'):
            continue

        # 整理水球換行格式
        # ScreenTemp = ScreenTemp.replace(
        #     ']\n', ']==PTTWaterBallNewLine==')
        # ScreenTemp = ScreenTemp.replace('\\\n', '')
        # ScreenTemp = ScreenTemp.replace('\n', '')
        # ScreenTemp = ScreenTemp.replace(
        #     ']==PTTWaterBallNewLine==', ']\n')

        # print('=' * 50)
        # print(LastLine)
        # print('=' * 50)

        pattern_result = line_from_pattern.search(last_line)
        try:
            last_read_line_list = pattern_result.group(0).split('~')
        except Exception as e:
            import traceback
            traceback.print_tb(e.__traceback__)
            print(e)
            print(f'ori_screen {ori_screen}')
            print(f'last_line {last_line}')
            raise e

        last_read_line_a_temp = int(last_read_line_list[0])
        last_read_line_b_temp = int(last_read_line_list[1])
        # last_read_line_a = last_read_line_a_temp - 1
        # last_read_line_b = last_read_line_b_temp - 1

        if first_page:
            first_page = False
            all_waterball.append(ori_screen)
            last_read_line_a = last_read_line_a_temp - 1
            last_read_line_b = last_read_line_b_temp - 1
        else:
            get_line_a = last_read_line_a_temp - last_read_line_a
            get_line_b = last_read_line_b_temp - last_read_line_b

            # print(f'last_read_line_a [{last_read_line_a}]')
            # print(f'last_read_line_b [{last_read_line_b}]')
            # print(f'last_read_line_a_temp [{last_read_line_a_temp}]')
            # print(f'last_read_line_b_temp [{last_read_line_b_temp}]')
            # print(f'get_line_a [{get_line_a}]')
            # print(f'get_line_b [{get_line_b}]')
            if get_line_b > 0:
                # print('Type 1')

                if not all_waterball[-1].endswith(']'):
                    get_line_b += 1

                new_content_part = '\n'.join(lines[-get_line_b:])
            else:
                # print('Type 2')
                if get_line_a > 0:
                    # print('Type 2 - 1')

                    if len(lines[-get_line_a]) == 0:
                        # print('!!!!!!!!!')
                        get_line_a += 1

                    new_content_part = '\n'.join(lines[-get_line_a:])
                else:
                    # print('Type 2 - 2')
                    new_content_part = '\n'.join(lines)

            all_waterball.append(new_content_part)
            log.show_value(
                api.config,
                log.level.DEBUG,
                'NewContentPart',
                new_content_part
            )

        if index == 1:
            break

        last_read_line_a = last_read_line_a_temp
        last_read_line_b = last_read_line_b_temp

        cmd = command.Down

    all_waterball = '\n'.join(all_waterball)

    if api.config.host == data_type.host_type.PTT1:
        all_waterball = all_waterball.replace(
            ']\n', ']==PTTWaterBallNewLine==')
        all_waterball = all_waterball.replace('\n', '')
        all_waterball = all_waterball.replace(
            ']==PTTWaterBallNewLine==', ']\n')
    else:
        all_waterball = all_waterball.replace('\\\n', '')
    log.show_value(
        api.config,
        log.level.DEBUG,
        'AllWaterball',
        all_waterball
    )
    # print('=' * 20)
    # print(AllWaterball)
    # print('=' * 20)

    water_ball_list = list()
    for line in all_waterball.split('\n'):

        if (not line.startswith('To')) and (not line.startswith('★')):
            log.show_value(
                api.config,
                log.level.DEBUG,
                'Discard waterball',
                line
            )
            continue
        log.show_value(
            api.config,
            log.level.DEBUG,
            'Ready to parse waterball',
            line
        )

        if line.startswith('To'):
            log.show_value(
                api.config,
                log.level.DEBUG,
                'Waterball Type',
                'Send'
            )
            waterball_type = data_type.waterball_type.SEND

            pattern_result = to_water_ball_target_pattern.search(line)
            target = pattern_result.group(0)[3:-1]

            pattern_result = water_ball_date_pattern.search(line)
            date = pattern_result.group(0)[1:-1]

            content = line
            content = content[content.find(
                target + ':') + len(target + ':'):]
            content = content[:content.rfind(date) - 1]
            content = content.strip()

        elif line.startswith('★'):
            log.show_value(
                api.config,
                log.level.DEBUG,
                'Waterball Type',
                'Catch'
            )
            waterball_type = data_type.waterball_type.CATCH

            pattern_result = from_water_ball_target_pattern.search(line)
            target = pattern_result.group(0)[1:-1]

            pattern_result = water_ball_date_pattern.search(line)
            date = pattern_result.group(0)[1:-1]

            content = line
            content = content[content.find(
                target + ' ') + len(target + ' '):]
            content = content[:content.rfind(date) - 1]
            content = content.strip()

        log.show_value(
            api.config,
            log.level.DEBUG,
            'Waterball target',
            target
        )
        log.show_value(
            api.config,
            log.level.DEBUG,
            'Waterball content',
            content
        )
        log.show_value(
            api.config,
            log.level.DEBUG,
            'Waterball date',
            date
        )

        current_waterball = data_type.WaterballInfo(
            waterball_type,
            target,
            content,
            date
        )

        water_ball_list.append(current_waterball)

    return water_ball_list
Exemplo n.º 24
0
def get_call_status(api) -> None:

    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('A')
    cmd_list.append(command.Right)
    cmd_list.append(command.Left)

    cmd = ''.join(cmd_list)

    target_list = [
        connect_core.TargetUnit([
            i18n.GetCallStatus,
            i18n.Success,
        ],
                                '[呼叫器]打開',
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.GetCallStatus,
            i18n.Success,
        ],
                                '[呼叫器]拔掉',
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.GetCallStatus,
            i18n.Success,
        ],
                                '[呼叫器]防水',
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.GetCallStatus,
            i18n.Success,
        ],
                                '[呼叫器]好友',
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.GetCallStatus,
            i18n.Success,
        ],
                                '[呼叫器]關閉',
                                break_detect=True,
                                log_level=log.level.DEBUG),
        connect_core.TargetUnit([
            i18n.GetCallStatus,
        ],
                                '★',
                                response=cmd,
                                log_level=log.level.DEBUG),
    ]

    for i in range(2):
        index = api.connect_core.send(cmd, target_list)
        if index < 0:
            if i == 0:
                continue
            ori_screen = api.connect_core.get_screen_queue()[-1]
            raise exceptions.UnknownError(ori_screen)

    if index == 0:
        return data_type.call_status.ON
    if index == 1:
        return data_type.call_status.UNPLUG
    if index == 2:
        return data_type.call_status.WATERPROOF
    if index == 3:
        return data_type.call_status.FRIEND
    if index == 4:
        return data_type.call_status.OFF

    ori_screen = api.connect_core.get_screen_queue()[-1]
    raise exceptions.UnknownError(ori_screen)
Exemplo n.º 25
0
def search_user(api: object, ptt_id: str, min_page: int,
                max_page: int) -> list:
    cmd_list = []
    cmd_list.append(command.GoMainMenu)
    cmd_list.append('T')
    cmd_list.append(command.Enter)
    cmd_list.append('Q')
    cmd_list.append(command.Enter)
    cmd_list.append(ptt_id)
    cmd = ''.join(cmd_list)

    if min_page is not None:
        template = min_page
    else:
        template = 1

    appendstr = ' ' * template
    cmdtemp = cmd + appendstr

    target_list = [
        connect_core.TargetUnit(
            i18n.AnyKeyContinue,
            '任意鍵',
            break_detect=True,
        ),
    ]

    resultlist = []

    while True:

        api.connect_core.send(cmdtemp, target_list)
        ori_screen = api.connect_core.get_screen_queue()[-1]
        log.log(api.config, log.level.INFO, i18n.Reading)
        # print(OriScreen)
        # print(len(OriScreen.split('\n')))

        if len(ori_screen.split('\n')) == 2:
            resultid = ori_screen.split('\n')[1]
            resultid = resultid[resultid.find(' ') + 1:].strip()
            # print(resultid)

            resultlist.append(resultid)
            break
        else:

            ori_screen = ori_screen.split('\n')[3:-1]
            ori_screen = '\n'.join(ori_screen)

            templist = ori_screen.replace('\n', ' ')

            while '  ' in templist:
                templist = templist.replace('  ', ' ')

            templist = templist.split(' ')
            resultlist.extend(templist)

            # print(templist)
            # print(len(templist))

            if len(templist) != 100 and len(templist) != 120:
                break

            template += 1
            if max_page is not None:
                if template > max_page:
                    break

            cmdtemp = ' '

    log.log(api.config, log.level.INFO, i18n.ReadComplete)

    api.connect_core.send(
        command.Enter,
        [
            # 《ID暱稱》
            connect_core.TargetUnit(
                i18n.QuitUserProfile,
                '《ID暱稱》',
                response=command.Enter,
                # log_level=log.level.DEBUG
            ),
            connect_core.TargetUnit(
                i18n.Done,
                '查詢網友',
                break_detect=True,
                # log_level=log.level.DEBUG
            )
        ])

    return list(filter(None, resultlist))
Exemplo n.º 26
0
def has_new_mail(api) -> int:

    cmd_list = list()
    cmd_list.append(command.GoMainMenu)
    cmd_list.append(command.Ctrl_Z)
    cmd_list.append('m')
    # cmd_list.append('1')
    # cmd_list.append(command.Enter)
    cmd = ''.join(cmd_list)
    current_capacity = None
    plus_count = 0
    index_pattern = re.compile('(\d+)')
    checked_index_list = list()
    break_detect = False

    target_list = [
        connect_core.TargetUnit(i18n.MailBox,
                                screens.Target.InMailBox,
                                break_detect=True,
                                log_level=log.level.DEBUG)
    ]

    api.connect_core.send(
        cmd,
        target_list,
    )
    current_capacity, _ = _api_util.get_mailbox_capacity(api)
    if current_capacity > 20:
        cmd_list = list()
        cmd_list.append(command.GoMainMenu)
        cmd_list.append(command.Ctrl_Z)
        cmd_list.append('m')
        cmd_list.append('1')
        cmd_list.append(command.Enter)
        cmd = ''.join(cmd_list)

    while True:
        if current_capacity > 20:
            api.connect_core.send(
                cmd,
                target_list,
            )
        last_screen = api.connect_core.get_screen_queue()[-1]

        last_screen_list = last_screen.split('\n')
        last_screen_list = last_screen_list[3:-1]
        last_screen_list = [x[:10] for x in last_screen_list]

        current_plus_count = 0
        for line in last_screen_list:
            if str(current_capacity) in line:
                break_detect = True

            index_result = index_pattern.search(line)
            if index_result is None:
                continue
            current_index = index_result.group(0)
            if current_index in checked_index_list:
                continue
            checked_index_list.append(current_index)
            if '+' not in line:
                continue

            current_plus_count += 1

        plus_count += current_plus_count
        if break_detect:
            break
        cmd = command.Ctrl_F

    return plus_count