banshee r3934 - in trunk/banshee: . src/Core/Banshee.Core/Banshee.Collection src/Core/Banshee.Core/Banshee.Streaming src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.MediaEngine src/Core/Banshee.Services/Banshee.Metadata src/Core/Banshee.Services/Banshee.Metadata.Embedded src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz src/Core/Banshee.Services/Banshee.Metadata.Rhapsody src/Core/Banshee.ThickClient/Banshee.Collection.Gui src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying src/Extensions/Banshee.Podcasting/Banshee.Podcasting src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source src/Extensions/Banshee.Podcasting/Resources src/Libraries/Hyena.Gui/Hyena.Data.Gui src/Libraries/Hyena/Hyena src/Libraries/Hyena/Hyena.Data.Sqlite src/Libraries/Hyena/Hyena.Query src/L ibraries/Migo src/Libraries/Migo/Migo/Migo.Syndication



Author: gburt
Date: Tue May 20 07:01:14 2008
New Revision: 3934
URL: http://svn.gnome.org/viewvc/banshee?rev=3934&view=rev

Log:
2008-05-20  Gabriel Burt  <gabriel burt gmail com>

	This commit fixes a major (though one-line) bug with threading that should
	fix "xcb" related crashes.  It improves podcast support, including
	automatically switching to Now Playing for videos and supporting Media RSS
	feeds.

	* src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs:
	Also switch to Now Playing if the trackinfo is updated and it is a video.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs:
	Delay refreshing the feeds, and don't try to download artwork if feed not
	fetched.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastActions.cs:
	Implement deleting a podcast feed, feed context menu.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs:
	Show a message if the user creates a playlist under the Podcast source.
	Should be allowed, but doesn't work properly yet, so we don't allow it.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastTrackInfo.cs:
	Set the LicenseUri and MediaAttributes.

	* src/Extensions/Banshee.Podcasting/Resources/GlobalUI.xml: Add a context
	menu just for the All Podcasts item.

	* src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellFileSize.cs:
	Right align and always show one decimal point.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImageFetchJob.cs:
	* src/Core/Banshee.Services/Banshee.Metadata/IMetadataLookupJob.cs:
	* src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs:
	* src/Core/Banshee.Services/Banshee.Metadata/MetadataSettings.cs:
	* src/Core/Banshee.Services/Banshee.Metadata/IMetadataProvider.cs:
	* src/Core/Banshee.Services/Banshee.Metadata/BaseMetadataProvider.cs:
	* src/Core/Banshee.Services/Banshee.Metadata/MetadataServiceJob.cs:
	* src/Core/Banshee.Services/Makefile.am:
	* src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzMetadataProvider.cs:
	* src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs:
	* src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyMetadataProvider.cs:
	* src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyQueryJob.cs:
	* src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedMetadataProvider.cs:
	* src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedQueryJob.cs:
	* src/Core/Banshee.Services/Banshee.Services.mdp:
	Get rid of MetadataSettings and use NetworkDetect.  Don't lookup if
	podcast MediaAttribute set.  Fix bug with calling GTK+ things from the
	metadata update thread; probably the cause of the xcb crashes.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs:
	Trim artist and album names when set.

	* src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs: Don't
	ignore media engine tags if the current track is not a local file.  This
	lets GStreamer tell us the streaming file is a video so Now Playing can
	switch to itself.

	* src/Core/Banshee.Core/Banshee.Collection/IBasicTrackInfo.cs: Add
	ArtworkId and MediaAttributes properties.

	* src/Core/Banshee.Core/Banshee.Collection/LicenseInfo.cs: New file, not
	in build.  Idea is to parse and represent Creative Commons license info.

	* src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs: Handle the
	VideoCodec tag, setting the VideoStream attribute.

	* src/Libraries/Hyena/Hyena/StringUtil.cs:
	* src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs: Allow specifying
	that one decimal point should always been shown.  By default, we hide the
	decimal point and tenths place if the number is within 0.05 of an int.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs: Make
	Delete methods virtual, add LIMIT 1 to FetchFirstMatching, and use
	DeleteCommand property instead of field.

	* src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs: Add a
	protected Pango.Alignment property.

	* src/Libraries/Migo/Makefile.am:
	* src/Libraries/Migo/Migo.mdp:
	* src/Libraries/Migo/Migo/Migo.Syndication/XmlUtils.cs: Removed, code
	moved into RssParser.

	* src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs: Add LicenseUri
	property, and fix loading of the enclosure.

	* src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs: Tweaks.

	* src/Libraries/Migo/Migo/Migo.Syndication/RssParser.cs: Merge the code
	from XmlUtils into here, add more namespaces so can pull out Creative
	Commons LicenseUri and can pull the highest bitrate <media:content> if
	there is no <enclosure> tag - eg for The Onion News Network.  Should
	probably allow setting global or per-podcast preference for preferred
	quality if there are ever options.

	* src/Libraries/Migo/Migo/Migo.Syndication/MigoModelProvider.cs: Make
	Delete methods override; as 'new' they weren't working.

	* src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs: Get rid of TTL and
	Interval properties, replace with UpdatePeriodMinutes property.  Fix
	Delete method.

	* configure.ac: Enable the podcast extension by default.


Added:
   trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/LicenseInfo.cs
Removed:
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataSettings.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/XmlUtils.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/configure.ac
   trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/IBasicTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedMetadataProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedQueryJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzMetadataProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyMetadataProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyQueryJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/BaseMetadataProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataLookupJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataProvider.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataServiceJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellFileSize.cs
   trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastTrackInfo.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastActions.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImageFetchJob.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Resources/GlobalUI.xml
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs
   trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs
   trunk/banshee/src/Libraries/Migo/Makefile.am
   trunk/banshee/src/Libraries/Migo/Migo.mdp
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/MigoModelProvider.cs
   trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/RssParser.cs

Modified: trunk/banshee/configure.ac
==============================================================================
--- trunk/banshee/configure.ac	(original)
+++ trunk/banshee/configure.ac	Tue May 20 07:01:14 2008
@@ -90,8 +90,7 @@
 dnl i18n
 SHAMROCK_CONFIGURE_I18N($PACKAGE)
 
-AC_ARG_ENABLE(podcast, AC_HELP_STRING([--enable-podcast], 
-	[Enable Podcast extension]), , enable_podcast="no")
+AC_ARG_ENABLE(podcast, AC_HELP_STRING([--disable-podcast], [Disable Podcasting support]), , enable_podcast="yes")
 AM_CONDITIONAL(ENABLE_PODCAST, test "x$enable_podcast" = "xyes")
 
 dnl generated files
@@ -187,7 +186,7 @@
       iPod:            ${enable_ipodsharp}
 
     DAAP Support:      ${enable_daap}	(unstable)
-    Podcast Support:   ${enable_podcast}	(unstable)
+    Podcast Support:   ${enable_podcast}
     Boo Scripting:     ${enable_boo}
 "
 if test -d ${expanded_libdir}/${PACKAGE}; then

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/IBasicTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/IBasicTrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/IBasicTrackInfo.cs	Tue May 20 07:01:14 2008
@@ -33,5 +33,7 @@
         string ArtistName { get; }
         string AlbumTitle { get; }
         string TrackTitle { get; }
+        string ArtworkId { get; }
+        TrackMediaAttributes MediaAttributes { get; }
     }
 }

