Skip to content

Commit

Permalink
Fix folder renaming (#449)
Browse files Browse the repository at this point in the history
  • Loading branch information
zoriya authored Apr 29, 2024
2 parents 08bb1cc + 8308bce commit 7daa10e
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 35 deletions.
21 changes: 21 additions & 0 deletions back/src/Kyoo.Core/Controllers/MiscRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,27 @@ public async Task<ICollection<string>> GetRegisteredPaths()
.ToListAsync();
}

public async Task<int> DeletePath(string path, bool recurse)
{
// Make sure to include a path separator to prevents deletions from things like:
// DeletePath("/video/abc", true) -> /video/abdc (should not be deleted)
string dirPath = path.EndsWith("/") ? path : $"{path}/";

int count = await context
.Episodes.Where(x => x.Path == path || (recurse && x.Path.StartsWith(dirPath)))
.ExecuteDeleteAsync();
count += await context
.Movies.Where(x => x.Path == path || (recurse && x.Path.StartsWith(dirPath)))
.ExecuteDeleteAsync();
await context
.Issues.Where(x =>
x.Domain == "scanner"
&& (x.Cause == path || (recurse && x.Cause.StartsWith(dirPath)))
)
.ExecuteDeleteAsync();
return count;
}

public async Task<ICollection<RefreshableItem>> GetRefreshableItems(DateTime end)
{
IQueryable<RefreshableItem> GetItems<T>()
Expand Down
24 changes: 23 additions & 1 deletion back/src/Kyoo.Core/Views/Admin/Misc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,48 @@ namespace Kyoo.Core.Api;
/// Private APIs only used for other services. Can change at any time without notice.
/// </summary>
[ApiController]
[Permission(nameof(Misc), Kind.Read, Group = Group.Admin)]
[PartialPermission(nameof(Misc), Group = Group.Admin)]
public class Misc(MiscRepository repo) : BaseApi
{
/// <summary>
/// List all registered paths.
/// </summary>
/// <returns>The list of paths known to Kyoo.</returns>
[HttpGet("/paths")]
[PartialPermission(Kind.Read)]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<ICollection<string>> GetAllPaths()
{
return repo.GetRegisteredPaths();
}

/// <summary>
/// Delete item at path.
/// </summary>
/// <param name="path">The path to delete.</param>
/// <param name="recursive">
/// If true, the path will be considered as a directory and every children will be removed.
/// </param>
/// <returns>Nothing</returns>
[HttpDelete("/paths")]
[PartialPermission(Kind.Delete)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> DeletePath(
[FromQuery] string path,
[FromQuery] bool recursive = false
)
{
await repo.DeletePath(path, recursive);
return NoContent();
}

/// <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")]
[PartialPermission(Kind.Read)]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<ICollection<RefreshableItem>> GetAllPaths([FromQuery] DateTime? date)
{
Expand Down
3 changes: 2 additions & 1 deletion scanner/matcher/parser/guess.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ async def main():
async with ClientSession() as client:
xem = TheXemClient(client)

advanced = any(x == "-a" for x in sys.argv)
ret = guessit(
sys.argv[1],
xem_titles=await xem.get_expected_titles(),
# extra_flags={"advanced": True},
extra_flags={"advanced": advanced},
)
print(json.dumps(ret, cls=GuessitEncoder, indent=4))

Expand Down
2 changes: 1 addition & 1 deletion scanner/matcher/parser/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class UnlistTitles(Rule):
consequence = [RemoveMatch, AppendMatch]

def when(self, matches: Matches, context) -> Any:
titles: List[Match] = matches.named("title") # type: ignore
titles: List[Match] = matches.named("title", lambda x: x.tagged("title")) # type: ignore

if not titles or len(titles) <= 1:
return
Expand Down
27 changes: 7 additions & 20 deletions scanner/providers/kyoo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,29 +104,16 @@ async def post(self, path: str, *, data: dict[str, Any]) -> str:
async def delete(
self,
path: str,
type: Literal["episode", "movie"] | None = None,
):
logger.info("Deleting %s", path)

if type is None or type == "movie":
async with self.client.delete(
f'{self._url}/movies?filter=path eq "{quote(path)}"',
headers={"X-API-Key": self._api_key},
) as r:
if not r.ok:
logger.error(f"Request error: {await r.text()}")
r.raise_for_status()

if type is None or type == "episode":
async with self.client.delete(
f'{self._url}/episodes?filter=path eq "{quote(path)}"',
headers={"X-API-Key": self._api_key},
) as r:
if not r.ok:
logger.error(f"Request error: {await r.text()}")
r.raise_for_status()

await self.delete_issue(path)
async with self.client.delete(
f"{self._url}/paths?recursive=true&path={quote(path)}",
headers={"X-API-Key": self._api_key},
) as r:
if not r.ok:
logger.error(f"Request error: {await r.text()}")
r.raise_for_status()

async def get(self, path: str):
async with self.client.get(
Expand Down
4 changes: 2 additions & 2 deletions scanner/scanner/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async def main():
async with Publisher() as publisher, KyooClient() as client:
path = os.environ.get("SCANNER_LIBRARY_ROOT", "/video")
await asyncio.gather(
monitor(path, publisher),
scan(path, publisher, client),
monitor(path, publisher, client),
scan(path, publisher, client, remove_deleted=True),
refresh(publisher, client),
)
11 changes: 8 additions & 3 deletions scanner/scanner/monitor.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
from logging import getLogger
from os.path import isdir
from watchfiles import awatch, Change

from .publisher import Publisher
from .scanner import scan
from providers.kyoo_client import KyooClient

logger = getLogger(__name__)


async def monitor(path: str, publisher: Publisher):
async def monitor(path: str, publisher: Publisher, client: KyooClient):
async for changes in awatch(path, ignore_permission_denied=True):
for event, file in changes:
if event == Change.added:
await publisher.add(file)
if isdir(file):
await scan(file, publisher, client)
else:
await publisher.add(file)
elif event == Change.deleted:
await publisher.delete(file)
elif event == Change.modified:
Expand Down
17 changes: 10 additions & 7 deletions scanner/scanner/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
logger = getLogger(__name__)


async def scan(path: str, publisher: Publisher, client: KyooClient):
async def scan(
path: str, publisher: Publisher, client: KyooClient, remove_deleted=False
):
logger.info("Starting the scan. It can take some times...")
ignore_pattern = None
try:
Expand All @@ -25,12 +27,13 @@ async def scan(path: str, publisher: Publisher, client: KyooClient):
to_register = [
p for p in videos if p not in registered and not ignore_pattern.match(p)
]
deleted = [x for x in registered if x not in videos]

if len(deleted) != len(registered):
await asyncio.gather(*map(publisher.delete, deleted))
elif len(deleted) > 0:
logger.warning("All video files are unavailable. Check your disks.")
if remove_deleted:
deleted = [x for x in registered if x not in videos]
if len(deleted) != len(registered):
await asyncio.gather(*map(publisher.delete, deleted))
elif len(deleted) > 0:
logger.warning("All video files are unavailable. Check your disks.")

await asyncio.gather(*map(publisher.add, to_register))
logger.info("Scan finished.")
logger.info(f"Scan finished for {path}.")

0 comments on commit 7daa10e

Please sign in to comment.