예제 #1
0
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        data = storage.classify()

        if pd.has(cls.PRenew):
            global_storage = cls.get_global_storage()
            global_data = global_storage.classify()
            if not global_data.phones:
                raise SMSMessage.NONE
            phone_num = len(global_data.phones)
            phone_index = random.randint(0, phone_num - 1)
            data.phone = global_data.phones[phone_index]
            storage.update(data)
            return data.phone

        if not data.phone:
            raise SMSMessage.NO_PHONE

        if pd.has(cls.PGet):
            return data.phone

        if pd.has(cls.PShow):
            lines = cls.crawler.get_msg(data, service=cls)
            return Lines(*lines)

        return cls.need_help()
예제 #2
0
class FontService(Service):
    name = 'font'
    desc = '英文数字转花体字'
    long_desc = Lines('若句子中存在空格,需加引号', '👉font "this is a sentence with space"',
                      '👉font TheSentenceWithoutSpace')

    @classmethod
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        if not args:
            return cls.need_help()

        resp = Tools.get(Tools.FlowerFont, {"sentence": args[0]})
        messages = []
        if not resp['supported']:
            messages.append('暂无完全支持的花字体')
        else:
            messages.append('以下为完全支持的花字体')
            for font in resp['supported']:
                messages.append(font['sentence'])

        if resp['unsupported']:
            messages.append('下方有部分字符无法转换')
            for font in resp['unsupported']:
                messages.append(font['sentence'])
        return '\n'.join(messages)
예제 #3
0
class PinyinService(Service):
    name = 'pinyin'
    desc = '汉字转拼音'
    long_desc = Lines("👉pinyin 林俊杰", "✅lín jùn jié",
                      "当输入单个汉字且是多音字时,默认返回该字的所有拼音", "👉pinyin 给", "✅gěi/jǐ",
                      "可以使用-s或--single来获得单个拼音", "👉pinyin -s 给", "✅gěi")

    PSingle = Parameter(P(read_name='多音字返回一个拼音').default(),
                        long='single',
                        short='s')

    @classmethod
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        if not args:
            return cls.need_help()
        text = args[0]

        heteronym_when_single = not pd.has(cls.PSingle)
        resp = Tools.get(Tools.Pinyin, {
            'text': text,
            'heteronym_when_single': heteronym_when_single
        })
        resp = list(filter(lambda x: x, resp))

        return ' /'[len(text) == 1].join(resp)

    @classmethod
    def init(cls):
        cls.validate(cls.PSingle)
예제 #4
0
class CDService(Service):
    name = 'cd'
    desc = '切换工具箱'
    long_desc = Lines('👉cd lang', '👉cd ../web')

    @classmethod
    def run(cls, directory: Service, storage: ServiceData, pd: ParamDict,
            *args):
        paths = args[0] if args else ''
        terminal = LSService.find_path(directory, paths)
        storage.update(dict(service=terminal.name))
        raise CDError.SUCCESS(terminal.name)
예제 #5
0
파일: watch.py 프로젝트: Jyonn/wechat
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        storage.user.require_phone()

        data = storage.classify()
        if pd.has(cls.PCancel):
            data.work = False
            storage.update(data)
            return '任务已取消'

        if pd.has(cls.PStatus):
            if not data.work:
                return '暂无监控任务'
            return Lines(
                '正在监控:%s' % data.name,
                '任务开始时间:%s' % cls.readable_time(data.create_time),
                '已监控次数:%s' % data.visit_times, '监控时间间隔:%s分钟' %
                (data.interval or cls.PInterval.p.default_value))

        if not args:
            return cls.need_help()
        url = args[0]
        if not url_validate(url):
            raise WatchError.URL

        key = cls.get_key_of(url)
        name = urlparse(url).netloc
        if pd.has(cls.PName):
            name = pd.get(cls.PName)
        interval = pd.get(cls.PInterval)

        crt_time = datetime.datetime.now().timestamp()
        storage.update(
            dict(
                work=True,
                name=name,
                url=url,
                visit_times=0,
                error_times=0,
                create_time=crt_time,
                last_visit_time=crt_time,
                key=key,
                interval=interval,
            ))

        return '监控已开启'
