|
1 | 1 | from datetime import datetime, timedelta |
2 | | -from typing import Annotated, Any, Dict, Optional, cast |
| 2 | +from typing import Annotated, Dict, Optional |
3 | 3 |
|
4 | | -from bson import ObjectId |
5 | 4 | from jkit.article import Article |
6 | 5 | from jkit.constants import ARTICLE_SLUG_REGEX |
7 | 6 | from jkit.exceptions import ResourceUnavailableError |
|
19 | 18 | success, |
20 | 19 | ) |
21 | 20 |
|
| 21 | +from models.jianshu.article_earning_ranking_record import ( |
| 22 | + ArticleEarningRankingRecordDocument, |
| 23 | +) |
22 | 24 | from utils.config import config |
23 | | -from utils.db import ARTICLE_FP_RANK_COLLECTION |
24 | 25 |
|
25 | 26 | # fmt: off |
26 | 27 | splitter = AbilityJiebaPossegSplitterV1( |
|
36 | 37 |
|
37 | 38 |
|
38 | 39 | async def get_latest_onrank_record( |
39 | | - author_url: str, *, minimum_ranking: Optional[int] = None |
40 | | -) -> Optional[Dict[str, Any]]: |
41 | | - cursor = ( |
42 | | - ARTICLE_FP_RANK_COLLECTION.find( |
43 | | - { |
44 | | - "author.url": author_url, |
45 | | - "ranking": { |
46 | | - "$lte": minimum_ranking if minimum_ranking else 100, |
47 | | - }, |
48 | | - } |
49 | | - ) |
50 | | - .sort("date", -1) |
51 | | - .limit(1) |
| 40 | + author_slug: str, *, minimum_ranking: Optional[int] = None |
| 41 | +) -> Optional[ArticleEarningRankingRecordDocument]: |
| 42 | + # TODO |
| 43 | + return await ArticleEarningRankingRecordDocument.find_one( |
| 44 | + { |
| 45 | + "authorSlug": author_slug, |
| 46 | + "ranking": { # type: ignore |
| 47 | + "$lte": minimum_ranking if minimum_ranking else 100, |
| 48 | + }, |
| 49 | + }, |
| 50 | + sort={"date": "DESC"}, |
52 | 51 | ) |
53 | 52 |
|
54 | | - try: |
55 | | - return await cursor.next() |
56 | | - except StopAsyncIteration: |
57 | | - return None |
58 | | - |
59 | 53 |
|
60 | 54 | async def get_pervious_onrank_record( |
61 | | - onrank_record: Dict[str, Any], minimum_ranking: Optional[int] = None |
62 | | -) -> Optional[Dict[str, Any]]: |
63 | | - cursor = ( |
64 | | - ARTICLE_FP_RANK_COLLECTION.find( |
65 | | - { |
66 | | - "_id": {"$lt": ObjectId(onrank_record["_id"])}, |
67 | | - "author.url": onrank_record["author"]["url"], |
68 | | - "ranking": { |
69 | | - "$lte": minimum_ranking if minimum_ranking else 100, |
70 | | - }, |
71 | | - } |
72 | | - ) |
73 | | - .sort("_id", -1) |
74 | | - .limit(1) |
| 55 | + onrank_record: ArticleEarningRankingRecordDocument, |
| 56 | + minimum_ranking: Optional[int] = None, |
| 57 | +) -> Optional[ArticleEarningRankingRecordDocument]: |
| 58 | + return await ArticleEarningRankingRecordDocument.find_one( |
| 59 | + { |
| 60 | + "_id": {"$lt": onrank_record._id}, |
| 61 | + "authorSlug": onrank_record.author_slug, |
| 62 | + "ranking": { # type: ignore |
| 63 | + "$lte": minimum_ranking if minimum_ranking else 100, |
| 64 | + }, |
| 65 | + }, |
| 66 | + sort={"_id": "DESC"}, |
75 | 67 | ) |
76 | 68 |
|
77 | | - try: |
78 | | - return await cursor.next() |
79 | | - except StopAsyncIteration: |
80 | | - return None |
81 | | - |
82 | 69 |
|
83 | | -async def caculate_next_can_recommend_date(author_url: str) -> Optional[datetime]: |
84 | | - counted_article_urls = set() |
| 70 | +async def get_earliest_can_recommend_date(author_slug: str) -> Optional[datetime]: |
| 71 | + counted_article_slugs = set() |
85 | 72 |
|
86 | 73 | latest_onrank_record = await get_latest_onrank_record( |
87 | | - author_url, minimum_ranking=85 |
| 74 | + author_slug, minimum_ranking=85 |
88 | 75 | ) |
89 | 76 | if not latest_onrank_record: |
90 | | - # 作者没有上榜文章,或全部上榜文章均低于 85 名 |
91 | 77 | return None |
92 | 78 |
|
93 | | - interval_days = 10 if latest_onrank_record["ranking"] <= 30 else 7 |
94 | | - counted_article_urls.add(latest_onrank_record["article"]["url"]) |
| 79 | + interval_days = 10 if latest_onrank_record.ranking <= 30 else 7 |
| 80 | + counted_article_slugs.add(latest_onrank_record.article.slug) |
95 | 81 |
|
96 | 82 | now_record = latest_onrank_record |
97 | 83 | while True: |
98 | 84 | pervious_record = await get_pervious_onrank_record( |
99 | 85 | now_record, minimum_ranking=85 |
100 | 86 | ) |
101 | 87 | if not pervious_record: |
102 | | - # 没有更多文章 |
103 | | - return cast(datetime, now_record["date"]) + timedelta(days=interval_days) |
104 | | - if pervious_record["article"]["url"] in counted_article_urls: |
105 | | - # 该文章之前计算过间隔 |
| 88 | + return latest_onrank_record.date + timedelta(days=interval_days) |
| 89 | + if pervious_record.article.slug in counted_article_slugs: |
106 | 90 | now_record = pervious_record |
107 | 91 | continue |
108 | 92 |
|
109 | | - counted_article_urls.add(pervious_record["article"]["url"]) |
| 93 | + counted_article_slugs.add(pervious_record.article.slug) |
110 | 94 |
|
111 | 95 | if ( |
112 | | - now_record["ranking"] <= 30 |
113 | | - and (now_record["date"] - pervious_record["date"]).days + 1 >= 10 |
| 96 | + now_record.ranking <= 30 |
| 97 | + and (now_record.date - pervious_record.date).days + 1 >= 10 |
114 | 98 | ) or ( |
115 | | - now_record["ranking"] > 30 |
116 | | - and (now_record["date"] - pervious_record["date"]).days + 1 >= 7 |
| 99 | + now_record.ranking > 30 |
| 100 | + and (now_record.date - pervious_record.date).days + 1 >= 7 |
117 | 101 | ): |
118 | | - return cast(datetime, now_record["date"]) + timedelta(days=interval_days) |
| 102 | + return latest_onrank_record.date + timedelta(days=interval_days) |
119 | 103 |
|
120 | | - if pervious_record["ranking"] <= 30: |
| 104 | + if pervious_record.ranking <= 30: |
121 | 105 | interval_days += 10 |
122 | 106 | else: |
123 | 107 | interval_days += 7 |
@@ -231,10 +215,10 @@ async def get_LP_recommend_check_handler( # noqa: N802 |
231 | 215 |
|
232 | 216 | article_info = await article.info |
233 | 217 |
|
234 | | - author_url = article_info.author_info.to_user_obj().url |
| 218 | + author_slug = article_info.author_info.to_user_obj().slug |
235 | 219 | article_title = article_info.title |
236 | 220 | article_fp_reward = article_info.earned_fp_amount |
237 | | - article_next_can_recommend_date = await caculate_next_can_recommend_date(author_url) |
| 221 | + article_next_can_recommend_date = await get_earliest_can_recommend_date(author_slug) |
238 | 222 |
|
239 | 223 | can_recommend_now = article_fp_reward < 35 and ( |
240 | 224 | not article_next_can_recommend_date |
|
0 commit comments