This repository has been archived by the owner on Nov 11, 2022. It is now read-only.
forked from goatcorp/DalamudPlugins
-
Notifications
You must be signed in to change notification settings - Fork 30
/
generate_pluginmaster.py
221 lines (189 loc) · 7.9 KB
/
generate_pluginmaster.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import json
import os
import codecs
from time import time
from sys import argv
from pathlib import Path
from os import listdir
from os.path import getmtime, isfile, join, exists
from zipfile import ZipFile, ZIP_DEFLATED
import requests
import hashlib
import copy
import re
md5 = hashlib.md5()
def get_md5(text: str):
md5.update(text.encode())
return md5.hexdigest()
# DOWNLOAD_URL = 'https://dalamudplugins-1253720819.cos.ap-nanjing.myqcloud.com/plugins/{plugin_name}/latest.zip'
DOWNLOAD_URL = 'https://service-knj2phup-1253720819.sh.apigw.tencentcs.com/release/dalamudcounter-1623520723?plugin={plugin_name}&isUpdate={is_update}&isTesting={is_testing}&branch=cn-api5'
IMAGE_URL = 'https://dalamudplugins-1253720819.cos.ap-nanjing.myqcloud.com/cn-api5/plugins/{plugin_name}/images/{image_file}'
DEFAULTS = {
'IsHide': False,
'IsTestingExclusive': False,
'ApplicableVersion': 'any',
}
DUPLICATES = {
'DownloadLinkInstall': ['DownloadLinkTesting', 'DownloadLinkUpdate'],
}
TRIMMED_KEYS = [
'Author',
'Name',
'Description',
'InternalName',
'AssemblyVersion',
'RepoUrl',
'ApplicableVersion',
'Tags',
'DalamudApiLevel',
'Punchline',
'ImageUrls',
'IconUrl'
]
def main():
# extract the manifests from inside the zip files
master = extract_manifests()
# trim the manifests
master = [trim_manifest(manifest) for manifest in master]
# download images to local
handle_images(master)
# convert the list of manifests into a master list
add_extra_fields(master)
# write the master
write_master(master)
# update the LastUpdated field in master
last_updated()
# update the Markdown
update_md(master)
def download_image(plugin_name, image_urls):
image_dir = f"./plugins/{plugin_name}/images/"
Path(image_dir).mkdir(parents=True, exist_ok=True)
images_map = {}
allowed_images = []
for url in image_urls:
if not url: continue
url_md5 = get_md5(url)
image_filename = f"{url_md5}.{url.split('.')[-1]}"
image_filepath = join(image_dir, image_filename)
allowed_images.append(image_filename)
if not exists(image_filepath):
with open(image_filepath, "wb") as f:
print(f"Downloading {url} -> {image_filepath}")
img = requests.get(url, timeout=5)
f.write(img.content)
images_map[url] = IMAGE_URL.format(plugin_name=plugin_name, image_file=image_filename)
all_files = [f for f in listdir(image_dir) if isfile(join(image_dir, f))]
for f in all_files:
if f not in allowed_images:
os.remove(join(image_dir, f))
return images_map
def handle_images(manifests):
return
for manifest in manifests:
image_urls = manifest.get('ImageUrls', []) + [manifest.get('IconUrl', '')]
images_map = download_image(manifest["InternalName"], image_urls)
if 'ImageUrls' in manifest:
manifest['ImageUrls'] = list(map(lambda x: images_map.get(x, x), manifest['ImageUrls']))
if 'IconUrl' in manifest:
manifest['IconUrl'] = images_map.get(manifest['IconUrl'], manifest['IconUrl'])
def extract_manifests():
manifests = []
testing_manifests = []
for dirpath, dirnames, filenames in os.walk('./plugins'):
if len(filenames) == 0 or 'latest.zip' not in filenames:
continue
plugin_name = dirpath.split('/')[-1].split('\\')[-1]
latest_json = f'{dirpath}/{plugin_name}.json'
with codecs.open(latest_json, "r", "utf-8") as f:
content = f.read()
if content.startswith(u'\ufeff'):
content = content.encode('utf8')[3:].decode('utf8')
content=clean_json(content)
manifests.append(json.loads(content))
for dirpath, dirnames, filenames in os.walk('./testing'):
if len(filenames) == 0 or 'latest.zip' not in filenames:
continue
plugin_name = dirpath.split('/')[-1].split('\\')[-1]
latest_json = f'{dirpath}/{plugin_name}.json'
with codecs.open(latest_json, "r", "utf-8") as f:
content = f.read()
if content.startswith(u'\ufeff'):
content = content.encode('utf8')[3:].decode('utf8')
content=clean_json(content)
testing_manifests.append(json.loads(content))
translations = {}
for manifest in manifests + testing_manifests:
translations[manifest["InternalName"]] = manifest.get('Description')
if manifest.get('Punchline'):
translations[manifest["InternalName"] + "-Punchline"] = manifest.get('Punchline')
with codecs.open("translations/en.json", "w", "utf-8") as f:
json.dump(translations, f, indent=4)
with codecs.open("translations/cn.json", "r", "utf-8") as f:
cn_translations = json.load(f)
for manifest in manifests + testing_manifests:
if manifest["InternalName"] in cn_translations:
cn_desc = cn_translations[manifest["InternalName"]]
if cn_desc:
manifest['Description'] = cn_desc
if (manifest["InternalName"] + "-Punchline") in cn_translations:
cn_punch = cn_translations[manifest["InternalName"] + "-Punchline"]
if cn_punch:
manifest['Punchline'] = cn_punch
return manifests
def add_extra_fields(manifests):
downloadcounts = {}
if os.path.exists('downloadcounts.json'):
with open('downloadcounts.json', 'r') as f:
downloadcounts = json.load(f)
categorymap = {}
if os.path.exists('categoryfallbacks.json'):
with open('categoryfallbacks.json', 'r') as f:
categorymap = json.load(f)
for manifest in manifests:
# generate the download link from the internal assembly name
manifest['DownloadLinkInstall'] = DOWNLOAD_URL.format(plugin_name=manifest["InternalName"], is_update=False, is_testing=False)
manifest['DownloadLinkUpdate'] = DOWNLOAD_URL.format(plugin_name=manifest["InternalName"], is_update=True, is_testing=False)
manifest['DownloadLinkTesting'] = DOWNLOAD_URL.format(plugin_name=manifest["InternalName"], is_update=False, is_testing=True)
# add default values if missing
for k, v in DEFAULTS.items():
if k not in manifest:
manifest[k] = v
# duplicate keys as specified in DUPLICATES
for source, keys in DUPLICATES.items():
for k in keys:
if k not in manifest:
manifest[k] = manifest[source]
manifest['DownloadCount'] = downloadcounts.get(manifest["InternalName"], 0)
manifest['CategoryTags'] = categorymap.get(manifest["InternalName"], categorymap.get(manifest["Name"], []))
def write_master(master):
# write as pretty json
with open('pluginmaster.json', 'w') as f:
json.dump(master, f, indent=4)
def trim_manifest(plugin):
return {k: plugin[k] for k in TRIMMED_KEYS if k in plugin}
def last_updated():
with open('pluginmaster.json') as f:
master = json.load(f)
for plugin in master:
latest = f'plugins/{plugin["InternalName"]}/latest.zip'
modified = int(getmtime(latest))
if 'LastUpdated' not in plugin or modified != int(plugin['LastUpdated']):
plugin['LastUpdated'] = str(modified)
with open('pluginmaster.json', 'w') as f:
json.dump(master, f, indent=4)
def update_md(master):
with codecs.open('mdtemplate.txt', 'r', 'utf8') as mdt:
md = mdt.read().strip()
for plugin in master:
desc = plugin.get('Description', '')
desc = desc.replace('\n', '<br>')
md += f"\n| {plugin['Name']} | {plugin['Author']} | {desc} |"
with codecs.open('plugins.md', 'w', 'utf8') as f:
f.write(md)
def clean_json(str):
str = re.sub(r",\s*}", "}", str)
str = re.sub(r",\s*]", "]", str)
# print(str)
return str
if __name__ == '__main__':
main()