Last active
September 6, 2017 03:25
Revisions
-
savetheclocktower revised this gist
Sep 6, 2017 . 1 changed file with 27 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,27 @@ #!/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 -
savetheclocktower created this gist
Sep 5, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,71 @@ #!/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." This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,71 @@ #!/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." This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,195 @@ #!/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