You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/** Readwise SYNC */letACCESS_TOKEN="XXX";// if not changed here, script will prompt for it.letBASE_URL="https://readwise.io/api/v2/";/** * General purpose readwise request method. * Make a readwise request of type 'method' at the specified url with the provided data * * @param {String} method http method: GET, POST, PUT, PATCH, DELETE * @param {String} url request url * @param {Object} params data parameters * @return {Promise} */functionreadwiseRequest(method,url,params){returnPromise.resolve($.ajax({type: method,url: url,contentType: 'application/json',beforeSend: function(xhr){xhr.setRequestHeader('Authorization','Token '+ACCESS_TOKEN);},data: params}));}/** * Retrieve all of the available results of type 'resource'. * * @param {String} resource [Readwise resource to retrieve. ie. books, highlights] * @param {Object} params [Data object containing request parameters] * @return {Array} Collection of results where the type 'resource' */asyncfunctiongetAllResults(resource,params){letresults=[];leturl=BASE_URL+resource+"/";letcomplete=false;letnum_tries=0;letmax_tries=10;while(!complete&&num_tries<max_tries){num_tries+=1;try{letresponse=awaitreadwiseRequest('GET',url,params);console.debug('Response:',response);if(response.results!=null){results.push(...response.results);}if(response.next==null){console.debug("All done.");complete=true;}else{console.debug("More to get...");url=response.next;params=null;// Params are already in the next url;}}catch(error){console.log('Error:',error);}}returnresults;}/** * Build a map of highlights where the key is the book id and the value is a mashup of the book details and the highlights for that book. * * @return {Object} The map of books with their highlights */asyncfunctiongetAllHighlightsByBook(){letbooks=awaitgetAllResults("books",{"page_size": 1000,"num_highlights__gt": 0,"updated__gt": bookListUpdated});lethighlights=awaitgetAllResults("highlights",{"page_size": 1000,"updated__gt": bookListUpdated});lethighlightsByBook={};// build map by book idbooks.forEach((book)=>{book.highlights=[];highlightsByBook[book.id]=book;});// inject highlights into the corresponding book (or article, tweet, etc.)highlights.forEach((highlight)=>{if(!highlightsByBook[highlight.book_id]){highlightsByBook[highlight.book_id]={highlights: []};}highlightsByBook[highlight.book_id].highlights.unshift(highlight);});returnhighlightsByBook;}/** * Retrieve the updated books and highlights since the last time we checked. * * @param {DateTime} lastUpdatedDate Retrieve updates since this date. Example: "2020-11-20T05:45:48.143797Z" * @return {Object} The map of books with their highlights *//* // Haven't tested this yet...function getUpdatedHighlightsByBook(lastUpdatedDate) { let books = await getAllResults("books", {"page_size": 1000, "num_highlights__gt": 0, "updated__gt": lastUpdatedDate}); let highlights = await getAllResults("highlights", {"page_size": 1000, "updated__gt": lastUpdatedDate}); // build map by book books.forEach((book) => { book.highlights = []; highlightsByBook[book.id] = book; }); // fill in highlights by book highlights.forEach((highlight) => { highlightsByBook[highlight.book_id].highlights.unshift(highlight)} ); return highlightsByBook;}*//*function findReadwiseBullet() { // Maybe a top level readwise bullet for metadata, like the last time we checked?}*/asyncfunctionupdateBookInWF(existingBookID,book){lethighlightArray=[]lethighlightsList=WF.getItemById(existingBookID).getChildren()// Create an array of the highlights that exist already for this book within WF// We're going to use this array to check for existing highlights we need to updatehighlightsList.forEach(function(highlight){highlightID=highlight.data.note.split("Note ID: ")[1];highlightUpdated=highlight.data.note.split("Highlighted: ")[1];highlightUpdated=highlightUpdated.split(" | ")[0];highlightLocation=highlight.data.note.split("Location: ")[1];highlightLocation=parseInt(highlightLocation.split(" | ")[0]);arr={wfID: highlight.data.id,wfName: highlight.data.name,wfNote: highlight.data.note,highlightID: highlightID,highlightedDate: highlightUpdated,location: highlightLocation}highlightArray.push(arr)});if(book.author){book.author=book.author.replaceAll(',','#');book.author=book.author.replaceAll(' ','_')book.author=book.author.replaceAll('.','')book.author=book.author.replaceAll('#',' #')}book.updated=newDate(book.updated)wfBook=WF.getItemById(existingBookID)oldBookCount++letitemNotes=[];if(book.author){if(book.author.startsWith("@")){// Leave Twitter authors aloneitemNotes.push(book.author);}else{itemNotes.push("#"+book.author);}}itemNotes.push("Notes: "+book.num_highlights);itemNotes.push("Updated: "+book.updated.toDateString());itemNotes.push("Resource ID: "+book.id);WF.setItemNote(wfBook,itemNotes.join(" | "));// We're going to add any new highlights we find to this array.// When we're done, we're going to sort them all by "Location", // And use the wfMove function to rearrange them as necessary.lethighlights=wfBook.getChildren();varbookHasNotes=false;book.highlights.forEach(function(highlight){// Does this highlight exist already in the highlights already listed on this WF node?existingHighlight=highlightArray.findIndex(x=>x.highlightID==highlight.id)highlight.highlighted_at=newDate(highlight.highlighted_at)if(existingHighlight!="-1"){// This highlight exists already - just update the existing oneexistingHighlight=highlightArray.find(x=>x.highlightID==highlight.id).wfIDletwfHighlight=WF.getItemById(existingHighlight)oldHighlightCount++WF.setItemName(wfHighlight,highlight.text)itemNotes=[];if(highlight.location){itemNotes.push("Location: "+highlight.location);}else{itemNotes.push("Location: 0");}itemNotes.push("Highlighted: "+highlight.highlighted_at.toDateString());itemNotes.push("Note ID: "+highlight.id);highlight.tags=[];letnoteWords=highlight.note.split(" ");noteWords.forEach(word=>{if(word.startsWith(".")){highlight.tags.push(word.replaceAll(".","#"));}});if(highlight.tags.length>0){itemNotes.push("Tags: "+highlight.tags.join(" "));}WF.setItemNote(wfHighlight,itemNotes.join(" | "));if(highlight.note!=""){allNotes=wfHighlight.getChildren()allNotes.forEach(function(note){noteTag=WF.getItemTags(note)noteTag=noteTag[0]["tag"]if(noteTag=="#readwise_notes"){WF.setItemName(note,highlight.note+" #readwise_notes")bookHasNotes=true;}})}}else{// This highlight doesn't exist - create a new onewfHighlight=WF.createItem(WF.currentItem(),0)newHighlightCount++WF.setItemName(wfHighlight,highlight.text)itemNotes=[];if(highlight.location){itemNotes.push("Location: "+highlight.location);}else{itemNotes.push("Location: 0");}itemNotes.push("Highlighted: "+highlight.highlighted_at.toDateString());itemNotes.push("Note ID: "+highlight.id);highlight.tags=[];letnoteWords=highlight.note.split(" ");noteWords.forEach(word=>{if(word.startsWith(".")){highlight.tags.push(word.replaceAll(".","#"));noteTags.push(word.replaceAll(".","#"));}});if(highlight.tags.length>0){itemNotes.push("Tags: "+highlight.tags.join(" "));}WF.setItemNote(wfHighlight,itemNotes.join(" | "));highlights.push(wfHighlight)if(highlight.note!=""){newNote=WF.createItem(wfHighlight,highlight.location)WF.setItemName(newNote,highlight.note+" #readwise_notes")bookHasNotes=true;}}});if(bookHasNotes){WF.setItemName(wfBook,wfBook.getName().split(" #readwise_notes")[0]+" #readwise_notes")}// Credit to rawbytz (https://github.com/rawbytz/sort) for the code to sort the bulletshighlights.sort(function(a,b){a=a.getNote().split("Location: ")[1].split(" | ")[0];b=b.getNote().split("Location: ")[1].split(" | ")[0];returna-b;});WF.editGroup(()=>{highlights.forEach((highlight,i)=>{if(highlight.getPriority()!==i)WF.moveItems([highlight],wfBook,i);});});}asyncfunctionaddBookToWF(book){if(book.author){book.author=book.author.replaceAll(',','#');book.author=book.author.replaceAll(' ','_')book.author=book.author.replaceAll('.','')book.author=book.author.replaceAll('#',' #')}letwfBook=WF.createItem(WF.currentItem(),0);newBookCount++;book.updated=newDate(book.updated)if(book.source_url==null){WF.setItemName(wfBook,book.title+' #'+book.category)}else{WF.setItemName(wfBook,'<a href="'+book.source_url+'">'+book.title+'</a> #'+book.category)}letitemNotes=[];if(book.author){if(book.author.startsWith("@")){// Leave Twitter authors aloneitemNotes.push(book.author);}else{itemNotes.push("#"+book.author);}}itemNotes.push("Notes: "+book.num_highlights);itemNotes.push("Updated: "+book.updated.toDateString());itemNotes.push("Resource ID: "+book.id);WF.setItemNote(wfBook,itemNotes.join(" | "));letwfHighlights=[]varbookHasNotes=false;book.highlights.forEach((highlight)=>{highlight.highlighted_at=newDate(highlight.highlighted_at)wfHighlight=WF.createItem(WF.currentItem(),0)newHighlightCount++WF.setItemName(wfHighlight,highlight.text)itemNotes=[];if(highlight.location){itemNotes.push("Location: "+highlight.location);}else{itemNotes.push("Location: 0");}itemNotes.push("Highlighted: "+highlight.highlighted_at.toDateString());itemNotes.push("Note ID: "+highlight.id);highlight.tags=[];letnoteWords=highlight.note.split(" ");noteWords.forEach(word=>{if(word.startsWith(".")){highlight.tags.push(word.replaceAll(".","#"));noteTags.push(word.replaceAll(".","#"));}});if(highlight.tags.length>0){itemNotes.push("Tags: "+highlight.tags.join(" "));}WF.setItemNote(wfHighlight,itemNotes.join(" | "));wfHighlights.push(wfHighlight)if(highlight.note!=""){newNote=WF.createItem(wfHighlight,highlight.location)WF.setItemName(newNote,highlight.note+" #readwise_notes")bookHasNotes=true;}});if(bookHasNotes){WF.setItemName(wfBook,wfBook.getName().split(" #readwise_notes")[0]+" #readwise_notes")}// Credit to rawbytz (https://github.com/rawbytz/sort) for the code to sort the bulletswfHighlights.sort(function(a,b){a=a.getNote().split("Location: ")[1].split(" | ")[0];b=b.getNote().split("Location: ")[1].split(" | ")[0];returna-b;});WF.editGroup(()=>{wfHighlights.forEach((highlight,i)=>{if(highlight.getPriority()!==i)WF.moveItems([highlight],wfBook,i);});});WF.moveItems(wfHighlights,wfBook);}asyncfunctionaddAllHighlightsToWorkflowy(){lethighlightsByBook=awaitgetAllHighlightsByBook();letcurrentBook=0;lettotalBooks=Object.keys(highlightsByBook).length;Object.keys(highlightsByBook).forEach(book_id=>{++currentBook;letbook=highlightsByBook[book_id];console.log("("+currentBook+"/"+totalBooks+"): Adding '"+book.title+"' to WorkFlowy...");// Does this book exist already in the books already listed in this WF node?letexistingBook=bookArray.findIndex(x=>x.bookID==book.id)if(existingBook!="-1"){existingBookID=bookArray.find(x=>x.bookID==book.id).wfID;}existingBook!="-1" ? updateBookInWF(existingBookID,book) : addBookToWF(book);});consttimeElapsed=Date.now();consttoday=newDate(timeElapsed);WF.setItemNote(booksRoot,`Updated: ${today.toISOString()}...\n\nWelcome! This page stores your entire Readwise library.\n\nTIPS/TRICKS\n- Don't change any of the imported bullets\n- (Use sub-bullets instead)\n- Use the tags below to navigate\n- <a href=\"https://github.com/zackdn/wf-readwise-integration\">Reach out with questions/support!</a>\n\nSHORTCUTS\nUse these shortcuts to navigate through your library, highlights, and notes:\n#books | #articles | #supplementals | #tweets | #readwise_notes\n\n`);// TODO: Add section in description for highlight tags via user's notes/* WF.setItemNote(booksRoot, `Updated: ${today.toDateString()}...\n\nWelcome! This page stores your entire Readwise library.\n\nTIPS/TRICKS\n- Don't change any of the imported bullets\n- (Use sub-bullets instead)\n- Use the tags below to navigate\n- <a href=\"https://github.com/zackdn/wf-readwise-integration\">Reach out with questions/support!</a>\n\nSHORTCUTS\nUse these shortcuts to navigate through your library, highlights, and notes:\n#books | #articles | #supplementals | #tweets | #readwise_notes\n\nYOUR NOTE TAGS\nUse these shortcuts to find highlights you've tagged via your notes:\n${noteTags.join(" ")}`);*/console.log("Import complete!");WF.showAlertDialog(`<strong>Success!</strong><br /><br /><strong>Imported:</strong><br />- ${newBookCount} new library items<br />- ${newHighlightCount} new highlights<br /><br /><strong>Updated:</strong><br />- ${oldBookCount} existing library items<br />- ${oldHighlightCount} existing highlights`)}letnewBookCount=0letoldBookCount=0letnewHighlightCount=0letoldHighlightCount=0letbookCountImported=0letbooksRoot=WF.currentItem()// TODO: Flesh this feature out more.// It will add all the user's highlight tags via their notes on initial import, but what about when updating?// And what about de-duping highlights that are used more than once throughout the notes?letnoteTags=[]letbookListUpdated=booksRoot.getNote()if(bookListUpdated!=""){bookListUpdated=bookListUpdated.split("Updated: ")[1]bookListUpdated=bookListUpdated.split("...")[0]bookListUpdated=newDate(bookListUpdated)bookListUpdated=bookListUpdated.toISOString()}else{bookListUpdated=newDate("1980-01-01")bookListUpdated=bookListUpdated.toISOString()}letbookArray=[]letbooksList=booksRoot.getChildren()booksList.forEach(function(book){letbookID=book.data.note.split("Resource ID: ")[1]letbookUpdated=book.data.note.split("Updated: ")[1]if(bookUpdated){// no updates present on initial importbookUpdated=bookUpdated.split(" | ")[0]letarr={wfID: book.data.id,wfName: book.data.name,wfNamePlain: book.data.nameInPlainText,wfNote: book.data.note,bookID: bookID,bookUpdated: bookUpdated}bookArray.push(arr)}});if(ACCESS_TOKEN=="XXX"){ACCESS_TOKEN=prompt("Enter Readwise Access Token from https://readwise.io/access_token");}addAllHighlightsToWorkflowy()
fix some code,now it works well
The text was updated successfully, but these errors were encountered:
The original code hasn't been updated for a long time. When I used it, I mainly encountered two issues: undefined variables and incorrect highlight updates. Both problems have now been resolved.
fix some code,now it works well
The text was updated successfully, but these errors were encountered: