notionary 0.3.1__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- notionary/__init__.py +6 -1
- notionary/blocks/enums.py +0 -6
- notionary/blocks/schemas.py +32 -78
- notionary/comments/schemas.py +2 -29
- notionary/data_source/properties/schemas.py +128 -107
- notionary/data_source/schemas.py +2 -2
- notionary/data_source/service.py +32 -23
- notionary/database/schemas.py +2 -2
- notionary/database/service.py +3 -5
- notionary/exceptions/__init__.py +6 -2
- notionary/exceptions/api.py +2 -2
- notionary/exceptions/base.py +1 -1
- notionary/exceptions/block_parsing.py +3 -3
- notionary/exceptions/data_source/builder.py +2 -2
- notionary/exceptions/data_source/properties.py +3 -3
- notionary/exceptions/file_upload.py +67 -0
- notionary/exceptions/properties.py +4 -4
- notionary/exceptions/search.py +4 -4
- notionary/file_upload/__init__.py +4 -0
- notionary/file_upload/client.py +124 -210
- notionary/file_upload/config/__init__.py +17 -0
- notionary/file_upload/config/config.py +32 -0
- notionary/file_upload/config/constants.py +16 -0
- notionary/file_upload/file/reader.py +28 -0
- notionary/file_upload/query/__init__.py +7 -0
- notionary/file_upload/query/builder.py +54 -0
- notionary/file_upload/query/models.py +37 -0
- notionary/file_upload/schemas.py +78 -0
- notionary/file_upload/service.py +152 -289
- notionary/file_upload/validation/factory.py +64 -0
- notionary/file_upload/validation/impl/file_name_length.py +23 -0
- notionary/file_upload/validation/models.py +124 -0
- notionary/file_upload/validation/port.py +7 -0
- notionary/file_upload/validation/service.py +17 -0
- notionary/file_upload/validation/validators/__init__.py +11 -0
- notionary/file_upload/validation/validators/file_exists.py +15 -0
- notionary/file_upload/validation/validators/file_extension.py +122 -0
- notionary/file_upload/validation/validators/file_name_length.py +21 -0
- notionary/file_upload/validation/validators/upload_limit.py +31 -0
- notionary/http/client.py +6 -22
- notionary/page/content/parser/factory.py +8 -5
- notionary/page/content/parser/parsers/audio.py +8 -33
- notionary/page/content/parser/parsers/embed.py +0 -2
- notionary/page/content/parser/parsers/file.py +8 -35
- notionary/page/content/parser/parsers/file_like_block.py +89 -0
- notionary/page/content/parser/parsers/image.py +8 -35
- notionary/page/content/parser/parsers/pdf.py +8 -35
- notionary/page/content/parser/parsers/video.py +8 -35
- notionary/page/content/renderer/renderers/audio.py +9 -21
- notionary/page/content/renderer/renderers/file.py +9 -21
- notionary/page/content/renderer/renderers/file_like_block.py +43 -0
- notionary/page/content/renderer/renderers/image.py +9 -21
- notionary/page/content/renderer/renderers/pdf.py +9 -21
- notionary/page/content/renderer/renderers/video.py +9 -21
- notionary/page/content/syntax/__init__.py +2 -1
- notionary/page/content/syntax/registry.py +38 -60
- notionary/page/properties/client.py +1 -1
- notionary/page/properties/{models.py → schemas.py} +93 -107
- notionary/page/properties/service.py +1 -1
- notionary/page/schemas.py +3 -3
- notionary/page/service.py +1 -1
- notionary/shared/entity/dto_parsers.py +1 -36
- notionary/shared/entity/entity_metadata_update_client.py +18 -4
- notionary/shared/entity/schemas.py +6 -6
- notionary/shared/entity/service.py +53 -30
- notionary/shared/models/file.py +34 -6
- notionary/shared/models/icon.py +5 -12
- notionary/user/bot.py +12 -12
- notionary/utils/decorators.py +8 -8
- notionary/workspace/__init__.py +2 -2
- notionary/workspace/query/__init__.py +2 -1
- notionary/workspace/query/service.py +3 -17
- notionary/workspace/service.py +45 -45
- {notionary-0.3.1.dist-info → notionary-0.4.0.dist-info}/METADATA +1 -1
- {notionary-0.3.1.dist-info → notionary-0.4.0.dist-info}/RECORD +77 -58
- notionary/file_upload/models.py +0 -69
- notionary/page/page_context.py +0 -50
- notionary/shared/models/cover.py +0 -20
- {notionary-0.3.1.dist-info → notionary-0.4.0.dist-info}/WHEEL +0 -0
- {notionary-0.3.1.dist-info → notionary-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,42 +1,15 @@
|
|
|
1
|
-
"""Parser for image blocks."""
|
|
2
|
-
|
|
3
1
|
from typing import override
|
|
4
2
|
|
|
5
|
-
from notionary.blocks.schemas import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
FileData,
|
|
9
|
-
FileType,
|
|
10
|
-
)
|
|
11
|
-
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
|
12
|
-
from notionary.page.content.syntax import SyntaxRegistry
|
|
13
|
-
|
|
3
|
+
from notionary.blocks.schemas import CreateImageBlock, ExternalFileWithCaption
|
|
4
|
+
from notionary.page.content.parser.parsers.file_like_block import FileLikeBlockParser
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition, SyntaxRegistry
|
|
14
6
|
|
|
15
|
-
class ImageParser(LineParser):
|
|
16
|
-
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
|
17
|
-
super().__init__(syntax_registry)
|
|
18
|
-
self._syntax = syntax_registry.get_image_syntax()
|
|
19
7
|
|
|
8
|
+
class ImageParser(FileLikeBlockParser[CreateImageBlock]):
|
|
20
9
|
@override
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
return False
|
|
24
|
-
return self._syntax.regex_pattern.search(context.line) is not None
|
|
10
|
+
def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
|
|
11
|
+
return syntax_registry.get_image_syntax()
|
|
25
12
|
|
|
26
13
|
@override
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if not url:
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
image_data = FileData(
|
|
33
|
-
type=FileType.EXTERNAL,
|
|
34
|
-
external=ExternalFile(url=url),
|
|
35
|
-
caption=[],
|
|
36
|
-
)
|
|
37
|
-
block = CreateImageBlock(image=image_data)
|
|
38
|
-
context.result_blocks.append(block)
|
|
39
|
-
|
|
40
|
-
def _extract_url(self, line: str) -> str | None:
|
|
41
|
-
match = self._syntax.regex_pattern.search(line)
|
|
42
|
-
return match.group(1).strip() if match else None
|
|
14
|
+
def _create_block(self, file_data: ExternalFileWithCaption) -> CreateImageBlock:
|
|
15
|
+
return CreateImageBlock(image=file_data)
|
|
@@ -1,42 +1,15 @@
|
|
|
1
|
-
"""Parser for PDF blocks."""
|
|
2
|
-
|
|
3
1
|
from typing import override
|
|
4
2
|
|
|
5
|
-
from notionary.blocks.schemas import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
FileData,
|
|
9
|
-
FileType,
|
|
10
|
-
)
|
|
11
|
-
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
|
12
|
-
from notionary.page.content.syntax import SyntaxRegistry
|
|
13
|
-
|
|
3
|
+
from notionary.blocks.schemas import CreatePdfBlock, ExternalFileWithCaption
|
|
4
|
+
from notionary.page.content.parser.parsers.file_like_block import FileLikeBlockParser
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition, SyntaxRegistry
|
|
14
6
|
|
|
15
|
-
class PdfParser(LineParser):
|
|
16
|
-
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
|
17
|
-
super().__init__(syntax_registry)
|
|
18
|
-
self._syntax = syntax_registry.get_pdf_syntax()
|
|
19
7
|
|
|
8
|
+
class PdfParser(FileLikeBlockParser[CreatePdfBlock]):
|
|
20
9
|
@override
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
return False
|
|
24
|
-
return self._syntax.regex_pattern.search(context.line) is not None
|
|
10
|
+
def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
|
|
11
|
+
return syntax_registry.get_pdf_syntax()
|
|
25
12
|
|
|
26
13
|
@override
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if not url:
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
pdf_data = FileData(
|
|
33
|
-
type=FileType.EXTERNAL,
|
|
34
|
-
external=ExternalFile(url=url),
|
|
35
|
-
caption=[],
|
|
36
|
-
)
|
|
37
|
-
block = CreatePdfBlock(pdf=pdf_data)
|
|
38
|
-
context.result_blocks.append(block)
|
|
39
|
-
|
|
40
|
-
def _extract_url(self, line: str) -> str | None:
|
|
41
|
-
match = self._syntax.regex_pattern.search(line)
|
|
42
|
-
return match.group(1).strip() if match else None
|
|
14
|
+
def _create_block(self, file_data: ExternalFileWithCaption) -> CreatePdfBlock:
|
|
15
|
+
return CreatePdfBlock(pdf=file_data)
|
|
@@ -1,42 +1,15 @@
|
|
|
1
|
-
"""Parser for video blocks."""
|
|
2
|
-
|
|
3
1
|
from typing import override
|
|
4
2
|
|
|
5
|
-
from notionary.blocks.schemas import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
FileData,
|
|
9
|
-
FileType,
|
|
10
|
-
)
|
|
11
|
-
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
|
12
|
-
from notionary.page.content.syntax import SyntaxRegistry
|
|
13
|
-
|
|
3
|
+
from notionary.blocks.schemas import CreateVideoBlock, ExternalFileWithCaption
|
|
4
|
+
from notionary.page.content.parser.parsers.file_like_block import FileLikeBlockParser
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition, SyntaxRegistry
|
|
14
6
|
|
|
15
|
-
class VideoParser(LineParser):
|
|
16
|
-
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
|
17
|
-
super().__init__(syntax_registry)
|
|
18
|
-
self._syntax = syntax_registry.get_video_syntax()
|
|
19
7
|
|
|
8
|
+
class VideoParser(FileLikeBlockParser[CreateVideoBlock]):
|
|
20
9
|
@override
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
return False
|
|
24
|
-
return self._syntax.regex_pattern.search(context.line) is not None
|
|
10
|
+
def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
|
|
11
|
+
return syntax_registry.get_video_syntax()
|
|
25
12
|
|
|
26
13
|
@override
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if not url:
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
video_data = FileData(
|
|
33
|
-
type=FileType.EXTERNAL,
|
|
34
|
-
external=ExternalFile(url=url),
|
|
35
|
-
caption=[],
|
|
36
|
-
)
|
|
37
|
-
block = CreateVideoBlock(video=video_data)
|
|
38
|
-
context.result_blocks.append(block)
|
|
39
|
-
|
|
40
|
-
def _extract_url(self, line: str) -> str | None:
|
|
41
|
-
match = self._syntax.regex_pattern.search(line)
|
|
42
|
-
return match.group(1).strip() if match else None
|
|
14
|
+
def _create_block(self, file_data: ExternalFileWithCaption) -> CreateVideoBlock:
|
|
15
|
+
return CreateVideoBlock(video=file_data)
|
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
from typing import override
|
|
2
2
|
|
|
3
|
-
from notionary.blocks.schemas import Block, BlockType
|
|
4
|
-
from notionary.page.content.renderer.renderers.
|
|
3
|
+
from notionary.blocks.schemas import Block, BlockType, ExternalFileWithCaption, NotionHostedFileWithCaption
|
|
4
|
+
from notionary.page.content.renderer.renderers.file_like_block import FileLikeBlockRenderer
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class AudioRenderer(
|
|
8
|
+
class AudioRenderer(FileLikeBlockRenderer):
|
|
8
9
|
@override
|
|
9
10
|
def _can_handle(self, block: Block) -> bool:
|
|
10
11
|
return block.type == BlockType.AUDIO
|
|
11
12
|
|
|
12
13
|
@override
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
def _get_syntax(self) -> SyntaxDefinition:
|
|
15
|
+
return self._syntax_registry.get_audio_syntax()
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
syntax = self._syntax_registry.get_audio_syntax()
|
|
20
|
-
return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
|
|
21
|
-
|
|
22
|
-
def _extract_audio_url(self, block: Block) -> str:
|
|
23
|
-
if not block.audio:
|
|
24
|
-
return ""
|
|
25
|
-
|
|
26
|
-
if block.audio.external:
|
|
27
|
-
return block.audio.external.url or ""
|
|
28
|
-
elif block.audio.file:
|
|
29
|
-
return block.audio.file.url or ""
|
|
30
|
-
|
|
31
|
-
return ""
|
|
17
|
+
@override
|
|
18
|
+
def _get_file_data(self, block: Block) -> ExternalFileWithCaption | NotionHostedFileWithCaption | None:
|
|
19
|
+
return block.audio
|
|
@@ -1,34 +1,22 @@
|
|
|
1
1
|
from typing import override
|
|
2
2
|
|
|
3
|
-
from notionary.blocks.schemas import Block, BlockType
|
|
4
|
-
from notionary.page.content.renderer.renderers.
|
|
3
|
+
from notionary.blocks.schemas import Block, BlockType, ExternalFileWithCaption, NotionHostedFileWithCaption
|
|
4
|
+
from notionary.page.content.renderer.renderers.file_like_block import FileLikeBlockRenderer
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class FileRenderer(
|
|
8
|
+
class FileRenderer(FileLikeBlockRenderer):
|
|
8
9
|
@override
|
|
9
10
|
def _can_handle(self, block: Block) -> bool:
|
|
10
11
|
return block.type == BlockType.FILE
|
|
11
12
|
|
|
12
13
|
@override
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
def _get_syntax(self) -> SyntaxDefinition:
|
|
15
|
+
return self._syntax_registry.get_file_syntax()
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
syntax = self._syntax_registry.get_file_syntax()
|
|
20
|
-
return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
|
|
21
|
-
|
|
22
|
-
def _extract_file_url(self, block: Block) -> str:
|
|
23
|
-
if not block.file:
|
|
24
|
-
return ""
|
|
25
|
-
|
|
26
|
-
if block.file.external:
|
|
27
|
-
return block.file.external.url or ""
|
|
28
|
-
elif block.file.file:
|
|
29
|
-
return block.file.file.url or ""
|
|
30
|
-
|
|
31
|
-
return ""
|
|
17
|
+
@override
|
|
18
|
+
def _get_file_data(self, block: Block) -> ExternalFileWithCaption | NotionHostedFileWithCaption | None:
|
|
19
|
+
return block.file
|
|
32
20
|
|
|
33
21
|
def _extract_file_name(self, block: Block) -> str:
|
|
34
22
|
if not block.file:
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import override
|
|
3
|
+
|
|
4
|
+
from notionary.blocks.schemas import (
|
|
5
|
+
Block,
|
|
6
|
+
ExternalFileWithCaption,
|
|
7
|
+
NotionHostedFileWithCaption,
|
|
8
|
+
)
|
|
9
|
+
from notionary.page.content.renderer.renderers.captioned_block import CaptionedBlockRenderer
|
|
10
|
+
from notionary.page.content.syntax import SyntaxDefinition
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FileLikeBlockRenderer(CaptionedBlockRenderer):
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def _get_syntax(self) -> SyntaxDefinition:
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def _get_file_data(self, block: Block) -> ExternalFileWithCaption | NotionHostedFileWithCaption | None:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
async def _render_main_content(self, block: Block) -> str:
|
|
24
|
+
url = self._extract_url(block)
|
|
25
|
+
|
|
26
|
+
if not url:
|
|
27
|
+
return ""
|
|
28
|
+
|
|
29
|
+
syntax = self._get_syntax()
|
|
30
|
+
return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
|
|
31
|
+
|
|
32
|
+
def _extract_url(self, block: Block) -> str:
|
|
33
|
+
file_data = self._get_file_data(block)
|
|
34
|
+
|
|
35
|
+
if not file_data:
|
|
36
|
+
return ""
|
|
37
|
+
|
|
38
|
+
if isinstance(file_data, ExternalFileWithCaption):
|
|
39
|
+
return file_data.external.url or ""
|
|
40
|
+
elif isinstance(file_data, NotionHostedFileWithCaption):
|
|
41
|
+
return file_data.file.url or ""
|
|
42
|
+
|
|
43
|
+
return ""
|
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
from typing import override
|
|
2
2
|
|
|
3
|
-
from notionary.blocks.schemas import Block, BlockType
|
|
4
|
-
from notionary.page.content.renderer.renderers.
|
|
3
|
+
from notionary.blocks.schemas import Block, BlockType, ExternalFileWithCaption, NotionHostedFileWithCaption
|
|
4
|
+
from notionary.page.content.renderer.renderers.file_like_block import FileLikeBlockRenderer
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class ImageRenderer(
|
|
8
|
+
class ImageRenderer(FileLikeBlockRenderer):
|
|
8
9
|
@override
|
|
9
10
|
def _can_handle(self, block: Block) -> bool:
|
|
10
11
|
return block.type == BlockType.IMAGE
|
|
11
12
|
|
|
12
13
|
@override
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
def _get_syntax(self) -> SyntaxDefinition:
|
|
15
|
+
return self._syntax_registry.get_image_syntax()
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
syntax = self._syntax_registry.get_image_syntax()
|
|
20
|
-
return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
|
|
21
|
-
|
|
22
|
-
def _extract_image_url(self, block: Block) -> str:
|
|
23
|
-
if not block.image:
|
|
24
|
-
return ""
|
|
25
|
-
|
|
26
|
-
if block.image.external:
|
|
27
|
-
return block.image.external.url or ""
|
|
28
|
-
elif block.image.file:
|
|
29
|
-
return block.image.file.url or ""
|
|
30
|
-
|
|
31
|
-
return ""
|
|
17
|
+
@override
|
|
18
|
+
def _get_file_data(self, block: Block) -> ExternalFileWithCaption | NotionHostedFileWithCaption | None:
|
|
19
|
+
return block.image
|
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
from typing import override
|
|
2
2
|
|
|
3
|
-
from notionary.blocks.schemas import Block, BlockType
|
|
4
|
-
from notionary.page.content.renderer.renderers.
|
|
3
|
+
from notionary.blocks.schemas import Block, BlockType, ExternalFileWithCaption, NotionHostedFileWithCaption
|
|
4
|
+
from notionary.page.content.renderer.renderers.file_like_block import FileLikeBlockRenderer
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class PdfRenderer(
|
|
8
|
+
class PdfRenderer(FileLikeBlockRenderer):
|
|
8
9
|
@override
|
|
9
10
|
def _can_handle(self, block: Block) -> bool:
|
|
10
11
|
return block.type == BlockType.PDF
|
|
11
12
|
|
|
12
13
|
@override
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
def _get_syntax(self) -> SyntaxDefinition:
|
|
15
|
+
return self._syntax_registry.get_pdf_syntax()
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
syntax = self._syntax_registry.get_pdf_syntax()
|
|
20
|
-
return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
|
|
21
|
-
|
|
22
|
-
def _extract_pdf_url(self, block: Block) -> str:
|
|
23
|
-
if not block.pdf:
|
|
24
|
-
return ""
|
|
25
|
-
|
|
26
|
-
if block.pdf.external:
|
|
27
|
-
return block.pdf.external.url or ""
|
|
28
|
-
elif block.pdf.file:
|
|
29
|
-
return block.pdf.file.url or ""
|
|
30
|
-
|
|
31
|
-
return ""
|
|
17
|
+
@override
|
|
18
|
+
def _get_file_data(self, block: Block) -> ExternalFileWithCaption | NotionHostedFileWithCaption | None:
|
|
19
|
+
return block.pdf
|
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
from typing import override
|
|
2
2
|
|
|
3
|
-
from notionary.blocks.schemas import Block, BlockType
|
|
4
|
-
from notionary.page.content.renderer.renderers.
|
|
3
|
+
from notionary.blocks.schemas import Block, BlockType, ExternalFileWithCaption, NotionHostedFileWithCaption
|
|
4
|
+
from notionary.page.content.renderer.renderers.file_like_block import FileLikeBlockRenderer
|
|
5
|
+
from notionary.page.content.syntax import SyntaxDefinition
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class VideoRenderer(
|
|
8
|
+
class VideoRenderer(FileLikeBlockRenderer):
|
|
8
9
|
@override
|
|
9
10
|
def _can_handle(self, block: Block) -> bool:
|
|
10
11
|
return block.type == BlockType.VIDEO
|
|
11
12
|
|
|
12
13
|
@override
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
def _get_syntax(self) -> SyntaxDefinition:
|
|
15
|
+
return self._syntax_registry.get_video_syntax()
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
syntax = self._syntax_registry.get_video_syntax()
|
|
20
|
-
return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
|
|
21
|
-
|
|
22
|
-
def _extract_video_url(self, block: Block) -> str:
|
|
23
|
-
if not block.video:
|
|
24
|
-
return ""
|
|
25
|
-
|
|
26
|
-
if block.video.external:
|
|
27
|
-
return block.video.external.url or ""
|
|
28
|
-
elif block.video.file:
|
|
29
|
-
return block.video.file.url or ""
|
|
30
|
-
|
|
31
|
-
return ""
|
|
17
|
+
@override
|
|
18
|
+
def _get_file_data(self, block: Block) -> ExternalFileWithCaption | NotionHostedFileWithCaption | None:
|
|
19
|
+
return block.video
|
|
@@ -4,6 +4,8 @@ from notionary.page.content.syntax.grammar import MarkdownGrammar
|
|
|
4
4
|
from notionary.page.content.syntax.models import SyntaxDefinition, SyntaxRegistryKey
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
# TODO: Add support for file upload in blocks for file types (refactor file types aswell)
|
|
8
|
+
# differentiate between external and uploaded files (file like blocks)
|
|
7
9
|
class SyntaxRegistry:
|
|
8
10
|
def __init__(self, markdown_markdown_grammar: MarkdownGrammar | None = None) -> None:
|
|
9
11
|
self._markdown_grammar = markdown_markdown_grammar or MarkdownGrammar()
|
|
@@ -92,63 +94,79 @@ class SyntaxRegistry:
|
|
|
92
94
|
def get_heading_syntax(self) -> SyntaxDefinition:
|
|
93
95
|
return self._definitions[SyntaxRegistryKey.HEADING]
|
|
94
96
|
|
|
97
|
+
def _create_media_syntax(self, media_type: str, url_pattern: str | None = None) -> SyntaxDefinition:
|
|
98
|
+
url_pattern = url_pattern or "[^)]+"
|
|
99
|
+
return SyntaxDefinition(
|
|
100
|
+
start_delimiter=f"[{media_type}](",
|
|
101
|
+
end_delimiter=")",
|
|
102
|
+
regex_pattern=re.compile(rf"(?<!\!)\[{re.escape(media_type)}\]\(({url_pattern})\)"),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _create_url_media_syntax(self, media_type: str) -> SyntaxDefinition:
|
|
106
|
+
return SyntaxDefinition(
|
|
107
|
+
start_delimiter=f"[{media_type}](",
|
|
108
|
+
end_delimiter=")",
|
|
109
|
+
regex_pattern=re.compile(rf"(?<!\!)\[{re.escape(media_type)}\]\((https?://[^\s)]+)\)"),
|
|
110
|
+
)
|
|
111
|
+
|
|
95
112
|
def _register_defaults(self) -> None:
|
|
96
113
|
self._register_audio_syntax()
|
|
97
|
-
self._register_bookmark_syntax()
|
|
98
|
-
self._register_image_syntax()
|
|
99
114
|
self._register_video_syntax()
|
|
115
|
+
self._register_image_syntax()
|
|
100
116
|
self._register_file_syntax()
|
|
101
117
|
self._register_pdf_syntax()
|
|
118
|
+
self._register_bookmark_syntax()
|
|
119
|
+
self._register_embed_syntax()
|
|
102
120
|
|
|
103
|
-
# List blocks
|
|
104
121
|
self._register_bulleted_list_syntax()
|
|
105
122
|
self._register_numbered_list_syntax()
|
|
106
123
|
self._register_todo_syntax()
|
|
107
124
|
self._register_todo_done_syntax()
|
|
108
125
|
|
|
109
|
-
# Container blocks
|
|
110
126
|
self._register_toggle_syntax()
|
|
111
127
|
self._register_toggleable_heading_syntax()
|
|
112
128
|
self._register_callout_syntax()
|
|
113
129
|
self._register_quote_syntax()
|
|
114
130
|
self._register_code_syntax()
|
|
115
131
|
|
|
116
|
-
# Column layout blocks
|
|
117
132
|
self._register_column_list_syntax()
|
|
118
133
|
self._register_column_syntax()
|
|
119
134
|
|
|
120
135
|
self._register_heading_1_syntax()
|
|
121
136
|
self._register_heading_2_syntax()
|
|
122
137
|
self._register_heading_3_syntax()
|
|
123
|
-
self._register_heading_syntax()
|
|
138
|
+
self._register_heading_syntax()
|
|
124
139
|
|
|
125
140
|
self._register_divider_syntax()
|
|
126
141
|
self._register_breadcrumb_syntax()
|
|
127
142
|
self._register_table_of_contents_syntax()
|
|
128
143
|
self._register_equation_syntax()
|
|
129
|
-
self._register_embed_syntax()
|
|
130
144
|
self._register_table_syntax()
|
|
131
145
|
self._register_table_row_syntax()
|
|
132
146
|
|
|
133
|
-
# Post-processing and utility blocks
|
|
134
147
|
self._register_caption_syntax()
|
|
135
148
|
self._register_space_syntax()
|
|
136
149
|
|
|
137
150
|
def _register_audio_syntax(self) -> None:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
151
|
+
self._definitions[SyntaxRegistryKey.AUDIO] = self._create_media_syntax("audio")
|
|
152
|
+
|
|
153
|
+
def _register_video_syntax(self) -> None:
|
|
154
|
+
self._definitions[SyntaxRegistryKey.VIDEO] = self._create_media_syntax("video")
|
|
155
|
+
|
|
156
|
+
def _register_image_syntax(self) -> None:
|
|
157
|
+
self._definitions[SyntaxRegistryKey.IMAGE] = self._create_media_syntax("image")
|
|
158
|
+
|
|
159
|
+
def _register_file_syntax(self) -> None:
|
|
160
|
+
self._definitions[SyntaxRegistryKey.FILE] = self._create_media_syntax("file")
|
|
161
|
+
|
|
162
|
+
def _register_pdf_syntax(self) -> None:
|
|
163
|
+
self._definitions[SyntaxRegistryKey.PDF] = self._create_media_syntax("pdf")
|
|
144
164
|
|
|
145
165
|
def _register_bookmark_syntax(self) -> None:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
)
|
|
151
|
-
self._definitions[SyntaxRegistryKey.BOOKMARK] = definition
|
|
166
|
+
self._definitions[SyntaxRegistryKey.BOOKMARK] = self._create_url_media_syntax("bookmark")
|
|
167
|
+
|
|
168
|
+
def _register_embed_syntax(self) -> None:
|
|
169
|
+
self._definitions[SyntaxRegistryKey.EMBED] = self._create_url_media_syntax("embed")
|
|
152
170
|
|
|
153
171
|
def _register_breadcrumb_syntax(self) -> None:
|
|
154
172
|
definition = SyntaxDefinition(
|
|
@@ -217,14 +235,6 @@ class SyntaxRegistry:
|
|
|
217
235
|
)
|
|
218
236
|
self._definitions[SyntaxRegistryKey.DIVIDER] = definition
|
|
219
237
|
|
|
220
|
-
def _register_embed_syntax(self) -> None:
|
|
221
|
-
definition = SyntaxDefinition(
|
|
222
|
-
start_delimiter="[embed](",
|
|
223
|
-
end_delimiter=")",
|
|
224
|
-
regex_pattern=re.compile(r"\[embed\]\((https?://[^\s)]+)\)"),
|
|
225
|
-
)
|
|
226
|
-
self._definitions[SyntaxRegistryKey.EMBED] = definition
|
|
227
|
-
|
|
228
238
|
def _register_equation_syntax(self) -> None:
|
|
229
239
|
definition = SyntaxDefinition(
|
|
230
240
|
start_delimiter="$$",
|
|
@@ -233,14 +243,6 @@ class SyntaxRegistry:
|
|
|
233
243
|
)
|
|
234
244
|
self._definitions[SyntaxRegistryKey.EQUATION] = definition
|
|
235
245
|
|
|
236
|
-
def _register_file_syntax(self) -> None:
|
|
237
|
-
definition = SyntaxDefinition(
|
|
238
|
-
start_delimiter="[file](",
|
|
239
|
-
end_delimiter=")",
|
|
240
|
-
regex_pattern=re.compile(r"\[file\]\(([^)]+)\)"),
|
|
241
|
-
)
|
|
242
|
-
self._definitions[SyntaxRegistryKey.FILE] = definition
|
|
243
|
-
|
|
244
246
|
def _register_heading_1_syntax(self) -> None:
|
|
245
247
|
definition = SyntaxDefinition(
|
|
246
248
|
start_delimiter="# ",
|
|
@@ -265,14 +267,6 @@ class SyntaxRegistry:
|
|
|
265
267
|
)
|
|
266
268
|
self._definitions[SyntaxRegistryKey.HEADING_3] = definition
|
|
267
269
|
|
|
268
|
-
def _register_image_syntax(self) -> None:
|
|
269
|
-
definition = SyntaxDefinition(
|
|
270
|
-
start_delimiter="[image](",
|
|
271
|
-
end_delimiter=")",
|
|
272
|
-
regex_pattern=re.compile(r"(?<!!)\[image\]\(([^)]+)\)"),
|
|
273
|
-
)
|
|
274
|
-
self._definitions[SyntaxRegistryKey.IMAGE] = definition
|
|
275
|
-
|
|
276
270
|
def _register_numbered_list_syntax(self) -> None:
|
|
277
271
|
definition = SyntaxDefinition(
|
|
278
272
|
start_delimiter="1. ",
|
|
@@ -281,14 +275,6 @@ class SyntaxRegistry:
|
|
|
281
275
|
)
|
|
282
276
|
self._definitions[SyntaxRegistryKey.NUMBERED_LIST] = definition
|
|
283
277
|
|
|
284
|
-
def _register_pdf_syntax(self) -> None:
|
|
285
|
-
definition = SyntaxDefinition(
|
|
286
|
-
start_delimiter="[pdf](",
|
|
287
|
-
end_delimiter=")",
|
|
288
|
-
regex_pattern=re.compile(r"\[pdf\]\(([^)]+)\)"),
|
|
289
|
-
)
|
|
290
|
-
self._definitions[SyntaxRegistryKey.PDF] = definition
|
|
291
|
-
|
|
292
278
|
def _register_quote_syntax(self) -> None:
|
|
293
279
|
definition = SyntaxDefinition(
|
|
294
280
|
start_delimiter="> ",
|
|
@@ -360,14 +346,6 @@ class SyntaxRegistry:
|
|
|
360
346
|
)
|
|
361
347
|
self._definitions[SyntaxRegistryKey.TOGGLEABLE_HEADING] = definition
|
|
362
348
|
|
|
363
|
-
def _register_video_syntax(self) -> None:
|
|
364
|
-
definition = SyntaxDefinition(
|
|
365
|
-
start_delimiter="[video](",
|
|
366
|
-
end_delimiter=")",
|
|
367
|
-
regex_pattern=re.compile(r"\[video\]\(([^)]+)\)"),
|
|
368
|
-
)
|
|
369
|
-
self._definitions[SyntaxRegistryKey.VIDEO] = definition
|
|
370
|
-
|
|
371
349
|
def _register_caption_syntax(self) -> None:
|
|
372
350
|
definition = SyntaxDefinition(
|
|
373
351
|
start_delimiter="[caption]",
|
|
@@ -4,7 +4,7 @@ from pydantic import BaseModel
|
|
|
4
4
|
|
|
5
5
|
from notionary.blocks.rich_text.models import RichText
|
|
6
6
|
from notionary.http.client import NotionHttpClient
|
|
7
|
-
from notionary.page.properties.
|
|
7
|
+
from notionary.page.properties.schemas import (
|
|
8
8
|
DateValue,
|
|
9
9
|
PageCheckboxProperty,
|
|
10
10
|
PageDateProperty,
|