Example #1
0
    async def _init_loginAll(
            self, usablePhones: list, bandPhones: list, lockPhones: list,
            clientCount: int
    ) -> typing.Union[None, typing.List[TelegramClient]]:
        chanDataNiUsers = self.chanDataNiUsers

        pickPhones = []
        pickClients = []

        usablePhonesLength = len(usablePhones)
        # 避免頻繁使用同一帳號
        indexStart = random.randrange(0, usablePhonesLength)
        for idx in range(indexStart, usablePhonesLength + indexStart):
            phoneNumber = usablePhones[idx % usablePhonesLength]

            if novice.indexOf(bandPhones, phoneNumber) != -1 \
                    or novice.indexOf(lockPhones, phoneNumber) != -1:
                continue

            if chanDataNiUsers.lockPhone(phoneNumber):
                client = await self._login(phoneNumber)
                if client != None:
                    pickPhones.append(phoneNumber)
                    pickClients.append(client)
                    if len(pickClients) == clientCount:
                        return pickClients

        chanDataNiUsers.unlockPhones(pickPhones)
        for client in pickClients:
            await client.disconnect()
        return None
Example #2
0
    def pushCemeteryData(self, phoneNumber: str, err: Exception) -> None:
        sessionPath = self.getSessionPath(phoneNumber)
        if os.path.exists(sessionPath):
            os.remove(sessionPath)

        self._pushCemeteryData_chanData(phoneNumber)
        niUsers = self.chanData.data['niUsers']

        locks = niUsers['lockList']
        locksIdx = novice.indexOf(locks, phoneNumber)
        if locksIdx != -1:
            del locks[locksIdx]

        bands = niUsers['bandList']
        bandsIdx = novice.indexOf(bands, phoneNumber)
        if bandsIdx != -1:
            del bands[bandsIdx]
            bandInfos = niUsers['bandInfos']
            bandInfosLength = len(bandInfos)
            for bandInfosIdx in range(bandInfosLength):
                bandInfo = bandInfos[bandInfosIdx]
                if bandInfo['id'] == phoneNumber:
                    del bandInfos[bandInfosIdx]
                    break

        niUsers['cemetery'].append({
            'id':
            phoneNumber,
            'message':
            '{} Error: {}'.format(type(err), err),
        })

        self.chanData.store()
Example #3
0
def _filterGuy(tgTool: TgBaseTool, mainList: typing.List[str]) -> typing.List[str]:
    blackGuyList = tgTool.chanData.data['blackGuy']['list']
    newList = []
    for peer in mainList:
        if novice.indexOf(blackGuyList, peer) == -1:
            newList.append(peer)
    return newList
Example #4
0
 def lockPhone(self, phoneNumber: str) -> bool:
     locks = self.chanData.data['niUsers']['lockList']
     if novice.indexOf(locks, phoneNumber) == -1:
         locks.append(phoneNumber)
         self.pickPhones.append(phoneNumber)
         return True
     return False
Example #5
0
    async def getParticipants(self,
                              client: TelegramClient,
                              groupPeer: str,
                              offset: int = 0,
                              ynRealUser: bool = True,
                              excludedUserList: list = [],
                              amount: int = 200000) -> typing.Tuple[int, list]:
        # 每次請求用戶數
        pageAmount = amount * 2 + 10  # 估值 猜想排除的用戶數
        pageAmount = pageAmount if pageAmount < 100 else 100
        ynHasExcludedUsers = len(excludedUserList) != 0,
        pickIdx = pickRealIdx = offset
        channelParticipantsSearch = telethon.types.ChannelParticipantsSearch(
            q='')

        ynBreak = False
        users = []
        while len(users) < amount:
            participants = await client(
                telethon.functions.channels.GetParticipantsRequest(
                    channel=groupPeer,
                    filter=channelParticipantsSearch,
                    offset=pickIdx,
                    limit=pageAmount,
                    hash=0))

            if not participants.participants:
                break  # No more participants left

            for user in participants.users:
                pickRealIdx += 1

                # 排除 自己, 已刪除帳號, 機器人
                # type(user.is_self) == type(user.deleted) == type(user.bot) == bool
                if ynRealUser and (user.is_self or user.deleted or user.bot):
                    continue
                # 排除欲除外用戶
                if ynHasExcludedUsers \
                        and novice.indexOf(excludedUserList, user.id) != -1:
                    continue
                # 排除仿用戶
                if self.lookforClientInfo(user.id) != None:
                    continue

                # 可用物件有:
                #   id, username, first_name, last_name
                #   access_hash
                users.append(user)

                if len(users) == amount:
                    ynBreak = True
                    break

            if ynBreak:
                break

            pickIdx += pageAmount

        return (pickRealIdx, users)
