mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 10:37:13 -04:00 
			
		
		
		
	Add auto refresh of items (#433)
This commit is contained in:
		
						commit
						2641a36352
					
				| @ -28,6 +28,7 @@ using Kyoo.Abstractions.Models; | |||||||
| using Kyoo.Postgresql; | using Kyoo.Postgresql; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
|  | using static System.Text.Json.JsonNamingPolicy; | ||||||
| 
 | 
 | ||||||
| namespace Kyoo.Core.Controllers; | namespace Kyoo.Core.Controllers; | ||||||
| 
 | 
 | ||||||
| @ -82,4 +83,38 @@ public class MiscRepository( | |||||||
| 			.Concat(context.Movies.Select(x => x.Path)) | 			.Concat(context.Movies.Select(x => x.Path)) | ||||||
| 			.ToListAsync(); | 			.ToListAsync(); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	public async Task<ICollection<RefreshableItem>> GetRefreshableItems(DateTime end) | ||||||
|  | 	{ | ||||||
|  | 		IQueryable<RefreshableItem> GetItems<T>() | ||||||
|  | 			where T : class, IResource, IRefreshable | ||||||
|  | 		{ | ||||||
|  | 			return context | ||||||
|  | 				.Set<T>() | ||||||
|  | 				.Select(x => new RefreshableItem | ||||||
|  | 				{ | ||||||
|  | 					Kind = CamelCase.ConvertName(typeof(T).Name), | ||||||
|  | 					Id = x.Id, | ||||||
|  | 					RefreshDate = x.NextMetadataRefresh!.Value | ||||||
|  | 				}); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return await GetItems<Show>() | ||||||
|  | 			.Concat(GetItems<Movie>()) | ||||||
|  | 			.Concat(GetItems<Season>()) | ||||||
|  | 			.Concat(GetItems<Episode>()) | ||||||
|  | 			.Concat(GetItems<Collection>()) | ||||||
|  | 			.Where(x => x.RefreshDate <= end) | ||||||
|  | 			.OrderBy(x => x.RefreshDate) | ||||||
|  | 			.ToListAsync(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | public class RefreshableItem | ||||||
|  | { | ||||||
|  | 	public string Kind { get; set; } | ||||||
|  | 
 | ||||||
|  | 	public Guid Id { get; set; } | ||||||
|  | 
 | ||||||
|  | 	public DateTime RefreshDate { get; set; } | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with Kyoo. If not, see <https://www.gnu.org/licenses/>. | // along with Kyoo. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
|  | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using Kyoo.Abstractions.Models.Permissions; | using Kyoo.Abstractions.Models.Permissions; | ||||||
| @ -42,4 +43,16 @@ public class Misc(MiscRepository repo) : BaseApi | |||||||
| 	{ | 	{ | ||||||
| 		return repo.GetRegisteredPaths(); | 		return repo.GetRegisteredPaths(); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	/// <summary> | ||||||
|  | 	/// List items to refresh. | ||||||
|  | 	/// </summary> | ||||||
|  | 	/// <param name="date">The upper limit for the refresh date.</param> | ||||||
|  | 	/// <returns>The items that should be refreshed before the given date</returns> | ||||||
|  | 	[HttpGet("/refreshables")] | ||||||
|  | 	[ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|  | 	public Task<ICollection<RefreshableItem>> GetAllPaths([FromQuery] DateTime? date) | ||||||
|  | 	{ | ||||||
|  | 		return repo.GetRefreshableItems(date ?? DateTime.UtcNow); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -198,7 +198,7 @@ class Matcher: | |||||||
| 			"episode": id_episode, | 			"episode": id_episode, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		current = await self._client.get(kind, kyoo_id) | 		current = await self._client.get(f"{kind}/{kyoo_id}") | ||||||
| 		if self._provider.name not in current["externalId"]: | 		if self._provider.name not in current["externalId"]: | ||||||
| 			logger.error( | 			logger.error( | ||||||
| 				f"Could not refresh metadata of {kind}/{kyoo_id}. Missing provider id." | 				f"Could not refresh metadata of {kind}/{kyoo_id}. Missing provider id." | ||||||
|  | |||||||
| @ -128,11 +128,9 @@ class KyooClient: | |||||||
| 
 | 
 | ||||||
| 		await self.delete_issue(path) | 		await self.delete_issue(path) | ||||||
| 
 | 
 | ||||||
| 	async def get( | 	async def get(self, path: str): | ||||||
| 		self, kind: Literal["movie", "show", "season", "episode", "collection"], id: str |  | ||||||
| 	): |  | ||||||
| 		async with self.client.get( | 		async with self.client.get( | ||||||
| 			f"{self._url}/{kind}/{id}", | 			f"{self._url}/{path}", | ||||||
| 			headers={"X-API-Key": self._api_key}, | 			headers={"X-API-Key": self._api_key}, | ||||||
| 		) as r: | 		) as r: | ||||||
| 			if not r.ok: | 			if not r.ok: | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ async def main(): | |||||||
| 	import logging | 	import logging | ||||||
| 	from .monitor import monitor | 	from .monitor import monitor | ||||||
| 	from .scanner import scan | 	from .scanner import scan | ||||||
|  | 	from .refresher import refresh | ||||||
| 	from .publisher import Publisher | 	from .publisher import Publisher | ||||||
| 	from providers.kyoo_client import KyooClient | 	from providers.kyoo_client import KyooClient | ||||||
| 
 | 
 | ||||||
| @ -15,4 +16,5 @@ async def main(): | |||||||
| 		await asyncio.gather( | 		await asyncio.gather( | ||||||
| 			monitor(path, publisher), | 			monitor(path, publisher), | ||||||
| 			scan(path, publisher, client), | 			scan(path, publisher, client), | ||||||
|  | 			refresh(publisher, client), | ||||||
| 		) | 		) | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| import os | import os | ||||||
| from guessit.jsonutils import json | from guessit.jsonutils import json | ||||||
| from aio_pika import Message, connect_robust | from aio_pika import Message, connect_robust | ||||||
|  | from typing import Literal | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Publisher: | class Publisher: | ||||||
| @ -31,3 +32,11 @@ class Publisher: | |||||||
| 
 | 
 | ||||||
| 	async def delete(self, path: str): | 	async def delete(self, path: str): | ||||||
| 		await self._publish({"action": "delete", "path": path}) | 		await self._publish({"action": "delete", "path": path}) | ||||||
|  | 
 | ||||||
|  | 	async def refresh( | ||||||
|  | 		self, | ||||||
|  | 		kind: Literal["collection", "show", "movie", "season", "episode"], | ||||||
|  | 		id: str, | ||||||
|  | 		**_kwargs, | ||||||
|  | 	): | ||||||
|  | 		await self._publish({"action": "refresh", "kind": kind, "id": id}) | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								scanner/scanner/refresher.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								scanner/scanner/refresher.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | import asyncio | ||||||
|  | from logging import getLogger | ||||||
|  | 
 | ||||||
|  | from providers.kyoo_client import KyooClient | ||||||
|  | from scanner.publisher import Publisher | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | logger = getLogger(__name__) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | async def refresh(publisher: Publisher, client: KyooClient): | ||||||
|  | 	while True: | ||||||
|  | 		# Check for updates every 4 hours | ||||||
|  | 		await asyncio.sleep(60 * 60 * 4) | ||||||
|  | 		todo = await client.get("refreshables") | ||||||
|  | 		await asyncio.gather(*(publisher.refresh(**x) for x in todo)) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user