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.

yarrbox.py 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #!/usr/bin/env python3
  2. import os
  3. from collections import OrderedDict
  4. import sys
  5. import subprocess
  6. import getpass
  7. import json
  8. # Each entry here is key => (label, hide input)
  9. PROPS = OrderedDict([
  10. ('net.vpn.host', ('VPN Provider', 'See https://github.com/sscraggles/docker-deluge-openvpn for options')),
  11. ('net.vpn.config', ('VPN Config', 'See README for above, for PIA just say "Netherlands"')),
  12. ('net.vpn.username', ('VPN Username', None)),
  13. ('net.vpn.password', ('VPN Password', None)),
  14. ('vol.media.movies', ('Movies Storage Path', None)),
  15. ('vol.media.tv', ('TV Storage Path', None)),
  16. ('vol.media.anime', ('Anime Storage Path', None)),
  17. ('vol.conf.torrent', ('Torrent Data Dir', 'Directory for torrent client(s) to store configs and state')),
  18. ('vol.conf.yarr', ('Yarrbox Config Dir', 'Directory for Bootybot to store generated configs for live use')),
  19. ('vol.conf.plex', ('Plex Data Dir', 'Directory for all of Plex\'s stuff (databases, etc.)')),
  20. ('vol.ingest.torrent', ('Torrent Ingest Dir', 'Directory to drop .torrent files to download through VPN')),
  21. ('vol.ingest.media', ('Media Ingest Dir', 'Directory to drop media files archives for gangplank/bootybot to deal with')),
  22. ('vol.log.yarr', ('Yarrbox Logs Dir', 'Yarrbox logs dirs')),
  23. ('vol.torrent.active', ('Torrent Download Dir', 'Directory for actively downloading torrents to be stored')),
  24. ('vol.torrent.seed', ('Torrent Seeding Dir', 'Directory to move torrents after download finished for seeding')),
  25. ('vol.work.plextrans', ('Plex Transcode Dir', 'Directory for Plex to store certain transcoded files')),
  26. ('vol.work.yarr', ('Yarrbox Work Dirs', 'Directory where Yarrbox scripts store work data')),
  27. ])
  28. PROMPT = '> '
  29. def ask_config_opt(config, key):
  30. label, desc = PROPS[key]
  31. nodisp = 'password' in key
  32. # Print titles
  33. title = '= ' + label + ' ='
  34. bars = '=' * len(title)
  35. print(bars + '\n' + title + '\n' + bars)
  36. if desc is not None:
  37. print(desc)
  38. # Current state stuff.
  39. if key in config:
  40. if not nodisp:
  41. print('Current: \'' + config[key] + '\'')
  42. # Actually ask for input.
  43. if not nodisp:
  44. val = input(PROMPT)
  45. if len(val) > 0:
  46. config[key] = val
  47. else:
  48. val = getpass.getpass('(hidden) ' + PROMPT)
  49. if len(val) > 0:
  50. config[key] = val
  51. def apply_template_settings(tmplt, settings):
  52. cur = tmplt
  53. for k, v in settings.items():
  54. cur = cur.replace('${' + k + '}', v)
  55. return cur
  56. def read_config():
  57. try:
  58. with open('config.json', 'r') as f:
  59. return json.loads(f.read())
  60. except e:
  61. print('error loading config, is it missing or corrupt?', e)
  62. sys.exit(1)
  63. def save_config(cfg):
  64. try:
  65. with open('config.json', 'w') as f:
  66. f.write(json.dumps(cfg, sort_keys=True, indent=' '))
  67. f.write('\n') # json.dumps doesn't put trailing newline
  68. except e:
  69. print('error writing config, do we have write perms?', e)
  70. sys.exit(1)
  71. USAGE_STR = 'usage: yarrbox.py <init|edit|generate>'
  72. def print_ascii_art():
  73. art = 'Yarrbox - Boxing your yarrs since 2019' # fallback text
  74. try:
  75. artfile = 'yb-art.txt'
  76. if os.getenv('TERM') == 'xterm-256color':
  77. artfile = 'yb-art-lol.txt'
  78. with open(artfile, 'r') as f:
  79. art = f.read()
  80. except:
  81. pass
  82. print(art)
  83. def main():
  84. if len(sys.argv) != 2:
  85. print(USAGE_STR)
  86. sys.exit(1)
  87. command = sys.argv[1]
  88. if command == 'init':
  89. print_ascii_art()
  90. # Check if a config already exists
  91. if os.path.exists('config.json'):
  92. print('A config exists here, overwrite? [y/n, default: n] ', end='', flush=True)
  93. yesno = input()
  94. if yesno != 'y':
  95. print('leaving config unchanged')
  96. sys.exit(1)
  97. # Make a new config object and read all the properties.
  98. cfg = {}
  99. for k in PROPS:
  100. ask_config_opt(cfg, k)
  101. print('')
  102. # Write it to file
  103. save_config(cfg)
  104. elif command == 'edit':
  105. print_ascii_art()
  106. print('Leave options blank to leave unchanged!\n')
  107. cfg = read_config()
  108. # Go through all the properties again and reread them.
  109. for k in PROPS:
  110. ask_config_opt(cfg, k)
  111. print('')
  112. # Write it back.
  113. save_config(cfg)
  114. elif command == 'generate':
  115. # Load the config.
  116. cfg = read_config()
  117. # Read the template.
  118. tmplt = None
  119. try:
  120. with open('compose-template.yml', 'r') as f:
  121. tmplt = f.read()
  122. except e:
  123. print('error reading template:', e)
  124. sys.exit(1)
  125. # Fill in the template and save it.
  126. gen = apply_template_settings(tmplt, cfg)
  127. try:
  128. with open('docker-compose.yml', 'w') as f:
  129. f.write(gen)
  130. except e:
  131. print('error writing generated file, do we have write perms?', e)
  132. sys.exit(1)
  133. else:
  134. print(USAGE_STR)
  135. if __name__ == '__main__':
  136. main()