Added: trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/LicenseInfo.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/LicenseInfo.cs	Tue May 20 07:01:14 2008
@@ -0,0 +1,246 @@
+//
+// LicenseInfo.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace CreativeCommons
+{
+    public class LicenseInfo
+    {
+    }
+    
+    [Flags]
+    public enum Permissions
+    {
+        None = 0,
+        Reproduction,
+        Distribution,
+        DerivativeWorks,
+        HighIncomNationUse,
+        Sharing
+    }
+    
+    [Flags]
+    public enum Requirements
+    {
+        None = 0,
+        Notice,
+        Attribution,
+        ShareAlike,
+        SourceCode
+    }
+    
+    [Flags]
+    public enum Prohibitions
+    {
+        None = 0,
+        CommercialUse
+    }
+        
+    public class CreativeCommonsLicenseInfo 
+    {
+        private static string [] known_licenses = new string [] {
+            "http://creativecommons.org/licenses/by/2.5/rdf";,
+            "http://creativecommons.org/licenses/by/3.0/rdf";,
+        };
+        
+        public static IEnumerable<CreativeCommonsLicenseInfo> KnownLicenses {
+            get {
+                foreach (string known_license in known_licenses) {
+                    if (!licenses.ContainsKey (known_license)) {
+                        FromLicenseUrl (known_license);
+                    }
+                }
+                
+                foreach (CreativeCommonsLicenseInfo license in licenses.Values) {
+                    if (license != null)
+                        yield return license;
+                }
+            }
+        }
+    
+        private Permissions permissions;
+        private Requirements requirements;
+        private Prohibitions prohibitions;
+        
+        private bool is_deprecated;
+        private string title;
+        private string version;
+        private string code_name;
+        private string about_url;
+        private string legal_url;
+        private string jurisdiction_url;
+        private string creator_url;
+        
+        /*public static CreateiveCommonsLicenseInfo FromCodeName (string code_name)
+        {
+            return null;
+        }*/
+        
+        private static Dictionary<string, CreativeCommonsLicenseInfo> licenses = new Dictionary<string, CreativeCommonsLicenseInfo> ();
+        
+        public static CreateiveCommonsLicenseInfo FromLicenseUrl (string license_url)
+        {
+            if (String.IsNullOrEmpty (license_url))
+                return null;
+
+            string rdf_url = GetRdfUrl (license_url);
+            if (rdf_url == null)
+                return null;
+                
+            if (licenses.ContainsKey (rdf_url)) {
+                return licenses[rdf_url];
+            }
+            
+            CreativeCommonsLicenseInfo license = null; // Grab from web and parse
+            licenses[rdf_url] = license;
+            return license;
+        }
+        
+        private static string GetRdfUrl (string license_url)
+        {
+            if (license_uri.StartsWith ("http://creativecommons.org/licenses/";)) {
+                if (license_url.EndsWith ("/rdf"))
+                    return license_url;
+                else if (license_url.EndsWith ("/"))
+                    return String.Format ("{0}rdf", license_url);
+                else
+                    return String.Format ("{0}/rdf", license_url);
+            }
+            return null;
+        }
+                
+
+        public LicenseInfo ()
+        {
+        }
+        
+        /*public void GetLicenseInfo (string license_uri)
+        {
+            if (String.IsNullOrEmpty (license_uri))
+                return;
+
+            if (license_uri.StartsWith ("http://creativecommons.org/";)) {
+                if ()
+            }
+        }*/
+    }
+    
+    public class CreativeCommonsRdfParser
+    {
+        public static CreativeCommonsLicenseInfo (string xml_blob)
+        {
+        }
+
+        //ns_mgr = XmlUtils.GetNamespaceManager (doc);
+        //ns_mgr.AddNamespace ("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd";);
+        /*xmlns:cc='http://creativecommons.org/ns#'
+        xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
+        xmlns:dc='http://purl.org/dc/elements/1.1/'
+        xmlns:dcq='http://purl.org/dc/terms/'*/
+    }
+}
+
+/*
+<?xml version="1.0" encoding="utf-8"?>
+<rdf:RDF
+  xmlns:cc='http://creativecommons.org/ns#'
+  xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
+  xmlns:dc='http://purl.org/dc/elements/1.1/'
+  xmlns:dcq='http://purl.org/dc/terms/'
+>
+  <cc:License rdf:about="http://creativecommons.org/licenses/by-sa/3.0/us/";>
+    <dcq:hasVersion>3.0</dcq:hasVersion>
+    <cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
+    <cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
+    <cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
+    <dc:creator rdf:resource="http://creativecommons.org"/>
+    <cc:legalcode rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/us/legalcode"/>
+
+    <dc:title xml:lang="ca">Reconeixement-CompartirIgual</dc:title>
+    <dc:title xml:lang="hu">Nevezd meg! - Ãgy add tovÃbb!</dc:title>
+    <dc:title xml:lang="ko">ìììíì-ëììêëêíë</dc:title>
+    <dc:title xml:lang="fi">NimeÃ-Tarttuva</dc:title>
+    <dc:title xml:lang="es-cl">AtribuciÃn-LicenciarIgual</dc:title>
+    <dc:title xml:lang="en-ca">Attribution-ShareAlike</dc:title>
+
+    <dc:title xml:lang="es-mx">AtribuciÃn-Licenciamiento RecÃproco</dc:title>
+    <dc:title xml:lang="es-pe">Reconocimiento-CompartirIgual</dc:title>
+    <dc:title xml:lang="pt-pt">AtribuiÃÃo-Partilha nos termos da mesma licenÃa</dc:title>
+    <dc:title xml:lang="da">Navngivelse-DelPÃSammeVilkÃr</dc:title>
+    <dc:title xml:lang="en">Attribution-ShareAlike</dc:title>
+    <dc:title xml:lang="en-gb">Attribution-ShareAlike</dc:title>
+
+    <dc:title xml:lang="sv">ErkÃnnande-DelaLika</dc:title>
+    <dc:title xml:lang="pt">AtribuiÃÃo-Compartilhamento pela mesma licenÃa</dc:title>
+    <dc:title xml:lang="de">Namensnennung-Weitergabe unter gleichen Bedingungen</dc:title>
+    <dc:title xml:lang="st">Attribution-ShareAlike</dc:title>
+    <dc:title xml:lang="pl">Uznanie autorstwa-Na tych samych warunkach</dc:title>
+    <dc:title xml:lang="it-ch">Attribuzione - Condividi allo stesso modo</dc:title>
+
+    <dc:title xml:lang="af">Erkenning-InsgelyksDeel</dc:title>
+    <dc:title xml:lang="it">Attribuzione - Condividi allo stesso modo</dc:title>
+    <dc:title xml:lang="fr-lu">Paternità - Partage des Conditions Initiales à l'Identique</dc:title>
+    <dc:title xml:lang="fr-ch">Paternità - Partage des Conditions Initiales à l'Identique</dc:title>
+    <dc:title xml:lang="eo">Atribuo-distribui samrajte</dc:title>
+    <dc:title xml:lang="en-us">Attribution-ShareAlike</dc:title>
+
+    <dc:title xml:lang="bg">ÐÑÐÐÐÐÐÐÐ-ÐÐÐÐÐÐÑÐÐ ÐÐ ÑÐÐÐÐÐÐÐÐÑÐ</dc:title>
+    <dc:title xml:lang="fr">Paternità - Partage des Conditions Initiales à l'Identique</dc:title>
+    <dc:title xml:lang="nso">TsebagatÅo -Mohlakanelwa</dc:title>
+    <dc:title xml:lang="gl">RecoÃecemento-CompartirIgual</dc:title>
+    <dc:title xml:lang="eu">Aitortu-PartekatuBerdin</dc:title>
+    <dc:title xml:lang="es">Reconocimiento-CompartirIgual</dc:title>
+
+    <dc:title xml:lang="sl">Priznanje avtorstva-Deljenje pod enakimi pogoji</dc:title>
+    <dc:title xml:lang="es-co">Reconocimiento-CompartirIgual</dc:title>
+    <dc:title xml:lang="ja">èç - çæ</dc:title>
+    <dc:title xml:lang="es-ar">AtribuciÃn-CompartirDerivadasIgual</dc:title>
+    <dc:title xml:lang="fr-ca">Paternità - Partage des Conditions Initiales à l'Identique</dc:title>
+    <dc:title xml:lang="nl">Naamsvermelding-GelijkDelen</dc:title>
+
+    <dc:title xml:lang="de-ch">Namensnennung-Weitergabe unter gleichen Bedingungen</dc:title>
+    <dc:title xml:lang="zh-tw">ååæç-çåæååä</dc:title>
+    <dc:title xml:lang="mk">ÐÐÐÐÐÐÐÐÐÐÑ-ÐÐÐÐÐÐÐÐÐÐÐÑÑÐÐÑÐÐÐÐ</dc:title>
+    <dc:title xml:lang="zh">çå-çåæååä</dc:title>
+    <dc:title xml:lang="zu">Qaphela Umnikazi-Zihlanganyeleni</dc:title>
+    <dc:title xml:lang="he">×××××-××××× ×××</dc:title>
+
+    <dc:title xml:lang="ms">Pengiktirafan-PerkongsianSerupa</dc:title>
+    <dc:title xml:lang="hr">Imenovanje-Dijeli pod istim uvjetima</dc:title>
+    <dc:title xml:lang="de-at">Namensnennung-Weitergabe unter gleichen Bedingungen</dc:title>
+    <cc:jurisdiction rdf:resource="http://creativecommons.org/international/us/"/>
+    <cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
+    <cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
+    <cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
+
+    <dc:source rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/"/>
+  </cc:License>
+</rdf:RDF>
+*/
\ No newline at end of file

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs	Tue May 20 07:01:14 2008
@@ -192,6 +192,11 @@
                     case CommonTags.StreamType:
                         track.MimeType = (string)tag.Value;
                         break;
