cli.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #!/usr/bin/env python3
  2. from argparse import ArgumentParser
  3. import os
  4. import subprocess
  5. import sys
  6. import tempfile
  7. import marxbook
  8. import marxbook.extract
  9. def get_parser():
  10. p = ArgumentParser()
  11. p.add_argument("--store-dir")
  12. p.add_argument("--editor", default="sensible-editor")
  13. p.add_argument("--batch", default=False, action="store_true")
  14. p.set_defaults(func=None)
  15. subcommands = p.add_subparsers(help="Sub-commands")
  16. list_p = subcommands.add_parser("list")
  17. list_p.add_argument("--format", default="{Path}\t{Tag}\t{Title}\t{Url}", dest='fmt')
  18. list_p.add_argument("folder", nargs="?", default="")
  19. list_p.set_defaults(func=main_list)
  20. add_p = subcommands.add_parser("add")
  21. add_p.add_argument("--folder", default="")
  22. add_p.add_argument("--tag", help="Comma-separated list of tags", default="")
  23. add_p.add_argument("--title", help="If omitted, auto-fetch")
  24. add_p.add_argument("--description", help="If omitted, auto-fetch")
  25. add_p.add_argument("url", nargs="?")
  26. add_p.set_defaults(func=main_add)
  27. return p
  28. def main():
  29. p = get_parser()
  30. args = p.parse_args()
  31. if args.func is None:
  32. print("Must specify a subcommand", file=sys.stderr)
  33. return 2
  34. store = marxbook.Store(args.store_dir)
  35. args.func(store, args)
  36. def main_list(store, args):
  37. for mark in store.folder(args.folder):
  38. markdata = {"Folder": os.path.dirname(mark['Path'])}
  39. markdata.update(mark)
  40. markdata['Tag'] = ','.join(mark['Tag'])
  41. print(args.fmt.replace(r'\t', '\t').format(**markdata))
  42. def edit_before_add(data: dict, args) -> dict:
  43. ser = marxbook.Serializer()
  44. fd, fpath = tempfile.mkstemp()
  45. buf = os.fdopen(fd, "w")
  46. buf.write(ser.encode(data))
  47. buf.close()
  48. proc = subprocess.Popen([args.editor, fpath])
  49. proc.communicate()
  50. with open(fpath) as buf:
  51. read_data = ser.decode(buf.read())
  52. os.unlink(fpath)
  53. data = {}
  54. for key in read_data:
  55. data[key.lower()] = read_data[key]
  56. return data
  57. def main_add(store, args):
  58. store = store.folder(args.folder)
  59. batch = args.batch
  60. if args.url is not None:
  61. urls = [args.url]
  62. else:
  63. batch = True
  64. urls = []
  65. for line in sys.stdin.readlines():
  66. urls.append(line.strip())
  67. for url in urls:
  68. data = dict(title=args.title, description=args.description, url=url)
  69. data['tag'] = [t.strip() for t in args.tag.split(",")]
  70. if args.title is None or args.description is None:
  71. _title, _description, _keys, mime, bad = marxbook.extract.network_handler(url)
  72. if not args.title:
  73. data["title"] = _title
  74. if not args.description:
  75. data["description"] = _description
  76. if not batch:
  77. data = edit_before_add(data, args)
  78. store.add(**data)
  79. print(urls)
  80. if __name__ == "__main__":
  81. ret = main()
  82. if type(ret) is int:
  83. sys.exit(ret)