export.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/env python3
  2. import os, pathlib
  3. import gkeepapi
  4. import frontmatter
  5. import click
  6. from pathvalidate import sanitize_filename
  7. def login(user_email: str, password: str) -> gkeepapi.Keep:
  8. keep = gkeepapi.Keep()
  9. try:
  10. keep.login(user_email, password)
  11. except Exception:
  12. raise click.BadParameter("Login failed.")
  13. return keep
  14. def process_note(note: gkeepapi._node.Note) -> frontmatter.Post:
  15. metadata = {
  16. "id": note.id,
  17. "title": note.title,
  18. "pinned": note.pinned,
  19. "trashed": note.trashed,
  20. "deleted": note.deleted,
  21. "color": note.color.name,
  22. "type": note.type.name,
  23. "parent_id": note.parent_id,
  24. "sort": note.sort,
  25. "url": note.url,
  26. "timestamps": {
  27. "created": note.timestamps.created.timestamp(),
  28. "edited": note.timestamps.edited.timestamp(),
  29. "updated": note.timestamps.updated.timestamp(),
  30. },
  31. }
  32. if note.timestamps.trashed:
  33. metadata["timestamps"]["trashed"] = note.timestamps.trashed.timestamp()
  34. if note.timestamps.deleted:
  35. metadata["timestamps"]["deleted"] = note.timestamps.deleted.timestamp()
  36. return frontmatter.Post(note.text, handler=None, **metadata)
  37. @click.command()
  38. @click.option(
  39. "--directory",
  40. "-d",
  41. default="./gkeep-export",
  42. help="Output directory for exported notes",
  43. )
  44. @click.option(
  45. "--user",
  46. "-u",
  47. default=lambda: os.environ.get("GKEEP_USER"),
  48. prompt=True,
  49. help="Google account email (environment variable 'GKEEP_USER')",
  50. )
  51. @click.option(
  52. "--password",
  53. "-p",
  54. default=lambda: os.environ.get("GKEEP_PASSWORD"),
  55. prompt=True,
  56. help="Google account password (environment variable 'GKEEP_PASSWORD')",
  57. hide_input=True,
  58. )
  59. def main(directory, user, password):
  60. """A simple utility to export google keep notes to markdown files with metadata stored as a frontmatter header."""
  61. outpath = pathlib.Path(directory).resolve()
  62. click.echo(f"Output directory: {outpath}")
  63. click.echo("Logging in.")
  64. keep = login(user, password)
  65. click.echo("Beginning note export.")
  66. if not outpath.exists():
  67. click.echo("output directory does not exist, creating.")
  68. outpath.mkdir(parents=True)
  69. notes = keep.all()
  70. note_count = 0
  71. for note in notes:
  72. note_count += 1
  73. click.echo(f"Processing note #{note_count}")
  74. post = process_note(note)
  75. outfile = (
  76. outpath
  77. / f'{sanitize_filename(f"{note_count:04} - " + post.metadata["title"],max_len=135)} .md'
  78. )
  79. with outfile.open("wb") as fp:
  80. frontmatter.dump(post, fp)
  81. click.echo("Done.")
  82. if __name__ == "__main__":
  83. main()