Added ftp-sync, nkit, sfo-read, and vita-sync.
parent
131b9178e8
commit
8d8837927e
@ -1,8 +1,9 @@
|
||||
#!/usr/bash
|
||||
#!/bin/bash
|
||||
|
||||
test_dir='/media/hoard-disk/ebooks'
|
||||
dir='/media/hoard/hoard/'
|
||||
fileshare_group='library-users'
|
||||
fileshare_owner='emily'
|
||||
|
||||
sudo chown root:root "$test_dir"
|
||||
sudo chmod 600 "$test_dir"
|
||||
sudo setfacl -Rm 'group:fileshare:r-x' "$test_dir"
|
||||
sudo setfacl -Rm 'group:fileshare-admin:rwx' "$test_dir"
|
||||
chown -R $fileshare_owner:$fileshare_group "$dir"
|
||||
find "$dir" -type d -exec chmod 755 {} \;
|
||||
find "$dir" -type f -exec chmod 644 {} \;
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
FTP_DIR=~/.local/var/ftp-mount/
|
||||
host="$1"
|
||||
local_dir="$2"
|
||||
|
||||
curlftpfs "$host" "$FTP_DIR" || exit 1
|
||||
|
||||
# TODO: Copying to FTP produces "ftruncate failed" errors. Not sure how to convince rsync to not use
|
||||
# that.
|
||||
# TODO: Rsync is probably not the best tool for the job here. It has *no* conflict handling.
|
||||
echo "Copying new data to FTP server."
|
||||
rsync -rtu --progress --inplace "$local_dir/" "$FTP_DIR"
|
||||
|
||||
echo "Copying new data from FTP server."
|
||||
rsync -rtu --progress "$FTP_DIR" "$local_dir"
|
||||
|
||||
# TODO: This should probably be in a trap function.
|
||||
fusermount -u "$FTP_DIR"
|
||||
echo "Done."
|
||||
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# rebuild-iso
|
||||
# compress
|
||||
|
||||
case $1 in
|
||||
'compress')
|
||||
mono /usr/lib/nkit/ConvertToNKit.exe "${@:2}"
|
||||
;;
|
||||
'rebuild-iso')
|
||||
mono /usr/lib/nkit/ConvertToISO.exe "${@:2}"
|
||||
;;
|
||||
*)
|
||||
echo 'Missing action.'
|
||||
;;
|
||||
esac
|
||||
@ -1,82 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
### ps2-sync
|
||||
This tool makes links to ISO files in the way that Open PS2 Loader expects. It should work for both
|
||||
Samba and USB loading, but has only been tested with Samba.
|
||||
|
||||
This depends on hdl-dump.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
# TODO: Replace these with user input and/or config files.
|
||||
ROOT_PATH = '.'
|
||||
|
||||
def get_disc_info(disc_image_path):
|
||||
this_disc_info = {
|
||||
'gameid': None,
|
||||
'disc_type': None,
|
||||
'filename': None
|
||||
}
|
||||
|
||||
# TODO: Figure out how to do hdl-dump's work in this script.
|
||||
# I tried this with isoparser, but the parsing took far too long.
|
||||
hdl_dump_args = ['hdl-dump', 'cdvd_info2', disc_image_path]
|
||||
# hdl-dump has a weird output format, quoting items inconsistently. Fortunately, it isn't
|
||||
# likely to change anytime soon.
|
||||
hdl_dump_result = subprocess.run(hdl_dump_args, capture_output=True)
|
||||
if hdl_dump_result.returncode == 0:
|
||||
hdl_dump_output = hdl_dump_result.stdout.decode('utf-8').split(' ')
|
||||
|
||||
# hdl-dump prepends "dual-layer" to the disc type field instead of using DVD5/DVD9.
|
||||
if hdl_dump_output[0] == 'dual-layer':
|
||||
this_disc_info['gameid'] = hdl_dump_output[4][1:-1]
|
||||
this_disc_info['disc_type'] = hdl_dump_output[1]
|
||||
|
||||
else:
|
||||
this_disc_info['gameid'] = hdl_dump_output[3][1:-1]
|
||||
this_disc_info['disc_type'] = hdl_dump_output[0]
|
||||
|
||||
this_disc_info['filename'] = os.path.basename(disc_image_path)
|
||||
else:
|
||||
print('File %s is not a Playstation 2 disc image.' % os.path.basename(disc_image_path))
|
||||
|
||||
return this_disc_info
|
||||
|
||||
def remove_dead_links(directory):
|
||||
for link_name in os.listdir(directory):
|
||||
link_path = os.path.abspath(os.path.join(directory, link_name))
|
||||
if os.path.islink(link_path):
|
||||
link_target = os.path.join(directory, os.readlink(link_path))
|
||||
if not os.path.exists(link_target):
|
||||
print('Removing dead link %s.' % link_path)
|
||||
os.remove(link_path)
|
||||
|
||||
root_path = os.path.abspath(ROOT_PATH)
|
||||
source_path = os.path.join(root_path, 'iso')
|
||||
disc_repo = os.path.join(root_path, '.opl-srv')
|
||||
|
||||
os.makedirs(os.path.join(disc_repo, 'DVD'), exist_ok=True)
|
||||
os.makedirs(os.path.join(disc_repo, 'CD'), exist_ok=True)
|
||||
remove_dead_links(os.path.join(disc_repo, 'DVD'))
|
||||
remove_dead_links(os.path.join(disc_repo, 'CD'))
|
||||
|
||||
for filename in os.listdir(source_path):
|
||||
disc_path = os.path.join(source_path, filename)
|
||||
disc_info = get_disc_info(disc_path)
|
||||
|
||||
if not disc_info['disc_type'] or not disc_info['gameid']:
|
||||
print("Disc type could not be determined for %s" % disc_info['filename'])
|
||||
|
||||
else:
|
||||
disc_link_filename = '%s.%s' % (disc_info['gameid'], disc_info['filename'])
|
||||
disc_link_path = os.path.join(disc_repo, disc_info['disc_type'], disc_link_filename)
|
||||
disc_rel_path = os.path.relpath(disc_path, start=os.path.dirname(disc_link_path))
|
||||
|
||||
if not os.path.exists(disc_link_path):
|
||||
print('Adding disc %s.' % disc_info['filename'])
|
||||
print('Linking to %s.' % disc_rel_path)
|
||||
os.symlink(disc_rel_path, disc_link_path)
|
||||
else:
|
||||
print('Disc %s already linked.' % disc_info['filename'])
|
||||
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import struct
|
||||
import sys
|
||||
|
||||
SFO_MAGIC = b'\x00PSF'
|
||||
SFO_HEADER_FORMAT = '<iiiii'
|
||||
SFO_INDEX_FORMAT = '<HHLLL'
|
||||
SFO_INDEX_STRUCT = struct.Struct(SFO_INDEX_FORMAT)
|
||||
|
||||
parameter_format_enum = {}
|
||||
parameter_format_enum[int(0x0004)] = 'utf8-special'
|
||||
parameter_format_enum[int(0x0204)] = 'utf8'
|
||||
parameter_format_enum[int(0x0404)] = 'integer'
|
||||
|
||||
class SFOReadError(Exception):
|
||||
'''This error is raised when an SFO file could not be read.'''
|
||||
|
||||
class SFO:
|
||||
def __init__(self, filename):
|
||||
self.data = {}
|
||||
self._metadata = {}
|
||||
with open(filename, mode='rb') as file_handle:
|
||||
self._contents = file_handle.read()
|
||||
|
||||
self._read_header()
|
||||
self._read_index()
|
||||
|
||||
def get_data(self, key):
|
||||
if key.upper() in self.data.keys():
|
||||
return self.data[key.upper()]
|
||||
|
||||
def _read_header(self):
|
||||
header_raw = struct.unpack(SFO_HEADER_FORMAT, self._contents[0:20])
|
||||
if header_raw[0] != int.from_bytes(SFO_MAGIC, 'little'):
|
||||
raise SFOReadError('This is not an SFO file.')
|
||||
|
||||
self._metadata['key_table_offset'] = header_raw[2]
|
||||
self._metadata['data_table_offset'] = header_raw[3]
|
||||
self._metadata['entry_count'] = header_raw[4]
|
||||
|
||||
def _read_index(self):
|
||||
self._metadata['data'] = []
|
||||
index_slice = self._contents[20:self._metadata['key_table_offset']]
|
||||
for index_raw in SFO_INDEX_STRUCT.iter_unpack(index_slice):
|
||||
data = {}
|
||||
data['key_table_offset'] = index_raw[0]
|
||||
data['parameter_format'] = parameter_format_enum[index_raw[1]]
|
||||
data['parameter_length'] = index_raw[2]
|
||||
data['parameter_max_length'] = index_raw[3]
|
||||
data['data_table_offset'] = index_raw[4]
|
||||
|
||||
key_start = self._metadata['key_table_offset'] + data['key_table_offset']
|
||||
key = self._read_nt_string(key_start)
|
||||
|
||||
value_start = self._metadata['data_table_offset'] + data['data_table_offset']
|
||||
value_end = value_start + data['parameter_length']
|
||||
|
||||
if data['parameter_format'] == 'utf8':
|
||||
self.data[key] = self._contents[value_start:value_end-1].decode('utf8')
|
||||
elif data['parameter_format'] == 'integer':
|
||||
self.data[key] = int.from_bytes(self._contents[value_start:value_end], 'little')
|
||||
|
||||
self._metadata['data'].append(data)
|
||||
|
||||
def _read_nt_string(self, start_position):
|
||||
char = ''
|
||||
string = ''
|
||||
i = start_position
|
||||
|
||||
while char != 0:
|
||||
char = self._contents[i]
|
||||
if char != 0:
|
||||
string += chr(char)
|
||||
i += 1
|
||||
|
||||
return string
|
||||
|
||||
sfo_file = sys.argv[1]
|
||||
get_params = sys.argv[2:]
|
||||
|
||||
sfo = SFO(sfo_file)
|
||||
|
||||
values = []
|
||||
for param in get_params:
|
||||
values.append(sfo.get_data(param))
|
||||
|
||||
print(', '.join(values))
|
||||
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Sync Vita save data with a local directory.
|
||||
# Add non-Retroarch directories if it makes sense to.
|
||||
|
||||
vita_ip="$1"
|
||||
|
||||
RETROARCH_PATH_VITA="ux0:/data/retroarch/savefiles"
|
||||
RETROARCH_PATH_LOCAL=~/Nextcloud/game-saves/retroarch/saves
|
||||
|
||||
ftp-sync "${vita_ip}:1337/${RETROARCH_PATH_VITA}" "$RETROARCH_PATH_LOCAL"
|
||||
Loading…
Reference in New Issue