You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
4.3 KiB

  1. # Copyright (c) 2020 Tulir Asokan
  2. #
  3. # This Source Code Form is subject to the terms of the Mozilla Public
  4. # License, v. 2.0. If a copy of the MPL was not distributed with this
  5. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. from typing import Dict, Optional
  7. from hashlib import sha256
  8. import argparse
  9. import os.path
  10. import asyncio
  11. import string
  12. import json
  13. import magic
  14. from .lib import matrix, util
  15. def convert_name(name: str) -> str:
  16. name_translate = {
  17. ord(" "): ord("_"),
  18. }
  19. allowed_chars = string.ascii_letters + string.digits + "_-/.#"
  20. return "".join(filter(lambda char: char in allowed_chars, name.translate(name_translate)))
  21. async def upload_sticker(file: str, directory: str, old_stickers: Dict[str, matrix.StickerInfo]
  22. ) -> Optional[matrix.StickerInfo]:
  23. if file.startswith("."):
  24. return None
  25. path = os.path.join(directory, file)
  26. if not os.path.isfile(path):
  27. return None
  28. mime = magic.from_file(path, mime=True)
  29. if not mime.startswith("image/"):
  30. return None
  31. print(f"Processing {file}", end="", flush=True)
  32. try:
  33. with open(path, "rb") as image_file:
  34. image_data = image_file.read()
  35. except Exception as e:
  36. print(f"... failed to read file: {e}")
  37. return None
  38. name = os.path.splitext(file)[0]
  39. # If the name starts with "number-", remove the prefix
  40. name_split = name.split("-", 1)
  41. if len(name_split) == 2 and name_split[0].isdecimal():
  42. name = name_split[1]
  43. sticker_id = f"sha256:{sha256(image_data).hexdigest()}"
  44. print(".", end="", flush=True)
  45. if sticker_id in old_stickers:
  46. sticker = {
  47. **old_stickers[sticker_id],
  48. "body": name,
  49. }
  50. print(f".. using existing upload")
  51. else:
  52. image_data, width, height = util.convert_image(image_data)
  53. print(".", end="", flush=True)
  54. mxc = await matrix.upload(image_data, "image/png", file)
  55. print(".", end="", flush=True)
  56. sticker = util.make_sticker(mxc, width, height, len(image_data), name)
  57. sticker["id"] = sticker_id
  58. print(" uploaded", flush=True)
  59. return sticker
  60. async def main(args: argparse.Namespace) -> None:
  61. await matrix.load_config(args.config)
  62. dirname = os.path.basename(os.path.abspath(args.path))
  63. meta_path = os.path.join(args.path, "pack.json")
  64. try:
  65. with open(meta_path) as pack_file:
  66. pack = json.load(pack_file)
  67. print(f"Loaded existing pack meta from {meta_path}")
  68. except FileNotFoundError:
  69. pack = {
  70. "title": args.title or dirname,
  71. "id": args.id or convert_name(dirname),
  72. "stickers": [],
  73. }
  74. old_stickers = {}
  75. else:
  76. old_stickers = {sticker["id"]: sticker for sticker in pack["stickers"]}
  77. pack["stickers"] = []
  78. for file in sorted(os.listdir(args.path)):
  79. sticker = await upload_sticker(file, args.path, old_stickers=old_stickers)
  80. if sticker:
  81. pack["stickers"].append(sticker)
  82. with open(meta_path, "w") as pack_file:
  83. json.dump(pack, pack_file)
  84. print(f"Wrote pack to {meta_path}")
  85. if args.add_to_index:
  86. picker_file_name = f"{pack['id']}.json"
  87. picker_pack_path = os.path.join(args.add_to_index, picker_file_name)
  88. with open(picker_pack_path, "w") as pack_file:
  89. json.dump(pack, pack_file)
  90. print(f"Copied pack to {picker_pack_path}")
  91. util.add_to_index(picker_file_name, args.add_to_index)
  92. parser = argparse.ArgumentParser()
  93. parser.add_argument("--config",
  94. help="Path to JSON file with Matrix homeserver and access_token",
  95. type=str, default="config.json", metavar="file")
  96. parser.add_argument("--title", help="Override the sticker pack displayname", type=str,
  97. metavar="title")
  98. parser.add_argument("--id", help="Override the sticker pack ID", type=str, metavar="id")
  99. parser.add_argument("--add-to-index", help="Sticker picker pack directory (usually 'web/packs/')",
  100. type=str, metavar="path")
  101. parser.add_argument("path", help="Path to the sticker pack directory", type=str)
  102. def cmd():
  103. asyncio.get_event_loop().run_until_complete(main(parser.parse_args()))
  104. if __name__ == "__main__":
  105. cmd()