File: YouTubeIntroduction.html

package info (click to toggle)
gdata-sharp 2.2.0.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 12,092 kB
  • sloc: cs: 67,781; xml: 38,234; python: 163; makefile: 149; sh: 27
file content (203 lines) | stat: -rw-r--r-- 10,583 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
<title>The YouTube simplified object mode</title>
<h1>YouTube simplified object model</h1>
<em>Frank Mantek, Google Data APIs team
<br>December 2008</em>

<ul>
  <li><a href="#introduction">Introduction</a></li>
  <ul>
  <li><a href="#oldcode">The current model</a></li>
  <li><a href="#newcodelooping">The new model: simple looping</a></li>
  <li><a href="#newcodeautopaging">The new model: automatic paging</a></li>
  <li><a href="#newcodemax">The new model: limit data retrieval</a></li>
  <li><a href="#newcodeinsert">The new model: inserting a new video</a></li>

  <li><a href="#conclusion">Conclusion</a></li>

</ul>


<a name="introduction"><h3>Introduction</h3></a>

The default object model, as available under the Google.GData.YouTube.* namespace is a direct protocol layer. It allows you to do everything there is to do with the protocol itself, but it has exactly the same disadvantage. It's overwhelming to be confronted with all that power of the Atom (pardon the pun), when all you want to do is work with Videos and YouTube.

To solve this problem, I will be working on more vertical libraries in the future. They will use the underlying protocol object model, but hide some of the protocol specific issues, and let you worry primarily on the task at hand. At the same time, you can get access to the protocol itself if the need arises.


<a name="oldcode"><h3>The current model</h3></a>

Let's look at some of the old model code:<br>


<p><code><pre>

            YouTubeService service = new YouTubeService("NETUnittests", this.ytClient, this.ytDevKey);
            service.Credentials = new GDataCredentials(this.ytUser, this.ytPwd);

            GDataRequestFactory factory = service.RequestFactory as GDataRequestFactory;
            factory.Timeout = 1000000; 

            YouTubeEntry entry = new YouTubeEntry();

            entry.MediaSource = new MediaFileSource(this.resourcePath + "test_movie.mov", "video/quicktime");
            entry.Media = new YouTube.MediaGroup();
            entry.Media.Description = new MediaDescription("This is a test with and & in it");
            entry.Media.Title = new MediaTitle("Sample upload");
            entry.Media.Keywords = new MediaKeywords("math");

            // entry.Media.Categories

            MediaCategory category = new MediaCategory("Nonprofit");
            category.Attributes["scheme"] = YouTubeService.DefaultCategory;

            entry.Media.Categories.Add(category);

            YouTubeEntry newEntry = service.Upload(this.ytUser, entry);

</pre>

       

</code></p>
<p>To insert a new video, you need to create a service object, set the timeout on the service to a reasonable amount, create a new YouTubeEntry object, create a MediaSource on that object, set the properties on that media source, add a category, and at the end upload the entry using the service upload method. Not too complicated, in general.</p>

If you wanted to iterate over a feed, this is the code you were writing:

<p><code>
<pre>
            YouTubeQuery query = new YouTubeQuery(YouTubeQuery.TopRatedVideo);
            YouTubeService service = new YouTubeService("NETUnittests", this.ytClient, this.ytDevKey);
            service.Credentials = new GDataCredentials(this.ytUser, this.ytPwd);

            query.Formats.Add(YouTubeQuery.VideoFormat.RTSP);
            query.Time = YouTubeQuery.UploadTime.ThisWeek;

            YouTubeFeed feed = service.Query(query);

            foreach (YouTubeEntry e in feed.Entries )
            {
                Console.WriteLine(e.Media.Title.Value);
            }
        

</pre>
</code></p>

<p>Again, the code is pretty straightforward. Create a service object, create a query, have a loop to go over the data. But, as you are aware, the loop above will only return 25 entries, or whatever the service default is. So while you wanted all TopRatedVideos, you in fact, only got a part of it. To get more, you need to page by checking the feeds nextChunk property and executing another query.</p>


<p>This was well as long as you were trying to retrieve required elements. An entry object is required to have a Summary, but the code above <b>e.Media.Title.Value</b> can actually crash on you, as e.Media might return NULL - while YouTube entries are unlikely to have no Media subelement,
the implementation code would return a null element if none is found.</p>
<p>And that is one of the more fundamental problems with the protocol based object model. Due to the nature of the beast, you will end up with a lot of code that looks like this:</p>

