mirror of
https://github.com/RetroDECK/RetroDECK.git
synced 2024-11-25 07:25:38 +00:00
First upload
This commit is contained in:
commit
67f387b5a4
30
es_input.cfg
Normal file
30
es_input.cfg
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0"?>
|
||||
<inputList>
|
||||
<inputConfig type="keyboard" deviceName="Keyboard" deviceGUID="-1">
|
||||
<input name="a" type="key" id="122" value="1" />
|
||||
<input name="b" type="key" id="120" value="1" />
|
||||
<input name="down" type="key" id="1073741905" value="1" />
|
||||
<input name="hotkeyenable" type="key" id="32" value="1" />
|
||||
<input name="left" type="key" id="1073741904" value="1" />
|
||||
<input name="leftanalogdown" type="key" id="107" value="1" />
|
||||
<input name="leftanalogleft" type="key" id="106" value="1" />
|
||||
<input name="leftanalogright" type="key" id="108" value="1" />
|
||||
<input name="leftanalogup" type="key" id="105" value="1" />
|
||||
<input name="leftshoulder" type="key" id="119" value="1" />
|
||||
<input name="leftthumb" type="key" id="99" value="1" />
|
||||
<input name="lefttrigger" type="key" id="113" value="1" />
|
||||
<input name="right" type="key" id="1073741903" value="1" />
|
||||
<input name="rightanalogdown" type="key" id="1073741914" value="1" />
|
||||
<input name="rightanalogleft" type="key" id="1073741916" value="1" />
|
||||
<input name="rightanalogright" type="key" id="1073741918" value="1" />
|
||||
<input name="rightanalogup" type="key" id="1073741920" value="1" />
|
||||
<input name="rightshoulder" type="key" id="101" value="1" />
|
||||
<input name="rightthumb" type="key" id="118" value="1" />
|
||||
<input name="righttrigger" type="key" id="114" value="1" />
|
||||
<input name="select" type="key" id="8" value="1" />
|
||||
<input name="start" type="key" id="13" value="1" />
|
||||
<input name="up" type="key" id="1073741906" value="1" />
|
||||
<input name="x" type="key" id="97" value="1" />
|
||||
<input name="y" type="key" id="115" value="1" />
|
||||
</inputConfig>
|
||||
</inputList>
|
78
es_settings.cfg
Normal file
78
es_settings.cfg
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0"?>
|
||||
<config>
|
||||
<bool name="EnableSounds" value="false" />
|
||||
<bool name="ScrapeFanart" value="false" />
|
||||
<bool name="ScrapeManual" value="false" />
|
||||
<bool name="ScrapeMap" value="false" />
|
||||
<int name="ScreenSaverTime" value="180000" />
|
||||
<int name="recent.sort" value="7" />
|
||||
<string name="3do.HiddenExt" value="iso;bin" />
|
||||
<string name="AudioCard" value="default" />
|
||||
<string name="AudioDevice" value="Playback" />
|
||||
<string name="CollectionSystemsAuto" value="favorites, recent" />
|
||||
<string name="CollectionSystemsCustom" value="" />
|
||||
<string name="DefaultGridSize" value="" />
|
||||
<string name="FolderViewMode" value="always" />
|
||||
<string name="GameTransitionStyle" value="auto" />
|
||||
<string name="GamelistViewStyle" value="automatic" />
|
||||
<string name="HiddenSystems" value="" />
|
||||
<string name="INPUT P1" value="DEFAULT" />
|
||||
<string name="INPUT P1NAME" value="DEFAULT" />
|
||||
<string name="INPUT P2" value="DEFAULT" />
|
||||
<string name="INPUT P2NAME" value="DEFAULT" />
|
||||
<string name="INPUT P3" value="DEFAULT" />
|
||||
<string name="INPUT P3NAME" value="DEFAULT" />
|
||||
<string name="INPUT P4" value="DEFAULT" />
|
||||
<string name="INPUT P4NAME" value="DEFAULT" />
|
||||
<string name="INPUT P5" value="DEFAULT" />
|
||||
<string name="INPUT P5NAME" value="DEFAULT" />
|
||||
<string name="INPUT P6NAME" value="DEFAULT" />
|
||||
<string name="INPUT P7NAME" value="DEFAULT" />
|
||||
<string name="INPUT P8NAME" value="DEFAULT" />
|
||||
<string name="Language" value="en_US" />
|
||||
<string name="LastSystem" value="megadrive" />
|
||||
<string name="OMXAudioDev" value="both" />
|
||||
<string name="Overclock" value="none" />
|
||||
<string name="PowerSaverMode" value="default" />
|
||||
<string name="Scraper" value="ArcadeDB" />
|
||||
<string name="ScrapperImageSrc" value="ss" />
|
||||
<string name="ScrapperLogoSrc" value="" />
|
||||
<string name="ScrapperThumbSrc" value="" />
|
||||
<string name="ScreenSaverBehavior" value="black" />
|
||||
<string name="ScreenSaverDecorations" value="none" />
|
||||
<string name="ScreenSaverGameInfo" value="never" />
|
||||
<string name="ShowBattery" value="text" />
|
||||
<string name="SlideshowScreenSaverImageDir" value="/storage/screenshots" />
|
||||
<string name="SlideshowScreenSaverImageFilter" value=".png,.jpg" />
|
||||
<string name="SlideshowScreenSaverVideoDir" value="/storage/roms/mplayer" />
|
||||
<string name="SlideshowScreenSaverVideoFilter" value=".mp4,.avi,.mkv,.flv,.mpg,.mov" />
|
||||
<string name="SortSystems" value="alpha" />
|
||||
<string name="StartupSystem" value="lastsystem" />
|
||||
<string name="ThemeColorSet" value="red" />
|
||||
<string name="ThemeGamelistView" value="" />
|
||||
<string name="ThemeIconSet" value="" />
|
||||
<string name="ThemeMenu" value="" />
|
||||
<string name="ThemeRegionName" value="" />
|
||||
<string name="ThemeSet" value="es-theme-art-book-next" />
|
||||
<string name="ThemeSystemView" value="" />
|
||||
<string name="TransitionStyle" value="auto" />
|
||||
<string name="UIMode" value="Full" />
|
||||
<string name="UIMode_passkey" value="aaaba" />
|
||||
<string name="amigacd32.HiddenExt" value="iso" />
|
||||
<string name="megacd.HiddenExt" value="iso" />
|
||||
<string name="neogeocd.HiddenExt" value="iso" />
|
||||
<string name="pcenginecd.HiddenExt" value="iso;img;bin" />
|
||||
<string name="pcfx.HiddenExt" value="toc" />
|
||||
<string name="psx.HiddenExt" value="bin;img;iso" />
|
||||
<string name="saturn.HiddenExt" value="iso" />
|
||||
<string name="segacd.HiddenExt" value="iso" />
|
||||
<string name="subset.88-mph" value="on" />
|
||||
<string name="subset.airen-thumbs" value="thumb-image" />
|
||||
<string name="subset.background-art" value="on" />
|
||||
<string name="subset.blindornot" value="blind-on" />
|
||||
<string name="subset.clickset" value="click1" />
|
||||
<string name="subset.colorset" value="red" />
|
||||
<string name="subset.metadata" value="custommeta" />
|
||||
<string name="subset.themestyle" value="light" />
|
||||
<string name="tg16cd.HiddenExt" value="iso;img;bin" />
|
||||
</config>
|
2168
es_systems.cfg
Normal file
2168
es_systems.cfg
Normal file
File diff suppressed because it is too large
Load diff
195
export_func.sh
Executable file
195
export_func.sh
Executable file
|
@ -0,0 +1,195 @@
|
|||
#!/bin/bash
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2019-present Shanti Gilbert (https://github.com/shantigilbert)
|
||||
# Copyright (C) 2020-present Fewtarius
|
||||
|
||||
# This content was taken from 99-distribution.conf and made as a shell script for steam deck
|
||||
# TODO: remove absolute paths and put the variables INSTALL_DIR
|
||||
|
||||
export PATH="$PATH:/usr/local/bin:/usr/bin:/storage/bin"
|
||||
|
||||
export SDL_GAMECONTROLLERCONFIG_FILE="~/retrodeck/storage/.config/SDL-GameControllerDB/gamecontrollerdb.txt"
|
||||
|
||||
EE_DIR="~/retrodeck/storage/.config/distribution"
|
||||
EE_CONF="${EE_DIR}/configs/distribution.conf"
|
||||
ES_CONF="~/retrodeck/storage/.emulationstation/es_settings.cfg"
|
||||
EE_DEVICE=$(cat ~/retrodeck/storage/.config/.OS_ARCH)
|
||||
JSLISTENCONF="~/retrodeck/storage/.config/distribution/configs/jslisten.cfg"
|
||||
|
||||
get_ee_setting() {
|
||||
# Argument $1 is the setting name, EmuELEC settings alway start with ee_ e.g. ee_novideo
|
||||
# Usage: get_ee_setting setting [platform] [rom]
|
||||
# Only the setting argument is required
|
||||
# Priority is: GAME, PLATFORM, GLOBAL, EE_SETTING if at any point one returns 0 it means its dissabled, if it returns empty it will continue onto the next one.
|
||||
|
||||
SETTING="${1}"
|
||||
PLATFORM="${2}"
|
||||
ROM="${3}"
|
||||
|
||||
#ROM
|
||||
ROM=$(echo [\"${ROM}\"] | sed -e 's|\[|\\\[|g' | sed -e 's|\]|\\\]|g' | sed -e 's|(|\\\(|g' | sed -e 's|)|\\\)|g')
|
||||
PAT="^${PLATFORM}${ROM}[.-]${SETTING}=(.*)"
|
||||
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
|
||||
EES="${EES##*=}"
|
||||
|
||||
if [ -z "${EES}" ]; then
|
||||
#PLATFORM
|
||||
PAT="^${PLATFORM}[.-]${SETTING}=(.*)"
|
||||
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
|
||||
EES="${EES##*=}"
|
||||
fi
|
||||
|
||||
if [ -z "${EES}" ]; then
|
||||
#GLOBAL
|
||||
PAT="^global[.-]${SETTING}=(.*)"
|
||||
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
|
||||
EES="${EES##*=}"
|
||||
fi
|
||||
|
||||
if [ -z "${EES}" ]; then
|
||||
#EE_SETTINGS
|
||||
PAT="^${SETTING}=(.*)"
|
||||
EES=$(cat "${EE_CONF}" | grep -oE "${PAT}")
|
||||
EES="${EES##*=}"
|
||||
fi
|
||||
|
||||
echo "${EES}"
|
||||
}
|
||||
|
||||
set_ee_setting() {
|
||||
# argument $1 is the setting name e.g. nes.integerscale. $2 is the value, e.g "1"
|
||||
sed -i "/$1=/d" "${EE_CONF}"
|
||||
[ $2 == "disable" ] && echo "#${1}=" >> "${EE_CONF}" || echo "${1}=${2}" >> "${EE_CONF}"
|
||||
}
|
||||
|
||||
get_es_setting() {
|
||||
echo $(sed -n "s|\s*<${1} name=\"${2}\" value=\"\(.*\)\" />|\1|p" ${ES_CONF})
|
||||
}
|
||||
|
||||
|
||||
normperf() {
|
||||
# A foo function as in steam deck is not needed, however sometime it's called and I am lazy to edit everything, sorry -Xargon
|
||||
return
|
||||
}
|
||||
|
||||
maxperf() {
|
||||
# A foo function as in steam deck is not needed, however sometime it's called and I am lazy to edit everything, sorry -Xargon
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
ee_check_bios() {
|
||||
|
||||
PLATFORM="${1}"
|
||||
CORE="${2}"
|
||||
EMULATOR="${3}"
|
||||
ROMNAME="${4}"
|
||||
LOG="${5}"
|
||||
|
||||
if [[ -z "$LOG" ]]; then
|
||||
LOG="/tmp/logs/exec.log"
|
||||
cat /etc/motd > "$LOG"
|
||||
fi
|
||||
|
||||
MISSINGBIOS="$(batocera-systems --strictfilter ${PLATFORM})"
|
||||
if [ "$?" == "2" ]; then
|
||||
|
||||
# formating so it looks nice :)
|
||||
PLATFORMNAME="${MISSINGBIOS##*>}" # read from -P onwards
|
||||
PLATFORMNAME="${PLATFORMNAME%%MISSING*}" # until a space is found
|
||||
PLATFORMNAME=$(echo $PLATFORMNAME | sed -e 's/\\n//g')
|
||||
|
||||
if [[ -f "${LOG}" ]]; then
|
||||
echo "${CORE} ${EMULATOR} ${ROMNAME}" >> $LOG
|
||||
echo "${PLATFORMNAME} missing BIOS - Could not find all BIOS: " >> $LOG
|
||||
echo "please make sure you copied the files into the corresponding folder " >> $LOG
|
||||
echo "${MISSINGBIOS}" >> $LOG
|
||||
fi
|
||||
MISSINGBIOS=$(echo "$MISSINGBIOS" | sed -e 's/$/\\n/g')
|
||||
|
||||
/usr/bin/error.sh "${PLATFORMNAME} missing BIOS" "Could not find all BIOS/files in /storage/roms, the game may not work:\n\n ${MISSINGBIOS}\n\nPlease make sure you copied the files into the corresponding folder."
|
||||
error_process="$!"
|
||||
pkill -P $error_process
|
||||
fi
|
||||
}
|
||||
|
||||
message_stream () {
|
||||
local MESSAGE=$1
|
||||
local DELAY=$2
|
||||
local LOADBUFFER=0
|
||||
local ANSI=0
|
||||
for (( i=0; i<${#MESSAGE}; i++ ))
|
||||
do
|
||||
CHAR="${MESSAGE:$i:1}"
|
||||
# Is this an escape character?
|
||||
if [ "${CHAR}" == "\\" ]
|
||||
then
|
||||
LOADBUFFER=1
|
||||
BUFFER="$BUFFER${CHAR}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Is this ANSI? (\e[*[a-Z])
|
||||
if [ "${BUFFER}" == "\e[" ] && [ "${LOADBUFFER}" -eq 1 ]
|
||||
then
|
||||
ANSI=1
|
||||
BUFFER="$BUFFER${CHAR}"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${LOADBUFFER}" -eq 1 ] && [ "${ANSI}" -eq 1 ]
|
||||
then
|
||||
# If it isn't ANSI it's a control char like \n
|
||||
if [[ "${CHAR}" =~ [a-Z] ]]
|
||||
then
|
||||
echo -ne "${BUFFER}${CHAR}" >/dev/console
|
||||
unset BUFFER
|
||||
LOADBUFFER=0
|
||||
ANSI=0
|
||||
fi
|
||||
else
|
||||
# otherwise it's text
|
||||
echo -ne "${BUFFER}${CHAR}" >/dev/console
|
||||
unset BUFFER
|
||||
LOADBUFFER=0
|
||||
ANSI=0
|
||||
fi
|
||||
sleep ${DELAY}
|
||||
done
|
||||
}
|
||||
|
||||
spinny_cursor() {
|
||||
message_stream "$1" 0
|
||||
for (( c=0; c<=$2; c++ ))
|
||||
do
|
||||
echo -ne '\e[2D' '-' > /dev/console
|
||||
sleep .01
|
||||
echo -ne '\e[2D' '\\' > /dev/console
|
||||
sleep .01
|
||||
echo -ne '\e[2D' '|' > /dev/console
|
||||
sleep .01
|
||||
echo -ne '\e[2D' '/' > /dev/console
|
||||
sleep .01
|
||||
done
|
||||
echo -ne '\e[80D\e[K' > /dev/console
|
||||
}
|
||||
|
||||
jslisten() {
|
||||
# A foo function as in steam deck is not needed, however sometime it's called and I am lazy to edit everything, sorry -Xargon
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
# 351EDECK specific code
|
||||
|
||||
export -f get_ee_setting
|
||||
export -f set_ee_setting
|
||||
export -f get_es_setting
|
||||
export -f maxperf
|
||||
export -f normperf
|
||||
export -f ee_check_bios
|
||||
export -f message_stream
|
||||
export -f spinny_cursor
|
||||
#export -f jslisten
|
||||
#export -f init_port
|
248
install-retrodeck.sh
Executable file
248
install-retrodeck.sh
Executable file
|
@ -0,0 +1,248 @@
|
|||
#!/bin/bash
|
||||
|
||||
INSTALL_DIR=~/retrodeck
|
||||
CORES_LINK=https://buildbot.libretro.com/stable/1.10.1/linux/x86_64/RetroArch_cores.7z
|
||||
PREVIOUS_DIR=$PWD
|
||||
|
||||
echo "Welcome to the RetroDECK installer."
|
||||
echo "RetroDECK will be installed in $INSTALL_DIR."
|
||||
|
||||
# TODO-MAYBE: give the option to change the installation directory?
|
||||
|
||||
echo "WARNING: RetroDECK will replace your retroarch.cfg, the former one will be renamed moved in ~/.config/retroarch/retroarch.cfg.bak."
|
||||
echo "Whenever a choice is prompted just accept it to continue (yes/enter), root password will be asked."
|
||||
# but maybe it will not affect the original retroarch, let's see
|
||||
# maybe --root option of pacman may be useful to install my own copy of retroarch without messing the one already installed
|
||||
read -n 1 -r -s -p $'Press enter to continue...\n'
|
||||
echo "Installing RetroDECK in $INSTALL_DIR, please stand by."
|
||||
|
||||
cd $INSTALL_DIR
|
||||
|
||||
# TODO: download everything from retrodeck github
|
||||
# git clone --recursive https://github.com/XargonWan/RetroDECK retrodeck
|
||||
|
||||
# Initalizing rom folders
|
||||
if [ test ! -d "$INSTALL_DIR/storage/roms/" ]; then
|
||||
mkdir -p $INSTALL_DIR/storage/roms/
|
||||
fi
|
||||
if [ test ! -d "$INSTALL_DIR/roms" ]; then
|
||||
ln -s $INSTALL_DIR/storage/roms $INSTALL_DIR/roms
|
||||
fi
|
||||
mkdir -p $INSTALL_DIR/roms/3do
|
||||
mkdir -p $INSTALL_DIR/roms/amiga
|
||||
mkdir -p $INSTALL_DIR/roms/amigacd32
|
||||
mkdir -p $INSTALL_DIR/roms/amstradcpc
|
||||
mkdir -p $INSTALL_DIR/roms/arcade
|
||||
mkdir -p $INSTALL_DIR/roms/atari2600
|
||||
mkdir -p $INSTALL_DIR/roms/atari5200
|
||||
mkdir -p $INSTALL_DIR/roms/atari7800
|
||||
mkdir -p $INSTALL_DIR/roms/atarist
|
||||
mkdir -p $INSTALL_DIR/roms/atari800
|
||||
mkdir -p $INSTALL_DIR/roms/atomiswave
|
||||
mkdir -p $INSTALL_DIR/roms/channelf
|
||||
mkdir -p $INSTALL_DIR/roms/colecovision
|
||||
mkdir -p $INSTALL_DIR/roms/c64
|
||||
mkdir -p $INSTALL_DIR/roms/c128
|
||||
mkdir -p $INSTALL_DIR/roms/vic20
|
||||
mkdir -p $INSTALL_DIR/roms/laserdisc
|
||||
mkdir -p $INSTALL_DIR/roms/dreamcast
|
||||
mkdir -p $INSTALL_DIR/roms/easyrpg
|
||||
mkdir -p $INSTALL_DIR/roms/famicom
|
||||
mkdir -p $INSTALL_DIR/roms/fbn
|
||||
mkdir -p $INSTALL_DIR/roms/gb
|
||||
mkdir -p $INSTALL_DIR/roms/gbh
|
||||
mkdir -p $INSTALL_DIR/roms/gameandwatch
|
||||
mkdir -p $INSTALL_DIR/roms/gba
|
||||
mkdir -p $INSTALL_DIR/roms/fds
|
||||
mkdir -p $INSTALL_DIR/roms/c16
|
||||
mkdir -p $INSTALL_DIR/roms/ggh
|
||||
mkdir -p $INSTALL_DIR/roms/gbah
|
||||
mkdir -p $INSTALL_DIR/roms/intellivision
|
||||
mkdir -p $INSTALL_DIR/roms/gbch
|
||||
mkdir -p $INSTALL_DIR/roms/atarilynx
|
||||
mkdir -p $INSTALL_DIR/roms/mame
|
||||
mkdir -p $INSTALL_DIR/roms/dos
|
||||
mkdir -p $INSTALL_DIR/roms/snesmsu1
|
||||
mkdir -p $INSTALL_DIR/roms/msx
|
||||
mkdir -p $INSTALL_DIR/roms/msx2
|
||||
mkdir -p $INSTALL_DIR/roms/naomi
|
||||
mkdir -p $INSTALL_DIR/roms/neogeo
|
||||
mkdir -p $INSTALL_DIR/roms/ngp
|
||||
mkdir -p $INSTALL_DIR/roms/nds
|
||||
mkdir -p $INSTALL_DIR/roms/n64
|
||||
mkdir -p $INSTALL_DIR/roms/nes
|
||||
mkdir -p $INSTALL_DIR/roms/nesh
|
||||
mkdir -p $INSTALL_DIR/roms/ngpc
|
||||
mkdir -p $INSTALL_DIR/roms/neocd
|
||||
mkdir -p $INSTALL_DIR/roms/pc-9800
|
||||
mkdir -p $INSTALL_DIR/roms/pcengine
|
||||
mkdir -p $INSTALL_DIR/roms/pcenginecd
|
||||
mkdir -p $INSTALL_DIR/roms/pcfx
|
||||
mkdir -p $INSTALL_DIR/roms/openbor
|
||||
mkdir -p $INSTALL_DIR/roms/piece
|
||||
mkdir -p $INSTALL_DIR/roms/odyssey2
|
||||
mkdir -p $INSTALL_DIR/roms/psp
|
||||
mkdir -p $INSTALL_DIR/roms/pspminis
|
||||
mkdir -p $INSTALL_DIR/roms/pokemini
|
||||
mkdir -p $INSTALL_DIR/roms/homebrew
|
||||
mkdir -p $INSTALL_DIR/roms/ports
|
||||
mkdir -p $INSTALL_DIR/roms/sc-3000
|
||||
mkdir -p $INSTALL_DIR/roms/scummvm
|
||||
mkdir -p $INSTALL_DIR/roms/psx
|
||||
mkdir -p $INSTALL_DIR/roms/segacd
|
||||
mkdir -p $INSTALL_DIR/roms/sega32x
|
||||
mkdir -p $INSTALL_DIR/roms/genesis
|
||||
mkdir -p $INSTALL_DIR/roms/genh
|
||||
mkdir -p $INSTALL_DIR/roms/mastersystem
|
||||
mkdir -p $INSTALL_DIR/roms/megadrive
|
||||
mkdir -p $INSTALL_DIR/roms/megaduck
|
||||
mkdir -p $INSTALL_DIR/roms/saturn
|
||||
mkdir -p $INSTALL_DIR/roms/sg-1000
|
||||
mkdir -p $INSTALL_DIR/roms/x1
|
||||
mkdir -p $INSTALL_DIR/roms/zxspectrum
|
||||
mkdir -p $INSTALL_DIR/roms/zx81
|
||||
mkdir -p $INSTALL_DIR/roms/pc-8800
|
||||
mkdir -p $INSTALL_DIR/roms/snes
|
||||
mkdir -p $INSTALL_DIR/roms/supergrafx
|
||||
mkdir -p $INSTALL_DIR/roms/pico-8
|
||||
mkdir -p $INSTALL_DIR/roms/megacd
|
||||
mkdir -p $INSTALL_DIR/roms/snesh
|
||||
mkdir -p $INSTALL_DIR/roms/satellaview
|
||||
mkdir -p $INSTALL_DIR/roms/sfc
|
||||
mkdir -p $INSTALL_DIR/roms/sufami
|
||||
mkdir -p $INSTALL_DIR/roms/tic-80
|
||||
mkdir -p $INSTALL_DIR/roms/tg16
|
||||
mkdir -p $INSTALL_DIR/roms/solarus
|
||||
mkdir -p $INSTALL_DIR/roms/vectrex
|
||||
mkdir -p $INSTALL_DIR/roms/gbc
|
||||
mkdir -p $INSTALL_DIR/roms/videopac
|
||||
mkdir -p $INSTALL_DIR/roms/virtualboy
|
||||
mkdir -p $INSTALL_DIR/roms/wonderswan
|
||||
mkdir -p $INSTALL_DIR/roms/wonderswancolor
|
||||
mkdir -p $INSTALL_DIR/roms/ecwolf
|
||||
mkdir -p $INSTALL_DIR/roms/x68000
|
||||
mkdir -p $INSTALL_DIR/roms/build
|
||||
mkdir -p $INSTALL_DIR/roms/tools
|
||||
mkdir -p $INSTALL_DIR/roms/imageviewer
|
||||
mkdir -p $INSTALL_DIR/roms/gamegear
|
||||
mkdir -p $INSTALL_DIR/roms/tg16cd
|
||||
mkdir -p $INSTALL_DIR/roms/j2me
|
||||
mkdir -p $INSTALL_DIR/roms/uzebox
|
||||
mkdir -p $INSTALL_DIR/roms/supervision
|
||||
mkdir -p $INSTALL_DIR/roms/doom
|
||||
|
||||
# Initializing directories
|
||||
mkdir -p $INSTALL_DIR/storage/.config/
|
||||
mkdir -p $INSTALL_DIR/usr/
|
||||
mkdir -p $INSTALL_DIR/emulators
|
||||
ln -s $INSTALL_DIR/emulationstation ~/.emulationstation
|
||||
|
||||
|
||||
# Defining architecture
|
||||
rm -f $INSTALL_DIR/storage/.config/.OS_ARCH
|
||||
touch $INSTALL_DIR/storage/.config/.OS_ARCH
|
||||
echo "DECK" >> $INSTALL_DIR/storage/.config/.OS_ARCH
|
||||
|
||||
# Installing RetroArch
|
||||
sudo pacman -S retroarch
|
||||
# Setting up RetroArch
|
||||
mkdir -p ~/.config/retroarch/
|
||||
mv ~/.config/retroarch/retroarch.cfg ~/.config/retroarch/retroarch.cfg.bak
|
||||
mv $INSTALL_DIR/retroarch.cfg ~/.config/retroarch/
|
||||
# TODO: download controller config
|
||||
|
||||
# Installing libretro cores
|
||||
cd $INSTALL_DIR/emulators
|
||||
|
||||
if test -f "$INSTALL_DIR/emulators/RetroArch_cores.7z"; then
|
||||
read -p "The RetroArch cores seems to be already downloaded, do you want to re-download them? [Y/n]: " -n 1 -r
|
||||
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
||||
break
|
||||
else
|
||||
rm -rf RetroArch*
|
||||
wget $CORES_LINK
|
||||
fi
|
||||
else
|
||||
wget $CORES_LINK
|
||||
fi
|
||||
|
||||
7z x RetroArch_cores.7z
|
||||
mv $INSTALL_DIR/emulators/RetroArch-Linux-x86_64/RetroArch-Linux-x86_64.AppImage.home/.config/retroarch/cores $INSTALL_DIR/emulators/
|
||||
|
||||
# TODO: Installing standalone emulators
|
||||
|
||||
# Installing 351elec-emulationstation
|
||||
cd $INSTALL_DIR
|
||||
git clone --recursive https://github.com/351ELEC/351elec-emulationstation emulationstation
|
||||
cd emulationstation
|
||||
sudo pacman -S base-devel cmake freeimage sdl2_mixer sdl2 rapidjson boost
|
||||
cmake -DENABLE_EMUELEC=1 -DGLES2=0 -DDISABLE_KODI=1 -DENABLE_FILEMANAGER=0 -DCEC=0 -DRG552=1
|
||||
make -j$(nproc)
|
||||
cp $INSTALL_DIR/es_systems.cfg $INSTALL_DIR/emulationstation/
|
||||
cp $INSTALL_DIR/es_settings.cfg $INSTALL_DIR/emulationstation/
|
||||
cp $INSTALL_DIR/es_input.cfg $INSTALL_DIR/emulationstation/
|
||||
|
||||
# Installing default theme
|
||||
mkdir -p $INSTALL_DIR/emulationstation/themes
|
||||
cd $INSTALL_DIR/emulationstation/themes
|
||||
git clone --recursive https://github.com/anthonycaccese/es-theme-art-book-next
|
||||
|
||||
|
||||
# Downloading needed files
|
||||
# TODO 351elec-es-packages batocera-config batocera-scraper batocera-settings runemu.py setsettings.py
|
||||
|
||||
# Creating desktop element
|
||||
rm -f ~/Desktop/RetroDECK.desktop
|
||||
touch ~/Desktop/RetroDECK.desktop
|
||||
cat << EOF >> ~/Desktop/RetroDECK.desktop
|
||||
[Desktop Entry]
|
||||
Comment=An enbedded emulation system.
|
||||
Exec=$INSTALL_DIR/retrodeck.sh
|
||||
GenericName=RetroDECK
|
||||
Icon=$INSTALL_DIR/res/icon128.png
|
||||
MimeType=
|
||||
Name=RetroDECK
|
||||
Path=$INSTALL_DIR/
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
TerminalOptions=
|
||||
Type=Application
|
||||
X-DBUS-ServiceName=
|
||||
X-DBUS-StartupType=
|
||||
X-KDE-SubstituteUID=false
|
||||
X-KDE-Username=
|
||||
EOF
|
||||
|
||||
# Creating start script
|
||||
rm -rf $INSTALL_DIR/retrodeck.sh
|
||||
touch $INSTALL_DIR/retrodeck.sh
|
||||
cat << EOF >> $INSTALL_DIR/retrodeck.sh
|
||||
#!/bin/bash
|
||||
|
||||
$INSTALL_DIR/export_func.sh
|
||||
|
||||
mkdir -p /tmp/logs
|
||||
|
||||
if [ test -d "/tmp/cores" ]; then break
|
||||
else
|
||||
ln -s $INSTALL_DIR/emulators/cores /tmp/cores
|
||||
fi
|
||||
|
||||
$INSTALL_DIR/emulationstation/emulationstation
|
||||
EOF
|
||||
|
||||
chmod 777 $INSTALL_DIR/retrodeck.sh
|
||||
chmod 777 $INSTALL_DIR/export_func.sh
|
||||
|
||||
# Cleaning up
|
||||
# TODO: these removal must be made when I am sure tghis file is safe on github
|
||||
#rm -rf $INSTALL_DIR/emulators/RetroArch-Linux-x86_64
|
||||
#rm -rf $INSTALL_DIR/emulators/RetroArch_cores.7z
|
||||
#rm $INSTALL_DIR/es_systems.cfg $INSTALL_DIR/emulationstation/
|
||||
#rm $INSTALL_DIR/es_settings.cfg $INSTALL_DIR/emulationstation/
|
||||
#rm $INSTALL_DIR/es_input.cfg $INSTALL_DIR/emulationstation/
|
||||
|
||||
echo "Installation terminated, you can run RetroDECK from the desktop link or add it on your Steam Library."
|
||||
# TODO: maybe I can add it to the steam library directly, I think I have to close steam and design a banner
|
||||
|
||||
cd $PREVIOUS_DIR
|
BIN
res/icon128.png
Normal file
BIN
res/icon128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3 KiB |
BIN
res/logo.png
Normal file
BIN
res/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 95 KiB |
232
storage/.config/distribution/configs/distribution.conf
Normal file
232
storage/.config/distribution/configs/distribution.conf
Normal file
|
@ -0,0 +1,232 @@
|
|||
## ------------ A - 351ELEC configuration ------------ #
|
||||
|
||||
## Enable D-Pad to analogue at boot until we create a proper toggle
|
||||
global.analogue=1
|
||||
|
||||
## Enable SSH at boot
|
||||
ee_ssh.enabled=1
|
||||
|
||||
## Enable SAMBA at boot
|
||||
ee_samba.enabled=1
|
||||
|
||||
## Enable Bluetooth at boot
|
||||
ee_bluetooth.enabled=0
|
||||
|
||||
## Use maxperf, enable max settings for GPU and performance governer, this setting can be set globally, per platform or per game on the ES menu
|
||||
global.maxperf=0
|
||||
|
||||
## Always show boot video
|
||||
#ee_bootvideo.enabled=0
|
||||
|
||||
## Set video mode
|
||||
ee_videomode=720p60hz
|
||||
|
||||
## What to start at boot Emulationstation or Retroarch
|
||||
ee_boot=Emulationstation
|
||||
|
||||
## Enable splash screens
|
||||
ee_splash.enabled=0
|
||||
|
||||
## set to 1 if you have long loading times after quitting a game, you will lose sound mixing in ES, this only affects S905/S912 devices as all others use alsa.
|
||||
#ee_alsa.always=0
|
||||
|
||||
## Force splash screens to display for X seconds
|
||||
#ee_splash.delay=0
|
||||
|
||||
## Some external HDDs take longer to mount than ES to load, if your external ROMS do not mount in time, increase this timer
|
||||
#ee_load.delay=0
|
||||
|
||||
# Enable Advance mame auto gamepad configuration 1,0 (default 1)
|
||||
advmame_auto_gamepad=0
|
||||
|
||||
## EmulationStation menu style
|
||||
## default -> default all options menu
|
||||
## none -> no menu except the game search menu
|
||||
## bartop -> less menu, only needed for bartops
|
||||
#system.es.menu=default
|
||||
|
||||
# ------------ B - Network ------------ #
|
||||
## Set system hostname
|
||||
system.hostname=351ELEC
|
||||
## Activate wifi (0,1)
|
||||
wifi.enabled=1
|
||||
## Wifi SSID (string)
|
||||
#wifi.ssid=
|
||||
## Wifi KEY (string)
|
||||
## after rebooting the "new key" is replace by a hidden value "enc:xxxxx"
|
||||
## you can edit the "enc:xxxxx" value to replace by a clear value, it will be updated again at the following reboot
|
||||
## Escape your special chars (# ; $) with a backslash : $ => \$
|
||||
#wifi.key=
|
||||
|
||||
# secondary wifi (not configurable via the user interface)
|
||||
#wifi2.ssid=new ssid
|
||||
#wifi2.key=new key
|
||||
|
||||
# third wifi (not configurable via the user interface)
|
||||
#wifi3.ssid=new ssid
|
||||
#wifi3.key=new key
|
||||
|
||||
# ------------ C - Audio ------------ #
|
||||
## Set the audio device (auto, hdmi, jack, speakers, headphones) mostly for OdroidGoAdvance
|
||||
## Set system volume (0..100)
|
||||
## Enable or disable system sounds in ES (0,1)
|
||||
audio.bgmusic=1
|
||||
|
||||
# -------------- D - Controllers ----------------- #
|
||||
# Enable support for standard bluetooth controllers
|
||||
controllers.bluetooth.enabled=1
|
||||
|
||||
# ------------ F - Language and keyboard ------------ #
|
||||
## Set the language of the system (fr_FR,en_US,en_GB,de_DE,pt_BR,es_ES,it_IT,eu_ES,tr_TR,zh_CN)
|
||||
system.language=en_US
|
||||
## Set you local time
|
||||
## Select your timezone from : ls /usr/share/zoneinfo/ (string)
|
||||
system.timezone=Europe/London
|
||||
|
||||
# ------------ G - UPDATES ------------ #
|
||||
## Automatically check for updates at start (0,1)
|
||||
updates.enabled=1
|
||||
updates.type=release
|
||||
|
||||
# fan profile - controls fan speed (values: default/performance/quiet)
|
||||
# Not used for DECK
|
||||
# fan.profile=default
|
||||
|
||||
# ------------ H - HERE IT IS - GLOBAL EMULATOR CONFIGURATION ------------ #
|
||||
## The global value will be used for all emulators, except if the value
|
||||
## is redefined in the emulator
|
||||
|
||||
## Bezel on by default
|
||||
global.bezel=default
|
||||
|
||||
## Retroarch menu driver, ozone (default), rgui or xmb
|
||||
global.retroarch.menu_driver=ozone
|
||||
|
||||
## Shader set
|
||||
## Automatically select shaders for all systems
|
||||
## (none, retro, scanlines)
|
||||
|
||||
## Once enabled, your screen will be cropped, and you will have a pixel perfect image (0,1)
|
||||
global.integerscale=1
|
||||
|
||||
## Set gpslp shader for all emulators (prefer shadersets above). Absolute path (string)
|
||||
#global.shaders=
|
||||
|
||||
## Set ratio for all emulators (auto,4/3,16/9,16/10,custom)
|
||||
global.ratio=4/3
|
||||
|
||||
## Set autosave/load savestate for all emulators (0,1,2,3)
|
||||
global.autosave=2
|
||||
|
||||
## Set incremental savestates for all emulators (0,1)
|
||||
global.incrementalsavestates=0
|
||||
|
||||
## Set runahead frames for all emulators (0,1,2,3,4,5,6)
|
||||
global.runahead=0
|
||||
|
||||
## Set secondinstance for runahead for all emulators (0,1)
|
||||
global.secondinstance=0
|
||||
|
||||
## Enable retroarchievements (0,1)
|
||||
## Set your www.retroachievements.org username/password
|
||||
## Escape your special chars (# ; $) with a backslash : $ => \$
|
||||
global.retroachievements=1
|
||||
global.retroachievements.hardcore=0
|
||||
global.retroachievements.leaderboards=disabled
|
||||
global.retroachievements.challengeindicators=0
|
||||
global.retroachievements.richpresence=0
|
||||
global.retroachievements.testunofficial=0
|
||||
global.retroachievements.soundenable=0
|
||||
global.retroachievements.verbose=0
|
||||
global.retroachievements.screenshot=1
|
||||
global.retroachievements.username=
|
||||
global.retroachievements.password=
|
||||
|
||||
## Enable RetroArch AI game translation service
|
||||
#global.ai_service_enabled=0
|
||||
#global.ai_service_url=
|
||||
#global.ai_target_lang=
|
||||
|
||||
## Configurations generated by Emulationstation
|
||||
audio.display_titles=1
|
||||
audio.persystem=0
|
||||
global.netplay=0
|
||||
global.netplay.port=55435
|
||||
global.netplay.relay=none
|
||||
audio.device=headphone
|
||||
audio.volume=75
|
||||
brightness.level=50
|
||||
system.brightness=50
|
||||
|
||||
## Device Overclock
|
||||
overclock=0
|
||||
|
||||
# ------------ I - EMULATORS CHOICES ----------- #
|
||||
## You can override the global configuration here
|
||||
## Here is the snes example
|
||||
#snes.shaders=mysnesshader.gplsp
|
||||
|
||||
3do.maxperf=1
|
||||
3do.rewind=0
|
||||
arcade.maxperf=1
|
||||
arcade.autosave=0
|
||||
atari2600.ratio=squarepixel
|
||||
atarilynx.ratio=squarepixel
|
||||
atarilynx.shaderset=handheld/lcd3x.glslp
|
||||
atomiswave.maxperf=1
|
||||
dreamcast.maxperf=1
|
||||
fbn.ratio=squarepixel
|
||||
gamegear.bezel.overlay.grid=1
|
||||
gamegear.bezel.overlay.shadow=1
|
||||
gamegear.ratio=squarepixel
|
||||
gb.bezel.overlay.grid=1
|
||||
gb.bezel.overlay.shadow=1
|
||||
gb.ratio=squarepixel
|
||||
gba.ratio=squarepixel
|
||||
gba.shaderset=handheld/lcd3x.glslp
|
||||
gbah.ratio=squarepixel
|
||||
gbah.shaderset=handheld/lcd3x.glslp
|
||||
gbc.bezel.overlay.grid=1
|
||||
gbc.bezel.overlay.shadow=1
|
||||
gbc.ratio=squarepixel
|
||||
gbch.bezel.overlay.grid=1
|
||||
gbch.bezel.overlay.shadow=1
|
||||
gbch.ratio=squarepixel
|
||||
gbh.bezel.overlay.grid=1
|
||||
gbh.bezel.overlay.shadow=1
|
||||
gbh.ratio=squarepixel
|
||||
ggh.bezel.overlay.grid=1
|
||||
ggh.bezel.overlay.shadow=1
|
||||
ggh.ratio=squarepixel
|
||||
j2me.maxperf=1
|
||||
megadrive.ratio=squarepixel
|
||||
mame.autosave=0
|
||||
mame.maxperf=1
|
||||
n64.maxperf=1
|
||||
nds.maxperf=1
|
||||
naomi.maxperf=1
|
||||
ngp.ratio=squarepixel
|
||||
ngp.shaderset=handheld/lcd3x.glslp
|
||||
ngpc.ratio=squarepixel
|
||||
ngpc.shaderset=handheld/lcd3x.glslp
|
||||
pc.maxperf=1
|
||||
pcfx.maxperf=1
|
||||
pokemini.ratio=3/2
|
||||
psp.maxperf=1
|
||||
psp.ratio=squarepixel
|
||||
pspminis.maxperf=1
|
||||
pspminis.ratio=squarepixel
|
||||
psx.integerscaleoverscale=1
|
||||
saturn.ratio=squarepixel
|
||||
segacd.ratio=squarepixel
|
||||
supervision.bezel.overlay.grid=1
|
||||
supervision.bezel.overlay.shadow=1
|
||||
supervision.ratio=squarepixel
|
||||
uzebox.integerscale=1
|
||||
vectrex.ratio=3/4
|
||||
virtualboy.maxperf=1
|
||||
virtualboy.ratio=squarepixel
|
||||
wonderswan.ratio=squarepixel
|
||||
wonderswan.shaderset=handheld/lcd3x.glslp
|
||||
wonderswancolor.ratio=squarepixel
|
||||
wonderswancolor.shaderset=handheld/lcd3x.glslp
|
3195
storage/.config/retroarch/retroarch.cfg
Normal file
3195
storage/.config/retroarch/retroarch.cfg
Normal file
File diff suppressed because it is too large
Load diff
236
usr/bin/351elec-es-packages
Executable file
236
usr/bin/351elec-es-packages
Executable file
|
@ -0,0 +1,236 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2020-present Batocera
|
||||
# Copyright (C) 2020-present Fewtarius
|
||||
|
||||
#
|
||||
# Download and install packages supported binary packages
|
||||
#
|
||||
# Usage:
|
||||
# 351elec-es-package 'list' or 'install <package>'
|
||||
#
|
||||
# If you don't provide a <package>, the list of packages will be downloaded and sent back to you.
|
||||
#
|
||||
|
||||
ARCH="$(cat /storage/.config/.OS_ARCH)"
|
||||
if [ "${ARCH}" == "RG351P" ]; then
|
||||
DEVICE="RG351P"
|
||||
elif [ "${ARCH}" == "RG351V" ]; then
|
||||
DEVICE="RG351V"
|
||||
elif [ "${ARCH}" == "RG351MP" ]; then
|
||||
DEVICE="RG351MP"
|
||||
elif [ "${ARCH}" == "RG552" ]; then
|
||||
DEVICE="RG552"
|
||||
fi
|
||||
DISTRO="351ELEC"
|
||||
CONFIGDIR="/storage/.config/packages"
|
||||
PACKAGELIST="https://raw.githubusercontent.com/351ELEC/351ELEC-metadata/main/${ARCH}/packages.cfg"
|
||||
LOCALPACKAGELIST="/storage/.config/packages.cfg"
|
||||
|
||||
# Community Package List Schema
|
||||
#
|
||||
# {PACKAGE NAME}|{PACKAGE URL}|{SHA256SUM}
|
||||
#
|
||||
# Half_Life|https://github.com/blah/half-life-1231.zip|d06489dcf04c602ddacc6f80b2809e6d25fd6298c461966e666e19d3188e04be
|
||||
#
|
||||
# packages.cfg must be a plain text pipe delimited file.
|
||||
|
||||
# Community Package Schema
|
||||
#
|
||||
# URL: https://github.com/blah/half-life-1231.zip
|
||||
# Content:
|
||||
# half-life/ <- must match "package" name ^
|
||||
# install.sh <- must be named install.sh/uninstall.sh and be in the package root.
|
||||
# uninstall.sh
|
||||
# Relevant files/directories included in install.sh/uninstall.sh
|
||||
# Minimum:
|
||||
# system-half-life.png
|
||||
# system-half-life-thumb.png
|
||||
#
|
||||
# The package blob may be hosted elsewhere, as long as install.sh is able to download it.
|
||||
|
||||
###############################
|
||||
#
|
||||
# Prepare the system for installation
|
||||
if [ ! -d "${CONFIGDIR}" ]
|
||||
then
|
||||
mkdir -p "${CONFIGDIR}"
|
||||
fi
|
||||
|
||||
###############################
|
||||
#
|
||||
function usage() {
|
||||
echo "$0 - downloads and installs packages supported packages in ${DISTRO}"
|
||||
echo " "
|
||||
echo "It accepts two modes: 'list' and 'install <package>'"
|
||||
echo "- 'list' for the list of packages available online, and if they are"
|
||||
echo " [A]vailable to install, [I]nstalled or [?]unknown."
|
||||
echo "- 'install <package>' to install the package, from its package name."
|
||||
echo "- 'remove <package>' to delete an installed package."
|
||||
echo " "
|
||||
exit 1
|
||||
}
|
||||
|
||||
###############################
|
||||
#
|
||||
function check_url() {
|
||||
[[ "$1" =~ ^(https?|ftp)://.*$ ]] && echo "[A]" || echo "[?]"
|
||||
}
|
||||
|
||||
###############################
|
||||
#
|
||||
function git_name() {
|
||||
echo "$1" | sed "s,.*/\(.*\),\1,"
|
||||
}
|
||||
|
||||
###############################
|
||||
#
|
||||
function repo_name() {
|
||||
echo "$1" | sed "s,.*github.com/\([A-Za-z0-9_-]*\)/.*,\1,"
|
||||
}
|
||||
|
||||
###############################
|
||||
#
|
||||
function list_packages() {
|
||||
fn=$(date +"%s")
|
||||
tmp="/tmp/packages_${fn}"
|
||||
echo "* ${DISTRO} packages *"
|
||||
if [ -f ${LOCALPACKAGELIST} ]; then
|
||||
cp -f "${LOCALPACKAGELIST}" "${tmp}"
|
||||
else
|
||||
curl -H 'Cache-Control: no-cache' -sfL "${PACKAGELIST}" -o "${tmp}" || exit 1
|
||||
sed -i 's/\r$//' "${tmp}"
|
||||
fi
|
||||
while IFS=$'|' read name url shasum; do
|
||||
[ x"${name}" == "x" ] && continue
|
||||
ia=$(check_url "${url}")
|
||||
[ -d "${CONFIGDIR}"/"${name}" ] && ia="[I]"
|
||||
echo "${ia} ${name} - ${url}"
|
||||
done < "${tmp}"
|
||||
[[ -e "${tmp}" ]] && rm "${tmp}"
|
||||
}
|
||||
|
||||
|
||||
###############################
|
||||
#
|
||||
function getPer() {
|
||||
TARFILE="$1"
|
||||
TARVAL="$2"
|
||||
while true; do
|
||||
CURVAL=$(stat "$TARFILE" | grep -E '^[ ]*Size:' | sed -e s+'^[ ]*Size: \([0-9][0-9]*\) .*$'+'\1'+)
|
||||
CURVAL=$((CURVAL / 1024 / 1024))
|
||||
PER=$((${CURVAL} * 100 / ${TARVAL}))
|
||||
echo "${PER}% - ${package} - [${TARVAL}MB]"
|
||||
sleep 2
|
||||
done
|
||||
}
|
||||
|
||||
###############################
|
||||
#
|
||||
function install_package() {
|
||||
package="$1"
|
||||
success_installed=0
|
||||
fn=$(date +"%s")
|
||||
tmp="/tmp/packages_${fn}"
|
||||
if [ -f ${LOCALPACKAGELIST} ]; then
|
||||
cp -f "${LOCALPACKAGELIST}" "${tmp}"
|
||||
else
|
||||
curl -H 'Cache-Control: no-cache' -sfL "${PACKAGELIST}" -o "${tmp}" || exit 1
|
||||
sed -i 's/\r$//' "${tmp}"
|
||||
fi
|
||||
while IFS=$'|' read name url shasum; do
|
||||
[ x"${name}" != x"${package}" ] && continue
|
||||
ia=$(check_url "${url}")
|
||||
if [ x"${ia}" != x"[A]" ]; then
|
||||
echo "Error - invalid package URL ${url}"
|
||||
exit 1
|
||||
else
|
||||
cd ${CONFIGDIR}
|
||||
filename=$(echo ${url} | sed "s#^.*/##")
|
||||
curl -H 'Cache-Control: no-cache' -sfL "${url}" -o "${filename}" || exit 1
|
||||
if [ -f "${filename}" ]; then
|
||||
echo "Verifying package checksum"
|
||||
dldsum=$(sha256sum ${filename} | awk '{print $1}')
|
||||
if [ ! "${shasum}" == "${dldsum}" ]
|
||||
then
|
||||
echo "Error - Checksum does not match."
|
||||
success_installed=0
|
||||
else
|
||||
echo "Unzipping ${filename} package files >>> 99%"
|
||||
if [ -d "${CONFIGDIR}/${filename}" ]
|
||||
then
|
||||
rm -rf "${CONFIGDIR}/${filename}"
|
||||
fi
|
||||
unzip "${filename}" >/dev/null 2>&1
|
||||
rm "${filename}"
|
||||
echo "Installing ${filename} package"
|
||||
sh ./${package}/install.sh
|
||||
if [ $? == 0 ]
|
||||
then
|
||||
success_installed=1
|
||||
else
|
||||
echo "Error - Installation failed."
|
||||
success_installed=0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Error - ${package} zip file could not be downloaded from ${url}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done < "${tmp}"
|
||||
[[ -e "${tmp}" ]] && rm "${tmp}"
|
||||
if [ "${success_installed}" == 1 ]; then
|
||||
echo "${package} is now installed >>> 100%"
|
||||
exit 0
|
||||
else
|
||||
echo "Error - ${package} could not be installed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
###############################
|
||||
#
|
||||
function remove_package() {
|
||||
package="$1"
|
||||
success_removed=0
|
||||
filename=${package}
|
||||
if [ -d "${CONFIGDIR}/${package}" ]; then
|
||||
sh ${CONFIGDIR}/${package}/uninstall.sh
|
||||
if [ $? == 0 ]
|
||||
then
|
||||
rm -rf "${CONFIGDIR}"/"${filename}" && success_removed=1
|
||||
else
|
||||
echo "Unable to uninstall ${package}"
|
||||
success_removed=0
|
||||
fi
|
||||
else
|
||||
echo "${package} doesn't appear to be in ${CONFIGDIR}/${filename}"
|
||||
fi
|
||||
if [ "${success_removed}" == 1 ]; then
|
||||
TERMINAL=0 && echo "${package} uninstalled >>>100"
|
||||
exit 0
|
||||
else
|
||||
echo "Error - ${package} could not be removed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
#### Main loop
|
||||
#
|
||||
command="$1"
|
||||
package="$2"
|
||||
|
||||
if ! [ -d "${CONFIGDIR}" ]; then
|
||||
echo "Error - package directory ${CONFIGDIR} is not valid."
|
||||
exit 1
|
||||
fi
|
||||
if [ x"${command}" == "xlist" ]; then
|
||||
list_packages
|
||||
elif [ x"${command}" == "xinstall" ]; then
|
||||
[ x"${package}" != "x" ] && install_package ${package} || usage
|
||||
elif [ x"${command}" == "xremove" ]; then
|
||||
[ x"${package}" != "x" ] && remove_package ${package} || usage
|
||||
else
|
||||
usage
|
||||
fi
|
373
usr/bin/batocera-config
Executable file
373
usr/bin/batocera-config
Executable file
|
@ -0,0 +1,373 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ ! "$1" ];then
|
||||
echo -e "usage : batocera-config [command] [args]\nWith command in\n\toverscan [enable|disable]\n\tlsaudio\n\tgetaudio\n\taudio [hdmi|jack|auto|custom|x,y]\n\tcanupdate\n\tupdate\n\twifi [enable|disable] ssid key\n\tstorage [current|list|INTERNAL|ANYEXTERNAL|RAM|DEV UUID]\n\tsetRootPassword [password]\n\tgetRootPassword\n\ttz [|tz]"
|
||||
exit 1
|
||||
fi
|
||||
configFile="/storage/.config/distribution/configs/config.txt"
|
||||
storageFile="/storage/.config/distribution/configs/batocera-boot.conf"
|
||||
command="$1"
|
||||
mode="$2"
|
||||
extra1="$3"
|
||||
extra2="$4"
|
||||
extra3="$5"
|
||||
extra4="$6"
|
||||
arch=$(cat /storage/.config/.OS_ARCH)
|
||||
|
||||
updateurl="https://127.0.0.1"
|
||||
|
||||
preBootConfig() {
|
||||
mount -o remount,rw /boot
|
||||
}
|
||||
|
||||
postBootConfig() {
|
||||
mount -o remount,ro /boot
|
||||
}
|
||||
|
||||
bato_config_set_value () {
|
||||
key=$1
|
||||
value=$2
|
||||
[ -z "$value" ] && value=0
|
||||
cat "$configFile" | grep "$key"
|
||||
valPresent=$?
|
||||
if [ "$valPresent" != "0" ];then
|
||||
echo "$key=$value" >> "$configFile"
|
||||
else
|
||||
sed -i "s/#\?$key=.*/$key=$value/g" "$configFile"
|
||||
fi
|
||||
}
|
||||
|
||||
#log=/userdata/system/logs/batocera.log
|
||||
#systemsetting="python /usr/lib/python2.7/site-packages/configgen/settings/batoceraSettings.py"
|
||||
|
||||
log=/tmp/logs/systemsettings.log
|
||||
systemsetting="/usr/bin/batocera-settings"
|
||||
|
||||
|
||||
echo "----config ----" >> $log
|
||||
|
||||
if [ "$command" == "getRootPassword" ]; then
|
||||
# security disabled, force the default one without changing boot configuration
|
||||
securityenabled="`$systemsetting -command load -key system.security.enabled`"
|
||||
if [ "$securityenabled" != "1" ];then
|
||||
echo "linux"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ENCPASSWD=$(grep -E '^[ \t]*rootshadowpassword[ \t]*=' "${storageFile}" | sed -e s+'^[ \t]*rootshadowpassword[ \t]*='++)
|
||||
if test -z "${ENCPASSWD}"
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
if ! batocera-encode decode "${ENCPASSWD}"
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$command" == "setRootPassword" ]; then
|
||||
PASSWD=${2}
|
||||
|
||||
# security disabled, don't change
|
||||
securityenabled="`$systemsetting -command load -key system.security.enabled`"
|
||||
if [ "$securityenabled" != "1" ];then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# if no password if provided, generate one
|
||||
if test -z "${PASSWD}"
|
||||
then
|
||||
PASSWD=$(tr -cd _A-Z-a-z-0-9 < /dev/urandom | fold -w8 | head -n1)
|
||||
fi
|
||||
PASSWDENC=$(batocera-encode encode "${PASSWD}")
|
||||
|
||||
preBootConfig
|
||||
if grep -qE '^[ \t]*rootshadowpassword[ \t]*=' "${storageFile}"
|
||||
then
|
||||
# update it
|
||||
if ! sed -i -e s@'^[ \t]*rootshadowpassword[ \t]*=.*$'@"rootshadowpassword=${PASSWDENC}"@ "${storageFile}"
|
||||
then
|
||||
postBootConfig
|
||||
exit 1
|
||||
fi
|
||||
postBootConfig
|
||||
exit 0
|
||||
else
|
||||
# create it
|
||||
if ! echo "rootshadowpassword=${PASSWDENC}" >> "${storageFile}"
|
||||
then
|
||||
postBootConfig
|
||||
exit 1
|
||||
fi
|
||||
postBootConfig
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$command" == "overscan" ]; then
|
||||
if [ "$mode" == "set" ];then
|
||||
# set will set overscan values abd also enable this mode
|
||||
if [ -z "$extra1" ] || [ -z "$extra2" ] || [ -z "$extra3" ] || [ -z "$extra4" ]; then
|
||||
echo "$0 $command $mode needs 4 arguments:"
|
||||
echo "$0 $command $mode overscan_left overscan_right overscan_top overscan_bottom"
|
||||
exit 2
|
||||
fi
|
||||
preBootConfig
|
||||
[ -f "$configFile" ] || touch "$configFile"
|
||||
|
||||
echo "setting overscan values $extra1 $extra2 $extra3 $extra4 " >> $log
|
||||
bato_config_set_value disable_overscan 0
|
||||
bato_config_set_value overscan_scale 1
|
||||
bato_config_set_value overscan_left "$extra1"
|
||||
bato_config_set_value overscan_right "$extra2"
|
||||
bato_config_set_value overscan_top "$extra3"
|
||||
bato_config_set_value overscan_bottom "$extra4"
|
||||
|
||||
postBootConfig
|
||||
exit 0
|
||||
|
||||
fi
|
||||
if [ -f "$configFile" ];then
|
||||
preBootConfig
|
||||
if [ "$mode" == "enable" ];then
|
||||
echo "enabling overscan" >> $log
|
||||
bato_config_set_value disable_overscan 0
|
||||
bato_config_set_value overscan_scale 1
|
||||
elif [ "$mode" == "disable" ];then
|
||||
echo "disabling overscan" >> $log
|
||||
bato_config_set_value disable_overscan 1
|
||||
bato_config_set_value overscan_scale 0
|
||||
else
|
||||
postBootConfig
|
||||
exit 1
|
||||
fi
|
||||
postBootConfig
|
||||
exit 0
|
||||
else
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$command" == "lsoutputs" ]
|
||||
then
|
||||
echo "auto"
|
||||
batocera-resolution listOutputs
|
||||
fi
|
||||
|
||||
if [ "$command" == "lsaudio" ];then
|
||||
if [[ "${arch}" =~ "rpi" ]]
|
||||
then
|
||||
echo "hdmi"
|
||||
echo "jack"
|
||||
echo "auto"
|
||||
elif [[ "${arch}" =~ "x86" ]];then
|
||||
echo "auto"
|
||||
echo "custom"
|
||||
LANG=C aplay -l | grep -E '^card [0-9]*:' | sed -e s+'^card \([0-9]*\): \([^,]*\), device \([0-9]*\): [^\[]* \[\([^]]*\)].*$'+'\1,\3 \4 \2'+
|
||||
else
|
||||
echo "auto"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$command" == "getaudio" ];then
|
||||
$systemsetting -command load -key audio.device
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$command" == "audio" ];then
|
||||
# this code is specific to the rpi
|
||||
# don't set it on other boards
|
||||
# find a more generic way would be nice
|
||||
if [[ "${arch}" =~ "rpi" ]]
|
||||
then
|
||||
# this is specific to the rpi
|
||||
cmdVal="0"
|
||||
if [ "$mode" == "hdmi" ];then
|
||||
cmdVal="2"
|
||||
elif [ "$mode" == "jack" ];then
|
||||
cmdVal="1"
|
||||
fi
|
||||
echo "setting audio output mode : $mode" >> $log
|
||||
amixer cset numid=3 $cmdVal || exit 1
|
||||
elif [[ "${arch}" =~ "x86" ]]
|
||||
then
|
||||
# auto: no .asoundrc file
|
||||
# custom: don't touch the .asoundrc file
|
||||
# any other, create the .asoundrd file
|
||||
if [ "$mode" == "auto" ];then
|
||||
rm -rf /userdata/system/.asoundrc || exit 1
|
||||
elif [ "$mode" != "custom" ];then
|
||||
if echo "${mode}" | grep -qE '^[0-9]*,[0-9]* '
|
||||
then
|
||||
cardnb=$(echo "${mode}" | sed -e s+'^\([0-9]*\),.*$'+'\1'+)
|
||||
devicenb=$(echo "${mode}" | sed -e s+'^[0-9]*,\([0-9]*\) .*$'+'\1'+)
|
||||
cat > /userdata/system/.asoundrc <<EOF
|
||||
pcm.!default { type plug slave { pcm "hw:${cardnb},${devicenb}" } }
|
||||
ctl.!default { type hw card ${cardnb} }
|
||||
EOF
|
||||
aplay "/usr/share/sounds/Mallet.wav"
|
||||
fi
|
||||
fi
|
||||
elif [[ "${arch}" =~ RG351 ]]
|
||||
then
|
||||
case "${mode}" in
|
||||
"auto"|"speakers")
|
||||
amixer cset name='Playback Path' SPK
|
||||
;;
|
||||
"headphone")
|
||||
amixer cset name='Playback Path' HP
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$command" == "volume" ];then
|
||||
if [ "$mode" != "" ];then
|
||||
echo "setting audio volume : $mode" >> $log
|
||||
|
||||
# on my pc, the master is turned off at boot
|
||||
# i don't know what are the rules to set here.
|
||||
amixer set Master unmute || exit 1
|
||||
amixer set Master -- ${mode}% || exit 1
|
||||
|
||||
# maximize the sound to be sure it's not 0, allow errors
|
||||
amixer set PCM -- 100% #|| exit 1
|
||||
amixer set Headphone -- 100% #|| exit 1
|
||||
exit 0
|
||||
fi
|
||||
exit 12
|
||||
fi
|
||||
|
||||
if [ "$command" == "gpiocontrollers" ];then
|
||||
command="module"
|
||||
mode="load"
|
||||
extra1="mk_arcade_joystick_rpi"
|
||||
extra2="map=1,2"
|
||||
fi
|
||||
|
||||
if [ "$command" == "module" ];then
|
||||
modulename="$extra1"
|
||||
map="$extra2"
|
||||
# remove in all cases
|
||||
rmmod /lib/modules/`uname -r`/extra/${modulename}.ko >> $log
|
||||
|
||||
if [ "$mode" == "load" ];then
|
||||
echo "loading module $modulename args = $map" >> $log
|
||||
insmod /lib/modules/`uname -r`/extra/${modulename}.ko $map >> $log
|
||||
[ "$?" ] || exit 1
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$command" == "canupdate" ];then
|
||||
available=$(updatecheck canupdate)
|
||||
echo "$available"
|
||||
if [[ "$available" != "no" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
exit 12
|
||||
fi
|
||||
|
||||
if [ "$command" == "update" ];then
|
||||
351elec-upgrade
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ "$command" == "wifi" ]]; then
|
||||
ssid="$3"
|
||||
psk="$4"
|
||||
|
||||
if [[ "$mode" == "enable" ]]; then
|
||||
echo "configure wifi" >> $log
|
||||
mkdir -p "/storage/.cache/connman" || exit 1
|
||||
cat > "/storage/.cache/connman/wifi.config" <<EOF
|
||||
[global]
|
||||
Name=351elec
|
||||
|
||||
[service_351elec_default]
|
||||
Type=wifi
|
||||
Name=${ssid}
|
||||
EOF
|
||||
if test "${psk}" != ""
|
||||
then
|
||||
echo "Passphrase=${psk}" >> "/storage/.cache/connman/wifi.config"
|
||||
fi
|
||||
# Power up the WIFI device
|
||||
if [ "$(cat /sys/firmware/devicetree/base/model)" == "Anbernic RG552" ]; then
|
||||
echo 1 > /sys/class/gpio/gpio113/value
|
||||
else
|
||||
echo 1 > /sys/class/gpio/gpio5/value
|
||||
fi
|
||||
sleep 3
|
||||
connmanctl enable wifi || exit 1
|
||||
connmanctl scan wifi || exit 1
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$mode" =~ "start" ]]; then
|
||||
if [[ "$mode" != "forcestart" ]]; then
|
||||
settingsWlan="`$systemsetting -command load -key wifi.enabled`"
|
||||
if [ "$settingsWlan" != "1" ];then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# Power up the WIFI device
|
||||
if [ "$(cat /sys/firmware/devicetree/base/model)" == "Anbernic RG552" ]; then
|
||||
echo 1 > /sys/class/gpio/gpio113/value
|
||||
else
|
||||
echo 1 > /sys/class/gpio/gpio5/value
|
||||
fi
|
||||
sleep 3
|
||||
connmanctl enable wifi || exit 1
|
||||
connmanctl scan wifi || exit 1
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$mode" == "disable" ]]; then
|
||||
connmanctl disable wifi
|
||||
# Power down the WIFI device
|
||||
if [ "$(cat /sys/firmware/devicetree/base/model)" == "Anbernic RG552" ]; then
|
||||
echo 0 > /sys/class/gpio/gpio113/value
|
||||
else
|
||||
echo 0 > /sys/class/gpio/gpio5/value
|
||||
fi
|
||||
exit $?
|
||||
fi
|
||||
if [[ "$mode" == "list" ]]; then
|
||||
WAVAILABLE=$(connmanctl services | cut -b 5- | sed -e s+'^\([^ ]*\).*$'+'\1'+ | grep -vE '^Wired$|^<hidden>$')
|
||||
if test -n "${ssid}"
|
||||
then
|
||||
echo "${WAVAILABLE}" | grep -qE '^'"${ssid}"'$' || echo "${ssid}"
|
||||
fi
|
||||
echo "${WAVAILABLE}"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$command" == "storage" ]]; then
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if [[ "$command" == "forgetBT" ]]; then
|
||||
killall -9 hcitool
|
||||
systemctl stop bluetooth
|
||||
rm -rf /storage/.cache/bluetooth/*
|
||||
systemctl start bluetooth
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$command" == "tz" ];then
|
||||
if test "$mode" == ""
|
||||
then
|
||||
cat /storage/.config/distribution/configs/tz
|
||||
else
|
||||
if test -f "/usr/share/zoneinfo/${mode}"
|
||||
then
|
||||
echo "TIMEZONE=${mode}" > /storage/.cache/timezone
|
||||
systemctl restart tz-data.service
|
||||
fi
|
||||
fi
|
||||
exit $?
|
||||
fi
|
||||
|
||||
exit 10
|
84
usr/bin/batocera-scraper
Executable file
84
usr/bin/batocera-scraper
Executable file
|
@ -0,0 +1,84 @@
|
|||
#!/bin/bash
|
||||
|
||||
# If we are on Steam Deck
|
||||
arch=$(cat /storage/.config/.OS_ARCH)
|
||||
if [ $arch == "DECK" ];then
|
||||
INSTALL_DIR="~/retrodeck"
|
||||
|
||||
systemsetting=$INSTALL_DIR+"/usr/bin/batocera-settings"
|
||||
syslang=$($systemsetting -command load -key system.language)
|
||||
IMGSTYLE=$($systemsetting -command load -key scrapper.style)
|
||||
|
||||
if test $# = 1
|
||||
then
|
||||
DOSYS=$1
|
||||
fi
|
||||
|
||||
# supported languages : en, fr, es, de, pt
|
||||
case "${syslang}" in
|
||||
fr_FR)
|
||||
sslang=fr,en
|
||||
;;
|
||||
es_ES)
|
||||
sslang=es,en
|
||||
;;
|
||||
de_DE)
|
||||
sslang=de,en
|
||||
;;
|
||||
pt_PT)
|
||||
sslang=pt,en
|
||||
;;
|
||||
pt_BR)
|
||||
sslang=pt,en
|
||||
;;
|
||||
*)
|
||||
sslang=en
|
||||
esac
|
||||
|
||||
if test -z "${IMGSTYLE}"
|
||||
then
|
||||
IMGSTYLE="b,f,a,l,3b,s"
|
||||
fi
|
||||
|
||||
do_scrap() {
|
||||
LRDIR=$1
|
||||
NF=$(ls "${LRDIR}" | grep -vE '\.txt$|\.xml$' | wc -l)
|
||||
if test "${NF}" -gt 0
|
||||
then
|
||||
BASEDIR=$(basename "${LRDIR}")
|
||||
echo "GAME: system ${BASEDIR}"
|
||||
EXTRAOPT=
|
||||
|
||||
for x in "mame" "fba" "fba_libretro" "neogeo"
|
||||
do
|
||||
test "${LRDIR}" = $INSTALL_DIR+"/storage/roms/${x}" && EXTRAOPT="-mame"
|
||||
done
|
||||
|
||||
(cd "${LRDIR}" && sselph-scraper -console_src ss,gdb,ovgdb -lang "${sslang}" -console_img "${IMGSTYLE}" -download_videos -workers 5 ${EXTRAOPT}) 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
# find system to scrape
|
||||
(if test -n "${DOSYS}"
|
||||
then
|
||||
test -d $INSTALL_DIR+"/storage/roms/${DOSYS}" && echo $INSTALL_DIR+"/storage/roms/${DOSYS}"
|
||||
else
|
||||
find /storage/roms -maxdepth 1 -mindepth 1 -type d
|
||||
fi) |
|
||||
while read RDIR1
|
||||
do
|
||||
# read the 2 next dir
|
||||
read RDIR2
|
||||
read RDIR3
|
||||
read RDIR4
|
||||
|
||||
do_scrap "${RDIR1}" &
|
||||
test -n "${RDIR2}" && do_scrap "${RDIR2}" &
|
||||
test -n "${RDIR3}" && do_scrap "${RDIR3}" &
|
||||
test -n "${RDIR4}" && do_scrap "${RDIR4}" &
|
||||
wait
|
||||
|
||||
done
|
||||
|
||||
# synchronize to not make the usb/sdcard slowing down once finnished
|
||||
sync
|
272
usr/bin/batocera-settings
Executable file
272
usr/bin/batocera-settings
Executable file
|
@ -0,0 +1,272 @@
|
|||
#!/bin/bash
|
||||
|
||||
# batocera-settings can mimic batoceraSettings.py
|
||||
# goal: abolish this python script, it's useless for the sake of the load feature only
|
||||
# get a more user friendly environment for setting, getting and saving keys
|
||||
#
|
||||
# Usage of BASE COMMAND:
|
||||
# longform: <filename> --command <cmd> --key <key> --value <value>
|
||||
#
|
||||
# shortform: <file> <cmd> <key> <value>
|
||||
#
|
||||
# --command load write enable disable status
|
||||
# --key any key in emuelec.conf (kodi.enabled...)
|
||||
# --value any alphanumerical string
|
||||
# use quotation marks to avoid globbing use slashes escape special characters
|
||||
|
||||
# This script reads only 1st occurrence if string and writes only to this first hit
|
||||
#
|
||||
# This script uses #-Character to comment values
|
||||
#
|
||||
# If there is a boolean value (0,1) then then enable and disable command will set the corresponding
|
||||
# boolean value.
|
||||
|
||||
# Examples:
|
||||
# 'batocera-settings --command load --key wifi.enabled' will print out 0 or 1
|
||||
# 'batocera-settings --command write --key wifi.ssid -value "This is my NET"' will set 'wlan.ssid=This is my NET'
|
||||
# 'batocera-settings enable wifi.ssid' will remove # from configfile (activate)
|
||||
# 'batocera-settings disable wifi.enabled' will set key wifi.enabled=0
|
||||
# 'botocera-settings /myown/config.file --command status --key my.key' will output status of own config.file and my.key
|
||||
|
||||
# by cyperghost - 2019/12/30
|
||||
|
||||
##### INITS #####
|
||||
# If we are on Steam Deck
|
||||
arch=$(cat /storage/.config/.OS_ARCH)
|
||||
if [ $arch == "DECK" ];then
|
||||
INSTALL_DIR="~/retrodeck"
|
||||
|
||||
BATOCERA_CONFIGFILE=$INSTALL_DIR+"/storage/.config/distribution/configs/distribution.conf"
|
||||
COMMENT_CHAR_SEARCH="[#|;]"
|
||||
COMMENT_CHAR="#"
|
||||
##### INITS #####
|
||||
|
||||
##### Function Calls #####
|
||||
|
||||
function get_config() {
|
||||
#Will search for key.value and #key.value for only one occurrence
|
||||
#If the character is the COMMENT CHAR then set value to it
|
||||
#Otherwise strip till the equal-char to obtain value
|
||||
local val
|
||||
local ret
|
||||
val="$(grep -E -m1 "^\s*$1\s*=" $BATOCERA_CONFIGFILE)"
|
||||
ret=$?
|
||||
if [[ $ret -eq 1 ]]; then
|
||||
val="$(grep -E -m1 "^$COMMENT_CHAR_SEARCH\s*$1\s*=" $BATOCERA_CONFIGFILE)"
|
||||
ret=$?
|
||||
[[ $ret -eq 0 ]] && val=$COMMENT_CHAR
|
||||
else
|
||||
#Maybe here some finetuning to catch key.value = ENTRY without blanks
|
||||
val="${val#*=}"
|
||||
fi
|
||||
echo "$val"
|
||||
return $ret
|
||||
}
|
||||
|
||||
function set_config() {
|
||||
#Will search for first key.name at beginning of line and write value to it
|
||||
sed -i "1,/^\(\s*$1\s*=\).*/s//\1$2/" "$BATOCERA_CONFIGFILE"
|
||||
}
|
||||
|
||||
function uncomment_config() {
|
||||
#Will search for first Comment Char at beginning of line and remove it
|
||||
sed -i "1,/^$COMMENT_CHAR_SEARCH\(\s*$1\)/s//\1/" "$BATOCERA_CONFIGFILE"
|
||||
}
|
||||
|
||||
function comment_config() {
|
||||
#Will search for first key.name at beginning of line and add a comment char to it
|
||||
sed -i "1,/^\(\s*$1\)/s//$COMMENT_CHAR\1/" "$BATOCERA_CONFIGFILE"
|
||||
}
|
||||
|
||||
function check_argument() {
|
||||
# This method does not accept arguments starting with '-'.
|
||||
if [[ -z "$2" || "$2" =~ ^- ]]; then
|
||||
echo >&2
|
||||
echo "ERROR: '$1' is missing an argument." >&2
|
||||
echo >&2
|
||||
echo "Just type '$0' to see usage page." >&2
|
||||
echo >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function dash_style() {
|
||||
#This function is needed to "simulate" the python script with single dash
|
||||
#commands. It will also accept the more common posix double dashes
|
||||
#Accept dashes and double dashes and build new array ii with parameter set
|
||||
#The else-branch can be used for the shortform
|
||||
|
||||
for i in --command --key --value; do
|
||||
if [[ -z "$1" ]]; then
|
||||
continue
|
||||
elif [[ "$i" =~ ^-{0,1}"${1,,}" ]]; then
|
||||
check_argument $1 $2
|
||||
[[ $? -eq 0 ]] || exit 1
|
||||
ii+=("$2")
|
||||
shift 2
|
||||
else
|
||||
ii+=("$1")
|
||||
shift 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
function usage() {
|
||||
val=" Usage of BASE COMMAND:
|
||||
|
||||
<file> --command <cmd> --key <key> --value <value>
|
||||
|
||||
shortform: <file> <cmd> <key> <value>
|
||||
|
||||
--command load write enable disable status
|
||||
--key any key in emuelec.conf (kodi.enabled...)
|
||||
--value any alphanumerical string
|
||||
use quotation marks to avoid globbing
|
||||
|
||||
For write command --value <value> must be provided
|
||||
|
||||
exit codes: exit 0 = value is available, proper exit
|
||||
exit 1 = general error
|
||||
exit 2 = file error
|
||||
exit 10 = value found, but empty
|
||||
exit 11 = value found, but not activated
|
||||
exit 12 = value not found
|
||||
|
||||
If you don't set a filename then default is '~/storage/.config/distribution.conf'"
|
||||
|
||||
echo "$val"
|
||||
|
||||
}
|
||||
##### Function Calls #####
|
||||
|
||||
##### MAIN FUNCTION #####
|
||||
function main() {
|
||||
|
||||
#Filename parsed?
|
||||
if [[ -f "$1" ]]; then
|
||||
BATOCERA_CONFIGFILE="$1"
|
||||
shift
|
||||
else
|
||||
[[ -f "$BATOCERA_CONFIGFILE" ]] || { echo "not found: $BATOCERA_CONFIGFILE" >&2; exit 2; }
|
||||
fi
|
||||
|
||||
#How much arguments are parsed, up to 6 then it is the long format
|
||||
#up to 3 then it is the short format
|
||||
if [[ ${#@} -eq 0 || ${#@} -gt 6 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
else
|
||||
dash_style "$@"
|
||||
command="${ii[0]}"
|
||||
keyvalue="${ii[1]}"
|
||||
newvalue="${ii[2]}"
|
||||
unset ii
|
||||
fi
|
||||
|
||||
[[ -z $keyvalue ]] && { echo "error: Please provide a proper keyvalue" >&2; exit 1; }
|
||||
|
||||
# value processing, switch case
|
||||
case "${command,,}" in
|
||||
|
||||
"read"|"get"|"load")
|
||||
val="$(get_config $keyvalue)"
|
||||
ret=$?
|
||||
[[ "$val" == "$COMMENT_CHAR" ]] && exit 11
|
||||
[[ -z "$val" && $ret -eq 0 ]] && exit 10
|
||||
[[ -z "$val" && $ret -eq 1 ]] && exit 12
|
||||
[[ -n "$val" ]] && echo "$val" && exit 0
|
||||
;;
|
||||
|
||||
"stat"|"status")
|
||||
val="$(get_config $keyvalue)"
|
||||
ret=$?
|
||||
[[ -f "$BATOCERA_CONFIGFILE" ]] && echo "ok: found '$BATOCERA_CONFIGFILE'" >&2 || echo "error: not found '$BATOCERA_CONFIGFILE'" >&2
|
||||
[[ -w "$BATOCERA_CONFIGFILE" ]] && echo "ok: r/w file '$BATOCERA_CONFIGFILE'" >&2 || echo "error: r/o file '$BATOCERA_CONFIGFILE'" >&2
|
||||
[[ -z "$val" && $ret -eq 1 ]] && echo "error: '$keyvalue' not found!" >&2
|
||||
[[ -z "$val" && $ret -eq 0 ]] && echo "error: '$keyvalue' is empty - use 'comment' command to retrieve" >&2
|
||||
[[ "$val" == "$COMMENT_CHAR" ]] && echo "error: '$keyvalue' is commented $COMMENT_CHAR!" >&2 && val=
|
||||
[[ -n "$val" ]] && echo "ok: '$keyvalue' $val"
|
||||
exit 0
|
||||
;;
|
||||
|
||||
"set"|"write"|"save")
|
||||
#Is file write protected?
|
||||
[[ -w "$BATOCERA_CONFIGFILE" ]] || { echo "r/o file: $BATOCERA_CONFIGFILE" >&2; exit 2; }
|
||||
#We can comment line above to erase keys, it's much saver to check if a value is setted
|
||||
[[ -z "$newvalue" ]] && echo "error: '$keyvalue' needs value to be setted" >&2 && exit 1
|
||||
|
||||
val="$(get_config $keyvalue)"
|
||||
ret=$?
|
||||
if [[ "$val" == "$COMMENT_CHAR" ]]; then
|
||||
echo "$keyvalue: hashed out!" >&2
|
||||
uncomment_config "$keyvalue"
|
||||
set_config "$keyvalue" "$newvalue"
|
||||
echo "$keyvalue: set from '$val' to '$newvalue'" >&2
|
||||
exit 0
|
||||
elif [[ -z "$val" && $ret -eq 1 ]]; then
|
||||
echo "$keyvalue: not found!" >&2
|
||||
exit 12
|
||||
elif [[ "$val" != "$newvalue" ]]; then
|
||||
set_config "$keyvalue" "$newvalue"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
|
||||
"uncomment"|"enable"|"activate")
|
||||
val="$(get_config $keyvalue)"
|
||||
ret=$?
|
||||
# Boolean
|
||||
if [[ "$val" == "$COMMENT_CHAR" ]]; then
|
||||
uncomment_config "$keyvalue"
|
||||
echo "$keyvalue: removed '$COMMENT_CHAR', key is active" >&2
|
||||
elif [[ "$val" == "0" ]]; then
|
||||
set_config "$keyvalue" "1"
|
||||
echo "$keyvalue: boolean set '1'" >&2
|
||||
elif [[ -z "$val" && $ret -eq 1 ]]; then
|
||||
echo "$keyvalue: not found!" && exit 2
|
||||
fi
|
||||
;;
|
||||
|
||||
"comment"|"disable"|"remark")
|
||||
val="$(get_config $keyvalue)"
|
||||
ret=$?
|
||||
# Boolean
|
||||
[[ "$val" == "$COMMENT_CHAR" || "$val" == "0" ]] && exit 0
|
||||
if [[ -z "$val" && $ret -eq 1 ]]; then
|
||||
echo "$keyvalue: not found!" >&2 && exit 12
|
||||
elif [[ "$val" == "1" ]]; then
|
||||
set_config "$keyvalue" "0"
|
||||
echo "$keyvalue: boolean set to '0'" >&2
|
||||
else
|
||||
comment_config "$keyvalue"
|
||||
echo "$keyvalue: added '$COMMENT_CHAR', key is not active" >&2
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "ERROR: invalid command '$command'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
##### MAIN FUNCTION #####
|
||||
|
||||
##### MAIN CALL #####
|
||||
|
||||
# Prepare arrays from fob python script
|
||||
# Keyword for python call is mimic_python
|
||||
# Attention the unset is needed to eliminate first argument (python basefile)
|
||||
|
||||
if [[ "${#@}" -eq 1 && "$1" =~ "mimic_python" ]]; then
|
||||
#batoceraSettings.py fob
|
||||
readarray -t arr <<< "$1"
|
||||
unset arr[0]
|
||||
else
|
||||
#regular call by shell
|
||||
arr=("$@")
|
||||
fi
|
||||
|
||||
main "${arr[@]}"
|
||||
|
||||
##### MAIN CALL #####
|
405
usr/bin/runemu.py
Executable file
405
usr/bin/runemu.py
Executable file
|
@ -0,0 +1,405 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from time import perf_counter
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from setsettings import set_settings
|
||||
|
||||
# If we are on Steam Deck we want a prefix
|
||||
|
||||
# TODO: INSTALL_DIR + '/storage/.config/.OS_ARCH' was not working, dunno why, I'll check later
|
||||
# DEVICE = "DECK" #for the moment this will do
|
||||
|
||||
INSTALL_DIR = os.path.expanduser('~/retrodeck')
|
||||
with open(INSTALL_DIR + r'/storage/.config/.OS_ARCH', 'r') as file:
|
||||
DEVICE = file.read().rstrip()
|
||||
|
||||
#if DEVICE == "DECK" :
|
||||
#
|
||||
#else:
|
||||
# INSTALL_DIR = ""
|
||||
|
||||
if TYPE_CHECKING:
|
||||
#These except Union are deprecated in 3.9 and should be replaced with collections.abc / builtin list type, but we have 3.8 for now
|
||||
from typing import List, Mapping, MutableMapping, Sequence, Union
|
||||
|
||||
LOGS_DIR = Path('/tmp/logs')
|
||||
RA_TEMP_CONF = INSTALL_DIR + '/storage/.config/retroarch/retroarch.cfg'
|
||||
RA_APPEND_CONF = '/tmp/raappend.cfg'
|
||||
log_path = LOGS_DIR / 'exec.log'
|
||||
|
||||
def call_profile_func(function_name: str, *args: str) -> str:
|
||||
# if we are on Steam Deck
|
||||
if DEVICE == "DECK" :
|
||||
proc = subprocess.run(f'. {INSTALL_DIR}/export_func.sh', shell=True, stdout=subprocess.PIPE, check=True, text=True)
|
||||
else:
|
||||
#We are going to want to call some stuff from /etc/profile, they are defined in ../profile.d/99-distribution.conf
|
||||
#But on Steam Deck this is not needed as these stuff is called by another script as profile.d is just for embedded distros
|
||||
proc = subprocess.run(f'. /etc/profile && {shlex.quote(function_name)} {shlex.join(args)}', shell=True, stdout=subprocess.PIPE, check=True, text=True)
|
||||
return proc.stdout.strip('\n')
|
||||
|
||||
def get_es_setting(setting_type: str, setting_name: str) -> str:
|
||||
#from es_settings.cfg (XML)
|
||||
return call_profile_func('get_es_setting', setting_type, setting_name)
|
||||
|
||||
log_level = get_es_setting('string', 'LogLevel') #If set to default, would equal empty string
|
||||
|
||||
def jslisten_set(*exe_names: str):
|
||||
#exe_names are passed as one argument, intended for killall to use them later
|
||||
if DEVICE != "DECK" :
|
||||
call_profile_func('jslisten', 'set', shlex.join(exe_names))
|
||||
|
||||
def jslisten_stop():
|
||||
#call_profile_func('jslisten', 'stop')
|
||||
if DEVICE != "DECK" :
|
||||
subprocess.check_call(['systemctl', 'stop', 'jslisten'])
|
||||
|
||||
def get_elec_setting(setting_name, platform=None, rom=None):
|
||||
#From distribution.conf
|
||||
#Potentially this can be reimplemented in Python if that turns out to be a good idea
|
||||
return call_profile_func('get_ee_setting', setting_name, platform, rom)
|
||||
|
||||
def set_elec_setting(setting_name, value):
|
||||
call_profile_func('set_ee_setting', setting_name, value)
|
||||
|
||||
def check_bios(platform, core, emulator, game, log_path_):
|
||||
call_profile_func('ee_check_bios', platform, core, emulator, game, log_path_)
|
||||
|
||||
def log(text):
|
||||
with log_path.open('at', encoding='utf-8') as log_file:
|
||||
print(text, file=log_file)
|
||||
|
||||
def cleanup_and_quit(return_code):
|
||||
if log_level == 'debug':
|
||||
log(f'Cleaning up and exiting with return code {return_code}')
|
||||
|
||||
if DEVICE != "DECK" :
|
||||
jslisten_stop()
|
||||
clear_screen()
|
||||
call_profile_func('normperf')
|
||||
call_profile_func('set_audio', 'default')
|
||||
sys.exit(return_code)
|
||||
|
||||
def clear_screen():
|
||||
if DEVICE != "DECK" :
|
||||
if log_level == 'debug':
|
||||
log('Clearing screen')
|
||||
with open('/dev/console', 'wb') as console:
|
||||
subprocess.run('clear', stdout=console, check=True)
|
||||
|
||||
def list_archive(path: Path) -> 'List[str]':
|
||||
#7z path needs to be given explicitly, otherwise it won't find 7z.so
|
||||
sevenzip_proc = subprocess.run(['/usr/bin/7z', 'l', '-slt', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
|
||||
if sevenzip_proc.returncode != 0:
|
||||
raise OSError(sevenzip_proc.stderr.strip())
|
||||
#Ignore the first Path = line which is the archive itself
|
||||
return [line[len('Path = '):] for line in sevenzip_proc.stdout.splitlines() if line.startswith('Path = ')][1:]
|
||||
|
||||
def extract_archive(path: Path) -> Path:
|
||||
#Assume there is only one file, otherwise things get weird
|
||||
inner_filename = list_archive(path)[0]
|
||||
#Since save files etc may be placed in the ROM folder, we should extract there so everything still works transparently, which also helps with overrides and such
|
||||
subprocess.check_call(['/usr/bin/7z', 'e', f'-o{str(path.parent)}', path, inner_filename], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
return path.parent.joinpath(inner_filename)
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class StandaloneEmulator():
|
||||
jskill_name: str
|
||||
args: 'Sequence[str]'
|
||||
should_extract: bool = False
|
||||
|
||||
standalone_emulators: 'MutableMapping[str, StandaloneEmulator]' = {
|
||||
'AMIBERRY': StandaloneEmulator('amiberry', ['/usr/bin/amiberry.start', '<path>']),
|
||||
'AdvanceMame': StandaloneEmulator('advmame', ['/usr/bin/advmame.sh', '<path>']),
|
||||
'HATARISA': StandaloneEmulator('hatari', ['/usr/bin/hatari.start', '<path>']),
|
||||
'hypseus_singe': StandaloneEmulator('hypseus', ['/usr/bin/hypseus.sh', '<path>']),
|
||||
'OPENBOR': StandaloneEmulator('openbor', ['/usr/bin/openbor.sh', '<path>']),
|
||||
'PPSSPPSDL': StandaloneEmulator('PPSSPPSDL', ['/usr/bin/ppsspp.sh', '<path>']),
|
||||
'SCUMMVMSA': StandaloneEmulator('scummvm', ['/usr/bin/scummvm.start', 'sa', '<path>']),
|
||||
'drastic': StandaloneEmulator('drastic', ['/usr/bin/drastic.sh', '<path>']),
|
||||
'ecwolf': StandaloneEmulator('ecwolf', ['/usr/bin/ecwolf.sh', '<path>']),
|
||||
'gzdoom': StandaloneEmulator('gzdoom', ['/usr/bin/gzdoom.sh', '<path>']),
|
||||
'lzdoom': StandaloneEmulator('lzdoom', ['/usr/bin/lzdoom.sh', '<path>']),
|
||||
'mpv': StandaloneEmulator('mpv', ['/usr/bin/mpv_video.sh', '<path>']),
|
||||
'pico8': StandaloneEmulator('pico8_dyn', ['/usr/bin/pico-8.sh', '<path>']),
|
||||
'piemu': StandaloneEmulator('piemu', ['/usr/bin/bash', '-l', '/usr/bin/piemu.sh', '<path>']),
|
||||
'raze': StandaloneEmulator('raze', ['/usr/bin/raze.sh', '<path>']),
|
||||
'solarus': StandaloneEmulator('solarus-run', ['/usr/bin/solarus.sh', '<path>']),
|
||||
}
|
||||
|
||||
def _load_customized_standalone_emulators():
|
||||
try:
|
||||
with open(INSTALL_DIR + '/storage/.config/standalone_emulators', 'rt', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if ': ' not in line or line.startswith('#'):
|
||||
continue
|
||||
name, rest = line.rstrip().split(': ', 1)
|
||||
args = rest.split(' ')
|
||||
kill_name = name
|
||||
should_extract = False
|
||||
#If name of exe to kill was not listed, assume it is the same as the emulator name
|
||||
if not args[0].startswith('/'):
|
||||
kill_name = args[0]
|
||||
args = args[1:]
|
||||
if args[-1] == 'should_extract':
|
||||
args = args[:-1]
|
||||
should_extract = True
|
||||
standalone_emulators[name] = StandaloneEmulator(kill_name, args, should_extract)
|
||||
except (FileNotFoundError, ValueError):
|
||||
pass
|
||||
|
||||
_load_customized_standalone_emulators()
|
||||
|
||||
class EmuRunner():
|
||||
def __init__(self, rom: Optional[Path], platform: Optional[str], emulator: Optional[str], core: Optional[str], args: 'Mapping[str, str]') -> None:
|
||||
self.rom = rom
|
||||
self.platform = platform
|
||||
self.emulator = emulator
|
||||
self.core = core
|
||||
self.args = args
|
||||
self.temp_files: 'List[Path]' = [] #Files that we extracted from archives, etc. to clean up later
|
||||
self.environment = os.environ.copy()
|
||||
|
||||
def download_things_if_needed(self) -> None:
|
||||
if self.core == 'freej2me':
|
||||
#freej2me needs the JDK to be downloaded on the first run
|
||||
subprocess.run(INSTALL_DIR + '/usr/bin/freej2me.sh', check=True)
|
||||
self.environment['JAVA_HOME']=INSTALL_DIR + '/storage/jdk'
|
||||
self.environment['PATH'] = INSTALL_DIR + '/storage/jdk/bin:' + os.environ['PATH']
|
||||
elif self.core == 'easyrpg':
|
||||
# easyrpg needs runtime files to be downloaded on the first run
|
||||
subprocess.run(INSTALL_DIR + '/usr/bin/easyrpg.sh', check=True)
|
||||
|
||||
def toggle_max_performance(self) -> None:
|
||||
if get_elec_setting('maxperf', self.platform, self.rom.name if self.rom else None) == '1':
|
||||
if log_level == 'debug':
|
||||
log('Enabling max performance as requested')
|
||||
call_profile_func('maxperf')
|
||||
else:
|
||||
call_profile_func('normperf')
|
||||
|
||||
def set_settings(self) -> str:
|
||||
rom_name = str(self.rom) if self.rom else ''
|
||||
core = self.core if self.core else ''
|
||||
platform = self.platform if self.platform else ''
|
||||
return set_settings(rom_name, core, platform, controllers=self.args.get('controllers', ''), autosave=self.args.get('autosave', ''), snapshot=self.args.get('state_slot', ''))
|
||||
|
||||
def get_standalone_emulator_command(self) -> 'Sequence[Union[str, Path]]':
|
||||
if not self.emulator:
|
||||
raise ValueError('runemu.py was called improperly, tried to launch a standard emulator with no emulator')
|
||||
if log_level != 'minimal':
|
||||
log('Running a standalone emulator:')
|
||||
log(f'platform: {self.platform}')
|
||||
log(f'emulator: {self.emulator}')
|
||||
#Core is not actually relevant (other than Mupen64Plus which is in another function)
|
||||
|
||||
emu = standalone_emulators[self.emulator]
|
||||
path = self.rom
|
||||
if self.rom and emu.should_extract and self.rom.suffix in {'.zip', '.7z', '.gz', '.bz2'}:
|
||||
path = extract_archive(self.rom)
|
||||
self.temp_files.append(path)
|
||||
|
||||
command = [arg for arg in (path if arg == '<path>' else arg for arg in emu.args) if arg]
|
||||
|
||||
jslisten_set(emu.jskill_name)
|
||||
return command
|
||||
|
||||
def get_retroarch_command(self, shader_arg: str) -> 'Sequence[Union[str, Path]]':
|
||||
if log_level != 'minimal':
|
||||
log('Running a libretro core via RetroArch')
|
||||
log(f'platform: {self.platform}')
|
||||
log(f'core: {self.core}')
|
||||
retroarch_binary = 'retroarch'
|
||||
if self.core in {'pcsx_rearmed', 'parallel_n64'}:
|
||||
retroarch_binary = 'retroarch32'
|
||||
self.environment['LD_LIBRARY_PATH'] = '/usr/lib32'
|
||||
|
||||
rom_path: 'Optional[Union[str, Path]]' = self.rom
|
||||
|
||||
if self.rom:
|
||||
if self.platform == 'doom' and self.rom.suffix == '.doom':
|
||||
subprocess.run(['dos2unix', self.rom], check=True) #Hmmmmm but do we need that
|
||||
with self.rom.open('rt', encoding='utf-8') as doomfile:
|
||||
for line in doomfile:
|
||||
key, _, value = line.partition('=')
|
||||
if key == 'IWAD':
|
||||
rom_path = value
|
||||
break
|
||||
if self.core == 'scummvm' and self.rom.suffix == '.scummvm':
|
||||
#ScummVM libretro core actually only works with .scummvm files that just have the game ID with no path specified, which isn't how they are generated by the scummvm scanner script
|
||||
#But if you give it any other path to a file, it will autodetect a game inside that file's parent directory, even if the file doesn't actually exist
|
||||
#This would otherwise be what /usr/bin/scummvm.start tries to do when its first arg is "libretro", by cd'ing into that game directory
|
||||
path = Path(self.rom.read_text(encoding='utf-8').split('"')[1])
|
||||
rom_path = path / 'game'
|
||||
|
||||
jslisten_set(retroarch_binary)
|
||||
command: 'List[Union[str, Path]]' = [os.path.join('/usr/bin/', retroarch_binary), '-L', Path('/tmp/cores/', f'{self.core}_libretro.so')]
|
||||
|
||||
if log_level != 'minimal':
|
||||
command.append('--verbose')
|
||||
|
||||
if 'host' in self.args or 'connect' in self.args:
|
||||
netplay_nick = get_elec_setting('netplay.nickname')
|
||||
if not netplay_nick:
|
||||
netplay_nick = '351ELEC'
|
||||
if 'connect' in self.args:
|
||||
set_elec_setting('netplay.client.port', self.args['port'])
|
||||
set_elec_setting('netplay.client.ip', self.args['connect']) #We should now have parsed that properly so it's just a hostname/IP address, no --port argument
|
||||
command += ['--connect', self.args['connect'] + '|' + self.args['port']]
|
||||
if 'host' in self.args:
|
||||
command += ['--host', self.args['host']]
|
||||
|
||||
command += ['--nick', netplay_nick]
|
||||
|
||||
if self.core == 'fbneo' and self.platform == 'neocd':
|
||||
command += ['--subsystem', self.platform]
|
||||
if shader_arg:
|
||||
#Returned from setsettings, this is of the form "--shader-set /tmp/shaders/blahblahblah", apparently actually needed even if video_shader is set in RA_APPEND_CONF
|
||||
command += shlex.split(shader_arg)
|
||||
command += ['--config', RA_TEMP_CONF, '--appendconfig', RA_APPEND_CONF]
|
||||
if rom_path:
|
||||
command.append(rom_path)
|
||||
|
||||
return command
|
||||
|
||||
def get_retrorun_command(self) -> 'Sequence[Union[str, Path]]':
|
||||
if not self.rom:
|
||||
raise ValueError('runemu.py was called improperly, tried to launch retrorun with no game')
|
||||
if not self.platform:
|
||||
raise ValueError('runemu.py was called improperly, tried to launch retrorun with no platform')
|
||||
if not self.core:
|
||||
raise ValueError('runemu.py was called improperly, tried to launch retrorun with no platform')
|
||||
|
||||
core_path = Path('/tmp/cores/', f'{self.core}_libretro.so')
|
||||
if log_level != 'minimal':
|
||||
log('Running a libretro core via retrorun')
|
||||
log(f'platform: {self.platform}')
|
||||
log(f'core: {self.core}')
|
||||
jslisten_set('retrorun', 'retrorun32')
|
||||
|
||||
path = self.rom
|
||||
if self.rom.suffix in {'.zip', '.7z', '.gz', '.bz2'} and self.platform not in {'arcade', 'naomi', 'atomiswave', 'fbneo', 'mame'}:
|
||||
path = extract_archive(self.rom)
|
||||
self.temp_files.append(path)
|
||||
|
||||
return [INSTALL_DIR + '/usr/bin/retrorun.sh', core_path, path, self.platform]
|
||||
|
||||
def get_mupen64plus_standalone_command(self) -> 'Sequence[Union[str, Path]]':
|
||||
if not self.rom:
|
||||
raise ValueError('runemu.py was called improperly, tried to launch Mupen64Plus standalone with no video plugin')
|
||||
if not self.core:
|
||||
raise ValueError('runemu.py was called improperly, tried to launch Mupen64Plus standalone with no video plugin')
|
||||
if log_level != 'minimal':
|
||||
log(f'Running Mupen64Plus standalone with {self.core} video plugin')
|
||||
jslisten_set('mupen64plus')
|
||||
path = self.rom
|
||||
if self.rom.suffix in {'.zip', '.7z', '.gz', '.bz2'}:
|
||||
path = extract_archive(self.rom)
|
||||
self.temp_files.append(path)
|
||||
|
||||
return [INSTALL_DIR + '/usr/bin/m64p.sh', self.core, path]
|
||||
|
||||
def get_command(self, shader_arg: str='') -> 'Sequence[Union[str, Path]]':
|
||||
is_libretro_port = self.core and not self.emulator
|
||||
#If true this was called from the inside of a port .sh that runs a libretro port (e.g. 2048, tyrQuake, etc), it makes no sense otherwise
|
||||
|
||||
if self.rom and (self.rom.suffix == '.sh' or self.platform == 'tools'):
|
||||
#If the ROM is a shell script then just execute it (tools, ports, Pico-8 splore, ScummVM scanner, etc)
|
||||
return ['/usr/bin/bash', '-l', self.rom]
|
||||
elif self.emulator == 'retroarch' or is_libretro_port:
|
||||
return self.get_retroarch_command(shader_arg)
|
||||
elif self.emulator == 'retrorun':
|
||||
return self.get_retrorun_command()
|
||||
elif self.emulator == 'mupen64plussa':
|
||||
return self.get_mupen64plus_standalone_command()
|
||||
else:
|
||||
return self.get_standalone_emulator_command()
|
||||
|
||||
def run(self, command: 'Sequence[Union[str, Path]]') -> None:
|
||||
clear_screen()
|
||||
if log_level != 'minimal':
|
||||
log(f'Executing game: {self.rom}')
|
||||
log(f'Executing {command}')
|
||||
with log_path.open('at', encoding='utf-8') as log_file:
|
||||
subprocess.run(command, stdout=log_file, stderr=subprocess.STDOUT, check=True, text=True, env=self.environment)
|
||||
|
||||
def cleanup_temp_files(self) -> None:
|
||||
for temp_file in self.temp_files:
|
||||
temp_file.unlink(missing_ok=True)
|
||||
|
||||
def main():
|
||||
time_started = perf_counter()
|
||||
|
||||
i = 0
|
||||
args: dict[str, str] = {}
|
||||
while i < len(sys.argv)-1:
|
||||
if sys.argv[i].startswith('--'):
|
||||
args[sys.argv[i][2:]] = sys.argv[i + 1]
|
||||
i += 1
|
||||
continue
|
||||
if sys.argv[i].startswith('-'):
|
||||
args[sys.argv[i][1:]] = sys.argv[i + 1]
|
||||
i += 1
|
||||
continue
|
||||
i += 1
|
||||
|
||||
rom = Path(args['rom']) if 'rom' in args else None
|
||||
platform = args.get('platform')
|
||||
core = args.get('core')
|
||||
emulator = args.get('emulator')
|
||||
|
||||
log_path.unlink(missing_ok=True)
|
||||
LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
log_path.touch()
|
||||
|
||||
log(f'Emulation run log: Started at {datetime.datetime.now()}')
|
||||
log(f'Args: {args}')
|
||||
|
||||
runner = EmuRunner(rom, platform, emulator, core, args)
|
||||
|
||||
runner.download_things_if_needed()
|
||||
runner.toggle_max_performance()
|
||||
|
||||
#Disable netplay by default
|
||||
set_elec_setting('netplay.client.ip', 'disable')
|
||||
set_elec_setting('netplay.client.port', 'disable')
|
||||
|
||||
jslisten_stop()
|
||||
|
||||
shader_arg = runner.set_settings()
|
||||
command = runner.get_command(shader_arg)
|
||||
if log_level != 'minimal':
|
||||
log(f'Took {perf_counter() - time_started} seconds to start up')
|
||||
clear_screen()
|
||||
|
||||
try:
|
||||
runner.run(command)
|
||||
exit_code = 0
|
||||
except subprocess.CalledProcessError as cpe:
|
||||
log(f'Process exited improperly with return code {cpe.returncode}')
|
||||
exit_code = 1
|
||||
requires_bios = {'atari5200', 'atari800', 'atari7800', 'atarilynx', 'colecovision', 'amiga', 'amigacd32', 'o2em', 'intellivision', 'pcengine', 'pcenginecd', 'pcfx', 'fds', 'segacd', 'saturn', 'dreamcast', 'naomi', 'atomiswave', 'x68000', 'neogeo', 'neogeocd', 'msx', 'msx2', 'sc-3000'}
|
||||
if platform in requires_bios:
|
||||
if platform == 'msx2':
|
||||
platform_to_check = 'msx2'
|
||||
elif platform == 'pcenginecd':
|
||||
platform_to_check = 'pcengine'
|
||||
elif platform == 'amigacd32':
|
||||
platform_to_check = 'amiga'
|
||||
else:
|
||||
platform_to_check = platform
|
||||
check_bios(platform_to_check, core, emulator, rom, log_path)
|
||||
finally:
|
||||
runner.cleanup_temp_files()
|
||||
cleanup_and_quit(exit_code)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
700
usr/bin/setsettings.py
Executable file
700
usr/bin/setsettings.py
Executable file
|
@ -0,0 +1,700 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# setsettings.py:
|
||||
# Copyright (C) 2021-present konsumschaf
|
||||
# Copyright (C) 2021-present konsumlamm
|
||||
#
|
||||
# based on setsettings.sh:
|
||||
# Copyright (C) 2019-present Shanti Gilbert (https://github.com/shantigilbert)
|
||||
# Copyright (C) 2020-present Fewtarius
|
||||
|
||||
|
||||
# Convert ES settings from distribution.conf to RetroArch configuration in raappend.conf.
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from configparser import ConfigParser
|
||||
from dataclasses import dataclass
|
||||
from glob import iglob
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
|
||||
# If we are on Steam Deck we want a prefix
|
||||
DEVICE = "DECK"
|
||||
# TODO: put a real check on the .OS_ARCH file, or maybe not as we are obviously running on Deck
|
||||
INSTALL_DIR = os.path.expanduser("~/retrodeck")
|
||||
|
||||
# if DEVICE == "DECK" :
|
||||
#
|
||||
#else:
|
||||
# INSTALL_DIR = ""
|
||||
|
||||
# Files and Folder
|
||||
ra_conf = INSTALL_DIR + "/storage/.config/retroarch/retroarch.cfg"
|
||||
ra_source_conf = INSTALL_DIR + "/usr/config/retroarch/retroarch.cfg"
|
||||
ra_core_conf = INSTALL_DIR + "/storage/.config/retroarch/retroarch-core-options.cfg"
|
||||
ra_append_conf = "/tmp/raappend.cfg"
|
||||
os_arch_conf = INSTALL_DIR + "/storage/.config/.OS_ARCH"
|
||||
snapshots = INSTALL_DIR + "/storage/roms/savestates"
|
||||
|
||||
# Logging
|
||||
class Logger:
|
||||
dir = "/tmp/logs"
|
||||
file = "exec.log"
|
||||
script_basename = os.path.basename(__file__)
|
||||
|
||||
def __init__(self):
|
||||
if not os.path.isdir(self.dir):
|
||||
os.makedirs(self.dir)
|
||||
self.file_handle = open(f'{self.dir}/{self.file}',"a+")
|
||||
|
||||
def log(self, text: str) -> None:
|
||||
self.file_handle.write(f'{self.script_basename}: {text}\n')
|
||||
|
||||
def __del__(self):
|
||||
self.file_handle.close()
|
||||
|
||||
|
||||
# No Sections in distribution.conf, we have to fake our own
|
||||
class MyConfigParser(ConfigParser):
|
||||
def read(self, filename: str) -> None:
|
||||
text = open(filename, encoding="utf_8").read()
|
||||
self.read_string("[351elec]\n" + text, filename)
|
||||
|
||||
@dataclass
|
||||
class Config:
|
||||
rom_name: str
|
||||
platform: str
|
||||
|
||||
distribution_conf = INSTALL_DIR + "/storage/.config/distribution/configs/distribution.conf"
|
||||
|
||||
def __post_init__(self):
|
||||
# Read the distribution.conf to a dictionary
|
||||
config_parser = MyConfigParser(strict=False)
|
||||
config_parser.read(self.distribution_conf)
|
||||
self.config = config_parser['351elec']
|
||||
|
||||
def get_setting(self, setting: str) -> str:
|
||||
"""Get the settings from distribution.conf"""
|
||||
|
||||
pat_rom = f'{self.platform}["{self.rom_name}"].{setting}'
|
||||
pat_platform = f'{self.platform}.{setting}'
|
||||
pat_global = f'global.{setting}'
|
||||
|
||||
if pat_rom in self.config:
|
||||
value = self.config[pat_rom]
|
||||
elif pat_platform in self.config:
|
||||
value = self.config[pat_platform]
|
||||
elif pat_global in self.config:
|
||||
value = self.config[pat_global]
|
||||
else:
|
||||
value = ""
|
||||
|
||||
if value == "0":
|
||||
value = ""
|
||||
return value
|
||||
|
||||
def get_bool_string(self, setting: str) -> str:
|
||||
"""For readability a function that returns "true" and "false" directly."""
|
||||
|
||||
if self.get_setting(setting):
|
||||
return "true"
|
||||
else:
|
||||
return "false"
|
||||
|
||||
# Delete lines from a config file
|
||||
def delete_lines(file_path: str, lines: tuple) -> None:
|
||||
with open(file_path, "r") as input:
|
||||
tmp_file = f'/tmp/{os.path.basename(file_path)}.tmp'
|
||||
with open(tmp_file, "w") as output:
|
||||
for line in input:
|
||||
write_this_line = True
|
||||
for item in lines:
|
||||
if line.strip().startswith(item):
|
||||
write_this_line = False
|
||||
break
|
||||
if write_this_line:
|
||||
output.write(line)
|
||||
# replace file with original name
|
||||
shutil.move(tmp_file, file_path)
|
||||
|
||||
# Append dictionary to the end of a file
|
||||
def write_file(file_path: str, dictionary: dict, separator: str = ' = ', quote_sign: str = '"') -> None:
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
with open(file_path, "a") as file:
|
||||
for (key, value) in dictionary.items():
|
||||
file.write(f'{key}{separator}{quote_sign}{value}{quote_sign}\n')
|
||||
|
||||
# Generate the config out of the distribution.conf
|
||||
def set_settings(rom_name: str, core: str, platform: str, controllers: str, autosave: str, snapshot: str) -> str:
|
||||
logger = Logger()
|
||||
shader_path = ''
|
||||
|
||||
#
|
||||
# Do some checks and clean up first
|
||||
#
|
||||
|
||||
# Log current call:
|
||||
logger.log(f'ROM: {rom_name}')
|
||||
logger.log(f'Platform: {platform}')
|
||||
logger.log(f'Core: {core}')
|
||||
logger.log(f'Controllers: {controllers}')
|
||||
logger.log(f'Autosave: {autosave}')
|
||||
logger.log(f'Snapshot: {snapshot}')
|
||||
|
||||
# We only need the ROM, but we get the fullpath
|
||||
rom_name = os.path.basename(rom_name)
|
||||
# Delete any existing raappend.cfg first
|
||||
if os.path.isfile(ra_append_conf):
|
||||
os.remove(ra_append_conf)
|
||||
# Restore retroarch.cfg if it is missing or empty
|
||||
if not os.path.isfile(ra_conf) or os.stat(ra_conf).st_size == 0:
|
||||
shutil.copy(ra_source_conf,ra_conf)
|
||||
|
||||
# Get the Device Name
|
||||
with open(os_arch_conf, encoding="utf-8") as f:
|
||||
device_name = f.readline().strip()
|
||||
logger.log(f'Device: {device_name}')
|
||||
|
||||
# Is the CORE 32 or 64bit?
|
||||
if core in {'pcsx_rearmed', 'parallel_n64'}:
|
||||
bits='32bit'
|
||||
else:
|
||||
bits='64bit'
|
||||
logger.log(f'core is {bits}')
|
||||
|
||||
# Dictionary for the raappend.cfg
|
||||
ra_append_dict = {}
|
||||
|
||||
# Create config from distribution.conf
|
||||
config = Config(rom_name, platform)
|
||||
|
||||
#
|
||||
# Global configuration directly in retroarch.cfg
|
||||
#
|
||||
|
||||
# RA menu rgui, ozone, glui or xmb (fallback if everthing else fails)
|
||||
# if empty (auto in ES) do nothing to enable configuration in RA
|
||||
if menu_driver := config.get_setting('retroarch.menu_driver'):
|
||||
ra_dict = {}
|
||||
# delete setting only if we set new ones
|
||||
# therefore configuring in RA is still possible
|
||||
delete_lines(ra_conf, ('menu_driver', 'menu_linear_filter'))
|
||||
if menu_driver == 'rgui':
|
||||
ra_dict['menu_driver'] = 'rgui'
|
||||
ra_dict['menu_linear_filter'] = 'true'
|
||||
elif menu_driver == 'ozone':
|
||||
ra_dict['menu_driver'] = 'ozone'
|
||||
elif menu_driver == 'glui':
|
||||
ra_dict['menu_driver'] = 'glui'
|
||||
else:
|
||||
# play it save and set xmb if nothing else matches
|
||||
ra_dict['menu_driver'] = 'xmb'
|
||||
write_file(ra_conf, ra_dict)
|
||||
|
||||
#
|
||||
# Convert the settings from distribution.conf to raappend.cfg
|
||||
#
|
||||
|
||||
# FPS
|
||||
ra_append_dict['fps_show'] = config.get_bool_string("showFPS")
|
||||
|
||||
# Retroachievements / Cheevos
|
||||
retro_achievements = {
|
||||
'arcade', 'atari2600', 'atari7800', 'atarilynx', 'colecovision',
|
||||
'famicom', 'fbn', 'fds', 'gamegear', 'gb', 'gba', 'gbah', 'gbc', 'gbch',
|
||||
'gbh', 'genesis', 'genh', 'ggh', 'intellivision', 'mastersystem',
|
||||
'megacd', 'megadrive', 'megadrive-japan', 'msx', 'msx2', 'n64',
|
||||
'neogeo', 'neogeocd', 'nes', 'nesh', 'ngp', 'ngpc', 'odyssey2',
|
||||
'pcengine', 'pcenginecd', 'pcfx', 'pokemini', 'psp', 'psx', 'sega32x',
|
||||
'segacd', 'sfc', 'sg-1000', 'snes', 'snesh', 'snesmsu1', 'supergrafx',
|
||||
'supervision', 'tg16', 'tg16cd', 'vectrex', 'virtualboy', 'wonderswan',
|
||||
'wonderswancolor',
|
||||
}
|
||||
if platform in retro_achievements:
|
||||
if config.get_setting("retroachievements"):
|
||||
ra_append_dict['cheevos_enable'] = "true"
|
||||
ra_append_dict['cheevos_username'] = config.get_setting("retroachievements.username")
|
||||
ra_append_dict['cheevos_password'] = config.get_setting("retroachievements.password")
|
||||
ra_append_dict['cheevos_hardcore_mode_enable'] = config.get_bool_string("retroachievements.hardcore")
|
||||
value = config.get_setting("retroachievements.leaderboards")
|
||||
if value == "enabled":
|
||||
ra_append_dict['cheevos_leaderboards_enable'] = "true"
|
||||
elif value == "trackers only":
|
||||
ra_append_dict['cheevos_leaderboards_enable'] = "trackers"
|
||||
elif value == "notifications only":
|
||||
ra_append_dict['cheevos_leaderboards_enable'] = "notifications"
|
||||
else:
|
||||
ra_append_dict['cheevos_leaderboards_enable'] = "false"
|
||||
ra_append_dict['cheevos_verbose_enable'] = config.get_bool_string("retroachievements.verbose")
|
||||
ra_append_dict['cheevos_auto_screenshot'] = config.get_bool_string("retroachievements.screenshot")
|
||||
ra_append_dict['cheevos_richpresence_enable'] = config.get_bool_string("retroachievements.richpresence")
|
||||
ra_append_dict['cheevos_challenge_indicators'] = config.get_bool_string("retroachievements.challengeindicators")
|
||||
ra_append_dict['cheevos_test_unofficial'] = config.get_bool_string("retroachievements.testunofficial")
|
||||
ra_append_dict['cheevos_badges_enable'] = config.get_bool_string("retroachievements.badges")
|
||||
ra_append_dict['cheevos_start_active'] = config.get_bool_string("retroachievements.active")
|
||||
ra_append_dict['cheevos_unlock_sound_enable'] = config.get_bool_string("retroachievements.soundenable")
|
||||
else:
|
||||
ra_append_dict['cheevos_enable'] = "false"
|
||||
ra_append_dict['cheevos_username'] = ""
|
||||
ra_append_dict['cheevos_password'] = ""
|
||||
ra_append_dict['cheevos_hardcore_mode_enable'] = "false"
|
||||
ra_append_dict['cheevos_leaderboards_enable'] = "false"
|
||||
ra_append_dict['cheevos_verbose_enable'] = "false"
|
||||
ra_append_dict['cheevos_test_unofficial'] = "false"
|
||||
ra_append_dict['cheevos_unlock_sound_enable'] = "false"
|
||||
ra_append_dict['cheevos_auto_screenshot'] = "false"
|
||||
ra_append_dict['cheevos_badges_enable'] = "false"
|
||||
ra_append_dict['cheevos_start_active'] = "false"
|
||||
ra_append_dict['cheevos_richpresence_enable'] = "false"
|
||||
ra_append_dict['cheevos_challenge_indicators'] = "false"
|
||||
|
||||
# Netplay
|
||||
if config.get_setting("netplay"):
|
||||
ra_append_dict['netplay'] = "true"
|
||||
# Not needed any more?
|
||||
## Disable Cheevos Hardcore Mode to allow savestates
|
||||
#if 'cheevos_hardcore_mode_enable' in ra_append_dict:
|
||||
# ra_append_dict['cheevos_hardcore_mode_enable'] = "false"
|
||||
# Host or Client
|
||||
value = config.get_setting('netplay.mode')
|
||||
if value == 'host':
|
||||
ra_append_dict['netplay_mode'] = "false"
|
||||
ra_append_dict['netplay_client_swap_input'] = "false"
|
||||
ra_append_dict['netplay_ip_port'] = config.get_setting('netplay.port')
|
||||
elif value == 'client':
|
||||
ra_append_dict['netplay_mode'] = "true"
|
||||
ra_append_dict['netplay_ip_address'] = config.get_setting('netplay.client.ip')
|
||||
ra_append_dict['netplay_ip_port'] = config.get_setting('netplay.client.port')
|
||||
ra_append_dict['netplay_client_swap_input'] = "true"
|
||||
# Relay
|
||||
if value := config.get_setting('netplay.relay'):
|
||||
ra_append_dict['netplay_use_mitm_server'] = "true"
|
||||
ra_append_dict['netplay_mitm_server'] = value
|
||||
else:
|
||||
ra_append_dict['netplay_use_mitm_server'] = "false"
|
||||
ra_append_dict['netplay_delay_frames'] = config.get_setting('netplay.frames')
|
||||
ra_append_dict['netplay_nickname'] = config.get_setting('netplay.nickname')
|
||||
# spectator mode
|
||||
ra_append_dict['netplay_spectator_mode_enable'] = config.get_bool_string("netplay.spectator")
|
||||
ra_append_dict['netplay_public_announce'] = config.get_bool_string("netplay_public_announce")
|
||||
else:
|
||||
ra_append_dict['netplay'] = "false"
|
||||
|
||||
# AI Translation Service
|
||||
if config.get_setting('ai_service_enabled'):
|
||||
ra_append_dict['ai_service_enable'] = "true"
|
||||
LangCodes = {
|
||||
"false": "0", "En": "1", "Fr": "3", "Pt": "49", "De": "5",
|
||||
"El": "30", "Es": "2", "Cs": "8", "Da": "9", "Hr": "11", "Hu": "35",
|
||||
"It": "4", "Ja": "6", "Ko": "12", "Nl": "7", "Nn": "46", "Po": "48",
|
||||
"Ro": "50", "Ru": "51", "Sv": "10", "Tr": "59", "Zh": "13",
|
||||
}
|
||||
ai_lang = config.get_setting('ai_target_lang')
|
||||
if ai_lang in LangCodes:
|
||||
ra_append_dict['ai_service_target_lang'] = f'{LangCodes[ai_lang]}'
|
||||
else:
|
||||
# use English as default
|
||||
ra_append_dict['ai_service_target_lang'] = "1"
|
||||
if ai_url := config.get_setting('ai_service_url'):
|
||||
ra_append_dict['ai_service_url'] = f'{ai_url}&mode=Fast&output=png&target_lang={ai_lang}'
|
||||
else:
|
||||
ra_append_dict['ai_service_url'] = f'http://ztranslate.net/service?api_key=BATOCERA&mode=Fast&output=png&target_lang={ai_lang}'
|
||||
else:
|
||||
ra_append_dict['ai_service_enable'] = "false"
|
||||
|
||||
#
|
||||
# Global/System/Game specific settings
|
||||
#
|
||||
|
||||
# Ratio
|
||||
# default to 22 (core provided) if case anything goes wrong
|
||||
ra_append_dict['aspect_ratio_index'] = "22"
|
||||
if ratio := config.get_setting('ratio'):
|
||||
index_rations = {
|
||||
'4/3': '0', '16/9': '1', '16/10': '2', '16/15': '3', '21/9': '4',
|
||||
'1/1': '5', '2/1': '6', '3/2': '7', '3/4': '8', '4/1': '9',
|
||||
'9/16': '10', '5/4': '11', '6/5': '12', '7/9': '13', '8/3': '14',
|
||||
'8/7': '15', '19/12': '16', '19/14': '17', '30/17': '18',
|
||||
'32/9': '19', 'config': '20', 'squarepixel': '21', 'core': '22',
|
||||
'custom': '23', 'full' : '24',
|
||||
}
|
||||
if ratio in index_rations:
|
||||
ra_append_dict['aspect_ratio_index'] = index_rations[ratio]
|
||||
|
||||
# Bilinear filtering
|
||||
ra_append_dict['video_smooth'] = config.get_bool_string("smooth")
|
||||
|
||||
# Video Integer Scale
|
||||
ra_append_dict['video_scale_integer'] = config.get_bool_string("integerscale")
|
||||
|
||||
# Video Integer Scale Overscale
|
||||
ra_append_dict['video_scale_integer_overscale'] = config.get_bool_string("integerscaleoverscale")
|
||||
|
||||
# RGA Scaling / CTX Scaling
|
||||
ra_append_dict['video_ctx_scaling'] = config.get_bool_string("rgascale")
|
||||
|
||||
# Shaderset
|
||||
if shaderset := config.get_setting('shaderset'):
|
||||
ra_append_dict['video_shader_enable'] = "true"
|
||||
ra_append_dict['video_shader'] = shaderset
|
||||
# We need to print the shader folder for runemu.sh to use it
|
||||
shader_path = f'--set-shader /tmp/shaders/{shaderset}'
|
||||
else:
|
||||
ra_append_dict['video_shader_enable'] = "false"
|
||||
ra_append_dict['video_shader'] = ""
|
||||
|
||||
# Filters
|
||||
# Set correct path for video- and audio-filters depending on 32/64bit
|
||||
ra_append_dict['audio_filter_dir'] = f'/usr/share/retroarch/filters/{bits}/audio'
|
||||
ra_append_dict['video_filter_dir'] = f'/usr/share/retroarch/filters/{bits}/video'
|
||||
# Filterset
|
||||
if filterset := config.get_setting('filterset'):
|
||||
# Filter do not work with RGA/CTX enabled
|
||||
ra_append_dict['video_ctx_scaling'] = "false"
|
||||
ra_append_dict['video_filter'] = f'/usr/share/retroarch/filters/{bits}/video/{filterset}'
|
||||
else:
|
||||
ra_append_dict['video_filter'] = ""
|
||||
|
||||
# Rewind
|
||||
no_rewind = {'sega32x', 'psx', 'zxspectrum', 'odyssey2', 'mame', 'n64', 'dreamcast', 'atomiswave', 'naomi', 'neogeocd', 'saturn', 'psp', 'pspminis'}
|
||||
if config.get_setting('rewind') and platform not in no_rewind:
|
||||
ra_append_dict['rewind_enable'] = "true"
|
||||
else:
|
||||
ra_append_dict['rewind_enable'] = "false"
|
||||
|
||||
# Saves
|
||||
# Incrementalsavestates
|
||||
if config.get_setting('incrementalsavestates'):
|
||||
ra_append_dict['savestate_auto_index'] = "true"
|
||||
ra_append_dict['savestate_max_keep'] = "0"
|
||||
else:
|
||||
ra_append_dict['savestate_auto_index'] = "false"
|
||||
ra_append_dict['savestate_max_keep'] = "50"
|
||||
# Autosave
|
||||
if config.get_setting('autosave'):
|
||||
ra_append_dict['savestate_auto_save'] = "true"
|
||||
ra_append_dict['savestate_auto_load'] = "true"
|
||||
else:
|
||||
ra_append_dict['savestate_auto_save'] = "false"
|
||||
ra_append_dict['savestate_auto_load'] = "false"
|
||||
# Snapshots
|
||||
ra_append_dict['savestate_directory'] = f'{snapshots}/{platform}'
|
||||
if snapshot:
|
||||
if autosave == "1":
|
||||
ra_append_dict['savestate_auto_load'] = "true"
|
||||
ra_append_dict['savestate_auto_save'] = "true"
|
||||
else:
|
||||
ra_append_dict['savestate_auto_load'] = "false"
|
||||
ra_append_dict['savestate_auto_save'] = "false"
|
||||
ra_append_dict['state_slot'] = f'{snapshot}'
|
||||
|
||||
# Runahead
|
||||
# Runahead 1st Instance
|
||||
no_run_ahead = {'psp', 'sega32x', 'n64', 'dreamcast', 'atomiswave', 'naomi', 'neogeocd', 'saturn'}
|
||||
if (runahead := config.get_setting('runahead')) and platform not in no_run_ahead:
|
||||
ra_append_dict['run_ahead_enabled'] = "true"
|
||||
ra_append_dict['run_ahead_frames'] = runahead
|
||||
else:
|
||||
ra_append_dict['run_ahead_enabled'] = "false"
|
||||
ra_append_dict['run_ahead_frames'] = "1"
|
||||
# Runahead 2nd Instance
|
||||
if config.get_setting('secondinstance') and platform not in no_run_ahead:
|
||||
ra_append_dict['run_ahead_secondary_instance'] = "true"
|
||||
else:
|
||||
ra_append_dict['run_ahead_secondary_instance'] = "false"
|
||||
|
||||
# Auto Frame Relay
|
||||
ra_append_dict['video_frame_delay_auto'] = config.get_bool_string("video_frame_delay_auto")
|
||||
|
||||
# maxperf / CPU Governor
|
||||
if config.get_setting('maxperf'):
|
||||
ra_append_dict['cpu_scaling_mode'] = '2'
|
||||
else:
|
||||
ra_append_dict['cpu_scaling_mode'] = '4'
|
||||
|
||||
#
|
||||
# Settings for special cores
|
||||
#
|
||||
|
||||
## atari800 core needs other settings when emulation atari5200
|
||||
if core == 'atari800':
|
||||
logger.log('Atari 800 section')
|
||||
retrocore_dict = {}
|
||||
atari800_dict = {}
|
||||
atari_dict = {}
|
||||
atari_conf = INSTALL_DIR + '/storage/.config/distribution/configs/atari800.cfg'
|
||||
atari800_conf = INSTALL_DIR + '/storage/.config/retroarch/config/Atari800/Atari800.opt'
|
||||
delete_lines(ra_core_conf, ('atari800_system =',))
|
||||
delete_lines(atari_conf, ('RAM_SIZE', 'STEREO_POKEY', 'BUILTIN_BASIC'))
|
||||
if os.path.isfile(atari800_conf):
|
||||
delete_lines(atari800_conf, ('atari800_system',))
|
||||
if platform == 'atari5200':
|
||||
retrocore_dict['atari800_system'] = '5200'
|
||||
atari800_dict['atari800_system'] = '5200'
|
||||
atari_dict['RAM_SIZE'] = '16'
|
||||
atari_dict['STEREO_POKEY'] = '0'
|
||||
atari_dict['BUILTIN_BASIC'] = '0'
|
||||
else:
|
||||
retrocore_dict['atari800_system'] = '800XL (64K)'
|
||||
atari800_dict['atari800_system'] = '800XL (64K)'
|
||||
atari_dict['RAM_SIZE'] = '64'
|
||||
atari_dict['STEREO_POKEY'] = '1'
|
||||
atari_dict['BUILTIN_BASIC'] = '1'
|
||||
write_file(ra_core_conf, retrocore_dict)
|
||||
# The format of the atari800.cfg is different
|
||||
# ('key=value' instead of 'key = "value"')
|
||||
write_file(atari_conf, atari_dict, separator='=', quote_sign='')
|
||||
write_file(atari800_conf, atari800_dict)
|
||||
|
||||
# Gambatte
|
||||
if core == 'gambatte':
|
||||
logger.log('Gambatte section')
|
||||
gambatte_dict = {}
|
||||
gambatte_conf = INSTALL_DIR + "/storage/.config/retroarch/config/Gambatte/Gambatte.opt"
|
||||
|
||||
if os.path.isfile(gambatte_conf):
|
||||
delete_lines(gambatte_conf, ('gambatte_gb_colorization', 'gambatte_gb_internal_palette'))
|
||||
else:
|
||||
gambatte_dict['gambatte_gbc_color_correction'] = 'disabled'
|
||||
|
||||
colorization = config.get_setting('renderer.colorization')
|
||||
logger.log(f'gambatte colorization: {colorization}')
|
||||
if not colorization or colorization == 'auto':
|
||||
gambatte_dict['gambatte_gb_colorization'] = 'disabled'
|
||||
elif colorization == 'Best Guess':
|
||||
gambatte_dict['gambatte_gb_colorization'] = 'auto'
|
||||
elif colorization == 'GBC' or colorization == 'SGB':
|
||||
gambatte_dict['gambatte_gb_colorization'] = colorization
|
||||
else:
|
||||
gambatte_dict['gambatte_gb_colorization'] = 'internal'
|
||||
gambatte_dict['gambatte_gb_internal_palette'] = colorization
|
||||
|
||||
write_file(gambatte_conf, gambatte_dict)
|
||||
|
||||
#
|
||||
# Controllers
|
||||
#
|
||||
# We set up the controller index
|
||||
if controllers:
|
||||
for player in range(1,6):
|
||||
logger.log(f'Controller section {player}')
|
||||
if pindex := re.search(fr'p{player}index\s+([0-9]+)', controllers):
|
||||
ra_append_dict['input_player{player}_joypad_index'] = pindex.group(1)
|
||||
# Setting controller type for different cores
|
||||
if platform == "atari5200":
|
||||
ra_append_dict['input_libretro_device_p{player}'] = '513'
|
||||
|
||||
#
|
||||
# Bezels / Decorations
|
||||
#
|
||||
# List of possible Bezel Folders
|
||||
bezel_dir = ('/tmp/overlays/bezels', INSTALL_DIR + '/storage/roms/bezels')
|
||||
# Define the resolutions of the different systems (0:x 1:y 2:width 3:height) as seen in Scaling -> Aspect Ration -> Custom
|
||||
# Devices (width x hight)
|
||||
# RG351P/M = 480x320
|
||||
# RG351V/MP = 640x480
|
||||
# RG552 = 1920x1152
|
||||
# DECK = 1280x800
|
||||
# Consoles (width x hight)
|
||||
# GB/GBC/GG = 160x144
|
||||
# supervision = 160x160
|
||||
# Pokemini = 96x64
|
||||
# ngp/ngpc = 160x152
|
||||
# wonderswan/wonderswancolor = 224×144
|
||||
if device_name == "RG351P":
|
||||
system_viewport = {
|
||||
'standard': (1, 1, 479, 319), # max-1
|
||||
'gb': (80, 16, 320, 288), # x2
|
||||
'gbh': (80, 16, 320, 288), # x2
|
||||
'gbc': (80, 16, 320, 288), # x2
|
||||
'gbch': (80, 16, 320, 288), # x2
|
||||
'supervision': (80, 0, 320, 320), # x2
|
||||
'gamegear': (80, 16, 320, 288), # x2
|
||||
'ggh': (80, 16, 320, 288), # x2
|
||||
'pokemini': (96, 64, 288, 192), # x3
|
||||
'ngp': (80, 8, 320, 304), # x2
|
||||
'ngpc': (80, 8, 320, 304), # x2
|
||||
'wonderswan': (16, 16, 448, 288), # x2
|
||||
'wonderswancolor': (16, 16, 448, 288), # x2
|
||||
}
|
||||
elif device_name == "RG351V" or device_name == "RG351MP":
|
||||
system_viewport = {
|
||||
'standard': (1, 1, 639, 479), # max-1
|
||||
'gb': (80, 24, 480, 432), # x3
|
||||
'gbh': (80, 24, 480, 432), # x3
|
||||
'gbc': (80, 24, 480, 432), # x3
|
||||
'gbch': (80, 24, 480, 432), # x3
|
||||
'supervision': (80, 0, 480, 480), # x3
|
||||
'gamegear': (80, 24, 480, 432), # x3
|
||||
'ggh': (80, 24, 480, 432), # x3
|
||||
'pokemini': (128, 112, 384, 256), # x4
|
||||
'ngp': (80, 12, 480, 456), # x3
|
||||
'ngpc': (80, 12, 480, 456), # x3
|
||||
'wonderswan': (96, 96, 448, 288), # x2
|
||||
'wonderswancolor': (96, 96, 448, 288), # x2
|
||||
}
|
||||
elif device_name == "RG552":
|
||||
system_viewport = {
|
||||
'standard': (1, 1, 1919, 1151), # max-1
|
||||
'gb': (320, 0, 1280, 1152), # x8
|
||||
'gbh': (320, 0, 1280, 1152), # x8
|
||||
'gbc': (320, 0, 1280, 1152), # x8
|
||||
'gbch': (320, 0, 1280, 1152), # x8
|
||||
'supervision': (400, 16, 1120, 1120), # x7
|
||||
'gamegear': (320, 0, 1280, 1152), # x8
|
||||
'ggh': (320, 0, 1280, 1152), # x8
|
||||
'pokemini': (384, 192, 1152, 768), # x12
|
||||
'ngp': (400, 44, 1120, 1064), # x7
|
||||
'ngpc': (400, 44, 1120, 1064), # x7
|
||||
'wonderswan': (64, 0, 1792, 1152), # x8
|
||||
'wonderswancolor': (64, 0, 1792, 1152), # x8
|
||||
}
|
||||
elif device_name == "DECK":
|
||||
#just copied from 552, I have to edit this
|
||||
system_viewport = {
|
||||
'standard': (1, 1, 1279, 799), # max-1
|
||||
'gb': (320, 0, 1280, 1152), # x8
|
||||
'gbh': (320, 0, 1280, 1152), # x8
|
||||
'gbc': (320, 0, 1280, 1152), # x8
|
||||
'gbch': (320, 0, 1280, 1152), # x8
|
||||
'supervision': (400, 16, 1120, 1120), # x7
|
||||
'gamegear': (320, 0, 1280, 1152), # x8
|
||||
'ggh': (320, 0, 1280, 1152), # x8
|
||||
'pokemini': (384, 192, 1152, 768), # x12
|
||||
'ngp': (400, 44, 1120, 1064), # x7
|
||||
'ngpc': (400, 44, 1120, 1064), # x7
|
||||
'wonderswan': (64, 0, 1792, 1152), # x8
|
||||
'wonderswancolor': (64, 0, 1792, 1152), # x8
|
||||
}
|
||||
|
||||
bezel_cfg = None
|
||||
|
||||
if (bezel := config.get_setting('bezel')) and platform in system_viewport:
|
||||
logger.log(f'bezel: {bezel} platform: {platform} rom: {rom_name}')
|
||||
tmp_bezel = "/tmp/351elec-bezel.cfg"
|
||||
game_cfg = ''
|
||||
# set path
|
||||
path = ''
|
||||
for searchpath in bezel_dir:
|
||||
if os.path.isdir(f'{searchpath}/{bezel}'):
|
||||
path = f'{searchpath}/{bezel}'
|
||||
|
||||
bezel_system = config.get_setting('bezel.system.override')
|
||||
if not bezel_system or bezel_system == "AUTO":
|
||||
bezel_system = platform
|
||||
|
||||
bezel_system_png = f'{path}/systems/{bezel_system}.png'
|
||||
logger.log(f'Bezel system png: {bezel_system_png}')
|
||||
|
||||
game_bezel_override = config.get_setting('bezel.game.override')
|
||||
logger.log(f'Game bezel override: {game_bezel_override}')
|
||||
if not game_bezel_override or game_bezel_override == "AUTO":
|
||||
logger.log('No game specific override found. Looking for games')
|
||||
# is there a $ROMNAME.cfg?
|
||||
# exactly the same / just the name / default
|
||||
# Random bezels have to match $ROMNAME./d+.cfg
|
||||
romdir = f'{path}/systems/{bezel_system}/games'
|
||||
full_name = os.path.splitext(rom_name)[0]
|
||||
short_name = full_name.split(' (')[0]
|
||||
if os.path.isdir(romdir):
|
||||
with os.scandir(romdir) as it:
|
||||
full_list = [entry.name for entry in it if entry.is_file() and entry.name.endswith('.cfg')]
|
||||
for romname in (full_name, short_name , 'default'):
|
||||
logger.log(f'Looking at: {romdir}/{romname}')
|
||||
file_list = [file for file in full_list if re.fullmatch(fr'{re.escape(romname)}\.[0-9]+\.cfg', file)]
|
||||
if len(file_list) > 0:
|
||||
game_cfg = f'{romdir}/{random.choice(file_list)}'
|
||||
logger.log(f'Using random config: {game_cfg}')
|
||||
break
|
||||
elif os.path.isfile(f'{romdir}/{romname}.cfg'):
|
||||
game_cfg = f'{romdir}/{romname}.cfg'
|
||||
logger.log(f'Using ROM config: {game_cfg}')
|
||||
break
|
||||
else:
|
||||
game_cfg = f'{path}/systems/{bezel_system}/games/{game_bezel_override}.cfg'
|
||||
|
||||
if os.path.isfile(game_cfg):
|
||||
logger.log(f'game config file exists: {game_cfg}')
|
||||
with open(game_cfg) as f:
|
||||
contents = f.read().strip()
|
||||
bezel_system_png = f'{path}/systems/{bezel_system}/games/{contents}'
|
||||
logger.log(f'bezel png: {bezel_system_png}')
|
||||
if os.path.isfile(bezel_system_png):
|
||||
tmp_bezel_dict = {}
|
||||
tmp_bezel_dict['overlays'] = '1'
|
||||
tmp_bezel_dict['overlay0_full_screen'] = 'true'
|
||||
tmp_bezel_dict['overlay0_normalized'] = 'true'
|
||||
tmp_bezel_dict['overlay0_overlay'] = bezel_system_png
|
||||
overlays_dir = f'{path}/systems/{bezel_system}/overlays/'
|
||||
count = 0
|
||||
if os.path.isdir(overlays_dir):
|
||||
for overlay_png in iglob(f'{overlays_dir}/*.png'):
|
||||
overlay_name = os.path.splitext(os.path.basename(overlay_png))[0]
|
||||
overlay_setting = config.get_setting(f'bezel.overlay.{overlay_name}')
|
||||
if not overlay_setting:
|
||||
continue
|
||||
logger.log(f'Adding overlay. name: {overlay_name} overlay setting: {overlay_setting}')
|
||||
tmp_bezel_dict[f'overlay0_desc{count}_overlay'] = overlay_png
|
||||
tmp_bezel_dict[f'overlay0_desc{count}'] = 'nul,0.5,0.5,rect,0.5,0.5'
|
||||
count += 1
|
||||
tmp_bezel_dict['overlay0_descs'] = count
|
||||
if os.path.isfile(tmp_bezel):
|
||||
os.remove(tmp_bezel)
|
||||
write_file(tmp_bezel, tmp_bezel_dict)
|
||||
bezel_cfg = tmp_bezel
|
||||
|
||||
if bezel_cfg is not None:
|
||||
logger.log('using bezel')
|
||||
# configure bezel
|
||||
ra_append_dict['input_overlay_enable'] = 'true'
|
||||
ra_append_dict['input_overlay'] = bezel_cfg
|
||||
ra_append_dict['input_overlay_hide_in_menu'] = 'true'
|
||||
ra_append_dict['input_overlay_opacity'] = '1.000000'
|
||||
ra_append_dict['input_overlay_show_inputs'] = '2'
|
||||
ra_append_dict['video_scale_integer'] = 'false'
|
||||
ra_append_dict['aspect_ratio_index'] = '23'
|
||||
# configure custom scaling
|
||||
# needs some grouping to reflect the hack systems as well (i. e. gb=gb, gbh, gbc and gbch)
|
||||
ra_append_dict['custom_viewport_x'] = system_viewport[platform][0]
|
||||
ra_append_dict['custom_viewport_y'] = system_viewport[platform][1]
|
||||
ra_append_dict['custom_viewport_width'] = system_viewport[platform][2]
|
||||
ra_append_dict['custom_viewport_height'] = system_viewport[platform][3]
|
||||
else:
|
||||
logger.log('not using bezel')
|
||||
# disable decorations
|
||||
ra_append_dict['input_overlay_enable'] = 'false'
|
||||
# set standard resolution for custom scaling
|
||||
ra_append_dict['custom_viewport_x'] = system_viewport['standard'][0]
|
||||
ra_append_dict['custom_viewport_y'] = system_viewport['standard'][1]
|
||||
ra_append_dict['custom_viewport_width'] = system_viewport['standard'][2]
|
||||
ra_append_dict['custom_viewport_height'] = system_viewport['standard'][3]
|
||||
|
||||
# DECK specific options TODO: integrate better in the code
|
||||
# TODO: not working
|
||||
#ra_append_dict['video_windowed_fullscreen'] = "true"
|
||||
|
||||
# Write the raappend.cfg
|
||||
logger.log('Write raappend.cfg')
|
||||
write_file(ra_append_conf, ra_append_dict)
|
||||
|
||||
logger.log('done ...')
|
||||
return shader_path
|
||||
|
||||
# Main (if we are run as a script and not as a module)
|
||||
if __name__ == '__main__':
|
||||
# Arguments
|
||||
parser = ArgumentParser(description="Convert ES settings from distribution.conf to RetroArch configuration in raappend.conf.")
|
||||
parser.add_argument("--core", help="core", required=True)
|
||||
parser.add_argument("--platform", help="platform", required=True)
|
||||
parser.add_argument("--rom", help="ROM file name", required=True)
|
||||
parser.add_argument("--controllers", help="controller config", default="-p1index 0")
|
||||
parser.add_argument("--autosave", help="autosave", default="0")
|
||||
parser.add_argument("--snapshot", help="snapshot", default="")
|
||||
args = parser.parse_args()
|
||||
shader_path = set_settings(rom_name=args.rom, core=args.core, platform=args.platform, controllers=args.controllers, autosave=args.autosave, snapshot=args.snapshot)
|
||||
if shader_path:
|
||||
print(shader_path)
|
Loading…
Reference in a new issue