Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import ctypes, json, os, sys, urllib.request, tkinter, tkinter.filedialog, tkinter.messagebox
- from sys import exc_info
- from time import sleep, strftime
- #return time with/without dash or space that it takes up
- def getTime(num=1): return {1: strftime('%H:%M:%S')+' - ', 2: strftime('%H:%M:%S'), -1: ' '*len(strftime('%H:%M:%S')+' - '), -2: ' '*len(strftime('%H:%M:%S'))}[num]
- #makes a system beep
- def beep(): sys.stdout.write('\a')
- #checks the JSON data and compares it to Recent.json or Recent.num
- #if any new songs/updates are found, download it
- def checkJSON(down_to, save_as_unicode):
- try:
- print (getTime()+'Checking JSON data.')
- items = getIs(1) #number of pages checked. 61? songs per page
- if os.path.isfile('Recent.json'): #check file and download new/updated songs
- with open('Recent.json') as file:
- data = json.load(file)
- if 'beatmaps' in data[0]:
- to_down = [i for i in items if i not in data] #makes list if checked items are updated/new from Recent.json
- for i in enumerate(to_down):
- print (getTime()+'Downloading '+str(i[0]+1)+' of '+str(len(to_down))+'.\n'+
- itemInfo(i[1]))
- download(down_to, i[1], save_as_unicode)
- else:
- os.remove('Recent.json') #delete old file if improper json is used
- for i in enumerate(items):
- print (getTime()+'Downloading '+str(i[0]+1)+' of '+str(len(items))+'.\n'+
- itemInfo(i[1]))
- download(down_to, i[1], save_as_unicode)
- # elif os.path.isfile('Recent.num'): #check old file type and download new/updated songs
- # print (getTime(-1)+'Old file type found.\n'+
- # getTime(-1)+'Will replace old file type with the new\n'+
- # getTime(-1)+'after check and downloads are complete.')
- # with open('Recent.num') as file:
- # data = file.read()
- # to_down = [i for i in items if i['id'] not in data]
- # for i in enumerate(to_down):
- # print (getTime()+'Downloading '+str(i[0]+1)+' of '+str(len(to_down))+'.\n'+
- # itemInfo(i[1]))
- # download(down_to, i[1], save_as_unicode)
- # os.remove('Recent.num') #delete old file type
- else: #if recent.num isn't found, download everything
- print (getTime(-1)+'Recent.json or Recent.num files not found.\n'+
- getTime(-1)+'Downloading all available beatmaps.')
- for i in enumerate(items):
- print (getTime()+'Downloading '+str(i[0]+1)+' of '+str(len(items))+'.\n'+
- itemInfo(i[1]))
- download(down_to, i[1], save_as_unicode)
- with open('Recent.json', 'w') as file: #save recently checked items to file
- json.dump(items, file)
- print (getTime()+'Finished check / download.')
- except:
- beep()
- print (getTime()+'Error in checkJSON.')
- print (exc_info())
- sleep(5)
- checkJSON(down_to, save_as_unicode)
- #this returns a list of all JSON data online.
- def getIs(max, page=1, error=0):
- if error >= 5: #if there are connection errors, check every minute.
- sleep(300)
- try:
- print (getTime()+'Checking page '+str(page)+' of '+str(max)+'.')
- conn = urllib.request.urlopen('http://bloodcat.com/osu/?mod=json&p='+str(page), timeout=60) #make the connection
- #data = json.loads(conn.readall().decode('utf-8')) #load the data old
- items = json.loads(conn.readall().decode('utf-8')) #load the data
- conn.close() #close connection
- #items = [i for i in data['results']] #separate unneeded info old
- sleep(.5) #can't check too fast. Only 15 checks per 10 seconds allowed as i found out via emails with the owner Sung Hwan.
- if page != max: #small bit of recursion.
- for i in getIs(max, page+1): #get another page if not the last/max page
- items.append(i) #add to this one
- return items
- except:
- beep()
- print (getTime()+'Error in getIs.')
- print (exc_info())
- sleep(5)
- return getIs(max, page, error+1)
- #this downloads the songs
- def download(down_to, item, save_as_unicode, error=0):
- if error >= 5: #if there are connection errors, check every 5 minutes
- sleep(300)
- try:
- conn = urllib.request.urlopen('http://bloodcat.com/osu/m/'+item['id'], timeout=600) #make connection
- data = conn.read() #download to program
- conn.close() #close connection
- if save_as_unicode and songFileName(item, True) != songFileName(item): #save file with unicode if chosen and if available
- with open(down_to+''.join([(i if i not in '\\/:*?"<>|' else '_') for i in songFileName(item, True)])+'.osz', 'wb') as file: #create new binary file. Replace any illegal Windows file name characters
- file.write(data) #actual save to file happens here
- else:
- with open(down_to+''.join([(i if i not in '\\/:*?"<>|' else '_') for i in songFileName(item)])+'.osz', 'wb') as file:
- file.write(data) #or here if you don't want unicode
- if os.path.isfile('Recent.json'):
- with open('Recent.json') as file: #save json data on completion if program is closed during multiple downloads
- data = json.load(file)
- data.append(item)
- with open('Recent.json', 'w') as f:
- json.dump(data, f)
- else:
- with open('Recent.json', 'w') as file:
- json.dump([item], file)
- except:
- beep()
- print (getTime()+'Error in download.\n'+
- getTime(-1)+'Redownloading: '+songFileName(item)+'\n')
- print (exc_info())
- sleep(5)
- download(down_to, item, save_as_unicode, error+1)
- #returns a string of all the info for each song being downloaded
- #def itemInfo(item):
- # return (getTime(-1)+'Song:'.ljust(13)+songFileName(item)+'\n'+
- # getTime(-1)+'Creator:'.ljust(13)+item['creatorId']+' '+item['creator']+'\n'+
- # getTime(-1)+'Genre:'.ljust(13)+'('+item['genre']+') '+genreCheck(item['genre'])+'\n'+
- # getTime(-1)+'Mode:'.ljust(13)+'('+item['mode'].upper()+') '+modeCheck(item['mode'])+'\n'+
- # getTime(-1)+'Song Status:'.ljust(13)+'('+item['status']+') '+statusCheck(item['status']))
- #returns a string of all the info for each song being downloaded
- def itemInfo(item):
- return (getTime(-1)+'Song:'.ljust(13)+songFileName(item)+'\n'+
- getTime(-1)+'Creator:'.ljust(13)+item['creatorId']+' '+item['creator']+'\n'+
- getTime(-1)+'Song Status:'.ljust(13)+'('+item['status']+') '+statusCheck(item['status'])+'\n'+
- getTime(-1)+'Mode:'.ljust(13)+modeCheck(item))
- #returns a string with songID artist and title with / without unicode
- def songFileName(item, save_as_unicode=False):
- if save_as_unicode: #only if user chooses to save as unicode will a unicode title be created
- if item['artistU']:
- if item['titleU']:
- return item['id']+' '+item['artistU']+' - '+item['titleU']
- else:
- return item['id']+' '+item['artistU']+' - '+item['title']
- else:
- if item['titleU']:
- return item['id']+' '+item['artist']+' - '+item['titleU']
- return (item['id']+' '+item['artist']+' - '+item['title']).encode('ascii', 'replace').decode('utf-8').replace('?', '_') #ascii title + replace any unicode characters if any for some reason
- (test+'test').encode('ascii', 'replace').decode('utf-8').replace('?', '_')
- #returns a string for the genre depending on the number
- def genreCheck(num='0'): return {'0': 'Undefined', '1': 'Video Games', '2': 'Animation', '3': 'Easy', '4': 'Pop', '5': 'Other', '6': 'Novelty', '8': 'Hip-Hop', '9': 'Electronic'}[num]
- #returns a string of playable modes
- def modeCheck(item):
- modes={'0': 'Standard', '1': 'Taiko', '2': 'Catch the Beat', '3': 'Mania'} #library for modes
- count={'0': 0, '1': 0, '2': 0, '3': 0}
- for i in item['beatmaps']: #for each character
- count[i['mode']] += 1
- temp = ''
- for i in count:
- if count[i] != 0:
- temp += modes[i]+', '
- return temp[:temp.rfind(', ')] #and don't forget to remove the last comma and space before return
- #returns a string for the status of the song
- def statusCheck(status='0'): return {'0': 'Unranked (Others)', '1': 'Ranked', '2': 'Approved', '3': 'Qualified'}[status]
- #start of running code
- ctypes.windll.kernel32.SetConsoleTitleW('Bloodcat beatmap auto-downloader') #window title
- delay = 300 #wait time before checks (5 minutes)
- root = tkinter.Tk() #used for the GUI
- root.withdraw() #hides the unneeded GUI window
- download_to_folder = tkinter.filedialog.askdirectory(parent=root, initialdir='\\',
- title='Select download destination.') #asks user location of downloads
- #if any directory was selected
- if download_to_folder != '':
- try:
- save_as_unicode = tkinter.messagebox.askyesno('Save as Unicode?', #asks user if tey want files saved with unicode characters
- 'Would you like to save the beatmaps\nwith unicode characters? (Ex.\u3084\u3042.osz)')
- while(True): #main loop
- checkJSON(download_to_folder+'\\', save_as_unicode)
- sleep(delay)
- except:
- beep()
- print (getTime()+'Error in MAIN')
- print (exc_info())
- sleep(1000)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement