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.

преди 3 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. # Standard library packages
  2. import logging
  3. import re
  4. from typing import AnyStr
  5. import sys
  6. import configparser
  7. import argparse
  8. # Third-party packages
  9. from pathlib import Path
  10. logger = logging.getLogger('main.' + __name__)
  11. __version__ = "1.5.1"
  12. def get_valid_filename(s: str) -> AnyStr:
  13. """
  14. Return the given string converted to a string that can be used for a clean
  15. filename. Remove leading and trailing spaces; convert other spaces to
  16. underscores; and remove anything that is not an alphanumeric, dash,
  17. underscore, or dot.
  18. :param s: str: A string that needs to be converted
  19. :return: str: A string with a clean filename
  20. """
  21. s = str(s).strip().replace(' ', '_')
  22. return re.sub(r'(?u)[^-\w.]', '', s)
  23. def count_values_dict(dict):
  24. """
  25. Count the values in a dictionary.
  26. """
  27. return sum([len(dict[x]) for x in dict])
  28. def fatal_error(msg):
  29. """
  30. Immediately exit and show an error to stderr and not log it
  31. Usually used argument, file or other simple errors that should not be logged as otherwise it creates noise
  32. :param msg: str
  33. :return:
  34. """
  35. print(msg, file=sys.stderr)
  36. sys.exit(1)
  37. class GetArgs:
  38. def __init__(self):
  39. parser = argparse.ArgumentParser()
  40. parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + __version__)
  41. parser.add_argument('-d', '--debug', help='Enable debug mode', action='store_true')
  42. parser.add_argument("-u", "--urls", help="JPS URL for a group, or multiple individual releases URLs to be added to the same group", type=str)
  43. parser.add_argument("-n", "--dryrun", help="Just parse url and show the output, do not add the torrent to SM", action="store_true")
  44. parser.add_argument("-b", "--batchuser", help="User id for batch user operations, default is user id of SM Username specified in jps2sm.cfg")
  45. parser.add_argument("-U", "--batchuploaded", help="(Batch mode only) Upload all releases uploaded by you or, if provided, user id specified by --batchuser", action="store_true")
  46. parser.add_argument("-S", "--batchseeding", help="(Batch mode only) Upload all releases currently seeding by you or, if provided, user id specified by --batchuser", action="store_true")
  47. parser.add_argument("--batchsnatched", help="(Batch mode only) Upload all releases snatched by you or, if provided, user id specified by --batchuser", action="store_true")
  48. parser.add_argument("-s", "--batchstart", help="(Batch mode only) Start at this page", type=int)
  49. parser.add_argument("-e", "--batchend", help="(Batch mode only) End at this page", type=int)
  50. parser.add_argument("-exc", "--exccategory", help="(Batch mode only) Exclude a JPS category from upload", type=str)
  51. parser.add_argument("-exf", "--excaudioformat", help="(Batch mode only) Exclude an audioformat from upload", type=str)
  52. parser.add_argument("-exm", "--excmedia", help="(Batch mode only) Exclude a media from upload", type=str)
  53. parser.add_argument("-m", "--mediainfo", help="Search and get mediainfo data from the source file(s) in the directories specified by MediaDirectories. Extract data to set codec, resolution, audio format and container fields as well as the mediainfo field itself.", action="store_true")
  54. self.parsed = parser.parse_args()
  55. class GetConfig:
  56. def __init__(self):
  57. script_dir = Path(__file__).parent.parent
  58. # Get configuration
  59. config = configparser.ConfigParser()
  60. configfile = Path(script_dir, 'jps2sm.cfg')
  61. try:
  62. open(configfile)
  63. except FileNotFoundError:
  64. fatal_error(
  65. f'Error: config file {configfile} not found - enter your JPS/SM credentials in jps2sm.cfg and check jps2sm.cfg.example to see the syntax.')
  66. config.read(configfile)
  67. self.jps_user = config.get('JPopSuki', 'User')
  68. self.jps_pass = config.get('JPopSuki', 'Password')
  69. self.sm_user = config.get('SugoiMusic', 'User')
  70. self.sm_pass = config.get('SugoiMusic', 'Password')
  71. self.media_roots = [x.strip() for x in config.get('Media', 'MediaDirectories').split(',')] # Remove whitespace after comma if any
  72. self.directories = config.items('Directories')
  73. def __getattr__(self, item):
  74. return self.item
  75. class HandleCfgOutputDirs:
  76. """
  77. Handle all config dir logic
  78. Get data, decide if relative or absolute path and create dir if required
  79. :param config_file_dirs_section: dict: Contents of 'Directories' section in jps2sm.cfg
  80. """
  81. def __init__(self, config_file_dirs_section):
  82. self.config_file_dirs_section = config_file_dirs_section
  83. self.file_dir = {}
  84. for (cfg_key, cfg_value) in config_file_dirs_section:
  85. if Path(cfg_value).is_absolute():
  86. self.file_dir[cfg_key] = cfg_value
  87. else:
  88. self.file_dir[cfg_key] = Path(Path.home(), cfg_value)
  89. if not Path(self.file_dir[cfg_key]).is_dir():
  90. Path(self.file_dir[cfg_key]).mkdir(parents=True, exist_ok=True)
  91. def remove_html_tags(text):
  92. """
  93. Strip html tags, used by GetGroupData() on the group description if unable to get bbcode
  94. """
  95. clean = re.compile('<.*?>')
  96. return re.sub(clean, '', text)