+                    case CommonTags.VideoCodec:
+                        if (tag.Value != null) {
+                            track.MediaAttributes |= TrackMediaAttributes.VideoStream;
+                        }
+                        break;
                     /*case CommonTags.AlbumCoverId:
                         foreach(string ext in TrackInfo.CoverExtensions) {
                             string path = Paths.GetCoverArtPath((string) tag.Value, "." + ext);

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	Tue May 20 07:01:14 2008
@@ -205,7 +205,8 @@
         public override string ArtistName {
             get { return base.ArtistName; }
             set {
-                if (value == ArtistName)
+                value = CleanseString (value, ArtistName);
+                if (value == null)
                     return;
 
                 base.ArtistName = value;
@@ -217,7 +218,8 @@
         public override string AlbumTitle {
             get { return base.AlbumTitle; }
             set {
-                if (value == AlbumTitle)
+                value = CleanseString (value, AlbumTitle);
+                if (value == null)
                     return;
 
                 base.AlbumTitle = value;
@@ -225,6 +227,23 @@
             }
         }
         
+        private static string CleanseString (string input, string old_val)
+        {
+            if (input == old_val)
+                return null;
+                    
+            if (input != null)
+                input = input.Trim ();
+                
+            if (input == String.Empty)
+                return null;
+                
+            if (input == old_val)
+                return null;
+            
+            return input;
+        }
+        
         private int tag_set_id;
         [DatabaseColumn]
         public int TagSetID {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs	Tue May 20 07:01:14 2008
@@ -174,15 +174,14 @@
         
         protected void OnTagFound (StreamTag tag)
         {
-            if (tag.Equals (StreamTag.Zero) || current_track == null || 
-                !current_track.IsLive) {
-                    return;
+            if (tag.Equals (StreamTag.Zero) || current_track == null || current_track.Uri.IsFile) {
+                return;
             }
-                        
+
             StreamTagger.TrackInfoMerge (current_track, tag);
             
             if (track_info_updated_timeout <= 0) {
-                track_info_updated_timeout = Application.RunTimeout (500, OnTrackInfoUpdated);
+                track_info_updated_timeout = Application.RunTimeout (250, OnTrackInfoUpdated);
             }
         }
         

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedMetadataProvider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedMetadataProvider.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedMetadataProvider.cs	Tue May 20 07:01:14 2008
@@ -42,9 +42,9 @@
         {
         }
         
-        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track, MetadataSettings settings)
+        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track)
         {
-            return new EmbeddedQueryJob(track, settings);
+            return new EmbeddedQueryJob(track);
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedQueryJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedQueryJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Embedded/EmbeddedQueryJob.cs	Tue May 20 07:01:14 2008
@@ -43,11 +43,10 @@
     {
         private TrackInfo track;
         
-        public EmbeddedQueryJob(IBasicTrackInfo track, MetadataSettings settings)
+        public EmbeddedQueryJob(IBasicTrackInfo track)
         {
             Track = track;
             this.track = track as TrackInfo;
-            Settings = settings;
         }
         
         public override void Run()
@@ -61,6 +60,9 @@
         
         protected void Fetch()
         {
+            if (!track.Uri.IsFile)
+                return;
+
             string artist_album_id = track.ArtworkId;
 
             if(artist_album_id == null) {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzMetadataProvider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzMetadataProvider.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzMetadataProvider.cs	Tue May 20 07:01:14 2008
@@ -41,9 +41,9 @@
         {
         }
         
-        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track, MetadataSettings settings)
+        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track)
         {
-            return new MusicBrainzQueryJob(track, settings);
+            return new MusicBrainzQueryJob(track);
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.MusicBrainz/MusicBrainzQueryJob.cs	Tue May 20 07:01:14 2008
@@ -39,6 +39,7 @@
 using Banshee.Kernel;
 using Banshee.Collection;
 using Banshee.Streaming;
+using Banshee.Networking;
 
 namespace Banshee.Metadata.MusicBrainz
 {
@@ -46,17 +47,14 @@
     {
         private static string AmazonUriFormat = "http://images.amazon.com/images/P/{0}.01._SCLZZZZZZZ_.jpg";;
     
-        private TrackInfo track;
         private string asin;
         
-        public MusicBrainzQueryJob(IBasicTrackInfo track, MetadataSettings settings)
+        public MusicBrainzQueryJob(IBasicTrackInfo track)
         {
             Track = track;
-            this.track = track as TrackInfo; 
-            Settings = settings;
         }
         
-        public MusicBrainzQueryJob(IBasicTrackInfo track, MetadataSettings settings, string asin) : this(track, settings)
+        public MusicBrainzQueryJob(IBasicTrackInfo track, string asin) : this(track)
         {
             this.asin = asin;
         }
@@ -68,17 +66,17 @@
         
         public bool Lookup()
         {
-            if(track == null) {
+            if (Track == null || (Track.MediaAttributes & TrackMediaAttributes.Podcast) != 0) {
                 return false;
             }
             
-            string album_artist_id = track.ArtworkId;
+            string artwork_id = Track.ArtworkId;
             
-            if(album_artist_id == null) {
+            if(artwork_id == null) {
                 return false;
-            } else if(CoverArtSpec.CoverExists(album_artist_id)) {
+            } else if(CoverArtSpec.CoverExists(artwork_id)) {
                 return false;
-            } else if(!Settings.NetworkConnected) {
+            } else if(!NetworkDetect.Instance.Connected) {
                 return false;
             }
             
@@ -89,12 +87,12 @@
                 }
             }
             
-            if(SaveHttpStreamCover(new Uri(String.Format(AmazonUriFormat, asin)), album_artist_id, 
+            if(SaveHttpStreamCover(new Uri(String.Format(AmazonUriFormat, asin)), artwork_id, 
                 new string [] { "image/gif" })) {
-                Log.Debug ("Downloaded cover art from Amazon", album_artist_id);
+                Log.Debug ("Downloaded cover art from Amazon", artwork_id);
                 StreamTag tag = new StreamTag();
                 tag.Name = CommonTags.AlbumCoverId;
-                tag.Value = album_artist_id;
+                tag.Value = artwork_id;
 
                 AddTag(tag);
                 
@@ -111,7 +109,7 @@
         private string FindAsin()
         {
             Uri uri = new Uri(String.Format("http://musicbrainz.org/ws/1/release/?type=xml&artist={0}&title={1}";,
-                track.ArtistName, track.AlbumTitle));
+                Track.ArtistName, Track.AlbumTitle));
 
             XmlTextReader reader = new XmlTextReader(GetHttpStream(uri));
 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyMetadataProvider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyMetadataProvider.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyMetadataProvider.cs	Tue May 20 07:01:14 2008
@@ -41,9 +41,9 @@
         {
         }
         
-        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track, MetadataSettings settings)
+        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track)
         {
-            return new RhapsodyQueryJob(track, settings);
+            return new RhapsodyQueryJob(track);
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyQueryJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyQueryJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata.Rhapsody/RhapsodyQueryJob.cs	Tue May 20 07:01:14 2008
@@ -40,6 +40,7 @@
 using Banshee.Metadata;
 using Banshee.Kernel;
 using Banshee.Streaming;
+using Banshee.Networking;
 
 namespace Banshee.Metadata.Rhapsody
 {
@@ -47,25 +48,24 @@
     {
         private static Uri base_uri = new Uri("http://www.rhapsody.com/";);
         
-        public RhapsodyQueryJob(IBasicTrackInfo track, MetadataSettings settings)
+        public RhapsodyQueryJob(IBasicTrackInfo track)
         {
             Track = track;
-            Settings = settings;
         }
         
         public override void Run()
         {
-            if(Track == null) {
+            if (Track == null || (Track.MediaAttributes & TrackMediaAttributes.Podcast) != 0) {
                 return;
             }
         
-            string album_artist_id = CoverArtSpec.CreateArtistAlbumId(Track.ArtistName, Track.AlbumTitle, false);
+            string artwork_id = Track.ArtworkId;
             
-            if(album_artist_id == null || CoverArtSpec.CoverExists(album_artist_id) || !Settings.NetworkConnected) {
+            if(artwork_id == null || CoverArtSpec.CoverExists(artwork_id) || !NetworkDetect.Instance.Connected) {
                 return;
             }
             
-            Uri data_uri = new Uri(base_uri, String.Format("/{0}/data.xml", album_artist_id.Replace('-', '/')));
+            Uri data_uri = new Uri(base_uri, String.Format("/{0}/data.xml", artwork_id.Replace('-', '/')));
         
             XmlDocument doc = new XmlDocument();
             Stream stream = GetHttpStream(data_uri);
@@ -83,12 +83,12 @@
                 string second_attempt = art_node.Attributes["src"].Value;
                 string first_attempt = second_attempt.Replace("170x170", "500x500");
 
-                if(SaveHttpStreamCover(new Uri(first_attempt), album_artist_id, null) || 
-                    SaveHttpStreamCover(new Uri(second_attempt), album_artist_id, null)) {
-                    Log.Debug ("Downloaded cover art from Rhapsody", album_artist_id);
+                if(SaveHttpStreamCover(new Uri(first_attempt), artwork_id, null) || 
+                    SaveHttpStreamCover(new Uri(second_attempt), artwork_id, null)) {
+                    Log.Debug ("Downloaded cover art from Rhapsody", artwork_id);
                     StreamTag tag = new StreamTag();
                     tag.Name = CommonTags.AlbumCoverId;
-                    tag.Value = album_artist_id;
+                    tag.Value = artwork_id;
                 
                     AddTag(tag);
                 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/BaseMetadataProvider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/BaseMetadataProvider.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/BaseMetadataProvider.cs	Tue May 20 07:01:14 2008
@@ -38,19 +38,17 @@
 {
     public abstract class BaseMetadataProvider : IMetadataProvider
     {
-        private MetadataSettings settings;
-        
         public event MetadataLookupResultHandler HaveResult;
         
         protected BaseMetadataProvider()
         {
         }
         
-        public abstract IMetadataLookupJob CreateJob(IBasicTrackInfo track, MetadataSettings settings);
+        public abstract IMetadataLookupJob CreateJob(IBasicTrackInfo track);
         
         public virtual void Lookup(IBasicTrackInfo track)
         {
-            IMetadataLookupJob job = CreateJob(track, settings);
+            IMetadataLookupJob job = CreateJob(track);
             job.Run();
         }
         
@@ -74,10 +72,5 @@
                     new ReadOnlyCollection<StreamTag>(tags)));
             }
         }
-        
-        public virtual MetadataSettings Settings {
-            get { return settings; }
-            set { settings = value; }
-        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataLookupJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataLookupJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataLookupJob.cs	Tue May 20 07:01:14 2008
@@ -40,6 +40,5 @@
     {
         IBasicTrackInfo Track { get; }
         IList<StreamTag> ResultTags { get; }
-        MetadataSettings Settings { get; set; }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataProvider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataProvider.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/IMetadataProvider.cs	Tue May 20 07:01:14 2008
@@ -61,12 +61,10 @@
     {
         event MetadataLookupResultHandler HaveResult;
         
-        IMetadataLookupJob CreateJob(IBasicTrackInfo track, MetadataSettings settings);
+        IMetadataLookupJob CreateJob(IBasicTrackInfo track);
         
         void Lookup(IBasicTrackInfo track);
         void Cancel(IBasicTrackInfo track);
         void Cancel();
-        
-        MetadataSettings Settings { get; set; }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataService.cs	Tue May 20 07:01:14 2008
@@ -53,7 +53,6 @@
         private Dictionary<IBasicTrackInfo, IMetadataLookupJob> queries 
             = new Dictionary<IBasicTrackInfo, IMetadataLookupJob>();
         private List<IMetadataProvider> providers = new List<IMetadataProvider>();
-        private MetadataSettings settings;
 
         public MetadataService()
         {
@@ -63,13 +62,11 @@
             
             Scheduler.JobFinished += OnSchedulerJobFinished;
             Scheduler.JobUnscheduled += OnSchedulerJobUnscheduled;
-            
-            Settings = new MetadataSettings();
         }
 
-        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track, MetadataSettings settings)
+        public override IMetadataLookupJob CreateJob(IBasicTrackInfo track)
         {
-            return new MetadataServiceJob(this, track, settings);
+            return new MetadataServiceJob(this, track);
         }
         
         public override void Lookup(IBasicTrackInfo track)
@@ -85,7 +82,7 @@
             
             lock(((ICollection)queries).SyncRoot) {
                 if(!queries.ContainsKey(track)) {
-                    IMetadataLookupJob job = CreateJob(track, Settings);
+                    IMetadataLookupJob job = CreateJob(track);
                     if(job == null) {
                         return;
                     }
@@ -143,7 +140,7 @@
             
             IMetadataLookupJob lookup_job = (IMetadataLookupJob)job;
             if(RemoveJob(lookup_job)) {
-                Settings.ProxyToMain(delegate { 
+                Banshee.Base.ThreadAssist.ProxyToMain(delegate { 
                     OnHaveResult(lookup_job.Track, lookup_job.ResultTags); 
                 });
             }
@@ -161,15 +158,5 @@
                 }
             }
         }
-        
-        public override MetadataSettings Settings {
-            get { return settings; }
-            set { 
-                settings = value;
-                foreach(IMetadataProvider provider in providers) {
-                    provider.Settings = value;
-                }
-            }
-        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataServiceJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataServiceJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Metadata/MetadataServiceJob.cs	Tue May 20 07:01:14 2008
@@ -43,32 +43,30 @@
     {
         private MetadataService service;
         private IBasicTrackInfo track;
-        private MetadataSettings settings;
         private List<StreamTag> tags = new List<StreamTag>();
         
         protected MetadataServiceJob()
         {
         }
         
-        public MetadataServiceJob(MetadataService service, IBasicTrackInfo track, MetadataSettings settings)
+        public MetadataServiceJob(MetadataService service, IBasicTrackInfo track)
         {
             this.service = service;
             this.track = track;
-            this.settings = settings;
         }
     
         public virtual void Run()
         {
             foreach(IMetadataProvider provider in service.Providers) {
                 try {
-                    IMetadataLookupJob job = provider.CreateJob(track, settings);
+                    IMetadataLookupJob job = provider.CreateJob(track);
                     job.Run();
                     
                     foreach(StreamTag tag in job.ResultTags) {
                         AddTag(tag);
                     }
-                } catch(Exception) {
-                   // Console.WriteLine(e);
+                } catch(Exception e) {
+                   Hyena.Log.Exception (e);
                 }
             }
         }
@@ -82,11 +80,6 @@
             get { return tags; }
         }
         
-        public virtual MetadataSettings Settings {
-            get { return settings; }
-            set { settings = value; }
-        }
-        
         protected void AddTag(StreamTag tag)
         {
             tags.Add(tag);
@@ -99,7 +92,7 @@
 
         protected Stream GetHttpStream(Uri uri, string [] ignoreMimeTypes)
         {
-            if(!Settings.NetworkConnected) {
+            if(!NetworkDetect.Instance.Connected) {
                 throw new NetworkUnavailableException();
             }
         

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	Tue May 20 07:01:14 2008
@@ -80,7 +80,6 @@
     <File name="Banshee.Metadata/IMetadataProvider.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Metadata/MetadataService.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Metadata/MetadataServiceJob.cs" subtype="Code" buildaction="Compile" />
-    <File name="Banshee.Metadata/MetadataSettings.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Metadata.Embedded/EmbeddedMetadataProvider.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Metadata.Embedded/EmbeddedQueryJob.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Metadata.MusicBrainz/MusicBrainzMetadataProvider.cs" subtype="Code" buildaction="Compile" />

Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am	Tue May 20 07:01:14 2008
@@ -83,7 +83,6 @@
 	Banshee.Metadata/IMetadataProvider.cs \
 	Banshee.Metadata/MetadataService.cs \
 	Banshee.Metadata/MetadataServiceJob.cs \
-	Banshee.Metadata/MetadataSettings.cs \
 	Banshee.Networking/NetworkDetect.cs \
 	Banshee.Networking/NetworkManager.cs \
 	Banshee.PlaybackController/IBasicPlaybackController.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellFileSize.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellFileSize.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellFileSize.cs	Tue May 20 07:01:14 2008
@@ -37,11 +37,12 @@
     {
         public ColumnCellFileSize (string property, bool expand) : base (property, expand)
         {
+            Alignment = Pango.Alignment.Right;
         }
         
         protected override string Text {
             get {
-                return new FileSizeQueryValue ((long) BoundObject).ToUserQuery ();
+                return new FileSizeQueryValue ((long) BoundObject).ToUserQuery (true);
             }
         }
     }

Modified: trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs	Tue May 20 07:01:14 2008
@@ -62,22 +62,37 @@
             
             ServiceManager.PlaybackController.Transition += OnPlaybackControllerTransition;
             ServiceManager.PlaybackController.TrackStarted += OnPlaybackControllerTrackStarted;
+            ServiceManager.PlayerEngine.ConnectEvent (OnTrackInfoUpdated, PlayerEvent.TrackInfoUpdated);
         }
         
         public void Dispose ()
         {
+            ServiceManager.PlaybackController.Transition -= OnPlaybackControllerTransition;
+            ServiceManager.PlaybackController.TrackStarted -= OnPlaybackControllerTrackStarted;
+            ServiceManager.PlayerEngine.DisconnectEvent (OnTrackInfoUpdated);
+
             if (now_playing_interface != null) {
                 now_playing_interface.Destroy ();
                 now_playing_interface = null;
             }
         }
         
+        private void OnTrackInfoUpdated (PlayerEventArgs args)
+        {
+            CheckForSwitch ();
+        }
+        
+        private void OnPlaybackControllerTrackStarted (object o, EventArgs args)
+        {
+            CheckForSwitch ();
+        }
+        
         private void OnPlaybackControllerTransition (object o, EventArgs args)
         {
             transitioned_track = ServiceManager.PlaybackController.CurrentTrack;
         }
         
-        private void OnPlaybackControllerTrackStarted (object o, EventArgs args)
+        private void CheckForSwitch ()
         {
             TrackInfo current_track = ServiceManager.PlaybackController.CurrentTrack;
             if (current_track != null && transitioned_track != current_track && 

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastTrackInfo.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastTrackInfo.cs	Tue May 20 07:01:14 2008
@@ -133,43 +133,6 @@
                 default:
                     return PodcastItemActivity.None;   
                 }
-            
-                /*if (Track != null) {
-                    if (ServiceManager.PlayerEngine.CurrentTrack == Track) {
-                        if (ServiceManager.PlayerEngine.CurrentState == PlayerEngineState.Playing) {
-                            ret = PodcastItemActivity.Playing;
-                        } else if (ServiceManager.PlayerEngine.CurrentState == PlayerEngineState.Paused) {
-                            ret = PodcastItemActivity.Paused;
-                        }
-                    } else {                             
-                        if (New) {
-                            ret = PodcastItemActivity.NewPodcastItem;
-                        } else if ((Track.MediaAttributes & TrackMediaAttributes.VideoStream) != 
-                                    TrackMediaAttributes.None) {
-                            ret = PodcastItemActivity.Video;
-                         } else {
-                            ret = PodcastItemActivity.Downloaded;
-                         }
-                    } 
-                } else {*/
-                    /*switch (Item.Enclosure.DownloadStatus) {
-                    case FeedDownloadStatus.Pending: 
-                        ret = PodcastItemActivity.DownloadPending;
-                        break;
-                    case FeedDownloadStatus.Downloading: 
-                        ret = PodcastItemActivity.Downloading;
-                        break;
-                    case FeedDownloadStatus.Downloaded: 
-                        ret = PodcastItemActivity.Downloaded;
-                        break;    
-                    case FeedDownloadStatus.DownloadFailed: 
-                        ret = PodcastItemActivity.DownloadFailed;
-                        break;  
-                    case FeedDownloadStatus.Paused: 
-                        ret = PodcastItemActivity.DownloadPaused;
-                        break;                        
-                    }*/
-                //}
             }
         }
         
