toybocks/backend.py
cecilkorik 053f435a0b initial import
--HG--
branch : toybocks
2010-03-26 03:50:24 +00:00

238 lines
6.5 KiB
Python
Executable file

import dblayer
from dblayer import db, cur
import subprocess, shlex
import os
from zipfile import ZipFile
from threading import Thread
from ringbuffer import SplitRingBuffer
import time
class EmulatorHandlerThread(Thread):
def __init__(self, game, proc):
Thread.__init__(self)
self.buffer = SplitRingBuffer(1024*1024, 512*1024)
self.game = game
self.proc = proc
def run(self):
while True:
data = self.proc.stdout.read(4096)
self.proc.poll()
if not data and self.proc.returncode != None:
break
self.buffer.write(data)
time.sleep(0.4)
emulator_table = {}
gamesystem_table = {}
playlist_list = []
playlist_table = {}
class GamesystemInfo(object):
def __init__(self, id, name, fileext):
self.id = id
self.name = name
self.fileexts = fileext.split(';')
self.emu_id = None
class EmulatorInfo(object):
def __init__(self, id, name, path, options):
self.id = id
self.name = name
self.path = path
self.options = options
self.system_id = None
def start_game(self, game):
args = shlex.split(self.options)
emu = subprocess.Popen([self.path] + args + [game.path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return emu
class GameInfo(object):
def __init__(self, id, name, path, emu, syst):
self.id = id
self.name = name
self.path = path
self.emu_id = emu
self.system_id = syst
class AllGames_Playlist(object):
def __init__(self):
self.id = None
self.name = '(All Games)'
def lookup(self):
pass
def gamelist(self):
cur.execute("select game.id, game.name, game.path, game.emu_id, game.gamesystem_id from game order by game.name")
gl = []
for r in cur:
i, n, p, e, s = r
gl.append(GameInfo(i, n, p, e, s))
return gl
class Playlist(object):
def __init__(self, id=None, name=None):
if id == None and name == None:
raise ValueError, "Either name or id must be specified"
self.id = id
self.name = name
self.gamelist_cache = None
def lookup(self):
if self.name != None:
cur.execute("select id from playlist where name = ?", [self.name])
else:
cur.execute("select name from playlist where id = ?", [self.id])
rs = cur.fetchall()
if len(rs) > 1:
raise ValueError, "Non unique name for playlist"
else:
raise ValueError, "Playlist not found"
if self.name == None:
self.name = rs[0][0]
else:
self.id = rs[0][0]
def gamelist(self):
if self.gamelist_cache != None:
return self.gamelist_cache
cur.execute("select game.id, game.name, game.path, game.emu_id, game.gamesystem_id from game, playlist_game where playlist_game.game_id = game.id and playlist_game.playlist_id = ? order by game.name", [self.id])
gl = []
for r in cur:
i, n, p, e, s = r
gl.append(GameInfo(i, n, p, e, s))
# enabling this could cause huge memory usage, but make things faster
#self.gamelist_cache = gl
return gl
def load_playlists():
global playlist_list
dblayer.connect()
cur.execute("select id, name from playlist order by name")
pl = [AllGames_Playlist()]
playlist_table[-1] = pl[0]
for r in cur:
id, name = r
p = Playlist(id, name)
pl.append(p)
playlist_table[id] = p
playlist_list = pl
def load_emulators():
dblayer.connect()
cur.execute("select id, name, path, options from emulator")
for r in cur:
id, name, path, options = r
ei = EmulatorInfo(id, name, path, options)
emulator_table[id] = ei
cur.execute("select id, name, fileext from gamesystem")
for r in cur:
id, name, fileext = r
gsi = GamesystemInfo(id, name, fileext)
gamesystem_table[id] = gsi
cur.execute("select gamesystem_id, emulator_id from gamesystem_emulator")
for r in cur:
gsid, eid = r
gamesystem_table[gsid].emu_id = eid
emulator_table[eid].system_id = gsid
def find_emu(emu):
if not os.environ.has_key('PATH'):
paths = ['.']
else:
paths = os.environ['PATH'].split(os.pathsep) + ['.']
for path in paths:
if os.path.exists(os.path.join(path, emu)):
return os.path.abspath(os.path.join(path, emu))
return None
def initialize_emulator_row(emulator, gamesystem):
cur.execute("insert into emulator (name, path, options) values (?, ?, ?)", [emulator.name, emulator.path, emulator.options])
emulator.id = cur.lastrowid
cur.execute("insert into gamesystem (name, fileext) values (?, ?)", [gamesystem.name, ';'.join(gamesystem.fileexts)])
gamesystem.id = cur.lastrowid
cur.execute("insert into gamesystem_emulator (gamesystem_id, emulator_id) values (?, ?)", [gamesystem.id, emulator.id])
def initialize_emulator_table():
emulist = [(('SNES','.SMC'),'snes9x','snes9x-sdl','snes9x-x11','snes9x-gtk','zsnes'),(('NES','.NES'),'fceu'),(('Genesis','.BIN'),'dgen'),(('MAME','**MAME**'),'xmame')]
for emutype in emulist:
system, fileext = emutype[0]
for emu in emutype[1:]:
emupath = find_emu(emu)
if emupath:
initialize_emulator_row(EmulatorInfo(None, emu, emupath, ''), GamesystemInfo(None, system, fileext))
def scan_zip(path):
zf = ZipFile(path, "r")
zfl = zf.namelist()
zf.close()
if len(zfl) > 1:
return "**MAME**"
elif zfl:
return os.path.splitext(zfl[0])[1].upper()
else:
return None
def autoload_data(path, playlist, system=None, emulator=None):
fileext_map = {}
if system == None:
for gsi in gamesystem_table.values():
for fe in gsi.fileexts:
fileext_map[fe.upper()] = gsi
print fileext_map
for base, dirs, files in os.walk(path):
for file in files:
fn, fe = os.path.splitext(file)
feu = fe.upper()
if feu == '.ZIP':
feu = scan_zip(os.path.join(path, base, file))
if not feu:
continue
autosystem = None
if feu in fileext_map:
autosystem = fileext_map[feu]
if system != None:
autosystem = system
if autosystem != None:
"We have a valid game, we know what system it's for, and we will use that system's default emulator"
emuid = None
if emulator != None:
emuid = emulator.id
sysid = None
if autosystem != None:
sysid = autosystem.id
cur.execute("insert into game (name, path, emu_id, gamesystem_id) values (?, ?, ?, ?)", [fn, os.path.join(path, base, file), emuid, sysid])
gameid = cur.lastrowid
cur.execute("insert into playlist_game (game_id, playlist_id) values (?, ?)", [gameid, playlist.id])
def get_game(idnum):
cur.execute("select game.id, game.name, game.path, game.emu_id, game.gamesystem_id from game where game.id = ? order by game.name", [idnum])
rs = cur.fetchall()
if len(rs) > 1:
raise ValueError, "Non unique id for game, multiple games matched"
elif len(rs) == 0:
raise ValueError, "Game not found"
i, n, p, e, s = rs[0]
gi = GameInfo(i, n, p, e, s)
return gi