diff --git a/driver/wxarticle.py b/driver/wxarticle.py index 53c0a891..fa2621c5 100644 --- a/driver/wxarticle.py +++ b/driver/wxarticle.py @@ -437,6 +437,42 @@ class WXArticleFetcher: except Exception as e: print_error(f"修复图片失败: {str(e)}") return content + def get_image_url(self,url:str)->str: + base_url=cfg.get("server.base_url","") + return f"{base_url}/static/res/logo/{url}" + def get_description(self,content:str,length:int=200)->str: + soup = BeautifulSoup(content, 'html.parser') + # 找到内容 + js_content_div = soup + if js_content_div is None: + return "" + content = js_content_div.get_text().strip().strip("\n").replace("\n"," ").replace("\r"," ") + return content[:length]+"..." if len(content)>length else content + + def proxy_images(self,content:str)->str: + try: + soup = BeautifulSoup(content, 'html.parser') + # 找到内容 + js_content_div = soup + # 移除style属性中的visibility: hidden; + if js_content_div is None: + return "" + js_content_div.attrs.pop('style', None) + # 找到所有的img标签 + img_tags = js_content_div.find_all('img') + # 遍历每个img标签并修改属性,设置宽度为1080p + for img_tag in img_tags: + if 'src' in img_tag.attrs: + img_tag['src'] = self.get_image_url(img_tag['src']) + if 'style' in img_tag.attrs: + style = img_tag['style'] + # 使用正则表达式替换width属性 + style = re.sub(r'width\s*:\s*\d+\s*px', 'width: 100%', style) + img_tag['style'] = style + return js_content_div.prettify() + except Exception as e: + print_error(f"Proxy图片失败: {str(e)}") + return content def clean_article_content(self,html_content: str): from tools.html import htmltools diff --git a/public/templates/article_detail.html b/public/templates/article_detail.html index dcbc8e95..5e59fcb1 100644 --- a/public/templates/article_detail.html +++ b/public/templates/article_detail.html @@ -8,7 +8,9 @@
- 📱 + {% if article.mp_cover %} + {{article.title}} + {% endif %}
{{article.mp_name}}
@@ -26,11 +28,7 @@
- {% if article.pic_url %} -
- {{article.title}} -
- {% endif %} + {% if article.description %}
@@ -40,7 +38,7 @@
-
+

{{article.content}}

diff --git a/public/templates/articles.html b/public/templates/articles.html index c2d88314..34d3c93d 100644 --- a/public/templates/articles.html +++ b/public/templates/articles.html @@ -3,10 +3,6 @@ {% include "includes/articles_styles.html" %} -

diff --git a/public/templates/home.html b/public/templates/home.html index 3d19421d..b119765e 100644 --- a/public/templates/home.html +++ b/public/templates/home.html @@ -1,15 +1,12 @@ {%include "includes/header.html" %} -{% block title %}WeRSS - 标签首页{% endblock %} - -
-

📚 标签分类

-

按标签浏览微信公众号文章,发现感兴趣的内容

-
{% if tags %}
{% for tag in tags %}
+
+ {{tag.name}} +

{{tag.name}}

{{tag.intro or "暂无简介"}}