@@ -196,24 +159,26 @@
         public void Delete ()
         {
             Provider.Delete (this);
-            //feed.Delete ();
         }
         
         public void SyncWithFeedItem ()
         {
+            //Console.WriteLine ("Syncing item, enclosure == null? {0}", Item.Enclosure == null);
             ArtistName = Item.Author;
             AlbumTitle = Item.Feed.Title;
             TrackTitle = Item.Title;
             Year = Item.PubDate.Year;
             CanPlay = true;
             Genre = Genre ?? "Podcast";
+            MediaAttributes |= TrackMediaAttributes.Podcast;
             ReleaseDate = Item.PubDate;
             MimeType = Item.Enclosure.MimeType;
             Duration = Item.Enclosure.Duration;
-            FileSize = item.Enclosure.FileSize;
-            Uri = new Banshee.Base.SafeUri (Item.Enclosure.LocalPath ?? item.Enclosure.Url);
+            FileSize = Item.Enclosure.FileSize;
+            LicenseUri = Item.LicenseUri;
+            Uri = new Banshee.Base.SafeUri (Item.Enclosure.LocalPath ?? Item.Enclosure.Url);
             
-            if (!String.IsNullOrEmpty (item.Enclosure.LocalPath)) {
+            if (!String.IsNullOrEmpty (Item.Enclosure.LocalPath)) {
                 TagLib.File file = Banshee.Streaming.StreamTagger.ProcessUri (Uri);
                 Banshee.Streaming.StreamTagger.TrackInfoMerge (this, file, true);
             }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastActions.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastActions.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastActions.cs	Tue May 20 07:01:14 2008
@@ -151,15 +151,16 @@
                 )
             });
             
