sticker-convert 2.8.12__py3-none-any.whl → 2.17.0.0__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.
Files changed (124) hide show
  1. sticker_convert/__main__.py +24 -24
  2. sticker_convert/auth/__init__.py +0 -0
  3. sticker_convert/auth/auth_base.py +19 -0
  4. sticker_convert/auth/auth_discord.py +149 -0
  5. sticker_convert/{utils/auth/get_kakao_auth.py → auth/auth_kakao_android_login.py} +331 -300
  6. sticker_convert/auth/auth_kakao_desktop_login.py +327 -0
  7. sticker_convert/auth/auth_kakao_desktop_memdump.py +281 -0
  8. sticker_convert/{utils/auth/get_line_auth.py → auth/auth_line.py} +98 -80
  9. sticker_convert/auth/auth_signal.py +139 -0
  10. sticker_convert/auth/auth_telethon.py +161 -0
  11. sticker_convert/auth/auth_viber.py +250 -0
  12. sticker_convert/auth/telegram_api.py +736 -0
  13. sticker_convert/cli.py +623 -509
  14. sticker_convert/converter.py +1093 -962
  15. sticker_convert/definitions.py +11 -0
  16. sticker_convert/downloaders/download_band.py +111 -0
  17. sticker_convert/downloaders/download_base.py +171 -130
  18. sticker_convert/downloaders/download_discord.py +92 -0
  19. sticker_convert/downloaders/download_kakao.py +417 -255
  20. sticker_convert/downloaders/download_line.py +484 -472
  21. sticker_convert/downloaders/download_ogq.py +80 -0
  22. sticker_convert/downloaders/download_signal.py +108 -92
  23. sticker_convert/downloaders/download_telegram.py +56 -130
  24. sticker_convert/downloaders/download_viber.py +121 -95
  25. sticker_convert/gui.py +788 -795
  26. sticker_convert/gui_components/frames/comp_frame.py +180 -165
  27. sticker_convert/gui_components/frames/config_frame.py +156 -113
  28. sticker_convert/gui_components/frames/control_frame.py +32 -30
  29. sticker_convert/gui_components/frames/cred_frame.py +232 -162
  30. sticker_convert/gui_components/frames/input_frame.py +139 -137
  31. sticker_convert/gui_components/frames/output_frame.py +112 -110
  32. sticker_convert/gui_components/frames/right_clicker.py +25 -23
  33. sticker_convert/gui_components/windows/advanced_compression_window.py +757 -715
  34. sticker_convert/gui_components/windows/base_window.py +7 -2
  35. sticker_convert/gui_components/windows/discord_get_auth_window.py +79 -0
  36. sticker_convert/gui_components/windows/kakao_get_auth_window.py +511 -186
  37. sticker_convert/gui_components/windows/line_get_auth_window.py +94 -102
  38. sticker_convert/gui_components/windows/signal_get_auth_window.py +84 -135
  39. sticker_convert/gui_components/windows/viber_get_auth_window.py +168 -0
  40. sticker_convert/ios-message-stickers-template/.github/FUNDING.yml +3 -3
  41. sticker_convert/ios-message-stickers-template/.gitignore +0 -0
  42. sticker_convert/ios-message-stickers-template/README.md +10 -10
  43. sticker_convert/ios-message-stickers-template/stickers/Info.plist +43 -43
  44. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Info.plist +31 -31
  45. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Contents.json +6 -6
  46. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Contents.json +20 -20
  47. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 1.sticker/Contents.json +9 -9
  48. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 1.sticker/Sticker 1.png +0 -0
  49. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 2.sticker/Contents.json +9 -9
  50. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 2.sticker/Sticker 2.png +0 -0
  51. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 3.sticker/Contents.json +9 -9
  52. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 3.sticker/Sticker 3.png +0 -0
  53. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/App-Store-1024x1024pt.png +0 -0
  54. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Contents.json +91 -91
  55. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-App-Store-1024x768pt.png +0 -0
  56. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPad-67x50pt@2x.png +0 -0
  57. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPad-Pro-74x55pt@2x.png +0 -0
  58. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPhone-60x45pt@2x.png +0 -0
  59. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPhone-60x45pt@3x.png +0 -0
  60. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages27x20pt@2x.png +0 -0
  61. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages27x20pt@3x.png +0 -0
  62. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages32x24pt@2x.png +0 -0
  63. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages32x24pt@3x.png +0 -0
  64. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/iPad-Settings-29pt@2x.png +0 -0
  65. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/iPhone-Settings-29pt@3x.png +0 -0
  66. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/iPhone-settings-29pt@2x.png +0 -0
  67. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.pbxproj +364 -364
  68. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -7
  69. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -8
  70. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/xcuserdata/niklaspeterson.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  71. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/xcuserdata/niklaspeterson.xcuserdatad/xcschemes/xcschememanagement.plist +14 -14
  72. sticker_convert/job.py +279 -179
  73. sticker_convert/job_option.py +15 -2
  74. sticker_convert/locales/en_US/LC_MESSAGES/base.mo +0 -0
  75. sticker_convert/locales/ja_JP/LC_MESSAGES/base.mo +0 -0
  76. sticker_convert/locales/zh_CN/LC_MESSAGES/base.mo +0 -0
  77. sticker_convert/locales/zh_TW/LC_MESSAGES/base.mo +0 -0
  78. sticker_convert/py.typed +0 -0
  79. sticker_convert/resources/NotoColorEmoji.ttf +0 -0
  80. sticker_convert/resources/compression.json +220 -16
  81. sticker_convert/resources/emoji.json +527 -77
  82. sticker_convert/resources/help.ja_JP.json +88 -0
  83. sticker_convert/resources/help.json +24 -10
  84. sticker_convert/resources/help.zh_CN.json +88 -0
  85. sticker_convert/resources/help.zh_TW.json +88 -0
  86. sticker_convert/resources/input.ja_JP.json +74 -0
  87. sticker_convert/resources/input.json +121 -71
  88. sticker_convert/resources/input.zh_CN.json +74 -0
  89. sticker_convert/resources/input.zh_TW.json +74 -0
  90. sticker_convert/resources/memdump_linux.sh +25 -0
  91. sticker_convert/resources/memdump_windows.ps1 +8 -0
  92. sticker_convert/resources/output.ja_JP.json +38 -0
  93. sticker_convert/resources/output.json +24 -0
  94. sticker_convert/resources/output.zh_CN.json +38 -0
  95. sticker_convert/resources/output.zh_TW.json +38 -0
  96. sticker_convert/uploaders/compress_wastickers.py +186 -156
  97. sticker_convert/uploaders/upload_base.py +44 -35
  98. sticker_convert/uploaders/upload_signal.py +218 -173
  99. sticker_convert/uploaders/upload_telegram.py +353 -388
  100. sticker_convert/uploaders/upload_viber.py +178 -0
  101. sticker_convert/uploaders/xcode_imessage.py +295 -285
  102. sticker_convert/utils/callback.py +238 -6
  103. sticker_convert/utils/chrome_remotedebug.py +219 -0
  104. sticker_convert/utils/chromiums/linux.py +52 -0
  105. sticker_convert/utils/chromiums/osx.py +68 -0
  106. sticker_convert/utils/chromiums/windows.py +45 -0
  107. sticker_convert/utils/emoji.py +28 -0
  108. sticker_convert/utils/files/json_resources_loader.py +24 -19
  109. sticker_convert/utils/files/metadata_handler.py +8 -7
  110. sticker_convert/utils/files/run_bin.py +1 -1
  111. sticker_convert/utils/media/codec_info.py +99 -67
  112. sticker_convert/utils/media/format_verify.py +33 -20
  113. sticker_convert/utils/process.py +231 -0
  114. sticker_convert/utils/translate.py +108 -0
  115. sticker_convert/utils/url_detect.py +40 -33
  116. sticker_convert/version.py +1 -1
  117. {sticker_convert-2.8.12.dist-info → sticker_convert-2.17.0.0.dist-info}/METADATA +189 -96
  118. sticker_convert-2.17.0.0.dist-info/RECORD +138 -0
  119. {sticker_convert-2.8.12.dist-info → sticker_convert-2.17.0.0.dist-info}/WHEEL +1 -1
  120. sticker_convert/utils/auth/get_signal_auth.py +0 -129
  121. sticker_convert-2.8.12.dist-info/RECORD +0 -101
  122. {sticker_convert-2.8.12.dist-info → sticker_convert-2.17.0.0.dist-info}/entry_points.txt +0 -0
  123. {sticker_convert-2.8.12.dist-info → sticker_convert-2.17.0.0.dist-info/licenses}/LICENSE +0 -0
  124. {sticker_convert-2.8.12.dist-info → sticker_convert-2.17.0.0.dist-info}/top_level.txt +0 -0
