PageRenderTime 56ms CodeModel.GetById 3ms app.highlight 43ms RepoModel.GetById 2ms app.codeStats 0ms

/gdata/youtube/service.py

http://radioappz.googlecode.com/
Python | 1563 lines | 1510 code | 15 blank | 38 comment | 1 complexity | 5736947e06cf5174243c579adba11b1d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1#!/usr/bin/python
   2#
   3# Copyright (C) 2008 Google Inc.
   4#
   5# Licensed under the Apache License, Version 2.0 (the "License");
   6# you may not use this file except in compliance with the License.
   7# You may obtain a copy of the License at
   8#
   9#      http://www.apache.org/licenses/LICENSE-2.0
  10#
  11# Unless required by applicable law or agreed to in writing, software
  12# distributed under the License is distributed on an "AS IS" BASIS,
  13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14# See the License for the specific language governing permissions and
  15# limitations under the License.
  16
  17"""YouTubeService extends GDataService to streamline YouTube operations.
  18
  19  YouTubeService: Provides methods to perform CRUD operations on YouTube feeds.
  20  Extends GDataService.
  21"""
  22
  23__author__ = ('api.stephaniel@gmail.com (Stephanie Liu), '
  24              'api.jhartmann@gmail.com (Jochen Hartmann)')
  25
  26try:
  27  from xml.etree import cElementTree as ElementTree
  28except ImportError:
  29  try:
  30    import cElementTree as ElementTree
  31  except ImportError:
  32    try:
  33      from xml.etree import ElementTree
  34    except ImportError:
  35      from elementtree import ElementTree
  36import os
  37import atom
  38import gdata
  39import gdata.service
  40import gdata.youtube
  41
  42YOUTUBE_SERVER = 'gdata.youtube.com'
  43YOUTUBE_SERVICE = 'youtube'
  44YOUTUBE_CLIENTLOGIN_AUTHENTICATION_URL = 'https://www.google.com/youtube/accounts/ClientLogin'
  45YOUTUBE_SUPPORTED_UPLOAD_TYPES = ('mov', 'avi', 'wmv', 'mpg', 'quicktime',
  46                                  'flv', 'mp4', 'x-flv')
  47YOUTUBE_QUERY_VALID_TIME_PARAMETERS = ('today', 'this_week', 'this_month',
  48                                       'all_time')
  49YOUTUBE_QUERY_VALID_ORDERBY_PARAMETERS = ('published', 'viewCount', 'rating',
  50                                          'relevance')
  51YOUTUBE_QUERY_VALID_RACY_PARAMETERS = ('include', 'exclude')
  52YOUTUBE_QUERY_VALID_FORMAT_PARAMETERS = ('1', '5', '6')
  53YOUTUBE_STANDARDFEEDS = ('most_recent', 'recently_featured',
  54                         'top_rated', 'most_viewed','watch_on_mobile')
  55YOUTUBE_UPLOAD_URI = 'http://uploads.gdata.youtube.com/feeds/api/users'
  56YOUTUBE_UPLOAD_TOKEN_URI = 'http://gdata.youtube.com/action/GetUploadToken'
  57YOUTUBE_VIDEO_URI = 'http://gdata.youtube.com/feeds/api/videos'
  58YOUTUBE_USER_FEED_URI = 'http://gdata.youtube.com/feeds/api/users'
  59YOUTUBE_PLAYLIST_FEED_URI = 'http://gdata.youtube.com/feeds/api/playlists'
  60
  61YOUTUBE_STANDARD_FEEDS = 'http://gdata.youtube.com/feeds/api/standardfeeds'
  62YOUTUBE_STANDARD_TOP_RATED_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS, 'top_rated')
  63YOUTUBE_STANDARD_MOST_VIEWED_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  64    'most_viewed')
  65YOUTUBE_STANDARD_RECENTLY_FEATURED_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  66    'recently_featured')
  67YOUTUBE_STANDARD_WATCH_ON_MOBILE_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  68    'watch_on_mobile')
  69YOUTUBE_STANDARD_TOP_FAVORITES_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  70    'top_favorites')
  71YOUTUBE_STANDARD_MOST_RECENT_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  72    'most_recent')
  73YOUTUBE_STANDARD_MOST_DISCUSSED_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  74    'most_discussed')
  75YOUTUBE_STANDARD_MOST_LINKED_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  76    'most_linked')
  77YOUTUBE_STANDARD_MOST_RESPONDED_URI = '%s/%s' % (YOUTUBE_STANDARD_FEEDS,
  78    'most_responded')
  79YOUTUBE_SCHEMA = 'http://gdata.youtube.com/schemas'
  80
  81YOUTUBE_RATING_LINK_REL = '%s#video.ratings' % YOUTUBE_SCHEMA
  82
  83YOUTUBE_COMPLAINT_CATEGORY_SCHEME = '%s/%s' % (YOUTUBE_SCHEMA,
  84                                               'complaint-reasons.cat')
  85YOUTUBE_SUBSCRIPTION_CATEGORY_SCHEME = '%s/%s' % (YOUTUBE_SCHEMA,
  86                                                  'subscriptiontypes.cat')
  87
  88YOUTUBE_COMPLAINT_CATEGORY_TERMS = ('PORN', 'VIOLENCE', 'HATE', 'DANGEROUS',
  89                                    'RIGHTS', 'SPAM')
  90YOUTUBE_CONTACT_STATUS = ('accepted', 'rejected')
  91YOUTUBE_CONTACT_CATEGORY = ('Friends', 'Family')
  92
  93UNKOWN_ERROR = 1000
  94YOUTUBE_BAD_REQUEST = 400
  95YOUTUBE_CONFLICT = 409
  96YOUTUBE_INTERNAL_SERVER_ERROR = 500
  97YOUTUBE_INVALID_ARGUMENT = 601
  98YOUTUBE_INVALID_CONTENT_TYPE = 602
  99YOUTUBE_NOT_A_VIDEO = 603
 100YOUTUBE_INVALID_KIND = 604
 101
 102
 103class Error(Exception):
 104  """Base class for errors within the YouTube service."""
 105  pass
 106
 107class RequestError(Error):
 108  """Error class that is thrown in response to an invalid HTTP Request."""
 109  pass
 110
 111class YouTubeError(Error):
 112  """YouTube service specific error class."""
 113  pass
 114
 115class YouTubeService(gdata.service.GDataService):
 116
 117  """Client for the YouTube service.
 118
 119  Performs all documented Google Data YouTube API functions, such as inserting,
 120  updating and deleting videos, comments, playlist, subscriptions etc.
 121  YouTube Service requires authentication for any write, update or delete
 122  actions.
 123
 124  Attributes:
 125    email: An optional string identifying the user. Required only for
 126        authenticated actions.
 127    password: An optional string identifying the user's password.
 128    source: An optional string identifying the name of your application.
 129    server: An optional address of the YouTube API server. gdata.youtube.com 
 130        is provided as the default value.
 131    additional_headers: An optional dictionary containing additional headers
 132        to be passed along with each request. Use to store developer key.
 133    client_id: An optional string identifying your application, required for   
 134        authenticated requests, along with a developer key.
 135    developer_key: An optional string value. Register your application at
 136        http://code.google.com/apis/youtube/dashboard to obtain a (free) key.
 137  """
 138
 139  def __init__(self, email=None, password=None, source=None,
 140               server=YOUTUBE_SERVER, additional_headers=None, client_id=None,
 141               developer_key=None, **kwargs):
 142    """Creates a client for the YouTube service.
 143
 144    Args:
 145      email: string (optional) The user's email address, used for
 146          authentication.
 147      password: string (optional) The user's password.
 148      source: string (optional) The name of the user's application.
 149      server: string (optional) The name of the server to which a connection
 150          will be opened. Default value: 'gdata.youtube.com'.
 151      client_id: string (optional) Identifies your application, required for
 152          authenticated requests, along with a developer key.
 153      developer_key: string (optional) Register your application at
 154          http://code.google.com/apis/youtube/dashboard to obtain a (free) key.
 155      **kwargs: The other parameters to pass to gdata.service.GDataService
 156          constructor.
 157    """
 158
 159    gdata.service.GDataService.__init__(
 160        self, email=email, password=password, service=YOUTUBE_SERVICE,
 161        source=source, server=server, additional_headers=additional_headers,
 162        **kwargs)
 163
 164    if client_id is not None:
 165      self.additional_headers['X-Gdata-Client'] = client_id
 166
 167    if developer_key is not None:
 168      self.additional_headers['X-GData-Key'] = 'key=%s' % developer_key
 169
 170    self.auth_service_url = YOUTUBE_CLIENTLOGIN_AUTHENTICATION_URL
 171
 172  def GetYouTubeVideoFeed(self, uri):
 173    """Retrieve a YouTubeVideoFeed.
 174
 175    Args:
 176      uri: A string representing the URI of the feed that is to be retrieved.
 177
 178    Returns:
 179      A YouTubeVideoFeed if successfully retrieved.
 180    """
 181    return self.Get(uri, converter=gdata.youtube.YouTubeVideoFeedFromString)
 182
 183  def GetYouTubeVideoEntry(self, uri=None, video_id=None):
 184    """Retrieve a YouTubeVideoEntry.
 185
 186    Either a uri or a video_id must be provided.
 187
 188    Args:
 189      uri: An optional string representing the URI of the entry that is to 
 190          be retrieved.
 191      video_id: An optional string representing the ID of the video.
 192
 193    Returns:
 194      A YouTubeVideoFeed if successfully retrieved.
 195
 196    Raises:
 197      YouTubeError: You must provide at least a uri or a video_id to the
 198          GetYouTubeVideoEntry() method.
 199    """
 200    if uri is None and video_id is None:
 201      raise YouTubeError('You must provide at least a uri or a video_id '
 202                         'to the GetYouTubeVideoEntry() method')
 203    elif video_id and not uri:
 204      uri = '%s/%s' % (YOUTUBE_VIDEO_URI, video_id)
 205    return self.Get(uri, converter=gdata.youtube.YouTubeVideoEntryFromString)
 206
 207  def GetYouTubeContactFeed(self, uri=None, username='default'):
 208    """Retrieve a YouTubeContactFeed.
 209
 210    Either a uri or a username must be provided.
 211
 212    Args:
 213      uri: An optional string representing the URI of the contact feed that
 214          is to be retrieved.
 215      username: An optional string representing the username. Defaults to the
 216          currently authenticated user.
 217
 218    Returns:
 219      A YouTubeContactFeed if successfully retrieved.
 220
 221    Raises:
 222      YouTubeError: You must provide at least a uri or a username to the
 223          GetYouTubeContactFeed() method.
 224    """
 225    if uri is None:
 226      uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, username, 'contacts')
 227    return self.Get(uri, converter=gdata.youtube.YouTubeContactFeedFromString)
 228
 229  def GetYouTubeContactEntry(self, uri):
 230    """Retrieve a YouTubeContactEntry.
 231
 232    Args:
 233      uri: A string representing the URI of the contact entry that is to
 234          be retrieved.
 235
 236    Returns:
 237      A YouTubeContactEntry if successfully retrieved.
 238    """
 239    return self.Get(uri, converter=gdata.youtube.YouTubeContactEntryFromString)
 240
 241  def GetYouTubeVideoCommentFeed(self, uri=None, video_id=None):
 242    """Retrieve a YouTubeVideoCommentFeed.
 243
 244    Either a uri or a video_id must be provided.
 245
 246    Args:
 247      uri: An optional string representing the URI of the comment feed that
 248          is to be retrieved.
 249      video_id: An optional string representing the ID of the video for which
 250          to retrieve the comment feed.
 251
 252    Returns:
 253      A YouTubeVideoCommentFeed if successfully retrieved.
 254
 255    Raises:
 256      YouTubeError: You must provide at least a uri or a video_id to the
 257          GetYouTubeVideoCommentFeed() method.
 258    """
 259    if uri is None and video_id is None:
 260      raise YouTubeError('You must provide at least a uri or a video_id '
 261                         'to the GetYouTubeVideoCommentFeed() method')
 262    elif video_id and not uri:
 263      uri = '%s/%s/%s' % (YOUTUBE_VIDEO_URI, video_id, 'comments')
 264    return self.Get(
 265        uri, converter=gdata.youtube.YouTubeVideoCommentFeedFromString)
 266
 267  def GetYouTubeVideoCommentEntry(self, uri):
 268    """Retrieve a YouTubeVideoCommentEntry.
 269
 270    Args:
 271      uri: A string representing the URI of the comment entry that is to
 272          be retrieved.
 273
 274    Returns:
 275      A YouTubeCommentEntry if successfully retrieved.
 276    """
 277    return self.Get(
 278        uri, converter=gdata.youtube.YouTubeVideoCommentEntryFromString)
 279
 280  def GetYouTubeUserFeed(self, uri=None, username=None):
 281    """Retrieve a YouTubeVideoFeed of user uploaded videos
 282
 283    Either a uri or a username must be provided.  This will retrieve list
 284    of videos uploaded by specified user.  The uri will be of format
 285    "http://gdata.youtube.com/feeds/api/users/{username}/uploads".
 286
 287    Args:
 288      uri: An optional string representing the URI of the user feed that is
 289          to be retrieved.
 290      username: An optional string representing the username.
 291
 292    Returns:
 293      A YouTubeUserFeed if successfully retrieved.
 294
 295    Raises:
 296      YouTubeError: You must provide at least a uri or a username to the
 297          GetYouTubeUserFeed() method.
 298    """
 299    if uri is None and username is None:
 300      raise YouTubeError('You must provide at least a uri or a username '
 301                         'to the GetYouTubeUserFeed() method')
 302    elif username and not uri:
 303      uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, username, 'uploads')
 304    return self.Get(uri, converter=gdata.youtube.YouTubeUserFeedFromString)
 305
 306  def GetYouTubeUserEntry(self, uri=None, username=None):
 307    """Retrieve a YouTubeUserEntry.
 308
 309    Either a uri or a username must be provided.
 310
 311    Args:
 312      uri: An optional string representing the URI of the user entry that is
 313          to be retrieved.
 314      username: An optional string representing the username.
 315
 316    Returns:
 317      A YouTubeUserEntry if successfully retrieved.
 318
 319    Raises:
 320      YouTubeError: You must provide at least a uri or a username to the
 321          GetYouTubeUserEntry() method.
 322    """
 323    if uri is None and username is None:
 324      raise YouTubeError('You must provide at least a uri or a username '
 325                         'to the GetYouTubeUserEntry() method')
 326    elif username and not uri:
 327      uri = '%s/%s' % (YOUTUBE_USER_FEED_URI, username)
 328    return self.Get(uri, converter=gdata.youtube.YouTubeUserEntryFromString)
 329
 330  def GetYouTubePlaylistFeed(self, uri=None, username='default'):
 331    """Retrieve a YouTubePlaylistFeed (a feed of playlists for a user).
 332
 333    Either a uri or a username must be provided.
 334
 335    Args:
 336      uri: An optional string representing the URI of the playlist feed that
 337          is to be retrieved.
 338      username: An optional string representing the username. Defaults to the
 339          currently authenticated user.
 340
 341    Returns:
 342      A YouTubePlaylistFeed if successfully retrieved.
 343
 344    Raises:
 345      YouTubeError: You must provide at least a uri or a username to the
 346          GetYouTubePlaylistFeed() method.
 347    """
 348    if uri is None:
 349      uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, username, 'playlists')
 350    return self.Get(uri, converter=gdata.youtube.YouTubePlaylistFeedFromString)
 351
 352  def GetYouTubePlaylistEntry(self, uri):
 353    """Retrieve a YouTubePlaylistEntry.
 354
 355    Args:
 356      uri: A string representing the URI of the playlist feed that is to
 357          be retrieved.
 358
 359    Returns:
 360      A YouTubePlaylistEntry if successfully retrieved.
 361    """
 362    return self.Get(uri, converter=gdata.youtube.YouTubePlaylistEntryFromString)
 363
 364  def GetYouTubePlaylistVideoFeed(self, uri=None, playlist_id=None):
 365    """Retrieve a YouTubePlaylistVideoFeed (a feed of videos on a playlist).
 366
 367    Either a uri or a playlist_id must be provided.
 368
 369    Args:
 370      uri: An optional string representing the URI of the playlist video feed
 371          that is to be retrieved.
 372      playlist_id: An optional string representing the Id of the playlist whose
 373          playlist video feed is to be retrieved.
 374
 375    Returns:
 376      A YouTubePlaylistVideoFeed if successfully retrieved.
 377
 378    Raises:
 379      YouTubeError: You must provide at least a uri or a playlist_id to the
 380          GetYouTubePlaylistVideoFeed() method.
 381    """
 382    if uri is None and playlist_id is None:
 383      raise YouTubeError('You must provide at least a uri or a playlist_id '
 384                         'to the GetYouTubePlaylistVideoFeed() method')
 385    elif playlist_id and not uri:
 386      uri = '%s/%s' % (YOUTUBE_PLAYLIST_FEED_URI, playlist_id)
 387    return self.Get(
 388        uri, converter=gdata.youtube.YouTubePlaylistVideoFeedFromString)
 389
 390  def GetYouTubeVideoResponseFeed(self, uri=None, video_id=None):
 391    """Retrieve a YouTubeVideoResponseFeed.
 392
 393    Either a uri or a playlist_id must be provided.
 394
 395    Args:
 396      uri: An optional string representing the URI of the video response feed
 397          that is to be retrieved.
 398      video_id: An optional string representing the ID of the video whose
 399          response feed is to be retrieved.
 400
 401    Returns:
 402      A YouTubeVideoResponseFeed if successfully retrieved.
 403
 404    Raises:
 405      YouTubeError: You must provide at least a uri or a video_id to the
 406          GetYouTubeVideoResponseFeed() method.
 407    """
 408    if uri is None and video_id is None:
 409      raise YouTubeError('You must provide at least a uri or a video_id '
 410                         'to the GetYouTubeVideoResponseFeed() method')
 411    elif video_id and not uri:
 412      uri = '%s/%s/%s' % (YOUTUBE_VIDEO_URI, video_id, 'responses')
 413    return self.Get(
 414        uri, converter=gdata.youtube.YouTubeVideoResponseFeedFromString)
 415
 416  def GetYouTubeVideoResponseEntry(self, uri):
 417    """Retrieve a YouTubeVideoResponseEntry.
 418
 419    Args:
 420      uri: A string representing the URI of the video response entry that
 421          is to be retrieved.
 422
 423    Returns:
 424      A YouTubeVideoResponseEntry if successfully retrieved.
 425    """
 426    return self.Get(
 427        uri, converter=gdata.youtube.YouTubeVideoResponseEntryFromString)
 428
 429  def GetYouTubeSubscriptionFeed(self, uri=None, username='default'):
 430    """Retrieve a YouTubeSubscriptionFeed.
 431
 432    Either the uri of the feed or a username must be provided.
 433
 434    Args:
 435      uri: An optional string representing the URI of the feed that is to
 436          be retrieved.
 437      username: An optional string representing the username whose subscription
 438          feed is to be retrieved. Defaults to the currently authenticted user.
 439
 440    Returns:
 441      A YouTubeVideoSubscriptionFeed if successfully retrieved.
 442    """
 443    if uri is None:
 444      uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, username, 'subscriptions')
 445    return self.Get(
 446        uri, converter=gdata.youtube.YouTubeSubscriptionFeedFromString)
 447
 448  def GetYouTubeSubscriptionEntry(self, uri):
 449    """Retrieve a YouTubeSubscriptionEntry.
 450
 451    Args:
 452      uri: A string representing the URI of the entry that is to be retrieved.
 453
 454    Returns:
 455      A YouTubeVideoSubscriptionEntry if successfully retrieved.
 456    """
 457    return self.Get(
 458        uri, converter=gdata.youtube.YouTubeSubscriptionEntryFromString)
 459
 460  def GetYouTubeRelatedVideoFeed(self, uri=None, video_id=None):
 461    """Retrieve a YouTubeRelatedVideoFeed.
 462
 463    Either a uri for the feed or a video_id is required.
 464
 465    Args:
 466      uri: An optional string representing the URI of the feed that is to
 467          be retrieved.
 468      video_id: An optional string representing the ID of the video for which
 469          to retrieve the related video feed.
 470
 471    Returns:
 472      A YouTubeRelatedVideoFeed if successfully retrieved.
 473
 474    Raises:
 475      YouTubeError: You must provide at least a uri or a video_id to the
 476          GetYouTubeRelatedVideoFeed() method.
 477    """
 478    if uri is None and video_id is None:
 479      raise YouTubeError('You must provide at least a uri or a video_id '
 480                         'to the GetYouTubeRelatedVideoFeed() method')
 481    elif video_id and not uri:
 482      uri = '%s/%s/%s' % (YOUTUBE_VIDEO_URI, video_id, 'related')
 483    return self.Get(
 484        uri, converter=gdata.youtube.YouTubeVideoFeedFromString)
 485
 486  def GetTopRatedVideoFeed(self):
 487    """Retrieve the 'top_rated' standard video feed.
 488
 489    Returns:
 490      A YouTubeVideoFeed if successfully retrieved.
 491    """
 492    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_TOP_RATED_URI)
 493
 494  def GetMostViewedVideoFeed(self):
 495    """Retrieve the 'most_viewed' standard video feed.
 496
 497    Returns:
 498      A YouTubeVideoFeed if successfully retrieved.
 499    """
 500    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_MOST_VIEWED_URI)
 501
 502  def GetRecentlyFeaturedVideoFeed(self):
 503    """Retrieve the 'recently_featured' standard video feed.
 504
 505    Returns:
 506      A YouTubeVideoFeed if successfully retrieved.
 507    """
 508    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_RECENTLY_FEATURED_URI)
 509
 510  def GetWatchOnMobileVideoFeed(self):
 511    """Retrieve the 'watch_on_mobile' standard video feed.
 512
 513    Returns:
 514      A YouTubeVideoFeed if successfully retrieved.
 515    """
 516    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_WATCH_ON_MOBILE_URI)
 517
 518  def GetTopFavoritesVideoFeed(self):
 519    """Retrieve the 'top_favorites' standard video feed.
 520
 521    Returns:
 522      A YouTubeVideoFeed if successfully retrieved.
 523    """
 524    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_TOP_FAVORITES_URI)
 525
 526  def GetMostRecentVideoFeed(self):
 527    """Retrieve the 'most_recent' standard video feed.
 528
 529    Returns:
 530      A YouTubeVideoFeed if successfully retrieved.
 531    """
 532    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_MOST_RECENT_URI)
 533
 534  def GetMostDiscussedVideoFeed(self):
 535    """Retrieve the 'most_discussed' standard video feed.
 536
 537    Returns:
 538      A YouTubeVideoFeed if successfully retrieved.
 539    """
 540    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_MOST_DISCUSSED_URI)
 541
 542  def GetMostLinkedVideoFeed(self):
 543    """Retrieve the 'most_linked' standard video feed.
 544
 545    Returns:
 546      A YouTubeVideoFeed if successfully retrieved.
 547    """
 548    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_MOST_LINKED_URI)
 549
 550  def GetMostRespondedVideoFeed(self):
 551    """Retrieve the 'most_responded' standard video feed.
 552
 553    Returns:
 554      A YouTubeVideoFeed if successfully retrieved.
 555    """
 556    return self.GetYouTubeVideoFeed(YOUTUBE_STANDARD_MOST_RESPONDED_URI)
 557
 558  def GetUserFavoritesFeed(self, username='default'):
 559    """Retrieve the favorites feed for a given user.
 560
 561    Args:
 562      username: An optional string representing the username whose favorites
 563          feed is to be retrieved. Defaults to the currently authenticated user.
 564
 565    Returns:
 566      A YouTubeVideoFeed if successfully retrieved.
 567    """
 568    favorites_feed_uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, username,
 569                                       'favorites')
 570    return self.GetYouTubeVideoFeed(favorites_feed_uri)
 571
 572  def InsertVideoEntry(self, video_entry, filename_or_handle,
 573                       youtube_username='default',
 574                       content_type='video/quicktime'):
 575    """Upload a new video to YouTube using the direct upload mechanism.
 576
 577    Needs authentication.
 578
 579    Args:
 580      video_entry: The YouTubeVideoEntry to upload.
 581      filename_or_handle: A file-like object or file name where the video
 582          will be read from.
 583      youtube_username: An optional string representing the username into whose
 584          account this video is to be uploaded to. Defaults to the currently
 585          authenticated user.
 586      content_type: An optional string representing internet media type
 587          (a.k.a. mime type) of the media object. Currently the YouTube API
 588          supports these types:
 589            o video/mpeg
 590            o video/quicktime
 591            o video/x-msvideo
 592            o video/mp4
 593            o video/x-flv
 594
 595    Returns:
 596      The newly created YouTubeVideoEntry if successful.
 597
 598    Raises:
 599      AssertionError: video_entry must be a gdata.youtube.VideoEntry instance.
 600      YouTubeError: An error occurred trying to read the video file provided.
 601      gdata.service.RequestError: An error occurred trying to upload the video
 602          to the API server.
 603    """
 604
 605    # We need to perform a series of checks on the video_entry and on the
 606    # file that we plan to upload, such as checking whether we have a valid
 607    # video_entry and that the file is the correct type and readable, prior
 608    # to performing the actual POST request.
 609
 610    try:
 611      assert(isinstance(video_entry, gdata.youtube.YouTubeVideoEntry))
 612    except AssertionError:
 613      raise YouTubeError({'status':YOUTUBE_INVALID_ARGUMENT,
 614          'body':'`video_entry` must be a gdata.youtube.VideoEntry instance',
 615          'reason':'Found %s, not VideoEntry' % type(video_entry)
 616          })
 617    #majtype, mintype = content_type.split('/')
 618    #
 619    #try:
 620    #  assert(mintype in YOUTUBE_SUPPORTED_UPLOAD_TYPES)
 621    #except (ValueError, AssertionError):
 622    #  raise YouTubeError({'status':YOUTUBE_INVALID_CONTENT_TYPE,
 623    #      'body':'This is not a valid content type: %s' % content_type,
 624    #      'reason':'Accepted content types: %s' %
 625    #          ['video/%s' % (t) for t in YOUTUBE_SUPPORTED_UPLOAD_TYPES]})
 626
 627    if (isinstance(filename_or_handle, (str, unicode)) 
 628        and os.path.exists(filename_or_handle)):
 629      mediasource = gdata.MediaSource()
 630      mediasource.setFile(filename_or_handle, content_type)
 631    elif hasattr(filename_or_handle, 'read'):
 632      import StringIO
 633      if hasattr(filename_or_handle, 'seek'):
 634        filename_or_handle.seek(0)
 635      file_handle = StringIO.StringIO(filename_or_handle.read())
 636      name = 'video'
 637      if hasattr(filename_or_handle, 'name'):
 638        name = filename_or_handle.name
 639      mediasource = gdata.MediaSource(file_handle, content_type,
 640          content_length=file_handle.len, file_name=name)
 641    else:
 642      raise YouTubeError({'status':YOUTUBE_INVALID_ARGUMENT, 'body':
 643          '`filename_or_handle` must be a path name or a file-like object',
 644          'reason': ('Found %s, not path name or object '
 645                     'with a .read() method' % type(filename_or_handle))})
 646    upload_uri = '%s/%s/%s' % (YOUTUBE_UPLOAD_URI, youtube_username,
 647                              'uploads')
 648    self.additional_headers['Slug'] = mediasource.file_name
 649
 650    # Using a nested try statement to retain Python 2.4 compatibility
 651    try:
 652      try:
 653        return self.Post(video_entry, uri=upload_uri, media_source=mediasource,
 654                         converter=gdata.youtube.YouTubeVideoEntryFromString)
 655      except gdata.service.RequestError, e:
 656        raise YouTubeError(e.args[0])
 657    finally:
 658      del(self.additional_headers['Slug'])
 659
 660  def CheckUploadStatus(self, video_entry=None, video_id=None):
 661    """Check upload status on a recently uploaded video entry.
 662
 663    Needs authentication. Either video_entry or video_id must be provided.
 664
 665    Args:
 666      video_entry: An optional YouTubeVideoEntry whose upload status to check
 667      video_id: An optional string representing the ID of the uploaded video
 668          whose status is to be checked.
 669
 670    Returns:
 671      A tuple containing (video_upload_state, detailed_message) or None if
 672          no status information is found.
 673
 674    Raises:
 675      YouTubeError: You must provide at least a video_entry or a video_id to the
 676          CheckUploadStatus() method.
 677    """
 678    if video_entry is None and video_id is None:
 679      raise YouTubeError('You must provide at least a uri or a video_id '
 680                         'to the CheckUploadStatus() method')
 681    elif video_id and not video_entry:
 682       video_entry = self.GetYouTubeVideoEntry(video_id=video_id)
 683
 684    control = video_entry.control
 685    if control is not None:
 686      draft = control.draft
 687      if draft is not None:
 688        if draft.text == 'yes':
 689          yt_state = control.extension_elements[0]
 690          if yt_state is not None:
 691            state_value = yt_state.attributes['name']
 692            message = ''
 693            if yt_state.text is not None:
 694              message = yt_state.text
 695
 696            return (state_value, message)
 697
 698  def GetFormUploadToken(self, video_entry, uri=YOUTUBE_UPLOAD_TOKEN_URI):
 699    """Receives a YouTube Token and a YouTube PostUrl from a YouTubeVideoEntry.
 700
 701    Needs authentication.
 702
 703    Args:
 704      video_entry: The YouTubeVideoEntry to upload (meta-data only).
 705      uri: An optional string representing the URI from where to fetch the
 706          token information. Defaults to the YOUTUBE_UPLOADTOKEN_URI.
 707
 708    Returns:
 709      A tuple containing the URL to which to post your video file, along
 710          with the youtube token that must be included with your upload in the
 711          form of: (post_url, youtube_token).
 712    """
 713    try:
 714      response = self.Post(video_entry, uri)
 715    except gdata.service.RequestError, e:
 716      raise YouTubeError(e.args[0])
 717
 718    tree = ElementTree.fromstring(response)
 719
 720    for child in tree:
 721      if child.tag == 'url':
 722        post_url = child.text
 723      elif child.tag == 'token':
 724        youtube_token = child.text
 725    return (post_url, youtube_token)
 726
 727  def UpdateVideoEntry(self, video_entry):
 728    """Updates a video entry's meta-data.
 729
 730    Needs authentication.
 731
 732    Args:
 733      video_entry: The YouTubeVideoEntry to update, containing updated
 734          meta-data.
 735
 736    Returns:
 737      An updated YouTubeVideoEntry on success or None.
 738    """
 739    for link in video_entry.link:
 740      if link.rel == 'edit':
 741        edit_uri = link.href
 742    return self.Put(video_entry, uri=edit_uri,
 743                    converter=gdata.youtube.YouTubeVideoEntryFromString)
 744
 745  def DeleteVideoEntry(self, video_entry):
 746    """Deletes a video entry.
 747
 748    Needs authentication.
 749
 750    Args:
 751      video_entry: The YouTubeVideoEntry to be deleted.
 752
 753    Returns:
 754      True if entry was deleted successfully.
 755    """
 756    for link in video_entry.link:
 757      if link.rel == 'edit':
 758        edit_uri = link.href
 759    return self.Delete(edit_uri)
 760
 761  def AddRating(self, rating_value, video_entry):
 762    """Add a rating to a video entry.
 763
 764    Needs authentication.
 765
 766    Args:
 767      rating_value: The integer value for the rating (between 1 and 5).
 768      video_entry: The YouTubeVideoEntry to be rated.
 769
 770    Returns:
 771      True if the rating was added successfully.
 772
 773    Raises:
 774      YouTubeError: rating_value must be between 1 and 5 in AddRating().
 775    """
 776    if rating_value < 1 or rating_value > 5:
 777      raise YouTubeError('rating_value must be between 1 and 5 in AddRating()')
 778
 779    entry = gdata.GDataEntry()
 780    rating = gdata.youtube.Rating(min='1', max='5')
 781    rating.extension_attributes['name'] = 'value'
 782    rating.extension_attributes['value'] = str(rating_value)
 783    entry.extension_elements.append(rating)
 784
 785    for link in video_entry.link:
 786      if link.rel == YOUTUBE_RATING_LINK_REL:
 787        rating_uri = link.href
 788
 789    return self.Post(entry, uri=rating_uri)
 790
 791  def AddComment(self, comment_text, video_entry):
 792    """Add a comment to a video entry.
 793
 794    Needs authentication. Note that each comment that is posted must contain
 795        the video entry that it is to be posted to.
 796
 797    Args:
 798      comment_text: A string representing the text of the comment.
 799      video_entry: The YouTubeVideoEntry to be commented on.
 800
 801    Returns:
 802      True if the comment was added successfully.
 803    """
 804    content = atom.Content(text=comment_text)
 805    comment_entry = gdata.youtube.YouTubeVideoCommentEntry(content=content)
 806    comment_post_uri = video_entry.comments.feed_link[0].href
 807
 808    return self.Post(comment_entry, uri=comment_post_uri)
 809
 810  def AddVideoResponse(self, video_id_to_respond_to, video_response):
 811    """Add a video response.
 812
 813    Needs authentication.
 814
 815    Args:
 816      video_id_to_respond_to: A string representing the ID of the video to be
 817          responded to.
 818      video_response: YouTubeVideoEntry to be posted as a response.
 819
 820    Returns:
 821      True if video response was posted successfully.
 822    """
 823    post_uri = '%s/%s/%s' % (YOUTUBE_VIDEO_URI, video_id_to_respond_to,
 824                             'responses')
 825    return self.Post(video_response, uri=post_uri)
 826
 827  def DeleteVideoResponse(self, video_id, response_video_id):
 828    """Delete a video response.
 829
 830    Needs authentication.
 831
 832    Args:
 833      video_id: A string representing the ID of video that contains the
 834          response.
 835      response_video_id: A string representing the ID of the video that was
 836          posted as a response.
 837
 838    Returns:
 839      True if video response was deleted succcessfully.
 840    """
 841    delete_uri = '%s/%s/%s/%s' % (YOUTUBE_VIDEO_URI, video_id, 'responses',
 842                                  response_video_id)
 843    return self.Delete(delete_uri)
 844
 845  def AddComplaint(self, complaint_text, complaint_term, video_id):
 846    """Add a complaint for a particular video entry.
 847
 848    Needs authentication.
 849
 850    Args:
 851      complaint_text: A string representing the complaint text.
 852      complaint_term: A string representing the complaint category term.
 853      video_id: A string representing the ID of YouTubeVideoEntry to
 854          complain about.
 855
 856    Returns:
 857      True if posted successfully.
 858
 859    Raises:
 860      YouTubeError: Your complaint_term is not valid.
 861    """
 862    if complaint_term not in YOUTUBE_COMPLAINT_CATEGORY_TERMS:
 863      raise YouTubeError('Your complaint_term is not valid')
 864
 865    content = atom.Content(text=complaint_text)
 866    category = atom.Category(term=complaint_term,
 867                             scheme=YOUTUBE_COMPLAINT_CATEGORY_SCHEME)
 868
 869    complaint_entry = gdata.GDataEntry(content=content, category=[category])
 870    post_uri = '%s/%s/%s' % (YOUTUBE_VIDEO_URI, video_id, 'complaints')
 871
 872    return self.Post(complaint_entry, post_uri)
 873
 874  def AddVideoEntryToFavorites(self, video_entry, username='default'):
 875    """Add a video entry to a users favorite feed.
 876
 877    Needs authentication.
 878
 879    Args:
 880      video_entry: The YouTubeVideoEntry to add.
 881      username: An optional string representing the username to whose favorite
 882          feed you wish to add the entry. Defaults to the currently
 883          authenticated user.
 884    Returns:
 885        The posted YouTubeVideoEntry if successfully posted.
 886    """
 887    post_uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, username, 'favorites')
 888
 889    return self.Post(video_entry, post_uri,
 890                     converter=gdata.youtube.YouTubeVideoEntryFromString)
 891
 892  def DeleteVideoEntryFromFavorites(self, video_id, username='default'):
 893    """Delete a video entry from the users favorite feed.
 894
 895    Needs authentication.
 896
 897    Args:
 898      video_id: A string representing the ID of the video that is to be removed
 899      username: An optional string representing the username of the user's
 900          favorite feed. Defaults to the currently authenticated user.
 901
 902    Returns:
 903        True if entry was successfully deleted.
 904    """
 905    edit_link = '%s/%s/%s/%s' % (YOUTUBE_USER_FEED_URI, username, 'favorites',
 906                                 video_id)
 907    return self.Delete(edit_link)
 908
 909  def AddPlaylist(self, playlist_title, playlist_description,
 910                  playlist_private=None):
 911    """Add a new playlist to the currently authenticated users account.
 912
 913    Needs authentication.
 914
 915    Args:
 916      playlist_title: A string representing the title for the new playlist.
 917      playlist_description: A string representing the description of the
 918          playlist.
 919      playlist_private: An optional boolean, set to True if the playlist is
 920          to be private.
 921
 922    Returns:
 923      The YouTubePlaylistEntry if successfully posted.
 924    """
 925    playlist_entry = gdata.youtube.YouTubePlaylistEntry(
 926        title=atom.Title(text=playlist_title),
 927        description=gdata.youtube.Description(text=playlist_description))
 928    if playlist_private:
 929      playlist_entry.private = gdata.youtube.Private()
 930
 931    playlist_post_uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, 'default', 
 932                                      'playlists')
 933    return self.Post(playlist_entry, playlist_post_uri,
 934                     converter=gdata.youtube.YouTubePlaylistEntryFromString)
 935
 936  def UpdatePlaylist(self, playlist_id, new_playlist_title,
 937                     new_playlist_description, playlist_private=None,
 938                     username='default'):
 939    """Update a playlist with new meta-data.
 940
 941    Needs authentication.
 942
 943    Args:
 944      playlist_id: A string representing the ID of the playlist to be updated.
 945      new_playlist_title: A string representing a new title for the playlist.
 946      new_playlist_description: A string representing a new description for the
 947          playlist.
 948      playlist_private: An optional boolean, set to True if the playlist is
 949          to be private.
 950      username: An optional string representing the username whose playlist is
 951          to be updated. Defaults to the currently authenticated user.
 952
 953   Returns:
 954      A YouTubePlaylistEntry if the update was successful.
 955    """
 956    updated_playlist = gdata.youtube.YouTubePlaylistEntry(
 957        title=atom.Title(text=new_playlist_title),
 958        description=gdata.youtube.Description(text=new_playlist_description))
 959    if playlist_private:
 960      updated_playlist.private = gdata.youtube.Private()
 961
 962    playlist_put_uri = '%s/%s/playlists/%s' % (YOUTUBE_USER_FEED_URI, username,
 963                                               playlist_id)
 964
 965    return self.Put(updated_playlist, playlist_put_uri,
 966                    converter=gdata.youtube.YouTubePlaylistEntryFromString)
 967
 968  def DeletePlaylist(self, playlist_uri):
 969    """Delete a playlist from the currently authenticated users playlists.
 970
 971    Needs authentication.
 972
 973    Args:
 974      playlist_uri: A string representing the URI of the playlist that is
 975          to be deleted.
 976
 977    Returns:
 978      True if successfully deleted.
 979    """
 980    return self.Delete(playlist_uri)
 981
 982  def AddPlaylistVideoEntryToPlaylist(
 983      self, playlist_uri, video_id, custom_video_title=None,
 984      custom_video_description=None):
 985    """Add a video entry to a playlist, optionally providing a custom title
 986    and description.
 987
 988    Needs authentication.
 989
 990    Args:
 991      playlist_uri: A string representing the URI of the playlist to which this
 992          video entry is to be added.
 993      video_id: A string representing the ID of the video entry to add.
 994      custom_video_title: An optional string representing a custom title for
 995          the video (only shown on the playlist).
 996      custom_video_description: An optional string representing a custom
 997          description for the video (only shown on the playlist).
 998
 999    Returns:
1000      A YouTubePlaylistVideoEntry if successfully posted.
1001    """
1002    playlist_video_entry = gdata.youtube.YouTubePlaylistVideoEntry(
1003        atom_id=atom.Id(text=video_id))
1004    if custom_video_title:
1005      playlist_video_entry.title = atom.Title(text=custom_video_title)
1006    if custom_video_description:
1007      playlist_video_entry.description = gdata.youtube.Description(
1008          text=custom_video_description)
1009
1010    return self.Post(playlist_video_entry, playlist_uri,
1011                    converter=gdata.youtube.YouTubePlaylistVideoEntryFromString)
1012
1013  def UpdatePlaylistVideoEntryMetaData(
1014      self, playlist_uri, playlist_entry_id, new_video_title, 
1015      new_video_description, new_video_position):
1016    """Update the meta data for a YouTubePlaylistVideoEntry.
1017
1018    Needs authentication.
1019
1020    Args:
1021      playlist_uri: A string representing the URI of the playlist that contains
1022          the entry to be updated.
1023      playlist_entry_id: A string representing the ID of the entry to be
1024          updated.
1025      new_video_title: A string representing the new title for the video entry.
1026      new_video_description: A string representing the new description for
1027          the video entry.
1028      new_video_position: An integer representing the new position on the
1029          playlist for the video.
1030
1031    Returns:
1032      A YouTubePlaylistVideoEntry if the update was successful.
1033    """
1034    playlist_video_entry = gdata.youtube.YouTubePlaylistVideoEntry(
1035        title=atom.Title(text=new_video_title),
1036        description=gdata.youtube.Description(text=new_video_description),
1037        position=gdata.youtube.Position(text=str(new_video_position)))
1038
1039    playlist_put_uri = playlist_uri + '/' + playlist_entry_id
1040
1041    return self.Put(playlist_video_entry, playlist_put_uri,
1042                    converter=gdata.youtube.YouTubePlaylistVideoEntryFromString)
1043
1044  def DeletePlaylistVideoEntry(self, playlist_uri, playlist_video_entry_id):
1045    """Delete a playlist video entry from a playlist.
1046
1047    Needs authentication.
1048
1049    Args:
1050      playlist_uri: A URI representing the playlist from which the playlist
1051          video entry is to be removed from.
1052      playlist_video_entry_id: A string representing id of the playlist video
1053          entry that is to be removed.
1054
1055    Returns:
1056        True if entry was successfully deleted.
1057    """
1058    delete_uri = '%s/%s' % (playlist_uri, playlist_video_entry_id)
1059    return self.Delete(delete_uri)
1060
1061  def AddSubscriptionToChannel(self, username_to_subscribe_to,
1062                               my_username = 'default'):
1063    """Add a new channel subscription to the currently authenticated users
1064    account.
1065
1066    Needs authentication.
1067
1068    Args:
1069      username_to_subscribe_to: A string representing the username of the 
1070          channel to which we want to subscribe to.
1071      my_username: An optional string representing the name of the user which
1072          we want to subscribe. Defaults to currently authenticated user.
1073
1074    Returns:
1075      A new YouTubeSubscriptionEntry if successfully posted.
1076    """
1077    subscription_category = atom.Category(
1078        scheme=YOUTUBE_SUBSCRIPTION_CATEGORY_SCHEME,
1079        term='channel')
1080    subscription_username = gdata.youtube.Username(
1081        text=username_to_subscribe_to)
1082
1083    subscription_entry = gdata.youtube.YouTubeSubscriptionEntry(
1084        category=subscription_category,
1085        username=subscription_username)
1086
1087    post_uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, my_username, 
1088                             'subscriptions')
1089
1090    return self.Post(subscription_entry, post_uri,
1091                     converter=gdata.youtube.YouTubeSubscriptionEntryFromString)
1092
1093  def AddSubscriptionToFavorites(self, username, my_username = 'default'):
1094    """Add a new subscription to a users favorites to the currently
1095    authenticated user's account.
1096
1097    Needs authentication
1098
1099    Args:
1100      username: A string representing the username of the user's favorite feed
1101          to subscribe to.
1102      my_username: An optional string representing the username of the user
1103          that is to be subscribed. Defaults to currently authenticated user.
1104
1105    Returns:
1106        A new YouTubeSubscriptionEntry if successful.
1107    """
1108    subscription_category = atom.Category(
1109        scheme=YOUTUBE_SUBSCRIPTION_CATEGORY_SCHEME,
1110        term='favorites')
1111    subscription_username = gdata.youtube.Username(text=username)
1112
1113    subscription_entry = gdata.youtube.YouTubeSubscriptionEntry(
1114        category=subscription_category,
1115        username=subscription_username)
1116
1117    post_uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, my_username,
1118                             'subscriptions')
1119
1120    return self.Post(subscription_entry, post_uri,
1121                     converter=gdata.youtube.YouTubeSubscriptionEntryFromString)
1122
1123  def AddSubscriptionToQuery(self, query, my_username = 'default'):
1124    """Add a new subscription to a specific keyword query to the currently
1125    authenticated user's account.
1126
1127    Needs authentication
1128
1129    Args:
1130      query: A string representing the keyword query to subscribe to.
1131      my_username: An optional string representing the username of the user
1132          that is to be subscribed. Defaults to currently authenticated user.
1133
1134    Returns:
1135        A new YouTubeSubscriptionEntry if successful.
1136    """
1137    subscription_category = atom.Category(
1138        scheme=YOUTUBE_SUBSCRIPTION_CATEGORY_SCHEME,
1139        term='query')
1140    subscription_query_string = gdata.youtube.QueryString(text=query)
1141
1142    subscription_entry = gdata.youtube.YouTubeSubscriptionEntry(
1143        category=subscription_category,
1144        query_string=subscription_query_string)
1145
1146    post_uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, my_username,
1147                             'subscriptions')
1148
1149    return self.Post(subscription_entry, post_uri,
1150                     converter=gdata.youtube.YouTubeSubscriptionEntryFromString)
1151
1152
1153
1154  def DeleteSubscription(self, subscription_uri):
1155    """Delete a subscription from the currently authenticated user's account.
1156
1157    Needs authentication.
1158
1159    Args:
1160      subscription_uri: A string representing the URI of the subscription that
1161          is to be deleted.
1162
1163    Returns:
1164      True if deleted successfully.
1165    """
1166    return self.Delete(subscription_uri)
1167
1168  def AddContact(self, contact_username, my_username='default'):
1169    """Add a new contact to the currently authenticated user's contact feed.
1170
1171    Needs authentication.
1172
1173    Args:
1174      contact_username: A string representing the username of the contact
1175          that you wish to add.
1176      my_username: An optional string representing the username to whose
1177          contact the new contact is to be added.
1178
1179    Returns:
1180        A YouTubeContactEntry if added successfully.
1181    """
1182    contact_category = atom.Category(
1183        scheme = 'http://gdata.youtube.com/schemas/2007/contact.cat',
1184        term = 'Friends')
1185    contact_username = gdata.youtube.Username(text=contact_username)
1186    contact_entry = gdata.youtube.YouTubeContactEntry(
1187        category=contact_category,
1188        username=contact_username)
1189
1190    contact_post_uri = '%s/%s/%s' % (YOUTUBE_USER_FEED_URI, my_username,
1191                                     'contacts')
1192
1193    return self.Post(contact_entry, contact_post_uri,
1194                     converter=gdata.youtube.YouTubeContactEntryFromString)
1195
1196  def UpdateContact(self, contact_username, new_contact_status, 
1197                    new_contact_category, my_username='default'):
1198    """Update a contact, providing a new status and a new category.
1199
1200    Needs authentication.
1201
1202    Args:
1203      contact_username: A string representing the username of the contact
1204          that is to be updated.
1205      new_contact_status: A string representing the new status of the contact.
1206          This can either be set to 'accepted' or 'rejected'.
1207      new_contact_category: A string representing the new category for the
1208          contact, either 'Friends' or 'Family'.
1209      my_username: An optional string representing the username of the user
1210          whose contact feed we are modifying. Defaults to the currently
1211          authenticated user.
1212
1213    Returns:
1214      A YouTubeContactEntry if updated succesfully.
1215
1216    Raises:
1217      YouTubeError: New contact status must be within the accepted values. Or
1218          new contact category must be within the accepted categories.
1219    """
1220    if new_contact_status not in YOUTUBE_CONTACT_STATUS:
1221      raise YouTubeError('New contact status must be one of %s' %
1222                          (' '.join(YOUTUBE_CONTACT_STATUS)))
1223    if new_contact_category not in YOUTUBE_CONTACT_CATEGORY:
1224      raise YouTubeError('New contact category must be one of %s' %
1225                         (' '.join(YOUTUBE_CONTACT_CATEGORY)))
1226
1227    contact_category = atom.Category(
1228        scheme='http://gdata.youtube.com/schemas/2007/contact.cat',
1229        term=new_contact_category)
1230
1231    contact_status = gdata.youtube.Status(text=new_contact_status)
1232    contact_entry = gdata.youtube.YouTubeContactEntry(
1233        category=contact_category,
1234        status=contact_status)
1235
1236    contact_put_uri = '%s/%s/%s/%s' % (YOUTUBE_USER_FEED_URI, my_username,
1237                                       'contacts', contact_username)
1238
1239    return self.Put(contact_entry, contact_put_uri,
1240                    converter=gdata.youtube.YouTubeContactEntryFromString)
1241
1242  def DeleteContact(self, contact_username, my_username='default'):
1243    """Delete a contact from a users contact feed.
1244
1245    Needs authentication.
1246
1247    Args:
1248      contact_username: A string representing the username of the contact
1249          that is to be deleted.
1250      my_username: An optional string representing the username of the user's
1251          contact feed from which to delete the contact. Defaults to the
1252          currently authenticated user.
1253
1254    Returns:
1255      True if the contact was deleted successfully
1256    """
1257    contact_edit_uri = '%s/%s/%s/%s' % (YOUTUBE_USER_FEED_URI, my_username,
1258                                        'contacts', contact_username)
1259    return self.Delete(contact_edit_uri)
1260
1261  def _GetDeveloperKey(self):
1262    """Getter for Developer Key property.
1263
1264    Returns:
1265      If the developer key has been set, a string representing the developer key
1266          is returned or None.
1267    """
1268    if 'X-GData-Key' in self.additional_headers:
1269      return self.additional_headers['X-GData-Key'][4:]
1270    else:
1271      return None
1272
1273  def _SetDeveloperKey(self, developer_key):
1274    """Setter for Developer Key property.
1275    
1276    Sets the developer key in the 'X-GData-Key' header. The actual value that
1277        is set is 'key=' plus the developer_key that was passed.
1278    """
1279    self.additional_headers['X-GData-Key'] = 'key=' + developer_key
1280
1281  developer_key = property(_GetDeveloperKey, _SetDeveloperKey,
1282                           doc="""The Developer Key property""")
1283
1284  def _GetClientId(self):
1285    """Getter for Client Id property.
1286
1287    Returns:
1288      If the client_id has been set, a string representing it is returned
1289          or None.
1290    """
1291    if 'X-Gdata-Client' in self.additional_headers:
1292      return self.additional_headers['X-Gdata-Client']
1293    else:
1294      return None
1295
1296  def _SetClientId(self, client_id):
1297    """Setter for Client Id property.
1298
1299    Sets the 'X-Gdata-Client' header.
1300    """
1301    self.additional_headers['X-Gdata-Client'] = client_id
1302
1303  client_id = property(_GetClientId, _SetClientId,
1304                       doc="""The ClientId property""")
1305
1306  def Query(self, uri):
1307    """Performs a query and returns a resulting feed or entry.
1308
1309    Args:
1310      uri: A string representing the URI of the feed that is to be queried.
1311
1312    Returns:
1313      On success, a tuple in the form:
1314      (boolean succeeded=True, ElementTree._Element result)
1315      On failure, a tuple in the form:
1316      (boolean succeeded=False, {'status': HTTP status code from server,
1317                                 'reason': HTTP reason from the server,
1318                                 'body': HTTP body of the server's response})
1319    """
1320    result = self.Get(uri)
1321    return result
1322
1323  def YouTubeQuery(self, query):
1324    """Performs a YouTube specific query and returns a resulting feed or entry.
1325
1326    Args:
1327      query: A Query object or one if its sub-classes (YouTubeVideoQuery,
1328          YouTubeUserQuery or YouTubePlaylistQuery).
1329
1330    Returns:
1331      Depending on the type of Query object submitted returns either a
1332          YouTubeVideoFeed, a YouTubeUserFeed, a YouTubePlaylistFeed. If the
1333          Query object provided was not YouTube-related, a tuple is returned.
1334          On success the tuple will be in this form:
1335          (boolean succeeded=True, ElementTree._Element result)
1336          On failure, the tuple will be in this form:
1337          (boolean succeeded=False, {'status': HTTP status code from server,
1338                                     'reason': HTTP reason from the server,
1339                                     'body': HTTP body of the server response})
1340    """
1341    result = self.Query(query.ToUri())
1342    if isinstance(query, YouTubeVideoQuery):
1343      return gdata.youtube.YouTubeVideoFeedFromString(result.ToString())
1344    elif isinstance(query, YouTubeUserQuery):
1345      return gdata.youtube.YouTubeUserFeedFromString(result.ToString())
1346    elif isinstance(query, YouTubePlaylistQuery):
1347      return gdata.youtube.YouTubePlaylistFeedFromString(result.ToString())
1348    else

Large files files are truncated, but you can click here to view the full file