-            // TODO deleting podcasts is not implemented
-            this ["PodcastDeleteAction"].Sensitive = false;
-            
             actions_id = Actions.UIManager.AddUiFromResource ("GlobalUI.xml");
             Actions.AddActionGroup (this);
 
             ServiceManager.SourceManager.ActiveSourceChanged += HandleActiveSourceChanged;
             
-            source.TrackModel.Selection.Changed += delegate { UpdateActions (); };
+            source.TrackModel.Selection.Changed += delegate { UpdateItemActions (); };
+            source.FeedModel.Selection.Changed += delegate { UpdateFeedActions (); };
+            
+            UpdateFeedActions ();
+            UpdateItemActions ();
         }
 
         public override void Dispose ()
@@ -173,14 +174,15 @@
 
         private void HandleActiveSourceChanged (SourceEventArgs args)
         {
-            UpdateActions ();
+            UpdateFeedActions ();
+            UpdateItemActions ();
         }
 
 #endregion
 
 #region Utility Methods
 
-        private void UpdateActions ()
+        private void UpdateItemActions ()
         {
             if (ServiceManager.SourceManager.ActiveSource == source) {
                 bool has_single_selection = source.TrackModel.Selection.Count == 1;
@@ -190,6 +192,19 @@
             }
         }
         
+        private void UpdateFeedActions ()
+        {
+            if (ServiceManager.SourceManager.ActiveSource == source) {
+                bool has_single_selection = source.FeedModel.Selection.Count == 1;
+                bool all_selected = source.FeedModel.Selection.AllSelected;
+
+                UpdateActions (true, has_single_selection && !all_selected,
+                    "PodcastDeleteAction", "PodcastUpdateFeedAction", "PodcastHomepageAction",
+                    "PodcastPropertiesAction"
+                );
+            }
+        }
+        
         private void SubscribeToPodcast (Uri uri, FeedAutoDownload syncPreference)
         {
             FeedsManager.Instance.FeedManager.CreateFeed (uri.ToString (), syncPreference);
@@ -206,7 +221,10 @@
 
         private void OnFeedPopup (object o, EventArgs args)
         {
-            ShowContextMenu ("/PodcastFeedPopup");
+            if (source.FeedModel.Selection.AllSelected)
+                ShowContextMenu ("/PodcastAllFeedsContextMenu");
+            else
+                ShowContextMenu ("/PodcastFeedPopup");
         }
 
         private void RunSubscribeDialog ()
@@ -364,29 +382,10 @@
         
         private void OnPodcastDelete (object sender, EventArgs e)
         {
-            /*lock (sync) {
-                if (!disposed || disposing) {
-                    bool deleteFeed;
-                    bool deleteFiles;
-                    ReadOnlyCollection<Feed> feeds = source.FeedModel.CopySelectedItems ();
-                    
-                    if (feeds != null) {                    
-                        RunConfirmDeleteDialog (
-                            true, feeds.Count, out deleteFeed, out deleteFiles
-                        );
-                        
-                        
-                        if (deleteFeed) {
-                            source.FeedModel.Selection.Clear ();
-                            source.TrackModel.Selection.Clear ();
-                            
-                            foreach (Feed f in feeds) {
-                                f.Delete (deleteFiles);   
-                            }                                 
-                        }                   
-                    }                    
-                }
-            }*/
+            Feed feed = source.FeedModel.FocusedItem;
+            if (feed != null) {
+                feed.Delete (true);
+            }
         }        
 
         private void OnPodcastItemDeleteFile (object sender, EventArgs e)

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastManager/Source/PodcastSource.cs	Tue May 20 07:01:14 2008
@@ -175,6 +175,14 @@
             AfterInitialized ();
         }
         
