# Omnisearch와 구글 연동을 위한 개선된 Userscript

Omnisearch와 구글 검색창 연동하는 기능을 사용하시다보면 레이아웃이 깨지는 경우가 있습니다.

아래 스크립트는 해당 내용과 디자인 요소를 조금 개선한 커맨드스페이스 버전입니다.

![Image](https://upload.cafenono.com/image/slashpagePost/20250804/121000_tvMOjgGMqIIVTkdoWh?q=80&s=1280x180&t=outside&f=webp)

Tampermonkey에 가셔서 새로운 스크립트로 추가하시고 사용하시면 됩니다.

![Image](https://upload.cafenono.com/image/slashpagePost/20250804/120936_1Ck2s6CU2HHeY34cMC?q=80&s=1280x180&t=outside&f=webp)

혹 아직 설치가 안되어있으신 분들은 패스트캠퍼스 강의의 Part 2_Chapter 6-1을 확인하시거나 아래 링크를 참고해주세요.

[Inject Omnisearch results into your search engine - Omnisearch - Obsidian Publish](https://publish.obsidian.md/omnisearch/Inject+Omnisearch+results+into+your+search+engine)

준비가 되었다면 아래의 Userscript를 복사해서 사용하세요. 두 가지 버전이 있습니다.

![Image](https://upload.cafenono.com/image/slashpagePost/20250804/120952_BSSNsHRRy7orvZKvrm?q=80&s=1280x180&t=outside&f=webp)

v1

![Image](https://upload.cafenono.com/image/slashpagePost/20250804/214310_rGB49C11WgeXUstmtH?q=80&s=1280x180&t=outside&f=webp)

v2

## 초기 버전(v1) 스크립트

**스크립트 복사하기**

```
"use strict";
// ==UserScript==
// @name         Obsidian Omnisearch in Google CMDS v0.1
// @namespace    https://github.com/scambier/userscripts
// @downloadURL  https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js
// @updateURL    https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js
// @version      0.4.2
// @description  Injects Obsidian notes in Google search results with modern design
// @author       Simon Cambier, Modified by CMDSPACE
// @match        https://google.com/*
// @match        https://www.google.com/*
// @icon         https://obsidian.md/favicon.ico
// @require      https://code.jquery.com/jquery-3.7.1.min.js
// @require      https://raw.githubusercontent.com/sizzlemctwizzle/GM_config/master/gm_config.js
// @require      https://gist.githubusercontent.com/scambier/109932d45b7592d3decf24194008be4d/raw/9c97aa67ff9c5d56be34a55ad6c18a314e5eb548/waitForKeyElements.js
// @grant        GM.xmlHttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM.getValue
// @grant        GM.setValue
// ==/UserScript==
/* globals GM_config, jQuery, $, waitForKeyElements */
(function () {
    "use strict";
    // Google's right "sidebar" that will contain the results div
    const sidebarSelector = "#rhs";
    // The results div
    const resultsDivId = "OmnisearchObsidianResults";
    // The "loading"/"no results" label
    const loadingSpanId = "OmnisearchObsidianLoading";

    // Modern styles for the sidebar panel
    const injectStyles = () => {
        const style = document.createElement('style');
        style.textContent = `
            /* Main container styles */
            #${resultsDivId} {
                margin-top: 20px;
                margin-bottom: 20px;
                padding: 0;
                width: 100%;
                min-width: 360px;
                box-sizing: border-box;
            }

            /* Header section */
            #${resultsDivId} .obsidian-header {
                background: #7C3AED;
                color: white;
                padding: 16px 20px;
                border-radius: 12px 12px 0 0;
                display: flex;
                align-items: center;
                justify-content: space-between;
                border: 1px solid #7C3AED;
                border-bottom: none;
            }

            #${resultsDivId} .obsidian-header-title {
                display: flex;
                align-items: center;
                gap: 10px;
                font-size: 16px;
                font-weight: 600;
                color: white;
            }

            #${resultsDivId} .obsidian-header svg {
                width: 24px;
                height: 24px;
                filter: brightness(0) invert(1);
            }

            #${resultsDivId} .obsidian-settings-link {
                color: white;
                opacity: 0.9;
                font-size: 13px;
                text-decoration: none;
                transition: opacity 0.2s;
            }

            #${resultsDivId} .obsidian-settings-link:hover {
                opacity: 1;
                text-decoration: underline;
            }

            /* Content container */
            #${resultsDivId} .obsidian-content {
                background: #ffffff;
                border: 1px solid #e0e0e0;
                border-top: none;
                border-radius: 0 0 12px 12px;
                padding: 16px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.05);
            }

            /* Result items */
            #${resultsDivId} [data-omnisearch-result] {
                background: #f8f9fa;
                border-radius: 8px;
                padding: 14px;
                margin-bottom: 12px;
                transition: all 0.2s ease;
                border: 1px solid transparent;
                cursor: pointer;
            }

            #${resultsDivId} [data-omnisearch-result]:last-child {
                margin-bottom: 0;
            }

            #${resultsDivId} [data-omnisearch-result]:hover {
                background: #ffffff;
                border-color: #dadce0;
                transform: translateX(-2px);
                box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            }

            /* Result title */
            #${resultsDivId} .LC20lb {
                color: #1a73e8;
                font-size: 15px;
                font-weight: 500;
                line-height: 1.4;
                margin-bottom: 6px;
                display: block;
                text-decoration: none;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

            #${resultsDivId} a:hover .LC20lb {
                text-decoration: underline;
            }

            /* Meta information */
            #${resultsDivId} .result-meta {
                display: flex;
                align-items: center;
                gap: 6px;
                margin-bottom: 8px;
            }

            #${resultsDivId} .result-meta svg {
                width: 14px;
                height: 14px;
            }

            #${resultsDivId} .VuuXrf {
                color: #7C3AED;
                font-size: 12px;
                font-weight: 500;
            }

            #${resultsDivId} .dyjrff {
                color: #80868b;
                font-size: 12px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                max-width: 100%;
                display: block;
            }

            /* Excerpt text */
            #${resultsDivId} .VwiC3b {
                color: #4d5156;
                font-size: 13px;
                line-height: 1.5;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
                overflow: hidden;
            }

            /* Loading state */
            #${resultsDivId} #${loadingSpanId} {
                display: block;
                text-align: center;
                color: #5f6368;
                padding: 20px;
                font-size: 14px;
            }

            /* Error state */
            #${resultsDivId} .error-message {
                color: #d93025;
                padding: 16px;
                text-align: center;
                font-size: 14px;
            }

            #${resultsDivId} .error-message a {
                color: #1a73e8;
                text-decoration: none;
            }

            #${resultsDivId} .error-message a:hover {
                text-decoration: underline;
            }

            /* Dark mode support */
            @media (prefers-color-scheme: dark) {
                #${resultsDivId} .obsidian-header {
                    background: #6B2EC5;
                    color: white;
                    border-color: #6B2EC5;
                }

                #${resultsDivId} .obsidian-settings-link {
                    color: white;
                    opacity: 0.9;
                }

                #${resultsDivId} .obsidian-settings-link:hover {
                    opacity: 1;
                }

                #${resultsDivId} .obsidian-content {
                    background: #202124;
                    border-color: #3c4043;
                }

                #${resultsDivId} [data-omnisearch-result] {
                    background: #303134;
                }

                #${resultsDivId} [data-omnisearch-result]:hover {
                    background: #3c4043;
                    border-color: #5f6368;
                }

                #${resultsDivId} .LC20lb {
                    color: #8ab4f8;
                }

                #${resultsDivId} .VuuXrf {
                    color: #9974F8;
                }

                #${resultsDivId} .dyjrff {
                    color: #9aa0a6;
                }

                #${resultsDivId} .VwiC3b {
                    color: #bdc1c6;
                }

                #${resultsDivId} #${loadingSpanId} {
                    color: #9aa0a6;
                }
            }

            /* Responsive adjustments */
            @media (max-width: 1200px) {
                #${resultsDivId} .obsidian-header {
                    padding: 14px 16px;
                }

                #${resultsDivId} .obsidian-header-title {
                    font-size: 15px;
                }

                #${resultsDivId} .obsidian-content {
                    padding: 12px;
                }
            }
        `;
        document.head.appendChild(style);
    };

    // The `new GM_config()` syntax is not recognized by the TS compiler
    // @ts-ignore
    const gmc = new GM_config({
        id: "ObsidianOmnisearchGoogle",
        title: "Omnisearch in Google - Configuration",
        fields: {
            port: {
                label: "HTTP Port",
                type: "text",
                default: "51361",
            },
            nbResults: {
                label: "Number of results to display",
                type: "int",
                default: 3,
            },
        },
        events: {
            save: () => {
                location.reload();
            },
            init: () => { },
        },
    });

    // Promise resolves when initialization completes
    const onInit = (config) => new Promise((resolve) => {
        let isInit = () => setTimeout(() => (config.isInit ? resolve() : isInit()), 0);
        isInit();
    });

    // Obsidian logo
    const logo = `<svg height="1em" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 256 256">