Example #6
0
 def unlockPhones(self, *args):
     pickPhones = self.pickPhones
     if len(args) == 0:
         self._unlockPhones_chanData(pickPhones)
         pickPhones.clear()
     else:
         unlockPhones = args[0]
         self._unlockPhones_chanData(unlockPhones)
         for phoneNumber in unlockPhones:
             phoneIdx = novice.indexOf(pickPhones, phoneNumber)
             if phoneIdx != -1:
                 del pickPhones[phoneIdx]
     self.chanData.store()
Example #7
0
 def pushBandData(self, phoneNumber: str, dt: datetime.datetime) -> bool:
     niUsers = self.chanData.data['niUsers']
     bands = niUsers['bandList']
     if novice.indexOf(bands, phoneNumber) == -1:
         bands.append(phoneNumber)
         niUsers['bandInfos'].append({
             'id':
             phoneNumber,
             'bannedWaitDate':
             novice.dateStringify(dt),
             'bannedWaitTimeMs':
             novice.dateTimestamp(dt)
         })
     return False
Example #8
0
    def pushGuy(self, peer: TgTypeing.Peer, err: Exception) -> None:
        blackGuy = self.data['blackGuy']
        blackGuyInfos = blackGuy['infos']
        blackGuyList = blackGuy['list']

        userId = peer.id
        if novice.indexOf(blackGuyList, userId) == -1:
            blackGuyList.append(userId)
            username = peer.username
            if username != '':
                blackGuyList.append(username)
            blackGuyInfos.append({
                'userId':
                peer.id,
                'username':
                username,
                'message':
                '{} Error: {}'.format(type(err), err),
            })

            self.chanData.store()
