forum

osu! python edition

posted
Total Posts
16
Topic Starter
superloach
I've very recently started work on an osu! client written in python3, using the pygame and tkinter libraries.
It's nothing much so far, mostly because it's also my first time using those libraries. :P

So far, it has:
  • intro screen
  • file picker if not passed as argument (python3 osu.py <...>.osz)
  • warnings for various errors (not a zip, missing osu files, etc.)
  • song name, artist, etc. detection from map filename, not metadata section
  • list difficulties and choose
  • list map section headers
#!/usr/bin/python3

fps = 60
size = (500,500)

import sys,os,zipfile,shutil
from math import *

try:
import tkinter as tk
from tkinter import filedialog
from tkinter import simpledialog as easy
from tkinter import messagebox
except:
print("Sorry, you need tkinter to choose a file.\nIf you want, you can just run `python3 osu.py <filename>` for now.")
sys.exit()
else:
root = tk.Tk()
root.withdraw()

try:
import pygame
except:
messagebox.showerror("missing library","Sorry, you need pygame to play.",type="ok")
sys.exit()

def col(a):return pygame.Color(str(a))

curdir = os.path.dirname(os.path.abspath(__file__))
impath = os.path.realpath((sys.argv+[""])[1])
tmpdir = os.path.join(curdir,"tmp",'')
mapdir = os.path.join(curdir,"maps",'')
fntdir = os.path.join(curdir,"fonts",'')

a='retry'
if os.path.isdir(impath):
while a == 'retry':
impath = filedialog.askopenfilename(initialdir=mapdir,title="Select Map")
if len(impath) == 0:
a=messagebox.showerror("cancellation","File selection cancelled.",type="retrycancel")
if a == 'cancel':
sys.exit()
else:
a = 'other thing'
try:
with zipfile.ZipFile(impath,'r') as osz:
osz.extractall(tmpdir)
except zipfile.BadZipFile:
messagebox.showerror("format error","Not even a valid zip file. Sad.")
a='retry'

files = os.listdir(tmpdir)

maps = []
hasbg = False
hassong = False
hasmap = False
for file in files:
if file[-3:] == "png" or file[-3:] == "jpg" or file[-4:] == "jpeg":
hasbg = True
if file[-3:] == "mp3" or file[-3:] == "wav":
hassong = True
if file[-3:] == "osu":
hasmap = True
maps = maps + [tmpdir+file]

if hasbg == False or hassong == False or hasmap == False:
messagebox.showerror("format error","Not a valid osz. Missing a song, background, and/or map file(s).")
sys.exit()

name = os.path.split(maps[0])[-1].split('.')[0].split('[')[0]
artist = name.split(' - ')[0]
songname = name.split(' - ')[1].split(' (')[0]
creator = name.split(' (')[1].split(') ')[0]

#print('name: '+name)
#print('artist: '+artist)
#print('song name: '+songname)
#print('creator: '+creator)

diffs = []
for mapname in maps:
diffs = diffs+[os.path.split(mapname)[-1].split('.')[0].split('[')[1].split(']')[0]]

pygame.init()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("osu! python edition")
clock = pygame.time.Clock()

lilfont = pygame.font.Font(os.path.join(fntdir,'lil.ttf'),25)
bigfont = pygame.font.Font(os.path.join(fntdir,'big.ttf'),90)
tinfont = pygame.font.Font(os.path.join(fntdir,'lil.ttf'),11)

