home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / databaseupgrade.py < prev    next >
Encoding:
Python Source  |  2007-11-12  |  30.3 KB  |  877 lines

  1. # Miro - an RSS based video player application
  2. # Copyright (C) 2005-2007 Participatory Culture Foundation
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  17.  
  18. """Responsible for upgrading old versions of the database.
  19.  
  20. NOTE: For really old versions (before the schema.py module, see
  21. olddatabaseupgrade.py)
  22. """
  23.  
  24. import schema
  25. import util
  26. import types
  27. from urlparse import urlparse
  28. from storedatabase import SavableObject
  29. import config
  30. import prefs
  31.  
  32. class DatabaseTooNewError(Exception):
  33.     """Error that we raise when we see a database that is newer than the
  34.     version that we can update too.
  35.     """
  36.     pass
  37.  
  38. def upgrade(savedObjects, saveVersion, upgradeTo=None):
  39.     """Upgrade a list of SavableObjects that were saved using an old version 
  40.     of the database schema.
  41.  
  42.     This method will call upgradeX for each number X between saveVersion and
  43.     upgradeTo.  For example, if saveVersion is 2 and upgradeTo is 4, this
  44.     method is equivelant to:
  45.  
  46.         upgrade3(savedObjects)
  47.         upgrade4(savedObjects)
  48.  
  49.     By default, upgradeTo will be the VERSION variable in schema.
  50.     """
  51.  
  52.     changed = set()
  53.  
  54.     if upgradeTo is None:
  55.         upgradeTo = schema.VERSION
  56.  
  57.     if saveVersion > upgradeTo:
  58.         msg = ("Database was created by a newer version of Miro " 
  59.                "(db version is %s)" % saveVersion)
  60.         raise DatabaseTooNewError(msg)
  61.  
  62.     while saveVersion < upgradeTo:
  63.         if util.chatter:
  64.             print "upgrading database to version %s" % (saveVersion + 1)
  65.         upgradeFunc = globals()['upgrade%d' % (saveVersion + 1)]
  66.         thisChanged = upgradeFunc(savedObjects)
  67.         if thisChanged is None or changed is None:
  68.             changed = None
  69.         else:
  70.             changed.update (thisChanged)
  71.         saveVersion += 1
  72.     return changed
  73.  
  74. def upgrade2(objectList):
  75.     """Add a dlerType variable to all RemoteDownloader objects."""
  76.  
  77.     for o in objectList:
  78.         if o.classString == 'remote-downloader':
  79.             # many of our old attributes are now stored in status
  80.             o.savedData['status'] = {}
  81.             for key in ('startTime', 'endTime', 'filename', 'state',
  82.                     'currentSize', 'totalSize', 'reasonFailed'):
  83.                 o.savedData['status'][key] = o.savedData[key]
  84.                 del o.savedData[key]
  85.             # force the download daemon to create a new downloader object.
  86.             o.savedData['dlid'] = 'noid'
  87.  
  88. def upgrade3(objectList):
  89.     """Add the expireTime variable to FeedImpl objects."""
  90.  
  91.     for o in objectList:
  92.         if o.classString == 'feed':
  93.             feedImpl = o.savedData['actualFeed']
  94.             if feedImpl is not None:
  95.                 feedImpl.savedData['expireTime'] = None
  96.  
  97. def upgrade4(objectList):
  98.     """Add iconCache variables to all Item objects."""
  99.     for o in objectList:
  100.         if o.classString in ['item', 'file-item', 'feed']:
  101.             o.savedData['iconCache'] = None
  102.  
  103. def upgrade5(objectList):
  104.     """Upgrade metainfo from old BitTorrent format to BitTornado format"""
  105.     for o in objectList:
  106.         if o.classString == 'remote-downloader':
  107.             if o.savedData['status'].has_key('metainfo'):
  108.                 o.savedData['status']['metainfo'] = None
  109.                 o.savedData['status']['infohash'] = None
  110.  
  111. def upgrade6(objectList):
  112.     """Add downloadedTime to items."""
  113.     for o in objectList:
  114.         if o.classString in ('item', 'file-item'):
  115.             o.savedData['downloadedTime'] = None
  116.  
  117. def upgrade7(objectList):
  118.     """Add the initialUpdate variable to FeedImpl objects."""
  119.     for o in objectList:
  120.         if o.classString == 'feed':
  121.             feedImpl = o.savedData['actualFeed']
  122.             if feedImpl is not None:
  123.                 feedImpl.savedData['initialUpdate'] = False
  124.  
  125. def upgrade8(objectList):
  126.     """Have items point to feed_id instead of feed."""
  127.     for o in objectList:
  128.         if o.classString in ('item', 'file-item'):
  129.             o.savedData['feed_id'] = o.savedData['feed'].savedData['id']
  130.             
  131. def upgrade9(objectList):
  132.     """Added the deleted field to file items"""
  133.     for o in objectList:
  134.         if o.classString == 'file-item':
  135.             o.savedData['deleted'] = False
  136.  
  137. def upgrade10(objectList):
  138.     """Add a watchedTime attribute to items.  Since we don't know when that
  139.     was, we use the downloaded time which matches with our old behaviour.
  140.     """
  141.  
  142.     import datetime
  143.     changed = set()
  144.     for o in objectList:
  145.         if o.classString in ('item', 'file-item'):
  146.             if o.savedData['seen']:
  147.                 o.savedData['watchedTime'] = o.savedData['downloadedTime']
  148.             else:
  149.                 o.savedData['watchedTime'] = None
  150.             changed.add(o)
  151.     return changed
  152.  
  153. def upgrade11(objectList):
  154.     """We dropped the loadedThisSession field from ChannelGuide.  No need to
  155.     change anything for this."""
  156.     return set()
  157.  
  158. def upgrade12(objectList):
  159.     import filetypes
  160.     from datetime import datetime
  161.     changed = set()
  162.     for o in objectList:
  163.         if o.classString in ('item', 'file-item'):
  164.             if not o.savedData.has_key('releaseDateObj'):
  165.                 try:
  166.                     enclosures = o.savedData['entry'].enclosures
  167.                     for enc in enclosures:
  168.                         if filetypes.isVideoEnclosure(enc):
  169.                             enclosure = enc
  170.                             break
  171.                     o.savedData['releaseDateObj'] = datetime(*enclosure.updated_parsed[0:7])
  172.                 except:
  173.                     try:
  174.                         o.savedData['releaseDateObj'] = datetime(*o.savedData['entry'].updated_parsed[0:7])
  175.                     except:
  176.                         o.savedData['releaseDateObj'] = datetime.min
  177.                 changed.add(o)
  178.     return changed
  179.  
  180. def upgrade13(objectList):
  181.     """Add an isContainerItem field.  Computing this requires reading
  182.     through files and we need to do this check anyway in onRestore, in
  183.     case it has only been half done."""
  184.     changed = set()
  185.     todelete = []
  186.     for i in xrange (len(objectList) - 1, -1, -1):
  187.         o = objectList [i]
  188.         if o.classString in ('item', 'file-item'):
  189.             if o.savedData['feed_id'] == None:
  190.                 del objectList[i]
  191.             else:
  192.                 o.savedData['isContainerItem'] = None
  193.                 o.savedData['parent_id'] = None
  194.                 o.savedData['videoFilename'] = ""
  195.             changed.add(o)
  196.     return changed
  197.  
  198. def upgrade14(objectList):
  199.     """Add default and url fields to channel guide."""
  200.     changed = set()
  201.     todelete = []
  202.     for o in objectList:
  203.         if o.classString == 'channel-guide':
  204.             o.savedData['url'] = None
  205.             changed.add(o)
  206.     return changed
  207.  
  208. def upgrade15(objectList):
  209.     """In the unlikely event that someone has a playlist around, change items
  210.     to item_ids."""
  211.     changed = set()
  212.     for o in objectList:
  213.         if o.classString == 'playlist':
  214.             o.savedData['item_ids'] = o.savedData['items']
  215.             changed.add(o)
  216.     return changed
  217.  
  218. def upgrade16(objectList):
  219.     changed = set()
  220.     for o in objectList:
  221.         if o.classString == 'file-item':
  222.             o.savedData['shortFilename'] = None
  223.             changed.add(o)
  224.     return changed
  225.  
  226. def upgrade17(objectList):
  227.     """Add folder_id attributes to Feed and SavedPlaylist.  Add item_ids
  228.     attribute to PlaylistFolder.
  229.     """
  230.     changed = set()
  231.     for o in objectList:
  232.         if o.classString in ('feed', 'playlist'):
  233.             o.savedData['folder_id'] = None
  234.             changed.add(o)
  235.         elif o.classString == 'playlist-folder':
  236.             o.savedData['item_ids'] = []
  237.             changed.add(o)
  238.     return changed
  239.  
  240. def upgrade18(objectList):
  241.     """Add shortReasonFailed to RemoteDownloader status dicts. """
  242.  
  243.     changed = set()
  244.     for o in objectList:
  245.         if o.classString == 'remote-downloader':
  246.             o.savedData['status']['shortReasonFailed'] = \
  247.                     o.savedData['status']['reasonFailed']
  248.             changed.add(o)
  249.     return changed
  250.  
  251. def upgrade19(objectList):
  252.     """Add origURL to RemoteDownloaders"""
  253.  
  254.     changed = set()
  255.     for o in objectList:
  256.         if o.classString == 'remote-downloader':
  257.             o.savedData['origURL'] = o.savedData['url']
  258.             changed.add(o)
  259.     return changed
  260.  
  261. def upgrade20(objectList):
  262.     """Add redirectedURL to Guides"""
  263.  
  264.     changed = set()
  265.     for o in objectList:
  266.         if o.classString == 'channel-guide':
  267.             o.savedData['redirectedURL'] = None
  268.             # set cachedGuideBody to None, to force us to update redirectedURL
  269.             o.savedData['cachedGuideBody'] = None
  270.             changed.add(o)
  271.     return changed
  272.  
  273. def upgrade21(objectList):
  274.     """Add searchTerm to Feeds"""
  275.  
  276.     changed = set()
  277.     for o in objectList:
  278.         if o.classString == 'feed':
  279.             o.savedData['searchTerm'] = None
  280.             changed.add(o)
  281.     return changed
  282.  
  283. def upgrade22(objectList):
  284.     """Add userTitle to Feeds"""
  285.  
  286.     changed = set()
  287.     for o in objectList:
  288.         if o.classString == 'feed':
  289.             o.savedData['userTitle'] = None
  290.             changed.add(o)
  291.     return changed
  292.  
  293. def upgrade23(objectList):
  294.     """Remove container items from playlists."""
  295.  
  296.     changed = set()
  297.     toFilter = set()
  298.     playlists = set()
  299.     for o in objectList:
  300.         if o.classString in ('playlist', 'playlist-folder'):
  301.             playlists.add(o)
  302.         elif (o.classString in ('item', 'file-item') and 
  303.                 o.savedData['isContainerItem']):
  304.             toFilter.add(o.savedData['id'])
  305.     for p in playlists:
  306.         filtered = [id for id in p.savedData['item_ids'] if id not in toFilter]
  307.         if len(filtered) != len(p.savedData['item_ids']):
  308.             changed.add(p)
  309.             p.savedData['item_ids'] = filtered
  310.     return changed
  311.  
  312. def upgrade24(objectList):
  313.     """Upgrade metainfo back to BitTorrent format."""
  314.     for o in objectList:
  315.         if o.classString == 'remote-downloader':
  316.             if o.savedData['status'].has_key('metainfo'):
  317.                 o.savedData['status']['metainfo'] = None
  318.                 o.savedData['status']['infohash'] = None
  319.  
  320. def upgrade25(objectList):
  321.     """Remove container items from playlists."""
  322.  
  323.     from datetime import datetime
  324.  
  325.     changed = set()
  326.     startfroms = {}
  327.     for o in objectList:
  328.         if o.classString == 'feed':
  329.             startfroms[o.savedData['id']] = o.savedData['actualFeed'].savedData['startfrom']
  330.     for o in objectList:
  331.         if o.classString == 'item':
  332.             pubDate = o.savedData['releaseDateObj']
  333.             feed_id = o.savedData['feed_id']
  334.             if feed_id is not None and startfroms.has_key(feed_id):
  335.                 o.savedData['eligibleForAutoDownload'] = pubDate != datetime.max and pubDate >= startfroms[feed_id]
  336.             else:
  337.                 o.savedData['eligibleForAutoDownload'] = False
  338.             changed.add(o)
  339.         if o.classString == 'file-item':
  340.             o.savedData['eligibleForAutoDownload'] = True
  341.             changed.add(o)
  342.     return changed
  343.  
  344. def upgrade26(objectList):
  345.     changed = set()
  346.     for o in objectList:
  347.         if o.classString == 'feed':
  348.             feedImpl = o.savedData['actualFeed']
  349.             for field in ('autoDownloadable', 'getEverything', 'maxNew', 'fallBehind', 'expire', 'expireTime'):
  350.                 o.savedData[field] = feedImpl.savedData[field]
  351.             changed.add(o)
  352.     return changed
  353.  
  354. def upgrade27(objectList):
  355.     """We dropped the sawIntro field from ChannelGuide.  No need to change
  356.     anything for this."""
  357.     return set()
  358.  
  359. def upgrade28(objectList):
  360.     import filetypes
  361.     objectList.sort(key=lambda o:o.savedData['id'])
  362.     changed = set()
  363.     items = set()
  364.     removed = set()
  365.  
  366.     def getFirstVideoEnclosure(entry):
  367.         """Find the first video enclosure in a feedparser entry.  Returns the
  368.         enclosure, or None if no video enclosure is found.
  369.         """
  370.         try:
  371.             enclosures = entry.enclosures
  372.         except (KeyError, AttributeError):
  373.             return None
  374.         for enclosure in enclosures:
  375.             if filetypes.isVideoEnclosure(enclosure):
  376.                 return enclosure
  377.         return None
  378.     
  379.     for i in xrange (len(objectList) - 1, -1, -1):
  380.         o = objectList [i]
  381.         if o.classString == 'item':
  382.             entry = o.savedData['entry']
  383.             videoEnc = getFirstVideoEnclosure(entry)
  384.             if videoEnc is not None:
  385.                 entryURL = videoEnc.get('url')
  386.             else:
  387.                 entryURL = None
  388.             title = entry.get("title")
  389.             feed_id = o.savedData['feed_id']
  390.             if title is not None or entryURL is not None:
  391.                 if (feed_id, entryURL, title) in items:
  392.                     removed.add (o.savedData['id'])
  393.                     changed.add(o)
  394.                     del objectList[i]
  395.                 else:
  396.                     items.add((feed_id, entryURL, title))
  397.  
  398.     for i in xrange (len(objectList) - 1, -1, -1):
  399.         o = objectList [i]
  400.         if o.classString == 'file-item':
  401.             if o.savedData['parent_id'] in removed:
  402.                 changed.add(o)
  403.                 del objectList[i]
  404.     return changed
  405.  
  406. def upgrade29(objectList):
  407.     changed = set()
  408.     for o in objectList:
  409.         if o.classString == 'guide':
  410.             o.savedData['default'] = (o.savedData['url'] is None)
  411.             changed.add(o)
  412.     return changed
  413.  
  414. def upgrade30(objectList):
  415.     changed = set()
  416.     for o in objectList:
  417.         if o.classString == 'guide':
  418.             if o.savedData['default']:
  419.                 o.savedData['url'] = None
  420.                 changed.add(o)
  421.     return changed
  422.  
  423. def upgrade31(objectList):
  424.     changed = set()
  425.     for o in objectList:
  426.         if o.classString == 'remote-downloader':
  427.             o.savedData['status']['retryTime'] = None
  428.             o.savedData['status']['retryCount'] = -1
  429.             changed.add(o)
  430.     return changed
  431.  
  432. def upgrade32(objectList):
  433.     changed = set()
  434.     for o in objectList:
  435.         if o.classString == 'remote-downloader':
  436.             o.savedData['channelName'] = None
  437.             changed.add(o)
  438.     return changed
  439.  
  440. def upgrade33(objectList):
  441.     changed = set()
  442.     for o in objectList:
  443.         if o.classString == 'remote-downloader':
  444.             o.savedData['duration'] = None
  445.             changed.add(o)
  446.     return changed
  447.  
  448. def upgrade34(objectList):
  449.     changed = set()
  450.     for o in objectList:
  451.         if o.classString in ('item', 'file-item'):
  452.             o.savedData['duration'] = None
  453.             changed.add(o)
  454.     return changed
  455.  
  456. def upgrade35(objectList):
  457.     changed = set()
  458.     for o in objectList:
  459.         if o.classString in ('item', 'file-item'):
  460.             if hasattr(o.savedData,'entry'):
  461.                 entry = o.savedData['entry']
  462.                 if entry.has_key('title') and type(entry.title) != types.UnicodeType:
  463.                     entry.title = entry.title.decode('utf-8', 'replace')
  464.                     changed.add(o)
  465.     return changed
  466.  
  467. def upgrade36(objectList):
  468.     changed = set()
  469.     for o in objectList:
  470.         if o.classString == 'remote-downloader':
  471.             o.savedData['manualUpload'] = False
  472.             changed.add(o)
  473.     return changed
  474.  
  475. def upgrade37(objectList):
  476.     changed = set()
  477.     removed = set()
  478.     id = 0
  479.     for o in objectList:
  480.         if o.classString == 'feed':
  481.             feedImpl = o.savedData['actualFeed']
  482.             if feedImpl.classString == 'directory-feed-impl':
  483.                 id = o.savedData['id']
  484.                 break
  485.  
  486.     if id == 0:
  487.         return changed
  488.  
  489.     for i in xrange (len(objectList) - 1, -1, -1):
  490.         o = objectList [i]
  491.         if o.classString == 'file-item' and o.savedData['feed_id'] == id:
  492.             removed.add (o.savedData['id'])
  493.             changed.add(o)
  494.             del objectList[i]
  495.  
  496.     for i in xrange (len(objectList) - 1, -1, -1):
  497.         o = objectList [i]
  498.         if o.classString == 'file-item':
  499.             if o.savedData['parent_id'] in removed:
  500.                 changed.add(o)
  501.                 del objectList[i]
  502.     return changed
  503.  
  504. def upgrade38(objectList):
  505.     changed = set()
  506.     for o in objectList:
  507.         if o.classString == 'remote-downloader':
  508.             try:
  509.                 if o.savedData['status']['channelName']:
  510.                     o.savedData['status']['channelName'] = o.savedData['status']['channelName'].translate({ ord('/')  : u'-',
  511.                                                                                                             ord('\\') : u'-',
  512.                                                                                                             ord(':')  : u'-' })
  513.                     changed.add(o)
  514.             except:
  515.                 pass
  516.     return changed
  517.  
  518. def upgrade39(objectList):
  519.     changed = set()
  520.     removed = set()
  521.     id = 0
  522.     for i in xrange (len(objectList) - 1, -1, -1):
  523.         o = objectList [i]
  524.         if o.classString in ('item', 'file-item'):
  525.             changed.add(o)
  526.             if o.savedData['parent_id']:
  527.                 del objectList[i]
  528.             else:
  529.                 o.savedData['isVideo'] = False
  530.                 o.savedData['videoFilename'] = ""
  531.                 o.savedData['isContainerItem'] = None
  532.                 if o.classString == 'file-item':
  533.                     o.savedData['offsetPath'] = None
  534.     return changed
  535.  
  536. def upgrade40(objectList):
  537.     changed = set()
  538.     for o in objectList:
  539.         if o.classString in ('item', 'file-item'):
  540.             o.savedData['resumeTime'] = 0
  541.             changed.add(o)
  542.     return changed
  543.  
  544. # Turns all strings in data structure to unicode, used by upgrade 41 and 47
  545. def unicodify(d):
  546.     from feedparser import FeedParserDict
  547.     from types import StringType
  548.     if isinstance(d, FeedParserDict):
  549.         for key in d.keys():
  550.             try:
  551.                 d[key] = unicodify(d[key])
  552.             except KeyError:
  553.                 # Feedparser dicts sometime return names in keys() that can't
  554.                 # actually be used in keys.  I guess the best thing to do here
  555.                 # is ignore it -- Ben
  556.                 pass
  557.     elif isinstance(d, dict):
  558.         for key in d.keys():
  559.             d[key] = unicodify(d[key])
  560.     elif isinstance(d, list):
  561.         for key in range(len(d)):
  562.             d[key] = unicodify(d[key])
  563.     elif type(d) == StringType:
  564.         d = d.decode('ascii','replace')
  565.     return d
  566.  
  567. def upgrade41(objectList):
  568.     from platformutils import FilenameType
  569.     # This is where John Lennon's ghost sings "Binary Fields Forever"
  570.     if FilenameType == str:
  571.         binaryFields = ['filename','videoFilename', 'shortFilename',
  572.                         'offsetPath','initialHTML','status','channelName']
  573.         icStrings = ['etag','modified','url']
  574.         icBinary = ['filename']
  575.         statusBinary = ['channelName','shortFilename','filename','metainfo']
  576.     else:
  577.         binaryFields = ['initialHTML','status']
  578.         icStrings = ['etag','modified','url','filename']
  579.         icBinary = []
  580.         statusBinary = ['metainfo']
  581.         
  582.     changed = set()
  583.     for o in objectList:
  584.         o.savedData = unicodify(o.savedData)
  585.         for field in o.savedData:
  586.             if field not in binaryFields:
  587.                 o.savedData[field] = unicodify(o.savedData[field])
  588.  
  589.                 # These get skipped because they're a level lower
  590.                 if field == 'actualFeed':
  591.                     o.savedData[field].__dict__ = \
  592.                          unicodify(o.savedData[field].__dict__)
  593.                 elif (field == 'iconCache' and
  594.                       o.savedData['iconCache'] is not None):
  595.                     for icfield in icStrings:
  596.                         o.savedData['iconCache'].savedData[icfield] = \
  597.                           unicodify(o.savedData['iconCache'].savedData[icfield])
  598.                     for icfield in icBinary:
  599.                         if (type(o.savedData['iconCache'].savedData[icfield])
  600.                                == unicode):
  601.                             o.savedData['iconCache'].savedData[icfield] =\
  602.                                o.savedData['iconCache'].savedData[icfield].encode('ascii','replace')
  603.  
  604.             else:
  605.                 if field == 'status':
  606.                     for subfield in o.savedData['status']:
  607.                         if (type(o.savedData[field][subfield]) == unicode
  608.                             and subfield in statusBinary):
  609.                                 o.savedData[field][subfield] = \
  610.                              o.savedData[field][subfield].encode('ascii',
  611.                                                                  'replace')
  612.                         elif (type(o.savedData[field][subfield]) == str
  613.                             and subfield not in statusBinary):
  614.                                 o.savedData[field][subfield] = \
  615.                              o.savedData[field][subfield].decode('ascii',
  616.                                                                  'replace')
  617.                 elif type(o.savedData[field]) == unicode:
  618.                     o.savedData[field] = o.savedData[field].encode('ascii','replace')
  619.         if o.classString == 'channel-guide':
  620.             del o.savedData['cachedGuideBody']
  621.         changed.add(o)
  622.     return changed
  623.  
  624. def upgrade42(objectList):
  625.     changed = set()
  626.     for o in objectList:
  627.         if o.classString in ('item', 'file-item'):
  628.             o.savedData['screenshot'] = None
  629.             changed.add(o)
  630.     return changed
  631.  
  632. def upgrade43(objectList):
  633.     changed = set()
  634.     removed = set()
  635.     id = 0
  636.     for i in xrange (len(objectList) - 1, -1, -1):
  637.         o = objectList [i]
  638.         if o.classString == 'feed':
  639.             feedImpl = o.savedData['actualFeed']
  640.             if feedImpl.classString == 'manual-feed-impl':
  641.                 id = o.savedData['id']
  642.                 break
  643.  
  644.     for i in xrange (len(objectList) - 1, -1, -1):
  645.         o = objectList [i]
  646.         if o.classString == 'file-item' and o.savedData['feed_id'] == id and o.savedData['deleted'] == True:
  647.             removed.add (o.savedData['id'])
  648.             changed.add(o)
  649.             del objectList[i]
  650.  
  651.     for i in xrange (len(objectList) - 1, -1, -1):
  652.         o = objectList [i]
  653.         if o.classString == 'file-item':
  654.             if o.savedData['parent_id'] in removed:
  655.                 changed.add(o)
  656.                 del objectList[i]
  657.     return changed
  658.  
  659. def upgrade44(objectList):
  660.     changed = set()
  661.     for o in objectList:
  662.         if 'iconCache' in o.savedData and o.savedData['iconCache'] is not None:
  663.             iconCache = o.savedData['iconCache']
  664.             iconCache.savedData['resized_filenames'] = {}
  665.             changed.add(o)
  666.     return changed
  667.  
  668. def upgrade45(objectList):
  669.     """Dropped the ChannelGuide.redirected URL attribute.  Just need to bump
  670.     the db version number."""
  671.     return set()
  672.  
  673. def upgrade46(objectList):
  674.     """fastResumeData should be str, not unicode."""
  675.     changed = set()
  676.     for o in objectList:
  677.         if o.classString == 'remote-downloader':
  678.             try:
  679.                 if type (o.savedData['status']['fastResumeData']) == unicode:
  680.                     o.savedData['status']['fastResumeData'] = o.savedData['status']['fastResumeData'].encode('ascii','replace')
  681.                 changed.add(o)
  682.             except:
  683.                 pass
  684.     return changed
  685.  
  686. def upgrade47(objectList):
  687.     """Parsed item entries must be unicode"""
  688.     changed = set()
  689.     for o in objectList:
  690.         if o.classString == 'item':
  691.             o.savedData['entry'] = unicodify(o.savedData['entry'])
  692.             changed.add(o)
  693.     return changed
  694.  
  695. def upgrade48(objectList):
  696.     changed = set()
  697.     removed = set()
  698.     ids = set()
  699.     for o in objectList:
  700.         if o.classString == 'feed':
  701.             feedImpl = o.savedData['actualFeed']
  702.             if feedImpl.classString == 'directory-watch-feed-impl':
  703.                 ids.add (o.savedData['id'])
  704.  
  705.     if len(ids) == 0:
  706.         return changed
  707.  
  708.     for i in xrange (len(objectList) - 1, -1, -1):
  709.         o = objectList [i]
  710.         if o.classString == 'file-item' and o.savedData['feed_id'] in ids:
  711.             removed.add (o.savedData['id'])
  712.             changed.add(o)
  713.             del objectList[i]
  714.  
  715.     for i in xrange (len(objectList) - 1, -1, -1):
  716.         o = objectList [i]
  717.         if o.classString == 'file-item':
  718.             if o.savedData['parent_id'] in removed:
  719.                 changed.add(o)
  720.                 del objectList[i]
  721.     return changed
  722.  
  723. upgrade49 = upgrade42
  724.  
  725. def upgrade50(objectList):
  726.     """Parsed item entries must be unicode"""
  727.     changed = set()
  728.     for o in objectList:
  729.         if o.classString in ('item', 'file-item'):
  730.             if o.savedData['videoFilename'] and o.savedData['videoFilename'][0] == '\\':
  731.                 o.savedData['videoFilename'] = o.savedData['videoFilename'][1:]
  732.                 changed.add(o)
  733.     return changed
  734.  
  735. def upgrade51(objectList):
  736.     """Added title field to channel guides"""
  737.     changed = set()
  738.     for o in objectList:
  739.         if o.classString in ('channel-guide'):
  740.             o.savedData['title'] = None
  741.             changed.add(o)
  742.     return changed
  743.  
  744. def upgrade52(objectList):
  745.     import filetypes
  746.     changed = set()
  747.     removed = set()
  748.     search_id = 0
  749.     downloads_id = 0
  750.  
  751.     def getVideoInfo(o):
  752.         """Find the first video enclosure in a feedparser entry.  Returns the
  753.         enclosure, or None if no video enclosure is found.
  754.         """
  755.         entry = o.savedData['entry']
  756.         enc = None
  757.         try:
  758.             enclosures = entry.enclosures
  759.         except (KeyError, AttributeError):
  760.             pass
  761.         else:
  762.             for enclosure in enclosures:
  763.                 if filetypes.isVideoEnclosure(enclosure):
  764.                     enc = enclosure
  765.         if enc is not None:
  766.             url = enc.get('url')
  767.         else:
  768.             url = None
  769.         id = entry.get('id')
  770.         id = entry.get('guid', id)
  771.         title = entry.get('title')
  772.         return (url, id, title)
  773.  
  774.  
  775.     for o in objectList:
  776.         if o.classString == 'feed':
  777.             feedImpl = o.savedData['actualFeed']
  778.             if feedImpl.classString == 'search-feed-impl':
  779.                 search_id = o.savedData['id']
  780.             elif feedImpl.classString == 'search-downloads-feed-impl':
  781.                 downloads_id = o.savedData['id']
  782.  
  783.     items_by_idURL = {}
  784.     items_by_titleURL = {}
  785.     if search_id != 0:
  786.         for o in objectList:
  787.             if o.classString == 'item':
  788.                 if o.savedData['feed_id'] == search_id:
  789.                     (url, id, title) = getVideoInfo(o)
  790.                     if url and id:
  791.                         items_by_idURL[(id, url)] = o
  792.                     if url and title:
  793.                         items_by_titleURL[(title, url)] = o
  794.     if downloads_id != 0:
  795.         for i in xrange (len(objectList) - 1, -1, -1):
  796.             o = objectList [i]
  797.             if o.classString == 'item':
  798.                 if o.savedData['feed_id'] == downloads_id:
  799.                     remove = False
  800.                     (url, id, title) = getVideoInfo(o)
  801.                     if url and id:
  802.                         if items_by_idURL.has_key((id, url)):
  803.                             remove = True
  804.                         else:
  805.                             items_by_idURL[(id, url)] = o
  806.                     if url and title:
  807.                         if items_by_titleURL.has_key((title, url)):
  808.                             remove = True
  809.                         else:
  810.                             items_by_titleURL[(title, url)] = o
  811.                     if remove:
  812.                         removed.add (o.savedData['id'])
  813.                         changed.add(o)
  814.                         del objectList[i]
  815.  
  816.         for i in xrange (len(objectList) - 1, -1, -1):
  817.             o = objectList [i]
  818.             if o.classString == 'file-item':
  819.                 if o.savedData['parent_id'] in removed:
  820.                     changed.add(o)
  821.                     del objectList[i]
  822.     return changed
  823.  
  824. def upgrade53(objectList):
  825.     """Added favicon and icon cache field to channel guides"""
  826.     changed = set()
  827.     for o in objectList:
  828.         if o.classString in ('channel-guide'):
  829.             o.savedData['favicon'] = None
  830.             o.savedData['iconCache'] = None
  831.             o.savedData['updated_url'] = o.savedData['url']
  832.             changed.add(o)
  833.     return changed
  834.  
  835. def upgrade54(objectList):
  836.     changed = set()
  837.     if config.get(prefs.APP_PLATFORM) != "windows-xul":
  838.         return changed
  839.     for o in objectList:
  840.         if o.classString in ('item', 'file-item'):
  841.             o.savedData['screenshot'] = None
  842.             o.savedData['duration'] = None
  843.             changed.add(o)
  844.     return changed
  845.  
  846. def upgrade55(objectList):
  847.     """Add resized_screenshots attribute. """
  848.     changed = set()
  849.     for o in objectList:
  850.         if o.classString in ('item', 'file-item'):
  851.             o.savedData['resized_screenshots'] = {}
  852.             changed.add(o)
  853.     return changed
  854.  
  855. def upgrade56(objectList):
  856.     """Added firstTime field to channel guides"""
  857.     changed = set()
  858.     for o in objectList:
  859.         if o.classString in ('channel-guide'):
  860.             o.savedData['firstTime'] = False
  861.             changed.add(o)
  862.     return changed
  863.         
  864. def upgrade57(objectList):
  865.     """Added ThemeHistory"""
  866.     changed = set()
  867.     return changed
  868.         
  869. #def upgradeX (objectList):
  870. #    """ upgrade an object list to X.  return set of changed savables. """
  871. #    changed = set()
  872. #    for o in objectList:
  873. #        if objectneedschange:
  874. #            changeObject()
  875. #            changed.add(o)
  876. #    return changed
  877.