make_readme.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/env python3
  2. """
  3. yt-dlp --help | make_readme.py
  4. This must be run in a console of correct width
  5. """
  6. # Allow direct execution
  7. import os
  8. import sys
  9. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  10. import functools
  11. import re
  12. from devscripts.utils import read_file, write_file
  13. README_FILE = 'README.md'
  14. OPTIONS_START = 'General Options:'
  15. OPTIONS_END = 'CONFIGURATION'
  16. EPILOG_START = 'See full documentation'
  17. ALLOWED_OVERSHOOT = 2
  18. DISABLE_PATCH = object()
  19. def take_section(text, start=None, end=None, *, shift=0):
  20. return text[
  21. text.index(start) + shift if start else None:
  22. text.index(end) + shift if end else None
  23. ]
  24. def apply_patch(text, patch):
  25. return text if patch[0] is DISABLE_PATCH else re.sub(*patch, text)
  26. options = take_section(sys.stdin.read(), f'\n {OPTIONS_START}', f'\n{EPILOG_START}', shift=1)
  27. max_width = max(map(len, options.split('\n')))
  28. switch_col_width = len(re.search(r'(?m)^\s{5,}', options).group())
  29. delim = f'\n{" " * switch_col_width}'
  30. PATCHES = (
  31. ( # Standardize `--update` message
  32. r'(?m)^( -U, --update\s+).+(\n \s.+)*$',
  33. r'\1Update this program to the latest version',
  34. ),
  35. ( # Headings
  36. r'(?m)^ (\w.+\n)( (?=\w))?',
  37. r'## \1',
  38. ),
  39. ( # Fixup `--date` formatting
  40. rf'(?m)( --date DATE.+({delim}[^\[]+)*)\[.+({delim}.+)*$',
  41. (rf'\1[now|today|yesterday][-N[day|week|month|year]].{delim}'
  42. f'E.g. "--date today-2weeks" downloads only{delim}'
  43. 'videos uploaded on the same day two weeks ago'),
  44. ),
  45. ( # Do not split URLs
  46. rf'({delim[:-1]})? (?P<label>\[\S+\] )?(?P<url>https?({delim})?:({delim})?/({delim})?/(({delim})?\S+)+)\s',
  47. lambda mobj: ''.join((delim, mobj.group('label') or '', re.sub(r'\s+', '', mobj.group('url')), '\n')),
  48. ),
  49. ( # Do not split "words"
  50. rf'(?m)({delim}\S+)+$',
  51. lambda mobj: ''.join((delim, mobj.group(0).replace(delim, ''))),
  52. ),
  53. ( # Allow overshooting last line
  54. rf'(?m)^(?P<prev>.+)${delim}(?P<current>.+)$(?!{delim})',
  55. lambda mobj: (mobj.group().replace(delim, ' ')
  56. if len(mobj.group()) - len(delim) + 1 <= max_width + ALLOWED_OVERSHOOT
  57. else mobj.group()),
  58. ),
  59. ( # Avoid newline when a space is available b/w switch and description
  60. DISABLE_PATCH, # This creates issues with prepare_manpage
  61. r'(?m)^(\s{4}-.{%d})(%s)' % (switch_col_width - 6, delim),
  62. r'\1 ',
  63. ),
  64. ( # Replace brackets with a Markdown link
  65. r'SponsorBlock API \((http.+)\)',
  66. r'[SponsorBlock API](\1)',
  67. ),
  68. )
  69. readme = read_file(README_FILE)
  70. write_file(README_FILE, ''.join((
  71. take_section(readme, end=f'## {OPTIONS_START}'),
  72. functools.reduce(apply_patch, PATCHES, options),
  73. take_section(readme, f'# {OPTIONS_END}'),
  74. )))