zotero-categorise
Version:
A command-line tool to manage Zotero collections by placing items into specific collections based on their title, description, and tags.
137 lines (126 loc) • 4.86 kB
text/typescript
import Zotero from 'zotero-lib';
export type ZoteroItem = {
key: string;
title: string;
abstractNote: string;
tags: [{ tag: string }];
collections: string[];
};
type ZoteroCollections = {
terms: { term: string; type: string }[];
collection: string;
collection_name: string;
situation: string;
}[];
function getCollectionLetters(collection: string) {
if (collection.includes('/')) {
const words = collection.split('/');
return words[words.length - 1];
}
return collection;
}
async function addItemToCollection(
item: string | ZoteroItem,
zotero: Zotero,
listCollections: ZoteroCollections,
testmode: boolean,
FinalOutput: string,
ignoretag: string[],
addtag?: string[]
) {
let result: ZoteroItem;
let itemId = typeof item === 'string' ? item : item.key;
try {
if (typeof item === 'string') {
result = await zotero.item({ key: item });
} else {
result = item;
}
for (const ignore of ignoretag) {
for (const elTag of result.tags) {
if (elTag.tag.toLowerCase() === ignore.toLowerCase()) {
FinalOutput += 'Item ' + itemId + ' has the tag "' + ignore + '" so it will be ignored' + '\n';
console.log('Item ' + itemId + ' has the tag "' + ignore + '" so it will be ignored');
return FinalOutput;
}
}
}
if (addtag?.length) {
for (const ell of addtag) {
result.tags.push({ tag: ell });
}
await zotero.update_item({
key: itemId,
json: { tags: result.tags },
verbose: false,
});
FinalOutput += 'Add tag ' + addtag + ' to item ' + itemId + '\n';
console.log('Add tag ' + addtag + ' to item ' + itemId);
}
FinalOutput += 'Get item data :' + itemId + '\n';
console.log('Get item data :' + itemId);
if (!result) throw new Error('not found');
// check if the item is already in the collection
for (const el of listCollections) {
if (!result.collections) el.situation = 'is_attachment';
else if (result.collections.includes(getCollectionLetters(el.collection))) el.situation = 'already_exist';
}
const alreadyCollections = listCollections.filter(
(item: { situation: string }) => item.situation === 'already_exist' || item.situation === 'is_attachment'
);
const alreadyCollectionsFiltered = alreadyCollections.map((item) => getCollectionLetters(item.collection));
FinalOutput +=
`Subcollections that already have the item ${itemId}: ` + JSON.stringify(alreadyCollectionsFiltered) + '\n';
console.log(`Subcollections that already have the item ${itemId}: ` + JSON.stringify(alreadyCollectionsFiltered));
// get the item data and check if it contains the terms of the sub collections
for (const element of listCollections) {
if (element.situation === 'already_exist') continue;
for (const term of element.terms) {
let searchFor: RegExp;
if (term.type === 'word') searchFor = new RegExp('\\b' + term.term + '\\b', 'i'); // \b is for word boundary
else if (term.type === 'regex') searchFor = new RegExp(term.term, 'i');
else if (term.type === 'words') {
// make the regex for the words
const parts = term.term.split('/');
const regex = parts[0] + '(?:' + parts.slice(1).join('|') + '?)';
searchFor = new RegExp('\\b' + regex + '\\b', 'i');
} else searchFor = new RegExp('\\b' + term.term + '\\b', 'i');
const resultIncludes =
searchFor.test(result.title) ||
searchFor.test(result.abstractNote) ||
(result.tags && result.tags.some((tag) => searchFor.test(tag.tag)));
if (resultIncludes) {
element.situation = 'to_add';
break;
}
}
}
} catch (error) {
console.log(`error happend when retreving ${itemId}`);
process.exit(0);
}
// get the sub collections that will have the item
const targetCollections = listCollections.filter((item: { situation: string }) => item.situation === 'to_add');
const targetCollectionsFiltered = targetCollections.map((item) => getCollectionLetters(item.collection));
FinalOutput +=
'Collections where item ' + itemId + ' will be added: ' + JSON.stringify(targetCollectionsFiltered) + '\n';
console.log('Collections where item ' + itemId + ' will be added: ' + JSON.stringify(targetCollectionsFiltered));
if (testmode) {
return FinalOutput;
}
// add the item to the sub collections
if (targetCollectionsFiltered.length) {
try {
await zotero.item({
key: itemId,
addtocollection: targetCollectionsFiltered,
verbose: false,
});
} catch (error) {
console.log(`error happend when retreving ${itemId}`);
process.exit(0);
}
}
return FinalOutput;
}
export { addItemToCollection };