From 0e7862ee4a0fb6653ecf0cf4a4cd2f65b0f79641 Mon Sep 17 00:00:00 2001 From: randogoth Date: Fri, 9 Jun 2023 01:23:14 +0300 Subject: [PATCH] office meta plugin --- .index.yaml | 150 +++++++++++++++++++++++++++++++++++++++ metareaders.py | 26 ------- orvani/cmd.py | 3 +- orvani/plugins/office.py | 82 +++++++++++++++++++++ requirements.txt | 2 + test/office.odt | Bin 0 -> 9201 bytes test/oldword.doc | Bin 0 -> 9728 bytes test/sheet.xlsx | Bin 0 -> 4379 bytes test/table.ods | Bin 0 -> 7314 bytes test/tableold.xls | Bin 0 -> 5632 bytes test/word.docx | Bin 0 -> 4715 bytes 11 files changed, 236 insertions(+), 27 deletions(-) create mode 100644 .index.yaml delete mode 100644 metareaders.py create mode 100644 orvani/plugins/office.py create mode 100644 test/office.odt create mode 100644 test/oldword.doc create mode 100644 test/sheet.xlsx create mode 100644 test/table.ods create mode 100644 test/tableold.xls create mode 100644 test/word.docx diff --git a/.index.yaml b/.index.yaml new file mode 100644 index 0000000..d011ded --- /dev/null +++ b/.index.yaml @@ -0,0 +1,150 @@ +contexts: + Chripo McFlu: + - ./test/chirpy.wav + 'calc #tessssting': + - ./test/sheet.xlsx + - ./test/table.ods + 'concon #tagz': + - ./test/word.docx + erfwegf: + - ./COMMANDS.md + frrreee: + - ./README.md + python: + - ./orvani/plugins/hashdoubleslash.py + - ./TODO.md + test: + - ./test/test.txt + this: + - ./test/office.odt + watch: + - ./test/chirpy.wav +files: + ./COMMANDS.md: + contexts: + - erfwegf + note: This is awesome + projects: + - coding + tags: + - super + - great + ./README.md: + contexts: + - frrreee + projects: + - test2 + - test + ./TODO.md: + contexts: + - python + note: Chawera + projects: + - bokertov + tags: + - frrr + - rusty + ./orvani/plugins/hashdoubleslash.py: + contexts: + - python + note: It even works in Python code + projects: + - orvani + tags: + - example + ./test/chirpy.wav: + contexts: + - watch + - Chripo McFlu + note: + - This is a title + projects: + - parakeetio + - sensorwatch + tags: + - funk + ./test/office.odt: + contexts: + - this + note: and a note + projects: + - oopsie + tags: + - whoa + - that + ./test/sheet.xlsx: + contexts: + - 'calc #tessssting' + projects: [] + tags: [] + ./test/table.ods: + contexts: + - 'calc #tessssting' + projects: [] + tags: [] + ./test/test.txt: + contexts: + - test + note: frrr + projects: + - test + tags: + - faa + - test + ./test/word.docx: + contexts: + - 'concon #tagz' + projects: [] + tags: [] +note: + Chawera: + - ./TODO.md + It even works in Python code: + - ./orvani/plugins/hashdoubleslash.py + This is a title: + - ./test/chirpy.wav + This is awesome: + - ./COMMANDS.md + and a note: + - ./test/office.odt + frrr: + - ./test/test.txt +projects: + bokertov: + - ./TODO.md + coding: + - ./COMMANDS.md + oopsie: + - ./test/office.odt + orvani: + - ./orvani/plugins/hashdoubleslash.py + parakeetio: + - ./test/chirpy.wav + sensorwatch: + - ./test/chirpy.wav + test: + - ./test/test.txt + - ./README.md + test2: + - ./README.md +tags: + example: + - ./orvani/plugins/hashdoubleslash.py + faa: + - ./test/test.txt + frrr: + - ./TODO.md + funk: + - ./test/chirpy.wav + great: + - ./COMMANDS.md + rusty: + - ./TODO.md + super: + - ./COMMANDS.md + test: + - ./test/test.txt + that: + - ./test/office.odt + whoa: + - ./test/office.odt diff --git a/metareaders.py b/metareaders.py deleted file mode 100644 index c41f4d6..0000000 --- a/metareaders.py +++ /dev/null @@ -1,26 +0,0 @@ -import taglib - -with taglib.File("/home/flux/Documents/230605-191750.wav", save_on_exit=True) as song: - -import frontmatter - -with open('README.md', 'r') as data: - y = frontmatter.load(data) - -print(y.metadata) - -@orvani.metareader - def yaml_read(conf, db): - for (root,dirs,files) in os.walk(path): - if files: - for file in files: - rpath = os.path.join(root, dir) - f, ext = os.path.splitext(file) - if ext[1:] in conf['index'] and ext[1:] in ['md', 'txt']: - with open(file, 'r') as data: - y = frontmatter.load(data) - print(y) - if y.metadata: - for meta in y.metadata: - db[file][meta] = y.metadata[meta] - return db \ No newline at end of file diff --git a/orvani/cmd.py b/orvani/cmd.py index 0586449..fd77b7d 100644 --- a/orvani/cmd.py +++ b/orvani/cmd.py @@ -5,7 +5,7 @@ from pathlib import Path from rich.console import Console from rich.table import Table from orvani import OrvaniTag, CONTEXT_FILE, CACHE_FILE, CONTEXTS -from plugins import frontmatter, hashdoubleslash, id3 +from plugins import frontmatter, hashdoubleslash, id3, office def mktable(query: str, index: dict): console = Console() @@ -89,6 +89,7 @@ def main(): frontmatter.reader(o) hashdoubleslash.reader(o) id3.reader(o) + office.reader(o) # orvani.metadata() diff --git a/orvani/plugins/office.py b/orvani/plugins/office.py new file mode 100644 index 0000000..302b20e --- /dev/null +++ b/orvani/plugins/office.py @@ -0,0 +1,82 @@ +import re +import mimetypes +import shutil +from pathlib import Path +from olefile import OleFileIO + +NAME = 'office' +TYPES = ['.doc', '.xls', '.ppt', '.docx', '.xlsx', '.pptx', '.odt', '.ods', '.odp'] +RE_ODT_CTX = r"((.*))<\/meta:keyword>" +RE_ODT_NOTE = r"((.*))<\/dc:description>" + +# Office Document processing inspired by +# https://github.com/kappapiana/anonymize/blob/master/anonymize.py + +def unzip_file(orig_file, tmp_dir): + type = mimetypes.guess_type(orig_file) + filetype = { + "application/vnd.oasis.opendocument.text" : "odt", + "application/vnd.oasis.opendocument.spreadsheet" : "ods", + "application/vnd.oasis.opendocument.presentation" : "odp", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "docx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "xlsx", + "application/vnd.openxmlformats-officedocument.presentationml.presentation" : "pptx", + } + if type[0] in filetype: + shutil.unpack_archive(orig_file, tmp_dir, 'zip') + return filetype[type[0]] + else: + return type[0] + +def reader(o): + file = Path(o.path) + suffixes = TYPES + if NAME in o.config: + if 'types' in o.config[NAME]: + suffixes = o.config[NAME]['types'] + if file.suffix in suffixes: + tmp_folder = Path('unzip__' + file.stem) + file_type = unzip_file(o.path, tmp_folder) + tags = note = [] + # OpenOffice / LibreOffice / Open Document Format + if file_type in ['odt', 'ods', 'odp']: + meta_file = tmp_folder / 'meta.xml' + meta_content = meta_file.read_text() + tagsearch = re.findall(RE_ODT_CTX, meta_content) + if tagsearch: + tags = list(set(tagsearch[0])) + notesearch = re.findall(RE_ODT_NOTE, meta_content) + if notesearch: + note = list(set(notesearch[0])) + argv = [x for x in ' '.join(tags).split(' ') + note if x != ''] + context = o.context(argv) + for context_key in context.keys(): + o.update(o.path, context, context_key) + shutil.rmtree(tmp_folder) + # Microsoft Office Format + elif file_type in ['docx', 'xlsx', 'pptx']: + meta_file = tmp_folder / 'docProps' / 'core.xml' + meta_content = meta_file.read_text() + tagsearch = re.findall(RE_ODT_CTX, meta_content) + if tagsearch: + tags = list(set(tagsearch[0])) + notesearch = re.findall(RE_ODT_NOTE, meta_content) + if notesearch: + note = list(set(notesearch[0])) + argv = [x for x in ' '.join(tags).split(' ') + note if x != ''] + context = o.context(argv) + for context_key in context.keys(): + o.update(o.path, context, context_key) + shutil.rmtree(tmp_folder) + elif file_type in ['application/msword', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint']: + ole = OleFileIO(o.path) + meta = ole.get_metadata() + ole.close() + if meta.keywords: + tags = meta.keywords.decode('UTF-8').split(' ') + if meta.comments: + note = [meta.comments.decode('UTF-8')] + argv = [x for x in tags + note if x != ''] + context = o.context(argv) + for context_key in context.keys(): + o.update(o.path, context, context_key) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index cfd6667..f29c13c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ +olefile==0.46 +pytaglib==2.0.0 PyYAML==6.0 rich==13.4.1 diff --git a/test/office.odt b/test/office.odt new file mode 100644 index 0000000000000000000000000000000000000000..f2a6e82e5ba4dbc4640de9e3cc3427eec29c7a10 GIT binary patch literal 9201 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 literal 0 HcmV?d00001 diff --git a/test/sheet.xlsx b/test/sheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..656c7d04435e52d33c8188f274b4c18f00ea73bf GIT binary patch literal 4379 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 bEEdC2N(XqevVoKdG6*uHvM?}+gQFJ!!@`So literal 0 HcmV?d00001 diff --git a/test/tableold.xls b/test/tableold.xls new file mode 100644 index 0000000000000000000000000000000000000000..65cd308e45b535359d61533e8e9e9ce47a4d8791 GIT binary patch literal 5632 zcmca`Uhu)fjZzO8(10}qGsD0CoD6J8;*1Oo3>+}N00RRP0|Ns{?BDcfq{XQfdL%n>Qe^B`iD#w`_7#Ps=Kd7t+<$o>)1_o{h z1_mAm1_oXR1_nL`1_pix1_l8J1_nU}1_mJp1_ogU1_luZ1_n_E1_m((1_p6xxgiOq zL3YY8Ffhn6FfhnL#T1}4!u6vpdWQffhX4Zu8!N+Z-ZP*gA6)i7WME?0z;X~=zdvGN zV2EKT0HqD*#GGUWdI2Y}8xk2oY4ZRh1A{Fi69Xf|90n!^K8E#R(LG?&7M%JR7#JKF z6fD4rpON7UqXXFOyvBgOBlZX2jvH_7Z?~A4k&=cK@J0pe<4mB z6k6ES;}Qp%icS6S6<@-@$bc=JwISjE0pxQKhK0W-4sjhE;#xSwIWfd1GqEr*G%)-J z(E<(3U|O(&4NMC)uz+dd26iwl(!lyZ0i1SQ8Tc3iK?OAf8$)nLYHEpL4+9GWBLgGD zK}HUSgNzIeA-#+YuNk61CG>|NkXIPkK1hIQ7DS63l&)adn1TBPs0827z`?-5(8$Qi zz`${U(Sd=1!+}BWBdCn$WnkdoVPN18XJFv?&cGm$%puB<45}PJrb5en5R(a1Q9ue5 z0h9uThk=P9g@GTO1qH#GPk@1g;m^vCmwb}~?Bl`W4T!DvQ-rM)^5TZ4gv zAq@;Z*lQxO7cwX@FfycoLz9uAi9v@^hY_sZ_@zCJW@HFuU}E54s0G)C42+%Jpqh|@ zfq@BBD}q7+hTkv*fV}*{16)&bd;kR)D9k}F=VxI4U;wT~Sw3ihdr_PpKp_p&3!|AB zxWM{AdO$66J0>B9ZQw4M1563HPUU9+)!$%)AmZs9;tc5^8zEd!sDWx05DyedAR2-h z8UFoe=3)T1;RHB9~FGy?;JZ)S2)esO+UiGpiIa%zr(rMYfMVp3{OPAa&n zaLPCpBK$VGVqgN7^`I&d zR>I-c0G0d(Do()#rZYo6LoP!BgFizOLl#t)cnV}c$Uh*vL6{hwpnT;CRmjNT&yd5A z3gwYbaWOD~%Wja}AWV!2QqaB{NG&TvFheOrE<-LuA_J)J@5zwIkOqzukVpwbCPO|$ z9!Mb$tO2zj6r9A`52{x#K+R)iaAC-2NCvwh6+8k#ntLpu_JiyOVW_cqDR~A4h7!Cg dNRtHF3&X_d1oef9QAeyAnB5?n7(K}L0|0$D9d`f# literal 0 HcmV?d00001 diff --git a/test/word.docx b/test/word.docx new file mode 100644 index 0000000000000000000000000000000000000000..e22a65169a0ef928d2c059b5ddec72b9d1028190 GIT binary patch literal 4715 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