Home > Articles > CastGrabber Journal
You are not currently logged in! · Login · Register
 
Monday 6th September, 2010
 
Search:
 
  Site Index
   Home
Writing
   Articles & Essays
   Journals
   The Storyboard
   Posting Guide
Distractions
   Nova Restoration
   Gamedev
   Podcasts
   Castgrabber
   Linux
   Movies
   Links
   Coding
   Books
Site Features
   Photo Gallery
   Members
   Changelog
   RSS Feed
About this Site
   About Me
   Contact Me
   Portfolio
CastGrabber Journal
by bpopp on Friday, September 29, 2006 - 02:09 AM
 
Tech

I've really gotten into listening to Podcasts in the last few months. I used to have an iPod that I would download everything to, but it was a PoS and eventually quit working altogether. Now I have a much smaller 512MB mp3 player that I use. I like it a lot better (smaller/lighter/longer battery life/can use any player), but because of the smaller capacity, I have to be more creative in how I keep fresh content on it.

Basically what I do is set my aggregator to download all my podcasts to a particular directory on my file server. Most of the aggregator's I've tried have a feature that will add each downloaded podcast to a Playlist in your corresponding player (WMP in my case) after the download finishes. This works well because then I have WMP setup to sync each of my podcast playlists. After I've listened to each one, I remove it from the playlist which removes the file from my player the next time I sync.

Unfortunately the biggest wrench in the whole system is the aggregator. All of the one's I've tried suck. Juice is decent, but it doesn't allow you to change the podcast's tags after downloading. This is important because many of the podcasts I listen to don't use meaningful tags and often change their tags week to week (for some strange reason). When I sync, this causes a bunch of goofy duplicate folders to be created on my player. I thought about trying to add the functionality I needed to Juice (either via plugins or by tweaking the code), but the code is a horrid mess of python gobbly-gook (which I don't know) and there's absolutely no documentation for it. Despite the nice, pretty logo and elegant interface, it seems to be a train-wreck of a project.

I'm currently using an aggregator called Doppler (Beta) which is really nice, BUT, it craps out on half my podcasts with parsing errors. I'm not sure why since it is, thus far, closed-source. It's also been a while since the author released a new version, so I'm not holding my breath. The interface is kind of goofy, too, because it doesn't let you pick which items you want to download. It either wants to download everything or the last x number of items.

So, given these limited options, and my recent curiosity regarding .net and C#, I've decided to write my own aggregator. Over the last couple days I jotted down a few milestones and sketched out some interface ideas and I think I have a pretty good idea what I want. Tonight I started doing some prototype coding and so far have been really impressed. In just a few hours of coding, I got finished what I expected to take a week or longer. C# is a very comfortable language, especially so with Visual Studio. I know what you're thinking.. "but Brian, what about open source?!" I'm still a huge fan of open-source, and wouldn't even consider using this technology server-side. For generating client applications, though, I don't know of anything on Windows that can come close. MacOS' XCode is nice (aside from that god-awful Objective-C), and KDE's QT kit is really nice, but for this project, I just want something that will run on Windows.

CastGrabber .1 

This isn't anything like what I'm invisioning for the interface, but it was an incredible start given how little C# experience I have. So far I have a dialog that takes a URL from the clipboard (if available) and adds it to the feed textbox. When you click Get, it downloads the feed, parses it, and adds the items to a listbox. When you click on each item, it shows you the attachment (if any) and you can download the file by hitting another Get button. I'll post an early version tomorrow night if anyone is curious. I plan on using this thread to keep track of my progress both with this project and with C#/.net, in general.

Update:CastGrabber is a fully-functioning aggregator now. Download the newest version here: Castgrabber v2

Update:Download the beta version 3 here: Castgrabber v3


 


  Comments
Page 1 of 4, 43 items total. (look for morebar™ improvements soon!)
 
scipiomphs  |  Friday, September 29, 2006 12:02 PM

I'm curious! I want to see what you come up with.

bpopp  |  Monday, October 02, 2006 02:50 AM

I made some more good progress this weekend. I'm still extremely impressed with C#. It's this really elegant bastardization of C++ and Java, and it encapsulates so much of the Windows API in a nice, elegant way. Granted, I'm still swimming in the 3ft area of the pool, but I've been able to do some pretty slick things even in such shallow water.

