sticker-convert 2.1.6__py3-none-any.whl → 2.1.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sticker_convert/__init__.py +1 -1
- sticker_convert/__main__.py +7 -4
- sticker_convert/cli.py +39 -31
- sticker_convert/converter.py +432 -0
- sticker_convert/downloaders/download_base.py +40 -16
- sticker_convert/downloaders/download_kakao.py +103 -136
- sticker_convert/downloaders/download_line.py +16 -6
- sticker_convert/downloaders/download_signal.py +48 -32
- sticker_convert/downloaders/download_telegram.py +71 -26
- sticker_convert/gui.py +78 -129
- sticker_convert/{gui_frames → gui_components/frames}/comp_frame.py +2 -3
- sticker_convert/{gui_frames → gui_components/frames}/config_frame.py +3 -4
- sticker_convert/{gui_frames → gui_components/frames}/control_frame.py +2 -2
- sticker_convert/{gui_frames → gui_components/frames}/cred_frame.py +4 -4
- sticker_convert/{gui_frames → gui_components/frames}/input_frame.py +4 -4
- sticker_convert/{gui_frames → gui_components/frames}/output_frame.py +3 -3
- sticker_convert/{gui_frames → gui_components/frames}/progress_frame.py +1 -1
- sticker_convert/{utils → gui_components}/gui_utils.py +38 -21
- sticker_convert/{gui_windows → gui_components/windows}/advanced_compression_window.py +3 -2
- sticker_convert/{gui_windows → gui_components/windows}/base_window.py +3 -2
- sticker_convert/{gui_windows → gui_components/windows}/kakao_get_auth_window.py +3 -3
- sticker_convert/{gui_windows → gui_components/windows}/line_get_auth_window.py +2 -2
- sticker_convert/{gui_windows → gui_components/windows}/signal_get_auth_window.py +2 -2
- sticker_convert/{flow.py → job.py} +91 -102
- sticker_convert/job_option.py +301 -0
- sticker_convert/resources/compression.json +1 -1
- sticker_convert/uploaders/compress_wastickers.py +95 -74
- sticker_convert/uploaders/upload_base.py +16 -4
- sticker_convert/uploaders/upload_signal.py +100 -62
- sticker_convert/uploaders/upload_telegram.py +168 -128
- sticker_convert/uploaders/xcode_imessage.py +202 -132
- sticker_convert/{auth → utils/auth}/get_kakao_auth.py +7 -5
- sticker_convert/{auth → utils/auth}/get_line_auth.py +3 -3
- sticker_convert/{auth → utils/auth}/get_signal_auth.py +1 -1
- sticker_convert/utils/fake_cb_msg.py +5 -2
- sticker_convert/utils/{cache_store.py → files/cache_store.py} +7 -3
- sticker_convert/utils/files/dir_utils.py +64 -0
- sticker_convert/utils/{json_manager.py → files/json_manager.py} +5 -4
- sticker_convert/utils/files/metadata_handler.py +226 -0
- sticker_convert/utils/files/run_bin.py +58 -0
- sticker_convert/utils/{apple_png_normalize.py → media/apple_png_normalize.py} +23 -20
- sticker_convert/utils/{codec_info.py → media/codec_info.py} +41 -35
- sticker_convert/utils/media/decrypt_kakao.py +68 -0
- sticker_convert/utils/media/format_verify.py +184 -0
- sticker_convert/utils/url_detect.py +16 -14
- {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/METADATA +8 -9
- {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/RECORD +52 -50
- {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/WHEEL +1 -1
- sticker_convert/utils/converter.py +0 -407
- sticker_convert/utils/curr_dir.py +0 -70
- sticker_convert/utils/format_verify.py +0 -188
- sticker_convert/utils/metadata_handler.py +0 -190
- sticker_convert/utils/run_bin.py +0 -46
- /sticker_convert/{gui_frames → gui_components/frames}/right_clicker.py +0 -0
- {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/LICENSE +0 -0
- {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/top_level.txt +0 -0
@@ -7,38 +7,47 @@ import plistlib
|
|
7
7
|
from typing import Optional
|
8
8
|
import zipfile
|
9
9
|
|
10
|
-
from
|
10
|
+
from .upload_base import UploadBase # type: ignore
|
11
|
+
from ..converter import StickerConvert # type: ignore
|
12
|
+
from ..utils.media.format_verify import FormatVerify # type: ignore
|
13
|
+
from ..utils.media.codec_info import CodecInfo # type: ignore
|
14
|
+
from ..utils.files.metadata_handler import MetadataHandler # type: ignore
|
15
|
+
from ..job_option import CompOption, OutputOption, CredOption # type: ignore
|
11
16
|
|
12
|
-
from .upload_base import UploadBase # type: ignore
|
13
|
-
from ..utils.converter import StickerConvert # type: ignore
|
14
|
-
from ..utils.format_verify import FormatVerify # type: ignore
|
15
|
-
from ..utils.metadata_handler import MetadataHandler # type: ignore
|
16
|
-
from ..utils.codec_info import CodecInfo # type: ignore
|
17
17
|
|
18
18
|
class XcodeImessageIconset:
|
19
|
+
iconset = {}
|
20
|
+
|
19
21
|
def __init__(self):
|
20
|
-
self.iconset
|
22
|
+
if self.iconset != {}:
|
23
|
+
return
|
21
24
|
|
22
|
-
if os.path.isdir(
|
23
|
-
with open(
|
25
|
+
if os.path.isdir("ios-message-stickers-template"):
|
26
|
+
with open(
|
27
|
+
"ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Contents.json"
|
28
|
+
) as f:
|
24
29
|
dict = json.load(f)
|
25
|
-
elif os.path.isfile(
|
26
|
-
with zipfile.ZipFile(
|
27
|
-
dict = json.loads(
|
30
|
+
elif os.path.isfile("ios-message-stickers-template.zip"):
|
31
|
+
with zipfile.ZipFile("ios-message-stickers-template.zip", "r") as f:
|
32
|
+
dict = json.loads(
|
33
|
+
f.read(
|
34
|
+
"stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Contents.json"
|
35
|
+
).decode()
|
36
|
+
)
|
28
37
|
else:
|
29
|
-
raise FileNotFoundError(
|
30
|
-
|
31
|
-
for i in dict[
|
32
|
-
filename = i[
|
33
|
-
size = i[
|
34
|
-
size_w = int(size.split(
|
35
|
-
size_h = int(size.split(
|
36
|
-
scale = int(i[
|
38
|
+
raise FileNotFoundError("ios-message-stickers-template not found")
|
39
|
+
|
40
|
+
for i in dict["images"]:
|
41
|
+
filename = i["filename"]
|
42
|
+
size = i["size"]
|
43
|
+
size_w = int(size.split("x")[0])
|
44
|
+
size_h = int(size.split("x")[1])
|
45
|
+
scale = int(i["scale"].replace("x", ""))
|
37
46
|
size_w_scaled = size_w * scale
|
38
47
|
size_h_scaled = size_h * scale
|
39
48
|
|
40
49
|
self.iconset[filename] = (size_w_scaled, size_h_scaled)
|
41
|
-
|
50
|
+
|
42
51
|
# self.iconset = {
|
43
52
|
# 'App-Store-1024x1024pt.png': (1024, 1024),
|
44
53
|
# 'iPad-Settings-29pt@2x.png': (58, 58),
|
@@ -56,51 +65,38 @@ class XcodeImessageIconset:
|
|
56
65
|
# }
|
57
66
|
|
58
67
|
|
59
|
-
|
60
68
|
class XcodeImessage(UploadBase):
|
61
69
|
def __init__(self, *args, **kwargs):
|
62
70
|
super(XcodeImessage, self).__init__(*args, **kwargs)
|
63
71
|
self.iconset = XcodeImessageIconset().iconset
|
64
72
|
|
65
|
-
base_spec = {
|
66
|
-
"size_max": {
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
'w': {
|
72
|
-
'min': 300,
|
73
|
-
'max': 300
|
74
|
-
},
|
75
|
-
'h': {
|
76
|
-
'min': 300,
|
77
|
-
'max': 300
|
78
|
-
}
|
79
|
-
},
|
80
|
-
'format': ('.png', '.apng', '.gif', '.jpeg', 'jpg'),
|
81
|
-
'square': True
|
82
|
-
}
|
73
|
+
base_spec = CompOption({
|
74
|
+
"size_max": {"img": 500000, "vid": 500000},
|
75
|
+
"res": 300,
|
76
|
+
"format": [".png", ".apng", ".gif", ".jpeg", "jpg"],
|
77
|
+
"square": True,
|
78
|
+
})
|
83
79
|
|
84
80
|
self.small_spec = copy.deepcopy(base_spec)
|
85
81
|
|
86
82
|
self.medium_spec = copy.deepcopy(base_spec)
|
87
|
-
self.medium_spec
|
88
|
-
self.medium_spec['res']['w']['max'] = 408
|
89
|
-
self.medium_spec['res']['h']['min'] = 408
|
90
|
-
self.medium_spec['res']['h']['max'] = 408
|
83
|
+
self.medium_spec.res = 408
|
91
84
|
|
92
85
|
self.large_spec = copy.deepcopy(base_spec)
|
93
|
-
self.large_spec
|
94
|
-
|
95
|
-
self.large_spec['res']['h']['min'] = 618
|
96
|
-
self.large_spec['res']['h']['max'] = 618
|
97
|
-
|
86
|
+
self.large_spec.res = 618
|
87
|
+
|
98
88
|
def create_imessage_xcode(self) -> list[str]:
|
99
89
|
urls = []
|
100
|
-
title, author, emoji_dict = MetadataHandler.get_metadata(
|
101
|
-
|
102
|
-
|
103
|
-
|
90
|
+
title, author, emoji_dict = MetadataHandler.get_metadata(
|
91
|
+
self.in_dir,
|
92
|
+
title=self.opt_output.title,
|
93
|
+
author=self.opt_output.author,
|
94
|
+
)
|
95
|
+
author = author.replace(" ", "_")
|
96
|
+
title = title.replace(" ", "_")
|
97
|
+
packs = MetadataHandler.split_sticker_packs(
|
98
|
+
self.in_dir, title=title, file_per_pack=100, separate_image_anim=False
|
99
|
+
)
|
104
100
|
|
105
101
|
res_choice = None
|
106
102
|
|
@@ -108,7 +104,7 @@ class XcodeImessage(UploadBase):
|
|
108
104
|
pack_title = FormatVerify.sanitize_filename(pack_title)
|
109
105
|
|
110
106
|
for src in stickers:
|
111
|
-
self.cb_msg(f
|
107
|
+
self.cb_msg(f"Verifying {src} for creating Xcode iMessage sticker pack")
|
112
108
|
|
113
109
|
src_path = os.path.join(self.in_dir, src)
|
114
110
|
dst_path = os.path.join(self.out_dir, src)
|
@@ -116,7 +112,7 @@ class XcodeImessage(UploadBase):
|
|
116
112
|
if res_choice == None:
|
117
113
|
res_choice, _ = CodecInfo.get_file_res(src_path)
|
118
114
|
res_choice = res_choice if res_choice != None else 300
|
119
|
-
|
115
|
+
|
120
116
|
if res_choice == 618:
|
121
117
|
spec_choice = self.large_spec
|
122
118
|
elif res_choice == 408:
|
@@ -124,14 +120,17 @@ class XcodeImessage(UploadBase):
|
|
124
120
|
else:
|
125
121
|
# res_choice == 300
|
126
122
|
spec_choice = self.small_spec
|
127
|
-
|
128
|
-
opt_comp_merged =
|
123
|
+
|
124
|
+
opt_comp_merged = copy.deepcopy(self.opt_comp)
|
125
|
+
opt_comp_merged.merge(spec_choice)
|
129
126
|
|
130
127
|
if FormatVerify.check_file(src, spec=spec_choice):
|
131
128
|
if src_path != dst_path:
|
132
129
|
shutil.copy(src_path, dst_path)
|
133
130
|
else:
|
134
|
-
StickerConvert(
|
131
|
+
StickerConvert(
|
132
|
+
src_path, dst_path, opt_comp_merged, self.cb_msg
|
133
|
+
).convert()
|
135
134
|
|
136
135
|
self.add_metadata(author, pack_title)
|
137
136
|
self.create_xcode_proj(author, pack_title)
|
@@ -139,11 +138,18 @@ class XcodeImessage(UploadBase):
|
|
139
138
|
result = os.path.join(self.out_dir, pack_title)
|
140
139
|
self.cb_msg(result)
|
141
140
|
urls.append(result)
|
142
|
-
|
141
|
+
|
143
142
|
return urls
|
144
143
|
|
145
144
|
def add_metadata(self, author: str, title: str):
|
146
|
-
first_image_path = os.path.join(
|
145
|
+
first_image_path = os.path.join(
|
146
|
+
self.in_dir,
|
147
|
+
[
|
148
|
+
i
|
149
|
+
for i in sorted(os.listdir(self.in_dir))
|
150
|
+
if os.path.isfile(os.path.join(self.in_dir, i)) and i.endswith(".png")
|
151
|
+
][0],
|
152
|
+
)
|
147
153
|
cover_path = MetadataHandler.get_cover(self.in_dir)
|
148
154
|
if cover_path:
|
149
155
|
icon_source = cover_path
|
@@ -151,70 +157,106 @@ class XcodeImessage(UploadBase):
|
|
151
157
|
icon_source = first_image_path
|
152
158
|
|
153
159
|
for icon, res in self.iconset.items():
|
154
|
-
spec_cover = {
|
160
|
+
spec_cover = CompOption({
|
155
161
|
"res": {
|
156
|
-
"w":
|
157
|
-
|
158
|
-
"max": res[0]
|
159
|
-
},
|
160
|
-
"h": {
|
161
|
-
"min": res[1],
|
162
|
-
"max": res[1]
|
163
|
-
}
|
162
|
+
"w": res[0],
|
163
|
+
"h": res[1]
|
164
164
|
}
|
165
|
-
}
|
165
|
+
})
|
166
166
|
|
167
167
|
icon_old_path = os.path.join(self.in_dir, icon)
|
168
168
|
icon_new_path = os.path.join(self.out_dir, icon)
|
169
|
-
if icon in os.listdir(self.in_dir) and not FormatVerify.check_file(
|
170
|
-
|
169
|
+
if icon in os.listdir(self.in_dir) and not FormatVerify.check_file(
|
170
|
+
icon_old_path, spec=spec_cover
|
171
|
+
):
|
172
|
+
StickerConvert(
|
173
|
+
icon_old_path, icon_new_path, spec_cover, self.cb_msg
|
174
|
+
).convert()
|
171
175
|
else:
|
172
|
-
StickerConvert(
|
173
|
-
|
176
|
+
StickerConvert(
|
177
|
+
icon_source, icon_new_path, spec_cover, self.cb_msg
|
178
|
+
).convert()
|
179
|
+
|
174
180
|
MetadataHandler.set_metadata(self.out_dir, author=author, title=title)
|
175
181
|
|
176
182
|
def create_xcode_proj(self, author: str, title: str):
|
177
183
|
pack_path = os.path.join(self.out_dir, title)
|
178
|
-
if os.path.isfile(
|
179
|
-
with zipfile.ZipFile(
|
184
|
+
if os.path.isfile("ios-message-stickers-template.zip"):
|
185
|
+
with zipfile.ZipFile("ios-message-stickers-template.zip", "r") as f:
|
180
186
|
f.extractall(pack_path)
|
181
|
-
elif os.path.isdir(
|
182
|
-
shutil.copytree(
|
187
|
+
elif os.path.isdir("ios-message-stickers-template"):
|
188
|
+
shutil.copytree("ios-message-stickers-template", pack_path)
|
183
189
|
else:
|
184
|
-
self.cb_msg(
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
190
|
+
self.cb_msg(
|
191
|
+
"Failed to create Xcode project: ios-message-stickers-template not found"
|
192
|
+
)
|
193
|
+
|
194
|
+
os.remove(os.path.join(pack_path, "README.md"))
|
195
|
+
shutil.rmtree(
|
196
|
+
os.path.join(pack_path, "stickers.xcodeproj/project.xcworkspace"),
|
197
|
+
ignore_errors=True,
|
198
|
+
)
|
199
|
+
shutil.rmtree(
|
200
|
+
os.path.join(pack_path, "stickers.xcodeproj/xcuserdata"), ignore_errors=True
|
201
|
+
)
|
202
|
+
|
203
|
+
with open(
|
204
|
+
os.path.join(pack_path, "stickers.xcodeproj/project.pbxproj"),
|
205
|
+
encoding="utf-8",
|
206
|
+
) as f:
|
191
207
|
pbxproj_data = f.read()
|
192
|
-
|
193
|
-
pbxproj_data = pbxproj_data.replace(
|
194
|
-
|
195
|
-
|
196
|
-
pbxproj_data = pbxproj_data.replace(
|
197
|
-
pbxproj_data = pbxproj_data.replace(
|
198
|
-
pbxproj_data = pbxproj_data.replace(
|
199
|
-
pbxproj_data = pbxproj_data.replace(
|
200
|
-
|
201
|
-
|
202
|
-
pbxproj_data = pbxproj_data.replace(
|
203
|
-
|
204
|
-
|
208
|
+
|
209
|
+
pbxproj_data = pbxproj_data.replace(
|
210
|
+
"stickers StickerPackExtension", f"{title} StickerPackExtension"
|
211
|
+
)
|
212
|
+
pbxproj_data = pbxproj_data.replace("stickers.app", f"{title}.app")
|
213
|
+
pbxproj_data = pbxproj_data.replace("/* stickers */", f"/* {title} */")
|
214
|
+
pbxproj_data = pbxproj_data.replace("name = stickers", f"name = {title}")
|
215
|
+
pbxproj_data = pbxproj_data.replace(
|
216
|
+
"productName = stickers", f"productName = {title}"
|
217
|
+
)
|
218
|
+
pbxproj_data = pbxproj_data.replace(
|
219
|
+
'/* Build configuration list for PBXProject "stickers" */',
|
220
|
+
f'/* Build configuration list for PBXProject "{title}" */',
|
221
|
+
)
|
222
|
+
pbxproj_data = pbxproj_data.replace(
|
223
|
+
'/* Build configuration list for PBXNativeTarget "stickers StickerPackExtension" */',
|
224
|
+
f'/* Build configuration list for PBXNativeTarget "{title} StickerPackExtension" */',
|
225
|
+
)
|
226
|
+
pbxproj_data = pbxproj_data.replace(
|
227
|
+
'/* Build configuration list for PBXNativeTarget "stickers" */',
|
228
|
+
f'/* Build configuration list for PBXNativeTarget "{title}" */',
|
229
|
+
)
|
230
|
+
pbxproj_data = pbxproj_data.replace("com.niklaspeterson", f"com.{author}")
|
231
|
+
pbxproj_data = pbxproj_data.replace(
|
232
|
+
"stickers/Info.plist", f"{title}/Info.plist"
|
233
|
+
)
|
234
|
+
|
235
|
+
with open(
|
236
|
+
os.path.join(pack_path, "stickers.xcodeproj/project.pbxproj"),
|
237
|
+
"w+",
|
238
|
+
encoding="utf-8",
|
239
|
+
) as f:
|
205
240
|
f.write(pbxproj_data)
|
206
|
-
|
241
|
+
|
207
242
|
# packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack
|
208
|
-
stickers_path = os.path.join(
|
209
|
-
|
243
|
+
stickers_path = os.path.join(
|
244
|
+
pack_path,
|
245
|
+
"stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack",
|
246
|
+
)
|
247
|
+
|
210
248
|
for i in os.listdir(stickers_path):
|
211
|
-
if i.endswith(
|
249
|
+
if i.endswith(".sticker"):
|
212
250
|
shutil.rmtree(os.path.join(stickers_path, i))
|
213
|
-
|
251
|
+
|
214
252
|
stickers_lst = []
|
215
253
|
for i in sorted(os.listdir(self.in_dir)):
|
216
|
-
if
|
217
|
-
|
254
|
+
if (
|
255
|
+
CodecInfo.get_file_ext(i) == ".png"
|
256
|
+
and os.path.splitext(i)[0] != "cover"
|
257
|
+
and i not in self.iconset
|
258
|
+
):
|
259
|
+
sticker_dir = f"{os.path.splitext(i)[0]}.sticker" # 0.sticker
|
218
260
|
stickers_lst.append(sticker_dir)
|
219
261
|
# packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker
|
220
262
|
sticker_path = os.path.join(stickers_path, sticker_dir)
|
@@ -223,56 +265,84 @@ class XcodeImessage(UploadBase):
|
|
223
265
|
shutil.copy(os.path.join(self.in_dir, i), os.path.join(sticker_path, i))
|
224
266
|
|
225
267
|
json_content = {
|
226
|
-
|
227
|
-
|
228
|
-
|
268
|
+
"info": {
|
269
|
+
"author": "xcode",
|
270
|
+
"version": 1,
|
229
271
|
},
|
230
|
-
|
231
|
-
'filename': i
|
232
|
-
}
|
272
|
+
"properties": {"filename": i},
|
233
273
|
}
|
234
274
|
|
235
275
|
# packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker/Contents.json
|
236
|
-
with open(os.path.join(sticker_path,
|
276
|
+
with open(os.path.join(sticker_path, "Contents.json"), "w+") as f:
|
237
277
|
json.dump(json_content, f, indent=2)
|
238
|
-
|
278
|
+
|
239
279
|
# packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Contents.json
|
240
|
-
with open(os.path.join(stickers_path,
|
280
|
+
with open(os.path.join(stickers_path, "Contents.json")) as f:
|
241
281
|
json_content = json.load(f)
|
242
|
-
|
243
|
-
json_content[
|
282
|
+
|
283
|
+
json_content["stickers"] = []
|
244
284
|
for i in stickers_lst:
|
245
|
-
json_content[
|
246
|
-
|
247
|
-
with open(os.path.join(stickers_path,
|
285
|
+
json_content["stickers"].append({"filename": i}) # type: ignore[attr-defined]
|
286
|
+
|
287
|
+
with open(os.path.join(stickers_path, "Contents.json"), "w+") as f:
|
248
288
|
json.dump(json_content, f, indent=2)
|
249
289
|
|
250
290
|
# packname StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset
|
251
|
-
iconset_path = os.path.join(
|
291
|
+
iconset_path = os.path.join(
|
292
|
+
pack_path,
|
293
|
+
"stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset",
|
294
|
+
)
|
252
295
|
|
253
296
|
for i in os.listdir(iconset_path):
|
254
|
-
if os.path.splitext(i)[1] ==
|
297
|
+
if os.path.splitext(i)[1] == ".png":
|
255
298
|
os.remove(os.path.join(iconset_path, i))
|
256
299
|
|
257
300
|
icons_lst = []
|
258
301
|
for i in self.iconset:
|
259
302
|
shutil.copy(os.path.join(self.in_dir, i), os.path.join(iconset_path, i))
|
260
303
|
icons_lst.append(i)
|
261
|
-
|
304
|
+
|
262
305
|
# packname/Info.plist
|
263
|
-
plist_path = os.path.join(pack_path,
|
264
|
-
with open(plist_path,
|
306
|
+
plist_path = os.path.join(pack_path, "stickers/Info.plist")
|
307
|
+
with open(plist_path, "rb") as f:
|
265
308
|
plist_dict = plistlib.load(f)
|
266
|
-
plist_dict[
|
309
|
+
plist_dict["CFBundleDisplayName"] = title
|
267
310
|
|
268
|
-
with open(plist_path,
|
311
|
+
with open(plist_path, "wb+") as f:
|
269
312
|
plistlib.dump(plist_dict, f)
|
270
313
|
|
271
|
-
os.rename(
|
272
|
-
|
273
|
-
|
274
|
-
|
314
|
+
os.rename(
|
315
|
+
os.path.join(pack_path, "stickers"), os.path.join(pack_path, f"{title}")
|
316
|
+
)
|
317
|
+
os.rename(
|
318
|
+
os.path.join(pack_path, "stickers StickerPackExtension"),
|
319
|
+
os.path.join(pack_path, f"{title} StickerPackExtension"),
|
320
|
+
)
|
321
|
+
os.rename(
|
322
|
+
os.path.join(pack_path, "stickers.xcodeproj"),
|
323
|
+
os.path.join(pack_path, f"{title}.xcodeproj"),
|
324
|
+
)
|
325
|
+
|
275
326
|
@staticmethod
|
276
|
-
def start(
|
277
|
-
|
327
|
+
def start(
|
328
|
+
opt_output: OutputOption,
|
329
|
+
opt_comp: CompOption,
|
330
|
+
opt_cred: CredOption,
|
331
|
+
cb_msg=print,
|
332
|
+
cb_msg_block=input,
|
333
|
+
cb_ask_bool=input,
|
334
|
+
cb_bar=None,
|
335
|
+
out_dir: Optional[str] = None,
|
336
|
+
**kwargs,
|
337
|
+
) -> list[str]:
|
338
|
+
exporter = XcodeImessage(
|
339
|
+
opt_output,
|
340
|
+
opt_comp,
|
341
|
+
opt_cred,
|
342
|
+
cb_msg,
|
343
|
+
cb_msg_block,
|
344
|
+
cb_ask_bool,
|
345
|
+
cb_bar,
|
346
|
+
out_dir,
|
347
|
+
)
|
278
348
|
return exporter.create_imessage_xcode()
|
@@ -6,12 +6,14 @@ import json
|
|
6
6
|
from urllib.parse import urlparse, parse_qs
|
7
7
|
from typing import Optional
|
8
8
|
|
9
|
+
from ...job_option import CredOption
|
10
|
+
|
9
11
|
class GetKakaoAuth:
|
10
|
-
def __init__(self, opt_cred:
|
11
|
-
self.username = opt_cred
|
12
|
-
self.password = opt_cred
|
13
|
-
self.country_code = opt_cred
|
14
|
-
self.phone_number = opt_cred
|
12
|
+
def __init__(self, opt_cred: CredOption, cb_msg=print, cb_msg_block=input, cb_ask_str=input):
|
13
|
+
self.username = opt_cred.kakao_username
|
14
|
+
self.password = opt_cred.kakao_password
|
15
|
+
self.country_code = opt_cred.kakao_country_code
|
16
|
+
self.phone_number = opt_cred.kakao_phone_number
|
15
17
|
|
16
18
|
self.cb_msg = cb_msg
|
17
19
|
self.cb_msg_block = cb_msg_block
|
@@ -7,9 +7,9 @@ import requests
|
|
7
7
|
|
8
8
|
class GetLineAuth:
|
9
9
|
def get_cred(self) -> Optional[str]:
|
10
|
-
|
11
|
-
cookies_dict = rookiepy.to_dict(
|
12
|
-
cookies_jar = rookiepy.to_cookiejar(
|
10
|
+
cookies_rookie = [c for c in rookiepy.load() if c.domain == 'store.line.me']
|
11
|
+
cookies_dict = rookiepy.to_dict(cookies_rookie)
|
12
|
+
cookies_jar = rookiepy.to_cookiejar(cookies_rookie)
|
13
13
|
|
14
14
|
if not GetLineAuth.validate_cookies(cookies_jar):
|
15
15
|
return None
|
@@ -15,7 +15,7 @@ from selenium import webdriver
|
|
15
15
|
from selenium.webdriver.chrome.service import Service
|
16
16
|
from selenium.common.exceptions import JavascriptException
|
17
17
|
|
18
|
-
from ..
|
18
|
+
from ..files.run_bin import RunBin # type: ignore
|
19
19
|
|
20
20
|
# https://stackoverflow.com/a/17197027
|
21
21
|
def strings(filename: str, min: int = 4) -> Generator[str, None, None]:
|
@@ -1,8 +1,11 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
|
3
|
+
|
3
4
|
class FakeCbMsg:
|
4
|
-
def __init__(self, msg_protocol =
|
5
|
+
def __init__(self, msg_protocol=print, silent=False):
|
5
6
|
self.msg_protocol = msg_protocol
|
7
|
+
self.silent = silent
|
6
8
|
|
7
9
|
def put(self, msg: str):
|
8
|
-
self.
|
10
|
+
if not self.silent:
|
11
|
+
self.msg_protocol(msg) # type: ignore[operator]
|
@@ -3,14 +3,17 @@ import os
|
|
3
3
|
import platform
|
4
4
|
import shutil
|
5
5
|
from uuid import uuid4
|
6
|
-
|
7
|
-
|
6
|
+
|
7
|
+
if platform.system() == "Linux":
|
8
|
+
import memory_tempfile # type: ignore
|
9
|
+
|
8
10
|
tempfile = memory_tempfile.MemoryTempfile(fallback=True)
|
9
11
|
else:
|
10
12
|
import tempfile
|
11
13
|
import contextlib
|
12
14
|
from typing import Optional
|
13
15
|
|
16
|
+
|
14
17
|
@contextlib.contextmanager
|
15
18
|
def debug_cache_dir(path: str):
|
16
19
|
path_random = os.path.join(path, str(uuid4()))
|
@@ -20,10 +23,11 @@ def debug_cache_dir(path: str):
|
|
20
23
|
finally:
|
21
24
|
shutil.rmtree(path_random)
|
22
25
|
|
26
|
+
|
23
27
|
class CacheStore:
|
24
28
|
@staticmethod
|
25
29
|
def get_cache_store(path: Optional[str] = None):
|
26
30
|
if path:
|
27
31
|
return debug_cache_dir(path)
|
28
32
|
else:
|
29
|
-
return tempfile.TemporaryDirectory()
|
33
|
+
return tempfile.TemporaryDirectory()
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
import os
|
3
|
+
import sys
|
4
|
+
import platform
|
5
|
+
from typing import Optional
|
6
|
+
|
7
|
+
|
8
|
+
class DirUtils:
|
9
|
+
@staticmethod
|
10
|
+
def _get_curr_dir_if_writable() -> Optional[str]:
|
11
|
+
appimage_path = os.getenv("APPIMAGE")
|
12
|
+
curr_dir = os.getcwd()
|
13
|
+
|
14
|
+
if (
|
15
|
+
curr_dir.startswith("/usr/bin/")
|
16
|
+
or curr_dir.startswith("/bin")
|
17
|
+
or curr_dir.startswith("/usr/local/bin")
|
18
|
+
or curr_dir.startswith("C:\\Program Files")
|
19
|
+
or "site-packages" in __file__
|
20
|
+
):
|
21
|
+
return None
|
22
|
+
|
23
|
+
if (
|
24
|
+
platform.system() == "Darwin"
|
25
|
+
and getattr(sys, "frozen", False)
|
26
|
+
and ".app/Contents/MacOS" in curr_dir
|
27
|
+
):
|
28
|
+
if curr_dir.startswith("/Applications/"):
|
29
|
+
return None
|
30
|
+
else:
|
31
|
+
curr_dir = os.path.abspath("../../../")
|
32
|
+
|
33
|
+
if appimage_path:
|
34
|
+
curr_dir = os.path.split(appimage_path)[0]
|
35
|
+
|
36
|
+
if not os.access(curr_dir, os.W_OK):
|
37
|
+
return None
|
38
|
+
|
39
|
+
return curr_dir
|
40
|
+
|
41
|
+
@staticmethod
|
42
|
+
def get_curr_dir() -> str:
|
43
|
+
home_dir = os.path.expanduser("~")
|
44
|
+
if os.path.isdir(os.path.join(home_dir, "Desktop")):
|
45
|
+
fallback_dir = os.path.join(home_dir, "Desktop")
|
46
|
+
else:
|
47
|
+
fallback_dir = home_dir
|
48
|
+
|
49
|
+
if (curr_dir := DirUtils._get_curr_dir_if_writable()) != None:
|
50
|
+
return curr_dir
|
51
|
+
else:
|
52
|
+
return fallback_dir
|
53
|
+
|
54
|
+
@staticmethod
|
55
|
+
def get_config_dir() -> str:
|
56
|
+
if platform.system() == "Windows":
|
57
|
+
fallback_dir = os.path.expandvars("%APPDATA%\\sticker-convert")
|
58
|
+
else:
|
59
|
+
fallback_dir = os.path.expanduser("~/.config/sticker-convert")
|
60
|
+
|
61
|
+
if (config_dir := DirUtils._get_curr_dir_if_writable()) != None:
|
62
|
+
return config_dir
|
63
|
+
else:
|
64
|
+
return fallback_dir
|
@@ -3,17 +3,18 @@ import os
|
|
3
3
|
import json
|
4
4
|
from typing import Optional
|
5
5
|
|
6
|
+
|
6
7
|
class JsonManager:
|
7
8
|
@staticmethod
|
8
9
|
def load_json(path: str) -> Optional[dict]:
|
9
10
|
if not os.path.isfile(path):
|
10
11
|
return None
|
11
12
|
else:
|
12
|
-
with open(path, encoding=
|
13
|
+
with open(path, encoding="utf-8") as f:
|
13
14
|
data = json.load(f)
|
14
15
|
return data
|
15
|
-
|
16
|
+
|
16
17
|
@staticmethod
|
17
18
|
def save_json(path: str, data: dict):
|
18
|
-
with open(path,
|
19
|
-
json.dump(data, f, indent=4)
|
19
|
+
with open(path, "w+", encoding="utf-8") as f:
|
20
|
+
json.dump(data, f, indent=4)
|