initial commit
This commit is contained in:
commit
53739b78f9
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*~
|
||||
.DS_Store
|
||||
*.swp
|
||||
/target
|
||||
**/*.rs.bk
|
19
.idea/misc.xml
Normal file
19
.idea/misc.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CargoProjects">
|
||||
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
|
||||
</component>
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="RustProjectSettings">
|
||||
<option name="toolchainHomeDirectory" value="$USER_HOME$/.cargo/bin" />
|
||||
</component>
|
||||
<component name="SbtLocalSettings">
|
||||
<option name="projectSyncType">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$/../../dev/gitsourcerepositories/dev-ding-10" value="PREVIEW" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/ecload.iml" filepath="$PROJECT_DIR$/ecload.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
400
.idea/workspace.xml
Normal file
400
.idea/workspace.xml
Normal file
@ -0,0 +1,400 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="a321fd91-c97c-4f17-b620-fd9934708617" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/LICENSE" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/error.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/loader.rs" afterDir="false" />
|
||||
</list>
|
||||
<ignored path="$PROJECT_DIR$/out/" />
|
||||
<ignored path="$PROJECT_DIR$/target/" />
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/main.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="360">
|
||||
<caret line="24" column="32" lean-forward="true" selection-start-line="24" selection-start-column="32" selection-end-line="24" selection-end-column="32" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/Cargo.toml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="15" lean-forward="true" selection-start-line="5" selection-start-column="15" selection-end-line="5" selection-end-column="65" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/README.md">
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="480">
|
||||
<caret line="32" lean-forward="true" selection-start-line="32" selection-end-line="32" />
|
||||
</first_editor>
|
||||
<second_editor />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/loader.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="225">
|
||||
<caret line="15" column="47" selection-start-line="15" selection-start-column="47" selection-end-line="15" selection-end-column="47" />
|
||||
<folding>
|
||||
<element signature="e#4669#4670#0" expanded="true" />
|
||||
<element signature="e#4723#4724#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/error.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="15">
|
||||
<caret line="1" column="47" selection-start-line="1" selection-start-column="47" selection-end-line="1" selection-end-column="47" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Rust File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="FindInProjectRecents">
|
||||
<findStrings>
|
||||
<find>got</find>
|
||||
<find>dpi</find>
|
||||
<find>Px</find>
|
||||
<find>PageFormat</find>
|
||||
<find>format</find>
|
||||
</findStrings>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/printpdf-0.2.10/src/types/pdf_document.rs" />
|
||||
<option value="$PROJECT_DIR$/src/loader.rs" />
|
||||
<option value="$PROJECT_DIR$/src/error.rs" />
|
||||
<option value="$PROJECT_DIR$/Cargo.toml" />
|
||||
<option value="$PROJECT_DIR$/LICENSE" />
|
||||
<option value="$PROJECT_DIR$/src/main.rs" />
|
||||
<option value="$PROJECT_DIR$/README.md" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="y" value="30" />
|
||||
<option name="width" value="2488" />
|
||||
<option name="height" value="1410" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator proportions="" version="1">
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scope" />
|
||||
<pane id="PackagesPane" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="ecload" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="ecload" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="ecload" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="ecload" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="src" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="android.sdk.path" value="$USER_HOME$/Library/Android/sdk" />
|
||||
<property name="editor.config.ad.shown" value="true" />
|
||||
<property name="editorconfig.notification" value="[*.md;*.pdf] " />
|
||||
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||
<property name="org.rust.cargo.project.model.PROJECT_DISCOVERY" value="true" />
|
||||
<property name="settings.editor.selected.configurable" value="preferences.keymap" />
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="Run ecload" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="command" value="run --package ecload --bin ecload" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="nocapture" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Cargo Command.Run ecload" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="0" y="23" width="2503" height="1417" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.13815522" />
|
||||
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||
<window_info id="Designer" order="2" />
|
||||
<window_info id="Favorites" order="3" side_tool="true" />
|
||||
<window_info anchor="bottom" id="Message" order="0" />
|
||||
<window_info anchor="bottom" id="Find" order="1" />
|
||||
<window_info active="true" anchor="bottom" id="Run" order="2" visible="true" weight="0.37962264" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info anchor="bottom" id="Docker" order="7" show_stripe_button="false" />
|
||||
<window_info anchor="bottom" id="Version Control" order="8" />
|
||||
<window_info anchor="bottom" id="Database Changes" order="9" />
|
||||
<window_info anchor="bottom" id="Terminal" order="10" />
|
||||
<window_info anchor="bottom" id="Event Log" order="11" side_tool="true" />
|
||||
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
<window_info anchor="right" id="Cargo" order="3" />
|
||||
<window_info anchor="right" id="Database" order="4" />
|
||||
<window_info anchor="right" id="Palette	" order="5" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="1" />
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/.gitignore">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" lean-forward="true" selection-start-line="5" selection-end-line="5" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/reqwest-0.9.9/src/error.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="130">
|
||||
<caret line="62" column="46" lean-forward="true" selection-start-line="62" selection-start-column="46" selection-end-line="62" selection-end-column="60" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/reqwest-0.9.9/src/lib.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="145">
|
||||
<caret line="300" column="39" lean-forward="true" selection-start-line="300" selection-start-column="39" selection-end-line="300" selection-end-column="39" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/cssparser-0.24.1/src/lib.rs">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/selectors-0.20.0/lib.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-149" />
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/scraper-0.9.1/src/lib.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="165">
|
||||
<caret line="135" column="17" lean-forward="true" selection-start-line="135" selection-start-column="17" selection-end-line="135" selection-end-column="17" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/scraper-0.9.1/src/selector.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="175">
|
||||
<caret line="27" column="28" selection-start-line="27" selection-start-column="28" selection-end-line="27" selection-end-column="28" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/convert.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="7065">
|
||||
<caret line="481" column="7" selection-start-line="481" selection-start-column="7" selection-end-line="481" selection-end-column="7" />
|
||||
<folding>
|
||||
<element signature="e#15247#15248#0" expanded="true" />
|
||||
<element signature="e#15280#15281#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/printpdf-0.2.10/src/scale.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="519">
|
||||
<caret line="55" column="8" selection-start-line="55" selection-start-column="8" selection-end-line="55" selection-end-column="47" />
|
||||
<folding>
|
||||
<element signature="e#1296#1297#0" expanded="true" />
|
||||
<element signature="e#1350#1351#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.21.0/src/dynimage.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="540">
|
||||
<caret line="36" column="9" selection-start-line="36" selection-start-column="9" selection-end-line="36" selection-end-column="9" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.20.1/src/jpeg/decoder.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="258">
|
||||
<caret line="33" lean-forward="true" selection-start-line="33" selection-end-line="33" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.20.1/src/dynimage.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="265">
|
||||
<caret line="716" column="7" selection-start-line="716" selection-start-column="7" selection-end-line="716" selection-end-column="7" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.20.1/src/image.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="265">
|
||||
<caret line="220" column="60" lean-forward="true" selection-start-line="220" selection-start-column="60" selection-end-line="220" selection-end-column="60" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/printpdf-0.2.10/src/types/plugins/graphics/xobject.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="220">
|
||||
<caret line="170" column="5" lean-forward="true" selection-start-line="170" selection-start-column="5" selection-end-line="170" selection-end-column="5" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/printpdf-0.2.10/src/types/plugins/graphics/two_dimensional/image.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="310">
|
||||
<caret line="32" column="41" selection-start-line="32" selection-start-column="41" selection-end-line="32" selection-end-column="41" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/lopdf-0.17.0/src/processor.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="258">
|
||||
<caret line="76" column="11" selection-start-line="76" selection-start-column="11" selection-end-line="76" selection-end-column="11" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/printpdf-0.2.10/src/types/pdf_document.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="610">
|
||||
<caret line="465" column="16" lean-forward="true" selection-start-line="465" selection-start-column="16" selection-end-line="465" selection-end-column="16" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-2.32.0/src/macros.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="538">
|
||||
<caret line="60" column="13" selection-start-line="60" selection-start-column="13" selection-end-line="60" selection-end-column="13" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/error.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="15">
|
||||
<caret line="1" column="47" selection-start-line="1" selection-start-column="47" selection-end-line="1" selection-end-column="47" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/loader.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="225">
|
||||
<caret line="15" column="47" selection-start-line="15" selection-start-column="47" selection-end-line="15" selection-end-column="47" />
|
||||
<folding>
|
||||
<element signature="e#4669#4670#0" expanded="true" />
|
||||
<element signature="e#4723#4724#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/LICENSE">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="707">
|
||||
<caret line="373" lean-forward="true" selection-start-line="373" selection-end-line="373" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/main.rs">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="360">
|
||||
<caret line="24" column="32" lean-forward="true" selection-start-line="24" selection-start-column="32" selection-end-line="24" selection-end-column="32" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/Cargo.toml">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="75">
|
||||
<caret line="5" column="15" lean-forward="true" selection-start-line="5" selection-start-column="15" selection-end-line="5" selection-end-column="65" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/README.md">
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="480">
|
||||
<caret line="32" lean-forward="true" selection-start-line="32" selection-end-line="32" />
|
||||
</first_editor>
|
||||
<second_editor />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<settings>
|
||||
<last-edited>1.8</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
1994
Cargo.lock
generated
Normal file
1994
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "ecload"
|
||||
version = "0.1.0"
|
||||
authors = ["Sebastian Hugentobler <sebastian@vanwa.ch>"]
|
||||
edition = "2018"
|
||||
description = "Download books from https://www.e-codices.unifr.ch"
|
||||
repository = "https://code.vanwa.ch/sebastian@vanwa.ch/ecload"
|
||||
readme = "README.md"
|
||||
keywords = ["e-codice", "cli"]
|
||||
categories = ["command-line-utilities"]
|
||||
license = "MPL-2.0"
|
||||
|
||||
|
||||
[dependencies]
|
||||
clap = "2.32.0"
|
||||
image = "0.20.0"
|
||||
log = "0.4.6"
|
||||
printpdf = "0.2.10"
|
||||
reqwest = "0.9.9"
|
||||
scraper = "0.9.1"
|
||||
simple_logger = "1.0.1"
|
||||
tempfile = "3.0.5"
|
373
LICENSE
Normal file
373
LICENSE
Normal file
@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
32
README.md
Normal file
32
README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# ecload
|
||||
|
||||
A small tool to download books from https://www.e-codices.unifr.ch.
|
||||
|
||||
|
||||
# Installation
|
||||
Install from [crates.io](https://crates.io/crates/ecload).
|
||||
|
||||
```
|
||||
cargo install ecload
|
||||
```
|
||||
|
||||
|
||||
# Usage
|
||||
|
||||
```
|
||||
USAGE:
|
||||
ecload [OPTIONS]
|
||||
|
||||
FLAGS:
|
||||
-h, --help Prints help information
|
||||
-V, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
-i, --id <ID> Id of the book to download. Copy the last to url parts on the overview page to get it (for
|
||||
example bbb/0003).
|
||||
-o, --out-dir <DIR> The directory where the resulting pdf is saved. [default: .]
|
||||
-s, --size <SIZE> Sets the size of the downloaded images. [default: medium] [possible values: Small, Medium,
|
||||
Large, Max]
|
||||
```
|
||||
|
||||
---
|
15
ecload.iml
Normal file
15
ecload.iml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="RUST_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
33
src/error.rs
Normal file
33
src/error.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#[derive(Debug)]
|
||||
/// Convert different errors into a common one.
|
||||
pub enum EcloadError {
|
||||
Error(String),
|
||||
StdError(std::io::Error),
|
||||
ReqwestError(reqwest::Error),
|
||||
PrintPdfError(printpdf::Error),
|
||||
ImageError(image::ImageError),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for EcloadError {
|
||||
fn from(e: std::io::Error) -> Self {
|
||||
EcloadError::StdError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for EcloadError {
|
||||
fn from(e: reqwest::Error) -> Self {
|
||||
EcloadError::ReqwestError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<printpdf::Error> for EcloadError {
|
||||
fn from(e: printpdf::Error) -> Self {
|
||||
EcloadError::PrintPdfError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<image::ImageError> for EcloadError {
|
||||
fn from(e: image::ImageError) -> Self {
|
||||
EcloadError::ImageError(e)
|
||||
}
|
||||
}
|
281
src/loader.rs
Normal file
281
src/loader.rs
Normal file
@ -0,0 +1,281 @@
|
||||
use std::fs;
|
||||
use std::fs::DirEntry;
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::io::copy;
|
||||
use std::path::Path;
|
||||
|
||||
use image::DynamicImage;
|
||||
use image::GenericImageView;
|
||||
use printpdf::{Image, Mm, PdfDocument};
|
||||
use scraper::{Html, Selector};
|
||||
use tempfile::TempDir;
|
||||
|
||||
use crate::error::EcloadError;
|
||||
|
||||
const BASEURL: &str = "https://www.e-codices.unifr.ch";
|
||||
const DPI: f64 = 300.0;
|
||||
const INCH_AS_MM: f64 = 25.4;
|
||||
|
||||
/// Provides functions to download e-codices.
|
||||
pub struct EcLoader {}
|
||||
|
||||
arg_enum! {
|
||||
#[derive(PartialEq, Debug)]
|
||||
/// Defines the different sizes that e-codice pages can be.
|
||||
pub enum PageFormat {
|
||||
Small,
|
||||
Medium,
|
||||
Large,
|
||||
Max,
|
||||
}
|
||||
}
|
||||
|
||||
impl PageFormat {
|
||||
/// Converts the formats in the represantation that the e-codice website uses.
|
||||
fn as_url_part(&self) -> &str {
|
||||
match self {
|
||||
PageFormat::Small => "small",
|
||||
PageFormat::Medium => "medium",
|
||||
PageFormat::Large => "large",
|
||||
PageFormat::Max => "max",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EcLoader {
|
||||
/// Download an e-codice from https://www.e-codices.unifr.ch.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - The combined id ot the e-codice. Consisting of the library id and the e-codice id (for example "bbb/0003").
|
||||
/// * `title` - Title of the pdf, this will also be the filename.
|
||||
/// * `out_dir` - Directory where the PDF gets saved (must already exist).
|
||||
/// * `format` - The size of the page to look for.
|
||||
pub fn download_codice(
|
||||
id: &str,
|
||||
title: &str,
|
||||
out_dir: &Path,
|
||||
format: PageFormat,
|
||||
) -> Result<(), EcloadError> {
|
||||
let tmp_dir = tempfile::tempdir()?;
|
||||
debug!("temporary download directory: {}", tmp_dir.path().display());
|
||||
|
||||
EcLoader::download_pages(id, format, &tmp_dir)
|
||||
.and_then(|_| EcLoader::build_pdf(title, out_dir, &tmp_dir))
|
||||
}
|
||||
|
||||
/// Order files in a temporary directory
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `tmp_dir`- Reference to the temporary directory.
|
||||
fn get_ordered_tmp_files(tmp_dir: &TempDir) -> Result<Vec<DirEntry>, EcloadError> {
|
||||
let paths = fs::read_dir(tmp_dir.path())?;
|
||||
let mut sorted_paths: Vec<DirEntry> = paths.filter_map(|r| r.ok()).collect();
|
||||
|
||||
sorted_paths.sort_by_key(|dir| dir.path());
|
||||
|
||||
Ok(sorted_paths)
|
||||
}
|
||||
|
||||
/// Calculate image dimensions in mm.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `image` - Image for the calculation.
|
||||
fn mm_from_image(image: &DynamicImage) -> (Mm, Mm) {
|
||||
let (width, height) = image.dimensions();
|
||||
let mm_width = Mm(width as f64 * (INCH_AS_MM / DPI));
|
||||
let mm_height = Mm(height as f64 * (INCH_AS_MM / DPI));
|
||||
|
||||
(mm_width, mm_height)
|
||||
}
|
||||
|
||||
/// Convert an image to BMP.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `img_path` - Path to the image that should be converted.
|
||||
///
|
||||
/// # Remarks
|
||||
///
|
||||
/// The BMP file gets saved to the same directory as the original, with the same name apart from
|
||||
/// the extension.
|
||||
fn get_img_as_bmp(img_path: &Path) -> Result<DynamicImage, EcloadError> {
|
||||
let image = image::open(img_path)?;
|
||||
let img_bmp_path = img_path.with_extension("bmp");
|
||||
image.save(&img_bmp_path)?;
|
||||
|
||||
Ok(image::open(img_bmp_path)?)
|
||||
}
|
||||
|
||||
/// Generate a PDF from images inside a directory.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `title` - Title of the pdf, this will also be the filename.
|
||||
/// * `out_dir` - Directory where the PDF gets saved (must already exist).
|
||||
/// * `tmp_dir` - Reference to the temporary directory where the images for the pdf are.
|
||||
fn build_pdf(title: &str, out_dir: &Path, tmp_dir: &TempDir) -> Result<(), EcloadError> {
|
||||
let ordered_tmp_files = EcLoader::get_ordered_tmp_files(tmp_dir)?;
|
||||
let first_file = match ordered_tmp_files.first() {
|
||||
Some(file) => file,
|
||||
None => return Err(EcloadError::Error("no tmp files".to_string())),
|
||||
};
|
||||
|
||||
let first_image_data = image::open(first_file.path())?;
|
||||
let (first_img_width, first_img_height) = EcLoader::mm_from_image(&first_image_data);
|
||||
|
||||
let (doc, page1, layer1) =
|
||||
PdfDocument::new(title, first_img_width, first_img_height, "Layer 1");
|
||||
let mut current_layer = doc.get_page(page1).get_layer(layer1);
|
||||
|
||||
let mut is_first_page = true;
|
||||
let mut page_count = 1;
|
||||
for entry in ordered_tmp_files {
|
||||
let filename_os = entry.file_name();
|
||||
let filename = match filename_os.to_str() {
|
||||
Some(filename) => filename,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if !filename.ends_with(".jpg") {
|
||||
continue;
|
||||
}
|
||||
|
||||
info!("saving page {} to pdf...", page_count);
|
||||
let image_bmp = match EcLoader::get_img_as_bmp(&entry.path()) {
|
||||
Ok(image_data) => image_data,
|
||||
Err(err) => {
|
||||
error!("could not decode {}: {:?}", entry.path().display(), err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut image_file = File::open(entry.path().with_extension("bmp")).unwrap();
|
||||
let image = Image::try_from(image::bmp::BMPDecoder::new(&mut image_file)).unwrap();
|
||||
|
||||
let (img_width, img_height) = EcLoader::mm_from_image(&image_bmp);
|
||||
debug!("dimensions: {:?} x {:?}", img_width, img_height);
|
||||
|
||||
if !is_first_page {
|
||||
let (new_page, new_layer) = doc.add_page(img_width, img_height, "Layer 1");
|
||||
current_layer = doc.get_page(new_page).get_layer(new_layer);
|
||||
}
|
||||
|
||||
image.add_to_layer(
|
||||
current_layer.clone(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(DPI),
|
||||
);
|
||||
|
||||
is_first_page = false;
|
||||
page_count += 1;
|
||||
}
|
||||
|
||||
let pdf_file_path = out_dir.join(format!("{}.pdf", title));
|
||||
info!("saved to {}", pdf_file_path.display());
|
||||
let pdf_file = File::create(pdf_file_path)?;
|
||||
doc.save(&mut BufWriter::new(pdf_file))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_thumbnail_url(id: &str) -> String {
|
||||
format!("{}/en/thumbs/{}", BASEURL, id)
|
||||
}
|
||||
|
||||
/// Download all the pages of an e-codice to a temporary directory.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - The combined id ot the e-codice. Consisting of the library id and the e-codice id (for example "bbb/0003").
|
||||
/// * `format` - The size of the page to look for.
|
||||
/// * `tmp_dir` - Reference to a temporary directory where the downloaded files get saved.
|
||||
fn download_pages(id: &str, format: PageFormat, tmp_dir: &TempDir) -> Result<(), EcloadError> {
|
||||
let thumbnail_url = EcLoader::get_thumbnail_url(id);
|
||||
let mut response = reqwest::get(thumbnail_url.as_str())?;
|
||||
let html = response.text()?;
|
||||
let fragment = Html::parse_fragment(&html);
|
||||
|
||||
let li_selector = Selector::parse("div.thumbnail-image > a").unwrap();
|
||||
|
||||
let mut page_count = 0;
|
||||
for element in fragment.select(&li_selector) {
|
||||
let page_link = match element.value().attr("href") {
|
||||
Some(href) => href.to_string(),
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
debug!("searching download links for {}...", page_link);
|
||||
let download_link = match EcLoader::get_download_link(&page_link, &format) {
|
||||
Ok(download_link) => download_link,
|
||||
Err(err) => {
|
||||
error!(
|
||||
"could not find download link for {} with format {}: {:?}",
|
||||
&page_link, format, err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
debug!("found {}", download_link);
|
||||
|
||||
info!("downloading {}...", download_link);
|
||||
let page_file_path = tmp_dir
|
||||
.path()
|
||||
.join(format!("{:0>5}.jpg", page_count.to_string()));
|
||||
|
||||
let mut page_download = match reqwest::get(&download_link) {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
error!("could not download {}: {:?}", download_link, err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut dest = File::create(page_file_path)?;
|
||||
copy(&mut page_download, &mut dest)?;
|
||||
|
||||
page_count += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finds the image url for a specified size for an e-codice page.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `page_link` - The specific e-codice page url.
|
||||
/// * `format` - The size of the page to look for.
|
||||
fn get_download_link(page_link: &str, format: &PageFormat) -> Result<String, EcloadError> {
|
||||
let mut response = reqwest::get(page_link)?;
|
||||
let html = response.text()?;
|
||||
let fragment = Html::parse_fragment(&html);
|
||||
|
||||
let a_selector = Selector::parse("ul.download-page-list > li > a").unwrap();
|
||||
for element in fragment.select(&a_selector) {
|
||||
let download_link = match element.value().attr("href") {
|
||||
Some(href) => href.to_string(),
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if download_link.ends_with(format.as_url_part()) {
|
||||
return Ok(download_link);
|
||||
}
|
||||
}
|
||||
|
||||
Err(EcloadError::Error(
|
||||
"could not find download link".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
84
src/main.rs
Normal file
84
src/main.rs
Normal file
@ -0,0 +1,84 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate image;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate printpdf;
|
||||
extern crate reqwest;
|
||||
extern crate scraper;
|
||||
extern crate simple_logger;
|
||||
extern crate tempfile;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use clap::{App, AppSettings, Arg};
|
||||
|
||||
use crate::error::EcloadError;
|
||||
use crate::loader::EcLoader;
|
||||
|
||||
pub mod error;
|
||||
pub mod loader;
|
||||
|
||||
fn main() {
|
||||
simple_logger::init_with_level(log::Level::Info).unwrap();
|
||||
|
||||
let app = App::new("ecload")
|
||||
.version("0.1.0")
|
||||
.author("Sebastian Hugentobler <sebastian@vanwa.ch>")
|
||||
.about("Download books from https://www.e-codices.unifr.ch")
|
||||
.arg(
|
||||
Arg::with_name("output directory")
|
||||
.short("o")
|
||||
.long("out-dir")
|
||||
.value_name("DIR")
|
||||
.help("The directory where the resulting pdf is saved.")
|
||||
.takes_value(true)
|
||||
.default_value("."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("size")
|
||||
.short("s")
|
||||
.long("size")
|
||||
.value_name("SIZE")
|
||||
.help("Sets the size of the downloaded images.")
|
||||
.takes_value(true)
|
||||
.possible_values(&loader::PageFormat::variants())
|
||||
.default_value("medium")
|
||||
.case_insensitive(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.short("i")
|
||||
.long("id")
|
||||
.value_name("ID")
|
||||
.help("Id of the book to download. Copy the last to url parts on the overview page to get it (for example bbb/0003).")
|
||||
.takes_value(true),
|
||||
)
|
||||
.setting(AppSettings::ArgRequiredElseHelp);
|
||||
|
||||
let matches = app.clone().get_matches();
|
||||
|
||||
let out_path_str = matches.value_of("output directory").unwrap();
|
||||
let out_path = Path::new(out_path_str);
|
||||
let size = value_t!(matches.value_of("size"), loader::PageFormat).unwrap();
|
||||
let id = match matches.value_of("id") {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
println!("ID is a required argument:");
|
||||
println!();
|
||||
app.clone().print_help().ok();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let title = &id.replace("/", "_");
|
||||
|
||||
match run(&out_path, size, id, title) {
|
||||
Ok(_) => info!("finished!"),
|
||||
Err(e) => error!("something went wrong: {:?}", e),
|
||||
};
|
||||
}
|
||||
|
||||
fn run(out_path: &Path, format: loader::PageFormat, id: &str, title: &str) -> Result<(), EcloadError> {
|
||||
EcLoader::download_codice(id, title, out_path, format)
|
||||
}
|
Loading…
Reference in New Issue
Block a user