Skip to content

Commit

Permalink
Fix: Address profileUrnId issue - fix #26
Browse files Browse the repository at this point in the history
 - Extracting profileUrnId from DOM was not working on some profiles; randomly grabbed *other* IDs from recommended section, etc.
 - Improve the profileUrnId getter method to use DOM as last resort, and try to use cached data as much as possible
 - Improve profileUrnId DOM match pattern
 - A little code cleanup
 - Version bump
  • Loading branch information
joshuatz committed Jul 31, 2020
1 parent f01e13c commit 55eee2a
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 20 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ When in doubt, refresh the profile page before using this tool.
## Updates:
Date | Release | Notes
--- | --- | ---
7/31/2020 | 1.4.1 | Fix: In some cases, wrong profileUrnId was extracted from current profile, which led to work history API call being ran against a *different* profile (e.g. from "recommended section", or something like that).
7/21/2020 | 1.4.0 | Fix: For vCard exports, Previous profile was getting grabbed after SPA navigation between profiles.
7/6/2020 | 1.3.0 | Fix: Incomplete work position entries for some users; LI was limiting the amount of pre-fetched data. Had to implement request paging to fix.<br/><br/>Also refactored a lot of code, improved result caching, and other tweaks.
6/18/2020 | 1.2.0 | Fix / Improve VCard export feature.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "linkedin-to-json-resume-exporter",
"version": "1.4.0",
"version": "1.4.1",
"description": "Browser tool to grab details from your open LinkedIn profile page and export to JSON Resume Schema",
"private": true,
"main": "src/main.js",
Expand Down
49 changes: 31 additions & 18 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ window.LinkedinToResumeJson = (() => {
}

/**
*
* Main parser for giant profile JSON block
* @param {LinkedinToResumeJson} instance
* @param {LiResponse} profileObj
*/
Expand Down Expand Up @@ -518,7 +518,9 @@ window.LinkedinToResumeJson = (() => {
resultSummary.localeStr = _this.preferLocale;
}
try {
// Build db object
const db = buildDbFromLiSchema(profileObj);

// Parse basics / profile
let profileGrabbed = false;
db.getValuesByKey(_liSchemaKeys.profile).forEach((profile) => {
Expand Down Expand Up @@ -869,8 +871,9 @@ window.LinkedinToResumeJson = (() => {
if (fullProfileView && typeof fullProfileView.data === 'object') {
// Try to use the same parser that I use for embedded
const profileParserResult = await parseProfileSchemaJSON(this, fullProfileView);
this.debugConsole.log(`Parse full profile via internal API, success = ${profileParserResult.parseSuccess}`);
if (profileParserResult.parseSuccess) {
this.debugConsole.log('Was able to parse full profile via internal API');
this.profileParseSummary = profileParserResult;
}
// Some sections might require additional fetches to fill missing data
if (profileParserResult.sections.work === 'incomplete') {
Expand Down Expand Up @@ -1193,11 +1196,11 @@ window.LinkedinToResumeJson = (() => {
if (_this.parseSuccess) {
if (_this.scannedPageUrl === _this.getUrlWithoutQuery() && localeStayedSame) {
// No need to reparse!
this.debugConsole.log('Skipped re-parse; page has not changed');
_this.debugConsole.log('Skipped re-parse; page has not changed');
resolve(true);
} else {
// Parse already done, but page changed (ajax)
this.debugConsole.warn('Re-parsing for new results; page has changed between scans');
_this.debugConsole.warn('Re-parsing for new results; page has changed between scans');
await _this.forceReParse(localeToUse);
resolve(true);
}
Expand All @@ -1216,7 +1219,7 @@ window.LinkedinToResumeJson = (() => {
} else {
await _this.parseViaInternalApi();
if (!_this.parseSuccess) {
await this.parseEmbeddedLiSchema();
await _this.parseEmbeddedLiSchema();
}
}
_this.scannedPageUrl = _this.getUrlWithoutQuery();
Expand Down Expand Up @@ -1431,16 +1434,35 @@ window.LinkedinToResumeJson = (() => {
* Get the internal URN ID of the active profile
* - Not needed for JSON Resume, but for Voyager calls
* - ID is also used as part of other URNs
* @param {boolean} [allowFetch] If DOM search fails, allow Voyager call to determine profile URN. Be careful about recursion...
* @param {boolean} [allowFetch] If DOM search fails, allow Voyager call to determine profile URN.
* @returns {Promise<string>} profile URN ID
*/
LinkedinToResumeJson.prototype.getProfileUrnId = async function getProfileUrnId(allowFetch = false) {
LinkedinToResumeJson.prototype.getProfileUrnId = async function getProfileUrnId(allowFetch = true) {
const profileViewUrnPatt = /urn:li:fs_profileView:(.+)$/i;

if (this.profileUrnId && this.scannedPageUrl === this.getUrlWithoutQuery()) {
return this.profileUrnId;
}

// Try to find in DOM
const urnPatt = /fsd_profile:([A-Za-z0-9-_]+)/g;
// Try to use cache
if (this.profileParseSummary && this.profileParseSummary.parseSuccess) {
const profileDb = buildDbFromLiSchema(this.profileParseSummary.profileObj);
this.profileUrnId = profileDb.tableOfContents['entityUrn'].match(profileViewUrnPatt)[1];
return this.profileUrnId;
}

const endpoint = _voyagerEndpoints.fullProfileView;
// Make a new API call to get ID - be wary of recursive calls
if (allowFetch && !endpoint.includes(`{profileUrnId}`)) {
const fullProfileView = await this.voyagerFetch(endpoint);
const profileDb = buildDbFromLiSchema(fullProfileView);
this.profileUrnId = profileDb.tableOfContents['entityUrn'].match(profileViewUrnPatt)[1];
return this.profileUrnId;
}
this.debugConsole.warn('Could not scrape profileUrnId from cache, but fetch is disallowed. Might be using a stale ID!');

// Try to find in DOM, as last resort
const urnPatt = /miniprofiles\/([A-Za-z0-9-_]+)/g;
const matches = document.body.innerHTML.match(urnPatt);
if (matches && matches.length > 1) {
// eslint-disable-next-line prettier/prettier
Expand All @@ -1449,15 +1471,6 @@ window.LinkedinToResumeJson = (() => {
return this.profileUrnId;
}

if (allowFetch) {
const fullProfileView = await this.voyagerFetch(_voyagerEndpoints.fullProfileView);
const profileDb = buildDbFromLiSchema(fullProfileView);
const profileViewUrnPatt = /urn:li:fs_profileView:(.+)$/i;
this.profileUrnId = profileDb.tableOfContents['entityUrn'].match(profileViewUrnPatt)[1];
} else {
this.debugConsole.warn('Could not scrape profileUrnId from DOM, but fetch is disallowed. Might be using a stale ID!');
}

return this.profileUrnId;
};

Expand Down

0 comments on commit 55eee2a

Please sign in to comment.