Skip to content

Commit

Permalink
Adda an --input-filter argument (#100)
Browse files Browse the repository at this point in the history
Also change the --filter argument to --output-filter, but keep --filter as an alias.
Also add the possibility to use file extensions etc as filter names, if they are specified (which they rarely are).

Co-authored-by: Lennart Regebro <[email protected]>
  • Loading branch information
regebro and Lennart Regebro authored Jan 12, 2024
1 parent 1c6184b commit 7797405
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 9 deletions.
11 changes: 10 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
2.0.2 (unreleased)
------------------

- Nothing changed yet.
- Add a --input-filter argument to specify a different file type than the
one LibreOffice will guess.

- For consistency renamed --filter to --output-filter, but the --filter
will remain for backwards compatibility.

- If you specify a non-existent filter, the list of filters is now alphabetical.

- You can now use both the LibreOffice name, but also internal shorter names
and sometimes even file suffices to specify the filter.


2.0.1 (2024-01-12)
Expand Down
10 changes: 9 additions & 1 deletion src/unoserver/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def convert(
filtername=None,
filter_options=[],
update_index=True,
infiltername=None,
):
"""Converts a file from one type to another
Expand Down Expand Up @@ -92,6 +93,7 @@ def convert(
filtername,
filter_options,
update_index,
infiltername,
)
if result is not None:
# We got the file back over xmlrpc:
Expand Down Expand Up @@ -192,6 +194,11 @@ def converter_main():
help="The file type/extension of the output file (ex pdf). Required when using stdout",
)
parser.add_argument(
"--input-filter",
help="The LibreOffice input filter to use (ex 'writer8'), if autodetect fails",
)
parser.add_argument(
"--output-filter",
"--filter",
default=None,
help="The export filter to use when converting. It is selected automatically if not specified.",
Expand Down Expand Up @@ -250,9 +257,10 @@ def converter_main():
indata=indata,
outpath=args.outfile,
convert_to=args.convert_to,
filtername=args.filter,
filtername=args.output_filter,
filter_options=args.filter_options,
update_index=args.update_index,
infiltername=args.input_filter,
)

if args.outfile is None:
Expand Down
4 changes: 3 additions & 1 deletion src/unoserver/comparer.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,9 @@ def compare(
)

logger.info(f"Exporting to {outpath}")
logger.info(f"Using {filtername} export filter")
logger.info(
f"Using {filtername} export filter from {new_type} to {export_type}"
)

output_props = (
PropertyValue(Name="FilterName", Value=filtername),
Expand Down
64 changes: 58 additions & 6 deletions src/unoserver/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ def find_filter(self, import_type, export_type):
# No filter found
return None

def get_available_import_filters(self):
# List import filters. You can only search on module, iflags and eflags,
# so the import and export types we have to test in a loop
import_filters = self.filter_service.createSubSetEnumerationByQuery(
"getSortedFilterList():iflags=1"
)

while import_filters.hasMoreElements():
# Filter DocumentService here
yield prop2dict(import_filters.nextElement())

def get_available_export_filters(self):
# List export filters. You can only search on module, iflags and eflags,
# so the import and export types we have to test in a loop
Expand All @@ -113,8 +124,20 @@ def get_available_export_filters(self):
# Filter DocumentService here
yield prop2dict(export_filters.nextElement())

def get_available_filter_names(self):
return [filter["Name"] for filter in self.get_available_export_filters()]
def get_filter_names(self, filters):
names = {}
for flt in filters:
# Add all names and exstensions, etc in a mapping to the internal
# Libreoffice name, so we can map it.
# The actual name:
names[flt["Name"]] = flt["Name"]
# UserData sometimes has file extensions, etc.
# Skip empty data, and those weird file paths, and "true"...
for name in filter(
lambda x: x and x != "true" and "." not in x, flt["UserData"]
):
names[name] = flt["Name"]
return names

def convert(
self,
Expand All @@ -125,6 +148,7 @@ def convert(
filtername=None,
filter_options=[],
update_index=True,
infiltername=None,
):
"""Converts a file from one type to another
Expand All @@ -139,12 +163,25 @@ def convert(
filtername: The name of the export filter to use for conversion. If None, it is auto-detected.
filter_options: A list of output filter options as strings, in a "OptionName=Value" format.
update_index: Updates the index before conversion
infiltername: The name of the input filter, ie "writer8", "PowerPoint 3", etc.
You must specify the inpath or the indata, and you must specify and outpath or a convert_to.
"""

input_props = (PropertyValue(Name="ReadOnly", Value=True),)
if infiltername:
infilters = self.get_filter_names(self.get_available_import_filters())
if infiltername in infilters:
input_props += (
PropertyValue(Name="FilterName", Value=infilters[infiltername]),
)
else:
raise ValueError(
f"There is no '{infiltername}' import filter. Available filters: {sorted(infilters.keys())}"
)

if inpath:
# TODO: Verify that inpath exists and is openable, and that outdir exists, because uno's
Expand All @@ -171,6 +208,17 @@ def convert(
import_path, "_default", 0, input_props
)

if document is None:
# Could not load document, fail
if not inpath:
inpath = "<remote file>"
if not infiltername:
infiltername = "default"

error = f"Could not load document {inpath} using the {infiltername} filter."
logger.error(error)
raise RuntimeError(error)

if update_index:
# Update document indexes
for ii in range(2):
Expand Down Expand Up @@ -216,10 +264,12 @@ def convert(
)

if filtername is not None:
available_filter_names = self.get_available_filter_names()
available_filter_names = self.get_filter_names(
self.get_available_export_filters()
)
if filtername not in available_filter_names:
raise RuntimeError(
f"'{filtername}' is not a valid filter name. Valid filters are {available_filter_names}"
f"There is no '{filtername}' export-filter. Available filters: {sorted(available_filter_names)}"
)
else:
filtername = self.find_filter(import_type, export_type)
Expand All @@ -229,7 +279,9 @@ def convert(
)

logger.info(f"Exporting to {outpath}")
logger.info(f"Using {filtername} export filter")
logger.info(
f"Using {filtername} export filter from {infiltername} to {export_type}"
)

filter_data = []
for option in filter_options:
Expand Down
2 changes: 2 additions & 0 deletions src/unoserver/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def convert(
filtername=None,
filter_options=[],
update_index=True,
infiltername=None,
):
if indata is not None:
indata = indata.data
Expand All @@ -114,6 +115,7 @@ def convert(
filtername,
filter_options,
update_index,
infiltername,
)
return result

Expand Down

0 comments on commit 7797405

Please sign in to comment.