355 lines
12 KiB
JavaScript
355 lines
12 KiB
JavaScript
|
/*
|
||
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||
|
if you want to view the source, please visit the github repository of this plugin
|
||
|
*/
|
||
|
|
||
|
var __create = Object.create;
|
||
|
var __defProp = Object.defineProperty;
|
||
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||
|
var __getProtoOf = Object.getPrototypeOf;
|
||
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||
|
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
||
|
var __export = (target, all) => {
|
||
|
__markAsModule(target);
|
||
|
for (var name in all)
|
||
|
__defProp(target, name, { get: all[name], enumerable: true });
|
||
|
};
|
||
|
var __reExport = (target, module2, desc) => {
|
||
|
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
||
|
for (let key of __getOwnPropNames(module2))
|
||
|
if (!__hasOwnProp.call(target, key) && key !== "default")
|
||
|
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
|
||
|
}
|
||
|
return target;
|
||
|
};
|
||
|
var __toModule = (module2) => {
|
||
|
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
|
||
|
};
|
||
|
var __async = (__this, __arguments, generator) => {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
var fulfilled = (value) => {
|
||
|
try {
|
||
|
step(generator.next(value));
|
||
|
} catch (e) {
|
||
|
reject(e);
|
||
|
}
|
||
|
};
|
||
|
var rejected = (value) => {
|
||
|
try {
|
||
|
step(generator.throw(value));
|
||
|
} catch (e) {
|
||
|
reject(e);
|
||
|
}
|
||
|
};
|
||
|
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
||
|
step((generator = generator.apply(__this, __arguments)).next());
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// main.ts
|
||
|
__export(exports, {
|
||
|
default: () => PDFAnnotationPlugin
|
||
|
});
|
||
|
var import_obsidian = __toModule(require("obsidian"));
|
||
|
|
||
|
// extractHighlight.ts
|
||
|
var SUPPORTED_ANNOTS = ["Text", "Highlight", "Underline"];
|
||
|
function searchQuad(minx, maxx, miny, maxy, items) {
|
||
|
const mycontent = items.reduce(function(txt, x) {
|
||
|
if (x.width == 0)
|
||
|
return txt;
|
||
|
if (!(miny <= x.transform[5] && x.transform[5] <= maxy))
|
||
|
return txt;
|
||
|
if (x.transform[4] + x.width < minx)
|
||
|
return txt;
|
||
|
if (x.transform[4] > maxx)
|
||
|
return txt;
|
||
|
const start = x.transform[4] >= minx ? 0 : Math.floor(x.str.length * (minx - x.transform[4]) / x.width);
|
||
|
if (x.transform[4] + x.width <= maxx) {
|
||
|
return txt + x.str.substr(start);
|
||
|
} else {
|
||
|
const lenc = Math.floor(x.str.length * (maxx - x.transform[4]) / x.width) - start;
|
||
|
return txt + x.str.substr(start, lenc);
|
||
|
}
|
||
|
}, "");
|
||
|
return mycontent.trim();
|
||
|
}
|
||
|
function extractHighlight(annot, items) {
|
||
|
const highlight = annot.quadPoints.reduce((txt, quad) => {
|
||
|
const minx = quad.reduce((prev, curr) => Math.min(prev, curr.x), quad[0].x);
|
||
|
const maxx = quad.reduce((prev, curr) => Math.max(prev, curr.x), quad[0].x);
|
||
|
const miny = quad.reduce((prev, curr) => Math.min(prev, curr.y), quad[0].y);
|
||
|
const maxy = quad.reduce((prev, curr) => Math.max(prev, curr.y), quad[0].y);
|
||
|
const res = searchQuad(minx, maxx, miny, maxy, items);
|
||
|
if (txt.substring(txt.length - 1) != "-") {
|
||
|
return txt + " " + res;
|
||
|
} else if (txt.substring(txt.length - 2).toLowerCase() == txt.substring(txt.length - 2) && res.substring(0, 1).toLowerCase() == res.substring(0, 1)) {
|
||
|
return txt.substring(0, txt.length - 1) + res;
|
||
|
} else {
|
||
|
return txt + res;
|
||
|
}
|
||
|
}, "");
|
||
|
return highlight;
|
||
|
}
|
||
|
function loadPage(page, pagenum, file, containingFolder, total) {
|
||
|
return __async(this, null, function* () {
|
||
|
let annotations = yield page.getAnnotations();
|
||
|
annotations = annotations.filter(function(anno) {
|
||
|
return SUPPORTED_ANNOTS.indexOf(anno.subtype) >= 0;
|
||
|
});
|
||
|
const content = yield page.getTextContent({ normalizeWhitespace: true });
|
||
|
content.items.sort(function(a1, a2) {
|
||
|
if (a1.transform[5] > a2.transform[5])
|
||
|
return -1;
|
||
|
if (a1.transform[5] < a2.transform[5])
|
||
|
return 1;
|
||
|
if (a1.transform[4] > a2.transform[4])
|
||
|
return 1;
|
||
|
if (a1.transform[4] < a2.transform[4])
|
||
|
return -1;
|
||
|
return 0;
|
||
|
});
|
||
|
annotations.map(function(anno) {
|
||
|
return __async(this, null, function* () {
|
||
|
if (anno.subtype == "Highlight" || anno.subtype == "Underline") {
|
||
|
anno.highlightedText = extractHighlight(anno, content.items);
|
||
|
}
|
||
|
anno.folder = containingFolder;
|
||
|
anno.file = file;
|
||
|
anno.filepath = file.path;
|
||
|
anno.pageNumber = pagenum;
|
||
|
anno.author = anno.titleObj.str;
|
||
|
anno.body = anno.contentsObj.str;
|
||
|
total.push(anno);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function loadPDFFile(file, pdfjsLib, containingFolder, total) {
|
||
|
return __async(this, null, function* () {
|
||
|
const content = yield this.app.vault.readBinary(file);
|
||
|
const pdf = yield pdfjsLib.getDocument(content).promise;
|
||
|
for (let i = 1; i <= pdf.numPages; i++) {
|
||
|
const page = yield pdf.getPage(i);
|
||
|
yield loadPage(page, i, file, containingFolder, total);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// main.ts
|
||
|
function template(strings, ...keys) {
|
||
|
return function(...values) {
|
||
|
const dict = values[values.length - 1] || {};
|
||
|
const result = [strings[0]];
|
||
|
keys.forEach(function(key, i) {
|
||
|
const value = Number.isInteger(key) ? values[key] : dict[key];
|
||
|
result.push(value, strings[i + 1]);
|
||
|
});
|
||
|
return result.join("");
|
||
|
};
|
||
|
}
|
||
|
var highlighted = template`> ${"highlightedText"}
|
||
|
|
||
|
${"body"}
|
||
|
|
||
|
* *highlighted by ${"author"} at page ${"pageNumber"} on [[${"filepath"}]]*
|
||
|
|
||
|
`;
|
||
|
var note = template`${"body"}
|
||
|
|
||
|
* *noted by ${"author"} at page ${"pageNumber"} on [[${"filepath"}]]*
|
||
|
|
||
|
`;
|
||
|
var PDFAnnotationPlugin = class extends import_obsidian.Plugin {
|
||
|
sort(grandtotal) {
|
||
|
const settings = this.settings;
|
||
|
if (settings.sortByTopic) {
|
||
|
grandtotal.forEach((anno) => {
|
||
|
const lines = anno.body.split(/\r\n|\n\r|\n|\r/);
|
||
|
anno.topic = lines[0];
|
||
|
anno.body = lines.slice(1).join("\r\n");
|
||
|
});
|
||
|
}
|
||
|
grandtotal.sort(function(a1, a2) {
|
||
|
if (settings.sortByTopic) {
|
||
|
if (a1.topic > a2.topic)
|
||
|
return 1;
|
||
|
if (a1.topic < a2.topic)
|
||
|
return -1;
|
||
|
}
|
||
|
if (settings.useFolderNames) {
|
||
|
if (a1.folder > a2.folder)
|
||
|
return 1;
|
||
|
if (a1.folder < a2.folder)
|
||
|
return -1;
|
||
|
}
|
||
|
if (a1.file.name > a2.file.name)
|
||
|
return 1;
|
||
|
if (a1.file.name < a2.file.name)
|
||
|
return -1;
|
||
|
if (a1.pageNumber > a2.pageNumber)
|
||
|
return 1;
|
||
|
if (a1.pageNumber < a2.pageNumber)
|
||
|
return -1;
|
||
|
if (a1.rect[1] > a2.rect[1])
|
||
|
return -1;
|
||
|
if (a1.rect[1] < a2.rect[1])
|
||
|
return 1;
|
||
|
return 0;
|
||
|
});
|
||
|
}
|
||
|
format(grandtotal) {
|
||
|
let text = "";
|
||
|
let topic = "";
|
||
|
let currentFolder = "";
|
||
|
grandtotal.forEach((a) => {
|
||
|
if (this.settings.sortByTopic) {
|
||
|
if (topic != a.topic) {
|
||
|
topic = a.topic;
|
||
|
currentFolder = "";
|
||
|
text += `# ${topic}
|
||
|
`;
|
||
|
}
|
||
|
}
|
||
|
if (this.settings.useFolderNames) {
|
||
|
if (currentFolder != a.folder) {
|
||
|
currentFolder = a.folder;
|
||
|
text += `## ${currentFolder}
|
||
|
`;
|
||
|
}
|
||
|
} else {
|
||
|
if (currentFolder != a.file.name) {
|
||
|
currentFolder = a.file.name;
|
||
|
text += `## ${currentFolder}
|
||
|
`;
|
||
|
}
|
||
|
}
|
||
|
if (a.subtype == "Text") {
|
||
|
text += note(a);
|
||
|
} else {
|
||
|
text += highlighted(a);
|
||
|
}
|
||
|
});
|
||
|
if (grandtotal.length == 0)
|
||
|
return "*No Annotations*";
|
||
|
else
|
||
|
return text;
|
||
|
}
|
||
|
loadSinglePDFFile(file) {
|
||
|
return __async(this, null, function* () {
|
||
|
const pdfjsLib = yield (0, import_obsidian.loadPdfJs)();
|
||
|
const containingFolder = file.parent.name;
|
||
|
const grandtotal = [];
|
||
|
console.log("loading from file ", file);
|
||
|
yield loadPDFFile(file, pdfjsLib, containingFolder, grandtotal);
|
||
|
this.sort(grandtotal);
|
||
|
const finalMarkdown = this.format(grandtotal);
|
||
|
let filePath = file.name.replace(".pdf", ".md");
|
||
|
filePath = "Annotations for " + filePath;
|
||
|
yield this.saveHighlightsToFile(filePath, finalMarkdown);
|
||
|
yield this.app.workspace.openLinkText(filePath, "", true);
|
||
|
});
|
||
|
}
|
||
|
onload() {
|
||
|
return __async(this, null, function* () {
|
||
|
this.loadSettings();
|
||
|
this.addSettingTab(new PDFAnnotationPluginSettingTab(this.app, this));
|
||
|
this.addCommand({
|
||
|
id: "extract-annotations-single",
|
||
|
name: "Extract PDF Annotations on single file",
|
||
|
checkCallback: (checking) => {
|
||
|
const file = this.app.workspace.getActiveFile();
|
||
|
if (file != null && file.extension === "pdf") {
|
||
|
if (!checking) {
|
||
|
this.loadSinglePDFFile(file);
|
||
|
}
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
this.addCommand({
|
||
|
id: "extract-annotations",
|
||
|
name: "Extract PDF Annotations",
|
||
|
editorCallback: (editor, view) => __async(this, null, function* () {
|
||
|
const file = this.app.workspace.getActiveFile();
|
||
|
if (file == null)
|
||
|
return;
|
||
|
const folder = file.parent;
|
||
|
const grandtotal = [];
|
||
|
const pdfjsLib = yield (0, import_obsidian.loadPdfJs)();
|
||
|
editor.replaceSelection("Extracting PDF Comments from " + folder.name + "\n");
|
||
|
const promises = [];
|
||
|
import_obsidian.Vault.recurseChildren(folder, (file2) => __async(this, null, function* () {
|
||
|
if (file2 instanceof import_obsidian.TFile) {
|
||
|
if (file2.extension === "pdf") {
|
||
|
promises.push(loadPDFFile(file2, pdfjsLib, file2.parent.name, grandtotal));
|
||
|
}
|
||
|
}
|
||
|
}));
|
||
|
yield Promise.all(promises);
|
||
|
this.sort(grandtotal);
|
||
|
editor.replaceSelection(this.format(grandtotal));
|
||
|
})
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
loadSettings() {
|
||
|
this.settings = new PDFAnnotationPluginSetting();
|
||
|
(() => __async(this, null, function* () {
|
||
|
const loadedSettings = yield this.loadData();
|
||
|
if (loadedSettings) {
|
||
|
this.settings.useFolderNames = loadedSettings.useFolderNames;
|
||
|
this.settings.sortByTopic = loadedSettings.sortByTopic;
|
||
|
}
|
||
|
}))();
|
||
|
}
|
||
|
onunload() {
|
||
|
}
|
||
|
saveHighlightsToFile(filePath, mdString) {
|
||
|
return __async(this, null, function* () {
|
||
|
const fileExists = yield this.app.vault.adapter.exists(filePath);
|
||
|
if (fileExists) {
|
||
|
yield this.appendHighlightsToFile(filePath, mdString);
|
||
|
} else {
|
||
|
yield this.app.vault.create(filePath, mdString);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
appendHighlightsToFile(filePath, note2) {
|
||
|
return __async(this, null, function* () {
|
||
|
let existingContent = yield this.app.vault.adapter.read(filePath);
|
||
|
if (existingContent.length > 0) {
|
||
|
existingContent = existingContent + "\r\r";
|
||
|
}
|
||
|
yield this.app.vault.adapter.write(filePath, existingContent + note2);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
var PDFAnnotationPluginSetting = class {
|
||
|
constructor() {
|
||
|
this.useFolderNames = true;
|
||
|
this.sortByTopic = true;
|
||
|
}
|
||
|
};
|
||
|
var PDFAnnotationPluginSettingTab = class extends import_obsidian.PluginSettingTab {
|
||
|
constructor(app, plugin) {
|
||
|
super(app, plugin);
|
||
|
this.plugin = plugin;
|
||
|
}
|
||
|
display() {
|
||
|
const { containerEl } = this;
|
||
|
containerEl.empty();
|
||
|
new import_obsidian.Setting(containerEl).setName("Use Folder Name").setDesc("If enabled, uses the PDF's folder name (instead of the PDF-Filename) for sorting").addToggle((toggle) => toggle.setValue(this.plugin.settings.useFolderNames).onChange((value) => {
|
||
|
this.plugin.settings.useFolderNames = value;
|
||
|
this.plugin.saveData(this.plugin.settings);
|
||
|
}));
|
||
|
new import_obsidian.Setting(containerEl).setName("Sort by Topic").setDesc("If enabled, uses the notes first line as Topic for primary sorting").addToggle((toggle) => toggle.setValue(this.plugin.settings.sortByTopic).onChange((value) => {
|
||
|
this.plugin.settings.sortByTopic = value;
|
||
|
this.plugin.saveData(this.plugin.settings);
|
||
|
}));
|
||
|
}
|
||
|
};
|