I did it again. This time, the bundle was a games bundle (The Humble Bundle for Android 4), which is Humble's normal fare. Also this time, I was able to collect data from the very beginning. There was a period of 7 hours where my server got turned off and no data was collected, but that time slot was in the middle of the data collection with no major events occurring near it. I patched it up with a little bit of linear interpolation. It shows up on the Marginal Average Price as a plateau, but is otherwise unremarkable.
One thing about this graph that I was not able to capture last time is that the average price was actually highest at the beginning, before sinking to a low, and then slowly rising. The "event" in the middle is when games from the previous Android bundle were added as an additional bonus. Interestingly, I was able to purchase at the point of lowest average price though I did beat it by making my purchase price a nice round number, thereby contributing to the bounce-back of the average price from its initial fall.
The initial fall is probably due to a bunch of people paying $0, or $1 immediately just to get the basic games and/or Steam keys.
The ramp-up of initial purchases is quite high, as you can see.
In this case at least, the initial "bump" was much more significant than the subsequent "blip" produced by adding more bonus content. A lot of people already have the previous bundle games, so this is somewhat expected.
Here again is the raw data, for those who might be interested:
Because some people simply can't handle the true scope of my geekiness.
Showing posts with label script. Show all posts
Showing posts with label script. Show all posts
Wednesday, November 28, 2012
Thursday, November 01, 2012
Humble Bundle Data - Results
In my previous post, I said I was going to finish collecting data for the rest of the Humble eBook Bundle at humblebundle.com and post the results here.
The results are in. This was probably the most successful Humble Bundle to date, based on the ending average price. Let's look at the data for the Average Price over Time.
You may notice that bump in the middle of the graph. That is the point in time when several PDF comic books were added to the Humble eBook Bundle. This had the effect of pushing a lot of fence-sitters over the edge to purchase the bundle, as well as increase the margin by which purchasers were willing to "beat" the average price.
You may notice that the Total Purchases graph has some missing data at the beginning. This is because initially I only collected the Average Price (and I was over an hour late in starting that collection). The bundle started at 10:00 AM PDT; I started recording the average price at 11:30 AM, and I started collecting the total number of purchases at 5:30 PM.
With those two numbers, I was able to calculate the total revenue collected. Later, I added direct collection of this figure.
As you can see from the graph. At no point did the average price go down much at all (there were a few times it went down a penny or two). This answers the question I was initially asking, at least for this bundle: should I wait for a lower price? The answer is of course emphatically no. If I was going to beat the average price, the time to do it was as early as possible.
I do seem to recall bundle average prices going down in past bundles, but this may have been due to abuse by people pumping the system for free and/or very cheap Steam keys. That practice seems to have been cracked down upon with CAPTCHAs (remember: only use your scripting powers for good), and the momentum of the price and interest in the bundle seems to have been maintained by the addition of the bonus content. I would expect similar measures in the future.
As it turned out, I when the extra bonus content was added, it was also added to the account of everyone who had previously purchased the bundle, whether they beat the average or not, so I ended up with all but the initial two bonus books.
These marginal rates were all calculated from the previous values. It would be interesting to have better data at the beginning of the data set. I'm curious to know how the profile of the initial wave compares to the second bump. You can't really tell with the first seven hours missing, unfortunately. My suspicion is that the secondary bump was sharper than the initial wave, mostly because I believe that the secondary wave was largely fence-sitters who had not bought because they thought the price was too high for the content offered. When more content was offered (and considering the content), they immediately jumped on it.
It should be noted that the website data is far from perfect. The totals sometimes went down from one reading to the next, and after the bundle had ended, the numbers were still in flux for several hours, but at the scale of these graphs, the fluctuations are insignificant.
If you would like to look at my raw data, I will provide it for download in its unprocessed CSV format generated by my script, as well as the Excel spreadsheet that I used to calculate the missing values and create these fancy graphs.
Here is the data:
Here is the final form of the script I used to create this data:
Enjoy!
The results are in. This was probably the most successful Humble Bundle to date, based on the ending average price. Let's look at the data for the Average Price over Time.
![]() |
| Average Price over Time |
![]() |
| Total Purchases over Time |
![]() |
| Total Revenue over Time |
As you can see from the graph. At no point did the average price go down much at all (there were a few times it went down a penny or two). This answers the question I was initially asking, at least for this bundle: should I wait for a lower price? The answer is of course emphatically no. If I was going to beat the average price, the time to do it was as early as possible.
I do seem to recall bundle average prices going down in past bundles, but this may have been due to abuse by people pumping the system for free and/or very cheap Steam keys. That practice seems to have been cracked down upon with CAPTCHAs (remember: only use your scripting powers for good), and the momentum of the price and interest in the bundle seems to have been maintained by the addition of the bonus content. I would expect similar measures in the future.
As it turned out, I when the extra bonus content was added, it was also added to the account of everyone who had previously purchased the bundle, whether they beat the average or not, so I ended up with all but the initial two bonus books.
These marginal rates were all calculated from the previous values. It would be interesting to have better data at the beginning of the data set. I'm curious to know how the profile of the initial wave compares to the second bump. You can't really tell with the first seven hours missing, unfortunately. My suspicion is that the secondary bump was sharper than the initial wave, mostly because I believe that the secondary wave was largely fence-sitters who had not bought because they thought the price was too high for the content offered. When more content was offered (and considering the content), they immediately jumped on it.
![]() |
| Marginal Purchases (every 15 minutes) |
![]() |
| Marginal Revenue (every 15 minutes) |
![]() |
| Marginal Average Price (every 15 minutes) |
If you would like to look at my raw data, I will provide it for download in its unprocessed CSV format generated by my script, as well as the Excel spreadsheet that I used to calculate the missing values and create these fancy graphs.
Here is the data:
Here is the final form of the script I used to create this data:
Enjoy!
Wednesday, October 10, 2012
Humble Bundle Data - Collection
Today was the launch of the Humble eBook Bundle. The way that Humble Bundles work is that the site lists a collection of downloadable items (traditionally games, but lately they have branched out into music, and now books). You can pay any price (including free, if you choose) for the bundle, and it's yours. You can even tweak how much of your purchase price goes (directly) to the content creators, the Humble Bundle site, and a few charities.
Well, not all of the bundle is yours at any price. There are bonus items, which are typically the best of the bunch. To get these items, you are required to beat the average price of the bundle so far.
Well, I like bundles, and I like e-books, so I decided to get the bundle. But I wasn't prepared to pay the price at the time to get the two bonus books. They looked good, but the average price was then just over $9, and I thought that if I was going to spend that much money on an e-book, did I really want the ones offered? I would be willing to bite--but only if the price went down. Humble Bundles typically hover around the $5-7 range for unlocking the bonus content, which for my money is a better impulse purchase for content I didn't get to pick out myself.
Funny thing about having to beat the average price: a lot of people do it, and that will have a tendency to create a constant upward trend in the price to unlock the bonus content. It got me wondering, though. I fully expected the price to trend up for the first couple of days, but then does it dip down again? My gut told me that there would be an initial spike, a dip, and then a spike at the end of the two-week window when the bundle was offered.
But I couldn't find any data on the subject. There are several websites where data on the various Humble Bundles can be found, but a graph of average price over time was nowhere to be found. "Well," I thought, "I'll make one then."
So I did. Or rather, am.
I whipped up a quick script on my Linux box that uses links -dump to grab a text-only version of the web page. It then successively greps this page for the data I'm after, and appends a line of data to a CSV file. Initially, I only collected the timestamp and average price, but I decided that the total quantity sold at that time would also be a valuable and relevant piece of data.
I added a line in my crontab file to run the script every 15 mninutes (which is plenty of granularity over two weeks, and also very reasonable to the remote server), and viola: data!
It will be interesting to see how this little experiment turns out. It may be that the price will almost always trend upward. I know that with certain past gaming bundles, games from previous bundles were added to the current bundle as bonus items in order to motivate people to pay the higher price and keep the average up. I suspect that these items were added at times when the average price was dipping in order to bring it back up. I don't know that there are any books in reserve for this bundle, so that may not be an option.
If it does happen, that will be interesting to watch in the data.
Side note:
I will post an update to this blog when the bundle is over with the full results of the data I collect.
Well, not all of the bundle is yours at any price. There are bonus items, which are typically the best of the bunch. To get these items, you are required to beat the average price of the bundle so far.
Well, I like bundles, and I like e-books, so I decided to get the bundle. But I wasn't prepared to pay the price at the time to get the two bonus books. They looked good, but the average price was then just over $9, and I thought that if I was going to spend that much money on an e-book, did I really want the ones offered? I would be willing to bite--but only if the price went down. Humble Bundles typically hover around the $5-7 range for unlocking the bonus content, which for my money is a better impulse purchase for content I didn't get to pick out myself.
Funny thing about having to beat the average price: a lot of people do it, and that will have a tendency to create a constant upward trend in the price to unlock the bonus content. It got me wondering, though. I fully expected the price to trend up for the first couple of days, but then does it dip down again? My gut told me that there would be an initial spike, a dip, and then a spike at the end of the two-week window when the bundle was offered.
But I couldn't find any data on the subject. There are several websites where data on the various Humble Bundles can be found, but a graph of average price over time was nowhere to be found. "Well," I thought, "I'll make one then."
So I did. Or rather, am.
![]() |
| My data collected at the end of day 1, showing average price and total purchases over time. |
I added a line in my crontab file to run the script every 15 mninutes (which is plenty of granularity over two weeks, and also very reasonable to the remote server), and viola: data!
It will be interesting to see how this little experiment turns out. It may be that the price will almost always trend upward. I know that with certain past gaming bundles, games from previous bundles were added to the current bundle as bonus items in order to motivate people to pay the higher price and keep the average up. I suspect that these items were added at times when the average price was dipping in order to bring it back up. I don't know that there are any books in reserve for this bundle, so that may not be an option.
If it does happen, that will be interesting to watch in the data.
Side note:
- Another bundle site of note that just got started specifically for e-books is StoryBundle. StoryBundle is slightly different, in that they set a minimum price ($1), and the bonus books can be unlocked at a constant price ($7).
I will post an update to this blog when the bundle is over with the full results of the data I collect.
Update: Here are the results.
Enjoy!
Wednesday, December 08, 2010
Twitpic-to-Posterous Script: Another Update
A while ago I wrote a script to import my Twitpic photo posts to Posterous and posted it on this blog.
Even though Posterous now supplies their own working transfer tool, it has its limitations. One person who tried that tool was unsatisfied, and tried my script. He really liked the results, but he noticed some drawbacks to my script as well. Here's what's new in my script v1.3.1:
Even though Posterous now supplies their own working transfer tool, it has its limitations. One person who tried that tool was unsatisfied, and tried my script. He really liked the results, but he noticed some drawbacks to my script as well. Here's what's new in my script v1.3.1:
- New feature by request - #hashtags and @username mentions are now linked to the appropriate Twitter page in the body of the Posterous post.
- Fix - issue where Twitpic now truncates the tweet text in the HTML title. Switched to using the image alt text from the full page.
- Fix - Twitpic started escaping single and double quotes in the tweet text, which were showing up uninterpreted in the Posterous titles. The script now handles them correctly.
- Other changes
- Only download the Full images by default (Scaled and thumbnails can be enabled by setting flags.)
- Print an error message and pause for 5 seconds if a download fails (Twitpic was being unreliable during my testing.)
- Other miscellaneous fixes and tweaks
- Update (v1.3.2): better regular expressions for @username and #hashtag formats.
- Update (v1.3.4): now optionally adds hashtags as post tags.
Wednesday, December 01, 2010
Dropbox Sync Script
Recently, I started using Steam, and while Steam can install each of your games on each of your computers, it doesn't keep the game saves in sync. I wanted to be able to pick up where I had left off on any computer I wanted, not needing to worry about copying over save files, so I turned to Dropbox, which I've been using for a while.
I had created a set of batch scripts that I used on Windows to set up the sync folders, but since I was adding several folders, and the number of scripts was getting to be large, I decided to combine them all into a single flexible and streamlined script. I also decided to make it as generic as possible, so that other people could use it with minimal fuss. Basically the script has a function that moves files and folders located outside of the Dropbox folder inside, and then creates a symlink (or folder junction), so that the program accessing the files doesn't need to be reconfigured in order to keep accessing the files. If the item is already in the Dropbox folder, the original is kept under a different name, and a link is created to the existing synced content. If the item doesn't exist in either place, it gets created in Dropbox, and linked to in the specified location.
The script is populated with things that I want synced, which will probably be different from what you want to sync, but it should be a simple matter to change that. If you add items, the script is set up so that you can re-run it without creating more and more symlinks.
It's worth noting that the mklink command requires Windows Vista or later. If you're running an earlier version such as XP, it will use the linkd command, which comes with the Windows 2003 Resource Kit. (You don't need to be running 2003 to install it.)
So, without further ado, here is the script:
PS: If you use my code, I appreciate comments to let me know, and any feedback you may have, especially if it's not working right for you, but also just to say thanks.
For convenience, you can download this script from my server.
I had created a set of batch scripts that I used on Windows to set up the sync folders, but since I was adding several folders, and the number of scripts was getting to be large, I decided to combine them all into a single flexible and streamlined script. I also decided to make it as generic as possible, so that other people could use it with minimal fuss. Basically the script has a function that moves files and folders located outside of the Dropbox folder inside, and then creates a symlink (or folder junction), so that the program accessing the files doesn't need to be reconfigured in order to keep accessing the files. If the item is already in the Dropbox folder, the original is kept under a different name, and a link is created to the existing synced content. If the item doesn't exist in either place, it gets created in Dropbox, and linked to in the specified location.
The script is populated with things that I want synced, which will probably be different from what you want to sync, but it should be a simple matter to change that. If you add items, the script is set up so that you can re-run it without creating more and more symlinks.
It's worth noting that the mklink command requires Windows Vista or later. If you're running an earlier version such as XP, it will use the linkd command, which comes with the Windows 2003 Resource Kit. (You don't need to be running 2003 to install it.)
So, without further ado, here is the script:
@echo off
:: This script creates symlinks (NTFS junctions) in order to sync the contents via Dropbox
:: Some of these items require Administrator privileges to execute because of where the items are located.
:: Copyright 2010 Tim "burndive" of http://burndive.blogspot.com/ and http://tuxbox.blogspot.com/
:: This software is licensed under the Creative Commons GNU GPL version 2.0 or later.
:: License informattion: http://creativecommons.org/licenses/GPL/2.0/
:: This script was obtained from here:
:: http://tuxbox.blogspot.com/2010/12/dropbox-sync-script.html
:: Set this to your Steam user ID
set STEAM_USER=burndive
:: The path to your Documents folder
set DOCUMENTS=%USERPROFILE%\My Documents
if exist "%USERPROFILE%\Documents" (
set DROPBOX=%USERPROFILE%\Documents
)
:: The path to your Dropbox folder
set DROPBOX=%DOCUMENTS%\My Dropbox
if exist "%USERPROFILE%\Dropbox" (
set DROPBOX=%USERPROFILE%\Dropbox
)
:: Determine which command to use for making Folder Junctions
ver | findstr "5." > nul
if errorlevel 1 (
:: This requires Windows Vista or later
set JUNCTION_CMD=mklink /j
) else (
:: This requires the Windows 2003 Resource Kit Tools
set JUNCTION_CMD=linkd
)
:: Find the correct Flash SharedObjects folder name if localhost subfolder exists
set FLASH_LOCAL=
for /F "tokens=*" %%I in ('dir /b "%APPDATA%\Macromedia\Flash Player\#SharedObjects"') do (
if exist "%APPDATA%\Macromedia\Flash Player\#SharedObjects\%%I\localhost" (
set FLASH_LOCAL=%APPDATA%\Macromedia\Flash Player\#SharedObjects\%%I\localhost
)
)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The following items require only User privileges to execute
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Make localhost Flash Shared Objects dir architecture neutral
if not "%FLASH_LOCAL%" == "" (
if exist "%FLASH_LOCAL%\Program Files (x86)" (
call:LinkFolder "%FLASH_LOCAL%", "Program Files", "%FLASH_LOCAL%\Program Files (x86)"
)
)
:: Digital Blasphemy wallpapers
call:LinkFolder "%USERPROFILE%\Pictures\wallpaper", "db-fs", "%DROPBOX%\images\digital-blasphemy\db-fs"
call:LinkFolder "%USERPROFILE%\Pictures\wallpaper", "db-ws", "%DROPBOX%\images\digital-blasphemy\db-ws"
call:LinkFolder "%USERPROFILE%\Pictures\wallpaper", "db-preview", "%DROPBOX%\images\digital-blasphemy\db-preview"
:: Images
call:LinkFolder "%USERPROFILE%\Pictures", "images", "%DROPBOX%\images"
:: Pidgin Instant Messenger
call:LinkFolder "%APPDATA%\.purple", "icons", "%DROPBOX%\app-files\pidgin\icons"
call:LinkFolder "%APPDATA%\.purple", "logs", "%DROPBOX%\app-files\pidgin\logs"
:: DVRMSToolbox Commercials XML files
call:LinkFolder "%PUBLIC%\DvrmsToolbox", "CommercialsXml", "%DROPBOX%\app-files\CommercialsXml"
::::::::::::::::::::::
:: Humble Bundle Games
::::::::::::::::::::::
:: Penumbra Overture
call:LinkFolder "%DOCUMENTS%\Penumbra Overture\Episode1", "save", "%DROPBOX%\app-files\game-saves\penumbra-overture"
:: Samarost2 : TODO
:: World of Goo
call:LinkFolder "%LOCALAPPDATA%\2DBoy", "WorldOfGoo", "%DROPBOX%\app-files\game-saves\world-of-goo"
:: Aquaria : TODO
:: Gish : TODO
:: Lugaru : TODO
::::::::::::::::::::::::
:: Humble Bundle 2 Games
::::::::::::::::::::::::
:: Braid
call:LinkFolder "%APPDATA%", "Braid", "%DROPBOX%\app-files\game-saves\braid"
:: Machinarium
if not "%FLASH_LOCAL%" == "" (
if exist "%FLASH_LOCAL%\Program Files" (
call:LinkFolder "%FLASH_LOCAL%\Program Files\Machinarium", "machinarium.exe", "%DROPBOX%\app-files\game-saves\machinarium"
)
)
:: Osmos
call:LinkFolder "%DOCUMENTS%", "Osmos", "%DROPBOX%\app-files\game-saves\osmos"
:: Cortex Command : TODO
:: Revenge of the Titans HIB
call:LinkFolder "%USERPROFILE%\Revenge of the Titans 1.71", "slots", "%DROPBOX%\app-files\game-saves\revenge-of-the-titans-1.71"
call:LinkFolder "%USERPROFILE%\Revenge of the Titans 1.72", "slots", "%DROPBOX%\app-files\game-saves\revenge-of-the-titans-1.72"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The following items require Administrator privileges to execute
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Eclipse workspace
call:LinkFolder "%USERPROFILE%", "workspace", "%DROPBOX%\app-files\workspace"
:: gVim config file
call:LinkFile "%USERPROFILE%", "_gvimrc", "%DROPBOX%\config\windows\_gvimrc"
:: Steam Game save folders
if exist "%PROGRAMFILES(X86)%" (
:: Note: The caret is an escape character
set STEAM_DIR=C:\Program Files ^(x86^)\Steam\steamapps
) else (
set STEAM_DIR=%PROGRAMFILES%\Steam\steamapps
)
call:LinkFolder "%STEAM_DIR%\%STEAM_USER%\half-life 2\hl2", "SAVE", "%DROPBOX%\app-files\game-saves\half-life-2-steam"
call:LinkFolder "%STEAM_DIR%\%STEAM_USER%\half-life 2 episode one\episodic", "SAVE", "%DROPBOX%\app-files\game-saves\half-life-2-ep1-steam"
call:LinkFolder "%STEAM_DIR%\%STEAM_USER%\half-life 2 episode two\ep2", "SAVE", "%DROPBOX%\app-files\game-saves\half-life-2-ep2-steam"
call:LinkFolder "%STEAM_DIR%\%STEAM_USER%\half-life 2 lostcoast\lostcoast", "SAVE", "%DROPBOX%\app-files\game-saves\half-life-2-lostcoast-steam"
call:LinkFolder "%STEAM_DIR%\%STEAM_USER%\portal\portal", "SAVE", "%DROPBOX%\app-files\game-saves\portal-steam"
:: Pause so the user can review output
pause
:: End of execution
goto:eof
::::::::::::
:: Functions
::::::::::::
:LinkFolder
setlocal
:: Arguments
set LINK_PATH=%~1
set LINK_NAME=%~2
set TARGET=%~3
::echo Link: %LINK_PATH%\%LINK_NAME%
::echo Target: %TARGET%
if not exist "%LINK_PATH%" (
mkdir "%LINK_PATH%"
)
cd "%LINK_PATH%"
:: If the folder is already a link, just delete it
dir | findstr /i "%LINK_NAME%" | findstr "<JUNCTION>" > NUL
if not errorlevel 1 (
rmdir "%LINK_NAME%"
)
if exist "%LINK_NAME%" (
if exist "%TARGET%" (
echo Backing up conflicting copy
move "%LINK_NAME%" "%LINK_NAME%-orig"
) else (
:: Move the original if target does not exist
echo Moving original folder to link location
echo move "%LINK_NAME%" "%TARGET%"
move "%LINK_NAME%" "%TARGET%"
)
) else (
if not exist "%TARGET%" (
:: If neither exist, create target
echo Creating target folder
mkdir "%TARGET%"
)
)
%JUNCTION_CMD% "%LINK_NAME%" "%TARGET%"
endlocal
goto:eof
:LinkFile
setlocal
:: Arguments
set LINK_PATH=%~1
set LINK_NAME=%~2
set TARGET=%~3
::echo Link: %LINK_PATH%\%LINK_NAME%
::echo Target: %TARGET%
if not exist "%LINK_PATH%" (
mkdir "%LINK_PATH%"
)
cd "%LINK_PATH%"
:: If the folder is already a link, just delete it
dir | findstr /i "%LINK_NAME%" | findstr "<SYMLINK>" > NUL
if not errorlevel 1 (
del "%LINK_NAME%"
)
if exist "%LINK_NAME%" (
if exist "%TARGET%" (
echo Backing up conflicting copy
move "%LINK_NAME%" "%LINK_NAME%-orig"
) else (
:: Move the original if target does not exist
echo Moving original file to target location
move "%LINK_NAME%" "%TARGET%"
)
) else (
if not exist "%TARGET%" (
:: If neither exist, create target
echo Creating empty target file
echo "" > "%TARGET%"
)
)
:: linkd will not work for files, only folders
mklink "%LINK_NAME%" "%TARGET%"
endlocal
goto:eof
This software is licensed under the CC-GNU GPL version 2.0 or later.
PS: If you use my code, I appreciate comments to let me know, and any feedback you may have, especially if it's not working right for you, but also just to say thanks.
For convenience, you can download this script from my server.
Friday, July 16, 2010
TwitPic to Posterous Export Script: Update
In the time since I wrote my script which downloads all of a user's TwitPic posts (text included) and uploads them as Posterous posts, Posterous has come out with their own import tool.
However, as noted in their blog post, TwitPic is currently blocking Posterous' servers, so someone came along and tried to use my script. It turned out that the TwitPic site had been updated, and my script no longer worked.
Well, I updated the script so that it works again. The script can be found here.
However, as noted in their blog post, TwitPic is currently blocking Posterous' servers, so someone came along and tried to use my script. It turned out that the TwitPic site had been updated, and my script no longer worked.
Well, I updated the script so that it works again. The script can be found here.
Wednesday, March 17, 2010
TwitPic to Posterous Export Script
Note: This post (and the script it contains) has been updated as of December 14, 2010. (v1.4.0) The script can also be downloaded from my server here.
Also, Posterous has done a lot of work on solving this problem since I wrote my script. You can see their latest solutions here.
Recently, I switched from TwitPic to Posterous as my method of posting phone pictures (and now video) to the Internet. But since I switched, I didn't want to have my data history split in two, so I decided to write a script to download each of my TwitPic images with their associated text and date, and upload them to Posterous with the same information.
Initially, I wanted to make one long post with all of the images, and their text below. However, with the Posterous API, it isn't possible to refer to a specific image in your body text, so individual posts is the way I went.
Along the way, I became familiar with yet another Linux command: curl.
I love that Posterous has an API that (once you figure out curl) is pretty easy to use. TwitPic, on the other hand, has absolutely zero support for exporting anything. The fact that they're so non-user-centric and out-dated was a driving force in my switching. The only reason I hadn't switched to img.ly already was because img.ly has a bug that prevents images sent from my phone from being posted, since my phone sends them without a file extension. I worked with their tech support for a while, but they didn't fix it. I got a new phone, but it was also a Samsung, and it did the same thing with images. Oh, well. Posterous is better.
Anyway, here is the script:
First run it with just the first two arguments, and it will download all of your TwitPic data, including thumbnail images. Once you're satisfied, supply your Posterous User ID, Password, and Site ID. (If you don't know your Site ID, run the script with your Posterous User ID, Password, and no Site ID, and it will query your Posterous site info as long as your Posterous credentials are valid.)
Note: if you want to run this from Windows, you should install Cygwin (with, at a mimum, curl and sed) and run it from there.
./twitpic-to-posterous.sh [twitpic-id] [working-dir] [postrous-id] [posterous-password] [posterous-site-id] [skip-number]
#!/bin/sh
# Copyright 2010 Tim "burndive" of http://burndive.blogspot.com/ and http://tuxbox.blogspot.com/
# This software is licensed under the Creative Commons GNU GPL version 2.0 or later.
# License informattion: http://creativecommons.org/licenses/GPL/2.0/
# This script was obtained from here:
# http://tuxbox.blogspot.com/2010/03/twitpic-to-posterous-export-script.html
RUN_DATE=`date +%F--%H-%m-%S`
SCRIPT_VERSION_STRING="v1.4.0"
TP_NAME=$1
WORKING_DIR=$2
P_ID=$3
P_PW=$4
P_SITE_ID=$5
UPLOAD_SKIP=$6
# Comma separated list of tags to apply to your posts
P_TAGS="twitpic"
# Whether or not to auto-post from Posterous
P_AUTOPOST=0
# Whether or not the Posterous posts are marked private
P_PRIVATE=0
# This is the default limit of the number of posts that can be uploaded per day
P_API_LIMIT=50
DOWNLOAD_FULL=1
DOWNLOAD_SCALED=0
DOWNLOAD_THUMB=0
PREFIX=twitpic-$TP_NAME
HTML_OUT=$PREFIX-all-$RUN_DATE.html
UPLOAD_OUT=posterous-upload-$P_SITE_ID-$RUN_DATE.xml
if [ -z "$TP_NAME" ]; then
echo "You must supply a TP_NAME."
exit
fi
if [ ! -d "$WORKING_DIR" ]; then
echo "You must supply a WORKING_DIR."
exit
fi
if [ -z "$UPLOAD_SKIP" ]; then
UPLOAD_SKIP=0
fi
UPLOAD_SKIP_DIGITS=`echo $UPLOAD_SKIP | sed -e 's/[^0-9]//g'`
if [ "$UPLOAD_SKIP" != "$UPLOAD_SKIP_DIGITS" ]; then
echo "Invalid UPLOAD_SKIP: $UPLOAD_SKIP"
exit
fi
cd $WORKING_DIR
if [ -f "$HTML_OUT" ]; then
rm -v $HTML_OUT
fi
# If Posterous username and password were supplied, but not site ID, query the server and exit.
P_SITE_INFO_FILE=posterous-$P_SITE_ID.out
if [ ! -z "$P_ID" ] && [ ! -z "$P_PW" ] && [ -z "$P_SITE_ID" ]; then
echo "Getting Posterous account info..."
curl -u "$P_ID:$P_PW" "http://posterous.com/api/getsites" -o $P_SITE_INFO_FILE
SITE_ID_RET=`grep "<id>$P_SITE_ID</id>" $P_SITE_INFO_FILE`
if [ -z "$SITE_ID_RET" ]; then
echo "Please supply your Posterous Site ID as the fifth argument."
echo "Here is the response from the Posterous server. If you entered correct credentials, you should see your Site ID(s):"
cat $P_SITE_INFO_FILE | tee -a $UPLOAD_OUT
exit
fi
fi
# Confirm that we have a valid Posterous Site ID
if [ ! -z "$P_SITE_ID" ]; then
echo "Getting Posterous account info..."
curl -u "$P_ID:$P_PW" "http://posterous.com/api/getsites" -o $P_SITE_INFO_FILE
SITE_ID_RET=`grep "<id>$P_SITE_ID</id>" $P_SITE_INFO_FILE`
if [ -z "$SITE_ID_RET" ]; then
echo "Make sure that you have supplied a valid Posterous Site ID as the fifth parameter. If you don't know your Site ID, leave it out, and this script will query the server."
echo "Here is the response from the Posterous server. If you entered correct credentials, you should see your site ID(s):"
cat $P_SITE_INFO_FILE | tee -a $UPLOAD_OUT
exit
fi
fi
MORE=1
PAGE=1
while [ $MORE -ne 0 ]; do
echo PAGE: $PAGE
FILENAME=$PREFIX-page-$PAGE.html
if [ ! -s $FILENAME ]; then
wget http://twitpic.com/photos/${TP_NAME}?page=$PAGE -O $FILENAME
if [ ! -s "$FILENAME" ]; then
echo "ERROR: could not get $FILENAME" | tee -a $LOG_FILE
sleep 5
fi
fi
if [ -z "`grep "More photos >" $FILENAME`" ]; then
MORE=0
else
PAGE=`expr $PAGE + 1`
fi
done
ALL_IDS=`cat $PREFIX-page-* | grep -Eo "<a href=\"/[a-zA-Z0-9]+\">" | grep -Eo "/[a-zA-Z0-9]+" | grep -Eo "[a-zA-Z0-9]+" | sort -r | xargs`
# For Testing
#ALL_IDS="1kdjc"
COUNT=0
LOG_FILE=$PREFIX-log-$RUN_DATE.txt
echo $ALL_IDS | tee -a $LOG_FILE
for ID in $ALL_IDS; do
COUNT=`expr $COUNT + 1`
echo $ID: $COUNT | tee -a $LOG_FILE
echo "Processing $ID..."
FULL_HTML=$PREFIX-$ID-full.html
if [ ! -s "$FULL_HTML" ]; then
wget http://twitpic.com/$ID/full -O $FULL_HTML
if [ ! -s "$FULL_HTML" ]; then
echo "ERROR: could not get FULL_HTML for $ID" | tee -a $LOG_FILE
sleep 5
fi
fi
TEXT=`grep "<img src=" $FULL_HTML | tail -n1 | grep -oE "alt=\"[^\"]*\"" | sed \
-e 's/^alt="//'\
-e 's/"$//'\
-e "s/'/'/g"\
-e 's/"/"/g'\
`
if [ "$TEXT" = "" ]; then
TEXT="Untitled"
fi
echo "TEXT: $TEXT" | tee -a $LOG_FILE
# Recognize hashtags and username references in the tweet
TEXT_RICH=`echo "$TEXT" | sed \
-e 's/\B\@\([0-9A-Za-z_]\+\)/\@<a href="http:\/\/twitter.com\/\1">\1<\/a>/g' \
-e 's/\#\([0-9A-Za-z_-]*[A-Za-z_-]\+[0-9A-Za-z_-]*\)/<a href="http:\/\/twitter.com\/search\?q\=%23\1">\#\1<\/a>/g' \
`
echo "TEXT_RICH: $TEXT_RICH" | tee -a $LOG_FILE
# Convert hashtags into post tags
P_TAGS_POST=$P_TAGS`echo "$TEXT" | sed \
-e 's/\#\([^A-Za-z_-]\)*\B//g' \
-e 's/^[^\#]*$//g' \
-e 's/[^\#]*\(\#\([0-9A-Za-z_-]*[A-Za-z_-]\+[0-9A-Za-z_-]*\)\)[^\#]*\(\#[0-9]*\B\)*/,\2/g' \
`
# Uncomment if you don't want hashtags converted into post tags
#P_TAGS_POST=$P_TAGS
# Add custom tags from a file (optional). The file is formatted like this:
# ,tag1,tag2,tag3
TAGS_FILE=$PREFIX-$ID-tags-extra.txt
if [ -s "$TAGS_FILE" ]; then
P_TAGS_POST=$P_TAGS_POST`cat $TAGS_FILE`
fi
echo "P_TAGS_POST: $P_TAGS_POST" | tee -a $LOG_FILE
TEXT_FILE=$PREFIX-$ID-text.txt
if [ ! -s $TEXT_FILE ]; then
echo "$TEXT" > $TEXT_FILE
fi
FULL_URL=`grep "<img src=" $FULL_HTML | grep -Eo "src=\"[^\"]*\"" | grep -Eo "http://[^\"]*"`
echo "FULL_URL: $FULL_URL" | tee -a $LOG_FILE
SCALED_HTML=$PREFIX-$ID-scaled.html
if [ ! -s "$SCALED_HTML" ]; then
wget http://twitpic.com/$ID -O $SCALED_HTML
if [ ! -s "$SCALED_HTML" ]; then
echo "ERROR: could not get SCALED_HTML for $ID" | tee -a $LOG_FILE
sleep 5
fi
fi
SCALED_URL=`grep "id=\"photo-display\"" $SCALED_HTML | grep -Eo "http://[^\"]*" | head -n1`
echo "SCALED_URL: $SCALED_URL" | tee -a $LOG_FILE
POST_DATE=`grep -Eo "Posted on [a-zA-Z0-9 ,]*" $SCALED_HTML | sed -e 's/Posted on //'`
echo "POST_DATE: $POST_DATE" | tee -a $LOG_FILE
THUMB_URL=`cat $PREFIX-page-* | grep -E "<a href=\"/$ID\">" | grep -Eo "src=\"[^\"]*\"" | head -n1 | sed -e 's/src=\"//' -e 's/\"$//'`
echo "THUMB_URL: $THUMB_URL" | tee -a $LOG_FILE
EXT=`echo "$FULL_URL" | grep -Eo "[a-zA-Z0-9]+\.[a-zA-Z0-9]+\?" | head -n1 | grep -Eo "\.[a-zA-Z0-9]+"`
if [ -z "$EXT" ]; then
EXT=`echo "$FULL_URL" | grep -Eo "\.[a-zA-Z0-9]+$"`
fi
echo "EXT: $EXT"
if [ "$DOWNLOAD_FULL" -eq 1 ]; then
FULL_FILE="$PREFIX-$ID-full$EXT"
if [ ! -s $FULL_FILE ]; then
wget "$FULL_URL" -O $FULL_FILE
if [ ! -s "$FULL_FILE" ]; then
echo "ERROR: could not get FULL_URL for $ID: $FULL_URL" | tee -a $LOG_FILE
sleep 5
fi
fi
fi
if [ "$DOWNLOAD_SCALED" -eq 1 ]; then
SCALED_FILE=$PREFIX-$ID-scaled$EXT
if [ ! -s $SCALED_FILE ]; then
wget "$SCALED_URL" -O $SCALED_FILE
if [ ! -s "$SCALED_FILE" ]; then
echo "ERROR: could not get SCALED_URL for $ID: $SCALED_URL" | tee -a $LOG_FILE
sleep 5
fi
fi
fi
if [ "$DOWNLOAD_THUMB" -eq 1 ]; then
THUMB_FILE=$PREFIX-$ID-thumb$EXT
if [ ! -s $THUMB_FILE ]; then
wget "$THUMB_URL" -O $THUMB_FILE
if [ ! -s "$THUMB_FILE" ]; then
echo "ERROR: could not get THUMB_URL for $ID: $THUMB_URL" | tee -a $LOG_FILE
sleep 5
fi
fi
fi
BODY_TEXT="$TEXT_RICH <p>[<a href=http://twitpic.com/$ID>Twitpic</a>]</p>"
# Format the post date correctly
YEAR=`echo "$POST_DATE" | sed -e 's/[A-Z][a-z]* [0-9]*, //'`
DAY=`echo "$POST_DATE" | sed -e 's/[A-Z][a-z]* //' -e 's/, [0-9]*//'`
MONTH=`echo "$POST_DATE" | sed -e 's/ [0-9]*, [0-9]*//' | sed \
-e 's/January/01/' \
-e 's/February/02/' \
-e 's/March/03/' \
-e 's/April/04/' \
-e 's/May/05/' \
-e 's/June/06/' \
-e 's/July/07/' \
-e 's/August/08/' \
-e 's/September/09/' \
-e 's/October/10/' \
-e 's/November/11/' \
-e 's/December/12/' \
`
# Adjust the time to local midnight when west of GMT
HOURS_LOC=`date | grep -Eo " [0-9]{2}:" | sed -e 's/://' -e 's/ //'`
HOURS_UTC=`date -u | grep -Eo " [0-9]{2}:" | sed -e 's/://' -e 's/ //'`
HOURS_OFF=`expr $HOURS_UTC - $HOURS_LOC + 7`
echo "HOURS_LOC: $HOURS_LOC"
echo "HOURS_UTC: $HOURS_UTC"
echo "HOURS_OFF: $HOURS_OFF"
if [ "$HOURS_OFF" -lt 0 ]; then
# We're east of GMT, do not adjust
HOURS_OFF=0
fi
if [ "$HOURS_OFF" -lt 10 ]; then
HOURS_OFF=0$HOURS_OFF
fi
if [ "$DAY" != "" ] && [ "$DAY" -lt 10 ]; then
DAY=0$DAY
fi
DATE_FORMATTED="$YEAR-$MONTH-$DAY-$HOURS_OFF:00"
echo "DATE_FORMATTED: $DATE_FORMATTED" | tee -a $LOG_FILE
echo "<p><img src='$FULL_FILE' alt='$TEXT' title='$TEXT' /></p>" >> $HTML_OUT
echo "$BODY_TEXT" >> $HTML_OUT
echo " Post date: $DATE_FORMATTED; Count: $COUNT" >> $HTML_OUT
# Upload this Twitpic data to Posterous
if [ ! -z "$P_SITE_ID" ]; then
# First make sure we're under the API upload limit
if [ "$COUNT" -le "$UPLOAD_SKIP" ]; then
echo Skipping upload...
continue
fi
if [ "$COUNT" -gt "`expr $UPLOAD_SKIP + $P_API_LIMIT`" ]; then
echo "Skipping upload due to daily Posterous API upload limit of $P_API_LIMIT."
echo "To resume uploading where we left off today, supply UPLOAD_SKIP parameter of `expr $UPLOAD_SKIP + $P_API_LIMIT`."
continue
fi
P_OUT_FILE="posterous-$P_SITE_ID-$ID.out"
if [ -s "$P_OUT_FILE" ]; then
rm "$P_OUT_FILE"
fi
echo "Uploading Twitpic image..."
curl -u "$P_ID:$P_PW" "http://posterous.com/api/newpost" -o "$P_OUT_FILE" \
-F "site_id=$P_SITE_ID" \
-F "title=$TEXT" \
-F "autopost=$P_AUTOPOST" \
-F "private=$P_PRIVATE" \
-F "date=$DATE_FORMATTED" \
-F "tags=$P_TAGS_POST" \
-F "source=burndive's Twitpic-to-Posterous script $SCRIPT_VERSION_STRING" \
-F "sourceLink=http://tuxbox.blogspot.com/2010/03/twitpic-to-posterous-export-script.html" \
-F "body=$BODY_TEXT" \
-F "media=@$FULL_FILE"
cat $P_OUT_FILE | tee -a $UPLOAD_OUT
fi
done
echo Done.This software is licensed under the CC-GNU GPL version 2.0 or later.
PS: If you use my code, I appreciate comments to let me know, and any feedback you may have, especially if it's not working right for you, but also just to say thanks.
For convenience, you can download this script from my server.
Saturday, March 13, 2010
Posterous Blogger Sidebar Widget Thumbnail Feed Script
It's been a while since this blog actually lived up to its name and I posted something to do with actual hacking on my Linux box.
You may recall a post a while back where I used the 'sed' command to create a modified copy of my TwitPic feed so that a thumbnail would show up when I imported the feed into a Blog List gadget in Blogger.
Well, I recently switched from using TwitPic for uploading pictures from my phone to using Posterous for uploading pictures and video from my phone. There were many reasons in the "pros" column, but in the "cons" was the fact that, when I imported my feed into that same Blogger widget, no thumbnail appeared.
So, just like with the TwitPic feed, I set out to modify my Posterous feed in order to get the thumbnail to appear. One problem I encountered is that the feeds were totally different formats. I based my TwitPic feed modification on a feed I knew to be working (from Digg), but performing that same transformation on the Posterous feed proved to be problematic.
What I ended up doing was simply extracting the information I needed from the Posterous feed, and then creating a one-item feed in the known-good format. The feed looks nothing like the original Posterous feed, but that's just fine, since all it will be used for is pulling the latest post into my blog sidebar.
One improvement I'm considering working on is providing a useful thumbnail when I upload a video. Currently (at least with the 3gp format), the Posterous feed just sticks a generic blank file icon in the thumbnail field. What I would like is a still frame from the movie. In order to do this myself, I would need to download the enclosure link, process the video into a still image, post the image on the web, and then put the image URL into the feed. All very doable given the right tools.
I'll have to test out what happens when I use the MP4 format for video, which my phone is also capable of creating.
Here's my script (so far). Feel free to use it under the terms of the license listed below. If you have any questions or suggestions, please feel free to leave a comment.
posterous.sh (run as an hourly cron job):
You may recall a post a while back where I used the 'sed' command to create a modified copy of my TwitPic feed so that a thumbnail would show up when I imported the feed into a Blog List gadget in Blogger.
Well, I recently switched from using TwitPic for uploading pictures from my phone to using Posterous for uploading pictures and video from my phone. There were many reasons in the "pros" column, but in the "cons" was the fact that, when I imported my feed into that same Blogger widget, no thumbnail appeared.
So, just like with the TwitPic feed, I set out to modify my Posterous feed in order to get the thumbnail to appear. One problem I encountered is that the feeds were totally different formats. I based my TwitPic feed modification on a feed I knew to be working (from Digg), but performing that same transformation on the Posterous feed proved to be problematic.
What I ended up doing was simply extracting the information I needed from the Posterous feed, and then creating a one-item feed in the known-good format. The feed looks nothing like the original Posterous feed, but that's just fine, since all it will be used for is pulling the latest post into my blog sidebar.
One improvement I'm considering working on is providing a useful thumbnail when I upload a video. Currently (at least with the 3gp format), the Posterous feed just sticks a generic blank file icon in the thumbnail field. What I would like is a still frame from the movie. In order to do this myself, I would need to download the enclosure link, process the video into a still image, post the image on the web, and then put the image URL into the feed. All very doable given the right tools.
I'll have to test out what happens when I use the MP4 format for video, which my phone is also capable of creating.
Here's my script (so far). Feel free to use it under the terms of the license listed below. If you have any questions or suggestions, please feel free to leave a comment.
posterous.sh (run as an hourly cron job):
#!/bin/sh # Copyright 2010 Tim "burndive" of http://burndive.blogspot.com/ # This software is licensed under the Creative Commons GNU GPL version 2.0 or later. # License informattion: http://creativecommons.org/licenses/GPL/2.0/ # This script was obtained from here: # http://tuxbox.blogspot.com/2010/03/posterous-blogger-sidebar-widget.html DOMAIN=$1 FEED_DIR=$2 FEED_TITLE=Posterous FEED_DESC="The purpose of this feed is to provide a thumbnail of the latest item in a Blogger sidebar widget." if [ -z $DOMAIN ]; then echo "You must enter a Posterous DOMAIN." exit fi if [ -z $FEED_DIR ]; then echo "You must supply a directory." exit fi if [ ! -d $FEED_DIR ]; then echo "You must supply a valid directory." exit fi FEED_URL="http://$DOMAIN/rss.xml" TMP_FILE="/tmp/posterous-$DOMAIN.xml" FEED_FILE="$FEED_DIR/posterous-$DOMAIN.xml" # Fetch the RSS feed wget -q $FEED_URL -O $TMP_FILE if [ ! -f $TMP_FILE ]; then echo "Failed to download $FEED_URL to $TMP_FILE" exit fi NEW_LATEST=`grep guid $TMP_FILE | head -n1` if [ ! -f $FEED_FILE ]; then FEED_LATEST="" else FEED_LATEST=`grep guid $FEED_FILE | head -n1` fi # Comment these out #echo "FEED_LATEST: $FEED_LATEST" #echo "NEW_LATEST : $NEW_LATEST" if [ "$FEED_LATEST" = "$NEW_LATEST" ]; then # echo "There is no change in the feed." # echo "FEED_LATEST: $FEED_LATEST" exit fi IMG_HTML=`grep -i "img src" $TMP_FILE | head -n1 | grep -Eo "<img src='[^']*'[^>]*>" | sed -e 's/\"/\"/g' -e 's/</\</g' -e 's/>/\>/g'` #echo "IMG_HTML: $IMG_HTML" IMG_URL=`grep -i "img src" $TMP_FILE | head -n1 | grep -Eo "http:[^']*" | tail -n1` #echo "IMG_URL: $IMG_URL" # Create a minimalist RSS feed echo "<?xml version='1.0'?> " > $FEED_FILE echo "<rss version='2.0' xmlns:media='http://search.yahoo.com/mrss/'>" >> $FEED_FILE echo "<channel>" >> $FEED_FILE echo "<title>$FEED_TITLE</title>" >> $FEED_FILE echo "<description>$FEED_DESC</description>" >> $FEED_FILE echo "<link>http://$DOMAIN/</link>" >> $FEED_FILE echo "<item>" >> $FEED_FILE grep "<title>" $TMP_FILE | head -n2 | tail -n1 >> $FEED_FILE grep "<pubDate>" $TMP_FILE | head -n1 >> $FEED_FILE echo "<description>$IMG_HTML</description>" >> $FEED_FILE grep "<link" $TMP_FILE | head -n3 | tail -n1 >> $FEED_FILE echo "$NEW_LATEST" >> $FEED_FILE echo "<media:thumbnail url=\"$IMG_URL\" height=\"56\" width=\"75\" />" >> $FEED_FILE echo "</item>" >> $FEED_FILE echo "</channel>" >> $FEED_FILE echo "</rss>" >> $FEED_FILE # Cean up rm $TMP_FILE
This software is licensed under the CC-GNU GPL version 2.0 or later.
Monday, April 13, 2009
That's What She sed
Lately, I've been uploading pictures to Twitter from my phone using TwitPic. Basically, you send them to a TwitPic e-mail address via multimedia messaging, and they are automatically posted to your Twitter account, along with the text from the subject.
This all works quite well, and they even supply an RSS feed of your pictures, which you can take and (among other thing) put on your blog's sidebar.
The problem was, when I put it in my blog sidebar, there was no thumbnail image. Other feeds that had images in them would have thumbnails, but not this one. This one just had a text link to the picture page. I found that disappointing.
So I examined feeds that showed thumbnails and the TwitPic feed to see what the difference was. Feeds that contained images within the feed content showed up in the Blogger widget with a thumbnail. But the TwitPic feed showed images. What was the difference?
The difference turned out to be CDATA. CDATA is a way to tell a feed reader, "Don't try to decipher my contents, just pass them along and leave the rendering to the end user application." It so happens that TwitPic's thumbnail images are within a CDATA block, and Blogger obediently ignores the CDATA contents when looking for images to display as a thumbnail.
So, how do I fix that? I need to read the feed, and for each item, locate the line that contains the thumbnail URL, and create a new attribute containing the thumbnail in a format that is decipherable to Blogger's widget. Using my digg feed as a model, I figured out what the end result should look like, but how to achieve it?
First, I tried Yahoo Pipes. Yahoo has a tool for processing feeds with a number of tools, controlled by a graphical pipe-looking interface. The problem is, none of the tools that I could find would add an attribute based on the transformed contents of another attribute. There were widgets that came close, but I couldn't get it to work, so I decided to host the feed myself and modify it using sed.
I had never used sed before, except when the exact command was given, so I didn't know how to use it, but I knew that it was a powerful enough tool to get the job done.
So I created a shell script on my Linux box, and a cron job to run it. The script basically downloaded the RSS feed from TwitPic to a local file, and then called sed on it with a particular set of parameters designed to extract the necessary information, and add the appropriate information in a format that is decipherable to Blogger.
In order to understand sed, I searched the Internet for a tutorial, and found this page from the Gentoo Linux Documentation to be the most helpful.
My sed command does two things, which are piped together:
- It adds an xmlns:media declaration, which allows me to use the media tag later on.
- It examines each CDATA line with the thumbnail URL, and below it, it adds a line with the media:thumbnail tag and the URL extracted from above.
sed -e 's/<rss version="[^"]*"/& xmlns:media="http:\/\/search.yahoo.com\/mrss\/"/g' $TMP_FILE | sed -e 's/\(http:\/\/twitpic.com\/show\/thumb\/[^"]*\).*/&\n <media:thumbnail url="\1" height="150" width="150" \/>/g' > $FEED_FILEI know it's possible to consilidate the two sed commands into one and do it in one pass, but this works. I may tweak it in further revisions. It is not necessary to use a yahoo-defined media tag, so I might modify the script later on to simply transform the CDATA portion into parseable encoded HTML. I might also add that I'm using Feedburner to host the feed. Basically, I change the file on my server, and Feedburner goes there to get it, and offers it to the rest of the world. That way if my server is offline, the feed is still active and available, and I don't have to deal with the traffic, just the Feedburner hits. If anyone else wants their TwitPic feed to have thumbnails available, let me know, and I can set one up for you on my server through Feedburner. (It's pretty easy, since the TwitPic username is passed in to the script as a parameter). I can't guarantee anything, but since it's in my interest to keep the script working and up-to-date, you don't have much to worry about. All I need to know is your TwitPic (Twitter) username.
- Update (2009-04-16): I have modified the code to accept all image formats, and be shorter.
Subscribe to:
Posts (Atom)














