Skip to content

Instantly share code, notes, and snippets.

@jasongrout
Created February 3, 2019 05:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasongrout/2baf84e243f8cb6d822fbdfd17715d6c to your computer and use it in GitHub Desktop.
Save jasongrout/2baf84e243f8cb6d822fbdfd17715d6c to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# TODO:
# [X] initialize only the modules we are using
# [X] Display a single specific picture from the 2011 folder
# [X] Regenerate pics for 1080p
# Minimum Viable Product (MVP)
# [X] Pick a random pic from the 2011 folder
# [X] Pick a random pic from the Export1080p folder
# [X] Display a random pic over and over again, with 10 minutes in between. Maybe move the picture slightly every so often?
# [X] Clear the screen between pictures
# [X] set_allowed(None) -> None
# [X] Shift-escape exits
# [X] Press a key changes the picture
# [X] Use a pygame clock? - NO, use the events instead.
# [X] Make program event-driven
# [X]forwards arrow
# [X] Center the picture
# [X] Make *just* the space key change the picture.
# [X] Make left mouse/right mouse click be the same as left/right arrow, and middle mouse click same as space bar.
# [X] Hold down a mouse button for a set time should also exit the program (7 seconds?)
# [X] Replace key checks with .key = pygame.K_LEFT, pygame.K_ESCAPE, etc. See https://www.pygame.org/docs/ref/key.html for constants
# [X] Move all constants up to the top of the program, make the units easy for Dad to change (like minutes for new picture, not milliseconds)
# [X] Fix shift-escape to check modifier keys using a bitmask (get binary repr with `bin`)
# [X] Print file name (without the '.jpg') in the upper left.
# [X] Print a small shadow to help reading the numbers when on a light background.
# [X] Use pygame.freetype module to render nicer text directly to the screen
# [X] Move text to the bottom left, say 5 pixels up from the bottom?
# [X] Make a shortcut you can click on to start the program
# [X] Toggle text for different formats with a key
# [X] Uninstall screensaver
# [X] Make the date text format a bit nicer, like 27 Aug 2006 (be careful, not all filenames are dates)
# [X] Turn off screensaver: http://www.raspberry-projects.com/pi/pi-operating-systems/raspbian/screensaver
# [X] Pick a random day, then a picture from that day - probably good enough to group based on the first 8 characters of the filename.
# [X] Make the pictures directory a variable
# [X] Make the program automatically run on bootup. http://www.raspberry-projects.com/pi/pi-operating-systems/raspbian/auto-running-programs-gui
# [ ] Make program version controlled and clean up the TODOs
# [ ] Copy the sd disk and check in the old pi to make sure it works
# [ ] Wrap, package up, and ship
# If we have time:
# [ ] Turn off screen at night (see note below about `xset dpms force off`. Also see https://wiki.libsdl.org/FAQUsingSDL#Why_does_SDL_disable_my_screensaver_by_default.3F about allowing the screen to blank while running the program - we'll need to set an environment variable in this program using os.environ).
# [ ] Save the pic history to a file to easily pick it back up again
# [ ] bias against showing pics we've already shown. Perhaps if we generate a pic already in the history list, try at least once to pick a new random picture, or after we show a picture, take it out of the list.
# [ ] Be able to rate a picture from 1-5, show the rating next, maybe make it more likely to be picked. Be able to say "don't show this pic again".
# Later
# [ ] Make it easy to turn on or off LED lights. Ask about good default.
# [ ] Print the date on the picture (get date with stat call?)
# [ ] Picture selection logic - higher preference to pictures in similar season, pics with higher ratings, etc.
# [ ] Print info about the pic on the pic display (date, filename, keywords, caption, etc.)
# [ ] up/down keys go through the pictures chronologically?
# [ ] Handle pics with different sizes/orientations. Rotate? Put upright and blur the background? Center smaller pics
# [ ] Hook up hardware buttons and switch: buttons to go prev/next, switch to hold a pic, buttons to rate a pic up or down.
# autorun: http://www.raspberry-projects.com/pi/pi-operating-systems/raspbian/auto-running-programs-gui
# control LEDs: https://www.jeffgeerling.com/blogs/jeff-geerling/controlling-pwr-act-leds-raspberry-pi - set the trigger for each led (if 'none' doesn't work to turn them off, try 'gpio')
# Setup:
# - Edit /boot/config.txt and add `hdmi_blanking=1`. Then you can use `xset dpms force off` to blank the screen and turn off the monitor until another key is pressed. See https://www.raspberrypi.org/documentation/configuration/config-txt/video.md and https://github.com/raspberrypi/linux/issues/487.
###########
# import stuff we need
from random import SystemRandom
import pygame
import time
import os
import pygame.freetype
# Set the variables so we can easily change the program
FULLSCREEN = True
TIMER = 60 # in minutes
FONTSIZE = 110
FORMAT = 1
PIC_DIRECTORY = 'Export1080p/'
def date (filename):
if FORMAT == 0:
return ''
elif FORMAT == 1:
if filename[0] == '2':
return convert(filename)
else:
return ''
elif FORMAT == 2:
return filename[:-4]
months = {
'01': 'Jan',
'02': 'Feb',
'03': 'Mar',
'04': 'Apr',
'05': 'May',
'06': 'June',
'07': 'July',
'08': 'Aug',
'09': 'Sep',
'10': 'Oct',
'11': 'Nov',
'12': 'Dec'
}
def convert(date):
year = date[:4]
month = date[4:6]
day = date[6:8]
month = months[month]
return day+' '+month+' '+year
def group(data):
"organizing the list of strings in a dict, returns the dict"
dic = {}
for name in data:
start = name[:8]
if start not in dic:
dic[start] = [name]
else:
dic[start].append(name)
return dic
# Start pygame up, setting allowed events
pygame.freetype.init()
pygame.display.init()
pygame.event.set_allowed(None)
pygame.event.set_allowed([pygame.USEREVENT,pygame.KEYDOWN,pygame.QUIT, pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP])
if FULLSCREEN:
pygame.mouse.set_visible(False)
screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN) # fullscreen
else:
screen = pygame.display.set_mode((300, 200)) # development
PICTURE_CHANGE = pygame.USEREVENT
font = pygame.freetype.SysFont(None, FONTSIZE)
random = SystemRandom()
def show(filename):
screen.fill([0,0,0])
image = pygame.image.load(PIC_DIRECTORY + filename)
cimage = image.convert()
if FULLSCREEN:
x = screen.get_width()
n = cimage.get_width()
offset = round((x-n)/2)
screen.blit(cimage, (offset,0))
else:
pygame.transform.smoothscale(cimage, (300, 200), screen) # development
# Put the filename up on the screen, not .jpg .
words = font.render( date(filename), fgcolor=(255,255,255), bgcolor=(0,0,0,100))
s = screen.get_height()
w = words[0].get_height()
screen.blit(words[0],(10,s-w-5))
pygame.display.flip()
pygame.time.set_timer(PICTURE_CHANGE,TIMER*60*1000)
# Set up the picture history
position = -1
history = [] # list of filenames tha you have veiwed
# Get all of the filenames in the picture directory
pic_files = os.listdir(path=PIC_DIRECTORY)
groups = group(pic_files)
days = list(groups.keys())
# Show the first picture after a second
pygame.time.set_timer(PICTURE_CHANGE, 1000)
# Handle events
while True:
f=pygame.event.wait()
# Show a new random picture
if (f.type == PICTURE_CHANGE
or (f.type == pygame.KEYDOWN and (f.key == pygame.K_SPACE))
or (f.type == pygame.MOUSEBUTTONDOWN and f.button == 2)):
#pick a day, then pick a random pic from that day
day = random.choice(days)
x = random.choice(groups[day])
history.append(x)
position = -1
show(history[position])
# Change the date format
if (f.type == pygame.KEYDOWN and f.key == pygame.K_RETURN):
FORMAT = FORMAT+1
if FORMAT == 3:
FORMAT = 0
show(history[position])
# Show the previous picture
if (f.type == pygame.KEYDOWN and f.key == pygame.K_LEFT) or (f.type == pygame.MOUSEBUTTONDOWN and f.button == 1):
if len(history) > -position:
position = position-1
show(history[position])
# Show the next picture
if (f.type == pygame.KEYDOWN and f.key == pygame.K_RIGHT) or (f.type == pygame.MOUSEBUTTONDOWN and f.button == 3):
if position < -1:
position = position+1
show(history[position])
# Quit the program
if f.type == pygame.QUIT:
break
# Quit if shift-escape
if (f.type == pygame.KEYDOWN
and f.key == pygame.K_ESCAPE
and (f.mod & pygame.KMOD_SHIFT != 0)):
break
# Quit if you hold down a mouse button for 5 seconds
if (f.type == pygame.MOUSEBUTTONDOWN and f.button in [1,2,3]):
pygame.time.set_timer(pygame.QUIT,1000*5)
if (f.type == pygame.MOUSEBUTTONUP and f.button in [1,2,3]):
# Cancel the quit event since we let up on the mouse button
pygame.time.set_timer(pygame.QUIT,0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment