Add auto refresh of items (#433)

This commit is contained in:
Zoe Roux 2024-04-23 22:32:19 +02:00 committed by GitHub
commit 2641a36352
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 78 additions and 5 deletions

View File

@ -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; }
} }

View File

@ -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);
}
} }

View File

@ -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."

View File

@ -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:

View File

@ -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),
) )

View File

@ -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})

View 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))