diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5f677db --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +patches/enhancer-query-selector-fix.patch text eol=lf +patches/enhancer-urlhelper-fix.patch text eol=lf +patches/notion-check-relativeurl.patch text eol=crlf +patches/enhancer-paths.patch text eol=tf diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..98e06e0 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,112 @@ +name: Port sources and Package + +on: + push: + branches: [main] + + release: + types: [created] + + workflow_dispatch: + inputs: {} + +env: + NOTION_VERSION: 2.0.16 + NOTION_DOWNLOAD_HASH: 9f72284086cda3977f7f569dff3974d5 + NOTION_ENHANCER_COMMIT: b248ffa3bac393f267a4600d4e951aba8565f31e + +jobs: + make-vanilla-sources: + name: Make vanilla sources + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Download official Windows build + run: scripts/download-exe.sh + - name: Extract sources from Windows Build + run: scripts/extract-src.sh + - name: Zips sources dir with 7z + working-directory: build + run: 7z a vanilla-src.zip vanilla-src + - name: Save vanilla sources as artifact + uses: actions/upload-artifact@v2 + with: + name: vanilla-sources + path: build/vanilla-src.zip + make-enhanced-sources: + name: Make enhanced sources + needs: [make-vanilla-sources] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Retrieve saved vanilla sources + uses: actions/download-artifact@v2 + with: + name: vanilla-sources + path: build/vanilla-src.zip + - name: Unzips sources with 7z + working-directory: build + run: 7z x vanilla-src.zip + - name: Enhance extracted sources + run: scripts/enhance-src.sh + - name: Zips sources dir with 7z + working-directory: build + run: 7z a enhanced-src.zip enhanced-src + - name: Save enhanced sources as artifact + uses: actions/upload-artifact@v2 + with: + name: enhanced-sources + path: build/enhanced-src.zip + build-app: + name: Build electron app + needs: [make-vanilla-sources, make-enhanced-sources] + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + edition: [vanilla, enhanced] + exclude: + - os: windows-latest + edition: vanilla + - os: macos-latest + edition: vanilla + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 14 + - name: Retrieve saved sources + uses: actions/download-artifact@v2 + with: + name: '${{ matrix.edition }}-sources' + path: sources.zip + - name: Unzips sources with 7z + run: 7z x sources.zip + - name: Install build packages + working-directory: ${{ matrix.edition }}-src + run: npm install electron@11 electron-builder --save-dev + - name: Run electron-builder (Windows) + working-directory: ${{ matrix.edition }}-src + if: matrix.os == 'windows-latest' + run: node_modules/.bin/electron-builder --windows nsis + - name: Run electron-builder (Linux) + working-directory: ${{ matrix.edition }}-src + if: matrix.os == 'ubuntu-latest' + run: node_modules/.bin/electron-builder --linux deb rpm AppImage pacman + - name: Run electron-builder (MacOS) + working-directory: ${{ matrix.edition }}-src + if: matrix.os == 'macos-latest' + run: node_modules/.bin/electron-builder --macos dmg + cleanup: + if: ${{ false }} + name: Cleanup artifacts + continue-on-error: true + needs: [build-app] + strategy: + matrix: + edition: [vanilla, enhanced] + runs-on: ubuntu-latest + steps: + - uses: geekyeggo/delete-artifact@v1 + with: + name: '${{ matrix.edition }}-sources' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..c951f07 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +14.17.1 \ No newline at end of file diff --git a/common-electron-builder.yaml b/common-electron-builder.yaml new file mode 100644 index 0000000..97c04f9 --- /dev/null +++ b/common-electron-builder.yaml @@ -0,0 +1,76 @@ +files: + - "build/" + - "package.json" + - "dev-app-update.yml" + - "!node_modules/jschardet/" + +extraResources: + - from: "python/dist/main" + to: "python-rpc" + filter: + - "**/*" + - "ThirdPartyNotices.txt" + - "data" + - "i18n" + - "node_modules/jschardet/" + +protocols: + - name: "BatchExplorer protocol" + role: "Viewer" + schemes: + - notion + - ms-batch-explorer + +# Mac OS configuration +mac: + icon: "src/app/assets/images/icon.icns" + +# Config for OSX dmg +dmg: + contents: + - x: 130 + y: 220 + - x: 410 + y: 220 + type: "link" + path: "/Applications" + +# Windows configuration +win: + icon: "src/app/assets/images/icon.ico" + target: + - "zip" + - "nsis" + +# Config for the windows installer +nsis: + oneClick: true + perMachine: true + +# Linux configuration +linux: + category: Development + target: + - "AppImage" + - "deb" + - "rpm" + +deb: + depends: + # --- Default START + - gconf2 + - gconf-service + - libnotify4 + - libappindicator1 + - libxtst6 + - libnss3 + # --- Default END + - libsecret-1-0 # This is needed for keytar on linux + +directories: + buildResources: "resources" + output: "release" + +publish: + provider: "generic" + url: "https://batchlabsdist.blob.core.windows.net/releases" \ No newline at end of file diff --git a/patches/enhancer-paths.patch b/patches/enhancer-paths.patch new file mode 100644 index 0000000..f0428ec --- /dev/null +++ b/patches/enhancer-paths.patch @@ -0,0 +1,90 @@ +--- pkg/helpers.js 2021-06-21 22:20:28.538393581 +0200 ++++ pkg/helpers.js.new 2021-06-21 22:27:12.478124395 +0200 +@@ -19,72 +19,18 @@ + } + } + +-// checks if being run on the windows subsystem for linux: +-// used to modify windows notion app. +-const is_wsl = +- process.platform === 'linux' && +- os.release().toLowerCase().includes('microsoft'), +- // ~/.notion-enhancer absolute path. +- __data = path.resolve( +- `${ +- is_wsl +- ? (() => { +- const stdout = execSync('cmd.exe /c echo %systemdrive%%homepath%', { +- encoding: 'utf8', +- }), +- drive = stdout[0]; +- return `/mnt/${drive.toLowerCase()}${stdout +- .replace(/\\/g, '/') +- .slice(2) +- .trim()}`; +- })() +- : os.homedir() +- }/.notion-enhancer` +- ); ++// patched: stripped unnecessary logic for WSL ++// ~/.notion-enhancer absolute path. ++const __data = `${os.homedir()}/.notion-enhancer` + +-// transform a wsl filepath to its relative windows filepath if necessary. ++// patched: stripped unnecessary logic for WSL + function realpath(hack_path) { +- if (!is_wsl) return hack_path.replace(/\\/g, '/'); +- hack_path = fs.realpathSync(hack_path); +- if (hack_path.startsWith('/mnt/')) { +- hack_path = `${hack_path[5].toUpperCase()}:${hack_path.slice(6)}`; +- } else hack_path = `//wsl$/${process.env.WSL_DISTRO_NAME}${hack_path}`; +- return hack_path; ++ return hack_path.replace(/\\/g, '/'); + } + +-// gets possible system notion app filepaths. ++// patched: stripped unnecessary logic for runtime path detection + function getNotionResources() { +- let folder = ''; +- switch (process.platform) { +- case 'darwin': +- folder = '/Applications/Notion.app/Contents/Resources'; +- break; +- case 'win32': +- folder = process.env.LOCALAPPDATA + '\\Programs\\Notion\\resources'; +- break; +- case 'linux': +- if (is_wsl) { +- const stdout = execSync('cmd.exe /c echo %localappdata%', { +- encoding: 'utf8', +- }), +- drive = stdout[0]; +- folder = `/mnt/${drive.toLowerCase()}${stdout +- .replace(/\\/g, '/') +- .slice(2) +- .trim()}/Programs/Notion/resources`; +- } else { +- for (let loc of [ +- '/usr/lib/notion-desktop/resources', // https://github.com/davidbailey00/notion-deb-builder/ +- '/opt/notion-app', // https://aur.archlinux.org/packages/notion-app/ +- '/opt/notion', // https://github.com/jaredallard/notion-app +- ]) { +- if (fs.pathExistsSync(loc)) folder = loc; +- } +- } +- } +- if (!folder) +- throw new EnhancerError('nothing found: platform not supported.'); +- return folder; ++ return path.resolve(__dirname, '../../../'); + } + + // lists/fetches all available extensions + themes +@@ -184,7 +130,6 @@ + + module.exports = { + EnhancerError, +- is_wsl, + __data, + realpath, + getNotionResources, diff --git a/patches/enhancer-query-selector-fix.patch b/patches/enhancer-query-selector-fix.patch new file mode 100644 index 0000000..0ea020a --- /dev/null +++ b/patches/enhancer-query-selector-fix.patch @@ -0,0 +1,11 @@ +--- mods/core/client.js 2021-04-28 23:47:55.867684760 +0200 ++++ mods/core/client.js.new 2021-04-28 23:58:26.305652911 +0200 +@@ -105,7 +105,7 @@ + if ( + !document.querySelector('.notion-frame') || + !document.querySelector('.notion-sidebar') || +- !document.querySelector('.notion-topbar') ++ !document.querySelector('.notion-topbar > div[style*="display: flex"]') + ) + return; + clearInterval(attempt_interval); diff --git a/patches/enhancer-urlhelper-fix.patch b/patches/enhancer-urlhelper-fix.patch new file mode 100644 index 0000000..0a33160 --- /dev/null +++ b/patches/enhancer-urlhelper-fix.patch @@ -0,0 +1,13 @@ +--- mods/core/createWindow.js 2021-04-28 23:47:55.867684760 +0200 ++++ mods/core/createWindow.js.new 2021-04-28 23:59:51.891726201 +0200 +@@ -16,6 +16,10 @@ + // createWindow = __exports.createWindow, + path = require('path'), + helpers = require('../../pkg/helpers.js'); ++ ++ __exports.getIndexUrl = require(`${helpers ++ .getNotionResources() ++ .replace(/\\/g, '/')}/app/helpers/urlHelpers.js`).getIndexUrl; + + __exports.createWindow = function (relativeUrl, focused_window) { + if (!relativeUrl) relativeUrl = ''; diff --git a/patches/notion-check-relativeurl.patch b/patches/notion-check-relativeurl.patch new file mode 100644 index 0000000..a071175 --- /dev/null +++ b/patches/notion-check-relativeurl.patch @@ -0,0 +1,11 @@ +--- main/main.js 2021-04-28 23:47:55.854352025 +0200 ++++ main/main.js.new 2021-04-28 23:55:08.414711920 +0200 +@@ -170,7 +170,7 @@ + notionIpc.sendMainToNotionWindow(targetWindow, "notion:navigate-to-url", relativeUrl); + targetWindow.focus(); + } +- else { ++ else if (relativeUrl) { + const win = createWindow_1.createWindow(relativeUrl); + win.focus(); + } diff --git a/scripts/_utils.sh b/scripts/_utils.sh new file mode 100755 index 0000000..9ffda7c --- /dev/null +++ b/scripts/_utils.sh @@ -0,0 +1,33 @@ + +WORKSPACE_DIR=`realpath $(dirname $0)/..` + +NOTION_VERSION="${NOTION_VERSION:-2.0.16}" +NOTION_DOWNLOAD_HASH="${NOTION_DOWNLOAD_HASH:-9f72284086cda3977f7f569dff3974d5}" +NOTION_DOWNLOAD_URL="https://desktop-release.notion-static.com/Notion%20Setup%20${NOTION_VERSION}.exe" +NOTION_DOWNLOADED_NAME="Notion-${NOTION_VERSION}.exe" + +NOTION_ENHANCER_COMMIT="${NOTION_ENHANCER_COMMIT:-b248ffa3bac393f267a4600d4e951aba8565f31e}" +NOTION_ENHANCER_REPO_URL="https://github.com/notion-enhancer/notion-enhancer" + +NOTION_EXTRACTED_EXE_NAME="extracted-exe" +NOTION_EXTRACTED_APP_NAME="extracted-app" +NOTION_VANILLA_SRC_NAME="vanilla-src" +NOTION_ENHANCED_SRC_NAME="enhanced-src" +NOTION_EMBEDDED_NAME="embedded_enhancer" + +function log() { + caller=`basename "$0"` + echo "[${caller%.*}]: $@" +} + +function check-cmd() { + if ! command -v $1 > /dev/null; then + log "Missing required command dependency: $1" + exit -1 + fi +} + +function workspace-dir-pushd() { + mkdir -p "${WORKSPACE_DIR}/build" + pushd "${WORKSPACE_DIR}/build" > /dev/null +} diff --git a/scripts/download-exe.sh b/scripts/download-exe.sh new file mode 100755 index 0000000..06dccb9 --- /dev/null +++ b/scripts/download-exe.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -ex + +source `dirname $0`/_utils.sh +workspace-dir-pushd + +check-cmd curl + +if [ -f "${NOTION_DOWNLOADED_NAME}" ]; then + log "Removing already downloaded file..." + rm "${NOTION_DOWNLOADED_NAME}" +fi + +log "Downloading Notion Windows package..." +curl "${NOTION_DOWNLOAD_URL}" --output "${NOTION_DOWNLOADED_NAME}" + +log "Verifying downloaded package checksum..." +echo "${NOTION_DOWNLOAD_HASH} ${NOTION_DOWNLOADED_NAME}" | md5sum --check - + +popd > /dev/null diff --git a/scripts/enhance-src.sh b/scripts/enhance-src.sh new file mode 100755 index 0000000..78afa7d --- /dev/null +++ b/scripts/enhance-src.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -ex + +source `dirname $0`/_utils.sh +workspace-dir-pushd + +check-cmd jq +check-cmd git +check-cmd convert + +if [ -d "${NOTION_ENHANCED_SRC_NAME}" ]; then + log "Removing already enhanced sources..." + rm -rf "${NOTION_ENHANCED_SRC_NAME}" +fi + +cp -r "${NOTION_VANILLA_SRC_NAME}" "${NOTION_ENHANCED_SRC_NAME}" + +pushd "${NOTION_ENHANCED_SRC_NAME}" > /dev/null + +log "Patching package.json for being enhanced" +PATCHED_PACKAGE_JSON=$(jq ' + .dependencies += {"keyboardevent-from-electron-accelerator": "^2.0.0"} | + .name="notion-app-enhanced"' package.json) +echo "${PATCHED_PACKAGE_JSON}" > package.json + +log "Applying additional notion patches..." +patch -p0 --binary < "${WORKSPACE_DIR}/patches/notion-check-relativeurl.patch" + +log "Fetching enhancer sources..." + +git clone "${NOTION_ENHANCER_REPO_URL}" "${NOTION_EMBEDDED_NAME}" + +pushd "${NOTION_EMBEDDED_NAME}" > /dev/null +git reset "${NOTION_ENHANCER_COMMIT}" --hard +rm -rf .git + +log "Applying enhancer patches..." +patch -p0 --binary < "${WORKSPACE_DIR}/patches/enhancer-query-selector-fix.patch" +patch -p0 --binary < "${WORKSPACE_DIR}/patches/enhancer-urlhelper-fix.patch" +patch -p0 --binary < "${WORKSPACE_DIR}/patches/enhancer-paths.patch" +popd > /dev/null + +log "Injecting enhancer loader..." +for patchable_file in $(find . -type d \( -path ./${NOTION_EMBEDDED_NAME} -o -path ./node_modules \) -prune -false -o -name '*.js'); do + patchable_file_dir=$(dirname $patchable_file) + rel_loader_path=$(realpath ${NOTION_EMBEDDED_NAME}/pkg/loader.js --relative-to $patchable_file_dir) + [ $patchable_file_dir = '.' ] && rel_loader_path="./"$rel_loader_path + rel_loader_require="require('${rel_loader_path}')(__filename, exports);" + + echo -e "\n\n" >> $patchable_file + echo "//notion-enhancer" >> $patchable_file + echo "${rel_loader_require}" >> $patchable_file +done + +log "Swapping the original icon with the enhancer's one..." +mv icon.icns original_icon.icns +mv icon.png original_icon.png +mv icon.ico original_icon.ico +#enhancer_icon_path="mods/core/icons/mac+linux.png" +enhancer_icon_path="mods/core/icons/windows.ico" +cp "${NOTION_EMBEDDED_NAME}/${enhancer_icon_path}" icon.ico +convert "icon.ico[0]" "icon.png" + +popd > /dev/null diff --git a/scripts/extract-src.sh b/scripts/extract-src.sh new file mode 100755 index 0000000..8192a87 --- /dev/null +++ b/scripts/extract-src.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -ex + +source `dirname $0`/_utils.sh +workspace-dir-pushd + +check-cmd 7z +check-cmd jq +check-cmd convert + +if [ -d "${NOTION_EXTRACTED_EXE_NAME}" ]; then + log "Removing already extracted exe contents..." + rm -r "${NOTION_EXTRACTED_EXE_NAME}" +fi + +log "Extracting Windows installer contents..." +7z x -y "${NOTION_DOWNLOADED_NAME}" \ + -o"${NOTION_EXTRACTED_EXE_NAME}" > /dev/null + +if [ -d "${NOTION_EXTRACTED_APP_NAME}" ]; then + log "Removing already extracted app contents..." + rm -r "${NOTION_EXTRACTED_APP_NAME}" +fi + +log "Extracting Windows app resources..." +7z x -y "${NOTION_EXTRACTED_EXE_NAME}/\$PLUGINSDIR/app-64.7z" \ + -o"${NOTION_EXTRACTED_APP_NAME}" > /dev/null + +if [ -d "${NOTION_VANILLA_SRC_NAME}" ]; then + log "Removing already extracted app sources..." + rm -r "${NOTION_VANILLA_SRC_NAME}" +fi + +log "Copying original app resources..." +mkdir -p "${NOTION_VANILLA_SRC_NAME}" +cp -r "${NOTION_EXTRACTED_APP_NAME}/resources/app/"* "${NOTION_VANILLA_SRC_NAME}" + +pushd "${NOTION_VANILLA_SRC_NAME}" > /dev/null + +log "Patching source for fixes..." +sed -i 's|process.platform === "win32"|process.platform !== "darwin"|g' main/main.js +PATCHED_PACKAGE_JSON=$(jq ' + .dependencies.cld="2.7.0" | + .name="notion-app"' package.json) +echo "${PATCHED_PACKAGE_JSON}" > package.json + +log "Removing package node_modules..." +rm -r node_modules + +log "Converting app icon to png..." +convert "icon.ico[0]" "icon.png" + +popd > /dev/null