├── setup.cfg
├── MANIFEST.in
├── dev-requirements.txt
├── tests
├── responses
│ ├── once.html
│ ├── mission.html
│ ├── signin.html
│ └── balance.html
├── v2ex_config.json
├── test_get_money.py
├── test_last.py
├── v2ex.log
├── test_read.py
└── conftest.py
├── Makefile
├── v2ex_daily_mission
├── notifier
│ ├── __init__.py
│ ├── none.py
│ ├── abc.py
│ ├── bark.py
│ └── slack.py
├── __init__.py
├── v2ex.py
└── cli.py
├── .travis.yml
├── tox.ini
├── LICENSE
├── .gitignore
├── setup.py
├── ChangeLog
└── README.rst
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
4 | [tool:pytest]
5 | pep8maxlinelength = 102
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 | recursive-include v2ex_daily_mission *.py
4 |
--------------------------------------------------------------------------------
/dev-requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 | click
3 | beautifulsoup4
4 | pytest
5 | pytest-pep8
6 | responses
7 | tox
8 |
--------------------------------------------------------------------------------
/tests/responses/once.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 | | 2015-06-22 19:11:48 +08:00 |
11 | 每日登录奖励 |
12 | 29.0 |
13 | 19191.61 |
14 | 20150622 的每日登录奖励 29 铜币 |
15 |
16 |
17 |
18 | | 2015-06-20 19:11:42 +08:00 |
19 | 每日登录奖励 |
20 | 47.0 |
21 | 19162.61 |
22 | 20150620 的每日登录奖励 47 铜币 |
23 |
24 |
25 |
26 | | 2015-06-18 19:11:47 +08:00 |
27 | 每日登录奖励 |
28 | 43.0 |
29 | 19115.61 |
30 | 20150618 的每日登录奖励 43 铜币 |
31 |
32 |
33 |
34 | | 2015-06-17 19:11:44 +08:00 |
35 | 每日登录奖励 |
36 | 40.0 |
37 | 19072.61 |
38 | 20150617 的每日登录奖励 40 铜币 |
39 |
40 |
41 |
42 | | 2015-06-16 19:11:46 +08:00 |
43 | 每日登录奖励 |
44 | 45.0 |
45 | 19032.61 |
46 | 20150616 的每日登录奖励 45 铜币 |
47 |
48 |
49 |
50 | | 2015-06-15 19:11:45 +08:00 |
51 | 每日登录奖励 |
52 | 35.0 |
53 | 18987.61 |
54 | 20150615 的每日登录奖励 35 铜币 |
55 |
56 |
57 |
58 | | 2015-06-14 19:11:49 +08:00 |
59 | 每日登录奖励 |
60 | 41.0 |
61 | 18952.61 |
62 | 20150614 的每日登录奖励 41 铜币 |
63 |
64 |
65 |
66 | | 2015-06-14 19:11:49 +08:00 |
67 | 连续登录奖励 |
68 | 200.0 |
69 | 18911.61 |
70 | 连续登录每 10 天奖励 200 铜币 |
71 |
72 |
73 |
74 | | 2015-06-13 19:11:43 +08:00 |
75 | 每日登录奖励 |
76 | 1.0 |
77 | 18711.61 |
78 | 20150613 的每日登录奖励 1 铜币 |
79 |
80 |
81 |
82 | | 2015-06-12 19:11:44 +08:00 |
83 | 每日登录奖励 |
84 | 16.0 |
85 | 18710.61 |
86 | 20150612 的每日登录奖励 16 铜币 |
87 |
88 |
89 |
90 | | 2015-06-11 19:11:46 +08:00 |
91 | 每日登录奖励 |
92 | 47.0 |
93 | 18694.61 |
94 | 20150611 的每日登录奖励 47 铜币 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/v2ex_daily_mission/cli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | from __future__ import absolute_import
5 |
6 | from collections import deque
7 | import os
8 | from os import path
9 | import sys
10 | import json
11 | from codecs import open
12 |
13 | import click
14 |
15 | from v2ex_daily_mission import __version__
16 | from v2ex_daily_mission.v2ex import V2ex
17 | from v2ex_daily_mission.notifier import BarkNotifier, NoneNotifier, SlackNotifier
18 |
19 |
20 | class Config(object):
21 | def __init__(self):
22 | self.config = {}
23 |
24 | def load_config(self, config_path):
25 | with open(config_path, encoding='utf-8') as f:
26 | self.config = json.load(f)
27 |
28 |
29 | pass_config = click.make_pass_decorator(Config, ensure=True)
30 |
31 |
32 | def read_config(ctx, param, config_path):
33 | """Callback that is used whenever --config is passed."""
34 | if sys.argv[1] == 'init':
35 | return
36 | cfg = ctx.ensure_object(Config)
37 | if config_path is None:
38 | config_path = path.join(sys.path[0], 'v2ex_config.json')
39 | if not path.exists(config_path):
40 | sys.exit("Can't find config file at {0}.\nPlease read "
41 | "https://github.com/lord63/v2ex_daily_mission "
42 | "to follow the guide.".format(config_path))
43 | cfg.load_config(config_path)
44 | return config_path
45 |
46 |
47 | def initialize_nitifier(config):
48 | if 'notifier' not in config:
49 | return NoneNotifier(config)
50 | if 'bark' in config['notifier']:
51 | return BarkNotifier(config)
52 | elif 'slack' in config['notifier']:
53 | return SlackNotifier(config)
54 | return NoneNotifier(config)
55 |
56 |
57 | @click.group(context_settings={'help_option_names': ('-h', '--help')})
58 | @click.version_option(__version__, '-V', '--version', message='%(version)s')
59 | @click.option('--config',
60 | type=click.Path(exists=True, dir_okay=False, resolve_path=True),
61 | callback=read_config, expose_value=False,
62 | help='Specify the config file path.')
63 | def cli():
64 | """Complete daily mission, get money, for V2EX."""
65 | pass
66 |
67 |
68 | @cli.command()
69 | @click.option(
70 | '--directory', default=sys.path[0],
71 | type=click.Path(exists=True, file_okay=False, resolve_path=True),
72 | help='the config file path directory.')
73 | def init(directory):
74 | """Init the config fle."""
75 | cookie = click.prompt("Input your cookie")
76 |
77 | log_directory = click.prompt("Input your log directory")
78 | if not path.exists(log_directory):
79 | sys.exit("Invalid log directory, please have a check.")
80 |
81 | notifier = click.prompt(
82 | "Input your notifier",
83 | default='none',
84 | type=click.Choice(['bark', 'slack', 'none'], case_sensitive=False),
85 | show_choices=True,
86 | show_default=True
87 | )
88 | if notifier != 'none':
89 | notifier_url = click.prompt("Input your notifier url")
90 |
91 | config = {
92 | "cookie": cookie,
93 | "log_directory": path.abspath(log_directory)
94 | }
95 | if notifier != 'none':
96 | config['notifier'] = {notifier: {'url': notifier_url}}
97 |
98 | config_file_path = path.join(directory, 'v2ex_config.json')
99 | with open(config_file_path, 'w') as f:
100 | json.dump(config, f)
101 | click.echo("Init the config file at: {0}".format(config_file_path))
102 |
103 |
104 | @cli.command()
105 | @pass_config
106 | def sign(conf):
107 | """Sign in and get money."""
108 | notifier = initialize_nitifier(conf.config)
109 | try:
110 | v2ex = V2ex(conf.config)
111 | balance = v2ex.get_money()
112 | click.echo(balance)
113 | except KeyError:
114 | notifier.send_notification()
115 | click.echo('Keyerror, please check your config file.')
116 | except IndexError:
117 | notifier.send_notification()
118 | click.echo('Please check your username and password.')
119 | except Exception as e:
120 | notifier.send_notification()
121 | click.echo('Sign failed, error: {}.'.format(e))
122 |
123 |
124 | @cli.command()
125 | @click.option('--count', '-c', default=5, help="the count of days.")
126 | @pass_config
127 | def read(conf, count):
128 | """Read log file."""
129 | file_path = os.path.join(path.abspath(conf.config['log_directory']),
130 | 'v2ex.log')
131 | for line in deque(open(file_path, encoding='utf-8'), int(count)):
132 | click.echo(line, nl=False)
133 |
134 |
135 | @cli.command()
136 | @pass_config
137 | def last(conf):
138 | """How long you have kept signing in."""
139 | try:
140 | v2ex = V2ex(conf.config)
141 | last_date = v2ex.get_last()
142 | click.echo(last_date)
143 | except KeyError:
144 | click.echo('Keyerror, please check your config file.')
145 | except IndexError:
146 | click.echo('Please check your username and password.')
147 |
148 |
149 | @cli.command()
150 | @pass_config
151 | def notify(conf):
152 | """Test notify send."""
153 | notifier = initialize_nitifier(conf.config)
154 | if isinstance(notifier, NoneNotifier):
155 | click.echo("There is no notifier configuration.")
156 | return
157 | notifier.send_notification()
158 | click.echo("send notification success.")
159 |
--------------------------------------------------------------------------------