diff --git a/public/templates/includes/article_detail_styles.html b/public/templates/includes/article_detail_styles.html index 7cd1da8f..b250b08b 100644 --- a/public/templates/includes/article_detail_styles.html +++ b/public/templates/includes/article_detail_styles.html @@ -3,4 +3,17 @@ .article-content { background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin-bottom: 2rem; line-height: 1.8; } .mp-info { display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem; padding: 1rem; background: #f8f9fa; border-radius: 4px; } .article-meta { display: flex; gap: 2rem; align-items: center; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #e9ecef; font-size: 0.9rem; color: #6c757d; } +img{max-width:1000px !important; +border-width: 0 !important; +height: auto !important; +} +@media (max-width: 768px) { + .article-header { padding: 1.5rem 1rem; margin-bottom: 1.5rem; } + .article-content { padding: 1.5rem 1rem; margin-bottom: 1.5rem; } + .mp-info { flex-direction: column; text-align: center; gap: 0.75rem; padding: 0.75rem; } + .article-meta { flex-direction: column; gap: 0.5rem; text-align: center; font-size: 0.8rem; } + .article-meta div { display: flex; flex-direction: column; gap: 0.25rem; } + img{max-width:100% !important;} +} + \ No newline at end of file diff --git a/public/templates/includes/articles_styles.html b/public/templates/includes/articles_styles.html index c625e545..b6db9ed5 100644 --- a/public/templates/includes/articles_styles.html +++ b/public/templates/includes/articles_styles.html @@ -7,9 +7,24 @@ .search-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 1rem; } .form-group { display: flex; flex-direction: column; } .form-group label { font-weight: 500; margin-bottom: 0.25rem; font-size: 0.9rem; } -.form-control { padding: 0.5rem; border: 1px solid #ced4da; border-radius: 4px; font-size: 0.9rem; } -.search-buttons { display: flex; gap: 0.5rem; justify-content: flex-end; } +.form-control { padding: 0.75rem; border: 1px solid #ced4da; border-radius: 4px; font-size: 1rem; transition: border-color 0.3s; } +.form-control:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1); } +.search-buttons { display: flex; gap: 0.5rem; justify-content: flex-end; flex-wrap: wrap; } + +@media (max-width: 768px) { + .search-form { padding: 1rem; } + .search-row { grid-template-columns: 1fr; gap: 0.75rem; } + .form-control { padding: 0.75rem; font-size: 16px; /* 防止iOS缩放 */ } + .search-buttons { justify-content: center; } + .btn { flex: 1; min-width: 120px; text-align: center; } +} .article-item { padding: 1rem 0; border-bottom: 1px solid #e9ecef; } .article-item:last-child { border-bottom: none; } -.article-meta { display: flex; gap: 1rem; font-size: 0.8rem; color: #6c757d; margin-top: 0.5rem; } +.article-meta { display: flex; gap: 1rem; font-size: 0.8rem; color: #6c757d; margin-top: 0.5rem; flex-wrap: wrap; } + +@media (max-width: 768px) { + .article-item { padding: 0.75rem 0; } + .article-meta { gap: 0.75rem; font-size: 0.75rem; } + .article-meta span { line-height: 1.4; } +} \ No newline at end of file diff --git a/public/templates/includes/footer.html b/public/templates/includes/footer.html index c9459649..a74e25b2 100644 --- a/public/templates/includes/footer.html +++ b/public/templates/includes/footer.html @@ -7,6 +7,22 @@

高效订阅您感兴趣的微信公众号内容

+ {% block extra_js %}{% endblock %} \ No newline at end of file diff --git a/public/templates/includes/header.html b/public/templates/includes/header.html index 5982b864..bb5ddbc1 100644 --- a/public/templates/includes/header.html +++ b/public/templates/includes/header.html @@ -3,7 +3,7 @@ - {% block title %}WeRSS{% endblock %} + {% block title %}微信公众号订阅助手{% endblock %} {% block extra_head %}{% endblock %} @@ -35,11 +66,16 @@
diff --git a/public/templates/includes/pagination.html b/public/templates/includes/pagination.html index 720dc63c..d6af41a4 100644 --- a/public/templates/includes/pagination.html +++ b/public/templates/includes/pagination.html @@ -1,15 +1,46 @@ {% if total_pages > 1 %} -
- {% if has_prev %} - « 上一页 - {% endif %} - - - 第 {{current_page}} 页,共 {{total_pages}} 页 (总计 {{total_items}} {{item_name}}) - - - {% if has_next %} - 下一页 » - {% endif %} +
+
+ {% if has_prev %} + « 上一页 + {% endif %} + +
+ 第 {{current_page}} 页 + 共 {{total_pages}} 页 + {{total_items}} {{item_name}} +
+ + {% if has_next %} + 下一页 » + {% endif %} +
+ + {% endif %} \ No newline at end of file diff --git a/public/templates/includes/tag_style.html b/public/templates/includes/tag_style.html index 5dd01c2c..505d005c 100644 --- a/public/templates/includes/tag_style.html +++ b/public/templates/includes/tag_style.html @@ -5,8 +5,16 @@ .tag-header { display: flex; align-items: start; gap: 2rem; margin-bottom: 2rem; } .tag-cover { width: 120px; height: 120px; border-radius: 8px; object-fit: cover; } .tag-info h1 { margin-bottom: 0.5rem; color: #333; } -.tag-stats { display: flex; gap: 1rem; margin-top: 1rem; } +.tag-stats { display: flex; gap: 1rem; margin-top: 1rem; flex-wrap: wrap; } .stat-item { background: #e9ecef; padding: 0.5rem 1rem; border-radius: 20px; font-size: 0.9rem; } + +@media (max-width: 768px) { + .tag-header { flex-direction: column; gap: 1rem; text-align: center; } + .tag-cover { width: 100px; height: 100px; margin: 0 auto; } + .tag-info { text-align: center; } + .tag-stats { justify-content: center; } + .stat-item { font-size: 0.8rem; padding: 0.4rem 0.8rem; } +} .article-item { border-bottom: 1px solid #e9ecef; padding-bottom: 1rem; margin-bottom: 1rem; } .article-item:last-child { border-bottom: none; } .article-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.5rem; } @@ -16,4 +24,9 @@ .mp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; margin-top: 1rem; } .mp-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; background: #f8f9fa; border-radius: 4px; } .mp-avatar { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; } + +@media (max-width: 768px) { + .mp-grid { grid-template-columns: 1fr; gap: 0.75rem; } + .mp-item { padding: 0.75rem; } +} \ No newline at end of file diff --git a/views/articles.py b/views/articles.py index e054f245..d447f0ea 100644 --- a/views/articles.py +++ b/views/articles.py @@ -3,6 +3,7 @@ from fastapi.responses import HTMLResponse from typing import Optional import os from datetime import datetime +import re from core.db import DB from core.models.article import Article @@ -11,6 +12,13 @@ from core.models.tags import Tags from apis.base import format_search_kw from core.lax.template_parser import TemplateParser from views.config import base +from driver.wxarticle import Web +def process_content_images(content: str) -> str: + """处理文章内容中的图片链接,添加前缀""" + if not content: + return content + return Web.proxy_images(content) + # 创建路由器 router = APIRouter(tags=["文章"]) @@ -81,11 +89,13 @@ async def articles_view( # 处理文章数据 article_list = [] for article, feed in articles: + processed_content = process_content_images(article.content or "") + content_display = processed_content[:200] + "..." if processed_content and len(processed_content) > 200 else processed_content article_data = { "id": article.id, "title": article.title, "description": article.description, - "pic_url": article.pic_url, + "pic_url": Web.get_image_url(article.pic_url), "url": article.url, "publish_time": datetime.fromtimestamp(article.publish_time).strftime('%Y-%m-%d %H:%M') if article.publish_time else "", "created_at": article.created_at.strftime('%Y-%m-%d %H:%M') if article.created_at else "", @@ -93,7 +103,7 @@ async def articles_view( "mp_id": article.mp_id, "mp_cover": feed.mp_cover if feed else "", "is_read": bool(article.is_read), - "content": article.content[:200] + "..." if article.content and len(article.content) > 200 else (article.content or "") + "content": content_display } article_list.append(article_data) @@ -226,8 +236,8 @@ async def article_detail_view( rel_data = { "id": rel_article.id, "title": rel_article.title, - "description": rel_article.description, - "pic_url": rel_article.pic_url, + "description": rel_article.description or Web.get_description(rel_article.content), + "pic_url": Web.get_image_url(rel_article.pic_url), "publish_time": datetime.fromtimestamp(rel_article.publish_time).strftime('%Y-%m-%d %H:%M') if rel_article.publish_time else "" } related_list.append(rel_data) @@ -236,15 +246,15 @@ async def article_detail_view( article_data = { "id": article.id, "title": article.title, - "description": article.description, - "pic_url": article.pic_url, + "description": article.description or Web.get_description(article.content), + "pic_url": Web.get_image_url(rel_article.pic_url), "url": article.url, "publish_time": datetime.fromtimestamp(article.publish_time).strftime('%Y-%m-%d %H:%M') if article.publish_time else "", "created_at": article.created_at.strftime('%Y-%m-%d %H:%M') if article.created_at else "", - "content": article.content or "", + "content": process_content_images(article.content or ""), "mp_name": feed.mp_name if feed else "未知公众号", "mp_id": article.mp_id, - "mp_cover": feed.mp_cover if feed else "", + "mp_cover": Web.get_image_url(feed.mp_cover) if feed else "", "mp_intro": feed.mp_intro if feed else "" } diff --git a/views/home.py b/views/home.py index 09a23986..8a71fd0d 100644 --- a/views/home.py +++ b/views/home.py @@ -60,7 +60,7 @@ async def home_view( tag_data = { "id": tag.id, "name": tag.name, - "cover": tag.cover, + "cover": Web.get_image_url(tag.cover) if tag.cover else "", "intro": tag.intro, "mp_count": mp_count, "article_count": article_count,