@@ -271,6 +271,150 @@ class Sonarr {
271271 }
272272 return csCards ;
273273 }
274+
275+ /**
276+ * Series with episode imports in the last N days (history downloadFolderImported).
277+ * Uses *arr artwork (not media-server poster cache).
278+ */
279+ async GetRecentlyAdded ( days , playThemes , hasArt ) {
280+ const cards = [ ] ;
281+ const dayCount = Math . max ( 0 , Number ( days ) || 0 ) ;
282+ if ( dayCount <= 0 ) return cards ;
283+
284+ const from = new Date ( ) ;
285+ from . setDate ( from . getDate ( ) - dayCount ) ;
286+ from . setHours ( 0 , 0 , 0 , 0 ) ;
287+
288+ let hist ;
289+ try {
290+ hist = await axios . get (
291+ this . sonarrUrl +
292+ "/api/v3/history?page=1&pageSize=250&sortKey=date&sortDirection=descending" +
293+ "&eventType=3&includeSeries=true&includeEpisode=true&apikey=" +
294+ this . sonarrToken
295+ ) ;
296+ } catch ( err ) {
297+ const d = new Date ( ) ;
298+ console . log (
299+ d . toLocaleString ( ) + " *Sonarr - Get recently added history:" ,
300+ err . message
301+ ) ;
302+ throw err ;
303+ }
304+
305+ const records =
306+ hist && hist . data && Array . isArray ( hist . data . records )
307+ ? hist . data . records
308+ : Array . isArray ( hist . data )
309+ ? hist . data
310+ : [ ] ;
311+
312+ const bySeries = new Map ( ) ;
313+ for ( const rec of records ) {
314+ if ( ! rec ) continue ;
315+ const when = rec . date ? new Date ( rec . date ) : null ;
316+ if ( ! when || Number . isNaN ( when . getTime ( ) ) || when < from ) continue ;
317+ const series = rec . series || { } ;
318+ const seriesId = series . id || rec . seriesId ;
319+ if ( ! seriesId ) continue ;
320+ const key = String ( seriesId ) ;
321+ const prev = bySeries . get ( key ) ;
322+ if ( ! prev || when > prev . when ) {
323+ bySeries . set ( key , { when, series, episode : rec . episode || { } } ) ;
324+ }
325+ }
326+
327+ for ( const { when, series, episode } of bySeries . values ( ) ) {
328+ let rawSeries = { data : series } ;
329+ if ( ! series . images || ! series . tvdbId ) {
330+ try {
331+ rawSeries = await this . GetSeriesRawData ( series . id || series . Id ) ;
332+ } catch ( e ) {
333+ continue ;
334+ }
335+ }
336+ const sd = rawSeries . data || series ;
337+ const tvdbId = sd . tvdbId || sd . TvdbId ;
338+ if ( ! tvdbId ) continue ;
339+
340+ const medCard = new mediaCard ( ) ;
341+ const addedDay = when . toISOString ( ) . split ( "T" ) [ 0 ] ;
342+ const epLabel =
343+ episode && episode . seasonNumber != null && episode . episodeNumber != null
344+ ? "S" +
345+ String ( episode . seasonNumber ) . padStart ( 2 , "0" ) +
346+ "E" +
347+ String ( episode . episodeNumber ) . padStart ( 2 , "0" )
348+ : "" ;
349+ medCard . tagLine =
350+ ( sd . title || series . title || "" ) +
351+ ( epLabel ? " — " + epLabel : "" ) +
352+ " (" +
353+ addedDay +
354+ ")" ;
355+ medCard . title = episode . title || sd . title || series . title || "" ;
356+ medCard . DBID = tvdbId ;
357+ medCard . year = addedDay ;
358+ medCard . runTime = sd . runtime ;
359+ medCard . genre = sd . genres ;
360+ medCard . summary = await util . emptyIfNull ( sd . overview ) ;
361+ medCard . mediaType = "episode" ;
362+ medCard . cardType = cType . CardTypeEnum . RecentlyAdded ;
363+ medCard . network = sd . network || "" ;
364+ medCard . posterAR = 1.47 ;
365+
366+ let contentRating = "NR" ;
367+ if ( ! ( await util . isEmpty ( sd . certification ) ) ) {
368+ contentRating = sd . certification ;
369+ }
370+ medCard . contentRating = contentRating ;
371+ medCard . ratingColour = "badge-dark" ;
372+
373+ if ( playThemes == "true" ) {
374+ const mp3 = tvdbId + ".mp3" ;
375+ await core . CacheMP3 ( mp3 ) ;
376+ medCard . theme = "/mp3cache/" + mp3 ;
377+ }
378+
379+ let posterUrl ;
380+ const images = Array . isArray ( sd . images ) ? sd . images : [ ] ;
381+ images . forEach ( ( i ) => {
382+ if ( i . coverType === "poster" ) posterUrl = i . remoteUrl ;
383+ } ) ;
384+ const fileName = "arr-sonarr-ra-" + tvdbId + ".jpg" ;
385+ if ( posterUrl ) {
386+ await core . CacheArrImage ( posterUrl , fileName ) ;
387+ medCard . posterURL = "/imagecache/" + fileName ;
388+ } else {
389+ medCard . posterURL = "/images/no-poster-available.png" ;
390+ }
391+
392+ if ( hasArt == "true" ) {
393+ let fanUrl ;
394+ images . forEach ( ( i ) => {
395+ if ( i . coverType === "fanart" ) fanUrl = i . remoteUrl ;
396+ } ) ;
397+ if ( fanUrl ) {
398+ const artName = "arr-sonarr-ra-" + tvdbId + "-art.jpg" ;
399+ await core . CacheArrImage ( fanUrl , artName ) ;
400+ medCard . posterArtURL = "/imagecache/" + artName ;
401+ }
402+ }
403+
404+ cards . push ( medCard ) ;
405+ }
406+
407+ const now = new Date ( ) ;
408+ console . log (
409+ now . toLocaleString ( ) +
410+ " *Sonarr — Recently added last " +
411+ dayCount +
412+ " day(s): " +
413+ cards . length +
414+ " series import(s)"
415+ ) ;
416+ return cards ;
417+ }
274418}
275419
276420module . exports = Sonarr ;
0 commit comments