Tonight I took my download function and wrapped it in a DownloadQueueManager (as I called it). It basically uses a Queue collection to hold items that the user chooses to download. Then I added some threading so that the download runs in the background. This works much better because it doesn't hold up the interface waiting for the download to finish. It also allows you to queue up a bunch of other downloads while you wait. I also fixed a bug in the RSS parser that was keeping some feeds from working correctly with attachments. Unfortunately I haven't got the progress bar working with my new QueueManager yet. I haven't exactly figure out an elegant way to bind UI components with running threads yet (I have a few ideas, though).

 

Anyway, it's still very green (not even Beta), but if anyone wants to try it out, you can download the newest version here. Just unzip it and then run the Setup.exe file. I'm 92% sure it won't format your hard drive and leave only nude pictures of Natalie from the Facts of Life where your important files used to be.

Seriously, it won't hurt anything, but it might crash. You'll need the .net framework version 2 for it to run, but I think the installer will install this for you automatically. I ran into some issues with an older version bombing out whenever it tried to write to a file. It has something to do with .net's security model and I'm not sure if I've fixed it in this version or not. If it craps out, just uninstall it using "Add Remove Programs" or just wait and I'll release a more stable version in the next week or so.

bpopp  |  Thursday, October 05, 2006 01:14 AM

I had a very interesting night with nothing much to show for it. The part I'm prototyping right now is the Download Manager. The intent is to allow the user to be able to select how many threads they want to use for downloading, and then to give each download process it's own thread. The current architecture is based around 3 classes. I have a DownloadItem, a DownloadQueueManager, and a DownloadQueue. The names are a little inappropriate now since my queue has technically been replaced with a Hash, but it's mostly throw-away code anyway.

Currently my main window instantiates the DownloadQueueManager, and then as items are selected for download, it calls an Add function of that class with a URL, a filepath, and a file size. The QueueManager then creates a new DownloadItem object and then adds it to the DownloadQueue item. When the user hits the Download button, the system calls a DownloadAll function in the QueueManager which then creates a single processing thread. That thread then loops through the DownloadItems to see what they are doing. If they are already in the process of downloading, it skips to the next. If they are done downloading, it removes them which then frees up a slot for more downloads. If they are not working, and there is an available download slot, it triggers another thread to download that item. That all seems to be working okay, but it's really a pain in the ass to try and figure out what all the different threads are doing at any given point in time. I have a sneaky suspicion that my app is wasting a lot of CPU cycles doing stuff it shouldn't.

Another interesting problem is trying to keep the GUI synced up with the objects in the background. Normally there is something called data binding in .net, but unfortunately the listview component doesn't support it (for reasons only the Microsoft engineers know?). This means that you have to handle refreshes of the GUI yourself. I'm using delegate events to do this which are very cool.

Basically the DownloadItem triggers an event whenever 1k of bytes have been downloaded. This event is being monitored by the DownloadQueue which then triggers it's own delegate event called QueueChanged. This event is then being subscribed to by the form object. Whenever it receives a QueueChanged event, it should refresh the list. In theory, I think this should work, but I get an exception whenever the list tries to refresh telling me that only the main thread can modify the listview. AFAIK the main thread is the only one modifying the GUI so I'm not sure what's going on. It'll hopefully make more sense tomorrow night after I get some sleep.

Hopefully I'll have a new version to release this weekend that allows multiple feeds to be watched and scheduled for download.

bpopp  |  Friday, October 06, 2006 02:22 AM

 

You can download v5 here. I tweaked the interface a little bit. As the screenshot shows, I changed it so that if you queue multiple items it asks you which folder you want to save the files in now (as opposed to prompting for each file). Unfortunately it's still not updating the progress the way it's supposed to, but at least it's loading and refreshing the queue list correctly now. I also setup the Queue thread so that it's always running watching for downloads. This means you don't have to hit "Download" anymore (just queue something).

Again, this isn't anything like what I'm invisioning for the final app, but I'm just playing around trying to learn the language/framework. More later.

bpopp  |  Saturday, October 07, 2006 03:11 AM

