支持导出音乐类型的记录

This commit is contained in:
tech-shrimp 2024-04-16 21:48:35 +08:00
parent 225123d291
commit 3e00811e1c
5 changed files with 89 additions and 9 deletions

View File

@ -34,13 +34,17 @@
## 2. 已知问题
* 视频下载不稳定如有解决方案欢迎PR
* 视频下载不稳定视频可能不全如有解决方案欢迎PR
* 只能开小号导出自己朋友圈如有解决方案欢迎PR
* HTML页面比较原始
* 音乐等朋友圈格式不支持
* 自动浏览朋友圈的功能不稳定如有解决方案欢迎PR
## 3. 常见问题与解决方法
问:怎么导出自己朋友圈
- 近期的朋友圈可以浏览全部朋友,然后导出好友列表选自己
- 需要导出长期的话,请开个小号然后使用搜一搜,详见[电脑微信浏览朋友圈](/doc/manual_guide.md)
问:为什么导出的数据不全?
- 答:软件只能导出在电脑微信**浏览过**的朋友圈记录,未浏览过的无法导出。

View File

@ -39,6 +39,8 @@ class Media:
thumb: Optional[Thumb] = None
thumbUrl: Optional[str] = None
videoDuration: Optional[str] = None
title: Optional[str] = None
description: Optional[str] = None
@dataclass_json
@dataclass
@ -61,6 +63,7 @@ class ContentObject:
contentStyle: int
contentUrl: Optional[str] = ""
title: Optional[str] = ""
description: Optional[str] = ""
mediaList: Optional[MediaList] = None
# 视频号消息
finderFeed: Optional[FinderFeed] = None

View File

@ -3,6 +3,7 @@ import json
import shutil
import threading
import time
from typing import Tuple
import xmltodict
@ -38,6 +39,31 @@ def get_img_css(size: int) -> str:
return f'width:5rem;height:5rem;float:left;margin-bottom:0.2rem;margin-right:0.2rem;{img_style}'
def is_music_msg(msg: MomentMsg) -> bool:
"""判断一个msg是否为音乐分享
"""
if msg.timelineObject.ContentObject and msg.timelineObject.ContentObject.mediaList and msg.timelineObject.ContentObject.mediaList.media:
media = msg.timelineObject.ContentObject.mediaList.media[0]
if media.type == '5':
return True
return False
def get_music_info(msg: MomentMsg) -> Tuple[str, str, str]:
"""获取音乐标题,演唱者,音乐源
"""
title = ""
musician = ""
src = ""
if msg.timelineObject.ContentObject and msg.timelineObject.ContentObject.mediaList and msg.timelineObject.ContentObject.mediaList.media:
media = msg.timelineObject.ContentObject.mediaList.media[0]
title = media.title
musician = media.description
if media.url:
src = media.url.text
return title, musician, src
class HtmlExporter(threading.Thread):
def __init__(self, gui: 'Gui', dir_name: str, contacts_map: dict[str, Contact], begin_date: datetime.date,
@ -85,12 +111,12 @@ class HtmlExporter(threading.Thread):
self.file.write(self.html_head)
# 加一天
end_date = self.end_date + datetime.timedelta(days=1)
begin_time = time.mktime(datetime.datetime(self.begin_date.year, self.begin_date.month, self.begin_date.day).timetuple())
begin_time = time.mktime(
datetime.datetime(self.begin_date.year, self.begin_date.month, self.begin_date.day).timetuple())
end_time = time.mktime(datetime.datetime(end_date.year, end_date.month, end_date.day).timetuple())
self.gui.video_decrypter.decrypt_videos(self, self.begin_date, end_date, self.dir_name, self.convert_video)
message_datas = sns_db.get_messages_in_time(begin_time, end_time)
for index, message_data in enumerate(message_datas):
if not self.stop_flag:
@ -157,6 +183,26 @@ class HtmlExporter(threading.Thread):
html += f' <div class ="text" >{msg.timelineObject.ContentObject.title}</div>\n'
html += ' </div >\n'
html += ' </a>\n'
# 音乐
elif is_music_msg(msg):
title, musician, src = get_music_info(msg)
html += f' <a href="{msg.timelineObject.ContentObject.contentUrl}" target="_blank">\n'
html += ' <div class ="music_link" >\n'
html += ' <div class ="music_des" >\n'
if images:
thumb_path, image_path = images[0]
html += f' <img src = "{thumb_path}"/>\n'
html += ' <div class = "music_title_musician">\n'
html += f' <div class = "music_title">{title}</div>\n'
html += f' <div class = "music_musician">{musician}</div>\n'
html += ' </div>\n'
html += ' </div>\n'
html += f' <audio class = "music_audio" controls>'
html += f' <source src="{src}" type="audio/mpeg">'
html += f' </audio>'
html += ' </div >\n'
html += ' </a>\n'
# 视频号
elif msg.timelineObject.ContentObject.finderFeed:
html += f' <div style="width:10rem; overflow:hidden">\n'

View File

@ -27,6 +27,23 @@ class ImageExporter:
file.write(response.content)
return f'{img_type}s/{file_name}.jpg'
@staticmethod
def get_image_thumb_and_url(media_item) -> Tuple[str, str]:
""" 获取图片的缩略图与大图的链接
"""
thumb = None
url = None
# 普通图片
if media_item.type == "2":
thumb = media_item.thumb.text
url = media_item.url.text
# 微信音乐
if media_item.type == "5":
thumb = media_item.thumb.text
url = media_item.thumb.text
return thumb, url
def get_images(self, msg: MomentMsg, download_pic: int) -> list[Tuple]:
""" 获取一条朋友圈的全部图像, 返回值是一个元组列表
[(缩略图路径原图路径)(缩略图路径原图路径)]
@ -37,13 +54,14 @@ class ImageExporter:
media = msg.timelineObject.ContentObject.mediaList.media
for media_item in media:
if media_item.type == "2":
thumb, url = self.get_image_thumb_and_url(media_item)
if thumb and url:
if download_pic:
thumb_path = self.save_image(media_item.thumb.text, 'thumb')
image_path = self.save_image(media_item.url.text, 'image')
thumb_path = self.save_image(thumb, 'thumb')
image_path = self.save_image(url, 'image')
else:
thumb_path = media_item.thumb.text
image_path = media_item.url.text
thumb_path = thumb
image_path = url
if thumb_path and image_path:
results.append((thumb_path, image_path))

View File

@ -60,6 +60,15 @@ padding-top:0.2rem;
.out_link {background-color:#F7F7F7 ;font-size:0.7rem ;width:95% ;color:#41454D ;overflow: hidden; cursor:pointer;}
.out_link img{width:2.5rem ;height:2.5rem ;margin:0.5rem 0.5rem ;float: left;}
.music_link {background-color:#F7F7F7 ;font-size:0.7rem ;width:95% ;color:#41454D ;overflow: hidden; cursor:pointer; display: flex; flex-direction:column}
.music_des {width:100%;display: flex;}
.music_title_musician {width:100%;margin-left: 1.5rem;display: flex;flex-direction:column}
.music_title {font-size:1.0rem;margin-top: 0.5rem;}
.music_musician {font-size:0.85rem;margin-top: 0.5rem;}
.music_link img{width:4rem ;height:4rem ;margin:0.2rem 0.2rem ;float: left;}
.music_audio {height: 1.5rem; width: 95%;}
.text{float: left;margin-top: 1.1rem;width:80% ;}
.pl{margin-top:0.5rem ;font-size:0.6rem ;color:#80858c ;clear: both;}
.pl span{display:inline-block ;width:2rem ;}