Example #9
0
async def asyncRun(args: list, _dirpy: str, _dirname: str):
    forwardPeersTxt = args[1]
    url = args[2]
    msg = args[3]

    mainGroup = novice.py_env['peers']['adChannle']
    forwardPeers = forwardPeersTxt.split(',')

    # 用於打印日誌
    runId = random.randrange(1000000, 9999999)
    usedClientCount = 3
    latestStatus = ''
    try:
        latestStatus = '炸群進度: 初始化...'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        tgTool = TgDefaultInit(TgBaseTool,
                               clientCount=3,
                               papaPhone=novice.py_env['papaPhoneNumber'])
        await tgTool.init()
    except Exception as err:
        latestStatus += ' (失敗)'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        raise err

    try:
        latestStatus = '炸群進度: 上傳圖片...'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        messageId = await _sendFile(tgTool, mainGroup, url, msg)

        if messageId == -1:
            raise Exception(
                'Use Papa send file fail. (url: {}, msg: {})'.format(url, msg))
    except Exception as err:
        latestStatus += ' (失敗)'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        raise err

    try:
        finalPeers = _filterGuy(tgTool, forwardPeers)
        finalPeersLength = len(finalPeers)
        bandNiUserList = []
        idx = 0
        async for clientInfo in tgTool.iterPickClient(-1, 1,
                                                      whichNiUsers=True):
            readableIdx = idx + 1
            myId = clientInfo['id']
            client = clientInfo['client']

            if novice.indexOf(bandNiUserList, myId) != -1:
                if len(bandNiUserList) == usedClientCount:
                    break
                continue

            if finalPeersLength <= idx:
                break

            latestStatus = '炸群進度: {}/{}'.format(readableIdx, finalPeersLength)
            novice.logNeedle.push('(runId: {}) ok: {}/{}'.format(
                runId, readableIdx, finalPeersLength))
            try:
                forwardPeer = finalPeers[idx]
                await tgTool.joinGroup(client, forwardPeer)
                await client(
                    telethon.functions.messages.ForwardMessagesRequest(
                        from_peer=mainGroup,
                        id=[messageId],
                        to_peer=forwardPeer,
                        random_id=[tgTool.getRandId()]))

                idx += 1
            except telethon.errors.ChannelsTooMuchError as err:
                print(novice.sysTracebackException(ysHasTimestamp=True))
                # 已加入了太多的渠道/超級群組。
                novice.logNeedle.push(
                    '(runId: {}) {} get ChannelsTooMuchError: wait 30 day.'.
                    format(runId, myId))
                maturityDate = novice.dateNowAfter(days=30)
                tgTool.chanDataNiUsers.pushBandData(myId, maturityDate)
                bandNiUserList.append(myId)
            except telethon.errors.FloodWaitError as err:
                print(novice.sysTracebackException(ysHasTimestamp=True))
                waitTimeSec = err.seconds
                novice.logNeedle.push(
                    '(runId: {}) {} get FloodWaitError: wait {} seconds.'.
                    format(runId, myId, waitTimeSec))
                # TODO 秒數待驗證
                if waitTimeSec < 180:
                    await asyncio.sleep(waitTimeSec)
                else:
                    maturityDate = novice.dateNowAfter(seconds=waitTimeSec)
                    tgTool.chanDataNiUsers.pushBandData(myId, maturityDate)
                    bandNiUserList.append(myId)
            except telethon.errors.PeerFloodError as err:
                print(novice.sysTracebackException(ysHasTimestamp=True))
                # 限制發送請求 Too many requests
                novice.logNeedle.push(
                    '(runId: {}) {} get PeerFloodError: wait 1 hour.'.format(
                        runId, myId))
                # TODO 12 小時只是估計值
                maturityDate = novice.dateNowAfter(hours=12)
                tgTool.chanDataNiUsers.pushBandData(myId, maturityDate)
                bandNiUserList.append(myId)
            except Exception as err:
                print(novice.sysTracebackException(ysHasTimestamp=True))
                errType = type(err)
                novice.logNeedle.push(
                    '(runId: {}) {} get {} Error: {} (target group: {})'.
                    format(runId, myId, errType, err, forwardPeer))
                if novice.indexOf(_invalidMessageErrorTypeList, errType) != -1:
                    novice.logNeedle.push(
                        'Invalid Message Error({}): {}'.format(errType, err))
                    break
                elif novice.indexOf(_invalidPeerErrorTypeList, errType) != -1:
                    novice.logNeedle.push('Invalid Peer Error({}): {}'.format(
                        errType, err))
                    idx += 1
                elif novice.indexOf(_knownErrorTypeList, errType) != -1:
                    novice.logNeedle.push('Known Error({}): {}'.format(
                        errType, err))
                    idx += 1
                    bandNiUserList.append(myId)
                else:
                    novice.logNeedle.push('Unknown Error({}): {}'.format(
                        type(err), err))
                    idx += 1
                    bandNiUserList.append(myId)

        latestStatus += ' ({})'.format('仿用戶用盡' if len(bandNiUserList) ==
                                       usedClientCount else '結束')
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
    except Exception as err:
        latestStatus += ' (失敗)'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        raise err