+        public override void AddChildSource (Source child)
+        {
+            Hyena.Log.Information ("Playlists and smart playlists are not supported by the Podcast Library, yet", "", true);
+            if (child is IUnmapableSource) {
+                (child as IUnmapableSource).Unmap ();
+            }
+        }
+        
         // Probably don't want this -- do we want to allow actually removing the item?  It will be
         // repopulated the next time we update the podcast feed...
         /*protected override void DeleteTrack (DatabaseTrackInfo track)

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImageFetchJob.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImageFetchJob.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImageFetchJob.cs	Tue May 20 07:01:14 2008
@@ -43,6 +43,7 @@
 using Banshee.Kernel;
 using Banshee.Collection;
 using Banshee.Streaming;
+using Banshee.Networking;
 
 using Banshee.Podcasting.Gui;
 
@@ -50,12 +51,10 @@
 {
     public class PodcastImageFetchJob : MetadataServiceJob
     {
-        private static MetadataSettings settings = new MetadataSettings ();
         private Feed feed;
         
         public PodcastImageFetchJob (Feed feed) : base ()
         {
-            this.Settings = settings;
             this.feed = feed;
         }
         
@@ -76,7 +75,7 @@
                 return;
             } else if (CoverArtSpec.CoverExists (cover_art_id)) {
                 return;
-            } else if (!Settings.NetworkConnected) {
+            } else if (!NetworkDetect.Instance.Connected) {
                 return;
             }
             

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs	Tue May 20 07:01:14 2008
@@ -49,7 +49,7 @@
 
 namespace Banshee.Podcasting
 {
-    public partial class PodcastService : IExtensionService, IDisposable
+    public partial class PodcastService : IExtensionService, IDisposable, IDelayedInitializeService
     {  
         private readonly string tmp_download_path;
         private string tmp_enclosure_path; 
@@ -88,18 +88,20 @@
             ServiceManager.PlayerEngine.ConnectEvent (OnPlayerEvent, PlayerEvent.StateChange);
 
             InitializeInterface ();
-            
-            foreach (Feed feed in Feed.Provider.FetchAll ()) {
-                RefreshArtworkFor (feed);
-            }
-
-            //import_manager = new PodcastImportManager (source);
         }
         
         public void Initialize ()
         {
         }
         
+        public void DelayedInitialize ()
+        {
+            foreach (Feed feed in Feed.Provider.FetchAll ()) {
+                feed.Update ();
+                RefreshArtworkFor (feed);
+            }
+        }
+        
         bool disposing;
         public void Dispose ()
         {                        
@@ -138,16 +140,21 @@
         
         private void RefreshArtworkFor (Feed feed)
         {
-            Banshee.Kernel.Scheduler.Schedule (new PodcastImageFetchJob (feed), Banshee.Kernel.JobPriority.Highest);
+            if (feed.LastDownloadTime != DateTime.MinValue)
+                Banshee.Kernel.Scheduler.Schedule (new PodcastImageFetchJob (feed), Banshee.Kernel.JobPriority.Highest);
         }
         
         private void OnItemAdded (FeedItem item)
         {
-            PodcastTrackInfo track = new PodcastTrackInfo (item);
-            track.PrimarySource = source;
-            track.Save (true);
-            
-            RefreshArtworkFor (item.Feed);
+            if (item.Enclosure != null) {
+                PodcastTrackInfo track = new PodcastTrackInfo (item);
+                track.PrimarySource = source;
+                track.Save (true);
+                RefreshArtworkFor (item.Feed);
+            } else {
+                // We're only interested in items that have enclosures
+                item.Delete (false);
+            }
         }
         
         private void OnItemRemoved (FeedItem item)

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Resources/GlobalUI.xml
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Resources/GlobalUI.xml	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Resources/GlobalUI.xml	Tue May 20 07:01:14 2008
@@ -13,6 +13,11 @@
           <menuitem name="SortChildrenSizeDesc" action="SortChildrenSizeDescAction"/>
         </menu>
     </popup>
+
+    <popup name="PodcastAllFeedsContextMenu" action="PodcastAllFeedsContextMenuAction">
+        <menuitem name="PodcastAdd" action="PodcastAddAction" />
+        <menuitem name="PodcastUpdateAll" action="PodcastUpdateAllAction"/>
+    </popup>
     
     <popup name="PodcastFeedPopup" action="PodcastFeedPopupAction">
         <menuitem name="PodcastUpdateFeed" action="PodcastUpdateFeedAction" />

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs	Tue May 20 07:01:14 2008
@@ -41,6 +41,7 @@
     
         private Pango.Weight font_weight = Pango.Weight.Normal;
         private Pango.EllipsizeMode ellipsize_mode = Pango.EllipsizeMode.End;
+        private Pango.Alignment alignment = Pango.Alignment.Left;
         private int text_width;
         private int text_height;
         
@@ -53,6 +54,7 @@
             context.Layout.Width = (int)((cellWidth - 8) * Pango.Scale.PangoScale);
             context.Layout.FontDescription.Weight = font_weight;
             context.Layout.Ellipsize = EllipsizeMode;
+            context.Layout.Alignment = alignment;
             
             context.Layout.SetText (Text);
             context.Layout.GetPixelSize (out text_width, out text_height);
@@ -79,6 +81,11 @@
             get { return text_height; }
         }
         
+        protected Pango.Alignment Alignment {
+            get { return alignment; }
+            set { alignment = value; }
+        }
+        
         public virtual Pango.Weight FontWeight {
             get { return font_weight; }
             set { font_weight = value; }

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	Tue May 20 07:01:14 2008
@@ -362,8 +362,7 @@
 
         public T FetchFirstMatching (string condition, params object [] vals)
         {
-            foreach (T item in FetchAllMatching (condition, vals)) {
-                // Just return the first result, if there is one
+            foreach (T item in FetchAllMatching (String.Format ("{0} LIMIT 1", condition), vals)) {
                 return item;
             }
             return default(T);
@@ -405,7 +404,7 @@
         
         protected long PrimaryKeyFor (T item)
         {
-            return (long) key.GetValue (item);
+            return Convert.ToInt64 (key.GetValue (item));
         }
         
         protected long PrimaryKeyFor (IDataReader reader)
@@ -413,9 +412,10 @@
             return Convert.ToInt64 (reader[key_select_column_index]);
         }
         
-        public void Delete (long id)
+        public virtual void Delete (long id)
         {
-            connection.Execute (delete_command, id);
+            if (id > 0)
+                connection.Execute (DeleteCommand, id);
         }
         
         public void Delete (T item)
@@ -423,7 +423,7 @@
             Delete (PrimaryKeyFor (item));
         }
         
-        public void Delete (IEnumerable<T> items)
+        public virtual void Delete (IEnumerable<T> items)
         {
             List<long> ids = new List<long> ();
             long id;
@@ -434,7 +434,7 @@
             }
             
             if (ids.Count > 0)
-                connection.Execute (delete_command, ids.ToArray ());
+                connection.Execute (DeleteCommand, ids.ToArray ());
         }
 
         public bool Refresh (T item)

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs	Tue May 20 07:01:14 2008
@@ -111,13 +111,18 @@
                 }
             }
         }
-
+        
         public override string ToUserQuery ()
         {
+            return ToUserQuery (false);
+        }
+
+        public string ToUserQuery (bool always_decimal)
+        {
             if (factor != FileSizeFactor.None) {
                 return String.Format (
                     "{0} {1}",
-                    IntValue == 0 ? "0" : StringUtil.DoubleToTenthsPrecision (((double)IntValue / (double)factor)),
+                    IntValue == 0 ? "0" : StringUtil.DoubleToTenthsPrecision (((double)IntValue / (double)factor), always_decimal),
                     factor.ToString ()
                 );
             } else {

Modified: trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs	Tue May 20 07:01:14 2008
@@ -115,9 +115,16 @@
 
         public static string DoubleToTenthsPrecision (double num)
         {
+            return DoubleToTenthsPrecision (num, false);
+        }
+        
+        public static string DoubleToTenthsPrecision (double num, bool always_decimal)
+        {
             num = Math.Round (num, 1, MidpointRounding.ToEven);
             return String.Format (
-                num == (int)num ? "{0:N0}" : "{0:N1}", num
+                !always_decimal && num == (int)num 
+                    ? "{0:N0}" : "{0:N1}",
+                num
             );
         }
         

Modified: trunk/banshee/src/Libraries/Migo/Makefile.am
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Makefile.am	(original)
+++ trunk/banshee/src/Libraries/Migo/Makefile.am	Tue May 20 07:01:14 2008
@@ -40,8 +40,6 @@
 	Migo/Migo.Syndication/OpmlParser.cs \
 	Migo/Migo.Syndication/Rfc822DateTime.cs \
 	Migo/Migo.Syndication/RssParser.cs \
-	Migo/Migo.Syndication/Tests/XmlTests.cs \
-	Migo/Migo.Syndication/XmlUtils.cs \
 	Migo/Migo.TaskCore/AsyncCommandQueue/AsyncCommandQueue.cs \
 	Migo/Migo.TaskCore/AsyncCommandQueue/CommandDelegate.cs \
 	Migo/Migo.TaskCore/AsyncCommandQueue/CommandWrapper.cs \

Modified: trunk/banshee/src/Libraries/Migo/Migo.mdp
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo.mdp	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo.mdp	Tue May 20 07:01:14 2008
@@ -68,7 +68,6 @@
     <File name="Migo/Migo.TaskCore/TaskGroup.cs" subtype="Code" buildaction="Compile" />
     <File name="Migo/Migo.Syndication/RssParser.cs" subtype="Code" buildaction="Compile" />
     <File name="Migo/Migo.Syndication/Rfc822DateTime.cs" subtype="Code" buildaction="Compile" />
-    <File name="Migo/Migo.Syndication/XmlUtils.cs" subtype="Code" buildaction="Compile" />
     <File name="Migo/Migo.Syndication/FeedManager.cs" subtype="Code" buildaction="Compile" />
     <File name="Migo/Migo.Syndication/EnclosureManager.cs" subtype="Code" buildaction="Compile" />
     <File name="Migo/Migo.Syndication/MigoItem.cs" subtype="Code" buildaction="Compile" />

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/Feed.cs	Tue May 20 07:01:14 2008
@@ -83,15 +83,12 @@
         
         //private ManualResetEvent updatingHandle = new ManualResetEvent (true);
         
-        private readonly object sync = new object ();     
-        
-        private List<FeedItem> items;
+        private readonly object sync = new object ();
         
         private string copyright;
         private string description;
-        private bool downloadEnclosuresAutomatically;
-        private string image;        
-        private long interval;
+        private string image_url;
+        private int update_period_minutes = 24 * 60;
         private string language;
         private DateTime last_build_date = DateTime.MinValue;
         private FeedDownloadError lastDownloadError;
@@ -103,7 +100,6 @@
         private DateTime pubDate;
         private FeedSyncSetting syncSetting;
         private string title;
-        private long ttl;
         private string url;
         private string keywords, category;
         
@@ -152,23 +148,15 @@
         }
         
         [DatabaseColumn]
-        public bool DownloadEnclosuresAutomatically { 
-            get { return downloadEnclosuresAutomatically; }
-            set { downloadEnclosuresAutomatically = value; }
-        } 
-        
-        [DatabaseColumn]
         public string ImageUrl {
-            get { return image; }
-            set { image = value; }
+            get { return image_url; }
+            set { image_url = value; }
         }
 
         [DatabaseColumn]
-        public long Interval { 
-            get { return interval; }
-            set { 
-                interval = (value < 15) ? 1440 : value;
-            } 
+        public int UpdatePeriodMinutes { 
+            get { return update_period_minutes; }
+            set { update_period_minutes = value; } 
         }
         
         [DatabaseColumn]
@@ -251,12 +239,6 @@
                 CheckForItemsToDownload ();
             }
         }
-              
-        [DatabaseColumn]
-        public long Ttl {
-            get { return ttl; }
-            set { ttl = value; }
-        }
         
         [DatabaseColumn("DownloadStatus")]
         private FeedDownloadStatus download_status;
@@ -331,7 +313,6 @@
 
         public Feed ()
         {
-            items = new List<FeedItem> ();
         }
         
 #endregion
@@ -379,11 +360,15 @@
         
         private bool AddItem (FeedItem item)
         {
+            try {
             if (!FeedItem.Exists (item.Guid)) {
                 item.Feed = this;
                 item.Save ();
                 return true;
             }
+            } catch (Exception e) {
+                Hyena.Log.Exception (e);
+            }
             return false;
         }
         
@@ -470,6 +455,7 @@
 
 #region Public Methods
 
+
         public void Update ()
         {
             Manager.QueueUpdate (this);
@@ -491,11 +477,10 @@
                     Manager.CancelUpdate (this);                 
                 }
 
-                foreach (FeedItem item in items) {
+                foreach (FeedItem item in Items) {
                     item.Delete (deleteEnclosures);
                 }
-                
-                //items_dirty = true;
+
                 Provider.Delete (this);
             }
             
@@ -506,7 +491,7 @@
         public void MarkAllItemsRead ()
         {
             lock (sync) {
-                foreach (FeedItem i in items) {
+                foreach (FeedItem i in Items) {
                     i.IsRead = true;
                 }
             }
@@ -537,7 +522,9 @@
             
             bool any = false;
             foreach (FeedItem item in Items) {
-                if (item.Active && item.Enclosure.DownloadStatus != FeedDownloadStatus.Downloaded && item.PubDate > LastAutoDownload) {
+                if (item.Enclosure != null && item.Active && 
+                    item.Enclosure.DownloadStatus != FeedDownloadStatus.Downloaded && item.PubDate > LastAutoDownload)
+                {
                     item.Enclosure.AsyncDownload ();
                     any = true;
                     if (only_first)

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedEnclosure.cs	Tue May 20 07:01:14 2008
@@ -69,14 +69,12 @@
 #region Public Properties
 
         public FeedItem Item { 
-            get { return item; } 
-            internal set {          
-                if (value == null) {
-                	throw new ArgumentNullException ("Parent");
-                }
-
+            get { return item ?? item = FeedItem.Provider.FetchSingle (item_id); } 
+            internal set {
                 item = value;
-                item_id = value.DbId;
+                if (item != null && item.DbId > 0) {
+                    item_id = item.DbId;
+                }
             }
         }
 
@@ -97,8 +95,9 @@
         {
             Provider.Save (this);
             
-            if (save_item)
+            if (save_item) {
                 Item.Save ();
+            }
         }
         
         public void Save ()
@@ -232,7 +231,7 @@
         [DatabaseColumn ("ItemID")]
         protected long item_id;
         public long ItemId {
-            get { return item_id; }
+            get { return Item.DbId; }
         }
         
         [DatabaseColumn]
@@ -300,5 +299,9 @@
 
 #endregion
 
+        public override string ToString ()
+        {
+            return String.Format ("FeedEnclosure<DbId: {0}, Url: {1}>", DbId, Url);
+        }
     }
 }

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/FeedItem.cs	Tue May 20 07:01:14 2008
@@ -119,11 +119,12 @@
         [DatabaseColumn]
         public bool IsRead {
             get { return isRead; }
-            set {          
-                if (isRead != value) {
+            set {
+                isRead = value;
+                /*if (isRead != value) {
                     isRead = value;
                     Save ();
-                }                                         
+                }*/                                        
             }
         }
         