<code><pre>
                if (youTubeEntry != null && 
                youTubeEntry.Media != null &&
                youTubeEntry.Media.Description != null)
                {
                    Console.WriteLine(youTubeEntry.Media.Description.Value);
</pre></code>

<a name="newcodelooping"><h3>The new model: simple looping</h3></a>

<p>In the new model, we are trying to hide a lot of the checks above, and make iteration over feeds easier. Let's look at how looping over a feed looks like, and what objects are involved.</p>

<code><pre>

            YouTubeRequestSettings settings = new YouTubeRequestSettings("NETUnittests", this.ytClient, this.ytDevKey, this.ytUser, this.ytPwd);
            YouTubeRequest f = new YouTubeRequest(settings);

            Feed&lt;Video&gt; feed = f.GetStandardFeed(YouTubeQuery.MostPopular);
            foreach (Video v in feed.Entries)
            {
                Feed&lt;Comment&gt; list = f.GetComments(v);
                foreach (Comment c in list.Entries)
                {
                    Console.WriteLine(c.Title);
                }
            }

</pre></code>
<p>A YouTubeRequestSettings object holds the information needed to connect to the YouTubeServer. Username, password, developer key etc. There are several different constructors (for anonymous access or AuthSub access). You pass this object to a YouTubeRequest object. The request object is your representation of the server in this code. You want data, you want to send data, that's the object that does it. No more entry.Update() or feed.Insert(). </p>
<p>From the YouTubeRequest, you get a generic type back, a feed of Videos in this case. You loop over that feed, and want to retrieve a comment feed for the video. So you return to the YouTubeRequest and ask for a comment feed for the current video. This time you get a feed of comments and you can iterate over this again.</p>


<a name="newcodeautopaging"><h3>The new model: automatic paging</h3></a>

<p>As mentioned above, the server will normally only return a page full of data, and that is true here as well. So we loop over the 25 top videos, and then the first 25 comments of that. To change this behaviour, we need to add one line of code:</p>
<code><pre>

            YouTubeRequestSettings settings = new YouTubeRequestSettings("NETUnittests", this.ytClient, this.ytDevKey, this.ytUser, this.ytPwd);
            settings.AutoPaging = true;
            YouTubeRequest f = new YouTubeRequest(settings);

            Feed&lt;Video&gt; feed = f.GetStandardFeed(YouTubeQuery.MostPopular);
            foreach (Video v in feed.Entries)
            {
                Feed&lt;Comment&gt; list = f.GetComments(v);
                foreach (Comment c in list.Entries)
                {
                    Console.WriteLine(c.Title);
                }
            }

</pre></code>


<p>That one line, settings.Autopaging = true, results in the iterator that is used when we loop over the entries collection to automatically request new data from the server when we reach the end of the current set. As the most popular feed is limited to a fixed set of videos, this will iterate over 50 videos, by requesting 2 set of results from the server, and get all comments for those videos. </p>


<a name="newcodemax"><h3>The new model: limit data retrieval</h3></a>

<p>If you wanted to say: yes, get me all data, up to a certain maximum, you add another line of code:</p>
<code><pre>

            YouTubeRequestSettings settings = new YouTubeRequestSettings("NETUnittests", this.ytClient, this.ytDevKey, this.ytUser, this.ytPwd);
            settings.AutoPaging = true;
            settings.Maximum = 15; 
            YouTubeRequest f = new YouTubeRequest(settings);

            Feed&lt;Video&gt; feed = f.GetStandardFeed(YouTubeQuery.MostPopular);
            foreach (Video v in feed.Entries)
            {
                Feed&lt;Comment&gt; list = f.GetComments(v);
                foreach (Comment c in list.Entries)
                {
                    Console.WriteLine(c.Title);
                }
            }

</pre></code>
<p>The Maximum property of the YouTubeRequestSettings allows you to specify that the iterators will stop at this maximum, no matter how much more data might be available.</p>

<a name="newcodeinsert"><h3>The new model: inserting a new video</h3></a>

<p>As you can see in the code below, the main difference is that the creation of the in-between objects (like Media or MediaDesription in the old code), is no longer required. The Timeout as well is easily accessible directly on the YouTubeRequestSettings object.</p>

<code><pre>
            YouTubeRequestSettings settings = new YouTubeRequestSettings("NETUnittests", this.ytClient, this.ytDevKey, this.ytUser, this.ytPwd);
            settings.Timeout = = 1000000; 
            YouTubeRequest f = new YouTubeRequest(settings);

            Video v = Video.CreateInstance();
            v.Title = "Sample upload";
            v.Description = "This is a test with and & in it";

            MediaCategory category = new MediaCategory("Nonprofit");
            category.Attributes["scheme"] = YouTubeService.DefaultCategory;
            
            v.Tags.Add(category);
            v.Keywords = "math"; 
            v.YouTubeEntry.MediaSource = new MediaFileSource(this.resourcePath + "test_movie.mov", "video/quicktime");

            Video newVideo = f.Upload(this.ytUser, v); 

</pre></code>

<p>But overall for creating new video, while the code looks nicer and is slightly less verbose, this is not introducing a significant code saving as it is for the read case before.</p>


<a name="conclusion"><h3>Conclusion</h3></a>

The new object model is found in the Google.YouTube namespace of the .NET SDK. I invite you play with it, and report all things missing etc at the usual place (<a href="http://code.google.com/p/google-gdata/issues">Bug Report page</a>). The features currently not modeled in this are asynchronous operations, which will come later.