예제 #6
0
class LSService(Service):
    name = 'ls'
    desc = '查看工具箱'
    long_desc = Lines('👉ls lang', '👉ls ../web')

    PLong = Parameter(P(read_name='是否显示完整信息').default(), short='l')

    @staticmethod
    def find_path(current: Service, paths: str):
        if paths and paths[0] == '/':
            current = ServiceDepot.get(ROOT_NAME)
        paths = paths.split('/')
        for path in paths:
            if path == '..':
                if not current.parent:
                    raise LSMessage.PARENT
                current = current.parent
            elif path != '.' and path != '':
                current = current.get(path)
                if not current:
                    raise LSMessage.NOT_FOUND(path)
                if not current.as_dir:
                    raise LSMessage.CD_DIR(current.name)
        return current

    @classmethod
    def init(cls):
        cls.validate(cls.PLong)

    @classmethod
    def run(cls, directory: Service, storage: ServiceData, pd: ParamDict,
            *args):
        paths = args[0] if args else ''
        terminal = cls.find_path(directory, paths)

        long = cls.PLong.is_set_in(pd)
        messages = ['%s中拥有以下工具:' % terminal.name]
        for child in terminal.get_services():
            name = child.name + ['(工具)', '(工具箱)'][child.as_dir]
            if long:
                messages.append('%s\t%s' % (name, child.desc))
            else:
                messages.append(name)
        return '\n'.join(messages)
예제 #7
0
class VideoService(Service):
    name = 'video'
    desc = '视频解析'
    long_desc = Lines('支持新片场、抖音、二更、开眼等多家视频网站解析',
                      '👉video https://www.xinpianchang.com/a11609495')

    @classmethod
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        if not args:
            return cls.need_help()

        resp = VoC.get(url=args[0])
        messages = [
            '视频名称:' + resp['video_info']['title'],
            '<a href="{}">视频封面</a>'.format(resp['video_info']['cover'])
        ]
        for option in resp['more_options']:
            messages.append('<a href="{}">{}</a>'.format(
                option['url'], option['quality']))
        return '\n'.join(messages)