Castgrabber v6: I started out slow tonight, but I really ended up getting a lot done. This screenshot shows a couple things. For one, you can see that the queue is updating now. I actually cheated a little bit. The way it should probably work is that the DownloadItem, as it is downloading, should be sending progress reports to the form (through the manager), and the form should just update the corresponding list as needed. Unfortunately, I can't figure out to make this work. Because the listview isn't actually tied to the data in any way, I can't figure out how to know which listitem corresponds with which item in the Queue collection. Instead I set a timer in the main form and I'm just redrawing the entire list periodically. It's a hack, and it causes an annoying flicker, but it works okay. I'll fix this later (famous last workds).

 

The other thing I coded, and I'm really surprised how easy this was, was to call Windows Media Player whenever a file finishes downloading and add it to a playlist. You can see the playlist in the background along with all the podcasts I have downloaded. I'm going to make this functionality an abstract interface so that I can add different players as needed. Basically you'll be able to choose from a couple different players and the system will just call "AddToPlaylist()" for the corresponding class (that implements that interface).

bpopp  |  Monday, October 09, 2006 03:17 AM

Castgrabber v7: Castgrabber is coming along nicely. Basically I created objects for.. err.. ya know what.. nevermind.. between it being 3AM and the Samantha Fox track that somehow ended up in my WMP collection, I can't think right now. I'll flesh this out tomorrow.

 

By the way, before you make fun of me for having Samantha Fox songs in my music collection, just know that her playboy centerfold was very special to me when I was younger. Her and I will always have a dubious bond that few will ever understand.

bpopp  |  Monday, October 09, 2006 11:50 AM

Details for Castgrabber v7: Okay. I got some sleep and some better music so I think I can talk a little bit about this weekend's changes. I'm getting very close to having an aggregator. It doesn't have many bells and whistles yet, but the architecture is all there.

Last night I added 4 classes to encapsulate the data. I added Feed, FeedCollection, FeedItem, and FeedItemCollection. Each feed, upon initialization, downloads the feed's source, parses it (using a third party module), and then updates itself. The feed is then added to the main form via a FeedCollection member variable (this will probably change). This FeedCollection is then used to build the main list.

The only part I don't really feel comfortable with is the synchronizing of the ListViews. Anytime a change is made to the list, I redraw the entire list (as opposed to just the item that changed). I'm toying with a possible solution to this now. Basically I am adding an "Index" field to the Feed class to keep track of the corresponding row in the list. I don't think this will work, though, because when an item is removed from the list, the indexes will surely change (but won't change in the Feed).

Anyway, here's the main features I'm planning to add (before the v3 rebuild):

Essential:
* The next minor version should add Serialization to the new Feed classes so that this information will persist when you close/reopen the program.
* I need to add a timer to periodically update the feeds and download any new content.
* I need a dialog or two for editing feed data and general preferences (download directory, run frequency, etc)
* I need contextual menus on the lists to handle basic functionality (redownload item, remove download file, etc.)
* I need a few menus for accessing preferences, about page, etc.
* I need to incorporate status in the Item list. It should track which items have been downloaded, which items need to be downloaded.

Would like to have:
* An auto-update feature to automatically snag the newest version.
* Sorting in lists.
* BitTorrent downloads
* Automatic subscription of feeds passed from IE/Firefox.


Bug fixes:
* Tweak the download queue thread. It's not counting downloads correctly or something because occasionally it will leave items stalled in the queue.

bpopp  |  Tuesday, October 10, 2006 02:31 AM

Castgrabber v8: I cranked up the Samantha Fox and knocked out a couple of the 'essential' features tonight. The biggest being Serialization. The only tricky part of this was converting any public properties to something that is easily serializable. Uri objects, for example, had to be converted to strings. I'm sure there's a way to teach the XmlSerializer class how to deal with these special types of objects, but it wasn't obvious and I couldn't find any examples. I think I'd prefer to keep my objects heavily typed (instead of using generic ints/strings), so I'll do some more research on this later.

 

The purpose of this serialization is to quickly store settings in an XML format (see screenshot). Basically when you close the App I'm finding the ApplicationData folder and then looking for a Castgrabber Feeds directory. If it doesn't exist, I create it. Then I delete any existing XML files in that folder. Finally, I iterate through my feed collection and write each object to a separate XML file using the index as the filename (0.xml, 1.xml). When the app loads, I do the reverse-- loading any XML files in the corresponding directory. The end affect is that when you close the app, it saves all your feeds (and any corresponding items). When you reopen the app, it loads these back up. Very cool.

