tag:blogger.com,1999:blog-28433547960099162122024-03-21T06:18:05.655-07:00Fuzzy's Projects Blog<img src="https://s.gravatar.com/avatar/5ccd01daef6b927c75726f62fa1ca3bb?s=100" align="left" hspace="20">Hi, I'm Fuzzy. <br>On this blog I post bits and pieces about the projects I'm work on. <br>For a list of things I've made, check out my <a href="http://fuzzwah.github.io/">Fuzzy's Projects</a> site.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-2843354796009916212.post-33087281318704702632016-06-04T22:43:00.002-07:002016-06-04T22:43:45.823-07:00fuzzyslogic.com changesI've spent a bit of time recently extending the new flask based backend I'm using on <a href="http://fuzzyslogic.com">fuzzyslogic.com</a>.<br />
<br />
The main areas of improvement is around image and thumbnail handling and refactoring the database models to allow for sucking in content from sites which use atom feeds with custom fields (ie: goodreads).<br />
<br />
I'm continuing to enjoy working with python, flask, sqlalchemy and jinja2. I feel like my understanding of the framework has really come along and I'm confident that things I used to consider to be major work I can throw together very quickly.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com1tag:blogger.com,1999:blog-2843354796009916212.post-79737783683958752882016-01-12T19:07:00.001-08:002016-01-12T19:07:26.369-08:00I Know Python... A BitBack in 2014 I had the realisation that not every problem was a nail which could be hit with my clumsy php hammer. I needed to find a language which I could use to create desktop applications and settled on python. I'm very glad I did.<br />
<br />
My initial apps were basic console based utilities but I quickly found myself wanting to create GUI based tools. I got my head around WXPython and have a couple of apps which I'm proud enough of that I'll let other people use them. Things that I'd always skipped over as being "too pro for me to bother with" such as unit tests, logging, error handling and code re-usability come second nature.<br />
<br />
During 2015 I decided I liked python so much I didn't even want to use php for websites any more. I read a bunch of stuff about web frameworks such as django and pyramid but finally settled on flask (well, actually flask appbuilder). I've used this to create a handful of sites which are at a level of complexity that I'd never have even attempted in php.<br />
<br />
The next big jump I made was learning about threading so that my GUI based apps were completely non-blocking and gave good feedback to the user about what was happening.<br />
<br />
Better yet is that I've got all these things set up in project skeletons which I can quickly build on top of to kick start development of new tools.<br />
<br />
My next step is to get my web based python stuff set up using docker, to make it even easier to shift around as required. This <a href="http://prakhar.me/docker-curriculum/">docker for beginners guide</a> is my current reading.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp5vEAOYQuFswZbpqIPBYaSnZgjUEVwhqEm1bet3X-U1TrLYy6iLY-kZhK9-53mtVnC2Jb6AbjewKake9jhMQ9LyOTIZA-7aUMtf0RHXf0NlvItNarefjVuIQMDH59GAr2fcRCCtE3H9u1/s1600/i_know_kung-fu.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp5vEAOYQuFswZbpqIPBYaSnZgjUEVwhqEm1bet3X-U1TrLYy6iLY-kZhK9-53mtVnC2Jb6AbjewKake9jhMQ9LyOTIZA-7aUMtf0RHXf0NlvItNarefjVuIQMDH59GAr2fcRCCtE3H9u1/s1600/i_know_kung-fu.gif" /></a></div>fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-44725729814210315332015-11-09T14:09:00.000-08:002015-11-18T20:12:48.197-08:00Digital Signage<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRvUGFgXsqouDbMpyesLUUH1JBaS3bofEzG2lZC2F6bzeWQkmNVzSbXRWDY6AXNMAPvnVYKX8J7CbINO3ghJZ-5U9UrHJJI5mPfK-dttqeMb2BEisoCl9VGGWU9VWlQDhWHbe_axBnVTS_/s1600/mk802.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRvUGFgXsqouDbMpyesLUUH1JBaS3bofEzG2lZC2F6bzeWQkmNVzSbXRWDY6AXNMAPvnVYKX8J7CbINO3ghJZ-5U9UrHJJI5mPfK-dttqeMb2BEisoCl9VGGWU9VWlQDhWHbe_axBnVTS_/s320/mk802.jpg" /></a></div><br />
After sitting unused for quite some time I found a task which my <a href="https://en.wikipedia.org/wiki/Android_Mini_PC_MK802">MK802 "PC on a stick"</a> would be perfectly suited to. As part of my day job I've been asked to set up a TV as a Digital Signage display. It is a vertically mounted Panasonic Viera which has its own "smart TV" features, along with this the company had purchased a <a href="http://www.cloudmedia.com/products/digital-signage/popcorn-hour-s-300">Popcorn Hour S-300</a>. Unfortunately this came with a European power plug and not enough room behind the TV to fit it and a plug converter.<br />
<br />
So in steps the MK802; there is a powered USB port in the TV which gives 5v, more than enough to power the MK802.<br />
<br />
I've installed Lubuntu onto it and worked out how to rotate the frame buffer display (thanks to <a href="http://tahnok.blogspot.com.au/2012/08/screen-rotation-for-ubuntu-on-mk802.html">this bit of info</a>):<br />
<br />
<b>/usr/share/X11/xorg.conf.d/01-device.conf</b><br />
<br />
<script src="https://gist.github.com/Fuzzwah/bbf38f453e3ebafe4ac1.js"></script><br />
<br />
I have a <a href="https://github.com/evolvedlight/pydashie">PyDashie</a> system rigged up as the dashboard which is displayed in a Chromium browser window that is automatically launched on login. The browser is launched in kiosk mode so that it is completely fullscreen.<br />
<br />
My <b>/etc/lightdm/lightdm.conf</b> has the following in it:<br />
<br />
<script src="https://gist.github.com/Fuzzwah/d3c3dbab17d3733cc1e2.js"></script><br />
<br />
This automatically logs in the user on boot and hides the mouse cursor.<br />
<br />
I also removed all screensavers and power management.<br />
<br />
The system connects to the network via wifi and occasionally its IP address will change. I rigged up a system where a notification will be sent to my phone using the Notify My Android app. To get the message sent out from the digital signage host I installed the nma-python package (pip install nma-python) and then have a cron task that executes the following bash script every 15 minutes:<br />
<br />
<script src="https://gist.github.com/Fuzzwah/0b8733affd490984626c.js"></script><br />
<br />
Here's a screenshot of the webpage displayed:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-HYuC_WEs6nqvnTcWqb0_1tTta5LJPGZO7w40BBe7kQoiJwMkC8Ypz5bgzPD8M1G7teNY2U6FmicvJyrK-NMMC28WAoO_MQr91_48AR2CHQPOLYcKxjhqNTecJmWuuB8WDlEmJgcHfhpM/s1600/digital_signage.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-HYuC_WEs6nqvnTcWqb0_1tTta5LJPGZO7w40BBe7kQoiJwMkC8Ypz5bgzPD8M1G7teNY2U6FmicvJyrK-NMMC28WAoO_MQr91_48AR2CHQPOLYcKxjhqNTecJmWuuB8WDlEmJgcHfhpM/s400/digital_signage.png" /></a></div><br />
And a photo of the setup on the wall:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTRMjv4Zmm4F1-3-z5KvVRKqjmZqUazh-rI-tqFeX4n_7_lq31s3xSzAbSm_nQ1xu8oY6bjl7-avMqmzsVleZCEXSdK7lFal46wAjYidj2iRiZ5a4rNZXpmorlAK2rnC2kRWQyiqNHrqql/s1600/digital_signage_photo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTRMjv4Zmm4F1-3-z5KvVRKqjmZqUazh-rI-tqFeX4n_7_lq31s3xSzAbSm_nQ1xu8oY6bjl7-avMqmzsVleZCEXSdK7lFal46wAjYidj2iRiZ5a4rNZXpmorlAK2rnC2kRWQyiqNHrqql/s400/digital_signage_photo.jpg" /></a></div>fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com35tag:blogger.com,1999:blog-2843354796009916212.post-18619069384940524512015-07-25T22:51:00.002-07:002015-07-25T22:51:47.026-07:00Fantasy Formula 1I'm a huge fan of Formula 1 racing.<br />
<br />
For the past few seasons myself and my other F1 loving friends have taken part in F1 Fantasy Leagues. The problem is that they've come and gone and each seemed to have a variety of issues; generally around the scoring or transfer systems.<br />
<br />
During the current 2015 season I decided that I wanted to take a stab at creating a system to use for next years season. A personal project with a deadline! Oh my.<br />
<br />
The objective is to create a system which the players have to balance two goals:<br />
<br />
1) increase their teams bankroll<br />
2) have their selected drivers earn as many championship points as possible<br />
<br />
To explain the bankroll idea; at the start of the season each player will be given X millions of in-game dollars. Up until qualifying of each race weekend players are able to select the two drivers who will make up their team for the weekend. After the race the value of each driver is re-evaluated based on their performance in qualifying and the race (with qualifying result having a lesser weight).<br />
<br />
The resulting value of the player's selected drivers (in addition to any left over money from their bankroll) becomes the player's new bankroll going into the next race weekend.<br />
<br />
Secondary to simply trying to predict which drivers are currently under valued the players will need to be selecting drivers who will be scoring points in the Formula 1 drivers championship.<br />
<br />
It will be the combination of these two goals which the players will need to balance. Do you select drivers who you think have the best chance of gaining in value, even though they may not be winning big championship points? <br />
<br />
I've already made progress on the system I'll use to collect results and the logic behind updating driver values.<br />
<br />
Here's an example (the change column displays the change in driver value from the most recent round at Silverstone):<br />
<br />
<table width='400px'><tr> <th>Driver</th> <th>TLA</th> <th>#</th> <th>Initial</th> <th>Current</th> <th>Change</th> </tr>
<tr> <td>Lewis Hamilton</td> <td>HAM</td> <td>44</td> <td>50.00</td> <td>48.04</td> <td>0.29</td> </tr>
<tr> <td>Nico Rosberg</td> <td>ROS</td> <td>6</td> <td>48.00</td> <td>44.85</td> <td>-0.23</td> </tr>
<tr> <td>Sebastian Vettel</td> <td>VET</td> <td>5</td> <td>40.00</td> <td>34.69</td> <td>-0.94</td> </tr>
<tr> <td>Kimi Räikkönen</td> <td>RAI</td> <td>7</td> <td>35.00</td> <td>26.84</td> <td>-0.79</td> </tr>
<tr> <td>Valtteri Bottas</td> <td>BOT</td> <td>77</td> <td>31.00</td> <td>26.41</td> <td>0.08</td> </tr>
<tr> <td>Felipe Massa</td> <td>MAS</td> <td>19</td> <td>30.00</td> <td>24.79</td> <td>0.74</td> </tr>
<tr> <td>Daniel Ricciardo</td> <td>RIC</td> <td>3</td> <td>25.00</td> <td>20.49</td> <td>-0.24</td> </tr>
<tr> <td>Romain Grosjean</td> <td>GRO</td> <td>8</td> <td>24.00</td> <td>19.27</td> <td>-0.27</td> </tr>
<tr> <td>Daniil Kvyat</td> <td>KVY</td> <td>26</td> <td>15.00</td> <td>18.55</td> <td>0.49</td> </tr>
<tr> <td>Pastor Maldonado</td> <td>MAL</td> <td>13</td> <td>20.00</td> <td>16.87</td> <td>-0.26</td> </tr>
<tr> <td>Carlos Sainz</td> <td>SAI</td> <td>55</td> <td>16.00</td> <td>16.47</td> <td>0.26</td> </tr>
<tr> <td>Max Verstappen</td> <td>VES</td> <td>33</td> <td>15.00</td> <td>16.05</td> <td>-0.07</td> </tr>
<tr> <td>Felipe Nasr</td> <td>NAS</td> <td>12</td> <td>15.00</td> <td>14.66</td> <td>-0.23</td> </tr>
<tr> <td>Nico Hulkenberg</td> <td>HUL</td> <td>27</td> <td>2.50</td> <td>14.07</td> <td>0.80</td> </tr>
<tr> <td>Sergio Perez</td> <td>PER</td> <td>11</td> <td>2.50</td> <td>13.14</td> <td>0.39</td> </tr>
<tr> <td>Marcus Ericsson</td> <td>ERI</td> <td>9</td> <td>13.00</td> <td>12.89</td> <td>-0.27</td> </tr>
<tr> <td>Fernando Alonso</td> <td>ALO</td> <td>14</td> <td>3.50</td> <td>10.31</td> <td>0.08</td> </tr>
<tr> <td>Jenson Button</td> <td>BUT</td> <td>22</td> <td>3.00</td> <td>8.22</td> <td>-0.16</td> </tr>
<tr> <td>Kevin Magnussen</td> <td>MAG</td> <td>20</td> <td>3.00</td> <td>2.03</td> <td>0</td> </tr>
<tr> <td>Will Stevens</td> <td>STE</td> <td>28</td> <td>1.00</td> <td>1.12</td> <td>-0.15</td> </tr>
<tr> <td>Roberto Merhi</td> <td>MER</td> <td>98</td> <td>1.00</td> <td>0.62</td> <td>0.03</td> </tr>
</table><br />
I'm still tweaking the value logic, as it appears that it is rewarding the lower drivers too much and punishing the higher drivers too hard. I'm already exempting drivers from having their value adjusted after a DNF.<br />
<br />
With the basics of the backend up and running my initial instinct was to put together a simple php based web front end for the users to manage their teams and display the results. However it dawned on me that this is the perfect opportunity to mess around with Flask; a python based web framework. I've had this on my radar for a while now and it seemed silly to switch languages between front and backend, when I'm sure at some stage there will be code cross over.<br />
<br />
My progress on this front has been pretty rapid. I've set up a dev environment;<br />
<br />
<li>An Ubuntu 14.04 server running in a VirtualBox VM<br />
<li>Postgres for the DB<br />
<li>I used <a href="https://github.com/dpgaspar/Flask-AppBuilder">Flask-Appbuilder</a> to kickstart everything, very impressed<br />
<li>I've then built a setup.py which allowed me to get all the python modules required by the backend installed<br />
<br />
Next up I'll get the backend running in this environment. I plan on hacking together a script which will take information from <a href="https://www.f1calendar.com/">f1calendar.com</a> to build a schedule of cron jobs so the system will automatically collect the results after each race weekend. This weekend's Hungarian GP will be a great test of this.<br />
<br />
Once I've got some data in my dev environment database I'll then work on setting up views to display the results of each round and the changes in values of the drivers.<br />
<br />
After that it'll be done to working on the system the users will use to select drivers for each round. My idea is to allow users to make changes to their teams before every round (obviously limited by their current team bankroll). Then it'll be a matter of balancing how much each player has as an opening bankroll.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-54476181965473785432015-02-16T11:30:00.000-08:002015-02-16T11:30:20.017-08:00Swipe Card JukeboxI think I've finally come up with a decent name for one of the projects I've tinkered with for a long time now. Previous I'd referred to it as RFID Music, but that doesn't help explain it to anyone who isn't a geek. Even if you know what RFID is then the you may be left pondering if you're swiping cards to actually make music.... a card for each note?
<p>Swipe Card Jukebox does a better job.
<p>I won't be renaming the github repo which is home to the underlying code, since I just see that mplayer-web-rfid-control is a fair explanation of what is going on under the covers.
<p>I have been able to get my Swipe Card Jukebox set up as a stand alone system (which no longer relies on XBMC / Kodi). I'm able to trigger playback of music via either swiping an RFID card or via the system's website. My next bit of work will be in converting the old flat file database of card associations over to the new SQLite based database, as I don't really want to have to go through the steps of manually assigning the cards from scratch again.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com1tag:blogger.com,1999:blog-2843354796009916212.post-78363606293426336312015-02-12T10:35:00.001-08:002015-02-12T10:35:21.776-08:00R-Pi 2 Media PlayerMy Raspberry Pi 2 model B arrived and I've got OSMC Alpha 4 installed on a micro SD card. I was very impressed by the installation process, their installer is very slick. I didn't have any time to tinker with anything beyond getting it booted for the first time.
<p>Here's my todo list:
<p><li>switch to the default kodi skin; confluence (eases the change from XBian to OSMC)
<li>I couldn't connect via ssh when I tried, I suspect the wifi device hasn't been detected
<li>get the remote control working
<li>plug the external drives which contain all our media into it
<li>export the library from the old XBian setup (including watched status)
<li>import library into OSMC setup
<li>install and configure transmission
<li>install and configure sickbeard
<li>install and configure samba, so I can access the media files from my PC
<p>Once I've switched us over to using this new OSMC system on the R-Pi 2 I can redeploy the old R-Pi as the base of my refactored RFID music triggering system. I've got a pair of speakers, another wifi dongle and external drive all ready to get that up and running. More on that as I get to it.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-91306761959497301572015-02-06T13:03:00.003-08:002015-02-06T13:04:19.703-08:00Raspberry Pi 2I've placed an order for a <a href="http://www.raspberrypi.org/raspberry-pi-2-on-sale/">Raspberry Pi 2</a>. Alas I didn't get in quick enough when they were first announced and I'm now waiting on a back order being filled. It'll probably arrive in my hot little hands in 2 to 3 weeks. The wait isn't going to kill me, due to what I'm planning on using it for.
<p>I'll be using it to replace the current first gen R-Pi I've been using as a media player, running <a href="http://xbian.org">XBian</a>. I've been pretty happy with the performance of it; as I was able to use xbmc, sickbeard and transmission on it and have 3 external USB drives connected via USB hub. But lately we've noticed that it can get a little slow to respond and update the file listings in menus.
<p>I'm looking towards switching the system over to use <a href="https://osmc.tv">OSMC</a> rather than XBian, they already have a build specifically for the R-Pi 2 and I like the approach they're taking. I suspect it'll be nice and speedy.
<p>This will then free up the old R-Pi to take on the work of being the guts of my revamped RFID Music setup.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-22267733833721551032014-12-04T14:35:00.002-08:002014-12-04T14:36:30.469-08:00Juggle MusicI've made some progress with my Juggle Music project, there is a <a href="https://github.com/Fuzzwah/juggle-music">public repo over on github</a> where I'm managing the code.
<p>After more research I decided to skip <a href="http://simplecv.org">SimpleCV</a> and just dive directly into learning <a href="http://opencv.org/">OpenCV</a>.
<p>I made this call due to the lessons I learned while coming to grips with developing the GUI for my python powered iRacing Stats project. Initially I used <a href="https://code.google.com/p/gui2py/">GUI2Py</a> which wraps around the <a href="http://www.wxpython.org/">WXPython</a> library, because WX looked very scary to begin with. As I progressed and my GUI became more complex I started hitting issues with GUI2Py and rather than hack on it to get it to interface how I wanted with WX I realized I was better off just doing it all in WX directly.
<p>I've got the basics of the object tracking completed. It is color based and works nice and simply. You fire up the app and it prompts you to select the 3 colored objects. I do this rather than hard coding the color ranges because this method handles different lighting conditions and allows me to change props.
<p>For the music playback I'm using the <a href="https://code.google.com/p/mingus/">Mingus</a> library along with <a href="http://www.fluidsynth.org/">Fluidsynth</a>. I've got a lot of learning to do on this side of things, my knowledge of all things midi is very basic at this stage. Currently I've got it rigged up to simply playback notes based on how high the objects are thrown. At this stage it really is just a proof of concept.
<p>I'll be working on configuring the "juggle space"; working out how many segments I can cut the webcam image up into so I'm able to accurately trigger samples. I can also see that drawing these segments on the output window would be helpful.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-47391033288426040652014-12-01T10:13:00.000-08:002014-12-04T14:36:30.472-08:00SimpleCV Object TrackingI've had an "on-again off-again" project kicking around for a long time which I want to dive back into and dedicate some more time and effort into.
<p>The idea is simple enough; I want to be able to trigger the playback of music and samples by juggling.
<p>The best method I've come up with is using a webcam and some computer vision code. Since my skills in python have been progressing quite well I feel that I can finally produce something solid based on the <a href="http://simplecv.org/">SimpleCV library</a>.
<p>Here's a few projects which I can learn from:
<p><li><a href="https://gist.github.com/xamox/2438871">Object Tracking with SimpleCV (White Ball)</a>
<li><a href="https://github.com/Nagasaki45/cards-tracker/blob/master/track.py">Track cards using python and SimpleCV</a>fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-83577291020636510292014-11-27T07:30:00.003-08:002014-11-27T07:36:51.127-08:00Python KnowledgeI learned a few things from an article linked to on HackerNews: <a href="http://prooffreaderplus.blogspot.com/2014/11/top-10-python-idioms-i-wished-id.html">Top 10 Python idioms I wish I'd learned earlier</a>
<p>There was also a lot of great information in the <a href="https://news.ycombinator.com/item?id=8665820">comments thread for the post</a>. This included a link to the youtube video below:
<p><iframe width="720" height="540" src="//www.youtube.com/embed/OSGv2VnC0go" frameborder="0" allowfullscreen></iframe>fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-1725571718652598962014-11-25T12:06:00.000-08:002014-11-25T12:17:53.128-08:00Google API'sI've been exporting info from my iRacing Stats application to html to do weekly and end of season updates on my iRacing blog. This process had been fairly manual; I'd manually upload the graph images to blogger, create a new blog post and paste in the exported html and edit the img tags to point to the uploaded images. Its not that it was too painful, but since it was a repetitive task I wanted to see if I could automate it.
<p>So I dived into the <a href="https://developers.google.com/api-client-library/python/apis/">Google API doco</a> and pretty quickly worked out how to get my python application to post a new blog update. Getting the images uploaded was more painful, since blogger actually uses picasa to store images and the picasa API is terrible. I ended up using Google Drive to store the images, which means I needed to handle a few more steps than just uploading; namely changing the permissions to public viewing, uploading to a folder and retrieving the public url.
<p>I've got it all working now, including prompting the user for only their blog's URL from which it app pulls the BlogID (rather than having to have the user go off and find it). All in all I'm quite proud of getting it all working. I just hope Google don't go changing their APIs in the near future.
<p>I'm sure the knowledge I've gained here will be useful in many other projects.
<p>Here's a bunch of links which I found helpful:
<p><li><a href="http://wescpy.blogspot.com/2014_11_01_archive.html">Authorized Google API access from Python</a>
<li><a href="https://github.com/google/google-api-python-client">google-api-python-client</a>
<li><a href="https://github.com/google/oauth2client">oauth2client</a>
<p>Here's a bit of code:
<p><pre class="brush: python">
from oauth2client import file, client, tools
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from httplib2 import Http
def blogger_post(outfile):
try:
html_file = open(outfile)
html_lines = html_file.read()
chop_start = html_lines.find('<body>')
chop_end = html_lines.find('</body>')
html_lines = html_lines[chop_start+6:chop_end]
CLIENT_SECRET = 'client_secrets.json'
SCOPE = 'https://www.googleapis.com/auth/blogger'
store = file.Storage('storage_blogger.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET, SCOPE)
creds = tools.run(flow, store)
service = build('blogger', 'v3', creds.authorize(Http()))
body = {
"kind": "blogger#post",
"id": cfg.config['Blogger']['blogid'],
"title": os.path.basename(os.path.splitext(outfile)[0]),
"content":html_lines
}
request = service.posts().insert(blogId=cfg.config['Blogger']['blogid'], isDraft=True, body=body)
response = request.execute()
return response['url']
except:
return "Failed"
def blogger_img_upload(filename):
try:
CLIENT_SECRET = 'client_secrets.json'
SCOPE = ('https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.file')
store = file.Storage('storage_drive.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET, SCOPE)
creds = tools.run(flow, store)
service = build('drive', 'v2', creds.authorize(Http()))
q = "title = 'iRacing Stats Graphs' and mimeType = 'application/vnd.google-apps.folder'"
request = service.files().list(q=q)
response = request.execute()
if len(response['items']) == 0:
body = {
"title": "iRacing Stats Graphs",
"mimeType": "application/vnd.google-apps.folder"
}
request = service.files().insert(body=body)
response = request.execute()
folderId = response['id']
else:
folderId = response['items'][0]['id']
pub.sendMessage('Uploading', graph=os.path.basename(os.path.splitext(filename)[0]))
body = {
"title": os.path.basename(os.path.splitext(filename)[0]),
}
body['parents'] = [{'id': folderId}]
media_body = MediaFileUpload(filename)
request = service.files().insert(body=body, media_body=media_body)
response = request.execute()
fileId = response['id']
body = {
"type": "anyone",
"role": "reader"
}
response = service.permissions().insert(fileId=fileId, body=body).execute()
response = service.files().get(fileId=fileId).execute()
return response['webContentLink'].split('&')[0]
except:
print("Upload of %s to blogger failed" % os.path.basename(os.path.splitext(filename)[0]))
return "Failed"
def blogger_config(url):
try:
CLIENT_SECRET = 'client_secrets.json'
SCOPE = 'https://www.googleapis.com/auth/blogger'
store = file.Storage('storage_blogger.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET, SCOPE)
creds = tools.run(flow, store)
service = build('blogger', 'v3', creds.authorize(Http()))
response = service.blogs().getByUrl(url=url).execute()
cfg.write_blogid(response['id'])
return True
except:
pub.sendMessage('Alert', msg="Unable to find BlogID of: %s" % url, title="Blogger Config Failed")
return False
</pre>fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0tag:blogger.com,1999:blog-2843354796009916212.post-31741268429122793012014-11-24T11:21:00.000-08:002014-11-24T11:21:02.251-08:00PhotoFrame PC UpdateThe <a href="http://fuzzwah.github.io/photoframe.html">Digital PhotoFrame PC</a> located in my kitchen sees near daily use; in the morning while I make coffee I trigger playback of the Australian Broadcasting Commision's 90 second news headlines and NPR's 5 minute news update. While I'm preparing dinner I'll often use it to stream jazz from KJZZ.org. Occasionally I'll use it to display a recipe to follow along with.
<p>All in all there isn't much reason that I'd want to change the setup, it currently functions exactly as I want. However, it is running Windows XP which is no longer support by Microsoft. I don't like the idea of having an unsecurable machine running on the network so I've started planning on switching it to run Lubuntu Linux.
<p>Obviously this would require that I recreate all the AutoIT scripts which currently trigger all of the above things. I'm very confident that I could easily do this via Python based scripts. I've also started looking for one to one replacements for the handful of other features I make use of:
<p><li><a href="http://peterlevi.com/variety/">Variety</a> to handle background image display and rotation.
<li>Conky or LXDE screenlet for weather and clock.fuzzwahhttp://www.blogger.com/profile/16034759673853676267noreply@blogger.com0