예제 #8
0
파일: watch.py 프로젝트: Jyonn/wechat
class WatchService(Service):
    name = 'watch'
    desc = '网页变化监控'
    long_desc = Lines('当网页发送变化时,将会发送短信提醒,且任务自动结束', '⚠️监控最短时间单位为1分钟',
                      '⚠️暂不支持中文域名网址监控', '⚠️网页格式规范,应以http/https开头',
                      '👉watch -n百度 https://www.baidu.com',
                      '👉watch -i2 https://www.zju.edu.cn')

    async_user_task = True

    PInterval = Parameter(P(read_name='监控时间单位').default(5).process(int),
                          long='interval',
                          short='i')
    PName = Parameter(P(read_name='监控名').default(), long='name', short='n')
    PCancel = Parameter(P(read_name='取消当前任务').default(), long='cancel')
    PStatus = Parameter(P(read_name='查看当前任务').default(), long='status')

    @staticmethod
    def readable_time(create_time):
        return datetime.datetime.fromtimestamp(create_time).strftime(
            '%m-%d %H:%M')

    @classmethod
    def init(cls):
        cls.validate(cls.PName, cls.PCancel, cls.PStatus, cls.PInterval)

    @classmethod
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        storage.user.require_phone()

        data = storage.classify()
        if pd.has(cls.PCancel):
            data.work = False
            storage.update(data)
            return '任务已取消'

        if pd.has(cls.PStatus):
            if not data.work:
                return '暂无监控任务'
            return Lines(
                '正在监控:%s' % data.name,
                '任务开始时间:%s' % cls.readable_time(data.create_time),
                '已监控次数:%s' % data.visit_times, '监控时间间隔:%s分钟' %
                (data.interval or cls.PInterval.p.default_value))

        if not args:
            return cls.need_help()
        url = args[0]
        if not url_validate(url):
            raise WatchError.URL

        key = cls.get_key_of(url)
        name = urlparse(url).netloc
        if pd.has(cls.PName):
            name = pd.get(cls.PName)
        interval = pd.get(cls.PInterval)

        crt_time = datetime.datetime.now().timestamp()
        storage.update(
            dict(
                work=True,
                name=name,
                url=url,
                visit_times=0,
                error_times=0,
                create_time=crt_time,
                last_visit_time=crt_time,
                key=key,
                interval=interval,
            ))

        return '监控已开启'

    @classmethod
    def async_user_handler(cls, storage_list: List[ServiceData]):
        for service_data in storage_list:
            cls.async_user(service_data)

    @staticmethod
    def get_key_of(url):
        try:
            with requests.get(url, timeout=3) as r:
                content = r.content  # type: bytes
        except Exception:
            raise WatchError.GET_URL

        return md5(content)

    @classmethod
    def async_user(cls, storage: ServiceData):
        data = storage.classify()
        data.interval = data.interval or cls.PInterval.p.default_value

        if not data.work:
            return

        crt_time = datetime.datetime.now().timestamp()
        if data.last_visit_time + 60 * data.interval > crt_time:
            return

        data.last_visit_time = crt_time
        data.visit_times += 1

        try:
            key = cls.get_key_of(data.url)
            data.error_times = 0
        except E:
            data.error_times += 1
            if data.error_times == 3:
                Phone.announce(storage.user, cls,
                               '监控任务%s网页连续三次无法访问,已停止任务' % data.name)
                storage.update(dict(work=False))
            return

        if data.key != key:
            Phone.announce(storage.user, cls, '监控任务%s的网页发生变化' % data.name)
            storage.update(dict(work=False))
            return

        storage.update(data)
