Compare commits

...

5 Commits

Author SHA1 Message Date
6e77474d15 Couple of fixes 2026-05-24 16:42:51 +10:00
72bad08a61 Merge branch 'master' into gdrive 2026-05-24 14:24:34 +10:00
b217fbea5e Sorted out linting 2026-05-24 14:23:59 +10:00
cec64ecd2f Working with manual sync 2026-05-24 13:51:23 +10:00
d30005d5b6 Indexing bug fix 2026-05-24 11:48:42 +10:00
6 changed files with 54 additions and 17 deletions

View File

@ -1,4 +1,5 @@
from .base import * # noqa from .base import * # noqa
from os import environ
DEBUG = True DEBUG = True
@ -8,3 +9,20 @@ SECRET_KEY = "DO NOT USE IN PRODUCTION"
INSTALLED_APPS.append("debug_toolbar") # noqa INSTALLED_APPS.append("debug_toolbar") # noqa
MIDDLEWARE.insert(1, "debug_toolbar.middleware.DebugToolbarMiddleware") # noqa MIDDLEWARE.insert(1, "debug_toolbar.middleware.DebugToolbarMiddleware") # noqa
INTERNAL_IPS = ["127.0.0.1"] INTERNAL_IPS = ["127.0.0.1"]
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": environ.get("DEBUG_LEVEL", "WARNING"),
},
},
"loggers": {
"polyphonic": {
"handlers": ["console"],
"level": environ.get("DEBUG_LEVEL", "WARNING"),
}
},
}

View File