@@ -1,285 +1,295 @@
1
- #!/usr/bin/env python3
2
- import copy
3
- import json
4
- import os
5
- import plistlib
6
- import shutil
7
- import zipfile
8
- from pathlib import Path
9
- from typing import Any, Dict, List
10
-
11
- from sticker_convert.converter import StickerConvert
12
- from sticker_convert.definitions import ROOT_DIR
13
- from sticker_convert.job_option import CompOption, CredOption, OutputOption
14
- from sticker_convert.uploaders.upload_base import UploadBase
15
- from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
16
- from sticker_convert.utils.files.metadata_handler import XCODE_IMESSAGE_ICONSET, MetadataHandler
17
- from sticker_convert.utils.files.sanitize_filename import sanitize_filename
18
- from sticker_convert.utils.media.codec_info import CodecInfo
19
- from sticker_convert.utils.media.format_verify import FormatVerify
20
-
21
-
22
- class XcodeImessage(UploadBase):
23
- def __init__(self, *args: Any, **kwargs: Any) -> None:
24
- super().__init__(*args, **kwargs)
25
- self.base_spec.set_size_max(500000)
26
- self.base_spec.set_res(300)
27
- self.base_spec.set_format(("png", ".apng", ".gif", ".jpeg", "jpg"))
28
- self.base_spec.square = True
29
-
30
- self.small_spec = copy.deepcopy(self.base_spec)
31
-
32
- self.medium_spec = copy.deepcopy(self.base_spec)
33
- self.medium_spec.set_res(408)
34
-
35
- self.large_spec = copy.deepcopy(self.base_spec)
36
- self.large_spec.set_res(618)
37
-
38
- def create_imessage_xcode(self) -> List[str]:
39
- urls: List[str] = []
40
- title, author, _ = MetadataHandler.get_metadata(
41
- self.opt_output.dir,
42
- title=self.opt_output.title,
43
- author=self.opt_output.author,
44
- )
45
- if not author:
46
- self.cb.put("author is required for creating Xcode iMessage sticker pack")
47
- return urls
48
- if not title:
49
- self.cb.put("title is required for creating Xcode iMessage sticker pack")
50
- return urls
51
-
52
- author = author.replace(" ", "_")
53
- title = title.replace(" ", "_")
54
- packs = MetadataHandler.split_sticker_packs(
55
- self.opt_output.dir,
56
- title=title,
57
- file_per_pack=100,
58
- separate_image_anim=False,
59
- )
60
-
61
- res_choice = None
62
- spec_choice = None
63
- opt_comp_merged = copy.deepcopy(self.opt_comp)
64
-
65
- for pack_title, stickers in packs.items():
66
- pack_title = sanitize_filename(pack_title)
67
-
68
- for src in stickers:
69
- self.cb.put(f"Verifying {src} for creating Xcode iMessage sticker pack")
70
-
71
- fpath = Path(self.opt_output.dir, src)
72
-
73
- if res_choice is None:
74
- res_choice, _ = CodecInfo.get_file_res(fpath)
75
-
76
- if res_choice == 618:
77
- spec_choice = self.large_spec
78
- elif res_choice == 408:
79
- spec_choice = self.medium_spec
80
- else:
81
- # res_choice == 300
82
- spec_choice = self.small_spec
83
-
84
- opt_comp_merged.merge(spec_choice)
85
-
86
- assert spec_choice
87
- if not FormatVerify.check_file(src, spec=spec_choice):
88
- StickerConvert.convert(
89
- fpath, fpath, opt_comp_merged, self.cb, self.cb_return
90
- )
91
-
92
- self.add_metadata(author, pack_title)
93
- self.create_xcode_proj(author, pack_title)
94
-
95
- result = Path(self.opt_output.dir / pack_title).as_posix()
96
- self.cb.put(result)
97
- urls.append(result)
98
-
99
- return urls
100
-
101
- def add_metadata(self, author: str, title: str) -> None:
102
- first_image_path = Path(
103
- self.opt_output.dir,
104
- [
105
- i
106
- for i in sorted(self.opt_output.dir.iterdir())
107
- if (self.opt_output.dir / i).is_file() and i.suffix == ".png"
108
- ][0],
109
- )
110
- cover_path = MetadataHandler.get_cover(self.opt_output.dir)
111
- if cover_path:
112
- icon_source = cover_path
113
- else:
114
- icon_source = first_image_path
115
-
116
- for icon, res in XCODE_IMESSAGE_ICONSET.items():
117
- spec_cover = CompOption()
118
- spec_cover.set_res_w(res[0])
119
- spec_cover.set_res_h(res[1])
120
- spec_cover.set_fps(0)
121
-
122
- icon_path = self.opt_output.dir / icon
123
- if Path(icon) in list(
124
- self.opt_output.dir.iterdir()
125
- ) and not FormatVerify.check_file(icon_path, spec=spec_cover):
126
- StickerConvert.convert(
127
- icon_path, icon_path, spec_cover, self.cb, self.cb_return
128
- )
129
- else:
130
- StickerConvert.convert(
131
- icon_source, icon_path, spec_cover, self.cb, self.cb_return
132
- )
133
-
134
- MetadataHandler.set_metadata(self.opt_output.dir, author=author, title=title)
135
-
136
- def create_xcode_proj(self, author: str, title: str) -> None:
137
- pack_path = self.opt_output.dir / title
138
- if (ROOT_DIR / "ios-message-stickers-template.zip").is_file():
139
- with zipfile.ZipFile(
140
- ROOT_DIR / "ios-message-stickers-template.zip", "r"
141
- ) as f:
142
- f.extractall(pack_path)
143
- elif (ROOT_DIR / "ios-message-stickers-template").is_dir():
144
- shutil.copytree(ROOT_DIR / "ios-message-stickers-template", pack_path)
145
- else:
146
- self.cb.put(
147
- "Failed to create Xcode project: ios-message-stickers-template not found"
148
- )
149
-
150
- os.remove(pack_path / "README.md")
151
- shutil.rmtree(
152
- pack_path / "stickers.xcodeproj/project.xcworkspace",
153
- ignore_errors=True,
154
- )
155
- shutil.rmtree(pack_path / "stickers.xcodeproj/xcuserdata", ignore_errors=True)
156
-
157
- with open(
158
- pack_path / "stickers.xcodeproj/project.pbxproj",
159
- encoding="utf-8",
160
- ) as f:
161
- pbxproj_data = f.read()
162
-
163
- pbxproj_data = pbxproj_data.replace(
164
- "stickers StickerPackExtension", f"{title} StickerPackExtension"
165
- )
166
- pbxproj_data = pbxproj_data.replace("stickers.app", f"{title}.app")
167
- pbxproj_data = pbxproj_data.replace("/* stickers */", f"/* {title} */")
168
- pbxproj_data = pbxproj_data.replace("name = stickers", f"name = {title}")
169
- pbxproj_data = pbxproj_data.replace(
170
- "productName = stickers", f"productName = {title}"
171
- )
172
- pbxproj_data = pbxproj_data.replace(
173
- '/* Build configuration list for PBXProject "stickers" */',
174
- f'/* Build configuration list for PBXProject "{title}" */',
175
- )
176
- pbxproj_data = pbxproj_data.replace(
177
- '/* Build configuration list for PBXNativeTarget "stickers StickerPackExtension" */',
178
- f'/* Build configuration list for PBXNativeTarget "{title} StickerPackExtension" */',
179
- )
180
- pbxproj_data = pbxproj_data.replace(
181
- '/* Build configuration list for PBXNativeTarget "stickers" */',
182
- f'/* Build configuration list for PBXNativeTarget "{title}" */',
183
- )
184
- pbxproj_data = pbxproj_data.replace("com.niklaspeterson", f"com.{author}")
185
- pbxproj_data = pbxproj_data.replace(
186
- "stickers/Info.plist", f"{title}/Info.plist"
187
- )
188
-
189
- with open(
190
- pack_path / "stickers.xcodeproj/project.pbxproj",
191
- "w+",
192
- encoding="utf-8",
193
- ) as f:
194
- f.write(pbxproj_data)
195
-
196
- # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack
197
- stickers_path = (
198
- pack_path
199
- / "stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack"
200
- )
201
-
202
- for i in stickers_path.iterdir():
203
- if i.suffix == ".sticker":
204
- shutil.rmtree(stickers_path / i)
205
-
206
- stickers_lst: List[str] = []
207
- for i in sorted(self.opt_output.dir.iterdir()):
208
- if (
209
- CodecInfo.get_file_ext(i) == ".png"
210
- and i.stem != "cover"
211
- and i.name not in XCODE_IMESSAGE_ICONSET
212
- ):
213
- sticker_dir = f"{i.stem}.sticker" # 0.sticker
214
- stickers_lst.append(sticker_dir)
215
- # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker
216
- sticker_path = stickers_path / sticker_dir
217
- os.mkdir(sticker_path)
218
- # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker/0.png
219
- shutil.copy(self.opt_output.dir / i.name, sticker_path / i.name)
220
-
221
- sticker_json_content = {
222
- "info": {
223
- "author": "xcode",
224
- "version": 1,
225
- },
226
- "properties": {"filename": str(i)},
227
- }
228
-
229
- # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker/Contents.json
230
- with open(sticker_path / "Contents.json", "w+", encoding="utf-8") as f:
231
- json.dump(sticker_json_content, f, indent=2)
232
-
233
- # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Contents.json
234
- with open(stickers_path / "Contents.json", encoding="utf-8") as f:
235
- stickerpack_json_content: Dict[str, List[Dict[str, str]]] = json.load(f)
236
-
237
- stickerpack_json_content["stickers"] = []
238
- for sticker in stickers_lst:
239
- stickerpack_json_content["stickers"].append({"filename": sticker})
240
-
241
- with open(stickers_path / "Contents.json", "w+", encoding="utf-8") as f:
242
- json.dump(stickerpack_json_content, f, indent=2)
243
-
244
- # packname StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset
245
- iconset_path = (
246
- pack_path
247
- / "stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset"
248
- )
249
-
250
- for iconfile_name in iconset_path.iterdir():
251
- if Path(iconfile_name).suffix == ".png":
252
- os.remove(iconset_path / iconfile_name)
253
-
254
- icons_lst: List[str] = []
255
- for icon in XCODE_IMESSAGE_ICONSET:
256
- shutil.copy(self.opt_output.dir / icon, iconset_path / icon)
257
- icons_lst.append(icon)
258
-
259
- # packname/Info.plist
260
- plist_path = pack_path / "stickers/Info.plist"
261
- with open(plist_path, "rb") as f:
262
- plist_dict = plistlib.load(f)
263
- plist_dict["CFBundleDisplayName"] = title
264
-
265
- with open(plist_path, "wb+") as f:
266
- plistlib.dump(plist_dict, f)
267
-
268
- Path(pack_path, "stickers").rename(Path(pack_path, title))
269
- Path(pack_path, "stickers StickerPackExtension").rename(
270
- Path(pack_path, f"{title} StickerPackExtension")
271
- )
272
- Path(pack_path, "stickers.xcodeproj").rename(
273
- Path(pack_path, f"{title}.xcodeproj")
274
- )
275
-
276
- @staticmethod
277
- def start(
278
- opt_output: OutputOption,
279
- opt_comp: CompOption,
280
- opt_cred: CredOption,
281
- cb: CallbackProtocol,
282
- cb_return: CallbackReturn,
283
- ) -> List[str]:
284
- exporter = XcodeImessage(opt_output, opt_comp, opt_cred, cb, cb_return)
285
- return exporter.create_imessage_xcode()
1
+ #!/usr/bin/env python3
2
+ import copy
3
+ import json
4
+ import os
5
+ import plistlib
6
+ import shutil
7
+ import zipfile
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List, Tuple
10
+
11
+ from sticker_convert.converter import StickerConvert
12
+ from sticker_convert.definitions import ROOT_DIR
13
+ from sticker_convert.job_option import CompOption, CredOption, OutputOption
14
+ from sticker_convert.uploaders.upload_base import UploadBase
15
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
16
+ from sticker_convert.utils.files.metadata_handler import XCODE_IMESSAGE_ICONSET, MetadataHandler
17
+ from sticker_convert.utils.files.sanitize_filename import sanitize_filename
18
+ from sticker_convert.utils.media.codec_info import CodecInfo
19
+ from sticker_convert.utils.media.format_verify import FormatVerify
20
+ from sticker_convert.utils.translate import I
21
+
22
+
23
+ class XcodeImessage(UploadBase):
24
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
25
+ super().__init__(*args, **kwargs)
26
+ self.base_spec.set_size_max(500000)
27
+ self.base_spec.set_res(300)
28
+ self.base_spec.set_format(("png", ".apng", ".gif", ".jpeg", "jpg"))
29
+
30
+ self.small_spec = copy.deepcopy(self.base_spec)
31
+
32
+ self.medium_spec = copy.deepcopy(self.base_spec)
33
+ self.medium_spec.set_res(408)
34
+
35
+ self.large_spec = copy.deepcopy(self.base_spec)
36
+ self.large_spec.set_res(618)
37
+
38
+ def create_imessage_xcode(self) -> Tuple[int, int, List[str]]:
39
+ urls: List[str] = []
40
+ title, author, _ = MetadataHandler.get_metadata(
41
+ self.opt_output.dir,
42
+ title=self.opt_output.title,
43
+ author=self.opt_output.author,
44
+ )
45
+ if not author:
46
+ self.cb.put(
47
+ I("author is required for creating Xcode iMessage sticker pack")
48
+ )
49
+ return 0, 0, urls
50
+ if not title:
51
+ self.cb.put(I("title is required for creating Xcode iMessage sticker pack"))
52
+ return 0, 0, urls
53
+
54
+ author = author.replace(" ", "_")
55
+ title = title.replace(" ", "_")
56
+ packs = MetadataHandler.split_sticker_packs(
57
+ self.opt_output.dir,
58
+ title=title,
59
+ file_per_pack=100,
60
+ separate_image_anim=False,
61
+ )
62
+
63
+ res_choice = None
64
+ spec_choice = None
65
+ opt_comp_merged = copy.deepcopy(self.opt_comp)
66
+
67
+ stickers_total = 0
68
+ for pack_title, stickers in packs.items():
69
+ pack_title = sanitize_filename(pack_title)
70
+
71
+ for src in stickers:
72
+ self.cb.put(
73
+ I("Verifying {} for creating Xcode iMessage sticker pack").format(
74
+ src
75
+ )
76
+ )
77
+
78
+ fpath = Path(self.opt_output.dir, src)
79
+
80
+ if res_choice is None:
81
+ res_choice, _ = CodecInfo.get_file_res(fpath)
82
+
83
+ if res_choice == 618:
84
+ spec_choice = self.large_spec
85
+ elif res_choice == 408:
86
+ spec_choice = self.medium_spec
87
+ else:
88
+ # res_choice == 300
89
+ spec_choice = self.small_spec
90
+
91
+ opt_comp_merged.merge(spec_choice)
92
+
93
+ assert spec_choice
94
+ if not FormatVerify.check_file(src, spec=spec_choice):
95
+ StickerConvert.convert(
96
+ fpath, fpath, opt_comp_merged, self.cb, self.cb_return
97
+ )
98
+ stickers_total += 1
99
+
100
+ self.add_metadata(author, pack_title)
101
+ self.create_xcode_proj(author, pack_title)
102
+
103
+ result = Path(self.opt_output.dir / pack_title).as_posix()
104
+ self.cb.put(result)
105
+ urls.append(result)
106
+
107
+ return stickers_total, stickers_total, urls
108
+
109
+ def add_metadata(self, author: str, title: str) -> None:
110
+ first_image_path = Path(
111
+ self.opt_output.dir,
112
+ [
113
+ i
114
+ for i in sorted(self.opt_output.dir.iterdir())
115
+ if (self.opt_output.dir / i).is_file() and i.suffix == ".png"
116
+ ][0],
117
+ )
118
+ cover_path = MetadataHandler.get_cover(self.opt_output.dir)
119
+ if cover_path:
120
+ icon_source = cover_path
121
+ else:
122
+ icon_source = first_image_path
123
+
124
+ for icon, res in XCODE_IMESSAGE_ICONSET.items():
125
+ spec_cover = CompOption()
126
+ spec_cover.set_res_w(res[0])
127
+ spec_cover.set_res_h(res[1])
128
+ spec_cover.set_fps(0)
129
+
130
+ icon_path = self.opt_output.dir / icon
131
+ if Path(icon) in list(
132
+ self.opt_output.dir.iterdir()
133
+ ) and not FormatVerify.check_file(icon_path, spec=spec_cover):
134
+ StickerConvert.convert(
135
+ icon_path, icon_path, spec_cover, self.cb, self.cb_return
136
+ )
137
+ else:
138
+ StickerConvert.convert(
139
+ icon_source, icon_path, spec_cover, self.cb, self.cb_return
140
+ )
141
+
142
+ MetadataHandler.set_metadata(self.opt_output.dir, author=author, title=title)
143
+
144
+ def create_xcode_proj(self, author: str, title: str) -> None:
145
+ pack_path = self.opt_output.dir / title
146
+ if (ROOT_DIR / "ios-message-stickers-template.zip").is_file():
147
+ with zipfile.ZipFile(
148
+ ROOT_DIR / "ios-message-stickers-template.zip", "r"
149
+ ) as f:
150
+ f.extractall(pack_path)
151
+ elif (ROOT_DIR / "ios-message-stickers-template").is_dir():
152
+ shutil.copytree(ROOT_DIR / "ios-message-stickers-template", pack_path)
153
+ else:
154
+ self.cb.put(
155
+ I(
156
+ "Failed to create Xcode project: ios-message-stickers-template not found"
157
+ )
158
+ )
159
+
160
+ os.remove(pack_path / "README.md")
161
+ shutil.rmtree(
162
+ pack_path / "stickers.xcodeproj/project.xcworkspace",
163
+ ignore_errors=True,
164
+ )
165
+ shutil.rmtree(pack_path / "stickers.xcodeproj/xcuserdata", ignore_errors=True)
166
+
167
+ with open(
168
+ pack_path / "stickers.xcodeproj/project.pbxproj",
169
+ encoding="utf-8",
170
+ ) as f:
171
+ pbxproj_data = f.read()
172
+
173
+ pbxproj_data = pbxproj_data.replace(
174
+ "stickers StickerPackExtension", f"{title} StickerPackExtension"
175
+ )
176
+ pbxproj_data = pbxproj_data.replace("stickers.app", f"{title}.app")
177
+ pbxproj_data = pbxproj_data.replace("/* stickers */", f"/* {title} */")
178
+ pbxproj_data = pbxproj_data.replace("name = stickers", f"name = {title}")
179
+ pbxproj_data = pbxproj_data.replace(
180
+ "productName = stickers", f"productName = {title}"
181
+ )
182
+ pbxproj_data = pbxproj_data.replace(
183
+ '/* Build configuration list for PBXProject "stickers" */',
184
+ f'/* Build configuration list for PBXProject "{title}" */',
185
+ )
186
+ pbxproj_data = pbxproj_data.replace(
187
+ '/* Build configuration list for PBXNativeTarget "stickers StickerPackExtension" */',
188
+ f'/* Build configuration list for PBXNativeTarget "{title} StickerPackExtension" */',
189
+ )
190
+ pbxproj_data = pbxproj_data.replace(
191
+ '/* Build configuration list for PBXNativeTarget "stickers" */',
192
+ f'/* Build configuration list for PBXNativeTarget "{title}" */',
193
+ )
194
+ pbxproj_data = pbxproj_data.replace("com.niklaspeterson", f"com.{author}")
195
+ pbxproj_data = pbxproj_data.replace(
196
+ "stickers/Info.plist", f"{title}/Info.plist"
197
+ )
198
+
199
+ with open(
200
+ pack_path / "stickers.xcodeproj/project.pbxproj",
201
+ "w+",
202
+ encoding="utf-8",
203
+ ) as f:
204
+ f.write(pbxproj_data)
205
+
206
+ # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack
207
+ stickers_path = (
208
+ pack_path
209
+ / "stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack"
210
+ )
211
+
212
+ for i in stickers_path.iterdir():
213
+ if i.suffix == ".sticker":
214
+ shutil.rmtree(stickers_path / i)
215
+
216
+ stickers_lst: List[str] = []
217
+ for i in sorted(self.opt_output.dir.iterdir()):
218
+ if (
219
+ CodecInfo.get_file_ext(i) == ".png"
220
+ and i.stem != "cover"
221
+ and i.name not in XCODE_IMESSAGE_ICONSET
222
+ ):
223
+ sticker_dir = f"{i.stem}.sticker" # 0.sticker
224
+ stickers_lst.append(sticker_dir)
225
+ # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker
226
+ sticker_path = stickers_path / sticker_dir
227
+ os.mkdir(sticker_path)
228
+ # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker/0.png
229
+ shutil.copy(self.opt_output.dir / i.name, sticker_path / i.name)
230
+
231
+ sticker_json_content = {
232
+ "info": {
233
+ "author": "xcode",
234
+ "version": 1,
235
+ },
236
+ "properties": {"filename": str(i)},
237
+ }
238
+
239
+ # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/0.sticker/Contents.json
240
+ with open(sticker_path / "Contents.json", "w+", encoding="utf-8") as f:
241
+ json.dump(sticker_json_content, f, indent=2)
242
+
243
+ # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Contents.json
244
+ with open(stickers_path / "Contents.json", encoding="utf-8") as f:
245
+ stickerpack_json_content: Dict[str, List[Dict[str, str]]] = json.load(f)
246
+
247
+ stickerpack_json_content["stickers"] = []
248
+ for sticker in stickers_lst:
249
+ stickerpack_json_content["stickers"].append({"filename": sticker})
250
+
251
+ with open(stickers_path / "Contents.json", "w+", encoding="utf-8") as f:
252
+ json.dump(stickerpack_json_content, f, indent=2)
253
+
254
+ # packname StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset
255
+ iconset_path = (
256
+ pack_path
257
+ / "stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset"
258
+ )
259
+
260
+ for iconfile_name in iconset_path.iterdir():
261
+ if Path(iconfile_name).suffix == ".png":
262
+ os.remove(iconset_path / iconfile_name)
263
+
264
+ icons_lst: List[str] = []
265
+ for icon in XCODE_IMESSAGE_ICONSET:
266
+ shutil.copy(self.opt_output.dir / icon, iconset_path / icon)
267
+ icons_lst.append(icon)
268
+
269
+ # packname/Info.plist
270
+ plist_path = pack_path / "stickers/Info.plist"
271
+ with open(plist_path, "rb") as f:
272
+ plist_dict = plistlib.load(f)
273
+ plist_dict["CFBundleDisplayName"] = title
274
+
275
+ with open(plist_path, "wb+") as f:
276
+ plistlib.dump(plist_dict, f)
277
+
278
+ Path(pack_path, "stickers").rename(Path(pack_path, title))
279
+ Path(pack_path, "stickers StickerPackExtension").rename(
280
+ Path(pack_path, f"{title} StickerPackExtension")
281
+ )
282
+ Path(pack_path, "stickers.xcodeproj").rename(
283
+ Path(pack_path, f"{title}.xcodeproj")
284
+ )
285
+
286
+ @staticmethod
287
+ def start(
288
+ opt_output: OutputOption,
289
+ opt_comp: CompOption,
290
+ opt_cred: CredOption,
291
+ cb: CallbackProtocol,
292
+ cb_return: CallbackReturn,
293
+ ) -> Tuple[int, int, List[str]]:
294
+ exporter = XcodeImessage(opt_output, opt_comp, opt_cred, cb, cb_return)
295
+ return exporter.create_imessage_xcode()