예제 #9
0
파일: bind.py 프로젝트: Jyonn/wechat
class BindPhoneService(Service):
    name = 'bind'
    desc = '绑定手机号'
    long_desc = Lines('用于推送其他功能产生的结果', '手机号绑定后允许更改',
                      '设置手机号并发送验证码:bind -p13xxxxxxxxx',
                      '非中国大陆手机号发送验证码格式为:bind -p+地区代码+手机号',
                      '如香港代码为852,则bind -p+85212345678',
                      '验证码反馈完成手机绑定:bind -c123456')

    WAIT = 0
    DONE = 1

    PPhone = Parameter(
        P(read_name='手机号').process(str).validate(phone_validator),
        long='phone',
        short='p')
    PCaptcha = Parameter(P(read_name='验证码').default(),
                         long='captcha',
                         short='c')

    @classmethod
    def init(cls):
        cls.validate(cls.PPhone, cls.PCaptcha)

    @staticmethod
    def readable_send_wait(send_wait: int):
        s = ''
        send_wait = int(send_wait)
        if send_wait // 60:
            s += '%s分' % (send_wait // 60)
        if send_wait % 60:
            s += '%s秒' % (send_wait % 60)
        return s

    @classmethod
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        data = storage.classify()

        # if data.status:  # 设置手机号
        #     raise BindPhoneError.MODIFY_NOT_ALLOWED

        crt_time = datetime.datetime.now().timestamp()
        last_time = data.last_time or 0

        if pd.has(cls.PPhone):
            phone = pd.get(cls.PPhone)
            captcha = get_random_string(length=6, allowed_chars='1234567890')

            send_wait = last_time + 60 - crt_time
            if send_wait > 0:
                raise BindPhoneMessage.SEND_WAIT(send_wait)

            Phone.validate(phone, captcha)
            storage.update(
                dict(
                    phone=phone,
                    captcha=captcha,
                    last_time=crt_time,
                    attempt=3,
                ))
            raise BindPhoneMessage.CAPTCHA_SENT
        elif pd.has(cls.PCaptcha):
            if not data.attempt:
                raise BindPhoneMessage.CAPTCHA_RESENT

            data.attempt -= 1
            storage.update(data)
            if last_time + 5 * 60 < crt_time:
                raise BindPhoneMessage.TIME_EXPIRED

            captcha = pd.get(cls.PCaptcha)
            if captcha != data.captcha:
                raise BindPhoneMessage.CAPTCHA_WRONG(data.attempt)

            storage.user.set_phone(data.phone)
            storage.update(dict(status=cls.DONE))
            raise BindPhoneMessage.SUCCESS
        else:
            return cls.need_help()
예제 #10
0
class BOCService(Service):
    name = 'boc'
    desc = '中银外汇牌价监测'
    long_desc = Lines(
        '监测中国银行外汇牌价',
        '⚠️支持多个币种现汇/现钞的买入/卖出价格',
        '⚠️使用短信提醒功能时需要设定具体的现汇/现钞和买入/卖出参数',
        '👉通过boc GBP -a命令获取英镑(GBP)的实时卖出价',
        '👉通过boc -s命令获取货币简写名称列表',
        '👉通过boc USA --ask --bn --sms=min命令监测美元的现钞卖出价,价格低于历史时会发短信提醒',
    )

    FX = {
        'GBP': '英镑',
        'UK': '英镑',
        'HKD': '港币',
        'HK': '港币',
        'USD': '美元',
        'US': '美元',
        'USA': '美元',
        'CHF': '瑞士法郎',
        'DEM': '德国马克',
        'FRF': '法国法郎',
        'FF': '法国法郎',
        'SGD': '新加坡元',
        'SEK': '瑞典克朗',
        'DKK': '丹麦克朗',
        'NOK': '挪威克朗',
        'JPY': '日元',
        'JP': '日元',
        'CAD': '加拿大元',
        'CA': '加拿大元',
        'AUD': '澳大利亚元',
        'AU': '澳大利亚元',
        'EUR': '欧元',
        'EU': '欧元',
        'MOP': '澳门元',
        'MO': '澳门元',
        'PHP': '菲律宾比索',
        'THB': '泰国铢',
        'NZD': '新西兰元',
        'KIWI': '新西兰元',
        'WON': '韩元',
        'SK': '韩元',
        'RUB': '卢布',
        'RU': '卢布',
        'MYR': '林吉特',
        'SEN': '林吉特',
        'NTD': '新台币',
        'TW': '新台币',
        'ESP': '西班牙比塞塔',
        'ITL': '意大利里拉',
        'ANG': '荷兰盾',
        'BEF': '比利时法郎',
        'FIM': '芬兰马克',
        'INR': '印度卢比',
        'IDR': '印尼卢比',
        'BRL': '巴西里亚尔',
        'AED': '阿联酋迪拉姆',
        'ZAF': '南非兰特',
        'SAR': '沙特里亚尔',
        'TRY': '土耳其里拉',
        'YTL': '土耳其里拉'
    }

    FX_REVERSE = dict()

    KEY_TRANS = dict(SE_BID='现汇买入价',
                     BN_BID='现钞买入价',
                     SE_ASK='现汇卖出价',
                     BN_ASK='现钞卖出价')
    M_TRANS = dict(min='低', max='高')

    async_user_task = True

    START = 1
    STOP = 0

    PSpotEx = Parameter(P(read_name='现汇价').default(), long='se')
    PBankNo = Parameter(P(read_name='现钞价').default(), long='bn')
    PBid = Parameter(P(read_name='买入价').default(), long='bid', short='b')
    PAsk = Parameter(P(read_name='卖出价').default(), long='ask', short='a')
    PShow = Parameter(P(read_name='显示货币简写列表').default(),
                      long='show',
                      short='s')
    PSms = Parameter(P(read_name='短信提醒').validate(sms_validator), long='sms')
    PSmsStop = Parameter(P(read_name='停止短信提醒').default(), long='sms-stop')

    @classmethod
    def init(cls):
        cls.validate(cls.PSpotEx, cls.PBankNo, cls.PBid, cls.PAsk, cls.PShow,
                     cls.PSms, cls.PSmsStop)
        for k in cls.FX:
            if cls.FX[k] in cls.FX_REVERSE:
                cls.FX_REVERSE[cls.FX[k]].append(k)
            else:
                cls.FX_REVERSE[cls.FX[k]] = [k]

    @classmethod
    def async_user_handler(cls, storage_list: List[ServiceData]):
        for service_data in storage_list:
            cls.async_user(service_data)

    @classmethod
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        data = storage.classify()

        if pd.has(cls.PShow):
            return Lines(*[
                '%s:%s' % (k, '或'.join(cls.FX_REVERSE[k]))
                for k in cls.FX_REVERSE
            ])

        if pd.has(cls.PSmsStop):
            if data.status == cls.START:
                data.status = cls.STOP
                storage.update(data)
                raise BOCError.STOP
            raise BOCError.NOT_START

        if not args:
            return cls.need_help()

        currency = args[0].upper()
        if currency not in cls.FX:
            raise BOCError.CURRENCY

        if pd.has(cls.PSms):
            storage.user.require_phone()
            if not (pd.has(cls.PSpotEx) ^ pd.has(cls.PBankNo)):
                raise BOCError.SE_BN
            if not (pd.has(cls.PAsk) ^ pd.has(cls.PBid)):
                raise BOCError.BID_ASK

            sort = ('SE' if pd.has(cls.PSpotEx) else 'BN') + ','
            sort += 'ASK' if pd.has(cls.PAsk) else 'BID'
            storage.update(
                dict(
                    currency=currency,
                    sort=sort,
                    monitor=pd.get(cls.PSms),
                    value=None,
                    status=cls.START,
                ))
            raise BOCError.START

        try:
            keys, values = bocfx(currency)
        except Exception as e:
            raise BOCError.SERVICE_INACCESSIBLE(debug_message=e)

        lines = []
        time = '实时'
        for i, k in enumerate(keys):
            if k in cls.KEY_TRANS:
                if pd.has(cls.PSpotEx) ^ pd.has(cls.PBankNo):
                    if pd.has(cls.PSpotEx) ^ ('SE' in k):
                        continue
                if pd.has(cls.PAsk) ^ pd.has(cls.PBid):
                    if pd.has(cls.PAsk) ^ ('ASK' in k):
                        continue
                lines.append('%s:%s' % (cls.KEY_TRANS[k], values[i]))
            if k == 'Time':
                time = values[i]
        lines.insert(0, '中国银行%s牌价(%s)' % (cls.FX[currency], time))
        return Lines(*lines)

    @classmethod
    def async_user(cls, storage: ServiceData):
        data = storage.classify()

        if not data.status:
            return
        if not data.error_times:
            data.error_times = 0

        crt_time = datetime.datetime.now().timestamp()
        if data.last_visit_time and data.last_visit_time + 60 * 60 > crt_time:
            return

        data.last_visit_time = crt_time

        try:
            value = bocfx(data.currency, data.sort)
        except E:
            data.error_times += 1
            if data.error_times == 3:
                Phone.announce(storage.user, cls,
                               '中银%s汇率连续三次无法访问,已停止任务' % cls.FX[data.currency])
                storage.update(dict(status=cls.STOP))
            return

        value = float(value[0])
        if not data.value or ((data.value > value) ^ (data.monitor == 'max')):
            data.value = value
            message = str(value) + '!' + \
                      '中银%s的%s达到历史新' % (cls.FX[data.currency], cls.KEY_TRANS[data.sort.replace(',', '_')]) + \
                      cls.M_TRANS[data.monitor] + '。'
            Phone.announce(storage.user, cls, message)

        storage.update(data)
예제 #11
0
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        data = storage.classify()

        if pd.has(cls.PShow):
            return Lines(*[
                '%s:%s' % (k, '或'.join(cls.FX_REVERSE[k]))
                for k in cls.FX_REVERSE
            ])

        if pd.has(cls.PSmsStop):
            if data.status == cls.START:
                data.status = cls.STOP
                storage.update(data)
                raise BOCError.STOP
            raise BOCError.NOT_START

        if not args:
            return cls.need_help()

        currency = args[0].upper()
        if currency not in cls.FX:
            raise BOCError.CURRENCY

        if pd.has(cls.PSms):
            storage.user.require_phone()
            if not (pd.has(cls.PSpotEx) ^ pd.has(cls.PBankNo)):
                raise BOCError.SE_BN
            if not (pd.has(cls.PAsk) ^ pd.has(cls.PBid)):
                raise BOCError.BID_ASK

            sort = ('SE' if pd.has(cls.PSpotEx) else 'BN') + ','
            sort += 'ASK' if pd.has(cls.PAsk) else 'BID'
            storage.update(
                dict(
                    currency=currency,
                    sort=sort,
                    monitor=pd.get(cls.PSms),
                    value=None,
                    status=cls.START,
                ))
            raise BOCError.START

        try:
            keys, values = bocfx(currency)
        except Exception as e:
            raise BOCError.SERVICE_INACCESSIBLE(debug_message=e)

        lines = []
        time = '实时'
        for i, k in enumerate(keys):
            if k in cls.KEY_TRANS:
                if pd.has(cls.PSpotEx) ^ pd.has(cls.PBankNo):
                    if pd.has(cls.PSpotEx) ^ ('SE' in k):
                        continue
                if pd.has(cls.PAsk) ^ pd.has(cls.PBid):
                    if pd.has(cls.PAsk) ^ ('ASK' in k):
                        continue
                lines.append('%s:%s' % (cls.KEY_TRANS[k], values[i]))
            if k == 'Time':
                time = values[i]
        lines.insert(0, '中国银行%s牌价(%s)' % (cls.FX[currency], time))
        return Lines(*lines)
예제 #12
0
class SMSService(Service):
    name = 'sms'
    desc = '共享手机短信'
    long_desc = Lines(
        '浏览某些不重要的网站且需要手机号注册时,本工具可以提供共享手机号。',
        '通过sms -g命令获取当前手机号,通过sms -s命令获取接收到的短信(由于手机号共享,收到的短信可能还有其他用户的,您收到的短信也公开),通过sms -r命令获取新手机号'
    )

    async_service_task = True

    PGet = Parameter(P(read_name='获取当前手机号').default(), long='get', short='g')
    PShow = Parameter(P(read_name='显示短信').default(), long='show', short='s')
    PRenew = Parameter(P(read_name='获取新手机号').default(),
                       long='renew',
                       short='r')

    crawler = FreeReceiveSMS()

    @classmethod
    def init(cls):
        cls.validate(cls.PGet, cls.PShow, cls.PRenew)

    @classmethod
    def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict,
            *args):
        data = storage.classify()

        if pd.has(cls.PRenew):
            global_storage = cls.get_global_storage()
            global_data = global_storage.classify()
            if not global_data.phones:
                raise SMSMessage.NONE
            phone_num = len(global_data.phones)
            phone_index = random.randint(0, phone_num - 1)
            data.phone = global_data.phones[phone_index]
            storage.update(data)
            return data.phone

        if not data.phone:
            raise SMSMessage.NO_PHONE

        if pd.has(cls.PGet):
            return data.phone

        if pd.has(cls.PShow):
            lines = cls.crawler.get_msg(data, service=cls)
            return Lines(*lines)

        return cls.need_help()

    @classmethod
    def async_service(cls, storage: ServiceData):
        data = storage.classify()

        last_time = data.last_update_time or 0
        crt_time = datetime.datetime.now().timestamp()
        if last_time + 60 * 30 > crt_time:
            return

        data.last_update_time = crt_time
        data.error_web_times = data.error_web_times or 0
        data.error_re_times = data.error_re_times or 0

        data.phones = cls.crawler.get_phone_list(data) or []
        storage.update(data)