missionpanel 1.0.2__tar.gz → 1.1__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.
- {missionpanel-1.0.2 → missionpanel-1.1}/PKG-INFO +19 -16
- missionpanel-1.1/missionpanel/example/__init__.py +2 -0
- missionpanel-1.1/missionpanel/example/rsshub.py +46 -0
- missionpanel-1.1/missionpanel/example/ttrss.py +142 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel.egg-info/PKG-INFO +19 -16
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel.egg-info/SOURCES.txt +3 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/setup.cfg +4 -4
- {missionpanel-1.0.2 → missionpanel-1.1}/setup.py +1 -1
- {missionpanel-1.0.2 → missionpanel-1.1}/LICENSE +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/README.md +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/__init__.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/handler/__init__.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/handler/handler.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/orm/__init__.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/orm/core.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/orm/handler.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/submitter/__init__.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/submitter/abc.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/submitter/asynchronous.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel/submitter/submitter.py +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel.egg-info/dependency_links.txt +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel.egg-info/requires.txt +0 -0
- {missionpanel-1.0.2 → missionpanel-1.1}/missionpanel.egg-info/top_level.txt +0 -0
@@ -1,16 +1,19 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: missionpanel
|
3
|
-
Version: 1.
|
4
|
-
Summary: A mission panel
|
5
|
-
Home-page: https://github.com/yindaheng98/missionpanel
|
6
|
-
Author: yindaheng98
|
7
|
-
Author-email: yindaheng98@gmail.com
|
8
|
-
|
9
|
-
|
10
|
-
Classifier:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: missionpanel
|
3
|
+
Version: 1.1
|
4
|
+
Summary: A mission panel
|
5
|
+
Home-page: https://github.com/yindaheng98/missionpanel
|
6
|
+
Author: yindaheng98
|
7
|
+
Author-email: yindaheng98@gmail.com
|
8
|
+
License: UNKNOWN
|
9
|
+
Platform: UNKNOWN
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Operating System :: OS Independent
|
13
|
+
Description-Content-Type: text/markdown
|
14
|
+
License-File: LICENSE
|
15
|
+
|
16
|
+
# missionnel
|
17
|
+
|
18
|
+
Just a mission panel.
|
19
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import abc
|
2
|
+
from typing import AsyncGenerator, List, Any
|
3
|
+
import httpx
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
from missionpanel.submitter import AsyncSubmitter
|
6
|
+
|
7
|
+
|
8
|
+
class RSSHubSubmitter(AsyncSubmitter, metaclass=abc.ABCMeta):
|
9
|
+
|
10
|
+
@abc.abstractmethod
|
11
|
+
async def parse_xml(self, xml: str) -> AsyncGenerator[Any, None]:
|
12
|
+
pass
|
13
|
+
|
14
|
+
async def derive_tags(self, mission_content) -> List[str]:
|
15
|
+
return []
|
16
|
+
|
17
|
+
async def derive_matcher(self, mission_content) -> List[str]:
|
18
|
+
return [mission_content['url']]
|
19
|
+
|
20
|
+
async def create_missions(self, rsshub: str, **httpx_client_options):
|
21
|
+
async with httpx.AsyncClient(**httpx_client_options) as client:
|
22
|
+
response = await client.get(rsshub)
|
23
|
+
async for mission_content in self.parse_xml(response.text):
|
24
|
+
matchers = await self.derive_matcher(mission_content)
|
25
|
+
await self.create_mission(mission_content, matchers)
|
26
|
+
tags = await self.derive_tags(mission_content)
|
27
|
+
if len(tags) > 0:
|
28
|
+
await self.add_tags(matchers, tags)
|
29
|
+
|
30
|
+
|
31
|
+
class RSSHubRootSubmitter(RSSHubSubmitter):
|
32
|
+
|
33
|
+
async def parse_xml(self, xml: str) -> AsyncGenerator[str, None]:
|
34
|
+
root = ElementTree.XML(xml)
|
35
|
+
yield {
|
36
|
+
'url': root.find('channel/link').text,
|
37
|
+
'latest': [item.find('link').text for item in root.iter('item')][0]
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
class RSSHubSubitemSubmitter(RSSHubSubmitter):
|
42
|
+
|
43
|
+
async def parse_xml(self, xml: str) -> AsyncGenerator[str, None]:
|
44
|
+
root = ElementTree.XML(xml)
|
45
|
+
for item in root.find('channel').iter('item'):
|
46
|
+
yield {'url': item.find('link').text}
|
@@ -0,0 +1,142 @@
|
|
1
|
+
import abc
|
2
|
+
import asyncio
|
3
|
+
import json
|
4
|
+
import logging
|
5
|
+
from typing import Any, AsyncGenerator, Dict, List
|
6
|
+
import httpx
|
7
|
+
from xml.etree import ElementTree
|
8
|
+
from missionpanel.submitter import AsyncSubmitter
|
9
|
+
|
10
|
+
|
11
|
+
class TTRSSClient(httpx.AsyncClient):
|
12
|
+
"""一个简单的异步TTRSS客户端"""
|
13
|
+
sem_list: Dict[str, asyncio.Semaphore] = {} # 同一时刻一个链接只能有一个客户端登录,这里用一个信号量列表控制
|
14
|
+
|
15
|
+
def __init__(self, url: str, username: str, password: str, **kwargs):
|
16
|
+
super().__init__(**kwargs)
|
17
|
+
self.__url = url
|
18
|
+
self.__username = username
|
19
|
+
self.__password = password
|
20
|
+
self.__logger = logging.getLogger("TTRSSClient")
|
21
|
+
self.__sid = None
|
22
|
+
if self.__url not in TTRSSClient.sem_list: # 给每个链接一个信号量
|
23
|
+
TTRSSClient.sem_list[self.__url] = None # 信号量必须在事件循环开始后生成,此处先给个标记
|
24
|
+
|
25
|
+
async def __aenter__(self):
|
26
|
+
for url in TTRSSClient.sem_list: # 信号量必须在事件循环开始后生成
|
27
|
+
if TTRSSClient.sem_list[url] is None: # 已经生成的信号量不要变
|
28
|
+
self.__logger.debug('semaphore for TTRSS API %s initialized' % url)
|
29
|
+
TTRSSClient.sem_list[url] = asyncio.Semaphore(1) # 生成信号量
|
30
|
+
await TTRSSClient.sem_list[self.__url].__aenter__() # 同一时刻一个链接只能有一个客户端登录
|
31
|
+
self.__logger.debug('semaphore for TTRSS API %s got' % self.__url)
|
32
|
+
await super().__aenter__()
|
33
|
+
self.__logger.debug('httpx cli for TTRSS API %s initialized' % self.__url)
|
34
|
+
try:
|
35
|
+
data = (await super().post(self.__url, content=json.dumps({
|
36
|
+
'op': 'login',
|
37
|
+
'user': self.__username,
|
38
|
+
'password': self.__password
|
39
|
+
}))).json()
|
40
|
+
self.__logger.debug('TTRSS API login response: %s' % data)
|
41
|
+
self.__sid = data['content']['session_id']
|
42
|
+
self.__logger.debug('TTRSS API login successful, sid: %s' % self.__sid)
|
43
|
+
except Exception:
|
44
|
+
self.__logger.exception('TTRSS API login failed, error: ')
|
45
|
+
return self
|
46
|
+
|
47
|
+
async def __aexit__(self, *args, **kwargs):
|
48
|
+
try:
|
49
|
+
data = (await super().post(self.__url, content=json.dumps({
|
50
|
+
"sid": self.__sid,
|
51
|
+
"op": "logout"
|
52
|
+
}))).json()
|
53
|
+
self.__logger.debug('TTRSS API logout response: %s' % data)
|
54
|
+
self.__logger.debug('TTRSS API logout successful, sid: %s' % self.__sid)
|
55
|
+
except Exception:
|
56
|
+
self.__logger.exception('TTRSS API logout failed, error: ')
|
57
|
+
await super().__aexit__(*args, **kwargs)
|
58
|
+
await TTRSSClient.sem_list[self.__url].__aexit__(*args, **kwargs)
|
59
|
+
self.__logger.debug('semaphore for TTRSS API %s released' % self.__url)
|
60
|
+
|
61
|
+
async def api(self, data: dict):
|
62
|
+
data['sid'] = self.__sid
|
63
|
+
self.__logger.debug("post data to TTRSS API %s: %s" % (self.__url, data))
|
64
|
+
try:
|
65
|
+
return (await super().post(self.__url, content=json.dumps(data))).json()['content']
|
66
|
+
except Exception:
|
67
|
+
self.__logger.exception('TTRSS API post failed, error: ')
|
68
|
+
return None
|
69
|
+
|
70
|
+
|
71
|
+
class TTRSSSubmitter(AsyncSubmitter, metaclass=abc.ABCMeta):
|
72
|
+
|
73
|
+
@abc.abstractmethod
|
74
|
+
async def parse_content(self, feed: dict, content: dict) -> AsyncGenerator[Any, None]:
|
75
|
+
pass
|
76
|
+
|
77
|
+
async def derive_tags(self, mission_content) -> List[str]:
|
78
|
+
return []
|
79
|
+
|
80
|
+
async def derive_matcher(self, mission_content) -> List[str]:
|
81
|
+
return [mission_content['url']]
|
82
|
+
|
83
|
+
async def create_missions(self, url: str, username: str, password: str, cat_id: int, **httpx_client_options):
|
84
|
+
async with TTRSSClient(url, username, password, **httpx_client_options) as client:
|
85
|
+
feeds = await client.api({
|
86
|
+
"op": "getFeeds",
|
87
|
+
"cat_id": cat_id,
|
88
|
+
"limit": None
|
89
|
+
})
|
90
|
+
for feed in feeds:
|
91
|
+
content = await client.api({
|
92
|
+
"op": "getHeadlines",
|
93
|
+
"feed_id": feed['id'],
|
94
|
+
"limit": 1,
|
95
|
+
"view_mode": "all_articles",
|
96
|
+
"order_by": "feed_dates"
|
97
|
+
})
|
98
|
+
async for mission_content in self.parse_content(feed, content, **httpx_client_options):
|
99
|
+
matchers = await self.derive_matcher(mission_content)
|
100
|
+
await self.create_mission(mission_content, matchers)
|
101
|
+
tags = await self.derive_tags(mission_content)
|
102
|
+
if len(tags) > 0:
|
103
|
+
await self.add_tags(matchers, tags)
|
104
|
+
|
105
|
+
|
106
|
+
class TTRSSHubSubmitter(TTRSSSubmitter):
|
107
|
+
logger = logging.getLogger("TTRSSHubSubmitter")
|
108
|
+
|
109
|
+
@abc.abstractmethod
|
110
|
+
async def parse_xml(self, xml: str) -> AsyncGenerator[Any, None]:
|
111
|
+
pass
|
112
|
+
|
113
|
+
async def parse_content_nocatch(self, feed: dict, content: dict, **httpx_client_options) -> AsyncGenerator[Any, None]:
|
114
|
+
async with httpx.AsyncClient(**httpx_client_options) as client:
|
115
|
+
response = await client.get(feed['feed_url'])
|
116
|
+
async for mission_content in self.parse_xml(response.text):
|
117
|
+
yield mission_content
|
118
|
+
|
119
|
+
async def parse_content(self, feed: dict, content: dict, **httpx_client_options) -> AsyncGenerator[Any, None]:
|
120
|
+
try:
|
121
|
+
async for mission_content in self.parse_content_nocatch(feed, content, **httpx_client_options):
|
122
|
+
yield mission_content
|
123
|
+
except Exception as e:
|
124
|
+
self.logger.warning(f'parse content failed, error: {e}')
|
125
|
+
|
126
|
+
|
127
|
+
class TTRRSSHubRootSubmitter(TTRSSHubSubmitter):
|
128
|
+
|
129
|
+
async def parse_xml(self, xml: str) -> AsyncGenerator[str, None]:
|
130
|
+
root = ElementTree.XML(xml)
|
131
|
+
yield {
|
132
|
+
'url': root.find('channel/link').text,
|
133
|
+
'latest': [item.find('link').text for item in root.iter('item')][0]
|
134
|
+
}
|
135
|
+
|
136
|
+
|
137
|
+
class TTRRSSHubSubitemSubmitter(TTRSSHubSubmitter):
|
138
|
+
|
139
|
+
async def parse_xml(self, xml: str) -> AsyncGenerator[str, None]:
|
140
|
+
root = ElementTree.XML(xml)
|
141
|
+
for item in root.find('channel').iter('item'):
|
142
|
+
yield {'url': item.find('link').text}
|
@@ -1,16 +1,19 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: missionpanel
|
3
|
-
Version: 1.
|
4
|
-
Summary: A mission panel
|
5
|
-
Home-page: https://github.com/yindaheng98/missionpanel
|
6
|
-
Author: yindaheng98
|
7
|
-
Author-email: yindaheng98@gmail.com
|
8
|
-
|
9
|
-
|
10
|
-
Classifier:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: missionpanel
|
3
|
+
Version: 1.1
|
4
|
+
Summary: A mission panel
|
5
|
+
Home-page: https://github.com/yindaheng98/missionpanel
|
6
|
+
Author: yindaheng98
|
7
|
+
Author-email: yindaheng98@gmail.com
|
8
|
+
License: UNKNOWN
|
9
|
+
Platform: UNKNOWN
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Operating System :: OS Independent
|
13
|
+
Description-Content-Type: text/markdown
|
14
|
+
License-File: LICENSE
|
15
|
+
|
16
|
+
# missionnel
|
17
|
+
|
18
|
+
Just a mission panel.
|
19
|
+
|
@@ -7,6 +7,9 @@ missionpanel.egg-info/SOURCES.txt
|
|
7
7
|
missionpanel.egg-info/dependency_links.txt
|
8
8
|
missionpanel.egg-info/requires.txt
|
9
9
|
missionpanel.egg-info/top_level.txt
|
10
|
+
missionpanel/example/__init__.py
|
11
|
+
missionpanel/example/rsshub.py
|
12
|
+
missionpanel/example/ttrss.py
|
10
13
|
missionpanel/handler/__init__.py
|
11
14
|
missionpanel/handler/handler.py
|
12
15
|
missionpanel/orm/__init__.py
|
@@ -1,4 +1,4 @@
|
|
1
|
-
[egg_info]
|
2
|
-
tag_build =
|
3
|
-
tag_date = 0
|
4
|
-
|
1
|
+
[egg_info]
|
2
|
+
tag_build =
|
3
|
+
tag_date = 0
|
4
|
+
|
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
|