Example #10
0
async def asyncRun(args: list, _dirpy: str, _dirname: str):
    if len(args) < 5:
        raise ValueError(
            'Usage: <phoneNumber> <loopTimes> <toGroupPeer> <forwardLink>')

    phoneNumber = args[1]
    loopTimes = int(args[2])
    toGroupPeer = args[3]
    forwardLink = args[4]

    regexForwardLink = r'^https:\/\/t\.me\/([^\/]+)\/(\d+)$'
    matchForwardLink = re.search(regexForwardLink, forwardLink)
    if not matchForwardLink:
        raise ValueError('轉傳來源鏈結 "{}" 不如預期'.format(forwardLink))
    forwardGroup = matchForwardLink.group(1)
    forwardMessageId = int(matchForwardLink.group(2))

    tgTool = TgDefaultInit(TgSimple)

    print('-> 登入用戶')
    client = await tgTool.login(phoneNumber)
    myInfo = await client.get_me()
    print('--> I\m {} {} ({}) and my phone is +{}.'.format(
        str(myInfo.first_name),
        str(myInfo.last_name),
        str(myInfo.username),
        myInfo.phone,
    ))

    print('-> 加入聊天室')
    inputPeer = await client.get_entity(toGroupPeer)
    if type(inputPeer) != telethon.types.User:
        print('--> telethon.functions.channels.JoinChannelRequest')
        await client(
            telethon.functions.channels.JoinChannelRequest(channel=toGroupPeer)
        )

    print('-> 紫爆轉傳 Hi')
    async for idx in tgTool.iterLoopInterval(loopTimes, 1):
        try:
            readableIdx = idx + 1
            print('--> {}/{}: {} -> {}'.format(readableIdx, loopTimes,
                                               phoneNumber, toGroupPeer))

            print('---> telethon.functions.messages.SendMessageRequest')
            await client(
                telethon.functions.messages.ForwardMessagesRequest(
                    from_peer=forwardGroup,
                    id=[forwardMessageId],
                    to_peer=toGroupPeer,
                    random_id=[tgTool.getRandId()]))
        except telethon.errors.FloodWaitError as err:
            print(novice.sysTracebackException(ysHasTimestamp=True))
            waitTimeSec = err.seconds
            print('FloodWaitError: wait {} seconds. {}'.format(
                waitTimeSec, err))
            break
        except telethon.errors.PeerFloodError as err:
            # 限制發送請求 Too many requests
            print(novice.sysTracebackException(ysHasTimestamp=True))
            print('PeerFloodError: {}'.format(err))
            break
        except telethon.errors.UserIsBlockedError as err:
            # User is blocked
            print(novice.sysTracebackException(ysHasTimestamp=True))
            print('UserIsBlockedError: {}'.format(err))
            break
        except Exception as err:
            print(novice.sysTracebackException(ysHasTimestamp=True))
            errType = type(err)
            if novice.indexOf(_invalidMessageErrorTypeList, errType) == -1:
                print('Invalid Error({}): {}'.format(errType, err))
            elif novice.indexOf(_knownErrorTypeList, errType) == -1:
                print('Known Error({}): {}'.format(errType, err))
                break
            else:
                print('Unknown Error({}): {}'.format(type(err), err))
                break