@ -1,4 +1,5 @@
from polyphonic.library.models import Collection, Work, WorkMeta, Document from polyphonic.library.models import Collection, Work, WorkMeta, Document
from byostorage.models import UserStorage
import logging import logging
@ -6,12 +7,11 @@ logger = logging.getLogger(__name__)
def sync_work(work: Work): def sync_work(work: Work):
logger.info("Syncing '%s'", work.name)
folder_id = work.meta_info.get(name="folderid").value folder_id = work.meta_info.get(name="folderid").value
storage = work.collection.storage.instance() logger.info("Syncing '%s' from %r", work.name, folder_id)
prefix = work.collection.storage.name
_, files = storage.listdir(folder_id) storage = UserStorage.objects.get(name="gdrive").instance()
existing = set( existing = set(
[ [
@ -21,6 +21,9 @@ def sync_work(work: Work):
) )
logger.debug("%d existing documents", len(existing)) logger.debug("%d existing documents", len(existing))
_, files = storage.listdir(folder_id)
logger.debug("Remote files: %r", files)
for file in files: for file in files:
if file.id in existing: if file.id in existing:
logger.debug("%30s: Skipping existing (%s)", file.name, file.id) logger.debug("%30s: Skipping existing (%s)", file.name, file.id)
@ -32,7 +35,7 @@ def sync_work(work: Work):
continue continue
logger.info("%40s: Adding", file.name) logger.info("%40s: Adding", file.name)
doc = work.docs.create(upload=f"{prefix}:{file}", doctype=Document.DOCTYPE_PDF) doc = work.docs.create(upload=f"gdrive:{file}", doctype=Document.DOCTYPE_PDF)
doc.auto_tag() doc.auto_tag()
for uri in existing: for uri in existing:
@ -45,8 +48,10 @@ def sync_collection(collection: Collection, sync_existing: bool = False):
if not collection.storage.storage.endswith("GDriveLinkStorage"): if not collection.storage.storage.endswith("GDriveLinkStorage"):
raise RuntimeError("Not a gdrive storage") raise RuntimeError("Not a gdrive storage")
if not collection.prefix: try:
raise KeyError("Prefix must store folder id") folder_id = collection.settings["folder_id"]
except KeyError:
raise KeyError("Missing 'folder_id' in settings")
existing = dict( existing = dict(
WorkMeta.objects.filter( WorkMeta.objects.filter(
@ -55,9 +60,12 @@ def sync_collection(collection: Collection, sync_existing: bool = False):
) )
storage = collection.storage.instance() storage = collection.storage.instance()
folders, _ = storage.listdir(collection.prefix) folders, _ = storage.listdir(folder_id)
for folder in folders: for folder in folders:
if folder[0] == "_":
continue
if folder.id in existing: if folder.id in existing:
if sync_existing: if sync_existing:
logger.info("%40s: Syncing (%s)", folder.name, folder.id[:12]) logger.info("%40s: Syncing (%s)", folder.name, folder.id[:12])

View File

@ -8,7 +8,7 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
SHARED_FOLDER = re.compile(r"https://drive.google.com/drive/folders/(\w+)") SHARED_FOLDER = re.compile(r"https://drive.google.com/drive[u0-9\/]+folders/([\w\-]+)")
SHARED_FILE = re.compile(r"https://drive.google.com/file/d/([\w\-]+)") SHARED_FILE = re.compile(r"https://drive.google.com/file/d/([\w\-]+)")
FILES_API = "https://www.googleapis.com/drive/v3/files" FILES_API = "https://www.googleapis.com/drive/v3/files"
@ -50,12 +50,11 @@ class GDriveLinkStorage(Storage):
return data return data
def listdir(self, path) -> tuple[list[str], list[str]]: def listdir(self, path) -> tuple[list[str], list[str]]:
# used to test for valid connection parameters - should do something to validate API key here # used to test for valid connection parameters - should do something to validate API key here
logger.debug("listdir: %s", path)
if path == "": if path == "":
return [], [] return [], []
logger.debug("LISTDIR: %s", path)
folder_id = self.parse_id(path) folder_id = self.parse_id(path)
url = f"{FILES_API}?q='{folder_id}'+in+parents&key={self.api_key}" url = f"{FILES_API}?q='{folder_id}'+in+parents&key={self.api_key}"
data = self.get_json(url) data = self.get_json(url)

View File

@ -6,6 +6,8 @@ from polyphonic.library.models import Work, Document
from polyphonic.library import forms from polyphonic.library import forms
from byostorage.models import UserStorage from byostorage.models import UserStorage
from . import sync_work
class WorkGDriveView(CollectionMixin, SingleObjectMixin, FormView): class WorkGDriveView(CollectionMixin, SingleObjectMixin, FormView):
model = Work model = Work
@ -37,11 +39,13 @@ class WorkGDriveView(CollectionMixin, SingleObjectMixin, FormView):
self.object.meta_info.update_or_create( self.object.meta_info.update_or_create(
name="folderid", defaults={"value": folderid} name="folderid", defaults={"value": folderid}
) )
sync_work(self.object)
return redirect("work_detail", self.collection.pk, self.kwargs["pk"]) return redirect("work_detail", self.collection.pk, self.kwargs["pk"])
link = storage.import_link(link) link = storage.import_link(link)
if link is None: if link is None:
form.add_error("link", str(e)) form.add_error("link", "Not a valid link")
return self.form_invalid(form) return self.form_invalid(form)
work = self.collection.works.get(pk=self.kwargs["pk"]) work = self.collection.works.get(pk=self.kwargs["pk"])

View File

@ -23,7 +23,7 @@ from polyphonic.library.models import Collection, Work, Document, Section
from polyphonic.library.music_tags import MUSIC_TAGS, MusicTag from polyphonic.library.music_tags import MUSIC_TAGS, MusicTag
from polyphonic.library import forms, models from polyphonic.library import forms, models
from polyphonic.library.pdf_utils import extract_pages, extract_and_concat from polyphonic.library.pdf_utils import extract_pages, extract_and_concat
from polyphonic.library.indexer import indexer, model_search from polyphonic.library.indexer import index_works, model_search
import logging import logging
@ -304,8 +304,7 @@ class WorkAddView(CollectionMixin, FormView):
for f in uploads: for f in uploads:
docs.append(work.docs.create(upload=f).pk) docs.append(work.docs.create(upload=f).pk)
ix = indexer.get_index() index_works([work])
indexer.index_works(ix, [work])
if len(docs) == 1: if len(docs) == 1:
return redirect("document_annotate", docs[0]) return redirect("document_annotate", docs[0])
@ -339,8 +338,7 @@ class WorkUpdateView(CollectionMixin, UpdateView):
def form_valid(self, form): def form_valid(self, form):
response = super().form_valid(form) response = super().form_valid(form)
ix = indexer.get_index() index_works([self.object])
indexer.index_works(ix, [self.object])
return response return response

View File

@ -26,12 +26,22 @@ dependencies = [
django-debug-toolbar = "5.2" django-debug-toolbar = "5.2"
ruff = "^0.15.12" ruff = "^0.15.12"
coverage = "^7.14.0" coverage = "^7.14.0"
django-types = "^0.24.0"
[tool.poetry.scripts] [tool.poetry.scripts]
poly-tool = "polyphonic.manage:main" poly-tool = "polyphonic.manage:main"
[tool.ruff] [tool.ruff]
extend-exclude = ["**/migrations/"] extend-exclude = ["**/migrations/"]
lint.extend-select = [
#"DJ", # flake8-django: Django-specific bugs
#"E", # pycodestyle errors
"F", # Pyflakes
#"W", # pycodestyle warnings
#"I", # isort
#"UP", # pyupgrade
#"B", # flake8-bugbear
]
[build-system] [build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"] requires = ["poetry-core>=2.0.0,<3.0.0"]