sticker-convert 2.8.3__py3-none-any.whl → 2.8.5__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- sticker_convert/cli.py +1 -0
- sticker_convert/converter.py +1 -1
- sticker_convert/downloaders/download_base.py +47 -10
- sticker_convert/downloaders/download_signal.py +7 -7
- sticker_convert/downloaders/download_viber.py +95 -0
- sticker_convert/job.py +4 -0
- sticker_convert/resources/compression.json +47 -0
- sticker_convert/resources/input.json +10 -0
- sticker_convert/uploaders/upload_signal.py +10 -10
- sticker_convert/uploaders/upload_telegram.py +91 -65
- sticker_convert/utils/auth/get_line_auth.py +15 -21
- sticker_convert/version.py +1 -1
- {sticker_convert-2.8.3.dist-info → sticker_convert-2.8.5.dist-info}/METADATA +12 -8
- {sticker_convert-2.8.3.dist-info → sticker_convert-2.8.5.dist-info}/RECORD +18 -17
- {sticker_convert-2.8.3.dist-info → sticker_convert-2.8.5.dist-info}/LICENSE +0 -0
- {sticker_convert-2.8.3.dist-info → sticker_convert-2.8.5.dist-info}/WHEEL +0 -0
- {sticker_convert-2.8.3.dist-info → sticker_convert-2.8.5.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.8.3.dist-info → sticker_convert-2.8.5.dist-info}/top_level.txt +0 -0
sticker_convert/cli.py
CHANGED
sticker_convert/converter.py
CHANGED
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any, List, Optional, Tuple
|
6
6
|
|
7
|
+
import anyio
|
7
8
|
import requests
|
8
9
|
|
9
10
|
from sticker_convert.job_option import CredOption
|
@@ -27,16 +28,50 @@ class DownloadBase:
|
|
27
28
|
|
28
29
|
def download_multiple_files(
|
29
30
|
self, targets: List[Tuple[str, Path]], retries: int = 3, **kwargs: Any
|
31
|
+
) -> None:
|
32
|
+
anyio.run(self.download_multiple_files_async, targets, retries, **kwargs)
|
33
|
+
|
34
|
+
async def download_multiple_files_async(
|
35
|
+
self, targets: List[Tuple[str, Path]], retries: int = 3, **kwargs: Any
|
30
36
|
) -> None:
|
31
37
|
# targets format: [(url1, dest2), (url2, dest2), ...]
|
32
38
|
self.cb.put(
|
33
39
|
("bar", None, {"set_progress_mode": "determinate", "steps": len(targets)})
|
34
40
|
)
|
35
41
|
|
36
|
-
|
37
|
-
|
42
|
+
async with anyio.create_task_group() as tg:
|
43
|
+
for url, dest in targets:
|
44
|
+
tg.start_soon(self.download_file_async, url, dest, retries, **kwargs)
|
45
|
+
|
46
|
+
async def download_file_async(
|
47
|
+
self,
|
48
|
+
url: str,
|
49
|
+
dest: Path,
|
50
|
+
retries: int = 3,
|
51
|
+
**kwargs: Any,
|
52
|
+
) -> None:
|
53
|
+
for retry in range(retries):
|
54
|
+
try:
|
55
|
+
response = requests.get(url, allow_redirects=True, **kwargs)
|
56
|
+
|
57
|
+
if not response.ok:
|
58
|
+
self.cb.put("update_bar")
|
59
|
+
raise requests.exceptions.RequestException(
|
60
|
+
f"Error {response.status_code}"
|
61
|
+
)
|
62
|
+
|
63
|
+
self.cb.put(f"Downloading {url}")
|
64
|
+
with open(dest, "wb+") as f:
|
65
|
+
f.write(response.content)
|
66
|
+
self.cb.put(f"Downloaded {url}")
|
67
|
+
break
|
68
|
+
|
69
|
+
except requests.exceptions.RequestException as e:
|
70
|
+
self.cb.put(
|
71
|
+
f"Cannot download {url} (tried {retry+1}/{retries} times): {e}"
|
72
|
+
)
|
38
73
|
|
39
|
-
|
74
|
+
self.cb.put("update_bar")
|
40
75
|
|
41
76
|
def download_file(
|
42
77
|
self,
|
@@ -51,10 +86,12 @@ class DownloadBase:
|
|
51
86
|
|
52
87
|
for retry in range(retries):
|
53
88
|
try:
|
54
|
-
response = requests.get(
|
89
|
+
response = requests.get(
|
90
|
+
url, stream=True, allow_redirects=True, **kwargs
|
91
|
+
)
|
55
92
|
total_length = int(response.headers.get("content-length")) # type: ignore
|
56
93
|
|
57
|
-
if response.
|
94
|
+
if not response.ok:
|
58
95
|
return b""
|
59
96
|
self.cb.put(f"Downloading {url}")
|
60
97
|
|
@@ -75,16 +112,16 @@ class DownloadBase:
|
|
75
112
|
self.cb.put("update_bar")
|
76
113
|
|
77
114
|
break
|
78
|
-
except requests.exceptions.RequestException:
|
79
|
-
|
80
|
-
|
115
|
+
except requests.exceptions.RequestException as e:
|
116
|
+
self.cb.put(
|
117
|
+
f"Cannot download {url} (tried {retry+1}/{retries} times): {e}"
|
118
|
+
)
|
81
119
|
|
82
120
|
if not result:
|
83
121
|
return b""
|
84
122
|
if dest:
|
85
123
|
with open(dest, "wb+") as f:
|
86
124
|
f.write(result)
|
87
|
-
|
88
|
-
self.cb.put(msg)
|
125
|
+
self.cb.put(f"Downloaded {url}")
|
89
126
|
return b""
|
90
127
|
return result
|
@@ -3,9 +3,9 @@ from pathlib import Path
|
|
3
3
|
from typing import Dict, Optional
|
4
4
|
|
5
5
|
import anyio
|
6
|
-
from signalstickers_client import
|
7
|
-
from signalstickers_client.
|
8
|
-
from signalstickers_client.
|
6
|
+
from signalstickers_client.errors import SignalException
|
7
|
+
from signalstickers_client.models import StickerPack
|
8
|
+
from signalstickers_client.stickersclient import StickersClient
|
9
9
|
|
10
10
|
from sticker_convert.downloaders.download_base import DownloadBase
|
11
11
|
from sticker_convert.job_option import CredOption
|
@@ -21,7 +21,7 @@ class DownloadSignal(DownloadBase):
|
|
21
21
|
@staticmethod
|
22
22
|
async def get_pack(pack_id: str, pack_key: str) -> StickerPack:
|
23
23
|
async with StickersClient() as client:
|
24
|
-
pack = await client.get_pack(pack_id, pack_key)
|
24
|
+
pack = await client.get_pack(pack_id, pack_key)
|
25
25
|
|
26
26
|
return pack
|
27
27
|
|
@@ -32,14 +32,14 @@ class DownloadSignal(DownloadBase):
|
|
32
32
|
None,
|
33
33
|
{
|
34
34
|
"set_progress_mode": "determinate",
|
35
|
-
"steps": len(pack.stickers),
|
35
|
+
"steps": len(pack.stickers),
|
36
36
|
},
|
37
37
|
)
|
38
38
|
)
|
39
39
|
|
40
40
|
emoji_dict: Dict[str, str] = {}
|
41
|
-
for sticker in pack.stickers:
|
42
|
-
f_id = str(sticker.id).zfill(3)
|
41
|
+
for sticker in pack.stickers:
|
42
|
+
f_id = str(sticker.id).zfill(3)
|
43
43
|
f_path = Path(self.out_dir, f_id)
|
44
44
|
with open(f_path, "wb") as f:
|
45
45
|
f.write(sticker.image_data) # type: ignore
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
import json
|
3
|
+
import zipfile
|
4
|
+
from io import BytesIO
|
5
|
+
from pathlib import Path
|
6
|
+
from typing import Optional, Tuple, cast
|
7
|
+
from urllib.parse import urlparse
|
8
|
+
|
9
|
+
import requests
|
10
|
+
from bs4 import BeautifulSoup
|
11
|
+
|
12
|
+
from sticker_convert.downloaders.download_base import DownloadBase
|
13
|
+
from sticker_convert.job_option import CredOption
|
14
|
+
from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
|
15
|
+
from sticker_convert.utils.files.metadata_handler import MetadataHandler
|
16
|
+
|
17
|
+
|
18
|
+
class DownloadViber(DownloadBase):
|
19
|
+
# def __init__(self, *args: Any, **kwargs: Any) -> None:
|
20
|
+
# super().__init__(*args, **kwargs)
|
21
|
+
|
22
|
+
def get_pack_info(self, url: str) -> Optional[Tuple[str, str]]:
|
23
|
+
r = requests.get(url, allow_redirects=True)
|
24
|
+
soup = BeautifulSoup(r.text, "html.parser")
|
25
|
+
|
26
|
+
is_custom = urlparse(url).path.startswith("/pages/custom-sticker-packs/")
|
27
|
+
if is_custom:
|
28
|
+
tag_text_search = "window.CUSTOM_STICKER_PACK"
|
29
|
+
else:
|
30
|
+
tag_text_search = "window.PRODUCT"
|
31
|
+
|
32
|
+
script_tag = soup.find(
|
33
|
+
lambda tag: tag.name == "script" and tag.text.startswith(tag_text_search)
|
34
|
+
)
|
35
|
+
if script_tag is None:
|
36
|
+
return None
|
37
|
+
|
38
|
+
pack_json = script_tag.text.replace(f"{tag_text_search} = ", "", 1)[:-1]
|
39
|
+
pack_dict = json.loads(pack_json)
|
40
|
+
|
41
|
+
title = pack_dict["title"]
|
42
|
+
first_sticker_url = cast(str, pack_dict["stickerFirstItemUrl"])
|
43
|
+
zip_url = "/".join(first_sticker_url.split("/")[:-1]) + ".zip"
|
44
|
+
|
45
|
+
return title, zip_url
|
46
|
+
|
47
|
+
def decompress(self, zip_file: bytes) -> None:
|
48
|
+
with zipfile.ZipFile(BytesIO(zip_file)) as zf:
|
49
|
+
self.cb.put("Unzipping...")
|
50
|
+
|
51
|
+
zf_files = zf.namelist()
|
52
|
+
self.cb.put(
|
53
|
+
(
|
54
|
+
"bar",
|
55
|
+
None,
|
56
|
+
{"set_progress_mode": "determinate", "steps": len(zf_files)},
|
57
|
+
)
|
58
|
+
)
|
59
|
+
|
60
|
+
for sticker in zf_files:
|
61
|
+
num = sticker.split(".")[0][-2:].zfill(3)
|
62
|
+
data = zf.read(sticker)
|
63
|
+
ext = Path(sticker).suffix
|
64
|
+
self.cb.put(f"Read {sticker}")
|
65
|
+
|
66
|
+
out_path = Path(self.out_dir, num + ext)
|
67
|
+
with open(out_path, "wb") as f:
|
68
|
+
f.write(data)
|
69
|
+
|
70
|
+
self.cb.put("update_bar")
|
71
|
+
|
72
|
+
def download_stickers_viber(self) -> bool:
|
73
|
+
pack_info = self.get_pack_info(self.url)
|
74
|
+
if pack_info is None:
|
75
|
+
self.cb.put("Download failed: Cannot get pack info")
|
76
|
+
return False
|
77
|
+
title, zip_url = pack_info
|
78
|
+
|
79
|
+
zip_file = self.download_file(zip_url)
|
80
|
+
self.decompress(zip_file)
|
81
|
+
|
82
|
+
MetadataHandler.set_metadata(self.out_dir, title=title)
|
83
|
+
|
84
|
+
return True
|
85
|
+
|
86
|
+
@staticmethod
|
87
|
+
def start(
|
88
|
+
url: str,
|
89
|
+
out_dir: Path,
|
90
|
+
opt_cred: Optional[CredOption],
|
91
|
+
cb: CallbackProtocol,
|
92
|
+
cb_return: CallbackReturn,
|
93
|
+
) -> bool:
|
94
|
+
downloader = DownloadViber(url, out_dir, opt_cred, cb, cb_return)
|
95
|
+
return downloader.download_stickers_viber()
|
sticker_convert/job.py
CHANGED
@@ -16,6 +16,7 @@ from sticker_convert.downloaders.download_kakao import DownloadKakao
|
|
16
16
|
from sticker_convert.downloaders.download_line import DownloadLine
|
17
17
|
from sticker_convert.downloaders.download_signal import DownloadSignal
|
18
18
|
from sticker_convert.downloaders.download_telegram import DownloadTelegram
|
19
|
+
from sticker_convert.downloaders.download_viber import DownloadViber
|
19
20
|
from sticker_convert.job_option import CompOption, CredOption, InputOption, OutputOption
|
20
21
|
from sticker_convert.uploaders.compress_wastickers import CompressWastickers
|
21
22
|
from sticker_convert.uploaders.upload_signal import UploadSignal
|
@@ -527,6 +528,9 @@ class Job:
|
|
527
528
|
if self.opt_input.option == "kakao":
|
528
529
|
downloaders.append(DownloadKakao.start)
|
529
530
|
|
531
|
+
if self.opt_input.option == "viber":
|
532
|
+
downloaders.append(DownloadViber.start)
|
533
|
+
|
530
534
|
if len(downloaders) > 0:
|
531
535
|
self.executor.cb("Downloading...")
|
532
536
|
else:
|
@@ -328,6 +328,53 @@
|
|
328
328
|
"quantize_method": "imagequant",
|
329
329
|
"default_emoji": "😀"
|
330
330
|
},
|
331
|
+
"viber": {
|
332
|
+
"size_max": {
|
333
|
+
"img": 0,
|
334
|
+
"vid": 0
|
335
|
+
},
|
336
|
+
"format": {
|
337
|
+
"img": ".png",
|
338
|
+
"vid": ".png"
|
339
|
+
},
|
340
|
+
"fps": {
|
341
|
+
"min": 1,
|
342
|
+
"max": 1,
|
343
|
+
"power": 1
|
344
|
+
},
|
345
|
+
"res": {
|
346
|
+
"w": {
|
347
|
+
"min": 490,
|
348
|
+
"max": 490
|
349
|
+
},
|
350
|
+
"h": {
|
351
|
+
"min": 490,
|
352
|
+
"max": 490
|
353
|
+
},
|
354
|
+
"power": 1
|
355
|
+
},
|
356
|
+
"quality": {
|
357
|
+
"min": 95,
|
358
|
+
"max": 95,
|
359
|
+
"power": 1
|
360
|
+
},
|
361
|
+
"color": {
|
362
|
+
"min": 257,
|
363
|
+
"max": 257,
|
364
|
+
"power": 1
|
365
|
+
},
|
366
|
+
"duration": {
|
367
|
+
"min": 0,
|
368
|
+
"max": 0
|
369
|
+
},
|
370
|
+
"padding_percent": 0,
|
371
|
+
"bg_color": "",
|
372
|
+
"steps": 1,
|
373
|
+
"fake_vid": false,
|
374
|
+
"scale_filter": "bicubic",
|
375
|
+
"quantize_method": "imagequant",
|
376
|
+
"default_emoji": "😀"
|
377
|
+
},
|
331
378
|
"imessage_small": {
|
332
379
|
"size_max": {
|
333
380
|
"img": 500000,
|
@@ -49,6 +49,16 @@
|
|
49
49
|
"author": true
|
50
50
|
}
|
51
51
|
},
|
52
|
+
"viber": {
|
53
|
+
"full_name": "Download from Viber",
|
54
|
+
"help": "Download viber stickers from a URL as input",
|
55
|
+
"example": "Example: https://stickers.viber.com/pages/example OR https://stickers.viber.com/pages/custom-sticker-packs/example",
|
56
|
+
"address_lbls": "URL address / ID",
|
57
|
+
"metadata_provides": {
|
58
|
+
"title": true,
|
59
|
+
"author": false
|
60
|
+
}
|
61
|
+
},
|
52
62
|
"local": {
|
53
63
|
"full_name": "From local directory",
|
54
64
|
"help": "Load files from local directory on computer",
|
@@ -4,9 +4,9 @@ from pathlib import Path
|
|
4
4
|
from typing import Any, Dict, List
|
5
5
|
|
6
6
|
import anyio
|
7
|
-
from signalstickers_client import
|
8
|
-
from signalstickers_client.
|
9
|
-
from signalstickers_client.
|
7
|
+
from signalstickers_client.errors import SignalException
|
8
|
+
from signalstickers_client.models import LocalStickerPack, Sticker
|
9
|
+
from signalstickers_client.stickersclient import StickersClient
|
10
10
|
|
11
11
|
from sticker_convert.converter import StickerConvert
|
12
12
|
from sticker_convert.job_option import CompOption, CredOption, OutputOption
|
@@ -39,7 +39,7 @@ class UploadSignal(UploadBase):
|
|
39
39
|
@staticmethod
|
40
40
|
async def upload_pack(pack: LocalStickerPack, uuid: str, password: str) -> str:
|
41
41
|
async with StickersClient(uuid, password) as client:
|
42
|
-
pack_id, pack_key = await client.upload_pack(pack)
|
42
|
+
pack_id, pack_key = await client.upload_pack(pack)
|
43
43
|
|
44
44
|
result = (
|
45
45
|
f"https://signal.art/addstickers/#pack_id={pack_id}&pack_key={pack_key}"
|
@@ -53,7 +53,7 @@ class UploadSignal(UploadBase):
|
|
53
53
|
self.cb.put(f"Verifying {src} for uploading to signal")
|
54
54
|
|
55
55
|
sticker = Sticker()
|
56
|
-
sticker.id = pack.nb_stickers
|
56
|
+
sticker.id = pack.nb_stickers
|
57
57
|
|
58
58
|
emoji = emoji_dict.get(Path(src).stem, None)
|
59
59
|
if not emoji:
|
@@ -61,7 +61,7 @@ class UploadSignal(UploadBase):
|
|
61
61
|
f"Warning: Cannot find emoji for file {Path(src).name}, skip uploading this file..."
|
62
62
|
)
|
63
63
|
continue
|
64
|
-
sticker.emoji = emoji[:1]
|
64
|
+
sticker.emoji = emoji[:1]
|
65
65
|
|
66
66
|
if Path(src).suffix == ".webp":
|
67
67
|
spec_choice = self.webp_spec
|
@@ -84,10 +84,10 @@ class UploadSignal(UploadBase):
|
|
84
84
|
|
85
85
|
assert isinstance(image_data, bytes)
|
86
86
|
|
87
|
-
sticker.image_data = image_data
|
87
|
+
sticker.image_data = image_data
|
88
88
|
else:
|
89
89
|
with open(src, "rb") as f:
|
90
|
-
sticker.image_data = f.read()
|
90
|
+
sticker.image_data = f.read()
|
91
91
|
|
92
92
|
pack._addsticker(sticker) # type: ignore
|
93
93
|
|
@@ -140,8 +140,8 @@ class UploadSignal(UploadBase):
|
|
140
140
|
)
|
141
141
|
for pack_title, stickers in packs.items():
|
142
142
|
pack = LocalStickerPack()
|
143
|
-
pack.title = pack_title
|
144
|
-
pack.author = author
|
143
|
+
pack.title = pack_title
|
144
|
+
pack.author = author
|
145
145
|
|
146
146
|
self.add_stickers_to_pack(pack, stickers, emoji_dict)
|
147
147
|
self.cb.put(f"Uploading pack {pack_title}")
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import copy
|
3
3
|
import re
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import Any, Dict, List, Optional,
|
5
|
+
from typing import Any, Dict, List, Optional, Union, cast
|
6
6
|
|
7
7
|
import anyio
|
8
8
|
from telegram import InputSticker, Sticker
|
@@ -96,7 +96,7 @@ class UploadTelegram(UploadBase):
|
|
96
96
|
"[^0-9a-zA-Z]+", "_", pack_short_name
|
97
97
|
) # name used in url, only alphanum and underscore only
|
98
98
|
|
99
|
-
sticker_set = None
|
99
|
+
sticker_set: Any = None
|
100
100
|
try:
|
101
101
|
sticker_set = await bot.get_sticker_set(
|
102
102
|
pack_short_name,
|
@@ -152,11 +152,10 @@ class UploadTelegram(UploadBase):
|
|
152
152
|
else:
|
153
153
|
sticker_type = Sticker.REGULAR
|
154
154
|
|
155
|
-
|
155
|
+
init_input_stickers: List[InputSticker] = []
|
156
156
|
sticker_format = None
|
157
|
-
|
158
|
-
|
159
|
-
for src in stickers:
|
157
|
+
sticker_format_prev = None
|
158
|
+
for count, src in enumerate(stickers):
|
160
159
|
self.cb.put(f"Verifying {src} for uploading to telegram")
|
161
160
|
|
162
161
|
emoji = emoji_dict.get(Path(src).stem, None)
|
@@ -175,16 +174,13 @@ class UploadTelegram(UploadBase):
|
|
175
174
|
ext = Path(src).suffix
|
176
175
|
if ext == ".tgs":
|
177
176
|
spec_choice = self.tgs_spec
|
178
|
-
cover_spec_choice = self.tgs_cover_spec
|
179
177
|
sticker_format = "animated"
|
180
178
|
elif ext == ".webm":
|
181
179
|
spec_choice = self.webm_spec
|
182
|
-
cover_spec_choice = self.webm_cover_spec
|
183
180
|
sticker_format = "video"
|
184
181
|
else:
|
185
182
|
ext = ".png"
|
186
183
|
spec_choice = self.png_spec
|
187
|
-
cover_spec_choice = self.png_cover_spec
|
188
184
|
sticker_format = "static"
|
189
185
|
|
190
186
|
if self.opt_output.option == "telegram_emoji":
|
@@ -203,81 +199,98 @@ class UploadTelegram(UploadBase):
|
|
203
199
|
)
|
204
200
|
sticker_bytes = cast(bytes, convert_result)
|
205
201
|
|
206
|
-
|
207
|
-
|
202
|
+
input_sticker = InputSticker(
|
203
|
+
sticker=sticker_bytes,
|
204
|
+
emoji_list=emoji_list,
|
205
|
+
format=sticker_format,
|
208
206
|
)
|
209
207
|
|
208
|
+
if sticker_set is None:
|
209
|
+
if count < 50 and (
|
210
|
+
sticker_format_prev is None
|
211
|
+
or sticker_format_prev == sticker_format
|
212
|
+
):
|
213
|
+
init_input_stickers.append(input_sticker)
|
214
|
+
else:
|
215
|
+
start_msg = f"Creating pack and bulk uploading {count} stickers with same format of {pack_short_name}"
|
216
|
+
finish_msg = f"Created pack and bulk uploaded {count} stickers with same format of {pack_short_name}"
|
217
|
+
error_msg = f"Cannot create pack and bulk upload {count} stickers with same format of {pack_short_name} due to"
|
218
|
+
self.cb.put(start_msg)
|
219
|
+
try:
|
220
|
+
await bot.create_new_sticker_set(
|
221
|
+
user_id=self.telegram_userid,
|
222
|
+
name=pack_short_name,
|
223
|
+
title=pack_title,
|
224
|
+
stickers=init_input_stickers,
|
225
|
+
sticker_type=sticker_type,
|
226
|
+
)
|
227
|
+
sticker_set = True
|
228
|
+
self.cb.put(finish_msg)
|
229
|
+
except TelegramError as e:
|
230
|
+
self.cb.put(f"{error_msg} {e}")
|
231
|
+
return None
|
232
|
+
else:
|
233
|
+
try:
|
234
|
+
# We could use tg.start_soon() here
|
235
|
+
# But this would disrupt the order of stickers
|
236
|
+
await bot.add_sticker_to_set(
|
237
|
+
user_id=self.telegram_userid,
|
238
|
+
name=pack_short_name,
|
239
|
+
sticker=input_sticker,
|
240
|
+
)
|
241
|
+
self.cb.put(f"Uploaded sticker {src} of {pack_short_name}")
|
242
|
+
except BadRequest as e:
|
243
|
+
self.cb.put(
|
244
|
+
f"Cannot upload sticker {src} of {pack_short_name} due to {e}"
|
245
|
+
)
|
246
|
+
if str(e) == "Stickerpack_not_found":
|
247
|
+
self.cb.put(
|
248
|
+
"Hint: You might had deleted and recreated pack too quickly. Wait about 3 minutes and try again."
|
249
|
+
)
|
250
|
+
except TelegramError as e:
|
251
|
+
self.cb.put(
|
252
|
+
f"Cannot upload sticker {src} of {pack_short_name} due to {e}"
|
253
|
+
)
|
254
|
+
|
255
|
+
sticker_format_prev = sticker_format
|
256
|
+
|
210
257
|
cover_path = MetadataHandler.get_cover(self.opt_output.dir)
|
211
|
-
|
212
|
-
|
258
|
+
if cover_path:
|
259
|
+
thumbnail_bytes: Union[None, bytes, Path] = None
|
260
|
+
cover_ext = Path(cover_path).suffix
|
261
|
+
|
262
|
+
if cover_ext == ".tgs":
|
263
|
+
thumbnail_format = "animated"
|
264
|
+
cover_spec_choice = self.tgs_cover_spec
|
265
|
+
elif cover_ext == ".webm":
|
266
|
+
thumbnail_format = "video"
|
267
|
+
cover_spec_choice = self.webm_cover_spec
|
268
|
+
else:
|
269
|
+
cover_ext = ".png"
|
270
|
+
thumbnail_format = "static"
|
271
|
+
cover_spec_choice = self.png_cover_spec
|
272
|
+
|
213
273
|
if FormatVerify.check_file(cover_path, spec=cover_spec_choice):
|
214
274
|
with open(cover_path, "rb") as f:
|
215
275
|
thumbnail_bytes = f.read()
|
216
276
|
else:
|
217
277
|
_, _, thumbnail_bytes, _ = StickerConvert.convert(
|
218
278
|
cover_path,
|
219
|
-
Path(f"bytes{
|
279
|
+
Path(f"bytes{cover_ext}"),
|
220
280
|
self.opt_comp_cover_merged,
|
221
281
|
self.cb,
|
222
282
|
self.cb_return,
|
223
283
|
)
|
224
284
|
|
225
|
-
if sticker_set is None and sticker_format is not None:
|
226
|
-
if len(input_stickers) > 50:
|
227
|
-
amount_str = "first 50"
|
228
|
-
else:
|
229
|
-
amount_str = "all"
|
230
|
-
start_msg = f"Creating pack and bulk uploading {amount_str} stickers of {pack_short_name}"
|
231
|
-
finish_msg = f"Created pack and bulk uploaded {amount_str} stickers of {pack_short_name}"
|
232
|
-
error_msg = f"Cannot create pack and bulk upload {amount_str} stickers of {pack_short_name} due to"
|
233
|
-
self.cb.put(start_msg)
|
234
|
-
try:
|
235
|
-
await bot.create_new_sticker_set(
|
236
|
-
user_id=self.opt_cred.telegram_userid,
|
237
|
-
name=pack_short_name,
|
238
|
-
title=pack_title,
|
239
|
-
stickers=[a for _, a in input_stickers[:50]],
|
240
|
-
sticker_format=sticker_format,
|
241
|
-
sticker_type=sticker_type,
|
242
|
-
)
|
243
|
-
self.cb.put(finish_msg)
|
244
|
-
input_stickers = input_stickers[50:]
|
245
|
-
except TelegramError as e:
|
246
|
-
self.cb.put(f"{error_msg} {e}")
|
247
|
-
return None
|
248
|
-
|
249
|
-
for src, sticker in input_stickers:
|
250
|
-
try:
|
251
|
-
# We could use tg.start_soon() here
|
252
|
-
# But this would disrupt the order of stickers
|
253
|
-
await bot.add_sticker_to_set(
|
254
|
-
user_id=self.opt_cred.telegram_userid,
|
255
|
-
name=pack_short_name,
|
256
|
-
sticker=sticker,
|
257
|
-
)
|
258
|
-
self.cb.put(f"Uploaded sticker {src} of {pack_short_name}")
|
259
|
-
except BadRequest as e:
|
260
|
-
self.cb.put(
|
261
|
-
f"Cannot upload sticker {src} of {pack_short_name} due to {e}"
|
262
|
-
)
|
263
|
-
if str(e) == "Stickerpack_not_found":
|
264
|
-
self.cb.put(
|
265
|
-
"Hint: You might had deleted and recreated pack too quickly. Wait about 3 minutes and try again."
|
266
|
-
)
|
267
|
-
except TelegramError as e:
|
268
|
-
self.cb.put(
|
269
|
-
f"Cannot upload sticker {src} of {pack_short_name} due to {e}"
|
270
|
-
)
|
271
|
-
|
272
|
-
if thumbnail_bytes is not None:
|
273
285
|
try:
|
274
286
|
self.cb.put(
|
275
287
|
f"Uploading cover (thumbnail) of pack {pack_short_name}"
|
276
288
|
)
|
277
289
|
await bot.set_sticker_set_thumbnail(
|
278
290
|
name=pack_short_name,
|
279
|
-
user_id=self.
|
291
|
+
user_id=self.telegram_userid,
|
280
292
|
thumbnail=thumbnail_bytes,
|
293
|
+
format=thumbnail_format,
|
281
294
|
)
|
282
295
|
self.cb.put(f"Uploaded cover (thumbnail) of pack {pack_short_name}")
|
283
296
|
except TelegramError as e:
|
@@ -300,6 +313,12 @@ class UploadTelegram(UploadBase):
|
|
300
313
|
self.cb.put("Token and userid required for uploading to telegram")
|
301
314
|
return urls
|
302
315
|
|
316
|
+
if self.opt_cred.telegram_userid.isnumeric():
|
317
|
+
self.telegram_userid = int(self.opt_cred.telegram_userid)
|
318
|
+
else:
|
319
|
+
self.cb.put("Invalid userid, should contain numbers only")
|
320
|
+
return urls
|
321
|
+
|
303
322
|
title, _, emoji_dict = MetadataHandler.get_metadata(
|
304
323
|
self.opt_output.dir,
|
305
324
|
title=self.opt_output.title,
|
@@ -327,11 +346,18 @@ class UploadTelegram(UploadBase):
|
|
327
346
|
)
|
328
347
|
|
329
348
|
assert title is not None
|
349
|
+
assert emoji_dict is not None
|
350
|
+
|
351
|
+
if self.opt_output.option == "telegram_emoji":
|
352
|
+
file_per_pack = 200
|
353
|
+
else:
|
354
|
+
file_per_pack = 120
|
355
|
+
|
330
356
|
packs = MetadataHandler.split_sticker_packs(
|
331
357
|
self.opt_output.dir,
|
332
358
|
title=title,
|
333
|
-
file_per_anim_pack=
|
334
|
-
file_per_image_pack=
|
359
|
+
file_per_anim_pack=file_per_pack,
|
360
|
+
file_per_image_pack=file_per_pack,
|
335
361
|
separate_image_anim=not self.opt_comp.fake_vid,
|
336
362
|
)
|
337
363
|
|
@@ -5,41 +5,35 @@ from http.cookiejar import CookieJar
|
|
5
5
|
from typing import Any, Callable, Dict, List, Optional, Union
|
6
6
|
|
7
7
|
import requests
|
8
|
-
import rookiepy
|
8
|
+
import rookiepy
|
9
9
|
|
10
10
|
|
11
11
|
class GetLineAuth:
|
12
12
|
def get_cred(self) -> Optional[str]:
|
13
13
|
browsers: List[Callable[..., Any]] = [
|
14
|
-
rookiepy.load, #
|
15
|
-
rookiepy.firefox,
|
16
|
-
rookiepy.
|
17
|
-
rookiepy.chrome,
|
18
|
-
rookiepy.chromium,
|
19
|
-
rookiepy.brave,
|
20
|
-
rookiepy.edge,
|
21
|
-
rookiepy.opera,
|
22
|
-
rookiepy.vivaldi,
|
14
|
+
rookiepy.load, # Supposed to load from any browser, but may fail
|
15
|
+
rookiepy.firefox,
|
16
|
+
rookiepy.librewolf,
|
17
|
+
rookiepy.chrome,
|
18
|
+
rookiepy.chromium,
|
19
|
+
rookiepy.brave,
|
20
|
+
rookiepy.edge,
|
21
|
+
rookiepy.opera,
|
22
|
+
rookiepy.vivaldi,
|
23
23
|
]
|
24
24
|
|
25
|
-
# https://github.com/thewh1teagle/rookie/pull/24
|
26
|
-
if "libre_wolf" in rookiepy.__all__:
|
27
|
-
browsers.extend(rookiepy.libre_wolf) # type: ignore
|
28
|
-
else:
|
29
|
-
browsers.extend(rookiepy.librewolf) # type: ignore
|
30
|
-
|
31
25
|
if platform.system() == "Windows":
|
32
26
|
browsers.extend(
|
33
27
|
[
|
34
|
-
rookiepy.opera_gx,
|
35
|
-
rookiepy.internet_explorer,
|
28
|
+
rookiepy.opera_gx,
|
29
|
+
rookiepy.internet_explorer,
|
36
30
|
]
|
37
31
|
)
|
38
32
|
elif platform.system() == "Darwin":
|
39
33
|
browsers.extend(
|
40
34
|
[
|
41
|
-
rookiepy.opera_gx,
|
42
|
-
rookiepy.safari,
|
35
|
+
rookiepy.opera_gx,
|
36
|
+
rookiepy.safari,
|
43
37
|
]
|
44
38
|
)
|
45
39
|
|
@@ -48,7 +42,7 @@ class GetLineAuth:
|
|
48
42
|
for browser in browsers:
|
49
43
|
try:
|
50
44
|
cookies_dict = browser(["store.line.me"])
|
51
|
-
cookies_jar = rookiepy.to_cookiejar(cookies_dict)
|
45
|
+
cookies_jar = rookiepy.to_cookiejar(cookies_dict)
|
52
46
|
|
53
47
|
if GetLineAuth.validate_cookies(cookies_jar):
|
54
48
|
break
|
sticker_convert/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sticker-convert
|
3
|
-
Version: 2.8.
|
3
|
+
Version: 2.8.5
|
4
4
|
Summary: Convert (animated) stickers to/from WhatsApp, Telegram, Signal, Line, Kakao, iMessage. Written in Python.
|
5
5
|
Author-email: laggykiller <chaudominic2@gmail.com>
|
6
6
|
Maintainer-email: laggykiller <chaudominic2@gmail.com>
|
@@ -349,7 +349,7 @@ Project-URL: Source, https://github.com/laggykiller/sticker-convert
|
|
349
349
|
Project-URL: Documentation, https://github.com/laggykiller/sticker-convert
|
350
350
|
Project-URL: Tracker, https://github.com/laggykiller/sticker-convert/issues
|
351
351
|
Project-URL: Repository, https://github.com/laggykiller/sticker-convert
|
352
|
-
Keywords: telegram,line,tgs,whatsapp,kakao,signal,imessage,wastickers
|
352
|
+
Keywords: telegram,line,tgs,whatsapp,kakao,signal,imessage,wastickers,viber
|
353
353
|
Classifier: Development Status :: 5 - Production/Stable
|
354
354
|
Classifier: Intended Audience :: End Users/Desktop
|
355
355
|
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
|
@@ -365,21 +365,21 @@ Requires-Python: >=3.8
|
|
365
365
|
Description-Content-Type: text/markdown
|
366
366
|
License-File: LICENSE
|
367
367
|
Requires-Dist: aiolimiter ~=1.1.0
|
368
|
-
Requires-Dist: anyio ~=3.
|
368
|
+
Requires-Dist: anyio ~=4.3.0
|
369
369
|
Requires-Dist: apngasm-python ~=1.2.3
|
370
370
|
Requires-Dist: av ~=12.0.0
|
371
371
|
Requires-Dist: beautifulsoup4 ~=4.12.3
|
372
|
-
Requires-Dist: rookiepy ~=0.
|
372
|
+
Requires-Dist: rookiepy ~=0.4.0
|
373
373
|
Requires-Dist: imagequant ~=1.1.1
|
374
374
|
Requires-Dist: memory-tempfile ~=2.2.3
|
375
375
|
Requires-Dist: mergedeep ~=1.3.4
|
376
376
|
Requires-Dist: numpy >=1.22.4
|
377
|
-
Requires-Dist: Pillow
|
377
|
+
Requires-Dist: Pillow ~=10.3.0
|
378
378
|
Requires-Dist: pyoxipng ~=9.0.0
|
379
|
-
Requires-Dist: python-telegram-bot ~=
|
379
|
+
Requires-Dist: python-telegram-bot ~=21.1
|
380
380
|
Requires-Dist: requests ~=2.31.0
|
381
381
|
Requires-Dist: rlottie-python ~=1.3.4
|
382
|
-
Requires-Dist: signalstickers-client ~=3.3.0
|
382
|
+
Requires-Dist: signalstickers-client-fork-laggykiller ~=3.3.0.post1
|
383
383
|
Requires-Dist: sqlcipher3-wheels ~=0.5.2.post1
|
384
384
|
Requires-Dist: tqdm ~=4.66.2
|
385
385
|
Requires-Dist: ttkbootstrap-fork-laggykiller ~=1.5.1
|
@@ -391,7 +391,7 @@ Requires-Dist: webp ~=0.3.0
|
|
391
391
|
|
392
392
|
- A python script for creating, downloading, converting+compressing and uploading stickers from multiple instant messaging applications.
|
393
393
|
- With GUI and CLI that runs on Windows, MacOS and Linux
|
394
|
-
- Currently supports Signal, Telegram, WhatsApp (Create .wastickers), Line (Download only), Kakao (Download only), iMessage (Create Xcode sticker pack project)
|
394
|
+
- Currently supports Signal, Telegram, WhatsApp (Create .wastickers), Line (Download only), Kakao (Download only), Viber (Download only), iMessage (Create Xcode sticker pack project)
|
395
395
|
- Supports static and animated stickers, with transparency support
|
396
396
|
|
397
397
|
## Downloads
|
@@ -429,6 +429,7 @@ Requires-Dist: webp ~=0.3.0
|
|
429
429
|
| [WhatsApp](docs/guide_whatsapp.md) | ⭕ (By Android or WhatsApp Web) | ⭕ (Create `.wastickers`, import by Sticker Maker) |
|
430
430
|
| [Line](docs/guide_line.md) | ✅ | 🚫 (Need to submit for manual approval) |
|
431
431
|
| [Kakao](docs/guide_kakao.md) | ✅ (Need 'share link' for animated) | 🚫 (Need to submit for manual approval) |
|
432
|
+
| [Viber](docs/guide_viber.md) | ✅ | 🚫 (Manually upload through Viber app) |
|
432
433
|
| [iMessage](docs/guide_imessage.md) | 🚫 | ⭕ (Create Xcode stickerpack project for sideload) |
|
433
434
|
|
434
435
|
✅ = Supported ⭕ = Partially supported 🚫 = Not supported
|
@@ -455,6 +456,9 @@ Requires-Dist: webp ~=0.3.0
|
|
455
456
|
- Kakao
|
456
457
|
- Download: Supported (e.g. `https://e.kakao.com/t/xxxxx` OR `kakaotalk://store/emoticon/4404400` OR `https://emoticon.kakao.com/items/xxxxx` OR `4404400`). It is rather complicated, learn more from [docs/guide_kakao.md](docs/guide_kakao.md)
|
457
458
|
- Upload: Not supported. You need to manually submit sticker pack for approval before you can use in app.
|
459
|
+
- Viber
|
460
|
+
- Download: Supported (e.g. `https://stickers.viber.com/pages/example` OR `https://stickers.viber.com/pages/custom-sticker-packs/example`)
|
461
|
+
- Upload: The program can convert images to png with 490x490 for uploading to viber manually. It should be noted that Viber is able to resize images for you, so it may not be necessary to use sticker-convert for creating Viber sticker pack.
|
458
462
|
- iMessage
|
459
463
|
- Download: Not supported.
|
460
464
|
- Upload: The program can create Xcode project for iMessage sticker pack, which could then be compiled and sideloaded using Xcode.
|
@@ -1,18 +1,19 @@
|
|
1
1
|
sticker_convert/__init__.py,sha256=iQnv6UOOA69c3soAn7ZOnAIubTIQSUxtq1Uhh8xRWvU,102
|
2
2
|
sticker_convert/__main__.py,sha256=6RJauR-SCSSTT3TU7FFB6B6PVwsCxO2xZXtmZ3jc2Is,463
|
3
|
-
sticker_convert/cli.py,sha256=
|
4
|
-
sticker_convert/converter.py,sha256=
|
3
|
+
sticker_convert/cli.py,sha256=QGCpCSVt6ChVGXkX7Ngivl-CDUewqklqz2GRJKPFlsg,18621
|
4
|
+
sticker_convert/converter.py,sha256=cmUCq_bAsDGYNDBnajxibqcgMrCND1w3icjUTDZSJRA,37353
|
5
5
|
sticker_convert/definitions.py,sha256=ZhP2ALCEud-w9ZZD4c3TDG9eHGPZyaAL7zPUsJAbjtE,2073
|
6
6
|
sticker_convert/gui.py,sha256=TRPGwMhSMPHnZppHmw2OWHKTJtGoeLpGWD0eRYi4_yk,30707
|
7
|
-
sticker_convert/job.py,sha256=
|
7
|
+
sticker_convert/job.py,sha256=vKv1--y4MVmZV_IBpUhEfNEiUeEqrTR1umzlALPXKdw,25775
|
8
8
|
sticker_convert/job_option.py,sha256=JHAFCxp7-dDwD-1PbpYLAFRF3OoJu8cj_BjOm5r8Gp8,7732
|
9
|
-
sticker_convert/version.py,sha256=
|
9
|
+
sticker_convert/version.py,sha256=e6mePgSboDriG7gF-dXdRqwITrYd0E04plj8K5a_YxM,46
|
10
10
|
sticker_convert/downloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
sticker_convert/downloaders/download_base.py,sha256=
|
11
|
+
sticker_convert/downloaders/download_base.py,sha256=rYoUijl_pKldzD8SJGFetDwgMWPSQSfQwzLDObEMGow,3980
|
12
12
|
sticker_convert/downloaders/download_kakao.py,sha256=UFp7EpMea62fIePY5DfhH4jThAwdeazfoC5iW1g4dAo,8516
|
13
13
|
sticker_convert/downloaders/download_line.py,sha256=9WzOWujTbZdAqBi52k21OUEfRmcV1loCaJiDmg6dklw,17853
|
14
|
-
sticker_convert/downloaders/download_signal.py,sha256=
|
14
|
+
sticker_convert/downloaders/download_signal.py,sha256=PfwscdbcEd_5C3Ecs0F8Qc8si1sLzLodAdnsHVwXgac,3063
|
15
15
|
sticker_convert/downloaders/download_telegram.py,sha256=jufMqc78aXOPDr7fQf9ykkNyhQ7KVCp4gRBxs09NgMo,4614
|
16
|
+
sticker_convert/downloaders/download_viber.py,sha256=mrM1XIuXuon4hlkYQc8vYqjYr1KAZGdWUI9n85W5vpU,3090
|
16
17
|
sticker_convert/gui_components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
18
|
sticker_convert/gui_components/gui_utils.py,sha256=okho2cA1Scem_m6rPiYifreFzpFrM21-yUkiAv64EUI,3431
|
18
19
|
sticker_convert/gui_components/frames/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -66,21 +67,21 @@ sticker_convert/resources/NotoColorEmoji.ttf,sha256=LurIVaCIA8bSCfjrdO1feYr0bhKL
|
|
66
67
|
sticker_convert/resources/appicon.icns,sha256=FB2DVTOQcFfQNZ9RcyG3z9c9k7eOiI1qw0IJhXMRFg4,5404
|
67
68
|
sticker_convert/resources/appicon.ico,sha256=-ldugcl2Yq2pBRTktnhGKWInpKyWzRjCiPvMr3XPTlc,38078
|
68
69
|
sticker_convert/resources/appicon.png,sha256=6XBEQz7PnerqS43aRkwpWolFG4WvKMuQ-st1ly-_JPg,5265
|
69
|
-
sticker_convert/resources/compression.json,sha256=
|
70
|
+
sticker_convert/resources/compression.json,sha256=8SAv5m7_R2QFaU656W7gpliCJF9ZmGdE_XfnJU3D0ZE,12156
|
70
71
|
sticker_convert/resources/emoji.json,sha256=sXSuKusyG1L2Stuf9BL5ZqfzOIOdeAeE3RXcrXAsLdY,413367
|
71
72
|
sticker_convert/resources/help.json,sha256=7VKc4Oxw6e4zv2IIeYRQ5e_aa88UlsgIHSBm9Tf-V70,6541
|
72
|
-
sticker_convert/resources/input.json,sha256=
|
73
|
+
sticker_convert/resources/input.json,sha256=5nc3US6WXAJzjqWqtDy7R2nBZ5VKVFZlKDAadE-q7SI,2657
|
73
74
|
sticker_convert/resources/output.json,sha256=QYP2gqDvEaAm5I9bH4NReaB1XMLboevv69u-V8YdZUs,1373
|
74
75
|
sticker_convert/uploaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
75
76
|
sticker_convert/uploaders/compress_wastickers.py,sha256=SMPf1_ir30ZKO2ChHspDFuyaufx0XeVBVLOlHmawEdY,6021
|
76
77
|
sticker_convert/uploaders/upload_base.py,sha256=uQupPn6r4zrlAzpKzzX7CgvZb69ATyrwPKahWOQj0ds,1203
|
77
|
-
sticker_convert/uploaders/upload_signal.py,sha256=
|
78
|
-
sticker_convert/uploaders/upload_telegram.py,sha256=
|
78
|
+
sticker_convert/uploaders/upload_signal.py,sha256=eZNfTwnZzPmJcl_UCfJT6rrmLlNpD2EKfxrO2jdi1yg,6396
|
79
|
+
sticker_convert/uploaders/upload_telegram.py,sha256=XnspO9VVbKND0gybUwdFTSzDBVDxLw9O_R7chnVQ0t0,15695
|
79
80
|
sticker_convert/uploaders/xcode_imessage.py,sha256=1gvOljf6kYsq_11tYhnF19Yf4oGY5y34te2DWBRMwf0,11254
|
80
81
|
sticker_convert/utils/callback.py,sha256=_w_dZ3DZTA9m4TjEg6NH_VOa5Dl2YHXdXAlwx_tBdoY,6061
|
81
82
|
sticker_convert/utils/url_detect.py,sha256=Cw3SzHj0xQTgCY8KvXbgFGRn_VhDJuZvH0mWsiQOg5s,769
|
82
83
|
sticker_convert/utils/auth/get_kakao_auth.py,sha256=ipAZ1DUd5CMTpUoxRXHVOFC3DKIpxwxpTYAfrOJ6UZ8,9829
|
83
|
-
sticker_convert/utils/auth/get_line_auth.py,sha256=
|
84
|
+
sticker_convert/utils/auth/get_line_auth.py,sha256=8l8ha2vQmk3rHGvDE7PkcxQXbH3oe62LKbI3qVUtvqc,2196
|
84
85
|
sticker_convert/utils/auth/get_signal_auth.py,sha256=6Sx-lMuyBHeX1RpjAWI8u03qnRu9fmO4p89pd7fowOE,4925
|
85
86
|
sticker_convert/utils/files/cache_store.py,sha256=etfe614OAhAyrnM5fGeESKq6R88YLNqkqkxSzEmZ0V0,1047
|
86
87
|
sticker_convert/utils/files/json_manager.py,sha256=Vr6pZJdLMkrJJWN99210aduVHb0ILyf0SSTaw4TZqgc,541
|
@@ -92,9 +93,9 @@ sticker_convert/utils/media/apple_png_normalize.py,sha256=LbrQhc7LlYX4I9ek4XJsZE
|
|
92
93
|
sticker_convert/utils/media/codec_info.py,sha256=SJSFvQzXHnGkj7MH9xJ5xiC4cqiOjFKckFKE_FICdT4,15562
|
93
94
|
sticker_convert/utils/media/decrypt_kakao.py,sha256=4wq9ZDRnFkx1WmFZnyEogBofiLGsWQM_X69HlA36578,1947
|
94
95
|
sticker_convert/utils/media/format_verify.py,sha256=Xf94jyqk_6M9IlFGMy0wYIgQKn_yg00nD4XW0CgAbew,5732
|
95
|
-
sticker_convert-2.8.
|
96
|
-
sticker_convert-2.8.
|
97
|
-
sticker_convert-2.8.
|
98
|
-
sticker_convert-2.8.
|
99
|
-
sticker_convert-2.8.
|
100
|
-
sticker_convert-2.8.
|
96
|
+
sticker_convert-2.8.5.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
|
97
|
+
sticker_convert-2.8.5.dist-info/METADATA,sha256=CWigvu2m37fdj14o8MqqmahgYDfUrbzG2zPbEO1KdCU,49868
|
98
|
+
sticker_convert-2.8.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
99
|
+
sticker_convert-2.8.5.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
|
100
|
+
sticker_convert-2.8.5.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
|
101
|
+
sticker_convert-2.8.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|