wikinator 0.1.0__tar.gz
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.
- wikinator-0.1.0/.github/workflows/release.yml +28 -0
- wikinator-0.1.0/.gitignore +20 -0
- wikinator-0.1.0/LICENSE +21 -0
- wikinator-0.1.0/Makefile +36 -0
- wikinator-0.1.0/PKG-INFO +116 -0
- wikinator-0.1.0/README.md +98 -0
- wikinator-0.1.0/pyproject.toml +47 -0
- wikinator-0.1.0/src/wikinator/__about__.py +5 -0
- wikinator-0.1.0/src/wikinator/__init__.py +0 -0
- wikinator-0.1.0/src/wikinator/__main__.py +6 -0
- wikinator-0.1.0/src/wikinator/app.py +151 -0
- wikinator-0.1.0/src/wikinator/quickstart.py +66 -0
- wikinator-0.1.0/src/wikinator/wiki.py +281 -0
- wikinator-0.1.0/tests/smoke_test.py +4 -0
- wikinator-0.1.0/uv.lock +1464 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
# Publish on any tag starting with a `v`, e.g. v1.2.3
|
|
7
|
+
- v*
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
pypi:
|
|
11
|
+
name: Publish to PyPI
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
# Environment and permissions trusted publishing.
|
|
14
|
+
environment:
|
|
15
|
+
# Create this environment in the GitHub repository under Settings -> Environments
|
|
16
|
+
name: release
|
|
17
|
+
permissions:
|
|
18
|
+
id-token: write
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: astral-sh/setup-uv@v3
|
|
22
|
+
- run: uv build
|
|
23
|
+
# Check that basic features work and we didn't miss to include crucial files
|
|
24
|
+
- name: Smoke test (wheel)
|
|
25
|
+
run: uv run --isolated --no-project -p 3.13 --with dist/*.whl tests/smoke_test.py
|
|
26
|
+
- name: Smoke test (source distribution)
|
|
27
|
+
run: uv run --isolated --no-project -p 3.13 --with dist/*.tar.gz tests/smoke_test.py
|
|
28
|
+
- run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
.python-version
|
|
9
|
+
|
|
10
|
+
# Virtual environments
|
|
11
|
+
.venv
|
|
12
|
+
|
|
13
|
+
# env and secure files
|
|
14
|
+
.env
|
|
15
|
+
.envrc
|
|
16
|
+
token.json
|
|
17
|
+
credentials.json
|
|
18
|
+
|
|
19
|
+
# Apple dingles
|
|
20
|
+
.DS_Store
|
wikinator-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Paul Philion
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wikinator-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.PHONY: all run clean
|
|
2
|
+
|
|
3
|
+
# Simple makefile to help me remember uv tasks
|
|
4
|
+
# Targets are:
|
|
5
|
+
# - lint : run ruff linter
|
|
6
|
+
# - fix : ... with fixes
|
|
7
|
+
# - test : run test suite
|
|
8
|
+
# - build : build
|
|
9
|
+
# - publish : publish
|
|
10
|
+
# - dist : clean, build, publish
|
|
11
|
+
# - clean : remove anything built
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
lint:
|
|
15
|
+
uvx ruff check
|
|
16
|
+
|
|
17
|
+
fix:
|
|
18
|
+
uvx ruff check --fix
|
|
19
|
+
|
|
20
|
+
test:
|
|
21
|
+
uv run pytest
|
|
22
|
+
|
|
23
|
+
build:
|
|
24
|
+
uv build
|
|
25
|
+
|
|
26
|
+
dist:
|
|
27
|
+
rm -fr dist/
|
|
28
|
+
uv build
|
|
29
|
+
uv publish
|
|
30
|
+
|
|
31
|
+
clean:
|
|
32
|
+
rm -rf __pycache__
|
|
33
|
+
rm -fr .ruff_cache/
|
|
34
|
+
rm -fr dist/
|
|
35
|
+
rm -f dpytest_*.dat
|
|
36
|
+
find . -type f -name ‘*.pyc’ -delete
|
wikinator-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wikinator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert Google docs to markdown
|
|
5
|
+
Project-URL: Documentation, https://github.com/philion/wikinator#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/philion/wikinator/issues
|
|
7
|
+
Project-URL: Source, https://github.com/philion/wikinator
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: >=3.13
|
|
10
|
+
Requires-Dist: dotenv>=0.9.9
|
|
11
|
+
Requires-Dist: google-api-python-client>=2.175.0
|
|
12
|
+
Requires-Dist: google-auth-httplib2>=0.2.0
|
|
13
|
+
Requires-Dist: google-auth-oauthlib>=1.2.2
|
|
14
|
+
Requires-Dist: gql[all]>=3.5.3
|
|
15
|
+
Requires-Dist: markitdown[all]>=0.1.2
|
|
16
|
+
Requires-Dist: typer-slim>=0.16.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# wikinator
|
|
20
|
+
|
|
21
|
+
Convert a Google drive download into a markdown-based wiki.
|
|
22
|
+
|
|
23
|
+
**Note**: This is a work in progress, and not all features will be supported or working properly.
|
|
24
|
+
|
|
25
|
+
## tl;dr
|
|
26
|
+
```
|
|
27
|
+
uvx wikinator some/dir another_dir
|
|
28
|
+
uvx wikinator some/dir -graphql https://wiki.example.com/graphql -token 'graphql-auth-token'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Given a directory, convert supported file types into markdown-based files while maintaining names and directory structure. This can then be uploaded into various wiki systems.
|
|
32
|
+
|
|
33
|
+
### Supported File Types
|
|
34
|
+
- DOCX files (default for GDocs) are converted to markdown
|
|
35
|
+
- images are extracted, uploaded and embedded in the markdown
|
|
36
|
+
- `text` and code file types are wrapped in markdown code blocks
|
|
37
|
+
- CSV and XSLT are converted to markdown tables
|
|
38
|
+
- for any document that is converted to markdown, a copy of the original is uploaded and attached
|
|
39
|
+
|
|
40
|
+
### Supported Wiki Import
|
|
41
|
+
- wiki.js (and other GraphQL-based wikis)
|
|
42
|
+
- Obsidian
|
|
43
|
+
|
|
44
|
+
The development log will be kept here until the 1.0 release.
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
```
|
|
48
|
+
uvx wikinator some/dir another_dir
|
|
49
|
+
uvx wikinator some/dir -graphql https://wiki.example.com/graphql -token 'graphql-auth-token'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Build & Test
|
|
53
|
+
1. Clone
|
|
54
|
+
```
|
|
55
|
+
git clone ...
|
|
56
|
+
cd wikinator
|
|
57
|
+
```
|
|
58
|
+
2. Run, with uv
|
|
59
|
+
```
|
|
60
|
+
uv run -m wikinator [options]
|
|
61
|
+
```
|
|
62
|
+
3. Test, with pytest
|
|
63
|
+
```
|
|
64
|
+
uv run pytest
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Development Log
|
|
68
|
+
|
|
69
|
+
### 2025-07-04
|
|
70
|
+
Let's make a project! Today's goals:
|
|
71
|
+
- [x] clean up code and README
|
|
72
|
+
- [x] add CLI options, using type (not all implemented)
|
|
73
|
+
- [x] initial commit to github
|
|
74
|
+
- [ ] add image handling
|
|
75
|
+
- [ ] upload to pypi and confirm uvx commands
|
|
76
|
+
|
|
77
|
+
Cruft removed. README updated. (author waves, breaking 4th wall)
|
|
78
|
+
|
|
79
|
+
Moving on the main() cleanup and adding support for https://github.com/fastapi/typer
|
|
80
|
+
|
|
81
|
+
Added simple CLI options for src and dest. Got end-to-end tree processing.
|
|
82
|
+
|
|
83
|
+
Let's go for git and call it a day!
|
|
84
|
+
|
|
85
|
+
### 2025-07-03
|
|
86
|
+
Next steps are testing different document converters and accessing google drive via API.
|
|
87
|
+
|
|
88
|
+
#### Markdown conversion libraries
|
|
89
|
+
- pandoc, see https://docs.asciidoctor.org/asciidoctor/latest/migrate/ms-word/
|
|
90
|
+
- markitdown, https://github.com/microsoft/markitdown
|
|
91
|
+
- docx2markdown, https://github.com/haesleinhuepf/docx2markdown
|
|
92
|
+
- docx2md, https://github.com/mattn/docx2md
|
|
93
|
+
|
|
94
|
+
Reference:
|
|
95
|
+
- https://www.docstomarkdown.pro/convert-word-or-docs-to-markdown-using-pandoc/
|
|
96
|
+
|
|
97
|
+
#### Google Drive API
|
|
98
|
+
Starting with https://developers.google.com/workspace/drive/api/quickstart/python
|
|
99
|
+
|
|
100
|
+
> Note: Follow those Google directions for setting up everything. It's complicated compared to simply generating a service token. Your intrepid author made different tokens in different accounts and couldn't access anything! And get permissions right! Document specific needs in intstall docs.
|
|
101
|
+
|
|
102
|
+
Further aside: There are two versions of the tool: file-based and google-takeout. The google related stuff will always be a bear to setup.
|
|
103
|
+
|
|
104
|
+
Made suffienct progress to feel like there a seperate CLI tool here. Set aside for now, and focus on:
|
|
105
|
+
1. Build file-based output
|
|
106
|
+
2. Generate and link images
|
|
107
|
+
3. Clean up for initial 0.1 version
|
|
108
|
+
|
|
109
|
+
### 2025-07-02
|
|
110
|
+
Initial time-boxed work started to examine what would be required to migrate our existing GoogleDocs-based info repo into a wiki, with wiki.js being targeted.
|
|
111
|
+
|
|
112
|
+
Initial proof-of-concept goals:
|
|
113
|
+
- Convert a docx page to md or asciidoc
|
|
114
|
+
- Upload test pages to wiki.js
|
|
115
|
+
|
|
116
|
+
I was able to get this working in sample code in a few hours.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# wikinator
|
|
2
|
+
|
|
3
|
+
Convert a Google drive download into a markdown-based wiki.
|
|
4
|
+
|
|
5
|
+
**Note**: This is a work in progress, and not all features will be supported or working properly.
|
|
6
|
+
|
|
7
|
+
## tl;dr
|
|
8
|
+
```
|
|
9
|
+
uvx wikinator some/dir another_dir
|
|
10
|
+
uvx wikinator some/dir -graphql https://wiki.example.com/graphql -token 'graphql-auth-token'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Given a directory, convert supported file types into markdown-based files while maintaining names and directory structure. This can then be uploaded into various wiki systems.
|
|
14
|
+
|
|
15
|
+
### Supported File Types
|
|
16
|
+
- DOCX files (default for GDocs) are converted to markdown
|
|
17
|
+
- images are extracted, uploaded and embedded in the markdown
|
|
18
|
+
- `text` and code file types are wrapped in markdown code blocks
|
|
19
|
+
- CSV and XSLT are converted to markdown tables
|
|
20
|
+
- for any document that is converted to markdown, a copy of the original is uploaded and attached
|
|
21
|
+
|
|
22
|
+
### Supported Wiki Import
|
|
23
|
+
- wiki.js (and other GraphQL-based wikis)
|
|
24
|
+
- Obsidian
|
|
25
|
+
|
|
26
|
+
The development log will be kept here until the 1.0 release.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
```
|
|
30
|
+
uvx wikinator some/dir another_dir
|
|
31
|
+
uvx wikinator some/dir -graphql https://wiki.example.com/graphql -token 'graphql-auth-token'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Build & Test
|
|
35
|
+
1. Clone
|
|
36
|
+
```
|
|
37
|
+
git clone ...
|
|
38
|
+
cd wikinator
|
|
39
|
+
```
|
|
40
|
+
2. Run, with uv
|
|
41
|
+
```
|
|
42
|
+
uv run -m wikinator [options]
|
|
43
|
+
```
|
|
44
|
+
3. Test, with pytest
|
|
45
|
+
```
|
|
46
|
+
uv run pytest
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Development Log
|
|
50
|
+
|
|
51
|
+
### 2025-07-04
|
|
52
|
+
Let's make a project! Today's goals:
|
|
53
|
+
- [x] clean up code and README
|
|
54
|
+
- [x] add CLI options, using type (not all implemented)
|
|
55
|
+
- [x] initial commit to github
|
|
56
|
+
- [ ] add image handling
|
|
57
|
+
- [ ] upload to pypi and confirm uvx commands
|
|
58
|
+
|
|
59
|
+
Cruft removed. README updated. (author waves, breaking 4th wall)
|
|
60
|
+
|
|
61
|
+
Moving on the main() cleanup and adding support for https://github.com/fastapi/typer
|
|
62
|
+
|
|
63
|
+
Added simple CLI options for src and dest. Got end-to-end tree processing.
|
|
64
|
+
|
|
65
|
+
Let's go for git and call it a day!
|
|
66
|
+
|
|
67
|
+
### 2025-07-03
|
|
68
|
+
Next steps are testing different document converters and accessing google drive via API.
|
|
69
|
+
|
|
70
|
+
#### Markdown conversion libraries
|
|
71
|
+
- pandoc, see https://docs.asciidoctor.org/asciidoctor/latest/migrate/ms-word/
|
|
72
|
+
- markitdown, https://github.com/microsoft/markitdown
|
|
73
|
+
- docx2markdown, https://github.com/haesleinhuepf/docx2markdown
|
|
74
|
+
- docx2md, https://github.com/mattn/docx2md
|
|
75
|
+
|
|
76
|
+
Reference:
|
|
77
|
+
- https://www.docstomarkdown.pro/convert-word-or-docs-to-markdown-using-pandoc/
|
|
78
|
+
|
|
79
|
+
#### Google Drive API
|
|
80
|
+
Starting with https://developers.google.com/workspace/drive/api/quickstart/python
|
|
81
|
+
|
|
82
|
+
> Note: Follow those Google directions for setting up everything. It's complicated compared to simply generating a service token. Your intrepid author made different tokens in different accounts and couldn't access anything! And get permissions right! Document specific needs in intstall docs.
|
|
83
|
+
|
|
84
|
+
Further aside: There are two versions of the tool: file-based and google-takeout. The google related stuff will always be a bear to setup.
|
|
85
|
+
|
|
86
|
+
Made suffienct progress to feel like there a seperate CLI tool here. Set aside for now, and focus on:
|
|
87
|
+
1. Build file-based output
|
|
88
|
+
2. Generate and link images
|
|
89
|
+
3. Clean up for initial 0.1 version
|
|
90
|
+
|
|
91
|
+
### 2025-07-02
|
|
92
|
+
Initial time-boxed work started to examine what would be required to migrate our existing GoogleDocs-based info repo into a wiki, with wiki.js being targeted.
|
|
93
|
+
|
|
94
|
+
Initial proof-of-concept goals:
|
|
95
|
+
- Convert a docx page to md or asciidoc
|
|
96
|
+
- Upload test pages to wiki.js
|
|
97
|
+
|
|
98
|
+
I was able to get this working in sample code in a few hours.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "wikinator"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Convert Google docs to markdown"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"dotenv>=0.9.9",
|
|
9
|
+
"google-api-python-client>=2.175.0",
|
|
10
|
+
"google-auth-httplib2>=0.2.0",
|
|
11
|
+
"google-auth-oauthlib>=1.2.2",
|
|
12
|
+
"gql[all]>=3.5.3",
|
|
13
|
+
"markitdown[all]>=0.1.2",
|
|
14
|
+
"typer-slim>=0.16.0",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Documentation = "https://github.com/philion/wikinator#readme"
|
|
19
|
+
Issues = "https://github.com/philion/wikinator/issues"
|
|
20
|
+
Source = "https://github.com/philion/wikinator"
|
|
21
|
+
|
|
22
|
+
[tool.coverage.run]
|
|
23
|
+
source_pkgs = ["wikinator", "tests"]
|
|
24
|
+
branch = true
|
|
25
|
+
parallel = true
|
|
26
|
+
|
|
27
|
+
[tool.coverage.paths]
|
|
28
|
+
clw = ["src/wikinator", "*/wikinator/src/wikinator"]
|
|
29
|
+
tests = ["tests", "*/wikinator/tests"]
|
|
30
|
+
|
|
31
|
+
[tool.coverage.report]
|
|
32
|
+
exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"]
|
|
33
|
+
|
|
34
|
+
[tool.hatch]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.version]
|
|
37
|
+
path = "src/wikinator/__about__.py"
|
|
38
|
+
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["hatchling"]
|
|
41
|
+
build-backend = "hatchling.build"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/wikinator"]
|
|
45
|
+
|
|
46
|
+
[project.scripts]
|
|
47
|
+
wikinator = "wikinator.app:main"
|
|
File without changes
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path, PurePath
|
|
3
|
+
import logging
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from markitdown import MarkItDown
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
class Page:
|
|
11
|
+
"""
|
|
12
|
+
Specific class for page, to help with validation, as graphql is strict about params
|
|
13
|
+
"""
|
|
14
|
+
content: str
|
|
15
|
+
editor: str
|
|
16
|
+
isPublished: bool
|
|
17
|
+
isPrivate: bool
|
|
18
|
+
locale: str
|
|
19
|
+
path: str
|
|
20
|
+
tags: list[str]
|
|
21
|
+
title: str
|
|
22
|
+
description: str
|
|
23
|
+
|
|
24
|
+
def __init__(self, content: str, editor: str, isPublished: bool, isPrivate: bool,
|
|
25
|
+
locale: str, path: str, tags: list[str], title: str, description: str):
|
|
26
|
+
self.content = content
|
|
27
|
+
self.editor = editor
|
|
28
|
+
self.isPublished = isPublished
|
|
29
|
+
self.isPrivate = isPrivate
|
|
30
|
+
self.locale = locale
|
|
31
|
+
self.path = path
|
|
32
|
+
self.tags = tags
|
|
33
|
+
self.title = title
|
|
34
|
+
self.description = description
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def load(cls, params: dict[str,any]):
|
|
38
|
+
return cls(
|
|
39
|
+
content = params["content"],
|
|
40
|
+
editor = params["editor"],
|
|
41
|
+
isPublished = params["isPublished"],
|
|
42
|
+
isPrivate = params["isPrivate"],
|
|
43
|
+
locale = params["locale"],
|
|
44
|
+
path = params["path"],
|
|
45
|
+
tags = params["tags"],
|
|
46
|
+
title = params["title"],
|
|
47
|
+
description = params["description"],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def load_json(cls, json_str:str):
|
|
52
|
+
return cls.load(cls, json.loads(json_str))
|
|
53
|
+
|
|
54
|
+
def write(self, root:str) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Output the converted document to the specified directory `root`.
|
|
57
|
+
Use the stored path to output relative to the provided root.
|
|
58
|
+
"""
|
|
59
|
+
filename = self.path + '.md'
|
|
60
|
+
target = Path(root, filename)
|
|
61
|
+
# assure required dirs exist
|
|
62
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
# write the content
|
|
64
|
+
with open(target, 'w') as output_file:
|
|
65
|
+
# TODO write yaml-based meta data?
|
|
66
|
+
output_file.write(self.content)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Converter:
|
|
70
|
+
root: Path # Root for file walk, and to resolve rol paths
|
|
71
|
+
|
|
72
|
+
def _convert(self, infile:Path) -> Page:
|
|
73
|
+
raise NotImplementedError
|
|
74
|
+
|
|
75
|
+
def convert(self, infile:Path, outroot:Path) -> Page:
|
|
76
|
+
# translate with subclass
|
|
77
|
+
new_doc = self._convert(infile)
|
|
78
|
+
|
|
79
|
+
#print("converted", infile, new_doc.path)
|
|
80
|
+
|
|
81
|
+
# write!
|
|
82
|
+
new_doc.write(outroot)
|
|
83
|
+
|
|
84
|
+
return new_doc
|
|
85
|
+
|
|
86
|
+
def convert_directory(self, inpath:str, outroot:str):
|
|
87
|
+
# load queues
|
|
88
|
+
#docx_queue: list[Path] = []
|
|
89
|
+
self.root = Path(inpath)
|
|
90
|
+
|
|
91
|
+
for root, dirs, files in os.walk(self.root):
|
|
92
|
+
for file in files:
|
|
93
|
+
full_path = Path(root, file)
|
|
94
|
+
ext = full_path.suffix.lower() # TODO strip first char, '.'
|
|
95
|
+
|
|
96
|
+
# TODO: generic mapping to queue based on ext.
|
|
97
|
+
if ext == ".docx":
|
|
98
|
+
#docx_queue.append(full_path) # TODO async!
|
|
99
|
+
self.convert(full_path, outroot)
|
|
100
|
+
else:
|
|
101
|
+
logging.debug(f"No processor for {ext}, skipping {full_path}")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class MarkitdownConverter(Converter):
|
|
105
|
+
def _convert(self, filepath:Path) -> Page:
|
|
106
|
+
"""
|
|
107
|
+
Converts a markdown file into a struct to add to the wiki
|
|
108
|
+
"""
|
|
109
|
+
md = MarkItDown(enable_plugins=False)
|
|
110
|
+
result = md.convert(filepath)
|
|
111
|
+
|
|
112
|
+
# determine the relative file path
|
|
113
|
+
# this *includes* the top-level directly name
|
|
114
|
+
rel_path = PurePath(os.path.relpath(filepath, self.root.parent)) # remove .parent to remove top dirname
|
|
115
|
+
rel_file = PurePath(rel_path.parent, filepath.stem)
|
|
116
|
+
|
|
117
|
+
return Page(
|
|
118
|
+
title = result.title if result.title else filepath.stem,
|
|
119
|
+
path = str(rel_file),
|
|
120
|
+
content = result.text_content,
|
|
121
|
+
editor = "markdown",
|
|
122
|
+
locale = "en",
|
|
123
|
+
tags = None,
|
|
124
|
+
description = f"generated from: {filepath}",
|
|
125
|
+
isPublished = False,
|
|
126
|
+
isPrivate = True,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# trying to make everything async
|
|
130
|
+
# skipping for now
|
|
131
|
+
# start workers
|
|
132
|
+
# with multiprocessing.Pool(3) as worker_pool:
|
|
133
|
+
# # create a list the same size for starmap
|
|
134
|
+
# args = [(doc, outroot) for doc in docx_queue]
|
|
135
|
+
# # run the workers
|
|
136
|
+
# results = worker_pool.starmap(convert_docx, args)
|
|
137
|
+
# # check result success
|
|
138
|
+
# for result in results:
|
|
139
|
+
# print(result)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def do_convert(src: str, dest: str) -> None:
|
|
143
|
+
MarkitdownConverter().convert_directory(src, dest)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def main() -> None:
|
|
147
|
+
typer.run(do_convert)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
if __name__ == "__main__":
|
|
151
|
+
main()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
|
|
3
|
+
from google.auth.transport.requests import Request
|
|
4
|
+
from google.oauth2.credentials import Credentials
|
|
5
|
+
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
6
|
+
from googleapiclient.discovery import build
|
|
7
|
+
from googleapiclient.errors import HttpError
|
|
8
|
+
|
|
9
|
+
# If modifying these scopes, delete the file token.json.
|
|
10
|
+
SCOPES = ["https://www.googleapis.com/auth/drive.metadata.readonly"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main():
|
|
14
|
+
"""Shows basic usage of the Drive v3 API.
|
|
15
|
+
Prints the names and ids of the first 10 files the user has access to.
|
|
16
|
+
"""
|
|
17
|
+
creds = None
|
|
18
|
+
# The file token.json stores the user's access and refresh tokens, and is
|
|
19
|
+
# created automatically when the authorization flow completes for the first
|
|
20
|
+
# time.
|
|
21
|
+
if os.path.exists("token.json"):
|
|
22
|
+
creds = Credentials.from_authorized_user_file("token.json", SCOPES)
|
|
23
|
+
# If there are no (valid) credentials available, let the user log in.
|
|
24
|
+
if not creds or not creds.valid:
|
|
25
|
+
if creds and creds.expired and creds.refresh_token:
|
|
26
|
+
creds.refresh(Request())
|
|
27
|
+
else:
|
|
28
|
+
flow = InstalledAppFlow.from_client_secrets_file(
|
|
29
|
+
"credentials.json", SCOPES
|
|
30
|
+
)
|
|
31
|
+
creds = flow.run_local_server(port=0)
|
|
32
|
+
# Save the credentials for the next run
|
|
33
|
+
with open("token.json", "w") as token:
|
|
34
|
+
token.write(creds.to_json())
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
service = build("drive", "v3", credentials=creds)
|
|
38
|
+
|
|
39
|
+
# Call the Drive v3 API
|
|
40
|
+
files = service.files()
|
|
41
|
+
request = files.list(pageSize=1, fields="nextPageToken, files(*)")
|
|
42
|
+
|
|
43
|
+
#while request is not None:
|
|
44
|
+
results = request.execute()
|
|
45
|
+
|
|
46
|
+
items = results.get("files", [])
|
|
47
|
+
if not items:
|
|
48
|
+
print("No files found.")
|
|
49
|
+
return
|
|
50
|
+
for item in items:
|
|
51
|
+
#print(json.dumps(item, indent=4))
|
|
52
|
+
print(item['name'], item['mimeType'])
|
|
53
|
+
|
|
54
|
+
# download
|
|
55
|
+
md_doc = files.export(fileId=item['id'], mimeType="text/markdown").execute()
|
|
56
|
+
print(md_doc)
|
|
57
|
+
|
|
58
|
+
# request = files.list_next(request, results)
|
|
59
|
+
|
|
60
|
+
except HttpError as error:
|
|
61
|
+
# TODO(developer) - Handle errors from drive API.
|
|
62
|
+
print(f"An error occurred: {error}")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
if __name__ == "__main__":
|
|
66
|
+
main()
|