PyPtt 1.2.19__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyptt-1.2.19 → pyptt-1.3.0}/PKG-INFO +1 -1
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/PTT.py +31 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/__init__.py +2 -2
- pyptt-1.3.0/PyPtt/_api_get_post_list.py +100 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_util.py +1 -1
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/check_value.py +12 -6
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/command.py +3 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/lang_en_US.py +2 -1
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/lang_zh_TW.py +2 -1
- pyptt-1.3.0/PyPtt/ssl_config.py +24 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt.egg-info/PKG-INFO +1 -1
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt.egg-info/SOURCES.txt +1 -0
- pyptt-1.2.19/PyPtt/ssl_config.py +0 -24
- {pyptt-1.2.19 → pyptt-1.3.0}/LICENSE +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/MANIFEST.in +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_bucket.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_call_status.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_change_pw.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_comment.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_del_post.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_board_info.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_board_list.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_bottom_post_list.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_favourite_board.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_newest_index.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_post.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_post_index.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_time.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_get_user.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_give_money.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_has_new_mail.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_loginout.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_mail.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_mark_post.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_post.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_reply_post.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_search_user.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/_api_set_board_title.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/config.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/connect_core.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/data_type.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/exceptions.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/i18n.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/lib_util.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/log.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/screens.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt/service.py +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt.egg-info/dependency_links.txt +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt.egg-info/requires.txt +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/PyPtt.egg-info/top_level.txt +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/README.md +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/setup.cfg +0 -0
- {pyptt-1.2.19 → pyptt-1.3.0}/setup.py +0 -0
|
@@ -15,6 +15,7 @@ from . import _api_get_bottom_post_list
|
|
|
15
15
|
from . import _api_get_favourite_board
|
|
16
16
|
from . import _api_get_newest_index
|
|
17
17
|
from . import _api_get_post
|
|
18
|
+
from . import _api_get_post_list
|
|
18
19
|
from . import _api_get_time
|
|
19
20
|
from . import _api_get_user
|
|
20
21
|
from . import _api_give_money
|
|
@@ -1055,6 +1056,36 @@ class API:
|
|
|
1055
1056
|
|
|
1056
1057
|
_api_del_post.del_post(self, board, aid, index)
|
|
1057
1058
|
|
|
1059
|
+
def get_post_list(self, board: str, limit: int = 20, offset: int = 0) -> list[dict]:
|
|
1060
|
+
"""
|
|
1061
|
+
取得文章列表。
|
|
1062
|
+
|
|
1063
|
+
Args:
|
|
1064
|
+
board (str): 看板名稱。
|
|
1065
|
+
limit (int): 取得文章數量,預設為 20。
|
|
1066
|
+
offset (int): 偏移量,預設為 0。
|
|
1067
|
+
Returns:
|
|
1068
|
+
list[dict],文章列表,詳見 :ref:`post-field`。
|
|
1069
|
+
|
|
1070
|
+
Raises:
|
|
1071
|
+
RequireLogin: 需要登入。
|
|
1072
|
+
NoSuchBoard: 看板不存在。
|
|
1073
|
+
|
|
1074
|
+
範例::
|
|
1075
|
+
|
|
1076
|
+
import PyPtt
|
|
1077
|
+
|
|
1078
|
+
ptt_bot = PyPtt.API()
|
|
1079
|
+
try:
|
|
1080
|
+
# .. login ..
|
|
1081
|
+
post_list = ptt_bot.get_post_list(board='Python', limit=10, offset=0)
|
|
1082
|
+
# .. do something ..
|
|
1083
|
+
finally:
|
|
1084
|
+
ptt_bot.logout()
|
|
1085
|
+
"""
|
|
1086
|
+
|
|
1087
|
+
return _api_get_post_list.get_post_list(self, board, limit, offset)
|
|
1088
|
+
|
|
1058
1089
|
def fast_post_step0(self, board: str, title: str, content: str, post_type: int) -> None:
|
|
1059
1090
|
_api_post.fast_post_step0(self, board, title, content, post_type)
|
|
1060
1091
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from typing import Dict, List
|
|
2
|
+
|
|
3
|
+
from . import _api_util
|
|
4
|
+
from . import check_value
|
|
5
|
+
from . import command
|
|
6
|
+
from . import connect_core
|
|
7
|
+
from . import data_type
|
|
8
|
+
from . import exceptions
|
|
9
|
+
from . import i18n
|
|
10
|
+
from . import log
|
|
11
|
+
from . import screens
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_post_list(api, board: str, limit: int = 20, offset: int = 0) -> List[Dict]:
|
|
15
|
+
_api_util.one_thread(api)
|
|
16
|
+
|
|
17
|
+
if not api._is_login:
|
|
18
|
+
raise exceptions.RequireLogin(i18n.require_login)
|
|
19
|
+
|
|
20
|
+
check_value.check_type(board, str, 'board')
|
|
21
|
+
if limit is not None:
|
|
22
|
+
check_value.check_type(limit, int, 'limit')
|
|
23
|
+
if offset is not None:
|
|
24
|
+
check_value.check_type(offset, int, 'offset')
|
|
25
|
+
|
|
26
|
+
max_index = api.get_newest_index(data_type.NewIndex.BOARD, board=board)
|
|
27
|
+
|
|
28
|
+
check_value.check_range(limit, min_value=1, max_value=max_index, name='limit')
|
|
29
|
+
check_value.check_range(offset, min_value=0, max_value=max_index - 1, name='offset')
|
|
30
|
+
|
|
31
|
+
start_index = max_index - limit - offset + 1
|
|
32
|
+
end_index = start_index + limit - 1
|
|
33
|
+
|
|
34
|
+
# the first page shows 10 posts, each next page shows 20 posts
|
|
35
|
+
if limit <= 10:
|
|
36
|
+
max_round = 1
|
|
37
|
+
else:
|
|
38
|
+
# 1 is for the first page, +1 is for rounding up
|
|
39
|
+
# so +2
|
|
40
|
+
max_round = (limit - 10) // 20 + 2
|
|
41
|
+
|
|
42
|
+
cmd_list = []
|
|
43
|
+
|
|
44
|
+
cmd_list.append(str(max(1, start_index - 100)))
|
|
45
|
+
cmd_list.append(command.enter)
|
|
46
|
+
cmd_list.append(str(start_index))
|
|
47
|
+
cmd_list.append(command.enter)
|
|
48
|
+
|
|
49
|
+
cmd = ''.join(cmd_list)
|
|
50
|
+
|
|
51
|
+
target_list = [
|
|
52
|
+
connect_core.TargetUnit(screens.Target.InBoard, log_level=log.DEBUG, break_detect=True)
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
post_list = []
|
|
56
|
+
|
|
57
|
+
for _ in range(max_round):
|
|
58
|
+
|
|
59
|
+
index = api.connect_core.send(cmd, target_list)
|
|
60
|
+
cmd = command.page_down
|
|
61
|
+
last_screen = api.connect_core.get_screen_queue()[-1]
|
|
62
|
+
|
|
63
|
+
is_parse_area = False
|
|
64
|
+
|
|
65
|
+
for line in last_screen.splitlines()[3:-1]:
|
|
66
|
+
|
|
67
|
+
if not line.startswith(api.cursor) and not is_parse_area:
|
|
68
|
+
continue
|
|
69
|
+
is_parse_area = True
|
|
70
|
+
|
|
71
|
+
if line.strip().startswith(api.cursor):
|
|
72
|
+
# replace the first cursor in the line
|
|
73
|
+
line = line.replace(api.cursor, ' ' * len(api.cursor.encode('big5uao')), 1)
|
|
74
|
+
|
|
75
|
+
if api.cursor == data_type.Cursor.NEW:
|
|
76
|
+
# add one space in the beginning to align the old cursor line
|
|
77
|
+
line = f' {line}'
|
|
78
|
+
|
|
79
|
+
cur_index = int(line[:8].strip())
|
|
80
|
+
status = line[8:10].strip()
|
|
81
|
+
comment = line[10:12].strip()
|
|
82
|
+
list_date = line[12:17].strip()
|
|
83
|
+
author = line[18:31].strip()
|
|
84
|
+
title = line[31:]
|
|
85
|
+
|
|
86
|
+
cur_post = {
|
|
87
|
+
data_type.PostField.board: board,
|
|
88
|
+
data_type.PostField.index: cur_index,
|
|
89
|
+
data_type.PostField.list_date: list_date,
|
|
90
|
+
data_type.PostField.author: author,
|
|
91
|
+
data_type.PostField.title: title,
|
|
92
|
+
data_type.PostField.push_number: comment
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
post_list.append(cur_post)
|
|
96
|
+
|
|
97
|
+
if cur_index >= end_index:
|
|
98
|
+
return post_list
|
|
99
|
+
|
|
100
|
+
raise exceptions.UnknownError(i18n.unknown_error)
|
|
@@ -94,7 +94,7 @@ def get_content(api, post_mode: bool = True):
|
|
|
94
94
|
# 這裡是 PyPtt 最黑暗最墮落的地方,所有你所知的程式碼守則,在這裡都不適用
|
|
95
95
|
# 每除完一次錯誤,我會陷入嚴重的創傷後壓力症候群,而我的腦袋會自動選擇遺忘這裡所有的一切
|
|
96
96
|
# 以確保下一個週一,我可以正常上班
|
|
97
|
-
# but it works
|
|
97
|
+
# but it works!!!
|
|
98
98
|
|
|
99
99
|
# print(LastScreen)
|
|
100
100
|
# print(f'last_read_line_a_temp [{last_read_line_a_temp}]')
|
|
@@ -15,14 +15,20 @@ def check_type(value, value_type, name) -> None:
|
|
|
15
15
|
raise TypeError(f'[PyPtt] {name} {i18n.must_be} {value_type}, but got {value}')
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def check_range(value, min_value, max_value, name) -> None:
|
|
18
|
+
def check_range(value, min_value: int = None, max_value: int = None, name: str = None) -> None:
|
|
19
19
|
check_type(value, int, name)
|
|
20
|
-
check_type(min_value, int, 'min_value')
|
|
21
|
-
check_type(max_value, int, 'max_value')
|
|
22
20
|
|
|
23
|
-
if min_value
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
if min_value is not None:
|
|
22
|
+
check_type(min_value, int, 'min_value')
|
|
23
|
+
|
|
24
|
+
if value < min_value:
|
|
25
|
+
raise exceptions.ParameterError(f'{name} {value} {i18n.must_between} {min_value} ~ {max_value}')
|
|
26
|
+
|
|
27
|
+
if max_value is not None:
|
|
28
|
+
check_type(max_value, int, 'max_value')
|
|
29
|
+
|
|
30
|
+
if value > max_value:
|
|
31
|
+
raise exceptions.ParameterError(f'{name} {value} {i18n.must_between} {min_value} ~ {max_value}')
|
|
26
32
|
|
|
27
33
|
|
|
28
34
|
def check_index(name, index, max_value=None) -> None:
|
|
@@ -115,5 +115,6 @@ string_data = {
|
|
|
115
115
|
"user_offline": "User offline",
|
|
116
116
|
"wait_for_no_fast_comment": "Because no fast comment, wait 5 sec",
|
|
117
117
|
"welcome": "PyPtt v _target0_ developed by CodingMan",
|
|
118
|
-
"wrong_id_pw": "Wrong id or pw"
|
|
118
|
+
"wrong_id_pw": "Wrong id or pw",
|
|
119
|
+
"unknown_error": "Unknown error",
|
|
119
120
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
key = """-----BEGIN EC PARAMETERS-----
|
|
2
|
+
BggqhkjOPQMBBw==
|
|
3
|
+
-----END EC PARAMETERS-----
|
|
4
|
+
-----BEGIN EC PRIVATE KEY-----
|
|
5
|
+
MHcCAQEEIKw/h9H04KLxJfnIkNO3wM2+JjX8VOiAAkv2vK2P4H1HoAoGCCqGSM49
|
|
6
|
+
AwEHoUQDQgAEnRlm+zkKvXUfHbay5w4QYc4GO5X/RVA+b7iPAcJdjapPnXBgdWxd
|
|
7
|
+
nqIJiHX/7a5OIcgZ5rjs8zUtc0UlYe7eEA==
|
|
8
|
+
-----END EC PRIVATE KEY-----
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
cert = """-----BEGIN CERTIFICATE-----
|
|
12
|
+
MIIB6jCCAY8CFCNOe3ddTd3VNwEtsYwbTsN8qW5oMAoGCCqGSM49BAMCMHcxCzAJ
|
|
13
|
+
BgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UE
|
|
14
|
+
CgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25hbCBVbml0MRQw
|
|
15
|
+
EgYDVQQDDAtDb21tb24gTmFtZTAeFw0yNTA5MDcwNzMwMTlaFw0zNTA5MDUwNzMw
|
|
16
|
+
MTlaMHcxCzAJBgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0
|
|
17
|
+
eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25h
|
|
18
|
+
bCBVbml0MRQwEgYDVQQDDAtDb21tb24gTmFtZTBZMBMGByqGSM49AgEGCCqGSM49
|
|
19
|
+
AwEHA0IABJ0ZZvs5Cr11Hx22sucOEGHOBjuV/0VQPm+4jwHCXY2qT51wYHVsXZ6i
|
|
20
|
+
CYh1/+2uTiHIGea47PM1LXNFJWHu3hAwCgYIKoZIzj0EAwIDSQAwRgIhAPoAa/vC
|
|
21
|
+
T5pmcdQRjItJuMvCdbX2AZIE58LZ2azm0rNkAiEA94lVjUIEcC6cZIR3b0ZhtEEc
|
|
22
|
+
fhFBVrfHxjt/rmXT3os=
|
|
23
|
+
-----END CERTIFICATE-----
|
|
24
|
+
"""
|
pyptt-1.2.19/PyPtt/ssl_config.py
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
key = """-----BEGIN EC PARAMETERS-----
|
|
2
|
-
BggqhkjOPQMBBw==
|
|
3
|
-
-----END EC PARAMETERS-----
|
|
4
|
-
-----BEGIN EC PRIVATE KEY-----
|
|
5
|
-
MHcCAQEEIG4BOpPiAtfiRgc2DydA/wkdxOGaxwH+exd4MXa4Cja8oAoGCCqGSM49
|
|
6
|
-
AwEHoUQDQgAEDS/OWw/BDHH2l2pZO6LPmWqNUKmuPNSJ7xbtVxsIpuJwNxntrch6
|
|
7
|
-
qbU2VrVjYuzRAjQvjff9rgC9kJLGi+Z2OQ==
|
|
8
|
-
-----END EC PRIVATE KEY-----
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
cert = """-----BEGIN CERTIFICATE-----
|
|
12
|
-
MIIB6DCCAY8CFAnIVb8H7lNPfebaSJJTQ0vn9OfhMAoGCCqGSM49BAMCMHcxCzAJ
|
|
13
|
-
BgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UE
|
|
14
|
-
CgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25hbCBVbml0MRQw
|
|
15
|
-
EgYDVQQDDAtDb21tb24gTmFtZTAeFw0yNTA3MTAwNjM3MDNaFw0zNTA3MDgwNjM3
|
|
16
|
-
MDNaMHcxCzAJBgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0
|
|
17
|
-
eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25h
|
|
18
|
-
bCBVbml0MRQwEgYDVQQDDAtDb21tb24gTmFtZTBZMBMGByqGSM49AgEGCCqGSM49
|
|
19
|
-
AwEHA0IABA0vzlsPwQxx9pdqWTuiz5lqjVCprjzUie8W7VcbCKbicDcZ7a3Ieqm1
|
|
20
|
-
Nla1Y2Ls0QI0L433/a4AvZCSxovmdjkwCgYIKoZIzj0EAwIDRwAwRAIgWFa5O1DU
|
|
21
|
-
knIrEdqRN1AoSccEbIVQM9q3W+IC0xFHeU8CIDOfBI4Tn40oE+85IslFMVLZaXGK
|
|
22
|
-
eD4SF5N8kWIN6UxT
|
|
23
|
-
-----END CERTIFICATE-----
|
|
24
|
-
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|