108 lines
4.6 KiB
Python
108 lines
4.6 KiB
Python
import asyncio
|
|
|
|
from telethon import errors
|
|
from telethon.tl import types
|
|
|
|
from conftest import RecordingNotifier
|
|
from errors import PermanentError, TransientError
|
|
from progress import ProgressReporter, TransferProgress, format_bytes, format_duration
|
|
from telegram_client import classify_media, map_telegram_error, parse_channel_reference, to_source_message
|
|
|
|
|
|
# -- progress ------------------------------------------------------------------------------
|
|
|
|
|
|
def test_formatting():
|
|
assert format_bytes(512) == "512 B"
|
|
assert format_bytes(1536) == "1.5 KB"
|
|
assert format_bytes(5 * 1024**3) == "5.0 GB"
|
|
assert format_duration(42) == "42s"
|
|
assert format_duration(125) == "2m 5s"
|
|
assert format_duration(3 * 3600 + 120) == "3h 2m"
|
|
|
|
|
|
def test_speed_and_eta():
|
|
now = [0.0]
|
|
p = TransferProgress(total=100 * 1024 * 1024, clock=lambda: now[0])
|
|
p.update(0)
|
|
now[0] = 10.0
|
|
p.update(50 * 1024 * 1024)
|
|
assert round(p.speed) == 5 * 1024 * 1024
|
|
assert round(p.eta) == 10
|
|
assert p.percent == 50
|
|
text = p.describe()
|
|
assert "50%" in text and "MB/s" in text and "ETA 10s" in text
|
|
|
|
|
|
def test_reporter_edits_single_message():
|
|
notifier = RecordingNotifier()
|
|
reporter = ProgressReporter(notifier, [1, 2], interval=60)
|
|
|
|
async def go():
|
|
reporter.board.begin_item(12, 150, "Misc• Grammar Practice", "Class 01 Aman sir.mp4")
|
|
reporter.board.start_download(1000)
|
|
reporter.board.download.update(640)
|
|
await reporter.refresh()
|
|
await reporter.refresh() # unchanged -> nothing sent
|
|
reporter.board.download.update(900)
|
|
await reporter.refresh()
|
|
|
|
asyncio.run(go())
|
|
assert len(notifier.sent) == 2 # one per chat
|
|
assert len(notifier.edits) == 2 # then edited
|
|
first = notifier.sent[0][1]
|
|
assert first.splitlines()[0] == "Processing video 12 of 150"
|
|
assert "Topic: Misc• Grammar Practice" in first and "Download: 64%" in first and "Upload: Waiting" in first
|
|
|
|
|
|
# -- telegram media classification ----------------------------------------------------------
|
|
|
|
|
|
def _doc(attributes, mime="video/mp4"):
|
|
return types.Document(id=77, access_hash=1, file_reference=b"", date=None, mime_type=mime, size=1234, dc_id=1,
|
|
attributes=attributes)
|
|
|
|
|
|
def _msg(media, text="Title: A.mp4"):
|
|
return types.Message(id=5, peer_id=types.PeerChannel(1), date=None, message=text, media=media)
|
|
|
|
|
|
def test_classify_video_message():
|
|
video = types.DocumentAttributeVideo(duration=60, w=1280, h=720)
|
|
info = classify_media(_msg(types.MessageMediaDocument(document=_doc([video]))), include_documents=False)
|
|
assert info.kind == "video" and info.size == 1234 and info.media_id == 77
|
|
sm = to_source_message(_msg(types.MessageMediaDocument(document=_doc([video]))), -100, False)
|
|
assert sm.caption == "Title: A.mp4" and sm.message_id == 5
|
|
|
|
|
|
def test_classify_document_video_only_when_enabled():
|
|
doc = _doc([types.DocumentAttributeFilename("lecture.mkv")], mime="application/octet-stream")
|
|
message = _msg(types.MessageMediaDocument(document=doc))
|
|
assert classify_media(message, include_documents=False) is None
|
|
assert classify_media(message, include_documents=True).file_name == "lecture.mkv"
|
|
|
|
|
|
def test_unsupported_media_is_ignored():
|
|
gif = _doc([types.DocumentAttributeVideo(duration=1, w=1, h=1), types.DocumentAttributeAnimated()])
|
|
note = _doc([types.DocumentAttributeVideo(duration=1, w=1, h=1, round_message=True)])
|
|
pdf = _doc([types.DocumentAttributeFilename("notes.pdf")], mime="application/pdf")
|
|
for doc in (gif, note, pdf):
|
|
assert classify_media(_msg(types.MessageMediaDocument(document=doc)), include_documents=True) is None
|
|
photo = types.MessageMediaPhoto(photo=types.PhotoEmpty(id=1))
|
|
assert classify_media(_msg(photo), include_documents=True) is None
|
|
assert classify_media(_msg(None, text="text only"), include_documents=True) is None
|
|
|
|
|
|
def test_channel_reference_parsing():
|
|
assert parse_channel_reference("-1001234567890") == -1001234567890
|
|
assert parse_channel_reference("@my_channel") == "my_channel"
|
|
assert parse_channel_reference("https://t.me/my_channel") == "my_channel"
|
|
assert parse_channel_reference("https://t.me/c/1234567890/55") == -1001234567890
|
|
|
|
|
|
def test_telegram_error_mapping():
|
|
flood = map_telegram_error(errors.FloodWaitError(request=None, capture=42))
|
|
assert isinstance(flood, TransientError) and flood.retry_after == 42 and flood.rate_limited
|
|
assert isinstance(map_telegram_error(errors.ChannelPrivateError(request=None)), PermanentError)
|
|
assert isinstance(map_telegram_error(ConnectionError("x")), TransientError)
|