@@ -150,6 +151,13 @@
             get { return title; } 
             set { title = value; }
         }
+        
+        [DatabaseColumn("LicenseUri")]
+        protected string license_uri;
+        public string LicenseUri {
+            get { return license_uri; }
+            set { license_uri = value; }
+        }
 
 #endregion
 
@@ -166,10 +174,17 @@
         }
 
         public FeedEnclosure Enclosure {
-            get { LoadEnclosure (); return enclosure; }
+            get {
+                if (enclosure == null) {
+                    LoadEnclosure ();
+                }
+                return enclosure;
+            }
             internal set {
                 enclosure = value;
-                enclosure.Item = this;
+                enclosure_loaded = true;
+                if (enclosure != null)
+                    enclosure.Item = this;
             }
         }
         
@@ -209,7 +224,7 @@
             if (enclosure != null) {
                 enclosure.Delete (delete_file);
             }
-            
+
             Provider.Delete (this);
             Manager.OnItemRemoved (this);
         }
@@ -220,18 +235,16 @@
         private void LoadEnclosure ()
         {
             if (!enclosure_loaded && DbId > 0) {
-                IEnumerable<FeedEnclosure> enclosures = FeedEnclosure.Provider.FetchAllMatching (String.Format (
+                FeedEnclosure enclosure = FeedEnclosure.Provider.FetchFirstMatching (String.Format (
                     "{0}.ItemID = {1}", FeedEnclosure.Provider.TableName, DbId
                 ));
                 
-                foreach (FeedEnclosure enclosure in enclosures) {
+                if (enclosure != null) {
                     enclosure.Item = this;
                     this.enclosure = enclosure;
-                    break; // should only have one
                 }
-                enclosure_loaded = true;
+                enclosure_loaded = true; 
             }
         }
-
     }
 }

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/MigoModelProvider.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/MigoModelProvider.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/MigoModelProvider.cs	Tue May 20 07:01:14 2008
@@ -65,22 +65,17 @@
             }
         }
         
-        public new void Delete (long id)
+        public override void Delete (long id)
         {
             full_cache.Remove (id);
             base.Delete (id);
         }
         