logo = pygame.transform.scale(pygame.image.load(os.path.join(curdir,"icon.png")),(3*size[0]//4,3*size[1]//4))
pygame.display.set_icon(pygame.transform.scale(logo,(32,32)))

done = False
ticks = 0
truefps = 0
secs = 0
chosendiff = ""
page = 0
sections = []
content = ""
version = ""
sectitles = []
keys = [pygame.K_1,pygame.K_2,pygame.K_3,pygame.K_4,pygame.K_5,pygame.K_6,pygame.K_7,pygame.K_8,pygame.K_9,pygame.K_0]
chosendiff = None
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
a=messagebox.askquestion(" ","Really leave osu! python edition?",type="yesno")
if a == 'yes':
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True

if page == 0:
screen.fill(col('magenta'))
screen.blit(logo,(size[0]//8,size[1]//8))

if page == 1:
screen.fill(col('pink'))

text=lilfont.render("artist - "+artist,True,col('cyan'))
screen.blit(text,(10,10))

text=lilfont.render("song name - "+songname,True,col('orange'))
screen.blit(text,(10,40))

text=lilfont.render("creator - "+creator,True,col('green'))
screen.blit(text,(10,70))

pygame.display.set_caption(songname)

text = lilfont.render("Difficulties:",True,col('black'))
screen.blit(text,(10,120))

i = 0
for diff in diffs:
text = lilfont.render(str(int(i+1))+") "+diff,True,col('black'))
screen.blit(text,(25,30*i+150))
i = i + 1

pygame.display.flip()

if chosendiff == None:
chosendiff = easy.askinteger(" ","Pick a map \N{number sign}:")
else:
page = 2

if page == 2:
screen.fill(col('white'))
pygame.display.set_caption(songname + " - " + diffs[chosendiff-1])
map = maps[chosendiff-1]

if len(content) == 0:
content = open(map,'r').read()

if len(sections) == 0:
sections = content.split('\n\n')
i = 0
for sect in sections:
lines = sect.split('\n')
if not lines[0].startswith('[') and len(version) == 0:
version = lines[0]

if lines[0].startswith('[') and lines[0].endswith(']'):
sectitles = sectitles + [lines[0][1:-1]]

i = i + 1

text = tinfont.render('['+'], ['.join(sectitles)+']',True,col('blue'))
screen.blit(text,(10,45))

text = lilfont.render(version,True,col('black'))
screen.blit(text,(10,10))

if round(ticks/fps,0) == ticks/fps and round(ticks/fps,0) > 0:
truefps = int(ticks//round(ticks/fps,0))

if secs > 2.5 and page == 0:page = 1

text = lilfont.render(str(truefps)+" fps",True,col('yellow'))
screen.blit(text,(10,size[1]-45))

secs = ticks//fps
clock.tick(fps)
ticks = ticks + 1
pygame.display.flip()

pygame.quit()
shutil.rmtree(tmpdir)

I saw mention in a thread about a JS/HTML5 port (https://osu.ppy.sh/forum/t/36805) that peppy would be willing to give advice on parsing mapfiles... hope I can get some of those tips! :D
Topic Starter
superloach
here's a link to a zip with all necessary files in it:
https://nofile.io/f/1Sm32xb6fyQ/osu!py.zip

yes, I found the logo font, but didn't use it. fight me. >:(:P
ZeroxPlaysOsu
If you're going to work on such a big project, I would give you the following advice

1-Don't put all your code in one file, be modular and divide in multiple files
2-Use a source control system like github or bitbucket that way you always have an older version to go back to if ever something terrible were to happen (I'm assuming you aren't using any since you posted your code directly in your post)

Good luck ;)
Kondou-Shinichi
but why???
ZeroxPlaysOsu

Kondou-Shinichi wrote:

but why???
I'm guessing just to hone his/her programming skills
anu
Github is a really good idea.

People can look at the code and offer help.
Jamu
hot
Hoofuyu
how tf am i supposed to install "pygame", never heard of it, and why did they make it hell to install

edit: thx for files
TicClick

P o n y wrote:

how the fuck am i supposed to install "pygame", never heard of it, and why the fuck did they make it hell to install
https://docs.python.org/3/tutorial/venv.html
https://www.pygame.org/wiki/GettingStarted
abraker

P o n y wrote:

how the fuck am i supposed to install "pygame", never heard of it, and why the fuck did they make it hell to install
you must not be familiar with python... pygame is a popular library for python used to make games with

pygame can be download using pip via console command
pip install pygame
Mr Sonic
Sorry, but I will not install pygame just to look at how is your progress, where are the screenshots?
FireRedz

Mr Sonic wrote:

Sorry, but I will not install pygame just to look at how is your progress, where are the screenshots?
it takes less than 10 minutes to install python and pygame
abraker

Mr Sonic wrote:

Sorry, but I will not install pygame just to look at how is your progress, where are the screenshots?
Yes screenshot would be good, but also....



FireRedz wrote:

Mr Sonic wrote:

Sorry, but I will not install pygame just to look at how is your progress, where are the screenshots?
it takes less than 10 minutes to install python and pygame
KnownError
As others have said here, you should definitely use a open-source version control hosting service like GitHub or GitLab.

There have been a few people complaining about installation, and honestly while Python and Pygame are relatively easy to install, for most people that's too complicated. The solution is to use PyInstaller to create a Windows EXE.

pip install pyinstaller
pyinstaller --onefile code.py
./dist myprog
jawabomber09
nice
brobeast
I won't go that far
and good luck
Please sign in to reply.

New reply