Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Scripts for Nostalgia-Tron series, part 10
#!/usr/bin/env ruby
require 'pathname'
begin
require 'inifile'
require 'nokogiri'
rescue LoadError => e
puts "This script requires nokogiri and inifile:"
puts " $ gem install nokogiri inifile"
exit 1
end
CATVER_PATH = Pathname.new(ARGV[0] || '/home/pi/catver.ini')
CATVER = IniFile::load(CATVER_PATH)
CATEGORIES = CATVER['Category']
GAMELIST_DIR = Pathname.new('/home/pi/.emulationstation/gamelists/arcade')
GAMELIST_BACKUP_PATH = GAMELIST_DIR.join("gamelist.xml.#{Time.now.to_i}.bak")
GAMELIST_CURRENT_PATH = GAMELIST_DIR.join('gamelist.xml')
# Backup current gamelist.xml.
GAMELIST_BACKUP_PATH.open('w') do |f|
f.write(GAMELIST_CURRENT_PATH.read)
end
GAMELIST_XML = Nokogiri::XML(GAMELIST_CURRENT_PATH.read)
# Traverse the gamelist.
GAMELIST_XML.css('gameList > game').each do |g|
path_node = g.at_css('path')
basename = Pathname.new(path_node).basename('.zip').to_s
genre_node = g.at_css('genre')
current_genre = g.at_css('genre').content rescue "(none)"
new_genre = CATEGORIES[basename]
puts "GAME: #{basename}"
# Do we need to do anything for this game?
if new_genre == current_genre
puts " genre is up to date"
next
end
# Do we have a genre to give it?
unless new_genre && !new_genre.empty?
puts " no genre found in INI"
next
end
# This game has a genre. Write it to the XML.
# Create the node if it didn't exist before.
if !genre_node
genre_node = Nokogiri::XML::Node.new('genre', GAMELIST_XML)
g.add_child(genre_node)
end
genre_node.content = new_genre
puts " Current genre: #{current_genre}"
puts " New genre: #{new_genre}"
end
# Write out the XML to a
GAMELIST_CURRENT_PATH.open('w') do |f|
GAMELIST_XML.write_xml_to(f)
end
puts "...done."
#!/usr/bin/env ruby
require 'pathname'
begin
require 'nokogiri'
rescue LoadError => e
puts "This script requires nokogiri:"
puts " $ gem install nokogiri"
exit 1
end
SYSTEM = 'arcade'
def screenshot_path_for_game(system, game)
Pathname.new("/home/pi/screens/#{system}/#{game}.png")
end
GAMELIST_DIR = Pathname.new("/home/pi/.emulationstation/gamelists/#{SYSTEM}")
GAMELIST_BACKUP_PATH = GAMELIST_DIR.join("gamelist.xml.#{Time.now.to_i}.bak")
GAMELIST_CURRENT_PATH = GAMELIST_DIR.join('gamelist.xml')
# Backup current gamelist.xml.
GAMELIST_BACKUP_PATH.open('w') do |f|
f.write(GAMELIST_CURRENT_PATH.read)
end
GAMELIST_XML = Nokogiri::XML(GAMELIST_CURRENT_PATH.read)
# Traverse the gamelist.
GAMELIST_XML.css('gameList > game').each do |g|
path_node = g.at_css('path')
basename = Pathname.new(path_node).basename('.zip').to_s
art_node = g.at_css('image')
current_art = art_node.content rescue nil
new_art = screenshot_path_for_game(SYSTEM, basename)
puts "GAME: #{basename}"
if new_art == current_art
puts " no change needed"
next
end
# Does the screenshot exist?
if new_art.file?
# Update the artwork's modified time so we can more easily tell which
# artwork files we aren't using later on.
path.touch
else
puts " could not find screenshot at #{new_art}"
next
end
# Create the `image` element if needed.
if !art_node
art_node = Nokogiri::XML::Node.new('image', GAMELIST_XML)
g.add_child(art_node)
end
art_node.content = new_art.to_s
puts " changed art path to #{new_art}"
end
# Write out the XML.
GAMELIST_CURRENT_PATH.open('w') do |f|
GAMELIST_XML.write_xml_to(f)
end
puts "...done."
#!/usr/bin/env ruby
require 'nokogiri'
require 'optparse'
require 'pathname'
SYSTEMS = ARGV
NAME_MAP = {
'arcade' => 'Arcade Games',
'daphne' => 'Laserdisc Games'
}
GAMELIST_ROOT = Pathname.new('/home/pi/.emulationstation/gamelists/')
output = []
$options = {
require: ['name', 'genre', 'developer']
}
opts = OptionParser.new do |o|
o.banner = "Usage: make-game-list [options] [systems]"
o.separator ""
o.on('-r', '--require=FOO,BAR', "Skip games that lack any of these fields (default: name, genre, developer)") do |value|
$options[:require] = value.split(',')
end
end
begin
opts.parse!
rescue OptionParser::InvalidArgument => e
STDERR.puts("#{e.message}\n\n")
STDERR.puts(opts)
exit 1
end
def fails_requirements?(meta)
$options[:require].any? { |k| meta[k.to_sym].nil? }
end
def html_for_game(game)
id = File.basename( game.at_css('path').content, '.zip' )
name = game.at_css('name').content
date = game.at_css('releasedate').content rescue nil
year = date.nil? ? nil : date[0..3]
genre = game.at_css('genre').content rescue nil
developer = game.at_css('developer').content rescue nil
description = game.at_css('desc').content rescue nil
return '' if fails_requirements?({
name: name,
year: year,
genre: genre,
developer: developer
})
%Q[
<tr>
<td data-game="#{id}" data-value="#{name}">
<a href="#" class="game-link" data-toggle="popover" data-title="#{name}">#{name}</a>
<div class="game-description">#{description}</div>
</td>
<td>#{year || '?'}</td>
<td>#{genre || '?'}</td>
<td>#{developer || '?'}</td>
</tr>
]
end
def html_for_system(path)
xml = Nokogiri::XML( path.open )
system = path.dirname.basename.to_s
games = xml.css('gameList > game')
%Q[
<h2 class="system-title">#{NAME_MAP[system] || system}</h2>
<table class="table table-bordered table-collapsed table-striped sortable">
<thead>
<tr>
<th data-defaultsort="asc">Game</th>
<th>Year</th>
<th>Genre</th>
<th>Manufacturer</th>
</tr>
</thead>
<tbody>
#{games.map(&method(:html_for_game)).join("\n")}
</tbody>
</table>
]
end
SYSTEMS.each do |system|
path = GAMELIST_ROOT.join(system, 'gamelist.xml')
output << html_for_system(path)
end
output = output.join("\n")
content = <<-HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Nostalgia-Tron Games List</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=News+Cycle:700|Oxygen">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css" media="screen">
h1, h2, h3:not(.popover-title) {
font-family: 'News Cycle', sans-serif;
}
h3.popover-title {
font-weight: bold;
}
h2.system-title {
margin: 2.5rem 0 2rem;
}
body {
font-family: 'Oxygen', sans-serif;
padding-top: 3rem;
padding-bottom: 3rem;
}
.popover {
font-family: 'Oxygen', sans-serif;
}
.game-description {
display: none;
}
</style>
</head>
<body>
<div class="container">
#{output}
</div>
<script type="text/javascript">
$(function () {
// When we open a popover, hide any others that may be open.
$('a.game-link').click(function (e) {
e.preventDefault();
var $others = $('[data-toggle="popover"]').not(e.target);
$others.popover('hide');
$(e.target).popover('toggle');
});
// Make popovers wider.
$('a.game-link').on('show.bs.popover', function () {
$(this).data("bs.popover").tip().css("max-width", "600px");
});
// Hide a popover whenever someone clicks off.
$('body').click(function (e) {
var $anchor = $(e.target).closest('a.game-link');
var $popover = $(e.target).closest('.popover');
if ($anchor.length > 0 || $popover.length > 0) return;
$('[data-toggle="popover"]').popover('hide');
});
$('[data-toggle="popover"]').popover({
html: true,
trigger: 'manual',
container: 'body',
placement: 'auto bottom',
content: function () {
var text = $(this).closest('td').find('.game-description').text();
text = "<p>" + text + "</p>";
text = text.replace(/\\n\\s*\\n/g, "</p>\\n<p>");
return text;
}
});
});
</script>
</body>
</html>
HTML
puts content
#!/bin/bash
print_help_and_exit() {
echo "Usage: quit-emulationstation [options]"
echo ""
echo "Exits EmulationStation gracefully (if it is running)."
exit 0
}
while true ; do
case "$1" in
-h) print_help_and_exit ;;
*) break ;;
esac
shift
done
pid=`ps -ef | awk '/emulationstation\/emulationstation$/ {print $2}'`
if [ -z $pid ]; then
echo "EmulationStation doesn't appear to be running."
exit 1
else
printf "Quitting EmulationStation..."
kill $pid && echo -e "done.\n"
exit 0
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment