1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Configuration ;
4+ using System . IO ;
5+ using System . Linq ;
6+ using System . Net ;
7+ using System . Web . Hosting ;
8+ using Newtonsoft . Json ;
9+ using Skybrud . Essentials . Json ;
10+ using Skybrud . Social . Google . Common ;
11+ using Skybrud . Social . Google . YouTube . Models . Videos ;
12+ using Skybrud . Social . Google . YouTube . Options . PlaylistItems ;
13+ using Skybrud . Social . Google . YouTube . Options . Playlists ;
14+ using Skybrud . Social . Google . YouTube . Options . Videos ;
15+ using Umbraco . Core ;
16+ using Umbraco . Core . IO ;
17+ using Umbraco . Core . Logging ;
18+
19+ namespace OurUmbraco . Community . Videos
20+ {
21+
22+ public class CommunityVideosService
23+ {
24+ protected GoogleService Api { get ; private set ; }
25+
26+ public CommunityVideosService ( )
27+ {
28+ Api = GoogleService . CreateFromServerKey ( ConfigurationManager . AppSettings [ "GoogleServerKey" ] ) ;
29+ }
30+
31+ private bool ExistsOnDiskAndIsUpToDate ( string id )
32+ {
33+
34+ string dir = IOHelper . MapPath ( "~/App_Data/TEMP/YouTube/" ) ;
35+ string path = dir + "Video_" + id + ".json" ;
36+ return File . Exists ( path ) && File . GetLastWriteTimeUtc ( path ) >= DateTime . UtcNow . AddDays ( - 1 ) ;
37+
38+ }
39+
40+ public YouTubeVideo LoadYouTubeVideo ( string videoId )
41+ {
42+ string dir = IOHelper . MapPath ( "~/App_Data/TEMP/YouTube/" ) ;
43+ string path = dir + "Video_" + videoId + ".json" ;
44+ return File . Exists ( path ) ? JsonUtils . LoadJsonObject ( path , YouTubeVideo . Parse ) : null ;
45+ }
46+
47+ public Playlist [ ] GetPlaylists ( )
48+ {
49+ try
50+ {
51+ var path = HostingEnvironment . MapPath ( "~/config/YouTubePlaylists.json" ) ;
52+ using ( var file = File . OpenText ( path ) )
53+ {
54+ var jsonSerializer = new JsonSerializer ( ) ;
55+ var youtube = ( YouTubeInfo ) jsonSerializer . Deserialize ( file , typeof ( YouTubeInfo ) ) ;
56+ return youtube . PlayLists ;
57+ }
58+ }
59+ catch ( Exception ex )
60+ {
61+ LogHelper . Error < CommunityVideosService > ( "Unable to parse config file" , ex ) ;
62+ }
63+
64+ return new List < Playlist > ( ) . ToArray ( ) ;
65+ }
66+
67+ public YouTubeVideo [ ] LoadYouTubePlaylistVideos ( )
68+ {
69+ var videos = new List < YouTubeVideo > ( ) ;
70+
71+ var playlists = GetPlaylists ( ) ;
72+ foreach ( var playlist in playlists )
73+ videos . AddRange ( LoadYouTubePlaylistVideo ( playlist . Id ) ) ;
74+
75+ return videos . ToArray ( ) ;
76+ }
77+
78+ public YouTubeVideo [ ] LoadYouTubePlaylistVideo ( string playlistId )
79+ {
80+ string dir = IOHelper . MapPath ( "~/App_Data/TEMP/YouTube/" ) ;
81+ string path = dir + "Playlist_" + playlistId + "_Videos.json" ;
82+ return File . Exists ( path ) ? JsonUtils . LoadJsonArray ( path , YouTubeVideo . Parse ) : new YouTubeVideo [ 0 ] ;
83+ }
84+
85+ public void UpdateYouTubePlaylistVideos ( )
86+ {
87+ if ( ConfigurationManager . AppSettings [ "GoogleServerKey" ] == "it's a secret.. and no, this is not the secret, this key will transformed on the build server" )
88+ {
89+ return ;
90+ }
91+
92+ var playlists = GetPlaylists ( ) ;
93+ foreach ( var playlist in playlists )
94+ UpdateYouTubePlaylistVideo ( playlist . Id ) ;
95+ }
96+
97+ public void UpdateYouTubePlaylistVideo ( string playlistId )
98+ {
99+
100+ // Make sure we have a TEMP directory
101+ string dir = IOHelper . MapPath ( "~/App_Data/TEMP/YouTube/" ) ;
102+ Directory . CreateDirectory ( dir ) ;
103+
104+ // Make an initial request to get information about the playlist
105+ var response1 = Api . YouTube . Playlists . GetPlaylists ( new YouTubeGetPlaylistListOptions
106+ {
107+ Ids = new [ ] { playlistId }
108+ } ) ;
109+
110+ // Get a reference to the playlist (using "Single" as there should be exactly one playlist)
111+ var playlist = response1 . Body . Items . Single ( ) ;
112+
113+ // Save the playlist to the disk
114+ JsonUtils . SaveJsonObject ( dir + "Playlist_" + playlist . Id + ".json" , playlist ) ;
115+
116+ // List of all video IDs
117+ List < string > ids = new List < string > ( ) ;
118+
119+ // Initialize the options for getting the playlist items
120+ var playlistItemsOptions = new YouTubeGetPlaylistItemListOptions ( playlistId )
121+ {
122+
123+ // Maximum allowed value is 50
124+ MaxResults = 50
125+
126+ } ;
127+
128+ int page = 0 ;
129+ while ( page < 10 )
130+ {
131+
132+ // Get the playlist items
133+ var response2 = Api . YouTube . PlaylistItems . GetPlaylistItems ( playlistItemsOptions ) ;
134+
135+ // Append each video ID to the list
136+ foreach ( var item in response2 . Body . Items )
137+ {
138+ ids . Add ( item . VideoId ) ;
139+ }
140+
141+ // Break the loop if there are no additional pages
142+ if ( String . IsNullOrWhiteSpace ( response2 . Body . NextPageToken ) )
143+ {
144+ break ;
145+ }
146+
147+ // Update the options with the page token
148+ playlistItemsOptions . PageToken = response2 . Body . NextPageToken ;
149+
150+ page ++ ;
151+
152+ }
153+
154+ // Iterate through groups of IDs (maximum 50 items per group)
155+ foreach ( var group in ids . Where ( x => ! ExistsOnDiskAndIsUpToDate ( x ) ) . InGroupsOf ( 50 ) )
156+ {
157+
158+ // Initialize the video options
159+ var videosOptions = new YouTubeGetVideoListOptions
160+ {
161+ Ids = group . ToArray ( ) ,
162+ Part = YouTubeVideoParts . Snippet + YouTubeVideoParts . ContentDetails + YouTubeVideoParts . Statistics
163+ } ;
164+
165+ // Make a request to the APi to get video information
166+ var res3 = Api . YouTube . Videos . GetVideos ( videosOptions ) ;
167+
168+ // Iterate through the videos
169+ foreach ( var video in res3 . Body . Items )
170+ {
171+
172+ // Save the video to the disk
173+ string path = dir + "Video_" + video . Id + ".json" ;
174+ JsonUtils . SaveJsonObject ( path , video ) ;
175+
176+ // Download the thumnails for each video
177+ var thumbnailUrl = GetThumbnail ( video ) . Url ;
178+
179+ const string mediaRoot = "~/media/YouTube" ;
180+ var thumbnailFile = IOHelper . MapPath ( $ "{ mediaRoot } /{ video . Id } .jpg") ;
181+
182+ var mediaPath = IOHelper . MapPath ( mediaRoot ) ;
183+ if ( Directory . Exists ( mediaPath ) == false )
184+ Directory . CreateDirectory ( mediaPath ) ;
185+
186+ if ( File . Exists ( thumbnailFile ) )
187+ continue ;
188+
189+ using ( var client = new WebClient ( ) )
190+ client . DownloadFile ( thumbnailUrl , thumbnailFile ) ;
191+ }
192+ }
193+
194+ // Load the videos from the individual files, and save them to a common file
195+ JsonUtils . SaveJsonArray ( dir + "Playlist_" + playlistId + "_Videos.json" , ids . Select ( LoadYouTubeVideo ) . WhereNotNull ( ) ) ;
196+ }
197+
198+ private static YouTubeVideoThumbnail GetThumbnail ( YouTubeVideo video )
199+ {
200+ var thumbnails = new List < YouTubeVideoThumbnail > ( ) ;
201+
202+ if ( video . Snippet . Thumbnails . HasDefault )
203+ thumbnails . Add ( video . Snippet . Thumbnails . Default ) ;
204+
205+ if ( video . Snippet . Thumbnails . HasStandard )
206+ thumbnails . Add ( video . Snippet . Thumbnails . Standard ) ;
207+
208+ if ( video . Snippet . Thumbnails . HasMedium )
209+ thumbnails . Add ( video . Snippet . Thumbnails . Medium ) ;
210+
211+ if ( video . Snippet . Thumbnails . HasHigh )
212+ thumbnails . Add ( video . Snippet . Thumbnails . High ) ;
213+
214+ if ( video . Snippet . Thumbnails . HasMaxRes )
215+ thumbnails . Add ( video . Snippet . Thumbnails . MaxRes ) ;
216+
217+ var thumbnail = thumbnails . OrderBy ( x => x . Width ) . FirstOrDefault ( x => x . Width >= 350 ) ;
218+ return thumbnail ;
219+ }
220+ }
221+ }
0 commit comments