|  |  | @ -1,5 +1,6 @@ | 
			
		
	
		
			
				
					|  |  |  | import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; | 
			
		
	
		
			
				
					|  |  |  | import { PrismaService } from '@ghostfolio/api/services/prisma.service'; | 
			
		
	
		
			
				
					|  |  |  | import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service'; | 
			
		
	
		
			
				
					|  |  |  | import { | 
			
		
	
		
			
				
					|  |  |  |   DATE_FORMAT, | 
			
		
	
		
			
				
					|  |  |  |   getYesterday, | 
			
		
	
	
		
			
				
					|  |  | @ -13,19 +14,20 @@ import * as cheerio from 'cheerio'; | 
			
		
	
		
			
				
					|  |  |  | import { format } from 'date-fns'; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | import { | 
			
		
	
		
			
				
					|  |  |  |   IDataGatheringItem, | 
			
		
	
		
			
				
					|  |  |  |   IDataProviderHistoricalResponse, | 
			
		
	
		
			
				
					|  |  |  |   IDataProviderResponse, | 
			
		
	
		
			
				
					|  |  |  |   MarketState | 
			
		
	
		
			
				
					|  |  |  | } from '../../interfaces/interfaces'; | 
			
		
	
		
			
				
					|  |  |  | import { DataProviderInterface } from '../interfaces/data-provider.interface'; | 
			
		
	
		
			
				
					|  |  |  | import { ScraperConfig } from './interfaces/scraper-config.interface'; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | @Injectable() | 
			
		
	
		
			
				
					|  |  |  | export class GhostfolioScraperApiService implements DataProviderInterface { | 
			
		
	
		
			
				
					|  |  |  |   private static NUMERIC_REGEXP = /[-]{0,1}[\d]*[.,]{0,1}[\d]+/g; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   public constructor(private readonly prismaService: PrismaService) {} | 
			
		
	
		
			
				
					|  |  |  |   public constructor( | 
			
		
	
		
			
				
					|  |  |  |     private readonly prismaService: PrismaService, | 
			
		
	
		
			
				
					|  |  |  |     private readonly symbolProfileService: SymbolProfileService | 
			
		
	
		
			
				
					|  |  |  |   ) {} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   public canHandle(symbol: string) { | 
			
		
	
		
			
				
					|  |  |  |     return isGhostfolioScraperApiSymbol(symbol); | 
			
		
	
	
		
			
				
					|  |  | @ -39,9 +41,10 @@ export class GhostfolioScraperApiService implements DataProviderInterface { | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       const symbol = aSymbols[0]; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       const scraperConfig = await this.getScraperConfigurationBySymbol(symbol); | 
			
		
	
		
			
				
					|  |  |  |       const [symbol] = aSymbols; | 
			
		
	
		
			
				
					|  |  |  |       const [symbolProfile] = await this.symbolProfileService.getSymbolProfiles( | 
			
		
	
		
			
				
					|  |  |  |         [symbol] | 
			
		
	
		
			
				
					|  |  |  |       ); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       const { marketPrice } = await this.prismaService.marketData.findFirst({ | 
			
		
	
		
			
				
					|  |  |  |         orderBy: { | 
			
		
	
	
		
			
				
					|  |  | @ -55,7 +58,7 @@ export class GhostfolioScraperApiService implements DataProviderInterface { | 
			
		
	
		
			
				
					|  |  |  |       return { | 
			
		
	
		
			
				
					|  |  |  |         [symbol]: { | 
			
		
	
		
			
				
					|  |  |  |           marketPrice, | 
			
		
	
		
			
				
					|  |  |  |           currency: scraperConfig?.currency, | 
			
		
	
		
			
				
					|  |  |  |           currency: symbolProfile?.currency, | 
			
		
	
		
			
				
					|  |  |  |           dataSource: DataSource.GHOSTFOLIO, | 
			
		
	
		
			
				
					|  |  |  |           marketState: MarketState.delayed | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
	
		
			
				
					|  |  | @ -67,25 +70,6 @@ export class GhostfolioScraperApiService implements DataProviderInterface { | 
			
		
	
		
			
				
					|  |  |  |     return {}; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   public async getCustomSymbolsToGather( | 
			
		
	
		
			
				
					|  |  |  |     startDate?: Date | 
			
		
	
		
			
				
					|  |  |  |   ): Promise<IDataGatheringItem[]> { | 
			
		
	
		
			
				
					|  |  |  |     const ghostfolioSymbolProfiles = | 
			
		
	
		
			
				
					|  |  |  |       await this.prismaService.symbolProfile.findMany({ | 
			
		
	
		
			
				
					|  |  |  |         where: { | 
			
		
	
		
			
				
					|  |  |  |           dataSource: DataSource.GHOSTFOLIO | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |       }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     return ghostfolioSymbolProfiles.map(({ dataSource, symbol }) => { | 
			
		
	
		
			
				
					|  |  |  |       return { | 
			
		
	
		
			
				
					|  |  |  |         dataSource, | 
			
		
	
		
			
				
					|  |  |  |         symbol, | 
			
		
	
		
			
				
					|  |  |  |         date: startDate | 
			
		
	
		
			
				
					|  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   public async getHistorical( | 
			
		
	
		
			
				
					|  |  |  |     aSymbols: string[], | 
			
		
	
		
			
				
					|  |  |  |     aGranularity: Granularity = 'day', | 
			
		
	
	
		
			
				
					|  |  | @ -99,11 +83,11 @@ export class GhostfolioScraperApiService implements DataProviderInterface { | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       const symbol = aSymbols[0]; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       const scraperConfiguration = await this.getScraperConfigurationBySymbol( | 
			
		
	
		
			
				
					|  |  |  |         symbol | 
			
		
	
		
			
				
					|  |  |  |       const [symbol] = aSymbols; | 
			
		
	
		
			
				
					|  |  |  |       const [symbolProfile] = await this.symbolProfileService.getSymbolProfiles( | 
			
		
	
		
			
				
					|  |  |  |         [symbol] | 
			
		
	
		
			
				
					|  |  |  |       ); | 
			
		
	
		
			
				
					|  |  |  |       const scraperConfiguration = symbolProfile?.scraperConfiguration; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       const get = bent(scraperConfiguration?.url, 'GET', 'string', 200, {}); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -128,22 +112,6 @@ export class GhostfolioScraperApiService implements DataProviderInterface { | 
			
		
	
		
			
				
					|  |  |  |     return {}; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   public async getScraperConfigurations(): Promise<ScraperConfig[]> { | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       const { value: scraperConfigString } = | 
			
		
	
		
			
				
					|  |  |  |         await this.prismaService.property.findFirst({ | 
			
		
	
		
			
				
					|  |  |  |           select: { | 
			
		
	
		
			
				
					|  |  |  |             value: true | 
			
		
	
		
			
				
					|  |  |  |           }, | 
			
		
	
		
			
				
					|  |  |  |           where: { key: 'SCRAPER_CONFIG' } | 
			
		
	
		
			
				
					|  |  |  |         }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       return JSON.parse(scraperConfigString); | 
			
		
	
		
			
				
					|  |  |  |     } catch {} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     return []; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   public getName(): DataSource { | 
			
		
	
		
			
				
					|  |  |  |     return DataSource.GHOSTFOLIO; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
	
		
			
				
					|  |  | @ -162,11 +130,4 @@ export class GhostfolioScraperApiService implements DataProviderInterface { | 
			
		
	
		
			
				
					|  |  |  |       return undefined; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   private async getScraperConfigurationBySymbol(aSymbol: string) { | 
			
		
	
		
			
				
					|  |  |  |     const scraperConfigurations = await this.getScraperConfigurations(); | 
			
		
	
		
			
				
					|  |  |  |     return scraperConfigurations.find((scraperConfiguration) => { | 
			
		
	
		
			
				
					|  |  |  |       return scraperConfiguration.symbol === aSymbol; | 
			
		
	
		
			
				
					|  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
	
		
			
				
					|  |  | 
 |