windingwind / zotero-better-notes

Everything about note management. All in Zotero.
GNU Affero General Public License v3.0
4.94k stars 175 forks source link

[Feature] Export notes containing images #201

Closed davidoskky closed 1 year ago

davidoskky commented 1 year ago

Is your feature request related to a problem? Please describe. It is currently impossible to export notes which contain images.

Describe the solution you'd like The note is exported and the contained images are exported as well and linked in the md file.

Describe alternatives you've considered Remove images from Zotero notes.

windingwind commented 1 year ago

We support that. Please use the export function provided by plugin, not the one provided by Zotero. See https://zotero.yuque.com/books/share/f3fe159f-956c-4f10-ade3-c87559cacb60/palqgb#xzQuO

davidoskky commented 1 year ago

I am using the plugin exporter with these settings. The md file is not created at all unless I remove the image. Screenshot from 2022-11-02 12-01-06

windingwind commented 1 year ago

What is the plugin version and Zotero version? Could you please goto Help-Debug Output-View Output and show me the debug log?

davidoskky commented 1 year ago

I'm using the latest version of the plugin, 0.7.16 and zotero 6.0.15 Here the debug log when trying to export:

version => 6.0.15, platform => Linux x86_64, oscpu => Linux x86_64, locale => en-US, appName => Zotero, appVersion => 6.0.15, extensions => Sci-Hub Plugin for Zotero (1.4.4, extension), Zotero LibreOffice Integration (6.0.2.SA.6.0.15, extension), Zotero Tag (0.2.18, extension), Zotero Better Notes (0.7.16, extension), Better BibTex for Zotero (6.7.36, extension)

(3)(+0010149): ===>223<=== (number)

(1)(+0003206): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19

(1)(+0000000): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19

(1)(+0000001): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19

(1)(+0000000): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19

(3)(+0000036): Knowledge4Zotero: onEditorEvent export

(3)(+0001988): { "dataIn": null "dataOut": null "deferred": { "resolve": function(value) {...} "reject": function (reason) {...} "promise": { "isFulfilled": false, "isRejected": false } } }

(3)(+0000002): ===>null<=== (object)

(3)(+0002580): renderTemplateAsync: [ExportMDFileName]

(1)(+0000005): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19

(1)(+0000001): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19

(1)(+0000001): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19

(1)(+0000000): TypeError: event.target.closest is not a function @resource://zotero/note-editor/editor.js:68673:19
windingwind commented 1 year ago

Could you please share a screenshot of your note? If there are images, you could see output like

(3)(+0000030): <img alt="" data-attachment-key="HQCY6MVD" data-annotation="%7B%22attachmentURI%22%3A%22http%3A%2F%2Fzotero.org%2Fusers%2F6099279%2Fitems%2FE3YEUWM3%22%2C%22annotationKey%22%3A%22AMUL6DBR%22%2C%22color%22%3A%22%23ffd400%22%2C%22pageLabel%22%3A%224%22%2C%22position%22%3A%7B%22pageIndex%22%3A3%2C%22rects%22%3A%5B%5B46.5%2C546.5%2C550.5%2C728.5%5D%5D%7D%2C%22citationItem%22%3A%7B%22uris%22%3A%5B%22http%3A%2F%2Fzotero.org%2Fusers%2F6099279%2Fitems%2FH37M6WPF%22%5D%2C%22locator%22%3A%224%22%7D%7D" width="840" height="303">

(3)(+0000001): ----Debug Link----

(3)(+0000003): { "attachmentURI": "http://zotero.org/users/6099279/items/E3YEUWM3" "annotationKey": "AMUL6DBR" "color": "#ffd400" "pageLabel": "4" "position": { "pageIndex": 3 "rects": [ "0": [ "0": 46.5 "1": 546.5 "2": 550.5 "3": 728.5 ] ] } "citationItem": { "uris": [ "0": "http://zotero.org/users/6099279/items/H37M6WPF" ] "locator": "4" } }

(3)(+0000001): http://zotero.org/users/6099279/items/E3YEUWM3

(3)(+0000001): E3YEUWM3
davidoskky commented 1 year ago

Sure, this is the screenshot of the note with the image. It's the same whose output I've attached above and no attachment output is present nor it gets exported until I remove the image. If I remove the image the note is correctly exported, but if I add it back it stops being synchronized. Screenshot from 2022-11-10 10-53-18

windingwind commented 1 year ago

I've test on a totally new install of Zotero and plugin without login on Windows 11, Ubuntu 16.04 and Ubuntu 22.04 LTS. They seem to be OK to export either w/ or w/o images.

