|
-
- import re
- import os
- import sys
- import shutil
- import string
- import argparse
- import html
- from urllib.parse import urlparse
- import json
- import ftplib
-
-
- import requests
- from bs4 import BeautifulSoup
- from mutagen.flac import FLAC
- from mutagen.mp3 import MP3
- from torf import Torrent
- from tqdm import tqdm
- from langdetect import detect
-
-
- import smpy
-
- def asciiart ():
- print("""
- ███████╗███╗ ███╗ █████╗ ██╗ ██╗
- ██╔════╝████╗ ████║ ██╔══██╗██║ ██║
- ███████╗██╔████╔██║█████╗███████║██║ ██║
- ╚════██║██║╚██╔╝██║╚════╝██╔══██║██║ ██║
- ███████║██║ ╚═╝ ██║ ██║ ██║╚██████╔╝
- ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
- """)
-
-
- def getargs():
- parser = argparse.ArgumentParser()
- parser.add_argument('-dir', '--directory', help='Initiate upload on directory.', nargs='?', required=True)
- parser.add_argument("-f", "--freeleech", help="Enables freeleech.", action="store_true")
- parser.add_argument("-t", "--tags", help="Add additional tags to the upload.", nargs='?')
- parser.add_argument('-n', '--debug', help='Enable debug mode.', action='store_true')
- parser.add_argument("-d", "--dryrun", help="Dryrun will carry out all actions other than the actual upload to JPS.", action="store_true")
- parser.add_argument("-im", "--imageURL", help='Set the torrent cover URL.', nargs='?')
- parser.add_argument("-a", "--artists", help='Set the artists. (Romaji\English)', nargs='?')
- parser.add_argument("-ca", "--contributingartists", help='Set the contributing artists. (Romaji\English)', nargs='?')
- parser.add_argument("-rt", "--releasetype", help='Set the release type.', nargs='?')
- parser.add_argument("-ti", "--title", help='Set the title. (Romaji\English)', nargs='?')
- parser.add_argument("-eti", "--editiontitle", help='Set the edition title', nargs='?')
- parser.add_argument("-ey", "--editionyear", help='Set the torrent edition year (YYYYMMDD or YYYY).', nargs='?')
- parser.add_argument("-ms", "--mediasource", help='Set the media source.', nargs='?')
- return parser.parse_args()
-
-
- def getauthkey():
- """
- Get SM session authkey for use by uploadtorrent() data dict.
- Uses SM login data
-
- :return: authkey
- """
- smpage = sm.retrieveContent("https://sugoimusic.me/torrents.php?id=118")
- soup = BeautifulSoup(smpage.text, 'html5lib')
- rel2 = str(soup.select('#content .thin .main_column .torrent_table tbody'))
- authkey = re.findall('authkey=(.*)&torrent_pass=', rel2)
- return authkey
-
-
- def copytree(src, dst, symlinks=False, ignore=None):
- for item in os.listdir(src):
- s = os.path.join(src, item)
- d = os.path.join(dst, item)
- if os.path.isdir(s):
- shutil.copytree(s, d, symlinks, ignore)
- else:
- shutil.copy2(s, d)
-
-
- def createtorrent(authkey, directory, filename, releasedata):
- t = Torrent(path=directory,
- trackers=[authkey])
-
- t.private = True
- t.source = "SugoiMusic"
- t.generate()
-
-
-
-
- filename = f"{releasedata['title']} [{releasedata['media']}-{releasedata['audioformat']}].torrent"
- filename = filename.replace("/","/")
- filename = filename.replace(":",":")
- filename = filename.replace("?","")
- try:
- t.write(filename)
- print("_" * 100)
- print("Torrent creation:\n")
- print(f"{filename} has been created.")
- except:
- print("_" * 100)
- print("Torrent creation:\n")
- os.remove(filename)
- print(f"{filename} already exists, existing torrent will be replaced.")
- t.write(filename)
- print(f"{filename} has been created.")
-
- return filename
-
-
- def readflac(filename):
- read = FLAC(filename)
-
- audio_info={
- "SAMPLE_RATE": read.info.sample_rate,
- "BIT_DEPTH": read.info.bits_per_sample
- }
-
- tags={
- "ALBUM": read.get('album'),
- "ALBUMARTIST": read.get('albumartist'),
- "ARTIST": read.get('artist'),
- "DATE": read.get('date')[0],
- "GENRE": "",
- "TITLE": read.get('title'),
- "COMMENT": read.get('comment'),
- "TRACKNUMBER": read.get('tracknumber')[0].zfill(2),
- "DISCNUMBER": read.get('discnumber')}
-
-
- tags['GROUPING'] = read.get('grouping')
-
-
- if tags['GROUPING'] == None:
- tags['GROUPING'] = read.get('contentgroup')
-
-
- required_tags = ['ALBUM', 'ALBUMARTIST','DATE','TRACKNUMBER']
- for k,v in tags.items():
- if v == None:
- if k in required_tags:
- print(f"{k} has returned {v}, this is a required tag")
- sys.exit()
-
- return tags, audio_info
-
-
- def readmp3(filename):
- read = MP3(filename)
-
-
- tags={
- "ALBUM": read.get('TALB'),
- "ALBUMARTIST": read.get('TPE2'),
- "ARTIST": read.get('TPE1'),
- "DATE": str(read.get('TDRC')),
- "GENRE": read.get('TCON').text,
- "TITLE": read.get('TIT2'),
- "COMMENT": read.get('COMM::eng'),
- "GROUPING": read.get('TIT1'),
- "TRACKNUMBER": re.sub(r"\/.*", "", str(read.get('TRCK'))).zfill(2),
- "DISCNUMBER": re.sub(r"\/.*", "", str(read.get('TPOS')))}
-
- required_tags = ['ALBUM', 'ALBUMARTIST','DATE','TRACKNUMBER']
- for k,v in tags.items():
- if v == None:
- if k in required_tags:
- print(f"{k} has returned {v}, this is a required tag")
- sys.exit()
-
- return tags
-
-
- def generatelog(track_titles, log_filename, log_directory):
-
- track_titles = '\n'.join([str(x) for x in track_titles])
-
-
- log_contents = f"""[size=5][b]Tracklist[/b][/size]\n{track_titles}
- """
-
-
- if cfg['local_prefs']['save_tracklist']:
-
- with open(f"{log_directory}/{log_filename}.log", "w+") as f:
- f.write(log_contents)
-
- f.seek(0)
- log_contents = f.read()
- f.close()
-
-
- if debug:
- print("_" * 100)
- print(f"Log Contents/Tracklisting: {log_contents}")
-
- return log_contents
-
- def readlog(log_name, log_directory):
- with open(f"{log_directory}/{log_name}.log", "r+") as f:
- log_contents = f.read()
- f.close()
-
- return log_contents
-
- def add_to_hangul_dict(hangul , english , category):
- hangul = str(hangul)
- english = str(english)
-
- categories = ['version','general','artist','genres', 'label', 'distr']
- file = f"json_data/dictionary.json"
- json_file = open(file, 'r', encoding='utf-8', errors='ignore')
- dictionary = json.load(json_file)
- json_file.close()
-
- new = dict()
- for cats in dictionary:
-
- new[cats] = dict()
-
- for key,value in dictionary[cats].items():
-
- new[cats][key] = value
-
- if hangul in new[category].keys():
-
- if new[category].get(hangul) is None:
-
- if english != 'None':
- new[category][hangul] = english
-
- else:
-
- if english != 'None':
- new[category][hangul] = english
- else:
-
- if english == 'None':
- new[category][hangul] = None
- else:
- new[category][hangul] = english
-
- json_write = open(file, 'w+', encoding='utf-8')
- json_write.write(json.dumps(new, indent=4, ensure_ascii=False))
- json_write.close()
-
- def translate(string, category, result=None, output=None):
-
- file = "json_data/dictionary.json"
- with open(file, encoding='utf-8', errors='ignore') as f:
- dictionary = json.load(f, strict=False)
-
- category = str(category)
- string = str(string)
- search = dictionary[category]
- string = string.strip()
-
- if string == 'Various Artists':
- output = ['Various Artists',None]
- else:
-
- if re.search("\((?P<inside>.*)\)", string):
-
-
-
- parenthesis = string.split("(")
- pre_parenthesis = parenthesis[0].strip()
- in_parenthesis = parenthesis[1].replace(")","").strip()
-
-
-
- if re.search("[^\u0000-\u007F]+",pre_parenthesis) and re.search("[^\u0000-\u007F]+",in_parenthesis):
-
- first = 'kr'
- second = 'kr'
- else:
- if re.search("[^\u0000-\u007F]+",pre_parenthesis):
- first = 'kr'
- second = 'eng'
- else:
- first = 'eng'
- second = 'kr'
-
- if first == 'kr' and second == 'eng':
-
- hangul = pre_parenthesis
- english = in_parenthesis
- add_to_hangul_dict(hangul,english,category)
-
- elif first == 'eng' and second == 'kr':
-
- hangul = in_parenthesis
- english = pre_parenthesis
- add_to_hangul_dict(hangul,english,category)
- elif first == 'kr' and second == 'kr':
-
- hangul = pre_parenthesis
- english = None
- add_to_hangul_dict(pre_parenthesis,None,category)
- add_to_hangul_dict(hangul,None,category)
- else:
-
- hangul = None
- english = pre_parenthesis
-
- output = [hangul,english]
-
-
- else:
-
-
- if re.search("[^\u0000-\u007F]+", string):
-
- if string in search.keys():
-
- if search.get(string) is None:
-
- output = [string,None]
- else:
-
- output = [string,search.get(string)]
- else:
- output = [string,None]
- add_to_hangul_dict(string, None, category)
-
-
- else:
- for key,value in search.items():
- if key == string:
- output = [value,string]
- break
- else:
- output = [string,string]
-
- return output
-
- def determine_flac_bitdepth_and_samplerate(audio_info):
- if audio_info['BIT_DEPTH'] == 16:
- return "Lossless"
- elif audio_info['BIT_DEPTH'] == 24 and audio_info['SAMPLE_RATE'] == 96000:
- return "24bit Lossless 96kHz"
- elif audio_info['BIT_DEPTH'] == 24 and audio_info['SAMPLE_RATE'] == 48000:
- return "24bit Lossless 48kHz"
- else:
- return "24bit Lossless"
-
- def gatherdata(directory):
-
- list_album_artists = []
- list_track_artists = []
- list_album = []
- list_genre = []
- translated_genre = []
- translated_album_artists = []
- tracklist_entries = []
-
- releasedata = {}
-
-
-
- log_available = False
- flac_present = False
- mp3_present = False
-
- for file in os.listdir(directory):
- file_location = os.path.join(directory, file)
- if file.endswith(".flac"):
-
- tags, audio_info = readflac(file_location)
- flac_present = True
-
- if tags['DISCNUMBER'] == None:
- tracklist_entry = f"[b]{tags['TRACKNUMBER']}[/b]. {tags['TITLE'][0]}"
- else:
- tracklist_entry = f"[b]{tags['DISCNUMBER'][0]}-{tags['TRACKNUMBER']}[/b]. {tags['TITLE'][0]}"
-
- tracklist_entries.append(tracklist_entry)
-
- if debug:
- print ("_" * 100)
- print(f"Tags for {file}:\n{tags}")
-
- if file.endswith(".mp3"):
-
- tags = readmp3(file_location)
- mp3_present = True
-
- if tags['DISCNUMBER'] == "None":
- tracklist_entry = f"[b]{tags['TRACKNUMBER']}[/b]. {tags['TITLE'][0]}"
- else:
- tracklist_entry = f"[b]{tags['DISCNUMBER']}-{tags['TRACKNUMBER']}[/b]. {tags['TITLE'][0]}"
-
- tracklist_entries.append(tracklist_entry)
-
- if debug:
- print ("_" * 100)
- print(f"Tags for {file}:\n{tags}")
-
-
- if len(tags['GENRE']) == 1:
- tags['GENRE'] = tags['GENRE'][0].split(";")
- for aa in tags['ALBUMARTIST']:
- list_album_artists.append(aa)
- for a in tags['ARTIST']:
- list_track_artists.append(a)
- list_album.append(tags['ALBUM'][0])
-
-
-
-
-
- if flac_present:
- format = 'FLAC'
- bitrate = determine_flac_bitdepth_and_samplerate(audio_info)
- if mp3_present:
- format = 'MP3'
- bitrate = '320'
- if flac_present and mp3_present:
- print("Mutt detected, exiting.")
- sys.exit()
-
- if file.endswith(".log"):
- log_available = True
-
- if log_available == True:
- media = 'CD'
- else:
- media = 'Web'
-
-
- file = "json_data/dictionary.json"
- with open(file, encoding='utf-8', errors='ignore') as f:
- dictionary = json.load(f, strict=False)
-
-
- if additional_tags != None:
- split_tags = additional_tags.split(",")
- for s in split_tags:
- list_genre.append(s)
-
-
- for g in set(list_genre):
- translation = translate(g, "genres")[0]
- translated_genre.append(translation)
-
-
- for a in set(list_album_artists):
- if tags['ALBUMARTIST'][0] == 'Various Artists':
- translated_artist_name = 'V.A.'
- translated_album_artists.append("V.A.")
- else:
- translated_artist_name = translate(string=tags['ALBUMARTIST'][0], category="artist")
- translated_album_artists.append(translated_artist_name[0])
-
-
- unique_album_artists = ','.join(set(translated_album_artists))
- unique_track_artists = ','.join(set(list_track_artists))
- unique_genre = ','.join(set(translated_genre))
- unique_album = set(list_album)
-
-
-
- log_directory = cfg['local_prefs']['log_directory']
-
- if cfg['local_prefs']['generate_tracklist']:
- log_filename = f"{unique_album_artists} - {tags['ALBUM'][0]}"
- album_description = generatelog(tracklist_entries, log_filename, log_directory)
- else:
- log_filename = tags['COMMENT'][0]
- album_description = readlog(log_filename, log_directory)
-
-
-
- if cfg['local_prefs']['enable_release_description']:
- try:
- release_description = f"Sourced from [url=https://music.bugs.co.kr/album/{tags['COMMENT'][0]}]Bugs[/url]"
-
- except:
- release_description = ""
-
- else:
- release_description = ""
-
-
-
- releasedata['submit'] = 'true'
-
-
- accepted_types = ['Album', 'Single', 'EP']
-
- if releasetype:
- releasedata['type'] = releasetype
- else:
-
- try:
- releasedata['type'] = translate(tags['GROUPING'][0], "release_types")[0]
- except TypeError:
- releasedata['type'] = input("\n" + "_" * 100 + "\nGrouping is empty or has received an error, please enter manually (Album/Single/EP)\n")
-
-
-
- if releasedata['type'] not in accepted_types:
- while True:
- releasedata['type'] = input("\n" + "_" * 100 + "\nGrouping tag or release type argument did not return an album type, please enter manually (Album/Single/EP)\n")
-
- if releasedata['type'] not in accepted_types:
- continue
- else:
- break
-
- if releasedata['type'] == "Album":
- releasedata['type'] = 0
- elif releasedata['type'] == "Single":
- releasedata['type'] = 2
- else:
- releasedata['type'] = 1
-
- releasedata['title'] = tags['ALBUM'][0]
- releasedata['idols[]'] = unique_album_artists
-
- if unique_album_artists != unique_track_artists:
- releasedata['artist_jp'] = unique_track_artists
-
- releasedata['year'] = re.sub(r"[^0-9]", "", tags['DATE'])
- releasedata['audioformat'] = format
- releasedata['bitrate'] = bitrate
- releasedata['media'] = media
- releasedata['album_desc'] = album_description
- releasedata['release_desc'] = release_description
- releasedata['tags'] = unique_genre
-
-
- if freeleech:
- releasedata['freeleech'] = "true"
-
-
-
- en = detectlanguage(releasedata['title'])
- if debug:
- print("_" * 100)
- print("Title/Artist Language:\n")
- print(f"{releasedata['title']} < English = {en}")
- if en == False:
- if title:
- input_english_title = title
- else:
- input_english_title = input("\n" + "_" * 100 + "\nKorean/Japanese Detected. Please enter the romaji/english title:\n")
-
- releasedata['title_jp'] = releasedata['title']
-
- releasedata['title'] = input_english_title
-
- en = detectlanguage(releasedata['idols[]'])
- if debug:
- print(f"{releasedata['idols[]']} < English = {en}")
- if en == False:
- if artists:
- input_english_artist = artists
- else:
- input_english_artist = input("\n" + "_" * 100 + "\nKorean/Japanese Detected. Separate multiple main artists with \",\". Please enter the romaji/english artist name:\n")
- input_english_artist = [x.strip() for x in input_english_artist.split(',')]
- releasedata['idols[]'] = input_english_artist
-
- if contributingartists:
- input_english_contributing_artist = contributingartists
- else:
- input_english_contributing_artist = input("\n" + "_" * 100 + "\nSeparate multiple contributing artists with \",\". Press enter to skip. Please enter the romaji/english artist name:\n")
- if input_english_contributing_artist != "":
- input_english_contributing_artist = [x.strip() for x in input_english_contributing_artist.split(',')]
- releasedata['contrib_artists[]'] = input_english_contributing_artist
-
- if mediasource:
- releasedata['media'] = mediasource
- else:
- while(True):
- input_mediasource = input("\n" + "_" * 100 + "\nEnter a number to choose the media source. \n1=CD\n2=Web\n3=Vinyl\n")
- if input_mediasource == "1":
- releasedata["media"] = "CD"
- break
- elif input_mediasource == "2":
- releasedata["media"] = "Web"
- break
- elif input_mediasource == "3":
- releasedata["media"] = "Vinyl"
- break
- print("Invalid choice.")
-
- if editiontitle:
- releasedata['remastertitle'] = editiontitle
- else:
- input_editiontitle = input("\n" + "_" * 100 + "\nEnter the edition TITLE. Press enter to skip.\n")
- print(input_editiontitle)
- if input_editiontitle != "":
- if editionyear:
- releasedata["remasteryear"] = editionyear
- else:
- input_editionyear = input("\n" + "_" * 100 + "\nEnter the edition year as YYYYMMDD or YYYY.\n")
- releasedata["remasteryear"] = input_editionyear
- releasedata['remastertitle'] = input_editiontitle
-
- return releasedata
-
-
- def split(word):
- return [char for char in word]
-
- def detectlanguage(string):
-
-
- characters = split(string)
- language_list = []
- for c in characters:
- try:
- language = detect(c)
- language_list.append(language)
- except:
- langauge = "error"
-
- if 'ko' or 'ja' in language_list:
- en = False
- else:
- en = True
-
- return en
-
- def uploadtorrent(torrent, imageURL, releasedata):
-
- uploadurl = "https://sugoimusic.me/upload.php"
-
-
- data = releasedata
- data['image'] = imageURL
-
- if not dryrun:
- data['auth'] = authkey
-
-
- if debug:
- print('_' * 100)
- print('Release Data:\n')
- print(releasedata)
-
- try:
- postDataFiles = {
- 'file_input': open(torrent, 'rb')
-
- }
- except FileNotFoundError:
- print("_" * 100)
- print('File not found!\nPlease confirm file locations and names. Cover image or .torrent file could not be found')
- sys.exit()
-
-
- if dryrun != True:
- SMres = sm.retrieveContent(uploadurl, "post", data, postDataFiles)
- SMerrorTorrent = re.findall('red; text-align: center;">(.*)</p>', SMres.text)
-
- if len(SMerrorTorrent)!=0:
- print("Upload failed. Torrent error")
- print(SMerrorTorrent)
-
-
-
-
- if dryrun != True:
- print('\nUpload POSTED. It may take a moment for this upload to appear on SugoiMusic.')
-
-
-
-
- def ftp_transfer(fileSource, fileDestination, directory, folder_name, watch_folder):
-
-
- session = ftplib.FTP(cfg['ftp_prefs']['ftp_server'],cfg['ftp_prefs']['ftp_username'],cfg['ftp_prefs']['ftp_password'])
-
- session.encoding='utf-8'
-
-
- print("_" * 100)
- print("FTP Login Successful")
- print(f"Server Name: {cfg['ftp_prefs']['ftp_server']} : Username: {cfg['ftp_prefs']['ftp_username']}\n")
-
- if cfg['ftp_prefs']['add_to_downloads_folder']:
-
-
- try:
- session.mkd(f"{fileDestination}/{folder_name}")
- print(f'Created directory {fileDestination}/{folder_name}')
- except ftplib.error_perm:
- pass
-
-
- print(f"Beginning transfer...")
-
- session.cwd(f"{fileDestination}/{folder_name}")
-
- for file in os.listdir(directory):
- with open(f"{directory}/{file}",'rb') as f:
- filesize = os.path.getsize(f"{directory}/{file}")
-
-
- with tqdm(unit = 'blocks', unit_scale = True, leave = False, miniters = 1, desc = f'Uploading [{file}]', total = filesize) as tqdm_instance:
- session.storbinary('STOR ' + file, f, 2048, callback = lambda sent: tqdm_instance.update(len(sent)))
- print(f"{file} | Complete!")
- f.close()
-
- if cfg['ftp_prefs']['add_to_watch_folder']:
- with open(fileSource,'rb') as t:
-
- session.cwd(watch_folder)
-
-
-
- session.storbinary(f"STOR {torrentfile}", t)
- print(f"{torrentfile} | Sent to watch folder!")
- t.close()
-
- session.quit()
-
- def localfileorganization(torrent, directory, watch_folder, downloads_folder):
-
- if cfg['local_prefs']['add_to_downloads_folder']:
- try:
- os.mkdir(os.path.join(downloads_folder, os.path.basename(directory)))
- except FileExistsError:
- pass
- copytree(directory, os.path.join(downloads_folder, os.path.basename(directory)))
- shutil.rmtree(directory)
- if cfg['local_prefs']['add_to_watch_folder']:
- os.rename(torrent, f"{watch_folder}/{torrent}")
-
- if __name__ == "__main__":
-
- asciiart()
- args = getargs()
- with open(f'json_data/config.json') as f:
- cfg = json.load(f)
-
-
- dryrun = freeleech = tags = directory = debug = imageURL = artists = contributingartists = releasetype = title = editiontitle = editionyear = mediasource = audio_info = None
-
- directory = args.directory
- additional_tags = args.tags
-
- if args.dryrun:
- dryrun = True
-
- if args.debug:
- debug = True
-
- if args.freeleech:
- freeleech = True
-
- if args.imageURL:
- imageURL = args.imageURL
-
- if args.releasetype:
- releasetype = args.releasetype
-
- if args.title:
- title = args.title
-
- if args.artists:
- artists = args.artists
-
- if args.contributingartists:
- contributingartists = args.contributingartists
-
- if args.editiontitle:
- editiontitle = args.editiontitle
-
- if args.editionyear:
- editionyear = args.editionyear
-
- if args.mediasource:
- mediatype = args.mediasource
-
-
-
- loginData = {'username': cfg['credentials']['username'], 'password': cfg['credentials']['password']}
- loginUrl = "https://sugoimusic.me/login.php"
- loginTestUrl = "https://sugoimusic.me"
- successStr = "Enabled users"
- passkey = cfg['credentials']['passkey']
- annouceurl = "https://tracker.sugoimusic.me:24601/"+passkey+"/announce"
-
-
- sm = smpy.MyLoginSession(loginUrl, loginData, loginTestUrl, successStr, debug=args.debug)
-
- authkey = getauthkey()
-
- releasedata = gatherdata(directory)
-
-
- folder_name = os.path.basename(os.path.normpath(directory))
-
-
-
-
-
- torrentfile = createtorrent(annouceurl, directory, folder_name, releasedata)
-
-
- uploadtorrent(torrentfile, imageURL, releasedata)
-
-
- ftp_watch_folder = cfg['ftp_prefs']['ftp_watch_folder']
- ftp_downloads_folder = cfg['ftp_prefs']['ftp_downloads_folder']
- local_watch_folder = cfg['local_prefs']['local_watch_folder']
- local_downloads_folder = cfg['local_prefs']['local_downloads_folder']
-
- if not dryrun:
- if cfg['ftp_prefs']['enable_ftp']:
- ftp_transfer(fileSource=torrentfile, fileDestination=ftp_downloads_folder, directory=directory, folder_name=folder_name, watch_folder=ftp_watch_folder)
-
- if cfg['local_prefs']['add_to_watch_folder'] or cfg['local_prefs']['add_to_downloads_folder']:
- localfileorganization(torrent=torrentfile, directory=directory, watch_folder=local_watch_folder, downloads_folder=local_downloads_folder)
|