1
1
import asyncio
2
2
from datetime import date
3
- from os .path import relpath
4
- from typing import Union , Optional
3
+ from typing import Union
5
4
6
5
from pyrogram import Client
7
6
from pyrogram .types import Message as PyroMessage
8
7
from pyrogram .utils import zero_datetime
9
8
10
- from texport .export_config import ExportConfig
11
- from texport .media import MEDIA_TYPES
12
- from texport .messages_saver import MessagesSaver
13
- from texport .progress_print import ProgressPrint
14
-
15
-
16
- class ExportStatus :
17
- def __init__ (self ):
18
- self .approx_messages_count = None
19
- self .last_message_id = None
20
- self .last_date = None
9
+ from .export_config import ExportConfig
10
+ from .media import MEDIA_TYPES
11
+ from .media_downloader import MediaExporter
12
+ from .messages_preloader import Preloader
13
+ from .messages_saver import MessagesSaver
14
+ from .progress_print import ProgressPrint
21
15
22
16
23
17
class Exporter :
24
18
def __init__ (self , client : Client , export_config : ExportConfig = None ):
25
19
self ._config = export_config or ExportConfig ()
26
20
self ._client = client
27
21
self ._task = None
28
- self .status : Optional [ExportStatus ] = None
29
- self ._progress : ProgressPrint = ProgressPrint (disabled = not self ._config .print )
22
+ self .progress : ProgressPrint = ProgressPrint (disabled = not self ._config .print )
30
23
self ._messages : list [PyroMessage ] = []
31
24
self ._media : dict [Union [int , str ], str ] = {}
32
25
self ._saver = MessagesSaver (self ._messages , self ._media , export_config )
26
+ self ._media_downloader = MediaExporter (client , export_config , self ._media , self .progress )
33
27
self ._excluded_media = self ._config .excluded_media ()
34
28
35
29
async def _export_media (self , message : PyroMessage ) -> None :
@@ -40,57 +34,59 @@ async def _export_media(self, message: PyroMessage) -> None:
40
34
if media .file_size > self ._config .size_limit * 1024 * 1024 :
41
35
return
42
36
43
- path = await message .download (file_name = f"{ self ._config .output_dir .absolute ()} /{ m .dir_name } /" )
44
- path = relpath (path , self ._config .output_dir .absolute ())
45
- self ._media [message .id ] = path
37
+ self ._media_downloader .add (media .file_id , f"{ self ._config .output_dir .absolute ()} /{ m .dir_name } /" , message .id )
46
38
47
39
if hasattr (media , "thumbs" ) and media .thumbs :
48
- path = await self ._client .download_media (media .thumbs [0 ].file_id ,
49
- file_name = f"{ self ._config .output_dir .absolute ()} /thumbs/" )
50
- path = relpath (path , self ._config .output_dir .absolute ())
51
- self ._media [f"{ message .id } _thumb" ] = path
40
+ self ._media_downloader .add (media .thumbs [0 ].file_id , f"{ self ._config .output_dir .absolute ()} /thumbs/" ,
41
+ f"{ message .id } _thumb" )
42
+
43
+ async def _write (self , wait_media : list [int ]) -> None :
44
+ self .progress .status = "Waiting for all media to be downloaded..."
45
+ await self ._media_downloader .wait (wait_media )
46
+ self .progress .status = "Writing messages to file..."
47
+ await self ._saver .save ()
52
48
53
49
async def _export (self , chat_id : Union [int , str ]):
50
+ await self ._media_downloader .run ()
51
+
54
52
offset_date = zero_datetime () if self ._config .to_date .date () >= date .today () else self ._config .to_date
55
53
loaded = 0
56
- self ._progress .approx_messages_count = await self ._client .get_chat_history_count (chat_id )
57
- async for message in self ._client .get_chat_history (chat_id , offset_date = offset_date ):
54
+ medias = []
55
+ self .progress .approx_messages_count = await self ._client .get_chat_history_count (chat_id )
56
+ messages_iter = Preloader (self ._client , self .progress , self ._export_media ) \
57
+ if self ._config .preload else self ._client .get_chat_history
58
+ async for message in messages_iter (chat_id , offset_date = offset_date ):
58
59
if message .date < self ._config .from_date :
59
60
break
60
61
61
62
loaded += 1
62
- with self ._progress .update ():
63
- self ._progress .status = "Exporting messages..."
64
- self ._progress .messages_exported = loaded
65
-
66
- if self .status .approx_messages_count is None :
67
- self .status .approx_messages_count = message .id
68
- self .status .last_message_id = message .id
69
- self .status .last_date = message .date
63
+ with self .progress .update ():
64
+ self .progress .status = "Exporting messages..."
65
+ self .progress .messages_exported = loaded
70
66
71
67
if message .media :
72
- self ._progress .status = "Downloading media..."
68
+ medias .append (message .id )
69
+ medias .append (f"{ message .id } _thumb" )
73
70
await self ._export_media (message )
74
71
75
72
if not message .text and not message .caption and message .id not in self ._media :
76
73
continue
77
74
78
75
self ._messages .append (message )
79
- if len (self ._messages ) > 5000 :
80
- self ._progress .status = "Writing messages to file..."
81
- await self ._saver .save ()
76
+ if len (self ._messages ) > 1000 :
77
+ await self ._write (medias )
82
78
83
79
if self ._messages :
84
- self ._progress .status = "Writing messages to file..."
85
- await self ._saver .save ()
86
- self .status = self ._task = None
80
+ await self ._write (medias )
81
+ self ._task = None
87
82
88
- self ._progress .status = "Done!"
83
+ self .progress .status = "Stopping media downloader..."
84
+ await self ._media_downloader .stop ()
85
+ self .progress .status = "Done!"
89
86
90
87
async def export (self , block : bool = True ) -> None :
91
- if self ._task is not None or self . status is not None :
88
+ if self ._task is not None :
92
89
return
93
- self .status = ExportStatus ()
94
90
coro = self ._export (self ._config .chat_id )
95
91
if block :
96
92
await coro
0 commit comments