Any hints of the possible causes? Like write access to the directory, an incomplete Zotero installation?

Right-click on the image and try to save as... it to the same directory, see if it works as expected?

If anyone else also meets this, please let me know. Currently I cannot provide any help because the cause is unclear.

davidoskky commented 1 year ago

Oh, I didn't specify: I'm running Fedora Linux. Write access is there and Zotero is correctly installed. Right clicking correctly saves the image, the default name is image.

windingwind commented 1 year ago

Could you please select the note containing images in the library and go to Tools-Developers-Run Javascript, then paste and click Run:

var item = ZoteroPane.getSelectedItems()[0];
item.getNote();

image

Please post the result here or email me(wyzlshx@foxmail.com). This is the content of the note.

davidoskky commented 1 year ago

Sure, here you go.

```

Crystal Structure First

In virtual screening, only the most promising molecules are subjected to biostructural assays. You first have to filter out all unpromising molecules and then test the remaining ones.

HTS has a hit rate of about 1%, molecules identified in this way are generally complex and have to be optimized; moreover the chemical space is not explored exhaustively.

To solve these problems, generally you perform some molecular docking studies to filter good candidates to send to the HTS.

It’s possible to screen huge chemical spaces, in the orders of billions of molecules, by docking.

The docking is performed on fragments and fragments with high quality interactions are retained and used to identify drugs that could be good candidates for more docking.

This has been called chemical space docking, it is much quicker to exhaustively screen a full chemical space.

Fragment Based Drug Discovery (FBDD) uses the idea to sample the chemical space more efficiently by starting with smaller and less complex molecules.

  • Fragments bind in different points of the binding site
  • Broader sampling for other compounds
  • Chemical space exploration through growth

FBDD has been used successfully to develop approved drugs (sotorasib, asciminib) and numerous drug candidates. It allowed targeting targets that were previously considered undruggable.

One problem with FBDD is the reliable detection and prioritization of fragments. Screening fragments might not be a good strategy to select good ones.

What are the problems with screening targets? Probably that you throw away a lot of good ones.

Using crystal data about the binding structure is better than using experimental or calculated binding affinity. [16, 36, 37]

Proposal

They propose to screen fragments directly through X-ray crystallography. This approach is called crystal structure first.

The advantage is that you immediately know the spatial conformation of the fragment within the binding pocket. There are studies that support the idea that affinity-driven approached don’t work so well and that it’s better to model the complex in a good way.

They do not consider the binding affinity of these fragments with the target protein, because the affinity values of fragments don’t explain much about the affinity of larger molecules containing those fragments.

They used four fragments which were co-crystallized with the target and performed a fuzzy search of those on the Enamine dataset.

The resulting molecules were placed in the binding pocket anchored to the fragment and then docked.

Results

  • 106 compounds were selected for synthesis
  • 93 compounds were synthesized
  • 40 compounds had some kind of activity
  • The process required 9 weeks

The obtained molecules are novel and present a low Tanimoto similarity with existing inhibitors.

Conclusions

The results are good because all tested molecules do exploit a key interaction in the active site.

To perform this strategy, you need good experimental structural data.

The results obtained are diverse from previously existing inhibitors.

Large screenings such as this would normally require huge computational powers, but through this methodology the requirements can be 10 times less. The fragments act as a magnet for the molecules to find the right place in the active site and to attract all the molecules that might interact there while discarding the other ones.

It’s been important that they used the REAL database, because this allowed for an easy synthesis of the identified molecules.

Starting from fragments, you allow introducing molecules with many different chemotypes.

This might be further optimized through SAR-by-Space [41]

This happened using only four fragments, all of which would have been discarded by normal screening techniques.

Thus, it is important for this methodology:

  • Good crystallographic fragment
  • Enumeration of a massive chemical space
  • Efficient on-demand synthesis

Experimental

19 highly reliable crystal structures of the target were evaluated; the one with the most open binding site was used to allow the acco.modation of more ligands.

Binding activity of fragments was not identified or used in the prioritization of fragments.

The reliability of the fragments poses were calculated through HYDE affinity estimations.

Chemical space docking workflow:

  • Placement of REAL fragments in crystallographically determined positions
  • Enumeration of sublibraries using Enamine reaction knowledge
  • Template-based docking of the libraries

Fragments were searched to fuzzily match the experimental ones and all of these were docked in 10 different poses. 50 of these fragments were selected and used to enumerate libraries from Enamine database.

An average of 13,000 molecules per fragment was obtained.

Molecules are docked using the fragment that matched them as a template. Each of the crystallographic fragments averaged 2,020,658 poses of molecules.

The obtained poses were scored for post processing. The processing of the libraries of molecules took on average 6 hours. Molecules clashing with the protein or had a strained conformation determined by HYDE were filtered out, around 50-60%.

Tanimoto on Morgan fingerprints was used to evaluate the novelty of found molecules compared to known inhibitors.

```
windingwind commented 1 year ago

