@@ -75,7 +75,12 @@ public static IEnumerable<VideoInfo> GetDownloadUrls(string videoUrl, bool decry
7575 if ( videoUrl == null )
7676 throw new ArgumentNullException ( "videoUrl" ) ;
7777
78- videoUrl = NormalizeYoutubeUrl ( videoUrl ) ;
78+ bool isYoutubeUrl = TryNormalizeYoutubeUrl ( videoUrl , out videoUrl ) ;
79+
80+ if ( ! isYoutubeUrl )
81+ {
82+ throw new ArgumentException ( "URL is not a valid youtube URL!" ) ;
83+ }
7984
8085 try
8186 {
@@ -115,6 +120,54 @@ public static IEnumerable<VideoInfo> GetDownloadUrls(string videoUrl, bool decry
115120 return null ; // Will never happen, but the compiler requires it
116121 }
117122
123+ #if PORTABLE
124+
125+ public static async System . Threading . Tasks . Task < IEnumerable < VideoInfo > > GetDownloadUrlsAsync ( string videoUrl , bool decryptSignature = true )
126+ {
127+ return await System . Threading . Tasks . Task . Run ( ( ) => GetDownloadUrls ( videoUrl , decryptSignature ) ) ;
128+ }
129+
130+ #endif
131+
132+ /// <summary>
133+ /// Normalizes the given YouTube URL to the format http://youtube.com/watch?v={youtube-id}
134+ /// and returns whether the normalization was successful or not.
135+ /// </summary>
136+ /// <param name="url">The YouTube URL to normalize.</param>
137+ /// <param name="normalizedUrl">The normalized YouTube URL.</param>
138+ /// <returns>
139+ /// <c>true</c>, if the normalization was successful; <c>false</c>, if the URL is invalid.
140+ /// </returns>
141+ public static bool TryNormalizeYoutubeUrl ( string url , out string normalizedUrl )
142+ {
143+ url = url . Trim ( ) ;
144+
145+ url = url . Replace ( "youtu.be/" , "youtube.com/watch?v=" ) ;
146+ url = url . Replace ( "www.youtube" , "youtube" ) ;
147+ url = url . Replace ( "youtube.com/embed/" , "youtube.com/watch?v=" ) ;
148+
149+ if ( url . Contains ( "/v/" ) )
150+ {
151+ url = "http://youtube.com" + new Uri ( url ) . AbsolutePath . Replace ( "/v/" , "/watch?v=" ) ;
152+ }
153+
154+ url = url . Replace ( "/watch#" , "/watch?" ) ;
155+
156+ IDictionary < string , string > query = HttpHelper . ParseQueryString ( url ) ;
157+
158+ string v ;
159+
160+ if ( ! query . TryGetValue ( "v" , out v ) )
161+ {
162+ normalizedUrl = null ;
163+ return false ;
164+ }
165+
166+ normalizedUrl = "http://youtube.com/watch?v=" + v ;
167+
168+ return true ;
169+ }
170+
118171 private static IEnumerable < Uri > ExtractDownloadUrls ( JObject json )
119172 {
120173 string [ ] splitByUrls = GetStreamMap ( json ) . Split ( ',' ) ;
@@ -254,42 +307,6 @@ private static JObject LoadJson(string url)
254307 return JObject . Parse ( extractedJson ) ;
255308 }
256309
257- #if PORTABLE
258-
259- public static async System . Threading . Tasks . Task < IEnumerable < VideoInfo > > GetDownloadUrlsAsync ( string videoUrl , bool decryptSignature = true )
260- {
261- return await System . Threading . Tasks . Task . Run ( ( ) => GetDownloadUrls ( videoUrl , decryptSignature ) ) ;
262- }
263-
264- #endif
265-
266- private static string NormalizeYoutubeUrl ( string url )
267- {
268- url = url . Trim ( ) ;
269-
270- url = url . Replace ( "youtu.be/" , "youtube.com/watch?v=" ) ;
271- url = url . Replace ( "www.youtube" , "youtube" ) ;
272- url = url . Replace ( "youtube.com/embed/" , "youtube.com/watch?v=" ) ;
273-
274- if ( url . Contains ( "/v/" ) )
275- {
276- url = "http://youtube.com" + new Uri ( url ) . AbsolutePath . Replace ( "/v/" , "/watch?v=" ) ;
277- }
278-
279- url = url . Replace ( "/watch#" , "/watch?" ) ;
280-
281- IDictionary < string , string > query = HttpHelper . ParseQueryString ( url ) ;
282-
283- string v ;
284-
285- if ( ! query . TryGetValue ( "v" , out v ) )
286- {
287- throw new ArgumentException ( "URL is not a valid youtube URL!" ) ;
288- }
289-
290- return "http://youtube.com/watch?v=" + v ;
291- }
292-
293310 private static void ThrowYoutubeParseException ( Exception innerException )
294311 {
295312 throw new YoutubeParseException ( "Could not parse the Youtube page.\n " +
0 commit comments