<style>
.purple { fill: #7C3AED; }
@media (prefers-color-scheme: dark) { .purple { fill: #9974F8; } }
</style>
<path class="purple" d="M94.82 149.44c6.53-1.94 17.13-4.9 29.26-5.71a102.97 102.97 0 0 1-7.64-48.84c1.63-16.51 7.54-30.38 13.25-42.1l3.47-7.14 4.48-9.18c2.35-5 4.08-9.38 4.9-13.56.81-4.07.81-7.64-.2-11.11-1.03-3.47-3.07-7.14-7.15-11.21a17.02 17.02 0 0 0-15.8 3.77l-52.81 47.5a17.12 17.12 0 0 0-5.5 10.2l-4.5 30.18a149.26 149.26 0 0 1 38.24 57.2ZM54.45 106l-1.02 3.06-27.94 62.2a17.33 17.33 0 0 0 3.27 18.96l43.94 45.16a88.7 88.7 0 0 0 8.97-88.5A139.47 139.47 0 0 0 54.45 106Z"/><path class="purple" d="m82.9 240.79 2.34.2c8.26.2 22.33 1.02 33.64 3.06 9.28 1.73 27.73 6.83 42.82 11.21 11.52 3.47 23.45-5.8 25.08-17.73 1.23-8.67 3.57-18.46 7.75-27.53a94.81 94.81 0 0 0-25.9-40.99 56.48 56.48 0 0 0-29.56-13.35 96.55 96.55 0 0 0-40.99 4.79 98.89 98.89 0 0 1-15.29 80.34h.1Z"/><path class="purple" d="M201.87 197.76a574.87 574.87 0 0 0 19.78-31.6 8.67 8.67 0 0 0-.61-9.48 185.58 185.58 0 0 1-21.82-35.9c-5.91-14.16-6.73-36.08-6.83-46.69 0-4.07-1.22-8.05-3.77-11.21l-34.16-43.33c0 1.94-.4 3.87-.81 5.81a76.42 76.42 0 0 1-5.71 15.9l-4.7 9.8-3.36 6.72a111.95 111.95 0 0 0-12.03 38.23 93.9 93.9 0 0 0 8.67 47.92 67.9 67.9 0 0 1 39.56 16.52 99.4 99.4 0 0 1 25.8 37.31Z"/></svg>
`;

    function omnisearch() {
        const port = gmc.get("port");
        const nbResults = gmc.get("nbResults");

        // Extract the ?q= part of the URL with URLSearchParams
        const params = new URLSearchParams(window.location.search);
        const query = params.get("q");
        if (!query)
            return;

        injectLoadingLabel();

        GM.xmlHttpRequest({
            method: "GET",
            url: `http://localhost:${port}/search?q=${query}`,
            headers: {
                "Content-Type": "application/json",
            },
            onload: function (res) {
                const data = JSON.parse(res.response);
                removeLoadingLabel(data.length > 0);

                // Keep the x first results
                data.splice(nbResults);

                const resultsContainer = $(`#${resultsDivId} .obsidian-content`);

                // Delete all existing data-omnisearch-result
                $("[data-omnisearch-result]").remove();

                // Inject results
                for (const item of data) {
                    const url = `obsidian://open?vault=${encodeURIComponent(item.vault)}&file=${encodeURIComponent(item.path)}`;
                    const element = $(`
                        <div data-omnisearch-result>
                            <a href="${url}" style="text-decoration: none; color: inherit;">
                                <h3 class="LC20lb">${item.basename}</h3>
                                <div class="result-meta">
                                    ${logo}
                                    <span class="VuuXrf">Obsidian</span>
                                </div>
                                <div class="dyjrff">${item.path}</div>
                                <div class="VwiC3b">
                                    ${item.excerpt.replaceAll("<br />", " ").replaceAll("<br>", " ")}
                                </div>
                            </a>
                        </div>
                    `);
                    resultsContainer.append(element);
                }
            },
            onerror: function (res) {
                console.log("Omnisearch error", res);
                const span = $("#" + loadingSpanId)[0];
                if (span) {
                    span.parentElement.innerHTML = `
                        <div class="error-message">
                            Error: Obsidian is not running or the Omnisearch server is not enabled.
                            <br /><a href="obsidian://open">Open Obsidian</a>
                        </div>
                    `;
                }
            },
        });
    }

    function injectTitle() {
        const id = "OmnisearchObsidianConfig";
        if (!$("#" + id)[0]) {
            const header = $(`
                <div class="obsidian-header">
                    <div class="obsidian-header-title">
                        ${logo}
                        <span>Omnisearch Results</span>
                    </div>
                    <a id="${id}" class="obsidian-settings-link" href="#">Settings</a>
                </div>
            `);
            $(`#${resultsDivId}`).prepend(header);

            $(document).on("click", "#" + id, function (e) {
                e.preventDefault();
                gmc.open();
            });
        }
    }

    function injectResultsContainer() {
        const resultsDiv = $(`
            <div id="${resultsDivId}">
                <div class="obsidian-content"></div>
            </div>
        `);
        $(sidebarSelector).append(resultsDiv); // append instead of prepend to put at bottom
    }

    function injectLoadingLabel() {
        if (!$("#" + loadingSpanId)[0]) {
            const label = $(`<span id="${loadingSpanId}">Loading Obsidian results...</span>`);
            $(`#${resultsDivId} .obsidian-content`).append(label);
        }
    }

    function removeLoadingLabel(foundResults = true) {
        if (foundResults) {
            $("#" + loadingSpanId).remove();
        } else {
            $("#" + loadingSpanId).text("No results found in Obsidian");
        }
    }

    console.log("Loading Omnisearch injector CMDS v0.1");

    let init = onInit(gmc);
    init.then(() => {
        // Inject styles
        injectStyles();

        // Make sure the results container is there
        if (!$(sidebarSelector)[0]) {
            // Create sidebar with proper width if it doesn't exist
            $("#rcnt").append('<div id="rhs" style="min-width: 400px; flex-shrink: 0;"></div>');
        }

        injectResultsContainer();
        injectTitle();
        omnisearch(); // Make an initial call

        console.log("Loaded Omnisearch injector CMDS v0.1");

        // Keep the results at the bottom of sidebar
        waitForKeyElements(sidebarSelector, () => {
            // Move to bottom if other elements are added
            const omnisearchDiv = $(`#${resultsDivId}`);
            if (omnisearchDiv.next().length > 0) {
                omnisearchDiv.appendTo(sidebarSelector);
            }
        });
    });
})();
```

이제는 여러 가지 레이아웃 상황에서도 깨지지 않고 잘 보입니다.

![Image](https://upload.cafenono.com/image/slashpagePost/20250804/121221_NBXfSbcVywBrMrmlzG?q=80&s=1280x180&t=outside&f=webp)

## 임영록님 수정 버전(v2) 스크립트

**스크립트 복사하기**

```
"use strict";
// ==UserScript==
// @name         Obsidian Omnisearch in Google CMDS v0.1 - Custom
// @namespace    https://github.com/scambier/userscripts
// @downloadURL  https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js
// @updateURL    https://github.com/scambier/userscripts/raw/master/dist/obsidian-omnisearch-google.user.js
// @version      0.4.2-custom
// @description  Injects Obsidian notes in Google search results with modern design - Custom version with dark header and no logos
// @author       Simon Cambier, Modified by CMDSPACE, Customized for user
// @match        https://google.com/*
// @match        https://www.google.com/*
// @icon         https://obsidian.md/favicon.ico
// @require      https://code.jquery.com/jquery-3.7.1.min.js
// @require      https://raw.githubusercontent.com/sizzlemctwizzle/GM_config/master/gm_config.js
// @require      https://gist.githubusercontent.com/scambier/109932d45b7592d3decf24194008be4d/raw/9c97aa67ff9c5d56be34a55ad6c18a314e5eb548/waitForKeyElements.js
// @grant        GM.xmlHttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM.getValue
// @grant        GM.setValue
// ==/UserScript==
/* globals GM_config, jQuery, $, waitForKeyElements */
(function () {
    "use strict";
    // Google's right "sidebar" that will contain the results div
    const sidebarSelector = "#rhs";
    // The results div
    const resultsDivId = "OmnisearchObsidianResults";
    // The "loading"/"no results" label
    const loadingSpanId = "OmnisearchObsidianLoading";

    // Modern styles for the sidebar panel - CUSTOMIZED VERSION
    const injectStyles = () => {
        const style = document.createElement('style');
        style.textContent = `
            /* Main container styles */
            #${resultsDivId} {
                margin-top: 20px;
                margin-bottom: 20px;
                padding: 0;
                width: 100%;
                min-width: 360px;
                box-sizing: border-box;
            }

            /* Header section - CUSTOMIZED: Light blue background without border */
            #${resultsDivId} .obsidian-header {
                background: #F2F6FF;
                color: #1B0CAB;
                padding: 16px 20px;
                border-radius: 20px 20px 0 0;
                display: flex;
                align-items: center;
                justify-content: space-between;
                border: none;
            }

            #${resultsDivId} .obsidian-header-title {
                display: flex;
                align-items: center;
                gap: 10px;
                font-size: 16px;
                font-weight: normal;
                color: #1B0CAB;
            }

            /* Logo in header */
            #${resultsDivId} .obsidian-header svg {
                width: 20px;
                height: 20px;
            }

            #${resultsDivId} .obsidian-settings-link {
                color: #1B0CAB;
                opacity: 0.7;
                font-size: 13px;
                text-decoration: none;
                transition: opacity 0.2s;
            }

            #${resultsDivId} .obsidian-settings-link:hover {
                opacity: 1;
                color: #1B0CAB;
                text-decoration: underline;
            }

            /* Content container */
            #${resultsDivId} .obsidian-content {
                background: #F2F6FF;
                border: none;
                border-top: none;
                border-radius: 0 0 20px 20px;
                padding: 8px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.05);
            }

            /* Result items */
            #${resultsDivId} [data-omnisearch-result] {
                background: #ffffff;
                border-radius: 8px;
                padding: 14px;
                margin-bottom: 12px;
                transition: all 0.2s ease;
                border: none;
                cursor: pointer;
            }

            #${resultsDivId} [data-omnisearch-result]:last-child {
                margin-bottom: 0;
            }

            #${resultsDivId} [data-omnisearch-result]:hover {
                background: #ffffff;
                transform: translateX(-2px);
                box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            }

            /* Result title - CUSTOMIZED: Smaller font size and reduced margin */
            #${resultsDivId} .LC20lb {
                color: #1B0CAB;
                font-size: 12px;
                font-weight: 500;
                line-height: 1.4;
                margin-bottom: 3px;
                display: block;
                text-decoration: none;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

            #${resultsDivId} a:hover .LC20lb {
                text-decoration: underline;
            }

            /* Meta information - CUSTOMIZED: Hide logos */
            #${resultsDivId} .result-meta {
                display: flex;
                align-items: center;
                gap: 6px;
                margin-bottom: 8px;
            }

            /* CUSTOMIZED: Hide all logos in result items */
            #${resultsDivId} .result-meta svg {
                display: none !important;
            }

            #${resultsDivId} .VuuXrf {
                color: #374151;
                font-size: 12px;
                font-weight: 500;
            }

            #${resultsDivId} .dyjrff {
                color: #80868b;
                font-size: 12px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                max-width: 100%;
                display: block;
            }

            /* Excerpt text - CUSTOMIZED: Highlight search terms, 4 lines */
            #${resultsDivId} .VwiC3b {
                color: #4d5156;
                font-size: 13px;
                line-height: 1.5;
                display: -webkit-box;
                -webkit-line-clamp: 4;
                -webkit-box-orient: vertical;
                overflow: hidden;
                margin-bottom: 8px;
                font-weight: 500;
            }

            /* Search term highlighting */
            #${resultsDivId} .search-highlight {
                font-weight: bold;
                background: rgba(255, 255, 0, 0.2);
                padding: 1px 2px;
                border-radius: 2px;
            }

            /* Loading state */
            #${resultsDivId} #${loadingSpanId} {
                display: block;
                text-align: center;
                color: #5f6368;
                padding: 20px;
                font-size: 14px;
            }

            /* Error state */
            #${resultsDivId} .error-message {
                color: #d93025;
                padding: 16px;
                text-align: center;
                font-size: 14px;
            }

            #${resultsDivId} .error-message a {
                color: #1a73e8;
                text-decoration: none;
            }

            #${resultsDivId} .error-message a:hover {
                text-decoration: underline;
            }

            /* Dark mode support - CUSTOMIZED: Unified color scheme */
            @media (prefers-color-scheme: dark) {
                /* Main container - no border */
                #${resultsDivId} {
                    border: none;
                    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
                }

                /* Header - Unified color */
                #${resultsDivId} .obsidian-header {
                    background: #2C303D;
                    color: #e2e8f0;
                    border: none;
                }

                #${resultsDivId} .obsidian-header-title {
                    color: #e2e8f0;
                }

                #${resultsDivId} .obsidian-settings-link {
                    color: #e2e8f0;
                    opacity: 0.7;
                }

                #${resultsDivId} .obsidian-settings-link:hover {
                    color: #e2e8f0;
                    opacity: 1;
                }

                /* Content container - Unified color */
                #${resultsDivId} .obsidian-content {
                    background: #2C303D;
                    border: none;
                }

                /* Individual result items - Unified color with subtle distinction */
                #${resultsDivId} [data-omnisearch-result] {
                    background: #2C303D;
                    border-bottom: 1px solid rgba(255, 255, 255, 0.03);
                }

                #${resultsDivId} [data-omnisearch-result]:last-child {
                    border-bottom: none;
                }

                #${resultsDivId} [data-omnisearch-result]:hover {
                    background: #363A47;
                    transform: translateX(-2px);
                    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
                }

                /* Text colors */
                #${resultsDivId} .LC20lb {
                    color: #9974F8;
                }

                #${resultsDivId} .VuuXrf {
                    color: #a0aec0;
                }

                #${resultsDivId} .dyjrff {
                    color: #9aa0a6;
                }

                #${resultsDivId} .VwiC3b {
                    color: #bdc1c6;
                }

                #${resultsDivId} #${loadingSpanId} {
                    color: #9aa0a6;
                }

                /* Search highlighting in dark mode */
                #${resultsDivId} .search-highlight {
                    background: rgba(153, 116, 248, 0.3);
                    color: #e2e8f0;
                }
            }

            /* Responsive adjustments */
            @media (max-width: 1200px) {
                #${resultsDivId} .obsidian-header {
                    padding: 14px 16px;
                }

                #${resultsDivId} .obsidian-header-title {
                    font-size: 15px;
                }

                #${resultsDivId} .obsidian-content {
                    padding: 12px;
                }
            }
        `;
        document.head.appendChild(style);
    };

    // The `new GM_config()` syntax is not recognized by the TS compiler
    // @ts-ignore
    const gmc = new GM_config({
        id: "ObsidianOmnisearchGoogle",
        title: "Omnisearch in Google - Configuration",
        fields: {
            port: {
                label: "HTTP Port",
                type: "text",
                default: "51361",
            },
            nbResults: {
                label: "Number of results to display",
                type: "int",
                default: 3,
            },
        },
        events: {
            save: () => {
                location.reload();
            },
            init: () => { },
        },
    });

    // Promise resolves when initialization completes
    const onInit = (config) => new Promise((resolve) => {
        let isInit = () => setTimeout(() => (config.isInit ? resolve() : isInit()), 0);
        isInit();
    });

    // Obsidian logo SVG
    const logo = `<svg height="1em" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 256 256">
<style>
.purple { fill: #1B0CAB; }
@media (prefers-color-scheme: dark) { .purple { fill: #9974F8; } }
</style>
<path class="purple" d="M94.82 149.44c6.53-1.94 17.13-4.9 29.26-5.71a102.97 102.97 0 0 1-7.64-48.84c1.63-16.51 7.54-30.38 13.25-42.1l3.47-7.14 4.48-9.18c2.35-5 4.08-9.38 4.9-13.56.81-4.07.81-7.64-.2-11.11-1.03-3.47-3.07-7.14-7.15-11.21a17.02 17.02 0 0 0-15.8 3.77l-52.81 47.5a17.12 17.12 0 0 0-5.5 10.2l-4.5 30.18a149.26 149.26 0 0 1 38.24 57.2ZM54.45 106l-1.02 3.06-27.94 62.2a17.33 17.33 0 0 0 3.27 18.96l43.94 45.16a88.7 88.7 0 0 0 8.97-88.5A139.47 139.47 0 0 0 54.45 106Z"/><path class="purple" d="m82.9 240.79 2.34.2c8.26.2 22.33 1.02 33.64 3.06 9.28 1.73 27.73 6.83 42.82 11.21 11.52 3.47 23.45-5.8 25.08-17.73 1.23-8.67 3.57-18.46 7.75-27.53a94.81 94.81 0 0 0-25.9-40.99 56.48 56.48 0 0 0-29.56-13.35 96.55 96.55 0 0 0-40.99 4.79 98.89 98.89 0 0 1-15.29 80.34h.1Z"/><path class="purple" d="M201.87 197.76a574.87 574.87 0 0 0 19.78-31.6 8.67 8.67 0 0 0-.61-9.48 185.58 185.58 0 0 1-21.82-35.9c-5.91-14.16-6.73-36.08-6.83-46.69 0-4.07-1.22-8.05-3.77-11.21l-34.16-43.33c0 1.94-.4 3.87-.81 5.81a76.42 76.42 0 0 1-5.71 15.9l-4.7 9.8-3.36 6.72a111.95 111.95 0 0 0-12.03 38.23 93.9 93.9 0 0 0 8.67 47.92 67.9 67.9 0 0 1 39.56 16.52 99.4 99.4 0 0 1 25.8 37.31Z"/></svg>`;

    function omnisearch() {
        const port = gmc.get("port");
        const nbResults = gmc.get("nbResults");

        // Extract the ?q= part of the URL with URLSearchParams
        const params = new URLSearchParams(window.location.search);
        const query = params.get("q");
        if (!query)
            return;

        injectLoadingLabel();

        GM.xmlHttpRequest({
            method: "GET",
            url: `http://localhost:${port}/search?q=${query}`,
            headers: {
                "Content-Type": "application/json",
            },
            onload: function (res) {
                const data = JSON.parse(res.response);
                removeLoadingLabel(data.length > 0);

                // Keep the x first results
                data.splice(nbResults);

                const resultsContainer = $(`#${resultsDivId} .obsidian-content`);

                // Delete all existing data-omnisearch-result
                $("[data-omnisearch-result]").remove();

                // Inject results - CUSTOMIZED: New order and search highlighting
                for (const item of data) {
                    const url = `obsidian://open?vault=${encodeURIComponent(item.vault)}&file=${encodeURIComponent(item.path)}`;
                    
                    // Highlight search terms in excerpt
                    let highlightedExcerpt = item.excerpt.replaceAll("<br />", " ").replaceAll("<br>", " ");
                    if (query) {
                        const queryTerms = query.split(' ').filter(term => term.length > 1);
                        queryTerms.forEach(term => {
                            const regex = new RegExp(`(${term})`, 'gi');
                            highlightedExcerpt = highlightedExcerpt.replace(regex, '<span class="search-highlight">$1</span>');
                        });
                    }
                    
                    const element = $(`
                        <div data-omnisearch-result>
                            <a href="${url}" style="text-decoration: none; color: inherit;">
                                <div class="VwiC3b">
                                    ${highlightedExcerpt}
                                </div>
                                <h3 class="LC20lb">${item.basename}</h3>
                                <div class="dyjrff">${item.path}</div>
                            </a>
                        </div>
                    `);
                    resultsContainer.append(element);
                }
            },
            onerror: function (res) {
                console.log("Omnisearch error", res);
                const span = $("#" + loadingSpanId)[0];
                if (span) {
                    span.parentElement.innerHTML = `
                        <div class="error-message">
                            Error: Obsidian is not running or the Omnisearch server is not enabled.
                            <br /><a href="obsidian://open">Open Obsidian</a>
                        </div>
                    `;
                }
            },
        });
    }

    function injectTitle() {
        const id = "OmnisearchObsidianConfig";
        if (!$("#" + id)[0]) {
            // CUSTOMIZED: Header with logo
            const header = $(`
                <div class="obsidian-header">
                    <div class="obsidian-header-title">
                        ${logo}
                        <span>Omnisearch Results</span>
                    </div>
                    <a id="${id}" class="obsidian-settings-link" href="#">Settings</a>
                </div>
            `);
            $(`#${resultsDivId}`).prepend(header);

            $(document).on("click", "#" + id, function (e) {
                e.preventDefault();
                gmc.open();
            });
        }
    }

    function injectResultsContainer() {
        const resultsDiv = $(`
            <div id="${resultsDivId}">
                <div class="obsidian-content"></div>
            </div>
        `);
        $(sidebarSelector).append(resultsDiv); // append instead of prepend to put at bottom
    }

    function injectLoadingLabel() {
        if (!$("#" + loadingSpanId)[0]) {
            const label = $(`<span id="${loadingSpanId}">Loading Obsidian results...</span>`);
            $(`#${resultsDivId} .obsidian-content`).append(label);
        }
    }

    function removeLoadingLabel(foundResults = true) {
        if (foundResults) {
            $("#" + loadingSpanId).remove();
        } else {
            $("#" + loadingSpanId).text("No results found in Obsidian");
        }
    }

    console.log("Loading Omnisearch injector CMDS v0.1 - Custom version");

    let init = onInit(gmc);
    init.then(() => {
        // Inject styles
        injectStyles();

        // Make sure the results container is there
        if (!$(sidebarSelector)[0]) {
            // Create sidebar with proper width if it doesn't exist
            $("#rcnt").append('<div id="rhs" style="min-width: 400px; flex-shrink: 0;"></div>');
        }

        injectResultsContainer();
        injectTitle();
        omnisearch(); // Make an initial call

        console.log("Loaded Omnisearch injector CMDS v0.1 - Custom version");

        // Keep the results at the bottom of sidebar
        waitForKeyElements(sidebarSelector, () => {
            // Move to bottom if other elements are added
            const omnisearchDiv = $(`#${resultsDivId}`);
            if (omnisearchDiv.next().length > 0) {
                omnisearchDiv.appendTo(sidebarSelector);
            }
        });
    });
})();

```

For the site tree, see the [root Markdown](https://slashpage.com/cmds-class.md).