try to run this in the Run JS window, with note item selected:

var item = ZoteroPane.getSelectedItems()[0];
var imgKey = "PQN9A3AL"
var imgItem = await Zotero.Items.getByLibraryAndKeyAsync(
        item.libraryID,
        imgKey
      );
return [imgItem, await imgItem.getFilePathAsync()]
davidoskky commented 1 year ago

It returns this:

``` [ "0": { "key": "PQN9A3AL", "version": 7711, "itemType": "attachment", "parentItem": "KJBF5D2C", "linkMode": "embedded_image", "contentType": "image/png", "filename": "image.png", "dateAdded": "2022-11-02T10:56:06Z", "dateModified": "2022-11-02T10:56:06Z" } "1": "/home/davide/.local/share/zotero/storage/PQN9A3AL/image.png" ] ```

I checked at that location and the image is in fact stored there.

ghost commented 1 year ago

尝试运行这个在运行JS窗口,注意到项目的选择:

var item = ZoteroPane.getSelectedItems()[0];
var imgKey = "PQN9A3AL"
var imgItem = await Zotero.Items.getByLibraryAndKeyAsync(
        item.libraryID,
        imgKey
      );
return [imgItem, await imgItem.getFilePathAsync()]

在 Arch Linux (6.0.8-arch1-1)中也有这个问题,执行后面的 JS,图片放在了~/Documents/Zotero/storage/2WS5H3X6

3)(+0005326): ===>206<=== (number)

(3)(+0005514): Knowledge4Zotero: onEditorEvent export

(3)(+0001418): { "dataIn": null "dataOut": null "deferred": { "resolve": function(value) {...} "reject": function (reason) {...} "promise": { "isFulfilled": false, "isRejected": false } } }

(3)(+0000000): ===>null<=== (object)

(3)(+0004089): renderTemplateAsync: [ExportMDFileName]
windingwind commented 1 year ago

Hi, I'm not sure why images failed to be exported. Could you please check this:

  1. Try to export a note with image(s). It doesn't matter if it fails.

  2. Run this and see if the export path is valid.

    Zotero.Knowledge4Zotero.NoteExport._exportPath;
  3. If so, run this and see if the dir is created correctly.

    await Zotero.File.createDirectoryIfMissingAsync(Zotero.Knowledge4Zotero.NoteExport._exportPath);
ghost commented 1 year ago

Export still failed.

Zotero.Knowledge4Zotero.NoteExport._exportPath;

Run this, print the export path: ~/Documents/notes/50Search/attachments

await Zotero.File.createDirectoryIfMissingAsync(Zotero.Knowledge4Zotero.NoteExport._exportPath);

Run this, created correct folder.


~/Documents/notes/50Search master !6 ?12                                                                 11:54:35 ─╮
❯ ls | grep attachment                                                                                            ─╯

~/Documents/notes/50Search master !6 ?12 12:02:06 ─╮ ❯ ls | grep attachment ─╯ attachments

windingwind commented 1 year ago

Oh I see. I don't know why but it seems you have a path starts with ~. Related to a previous issue: #66 , file path in mac which is not start with / will make the export fail, and I made all paths on non-Windows platfoms to force starts with /.

Could you please try if this version works? zotero-better-notes.zip

(Install it directly and do not unzip it.)

ghost commented 1 year ago

Use this new version(direct installation without uninstalling the old version), it works good.

The new debug info during the export (use the USERID to replace the true ID):

(3)(+0021555): Knowledge4Zotero: onEditorEvent export

(3)(+0001274): { "dataIn": null "dataOut": { "embedLink": false "exportNote": false "exportMD": true "exportSubMD": false "exportAutoSync": false "exportHighlight": true "convertSquare": true "exportDocx": false "exportPDF": false "exportFreeMind": false } "deferred": { "resolve": function(value) {...} "reject": function (reason) {...} "promise": { "isFulfilled": false, "isRejected": false } } }

(3)(+0000000): { "embedLink": false "exportNote": false "exportMD": true "exportSubMD": false "exportAutoSync": false "exportHighlight": true "convertSquare": true "exportDocx": false "exportPDF": false "exportFreeMind": false }

