@@ -222,5 +222,139 @@ public void DeleteMediaItem(int userId, int mediaItemId)
222222 AuditLogManager . Log ( user , AuditEventType . DeletedItem , "{EntityType:\" Comment\" , EntityID:" + mediaItemId + ",ChargePointID:" + cpID + "}" , "User deleted media item" ) ;
223223 }
224224 }
225+
226+ public async Task < List < MediaItem > > GetMediaItemsWithMissingThumbnails ( int maxResults = 100 )
227+ {
228+ var dataModel = new OCMEntities ( ) ;
229+
230+ var items = dataModel . MediaItems
231+ . Where ( m => m . IsEnabled == true &&
232+ m . ItemUrl != null &&
233+ ( m . ItemThumbnailUrl == null || m . ItemThumbnailUrl == "" ) &&
234+ ! m . IsExternalResource &&
235+ ! m . IsVideo )
236+ . Take ( maxResults )
237+ . ToList ( ) ;
238+
239+ return items ;
240+ }
241+
242+ public async Task < ReprocessMediaResult > ReprocessMediaItem ( int mediaItemId , string tempFolderPath )
243+ {
244+ var result = new ReprocessMediaResult { MediaItemId = mediaItemId } ;
245+ var dataModel = new OCMEntities ( ) ;
246+
247+ var mediaItem = dataModel . MediaItems . FirstOrDefault ( m => m . Id == mediaItemId ) ;
248+
249+ if ( mediaItem == null )
250+ {
251+ result . Success = false ;
252+ result . Message = "Media item not found" ;
253+ return result ;
254+ }
255+
256+ if ( string . IsNullOrEmpty ( mediaItem . ItemUrl ) )
257+ {
258+ result . Success = false ;
259+ result . Message = "No original image URL" ;
260+ return result ;
261+ }
262+
263+ if ( mediaItem . IsVideo || mediaItem . IsExternalResource )
264+ {
265+ result . Success = false ;
266+ result . Message = "Cannot reprocess video or external resources" ;
267+ return result ;
268+ }
269+
270+ // Get POI info for metadata
271+ var poi = await new POIManager ( ) . Get ( mediaItem . ChargePointId ) ;
272+ if ( poi == null )
273+ {
274+ result . Success = false ;
275+ result . Message = "Associated charging location not found" ;
276+ return result ;
277+ }
278+
279+ try
280+ {
281+ // Download the original image
282+ string extension = Path . GetExtension ( mediaItem . ItemUrl ) . ToLower ( ) ;
283+ if ( string . IsNullOrEmpty ( extension ) )
284+ {
285+ extension = ".jpg" ;
286+ }
287+
288+ string tempOriginalFile = Path . Combine ( tempFolderPath , $ "temp_original_{ mediaItemId } { extension } ") ;
289+
290+ using ( var client = new System . Net . Http . HttpClient ( ) )
291+ {
292+ client . Timeout = TimeSpan . FromMinutes ( 2 ) ;
293+ var imageBytes = await client . GetByteArrayAsync ( mediaItem . ItemUrl ) ;
294+ await File . WriteAllBytesAsync ( tempOriginalFile , imageBytes ) ;
295+ }
296+
297+ // Generate thumbnails
298+ string destFolderPrefix = poi . AddressInfo . Country . ISOCode + "/" + "OCM" + poi . ID + "/" ;
299+ string dateStamp = String . Format ( "{0:yyyyMMddHHmmssff}" , DateTime . UtcNow ) ;
300+ string thumbFileName = "OCM-" + poi . ID + ".thmb." + dateStamp + extension ;
301+ string mediumFileName = "OCM-" + poi . ID + ".medi." + dateStamp + extension ;
302+
303+ string thumbFilePath = Path . Combine ( tempFolderPath , thumbFileName ) ;
304+ string mediumFilePath = Path . Combine ( tempFolderPath , mediumFileName ) ;
305+
306+ GenerateImageThumbnails ( tempOriginalFile , thumbFilePath , 100 ) ;
307+ GenerateImageThumbnails ( tempOriginalFile , mediumFilePath , 400 ) ;
308+
309+ // Upload to storage
310+ var storage = new StorageManager ( ) ;
311+ var metadataTags = new List < KeyValuePair < string , string > >
312+ {
313+ new KeyValuePair < string , string > ( "OCM" , poi . ID . ToString ( ) ) ,
314+ new KeyValuePair < string , string > ( "Latitude" , poi . AddressInfo . Latitude . ToString ( ) ) ,
315+ new KeyValuePair < string , string > ( "Longitude" , poi . AddressInfo . Longitude . ToString ( ) )
316+ } ;
317+
318+ string thumbnailUrl = await storage . UploadImageAsync ( thumbFilePath , destFolderPrefix + thumbFileName , metadataTags ) ;
319+ string mediumUrl = await storage . UploadImageAsync ( mediumFilePath , destFolderPrefix + mediumFileName , metadataTags ) ;
320+
321+ // Update database
322+ mediaItem . ItemThumbnailUrl = thumbnailUrl ;
323+ await dataModel . SaveChangesAsync ( ) ;
324+
325+ // Clean up temp files
326+ try
327+ {
328+ File . Delete ( tempOriginalFile ) ;
329+ File . Delete ( thumbFilePath ) ;
330+ File . Delete ( mediumFilePath ) ;
331+ }
332+ catch { }
333+
334+ result . Success = true ;
335+ result . Message = "Successfully reprocessed" ;
336+ result . ThumbnailUrl = thumbnailUrl ;
337+ result . MediumUrl = mediumUrl ;
338+
339+ AuditLogManager . Log ( null , AuditEventType . UpdatedItem , $ "Reprocessed media item { mediaItemId } , generated thumbnail: { thumbnailUrl } ", "" ) ;
340+ }
341+ catch ( Exception ex )
342+ {
343+ result . Success = false ;
344+ result . Message = $ "Error: { ex . Message } ";
345+ AuditLogManager . Log ( null , AuditEventType . SystemErrorAPI , $ "Failed to reprocess media item { mediaItemId } : { ex . Message } ", ex . ToString ( ) ) ;
346+ }
347+
348+ return result ;
349+ }
350+ }
351+
352+ public class ReprocessMediaResult
353+ {
354+ public int MediaItemId { get ; set ; }
355+ public bool Success { get ; set ; }
356+ public string Message { get ; set ; }
357+ public string ThumbnailUrl { get ; set ; }
358+ public string MediumUrl { get ; set ; }
225359 }
226360}
0 commit comments