Another feature I added real quick to complement this feature is a contextual menu that pops up when you right click on the feed item. Currently the only item is "Remove", but this will surely grow in the future. A download item would make sense (and would probably let me safely remove the "Queue" button).

Finally, I added a status column to the FeedItem list. It keeps track of which items have been downloaded/removed. I really don't like how this is implemented, so I'll probably refactor it tomorrow night. Currently I'm using an enumerated int to keep track of the status. It works, but it's not very flexible and I'd like to eventually do a lot more with the status (sorting the list view, for example).

bpopp  |  Wednesday, October 11, 2006 02:21 AM

Castgrabber v9: Very quick update (sooo tired). Fixed the problems with the queue. Very stupid bug. Was incrementing a member variable (_usedThreads) and was checking a local variable (usedThreads). Doh.

I also added a slider to increase the amount of download threads dynamically. Kind of dumb, but I just wanted to see if it would work. It does, but unfortunately I think the servers are throttling back the connections. Any added threads seems to be attempting the download like they're supposed to, but it won't actually start receiving data until another thread is finished.

Finally, I added an UpdateThread function to the Feed. This will go out and check all the feeds for new items. New items will appear in the list as bold, old (or already downloaded) items will be normal. Next step, which is very simple, will be to put this function on a timer so that it polls the threads periodically. I'll probably put each feed on it's own timer so they don't all poll at the same time.

von  |  Wednesday, October 11, 2006 04:38 AM

Are you going to change the name at release date? You could be more like Microsoft if you do that.

bpopp  |  Wednesday, October 11, 2006 10:30 AM

Heh. I haven't decided about the name. Whatever I do, it will happen when I start working on the release version (v3). These versions are really just a staging area for building my classes, testing architecture, etc.

Updated to do list:

Essential:
* Need a dialog for editing feed data (playlist, download directory,etc.)
* Need to move the Update functionality to a thread.
* Need to add a timer to periodically update the feeds
* Any new feeds should (optionally) queue for downloading automatically.
* Need general preferences (download directory, run frequency, etc). These will all be stuffed in a class and that class should be serialized to XML in the root of the CastGrabber settings folder.
* Need more contextual menus on the lists to handle basic functionality (redownload item, remove download file, etc.)
* Need a few menus for accessing preferences, about page, etc.
* Need to refactor status in the Item list. It's goofy right now and shows item as having been downloaded before their downloaded. This will involve triggering events in the queue to let the item better know what's going on.
* Need to serialize the Queue so that aborted downloads will continue upon restart.
* Allow CastGrabber to be run in tray.
* Add optional download notification to tray.

Would like to have:
* An auto-update feature to automatically snag the newest version.
* Sorting in lists.
* BitTorrent downloads
* Automatic subscription of feeds passed from IE/Firefox.
* OPML Support

Bug fixes:
* The Select Download Folder dialog intermittently hangs on published versions. (?)

If you find anything else, please let me know. Don't worry so much about interface issues, though. I haven't (and probably won't) spend much time on that until I start recoding v3. I know it's ugly.

bpopp  |  Thursday, October 12, 2006 02:43 AM

Castgrabber v10: The lack of sleep is killing me, but I love this .net shit. After having coded in C++, Java, and Apple's Objective C (ack) it's such a fun language.

No really noticeable changes tonight. I did a lot of backend stuff. I tried a fix for the Select Download Folder bug. I'm not sure if it will work or not.

I made a pretty significant change to the Queue list so that it updates in real time using events (as opposed to using a timer). It's actually a little buggier this way and the flickering is awful, but it will work out better in the long run. I also used this same improvement to implement a progress bar. It looks cool, but it's not working right. It looks at how much stuff is currently in the queue as opposed to what has already been downloaded. This makes it horribly inaccurate when you have lots of stuff queued. I'll fix it later.

Finally, I enabled the playlist checkbox. Checking it will add downloads to your Windows Media Player playlist as they finish (using the feed name as the playlist name). May be a little buggy.. I really need to do some checking on the playlist name to ensure that it doesn't have any special characters (that might not translate to the filesystem). Leave it unchecked for now if you're worried about goofing up your playlists.

Page 1 of 4, 43 items total. (look for morebar™ improvements soon!)