(3)(+0002519): <img alt="" data-attachment-key="GD8HQBB8" data-annotation="%7B%22attachmentURI%22%3A%22http%3A%2F%2Fzotero.org%2Fusers%2FUSERID%2Fitems%2FYQKAGTD3%22%2C%22annotationKey%22%3A%22SUP8YZ6K%22%2C%22color%22%3A%22%23ffd400%22%2C%22pageLabel%22%3A%222%22%2C%22position%22%3A%7B%22pageIndex%22%3A1%2C%22rects%22%3A%5B%5B322.083%2C394.083%2C570.417%2C413.25%5D%5D%7D%2C%22citationItem%22%3A%7B%22uris%22%3A%5B%22http%3A%2F%2Fzotero.org%2Fusers%2FUSERID%2Fitems%2FDCSNWD9F%22%5D%2C%22locator%22%3A%222%22%7D%7D" height="32" width="414">

(3)(+0000000): ----Debug Link----

(3)(+0000001): { "attachmentURI": "http://zotero.org/users/USERID/items/YQKAGTD3" "annotationKey": "SUP8YZ6K" "color": "#ffd400" "pageLabel": "2" "position": { "pageIndex": 1 "rects": [ "0": [ "0": 322.083 "1": 394.083 "2": 570.417 "3": 413.25 ] ] } "citationItem": { "uris": [ "0": "http://zotero.org/users/USERID/items/DCSNWD9F" ] "locator": "2" } }

(3)(+0000000): http://zotero.org/users/USERID/items/YQKAGTD3

(3)(+0000000): YQKAGTD3

(3)(+0000000): <img alt="" data-attachment-key="XWIYAZ95" data-annotation="%7B%22attachmentURI%22%3A%22http%3A%2F%2Fzotero.org%2Fusers%2FUSERID%2Fitems%2FYQKAGTD3%22%2C%22annotationKey%22%3A%224EUX92EV%22%2C%22color%22%3A%22%23ffd400%22%2C%22pageLabel%22%3A%223%22%2C%22position%22%3A%7B%22pageIndex%22%3A2%2C%22rects%22%3A%5B%5B88.75%2C473.667%2C527.083%2C732.833%5D%5D%7D%2C%22citationItem%22%3A%7B%22uris%22%3A%5B%22http%3A%2F%2Fzotero.org%2Fusers%2FUSERID%2Fitems%2FDCSNWD9F%22%5D%2C%22locator%22%3A%223%22%7D%7D" height="432" width="731">

(3)(+0000000): ----Debug Link----

(3)(+0000000): { "attachmentURI": "http://zotero.org/users/USERID/items/YQKAGTD3" "annotationKey": "4EUX92EV" "color": "#ffd400" "pageLabel": "3" "position": { "pageIndex": 2 "rects": [ "0": [ "0": 88.75 "1": 473.667 "2": 527.083 "3": 732.833 ] ] } "citationItem": { "uris": [ "0": "http://zotero.org/users/USERID/items/DCSNWD9F" ] "locator": "3" } }

(3)(+0000000): http://zotero.org/users/USERID/items/YQKAGTD3

(3)(+0000000): YQKAGTD3

(3)(+0000002): { "key": "GD8HQBB8", "version": 11829, "itemType": "attachment", "parentItem": "G59NQXJ7", "linkMode": "embedded_image", "contentType": "image/png", "filename": "image.png", "dateAdded": "2022-11-15T14:39:39Z", "dateModified": "2022-11-15T14:39:39Z" }

(3)(+0000002): /home/zz/Documents/Zotero/storage/GD8HQBB8/image.png

(3)(+0000000): /home/zz/Documents/notes/50Search/attachments/GD8HQBB8.png

(3)(+0000002): attachments/GD8HQBB8.png

(3)(+0000001): { "key": "XWIYAZ95", "version": 11837, "itemType": "attachment", "parentItem": "G59NQXJ7", "linkMode": "embedded_image", "contentType": "image/png", "filename": "image.png", "dateAdded": "2022-11-16T05:05:56Z", "dateModified": "2022-11-16T05:05:56Z" }

(3)(+0000002): /home/zz/Documents/Zotero/storage/XWIYAZ95/image.png

(3)(+0000000): /home/zz/Documents/notes/50Search/attachments/XWIYAZ95.png

(3)(+0000001): attachments/XWIYAZ95.png

(3)(+0000000): DCSNWD9F

(3)(+0000000): DCSNWD9F

The path ~ is the home directory, equivalent to /home/zz only for user zz general. ~/Documents/notes/50Search/attachments = /home/zz/Documents/notes/50Search/attachments

windingwind commented 1 year ago

Glad to know. Fixed in v0.7.20

davidoskky commented 1 year ago

I confirm it's fixed in 0.7.20. Thank you very much for your great work!