Example #11
0
async def _paperSlipAction(pageId: str, innerSession: dict, data: dict):
    forwardPeers = data['forwardPeerList']
    mainGroup = data['mainGroup']
    messageId = data['messageId']

    # 用於打印日誌
    runId = random.randrange(1000000, 9999999)
    usedClientCount = 3
    latestStatus = ''
    try:
        latestStatus = '炸群進度: 初始化...'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        await _paperSlipAction_send(pageId, 1, latestStatus)
        tgTool = TgDefaultInit(
            TgBaseTool,
            clientCount = usedClientCount,
            papaPhone = novice.py_env['papaPhoneNumber']
        )
        await tgTool.init()
    except Exception as err:
        innerSession['runing'] = False
        latestStatus += ' (失敗)'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        await _paperSlipAction_send(pageId, -1, latestStatus, ynError = True)
        return

    try:
        finalPeers = _filterGuy(tgTool, forwardPeers)
        finalPeersLength = len(finalPeers)
        bandNiUserList = []
        idx = 0
        async for clientInfo in tgTool.iterPickClient(-1, 1, whichNiUsers = True):
            readableIdx = idx + 1
            myId = clientInfo['id']
            client = clientInfo['client']

            if novice.indexOf(bandNiUserList, myId) != -1:
                if len(bandNiUserList) == usedClientCount:
                    break
                continue

            if finalPeersLength <= idx:
                break

            latestStatus = '炸群進度: {}/{}'.format(readableIdx, finalPeersLength)
            novice.logNeedle.push('(runId: {}) ok: {}/{}'.format(
                runId, readableIdx, finalPeersLength
            ))
            await _paperSlipAction_send(pageId, 1, latestStatus)
            try:
                forwardPeer = finalPeers[idx]
                await tgTool.joinGroup(client, forwardPeer)
                await client(telethon.functions.messages.ForwardMessagesRequest(
                    from_peer = mainGroup,
                    id = [messageId],
                    to_peer = forwardPeer,
                    random_id = [tgTool.getRandId()]
                ))

                idx += 1
            except telethon.errors.ChannelsTooMuchError as err:
                # 已加入了太多的渠道/超級群組。
                novice.logNeedle.push(
                    '(runId: {}) {} get ChannelsTooMuchError: wait 30 day.'.format(
                        runId, myId
                    )
                )
                maturityDate = novice.dateNowAfter(days = 30)
                tgTool.chanDataNiUsers.pushBandData(myId, maturityDate)
                bandNiUserList.append(myId)
            except telethon.errors.FloodWaitError as err:
                waitTimeSec = err.seconds
                novice.logNeedle.push(
                    '(runId: {}) {} get FloodWaitError: wait {} seconds.'.format(
                        runId, myId, waitTimeSec
                    )
                )
                # TODO 秒數待驗證
                if waitTimeSec < 180:
                    await asyncio.sleep(waitTimeSec)
                else:
                    maturityDate = novice.dateNowAfter(seconds = waitTimeSec)
                    tgTool.chanDataNiUsers.pushBandData(myId, maturityDate)
                    bandNiUserList.append(myId)
            except telethon.errors.PeerFloodError as err:
                # 限制發送請求 Too many requests
                novice.logNeedle.push(
                    '(runId: {}) {} get PeerFloodError: wait 1 hour.'.format(runId, myId)
                )
                # TODO 12 小時只是估計值
                maturityDate = novice.dateNowAfter(hours = 12)
                tgTool.chanDataNiUsers.pushBandData(myId, maturityDate)
                bandNiUserList.append(myId)
            except Exception as err:
                errType = type(err)
                novice.logNeedle.push(
                    '(runId: {}) {} get {} Error: {} (target group: {})'.format(
                        runId, myId, errType, err, forwardPeer
                    )
                )
                if novice.indexOf(_invalidMessageErrorTypeList, errType) != -1:
                    novice.logNeedle.push(
                        'Invalid Message Error({}): {}'.format(errType, err)
                    )
                    break
                elif novice.indexOf(_invalidPeerErrorTypeList, errType) != -1:
                    novice.logNeedle.push(
                        'Invalid Peer Error({}): {}'.format(errType, err)
                    )
                    idx += 1
                elif novice.indexOf(_knownErrorTypeList, errType) != -1:
                    novice.logNeedle.push(
                        'Known Error({}): {}'.format(errType, err)
                    )
                    idx += 1
                    bandNiUserList.append(myId)
                else:
                    novice.logNeedle.push(
                        'Unknown Error({}): {}'.format(type(err), err)
                    )
                    idx += 1
                    bandNiUserList.append(myId)

        latestStatus += ' ({})'.format(
            '仿用戶用盡' if len(bandNiUserList) == usedClientCount else '結束'
        )
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        await _paperSlipAction_send(pageId, 1, latestStatus)
    except Exception as err:
        latestStatus += ' (失敗)'
        novice.logNeedle.push('(runId: {}) {}'.format(runId, latestStatus))
        await _paperSlipAction_send(pageId, -1, latestStatus, ynError = True)
    finally:
        innerSession['runing'] = False
        await tgTool.release()