-        public new void Delete (T item)
-        {
-            full_cache.Remove (PrimaryKeyFor (item));
-            base.Delete (item);
-        }
-        
-        public new void Delete (IEnumerable<T> items)
+        public override void Delete (IEnumerable<T> items)
         {
             foreach (T item in items) {
-                full_cache.Remove (PrimaryKeyFor (item));
+                if (item != null)
+                    full_cache.Remove (PrimaryKeyFor (item));
             }
                 
             base.Delete (items);

Modified: trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/RssParser.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/RssParser.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo/Migo.Syndication/RssParser.cs	Tue May 20 07:01:14 2008
@@ -37,7 +37,7 @@
     public class RssParser
     {
         private XmlDocument doc;
-        private XmlNamespaceManager ns_mgr;
+        private XmlNamespaceManager mgr;
         
         public RssParser (string url, string xml)
         {
@@ -64,25 +64,23 @@
         public Feed UpdateFeed (Feed feed)
         {
             try {
-                feed.Title            = XmlUtils.GetXmlNodeText (doc, "/rss/channel/title");
-                feed.Description      = XmlUtils.GetXmlNodeText (doc, "/rss/channel/description");
-                feed.Copyright        = XmlUtils.GetXmlNodeText (doc, "/rss/channel/copyright");
-                feed.ImageUrl         = XmlUtils.GetXmlNodeText (doc, "/rss/channel/itunes:image/@href", ns_mgr);
+                feed.Title            = GetXmlNodeText (doc, "/rss/channel/title");
+                feed.Description      = GetXmlNodeText (doc, "/rss/channel/description");
+                feed.Copyright        = GetXmlNodeText (doc, "/rss/channel/copyright");
+                feed.ImageUrl         = GetXmlNodeText (doc, "/rss/channel/itunes:image/@href");
                 if (String.IsNullOrEmpty (feed.ImageUrl)) {
-                    feed.ImageUrl = XmlUtils.GetXmlNodeText (doc, "/rss/channel/image/url");
+                    feed.ImageUrl = GetXmlNodeText (doc, "/rss/channel/image/url");
                 }
-                feed.Interval         = XmlUtils.GetInt64 (doc, "/rss/channel/interval"); 
-                feed.Language         = XmlUtils.GetXmlNodeText (doc, "/rss/channel/language");
-                feed.LastBuildDate    = XmlUtils.GetRfc822DateTime (doc, "/rss/channel/lastBuildDate");
-                feed.Link             = XmlUtils.GetXmlNodeText (doc, "/rss/channel/link"); 
-                feed.PubDate          = XmlUtils.GetRfc822DateTime (doc, "/rss/channel/pubDate");
-                feed.Ttl              = XmlUtils.GetInt64 (doc, "/rss/channel/ttl");
-                feed.Keywords         = XmlUtils.GetXmlNodeText (doc, "/rss/channel/itunes:keywords", ns_mgr);
-                feed.Category         = XmlUtils.GetXmlNodeText (doc, "/rss/channel/itunes:category/@text", ns_mgr);
+                feed.Language         = GetXmlNodeText (doc, "/rss/channel/language");
+                feed.LastBuildDate    = GetRfc822DateTime (doc, "/rss/channel/lastBuildDate");
+                feed.Link             = GetXmlNodeText (doc, "/rss/channel/link"); 
+                feed.PubDate          = GetRfc822DateTime (doc, "/rss/channel/pubDate");
+                feed.Keywords         = GetXmlNodeText (doc, "/rss/channel/itunes:keywords");
+                feed.Category         = GetXmlNodeText (doc, "/rss/channel/itunes:category/@text");
                 
                 return feed;
             } catch (Exception e) {
-                 Hyena.Log.Exception (e);
+                 Hyena.Log.Exception ("Caught error parsing RSS channel", e);
             }
              
             return null;
@@ -94,7 +92,7 @@
             try {
                 nodes = doc.SelectNodes ("//item");
             } catch (Exception e) {
-                Hyena.Log.Exception (e);
+                Hyena.Log.Exception ("Unable to get any RSS items", e);
             }
             
             if (nodes != null) {
@@ -103,58 +101,112 @@
                     
                     try {
                         item = ParseItem (node);
+                        if (item != null) {
+                            item.Feed = feed;
+                        }
                     } catch (Exception e) {
                         Hyena.Log.Exception (e);
                     }
                     
                     if (item != null) {
-                        item.Feed = feed;
                         yield return item;
                     }
                 }
             }
         }
         
-        public FeedItem ParseItem (XmlNode node)
+        private FeedItem ParseItem (XmlNode node)
         {
             try {
                 FeedItem item = new FeedItem ();
-                item.Description = XmlUtils.GetXmlNodeText (node, "description");                        
-                item.Title = XmlUtils.GetXmlNodeText (node, "title");                        
+                item.Description = GetXmlNodeText (node, "description");                        
+                item.Title = GetXmlNodeText (node, "title");                        
             
                 if (String.IsNullOrEmpty (item.Description) && String.IsNullOrEmpty (item.Title)) {
                     throw new FormatException ("node:  Either 'title' or 'description' node must exist.");
                 }
                 
-                item.Author            = XmlUtils.GetXmlNodeText (node, "author");
-                item.Comments          = XmlUtils.GetXmlNodeText (node, "comments");
-                item.Guid              = XmlUtils.GetXmlNodeText (node, "guid");
-                item.Link              = XmlUtils.GetXmlNodeText (node, "link");
-                item.Modified          = XmlUtils.GetRfc822DateTime (node, "dcterms:modified");
-                item.PubDate           = XmlUtils.GetRfc822DateTime (node, "pubDate");
-                
-                item.Enclosure = ParseEnclosure (node);
+                item.Author            = GetXmlNodeText (node, "author");
+                item.Comments          = GetXmlNodeText (node, "comments");
+                item.Guid              = GetXmlNodeText (node, "guid");
+                item.Link              = GetXmlNodeText (node, "link");
+                item.PubDate           = GetRfc822DateTime (node, "pubDate");
+                item.Modified          = GetRfc822DateTime (node, "dcterms:modified");
+                item.LicenseUri        = GetXmlNodeText (node, "creativeCommons:license");
+
+                // TODO prefer <media:content> nodes over <enclosure>?
+                item.Enclosure = ParseEnclosure (node) ?? ParseMediaContent (node);
                 
                 return item;
              } catch (Exception e) {
-                 Hyena.Log.Exception (e);
+                 Hyena.Log.Exception ("Caught error parsing RSS item", e);
              }
              
              return null;
         }
         
-        public FeedEnclosure ParseEnclosure (XmlNode node)
+        private FeedEnclosure ParseEnclosure (XmlNode node)
         {
             try {
                 FeedEnclosure enclosure = new FeedEnclosure ();
-                enclosure.Url = XmlUtils.GetXmlNodeText (node, "enclosure/@url");
-                enclosure.FileSize = Math.Max (0, XmlUtils.GetInt64 (node, "enclosure/@length"));
-                enclosure.MimeType = XmlUtils.GetXmlNodeText (node, "enclosure/@type");
-                enclosure.Duration = XmlUtils.GetITunesDuration (node, ns_mgr);
-                enclosure.Keywords = XmlUtils.GetXmlNodeText (node, "itunes:keywords", ns_mgr);
+
+                enclosure.Url = GetXmlNodeText (node, "enclosure/@url");
+                if (enclosure.Url == null)
+                    return null;
+                
+                enclosure.FileSize = Math.Max (0, GetInt64 (node, "enclosure/@length"));
+                enclosure.MimeType = GetXmlNodeText (node, "enclosure/@type");
+                enclosure.Duration = GetITunesDuration (node);
+                enclosure.Keywords = GetXmlNodeText (node, "itunes:keywords");
                 return enclosure;
              } catch (Exception e) {
-                 Hyena.Log.Exception (e);
+                 Hyena.Log.Exception ("Caught error parsing RSS enclosure", e);
+             }
+             
+             return null;
+        }
+        
+        // Parse one Media RSS media:content node
+        // http://search.yahoo.com/mrss/
+        private FeedEnclosure ParseMediaContent (XmlNode item_node)
+        {
+            try {
+                XmlNode node = null;
+                
+                // Get the highest bitrate "full" content item
+                // TODO allow a user-preference for a feed to decide what quality to get, if there
+                // are options?
+                int max_bitrate = 0;
+                foreach (XmlNode test_node in item_node.SelectNodes ("media:content", mgr)) {
+                    string expr = GetXmlNodeText (test_node, "@expression");
+                    if (!(String.IsNullOrEmpty (expr) || expr == "full"))
+                        continue;
+                    
+                    int bitrate = GetInt32 (test_node, "@bitrate");
+                    if (node == null || bitrate > max_bitrate) {
+                        node = test_node;
+                        max_bitrate = bitrate;
+                    }
+                }
+                
+                if (node == null)
+                    return null;
+                    
+                FeedEnclosure enclosure = new FeedEnclosure ();
+                enclosure.Url = GetXmlNodeText (node, "@url");
+                if (enclosure.Url == null)
+                    return null;
+                
+                enclosure.FileSize = Math.Max (0, GetInt64 (node, "@fileSize"));
+                enclosure.MimeType = GetXmlNodeText (node, "@type");
+                enclosure.Duration = TimeSpan.FromSeconds (GetInt64 (node, "@duration"));
+                enclosure.Keywords = GetXmlNodeText (item_node, "itunes:keywords");
+                
+                // TODO get the thumbnail URL
+                
+                return enclosure;
+             } catch (Exception e) {
+                 Hyena.Log.Exception ("Caught error parsing RSS media:content", e);
              }
              
              return null;
@@ -163,17 +215,92 @@
         private void CheckRss ()
         {            
             if (doc.SelectSingleNode ("/rss") == null) {
-                throw new FormatException ("Invalid rss document.");                                  
+                throw new FormatException ("Invalid RSS document.");
             }
             
-            if (XmlUtils.GetXmlNodeText (doc, "/rss/channel/title") == String.Empty) {
+            if (GetXmlNodeText (doc, "/rss/channel/title") == String.Empty) {
                 throw new FormatException (
                     "node: 'title', 'description', and 'link' nodes must exist."
                 );                
             }
             
-            ns_mgr = XmlUtils.GetNamespaceManager (doc);
-            ns_mgr.AddNamespace ("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd";);
+            mgr = new XmlNamespaceManager (doc.NameTable);
+            mgr.AddNamespace ("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd";);
+            mgr.AddNamespace ("creativeCommons", "http://backend.userland.com/creativeCommonsRssModule";);
+            mgr.AddNamespace ("media", "http://search.yahoo.com/mrss/";);
+            mgr.AddNamespace ("dcterms", "http://purl.org/dc/terms/";);
+        }
+        
+        public TimeSpan GetITunesDuration (XmlNode node)
+        {
+            return GetITunesDuration (GetXmlNodeText (node, "itunes:duration"));
+        }
+        
+        public static TimeSpan GetITunesDuration (string duration)
+        {
+            if (String.IsNullOrEmpty (duration)) {
+                return TimeSpan.Zero;
+            }
+
+            int hours = 0, minutes = 0, seconds = 0;
+            string [] parts = duration.Split (':');
+            
+            if (parts.Length > 0)
+                seconds = Int32.Parse (parts[parts.Length - 1]);
+                
+            if (parts.Length > 1)
+                minutes = Int32.Parse (parts[parts.Length - 2]);
+                
+            if (parts.Length > 2)
+                hours = Int32.Parse (parts[parts.Length - 3]);
+            
+            return TimeSpan.FromSeconds (hours * 3600 + minutes * 60 + seconds);
+        }
+
+#region Xml Convienience Methods
+    
+        public string GetXmlNodeText (XmlNode node, string tag)
+        {
+            XmlNode n = node.SelectSingleNode (tag, mgr);
+            return (n == null) ? null : n.InnerText.Trim ();
+        }
+        
+        public DateTime GetRfc822DateTime (XmlNode node, string tag)
+        {
+            DateTime ret = DateTime.MinValue;
+            string result = GetXmlNodeText (node, tag);
+
+            if (!String.IsNullOrEmpty (result)) {
+                Rfc822DateTime.TryParse (result, out ret);
+            }
+                    
+            return ret;              
+        }
+        
+        public long GetInt64 (XmlNode node, string tag)
+        {
+            long ret = 0;
+            string result = GetXmlNodeText (node, tag);
+
+            if (!String.IsNullOrEmpty (result)) {
+                Int64.TryParse (result, out ret);
+            }
+                    
+            return ret;              
+        }
+
+        public int GetInt32 (XmlNode node, string tag)
+        {
+            int ret = 0;
+            string result = GetXmlNodeText (node, tag);
+
+            if (!String.IsNullOrEmpty (result)) {
+                Int32.TryParse (result, out ret);
+            }
+                    
+            return ret;              
         }
+
+#endregion
     }
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]