-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
357 additions
and
63 deletions.
There are no files selected for viewing
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
## billboard | ||
|
||
Periodically pulls images and text from Reddit and displays them full-screen. | ||
Inspired by | ||
|
||
http://imgur.com/a/Io3xi | ||
|
||
|
||
### Note | ||
|
||
This requires PyQt4 to be installed on the system. It seems it currently cannot | ||
be deployed with pip, so it's not mentioned in the dependencies. | ||
|
||
|
||
### TODO | ||
|
||
- Currently a buch of stuff is hard-coded that should be configurable (e.g. | ||
subpreddits to pull images/text from) | ||
- Add more sources (currenltly, only Reddit) | ||
- An ability to remotely send images/text to the billboard for immediate display | ||
- Support Python 2 | ||
- Switch to PyQt5 | ||
- ... | ||
|
||
|
||
### LICENSE | ||
|
||
3-clause BSD | ||
|
||
|
Empty file.
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import sys | ||
import argparse | ||
|
||
from PyQt4.QtGui import QApplication | ||
|
||
from billboard.billboard import Billboard | ||
from billboard.display import BillboardDisplay | ||
from billboard.sources.reddit import RedditSource | ||
|
||
|
||
def parse_args(): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('-p', '--period', type=int, default=60*15, | ||
help=''' | ||
Period for switching billboard display in seconds. | ||
Defaults to 15 minutes. | ||
''') | ||
return parser.parse_args(sys.argv[1:]) | ||
|
||
|
||
def main(): | ||
args = parse_args() | ||
app = QApplication(sys.argv) | ||
|
||
display = BillboardDisplay() | ||
sources = [RedditSource()] | ||
|
||
billboard = Billboard(display, sources, args.period) | ||
|
||
billboard.start() | ||
display.show() | ||
app.exec_() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() | ||
|
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import time | ||
from threading import Thread | ||
from itertools import cycle | ||
|
||
|
||
class Billboard(Thread): | ||
|
||
def __init__(self, display, sources, period): | ||
super(Billboard, self).__init__() | ||
self.display = display | ||
self.sources = sources | ||
self.period = period | ||
self.daemon = True | ||
|
||
def run(self): | ||
for source in cycle(self.sources): | ||
image, text = source.next() | ||
if image is None and text is None: | ||
continue | ||
if image is not None: | ||
self.display.update_image(image) | ||
if text is not None: | ||
self.display.display_text(text) | ||
time.sleep(self.period) |
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import os | ||
|
||
from PyQt4.QtCore import Qt, QObject, SIGNAL | ||
from PyQt4.QtGui import (QMainWindow, QWidget, QPixmap, QLabel, | ||
QGraphicsDropShadowEffect, QColor, | ||
QDesktopWidget) | ||
|
||
|
||
class BillboardDisplay(QMainWindow): | ||
|
||
def __init__(self, parent=None, fontsize=42): | ||
super(BillboardDisplay, self).__init__(parent) | ||
desktop = QDesktopWidget() | ||
self.display = QWidget(self) | ||
size = desktop.availableGeometry(desktop.primaryScreen()); | ||
self.display.resize(size.width(), size.height()) | ||
self.display.setWindowTitle("Billboard") | ||
|
||
self.image_label = QLabel(self.display) | ||
self.image_label.resize(size.width(), size.height()) | ||
|
||
self.text_label = QLabel(self.display) | ||
self.text_label.resize(size.width(), size.height()) | ||
self.text_label.setMargin(100) | ||
self.text_label.setStyleSheet(''' | ||
QLabel {{ | ||
font-size: {}pt; | ||
color: #eeeeee; | ||
text-align: center; | ||
}} | ||
'''.format(fontsize)) | ||
self.text_label.setWordWrap(True) | ||
self.text_label.setAlignment(Qt.AlignCenter) | ||
|
||
dse = QGraphicsDropShadowEffect() | ||
dse.setBlurRadius(10) | ||
dse.setXOffset(0) | ||
dse.setYOffset(0) | ||
dse.setColor(QColor(0, 0, 0, 255)) | ||
self.text_label.setGraphicsEffect(dse) | ||
QObject.connect(self, SIGNAL("updateimage"), | ||
self.display_image) | ||
|
||
def update_image(self, imagepath): | ||
self.emit(SIGNAL("updateimage"), imagepath) | ||
|
||
def display(self, imagepath, text): | ||
self.display_text(text) | ||
self.display_image(imagepath) | ||
self.showFullScreen() | ||
|
||
def display_image(self, imagepath): | ||
pix = QPixmap(imagepath) | ||
self.image_label.setPixmap(pix.scaled(self.display.size(), | ||
Qt.KeepAspectRatioByExpanding)) | ||
|
||
def display_text(self, text): | ||
self.text_label.setText('"{}"'.format(text)) | ||
|
Empty file.
File renamed without changes.
This file contains 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 characters
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from collections import MutableSet | ||
|
||
# based on OrderedSet recipe: | ||
# https://code.activestate.com/recipes/576694/ | ||
class DroppingSet(MutableSet): | ||
""" | ||
A set with a maximum size. It keeps track of the order in which elements | ||
are added. Once max_size is reached, oldest elements are dropped. | ||
""" | ||
|
||
@property | ||
def max_size(self): | ||
return self._max_size | ||
|
||
@max_size.setter | ||
def max_size(self, value): | ||
self._max_size = value | ||
while len(self) > self._max_size: | ||
self.pop(last=False) | ||
|
||
def __init__(self, max_size, iterable=None): | ||
self._max_size = max_size | ||
self.end = end = [] | ||
end += [None, end, end] # sentinel node for doubly linked list | ||
self.map = {} # key --> [key, prev, next] | ||
if iterable is not None: | ||
self |= iterable | ||
|
||
def __len__(self): | ||
return len(self.map) | ||
|
||
def __contains__(self, key): | ||
return key in self.map | ||
|
||
def add(self, key): | ||
while len(self) >= self.max_size: | ||
self.pop(last=False) | ||
if key not in self.map: | ||
end = self.end | ||
curr = end[1] | ||
curr[2] = end[1] = self.map[key] = [key, curr, end] | ||
|
||
def discard(self, key): | ||
if key in self.map: | ||
key, prev, next = self.map.pop(key) | ||
prev[2] = next | ||
next[1] = prev | ||
|
||
def __iter__(self): | ||
end = self.end | ||
curr = end[2] | ||
while curr is not end: | ||
yield curr[0] | ||
curr = curr[2] | ||
|
||
def __reversed__(self): | ||
end = self.end | ||
curr = end[1] | ||
while curr is not end: | ||
yield curr[0] | ||
curr = curr[1] | ||
|
||
def pop(self, last=True): | ||
if not self: | ||
raise KeyError('set is empty') | ||
key = self.end[1][0] if last else self.end[2][0] | ||
self.discard(key) | ||
return key | ||
|
||
def __repr__(self): | ||
if not self: | ||
return '%s()' % (self.__class__.__name__,) | ||
return '%s(%r)' % (self.__class__.__name__, list(self)) | ||
|
||
def __eq__(self, other): | ||
if isinstance(other, OrderedSet): | ||
return len(self) == len(other) and list(self) == list(other) | ||
return set(self) == set(other) | ||
|
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env python3 | ||
from billboard.app import main | ||
main() |
Oops, something went wrong.