mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-11-04 03:27:14 -05: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