// ==UserScript== // @name data extraction linkedin // @namespace Violentmonkey Scripts // @match https://www.linkedin.com/* // @grant GM_getValue // @grant GM_setValue // @grant GM_getValues // @grant GM_setValues // @grant GM_listValues // @grant GM_deleteValue // @grant GM_deleteValues // @version 0.1 // @author Siarhei Siniak // @license Unlicense // @description 10/08/2024, 8:44:59 PM // @inject-into document // @require https://cdn.jsdelivr.net/npm/@violentmonkey/dom@1 // @require https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js // @noframes // ==/UserScript== class Linkedin { constructor() { this.data = new Map(); this.ui = { root: null, }; } async data_load() { let self = this; const keys = await GM_listValues(); let loaded = 0; for (let o of keys) { if (!o.startsWith('data-')) { return; } self.data.set( o.slice(5,), await GM_getValue(o) ); loaded += 1; } console.log({action: 'loaded', total: loaded}); } string_reduce (text) { return text.replaceAll(/\s+/gi, ' ').trim(); } parse_header() { let self = this; return [ $( '.scaffold-finite-scroll__content > div > .relative .update-components-header' ).map((i, o) => ({ header: o.innerText })), $( '.scaffold-finite-scroll__content > div > .relative .update-components-actor' ).map((i, o) => { let header = $(o); let teaser = $(o).parents('.relative') .parent().find('.feed-shared-update-v2__description-wrapper'); return { header: self.string_reduce(header.text()), teaser: self.string_reduce(teaser.text()), }; }) ] } async data_add (entry) { let self = this; if (self.data.has(entry.header)) { return false; } self.data.set(entry.header, { entry: entry, ts: (new Date()).valueOf(), }); await GM_setValue( 'data-' + entry.header, self.data.get(entry.header) ) console.log('saved ' + entry.header); console.log(self.data.get(entry.header)); return true; } async document_on_changed () { let self = this; let current_data = self.parse_header(); let changed = false; for (let o of current_data[0]) { let current_changed = await self.data_add(o); if (current_changed) { changed = current_changed; } } for (let o of current_data[1]) { let current_changed = await self.data_add(o); if (current_changed) { changed = current_changed; } } if (changed || (self.ui.root.length == 0 && self.data.size() > 0)) { self.display(); } } listener_add() { let self = this; return VM.observe( document.body, () => { self.document_on_changed(); } ); } display_init() { let self = this; self.ui.root = $(`<div class=online-fxreader-linkedin>`); $('head').append($('<style>').html(` div.online-fxreader-linkedin { height: 2em; overflow: scroll; z-index: 9999; position: fixed; top: 5em; background: yellow; margin-left: 1em; word-wrap: anywhere; white-space: break-spaces; margin-right: 1em; width: calc(100% - 2em); } .online-fxreader-linkedin pre { white-space: wrap; word-break: break-all; } .online-fxreader-linkedin:hover { height: 10em; } `)); $(document.body).append(self.ui.root); } display() { let self = this; let sorted_entries = Array.from(self.data.entries()).sort( (a, b) => a[1].ts - b[1].ts ); self.ui.root.empty(); let search = $('<div>').addClass('search').append( $('<input>') ).attr( 'onchange', `function() {this.setAttribute('search', this.value); console.log(this.value);}` ); self.ui.root.append(search); let entries = $('<div>').addClass('entries'); for (let o of sorted_entries.reverse()) { let raw = JSON.stringify(o[1]); let ts = (new Date(o[1].ts)); let entry = $('<div>').addClass('entry'); entry.append( $('<div>').addClass('ts').text( ts.toISOString(), ) ); entry.append( $('<div>').addClass('header').text( o[1].entry.header ) ); entry.append( $('<div>').addClass('teaser').text( o[1].entry.teaser ) ); // entry.append($('<pre>').text(raw)); entries.append(entry); } self.ui.root.append(entries); } } const l = new Linkedin(); (async () => { await l.data_load(); const disconnect = l.listener_add(); l.display_init(); })();