Example #12
0
 def getUsablePhones(self) -> list:
     phones = self.getOwnPhones()
     papaPhoneIdx = novice.indexOf(phones, self._papaPhone)
     if papaPhoneIdx != -1:
         del phones[papaPhoneIdx]
     return phones
Example #13
0
 def _unlockPhones_chanData(self, lockPhoneList: list) -> None:
     locks = self.chanData.data['niUsers']['lockList']
     for phoneNumber in lockPhoneList:
         phoneIdx = novice.indexOf(locks, phoneNumber)
         if phoneIdx != -1:
             del locks[phoneIdx]
Example #14
0
async def _niGraph(pageId: str, receiveDatasTxt: str) -> None:
    try:
        receiveDatas = json.loads(receiveDatasTxt)

        # 相當於請求錯誤
        if type(receiveDatas) != list:
            return

        resultDatas = []
        for item in receiveDatas:
            resultData = {'type': ''}

            try:
                if not 'type' in item:
                    raise KeyError('wschan: 項目缺少必要的 "type" 成員')

                requestMethod = item['type']
                resultData['type'] = requestMethod
                if type(requestMethod) != str:
                    raise TypeError('wschan: 項目 "type" 成員的類型應為字串')

                matchWsMethod = re.search(_regexWsMethod, requestMethod)
                if matchWsMethod == None:
                    raise ValueError('wschan: 項目 "type" 成員表示式格式錯誤')
                fileName = matchWsMethod.group(1)
                methodName = matchWsMethod.group(2)

                if novice.indexOf(_wsChannelList, fileName) == -1:
                    raise KeyError('wschan: 要求的方法文件不存在')

                pyImportPath = _wsChannelDirPyImportPath + '.' + fileName
                # TODO 不知為 `importlib.import_module()` 何會拋出以下訊息
                # Executing <Task pending name='Task-21' coro=<ASGIWebsocketConnection.handle_websocket() running at /home/bwaycer/ys/gitman/crepo/tgNiren.py/.venv/lib/python3.8/site-packages/quart/asgi.py:147> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f72d22eb250>()] created at /usr/lib/python3.8/asyncio/base_events.py:422> cb=[_wait.<locals>._on_completion() at /usr/lib/python3.8/asyncio/tasks.py:507] created at /home/bwaycer/ys/gitman/crepo/tgNiren.py/.venv/lib/python3.8/site-packages/quart/asgi.py:110> took 0.189 seconds
                module = importlib.import_module(pyImportPath)
                if not hasattr(module, methodName):
                    raise KeyError('wschan: 要求的方法不存在')

                action = getattr(importlib.import_module(pyImportPath),
                                 methodName)
                if 'prop' in item:
                    result = action(pageId, item['prop'])
                else:
                    result = action(pageId)
                if asyncio.iscoroutine(result):
                    result = await result
                # 測試是否可以編譯為 JSON (若其中包含 Python 的類型則會失敗)
                json.dumps(result)

                for key in result:
                    resultData[key] = result[key]
            except Exception:
                errInfo = novice.sysExceptionInfo()
                resultData['error'] = {
                    'name': errInfo['name'],
                    'message': errInfo['message'],
                }
                novice.logNeedle.push('Catch error in ws.py\n'
                                      '  resultData:\n{}\n'
                                      '  errMsg:\n{}'.format(
                                          resultData,
                                          novice.sysTracebackException()))

            if resultData['type'] != '':
                resultDatas.append(resultData)

        await quart.websocket.send(json.dumps(resultDatas))
    except Exception as err:
        raise err