google appscript based webapp is not giving results. frontend is receiving null from the backend, even though the backend is returning valid results [duplicate]

I want to create a simple web app to search a database.
google app-script based webapp is not giving results.
The issue is that the frontend is receiving null from the backend, even though the backend is returning valid results (as shown in the Execution Log).
i have tried with hard coded result, that it is showing, but not result from the search.
My index.html file is as below.

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style>
      body { font-family: Arial, sans-serif; margin: 20px; }
      input, select, button { margin: 5px; padding: 10px; }
      table { width: 100%; border-collapse: collapse; margin-top: 20px; }
      th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
      th { background-color: #f2f2f2; }
    </style>
  </head>
  <body>
    <h1>Book Search</h1>
    <input type="text" id="searchTerm" placeholder="Enter search term">
    <select id="category">
      <option value="">Select a category</option> <!-- Default option -->
    </select>
    <button onclick="search()">Search</button>

    <table id="results">
      <thead>
        <tr>
          <th>Timestamp</th>
          <th>Date of Addition</th>
          <th>Acc No</th>
          <th>Book Title</th>
          <th>Author</th>
          <th>Book Type</th>
          <th>Volume</th>
          <th>Publication House</th>
          <th>Publication Year</th>
          <th>Pages</th>
          <th>Bill No</th>
          <th>Bill Date</th>
          <th>Price</th>
          <th>Condition</th>
          <th>Subject</th>
          <th>Almirah</th>
          <th>Rack</th>
        </tr>
      </thead>
      <tbody>
      </tbody>
    </table>

    <script>
      // Load categories into dropdown
      google.script.run
        .withSuccessHandler((categories) => {
          console.log('Categories from backend:', categories); // Log categories for debugging
          const dropdown = document.getElementById('category');

          if (!categories || categories.length === 0) {
            console.error('No categories found or categories are empty');
            return;
          }

          // Add categories to the dropdown
          categories.forEach(([category]) => {
            const option = document.createElement('option');
            option.value = category;
            option.text = category;
            dropdown.appendChild(option);
          });
        })
        .withFailureHandler((error) => {
          console.error('Error fetching categories:', error);
          alert('An error occurred while loading categories. Please check the console for details.');
        })
        .getCategories();

      // Perform search
      function search() {
        const searchTerm = document.getElementById('searchTerm').value;
        const category = document.getElementById('category').value;

        if (!searchTerm || !category) {
          alert('Please enter a search term and select a category.');
          return;
        }

        console.log('Sending request to backend with:', { searchTerm, category }); // Log request data

        google.script.run
          .withSuccessHandler((results) => {
            console.log('Results from backend:', results); // Log results for debugging
            const tbody = document.querySelector('#results tbody');
            tbody.innerHTML = ''; // Clear previous results

            if (!results || results.length === 0) {
              tbody.innerHTML = '<tr><td colspan="17">No results found.</td></tr>';
              return;
            }

            // Ensure results is an array
            if (Array.isArray(results)) {
              results.forEach(row => {
                const tr = document.createElement('tr');
                row.forEach(cell => {
                  const td = document.createElement('td');
                  td.textContent = cell;
                  tr.appendChild(td);
                });
                tbody.appendChild(tr);
              });
            } else {
              console.error('Invalid results format:', results);
              tbody.innerHTML = '<tr><td colspan="17">Invalid results format.</td></tr>';
            }
          })
          .withFailureHandler((error) => {
            console.error('Error:', error);
            alert('An error occurred. Please check the console for details.');
          })
          .searchBooks(category, searchTerm);
      }
    </script>
  </body>
</html>

My code.gs file is as below

function doGet() {
  return HtmlService.createHtmlOutputFromFile('index');
}

function getCategories() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Category');
  if (!sheet) {
    console.error('Category sheet not found');
    return [];
  }
  const data = sheet.getRange(2, 1, sheet.getLastRow() - 1, 2).getValues(); // Skip header row
  console.log('Categories:', data); // Log categories for debugging
  return data;
}

function searchBooks(category, searchTerm) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const categorySheet = ss.getSheetByName('Category');
  const booksSheet = ss.getSheetByName('Books');

  if (!categorySheet || !booksSheet) {
    console.error('Sheets not found');
    return []; // Return an empty array if sheets are not found
  }

  // Get column number for the selected category
  const categories = categorySheet.getRange(2, 1, categorySheet.getLastRow() - 1, 2).getValues();
  const columnNumber = categories.find(([cat]) => cat === category)?.[1];

  if (!columnNumber) {
    console.error('Invalid category:', category);
    return []; // Return an empty array if category is invalid
  }

  // Search the Books sheet
  const booksData = booksSheet.getRange(2, 1, booksSheet.getLastRow() - 1, booksSheet.getLastColumn()).getValues();
  const results = booksData
    .filter(row => row[columnNumber - 1].toString().toLowerCase().includes(searchTerm.toLowerCase()))
    .map(row => row.map(cell => cell || '')); // Replace null/undefined with empty strings

  console.log('Search results:', results); // Log results for debugging
  return results;
}

THIS IS MY GOOGLE SHEET FILE
https://docs.google.com/spreadsheets/d/1jBkZie2i3Xnt1DGYL0ChAZmSgbseq_nE6V7FzqLLJ3g/edit?usp=sharing

Healthkit framework in Windows? [closed]

Is it possible to develop a native iOS app using HealthKit on Windows?
I want to create a native app that fetches data from HealthKit, but I only have a Windows PC and an iPhone. I understand that Xcode is required for iOS development, but I am looking for any possible workarounds.

What I have tried:
-Looking into Expo Go, but it doesn’t support HealthKit.
-Checking cloud Mac services, but I prefer a free solution.
-Is there any way to build and test an iOS app with HealthKit without a Mac?

Charts.js tooltip position not working properly on Zoom In

I have created a React Application.I was working on dasboard page, in which i have used chart.js for displaying data in Barchart,Pie Chart.All things was working fine,but when i try to zoom in the browser, the tooltip of the Bachart not showing properly, means when i move the cursor to the bar tooltip didn’t get displayed.but when i move the cursor to a specific point it get displayed.I am getting recursion error when i try to use the postioning function inside tooltip.
Do u have any suggestions for me . It will be a great help for me .

tooltip: {
backgroundColor: “rgba(0, 0, 0, 0.7)”,
titleFont: {
size: 12,
weight: “bold”,
},
bodyFont: {
size: 10,
},
footerFont: {
size: 8,
},
callbacks: {
label: function (tooltipItem) {
return ${tooltipItem.label}: ${tooltipItem.raw};
},
},
position: function (context) {
try {
if (!context || !context.tooltip || !context.chart) {
return { x: 0, y: 0 };
}

          const { chart, tooltip } = context;

          // Ensure canvas exists before getting bounding box
          if (!chart.canvas) {
            return { x: 0, y: 0 };
          }

          // Get bounding rectangle of the chart canvas
          const canvasRect = chart.canvas.getBoundingClientRect();
          const zoomLevel = zoomLevelRef?.current || 1;

          // Prevent recursion by avoiding unnecessary updates
          const newX = (tooltip.caretX || 0) * zoomLevel + canvasRect.left;
          const newY = (tooltip.caretY || 0) * zoomLevel + canvasRect.top;

          if (Number.isNaN(newX) || Number.isNaN(newY)) {
            return { x: 0, y: 0 }; // Return safe fallback position
          }

          return { x: Math.round(newX), y: Math.round(newY) };
        } catch (error) {
          console.error("Tooltip positioning error:", error);
          return { x: 0, y: 0 }; // Fallback to prevent crash
        }
      },
    },

Getting Cannot use import statement outside a module when running test in jest

I am trying to run the following test in jest:

import request from "supertest";
import app from '../../src/app';
import QuestionService from "../../src/api/services/questionService"; 
import { mockDBQuestions } from './get-question-utils';

// Mock the QuestionService function properly
jest.mock("../../src/api/services/questionService", () => ({
    __esModule: true, // Ensure ESM compatibility
    default: {
        getQuestionsAndAnswers: jest.fn(),
    },
}));

describe("fetchAllQuestionsController", () => {
    it("should return questions with status 200", async () => {
        // Mock DB response
        const mockQuestions = mockDBQuestions;

        jest.spyOn(QuestionService, "getQuestionsAndAnswers").mockResolvedValue(mockQuestions);

        const response = await request(app).get("/questions/fetchQuestions").query({ questionType: "Onboarding" });

        expect(response.status).toBe(200);
        expect(response.body).toEqual(mockQuestions);
        expect(QuestionService.getQuestionsAndAnswers).toHaveBeenCalledWith("Onboarding");
    });

    it("should return empty set with status 200", async () => {
        jest.spyOn(QuestionService, "getQuestionsAndAnswers").mockResolvedValue([]);

        const response = await request(app).get("/questions/fetchQuestions").query({ questionType: "abcdef" });

        expect(response.status).toBe(200);
        expect(response.body).toEqual([]);
        expect(QuestionService.getQuestionsAndAnswers).toHaveBeenCalledWith("Onboarding");
    });

    it("should return status 500 on error", async () => {
        jest.spyOn(QuestionService, "getQuestionsAndAnswers").mockRejectedValue(new Error("Internal Server Error"));

        const response = await request(app).get("/questions/fetchQuestions").query({ questionType: "Onboarding" });

        expect(response.status).toBe(500);
        expect(QuestionService.getQuestionsAndAnswers).toHaveBeenCalledWith("Onboarding");
    });
});

This is my babel.config.js:

export default {
  presets: [
      ['@babel/preset-env', { targets: { node: 'current' }, modules: false}],
      '@babel/preset-typescript',
  ],
  plugins: [
      ['@babel/plugin-proposal-decorators', { legacy: true }],
      ['@babel/plugin-transform-flow-strip-types'],
      ['@babel/plugin-proposal-class-properties', { loose: true }],
  ],
};

This is my test.config.js file :

export default {
    preset: 'ts-jest/presets/default-esm',
    testEnvironment: 'node',
    testMatch: ['**/tests/**/*.test.ts'],
    moduleFileExtensions: ['ts', 'js', 'json', 'node', 'mjs', 'cjs'],
    transform: {
        '^.+\.ts$': [
            'ts-jest',
            {
                useESM: true, // Ensuring Jest treats TS as ESM
            },
        ],
    },
    extensionsToTreatAsEsm: ['.ts'],
    transformIgnorePatterns: ['node_modules/(?!supertest/)'], // Transpile 'supertest' if needed
    globals: {
        'ts-jest': {
            tsconfig: 'tsconfig.json',
            useESM: true,
        },
    },
    setupFilesAfterEnv: ['./jest.setup.ts'], // Ensure Jest setup is working
};

This is my package.json file starting :

  "name": "backendtemplate",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "jest": {
    "transform": {}
  },

and this is my tsconfig.json:

{
    "compilerOptions": {
        "target": "ESNext",
        "module": "ESNext",
        "outDir": "./dist",
        "rootDir": "./src",
        "esModuleInterop": true,
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "useDefineForClassFields": false,
        "allowSyntheticDefaultImports": true,
        "forceConsistentCasingInFileNames": true,
        "noEmit": true,
        "allowImportingTsExtensions": true,
        "strict": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "skipLibCheck": true,
        "sourceMap": true,
        "removeComments": true,
        "noEmitOnError": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noImplicitReturns": true,
        "types": ["node"],
        "strictPropertyInitialization": false,
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules", "dist"]
}

I am getting the following error when trying to run my test case:

(dev-serve/api) [dynodatingappbe:user_profile_edit_api] % npm run test                         

> [email protected] test
> jest

 PASS  tests/UserProfileEditModule/update-user-profile.test.ts
 PASS  tests/server.test.ts
 FAIL  tests/QuestionModule/get-questions.test.ts
  ● Test suite failed to run

    Jest encountered an unexpected token

    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

    By default "node_modules" folder is ignored by transformers.

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
     • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/configuration
    For information about custom transformations, see:
    https://jestjs.io/docs/code-transformation

    Details:

    /Users/rahul.negi/personal/Dyno/dynodatingappbe/tests/QuestionModule/get-questions.test.ts:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import request from "supertest";
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14)

Test Suites: 1 failed, 2 passed, 3 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.143 s, estimated 1 s
Ran all test suites.

What am I missing which is causing this issue?

So far I have tried the following methods :

  1. Tried to rename babel.config.js to babel.config.cjs
  2. Tried to Ensure that "module": "ESNext" and "moduleResolution": "node" are correctly set in tsconfig.json
  3. Tried adding transformIgnorePatterns: ['node_modules/(?!supertest/)'], in test.config.js file.

midtrans payment gateway stop default redirect

I am integrating Snap Midtrans into my application, using Laravel as the backend and React as the frontend. The application follows a single-page app (SPA) concept, meaning page transitions are handled by react-router/react-router-dom without reloading, refreshing, or redirecting the web page.

Currently, I am adding the Snap feature to the application, but I am facing difficulties because every time a user completes the payment method selection, Snap redirects the application to the URL specified in the Midtrans Dashboard. This redirection disrupts my application’s state. However, I have already used JS callbacks, specifically the onPending option. As stated in the documentation:

If Merchant use snap.js JS callbacks (onPending, onSuccess, onError), those JS callbacks will be triggered instead of redirection.

I have tried removing the Finish URL from the dashboard and overriding the Finish URL through the backend, but Snap still redirects (this time to the application’s main frontend page). I have also checked the documentation, but there seems to be no option to disable the redirection to the Finish URL.

I would appreciate any guidance. Thank you.

How to add a memo/note button for each item in a React JSON Schema Form array?

I’m building a form with React JSON Schema Form (RJSF) that contains arrays of items. I need to add a custom feature: a button next to each array item that, when clicked, displays an input field where users can enter a note/memo for that specific item.

For example, in my Authorization schema (which renders as an array of text areas for JWT tokens), I want each token field to have an associated “Add Note” button. When clicked, it should show an input field where users can add a memo about that specific token.

Here’s my current code:

import { RJSFSchema, UiSchema } from '@rjsf/utils';
import { Form as RjsfForm } from '@rjsf/antd';
import validator from '@rjsf/validator-ajv8';
import { App, Button, Tabs } from 'antd';
import { JSX, useEffect, useState } from 'react';

export interface AuthSchema {
  id: string;
  title?: string;
  schema: RJSFSchema;
  uiSchema?: UiSchema;
}

export interface RegisterExtractorOptions {
  authSchema?: AuthSchema[];
}

// Auth schema definition
const auth = {
  authSchema: [
    {
      id: 'authorization',
      title: 'Authorization',
      schema: {
        type: 'array',
        items: {
          type: 'string',
          pattern: '^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$',
        },
      },
      uiSchema: {
        items: {
          'ui:widget': 'textarea',
        },
      },
    },
    {
      id: 'account',
      title: 'Account',
      schema: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            username: {
              type: 'string',
              title: 'Username',
              minLength: 5,
              pattern: '^[a-z0-9]+$',
            },
            password: {
              type: 'string',
              title: 'Password',
              minLength: 8,
            },
          },
          required: ['username', 'password'],
        },
      },
      uiSchema: {
        items: {
          password: {
            'ui:widget': 'password',
          },
        },
      },
    },
  ]
};

interface AccountTabProps {
  source: SourceInfoClient;
}

function AccountTab({ source }: AccountTabProps): JSX.Element {
  return (
    <Tabs
      tabPosition={'right'}
      items={source.authSchema!.map((auth) => {
        return {
          key: auth.id,
          label: auth.title,
          children: <TabItem source={source} auth={auth} />,
        };
      })}
    />
  );
}

type TabItemProps = Pick<AccountTabProps, 'source'> & {
  auth: AuthSchema;
};

function TabItem({source, auth}: TabItemProps): JSX.Element{
  const [formData, setFormData] = useState();
  
  const handleSubmit = async (id: string, event: IChangeEvent): Promise<void> => {
    // save data to db
  };
  
  useEffect(() => {
    // Retrieve data from the database and set it in formData.
  }, [auth.id, source.id]);
  
  return (
    <RjsfForm
      formData={formData}
      focusOnFirstError={true}
      liveValidate={true}
      schema={auth.schema}
      uiSchema={auth.uiSchema}
      validator={validator}
      onSubmit={(e) => handleSubmit(auth.id, e)}
      showErrorList={false}
    />
  );
}

export default AccountTab;

I’m not sure how to:

  • Add a custom “Add Note” button for each array item
  • Display an input field when the button is clicked
  • Save the notes along with the form data
  • Associate each note with its specific array item

I’ve looked into custom field templates and widgets in RJSF, but I’m not sure how to implement this specific functionality. Should I modify the schema to include a note field, or is there a way to add custom UI elements outside the schema definition?

Deploy web on Render

I am trying to deploy my node web on Render service but I encountered an Error [ERR_MODULE_NOT_FOUND]: Cannot find package @vitejs/plugin-react imported from /opt/render/project/src/frontEnd/node_modules/.vite-temp/vite.config.js.timestamp-1742661308779-16638e4679c7.mjs

this issue can not find @vitejs/plugin-react but I have it in @vitejs/plugin-react”: “^4.3.4,

and this is my build command
scripts: { dev": "cross-env NODE_ENV=development nodemon backend/server.js, start": "cross-env NODE_ENV=production node backend/server.js", build": "npm install && npm install --prefix frontEnd && npm run build ---prefix frontEnd },
Project Structure

Vite project not running

I am trying to run a vite project and I am getting the error below based on the main.jsx file (which has also been attached)

import App from "./App.jsx";
import "./index.css";
import "bootstrap/dist/css/bootstrap.css";
import { Provider } from "react-redux";
import store from "./app/store.js";
import { createRoot } from "react-dom/client";

createRoot(document.getElementById("root")).render(
  <Provider store={store}>
    <App />
  </Provider>
);

Error:

Uncaught SyntaxError: The requested module ‘/node_modules/react-dom/client.js?v=21d72c5d’ does not provide an export named ‘createRoot’ (at main.jsx:6:10)

I was trying to render my React app, expecting it to showcase on the web yet that is the error that was displayed on the console

Output or log the vite rollup configuration?

When we create a vite project running npm run build will create the rollup javascript bundle.

However the command npm init vite@latest that we used to scaffold out the project does not create a rollup.config.js file.

Is there a way to output the default rollup configuration, so we can see what the settings used to create the bundle?

Why dark mode is still dependent on browsers theme?

I am trying to implement dark mode in my Next js project.

Here’s theme store

import { create } from "zustand";

export const useThemeStore = create((set) => {
  let storedTheme = localStorage.getItem("theme");

  if (!storedTheme) {
    const systemPrefersDark = window.matchMedia(
      "(prefers-color-scheme: dark)"
    ).matches;
    storedTheme = systemPrefersDark ? "dark" : "light";
    localStorage.setItem("theme", storedTheme);
    document.documentElement.classList.toggle(storedTheme);
  }


  return {
    theme: storedTheme,
    toggleTheme: () =>
      set((state: { theme: string }) => {
        const newTheme = state.theme === "light" ? "dark" : "light";
        document.documentElement.classList.toggle("dark", newTheme === "dark");
        localStorage.setItem("theme", newTheme);
        // alert("Theme changed to " + newTheme);
        return { theme: newTheme };
      }),
  };
});

Here’s my tailwind.config.ts

import type { Config } from "tailwindcss";

export default {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  darkMode: "class", // Ensures dark mode works with manual toggle
  theme: {
    extend: {
      colors: {
        background: "var(--background)",
        foreground: "var(--foreground)",
      },
    },
  },
  plugins: [],
} satisfies Config;

Here is my toggle button

 <div className="sm:absolute  flex items-center gap-4 cursor-pointer">
          <Around
            toggled={theme === "dark"}
            onToggle={toggleTheme}
            className="h-full w-full text-3xl"
            duration={750}
          />
        </div>

Everything works as intended. Effectively maintains localstorage theme variable and applies “dark” class in html.
But the real problem is toggle button does not change theme. It is still dependent on browser’s theme.

How to Customize Video Player with Quality Selection (Using Node.js & EJS)?

Can anyone help me?

I want to customize a player like this:
Example Player

I use Node.js to get an M3U8 link and then pass it to anime.ejs in the sources variable.

server.js

res.render("anime", { animeData, sources });

Data passed to anime.ejs

[

{
“url”: “https://vault-14.kwikie.ru/stream/14/03/3ce25a73788d8dbf1420232be682f39b18d11533cd81d49cdba188b73c50e51b/uwu.m3u8”,
“isM3U8”: true,
“quality”: “SubsPlease · 360p”,
“isDub”: false
},
{
“url”: “https://vault-14.kwikie.ru/stream/14/03/891c61f3d388810669a19444f69eec108993f6ccff370c536603cf0e4dc7304c/uwu.m3u8”,
“isM3U8”: true,
“quality”: “SubsPlease · 720p”,
“isDub”: false
},
{
“url”: “https://vault-14.kwikie.ru/stream/14/03/e93f7997db52cf5ab666eaea58709e501fefc3494eaea65257ca13a99f510d5f/uwu.m3u8”,
“isM3U8”: true,
“quality”: “SubsPlease · 1080p”,
“isDub”: false
},
{
“url”: “https://vault-14.kwikie.ru/stream/14/04/fbb3d13e5f2d8f578a5835eea840f3e34d3e01ae6760ac71032d40a49459a62c/uwu.m3u8”,
“isM3U8”: true,
“quality”: “Yameii · 360p eng”,
“isDub”: true
},
{
“url”: “https://vault-14.kwikie.ru/stream/14/04/e56837232369912fa78dd9117e11239ccbcd18de26bfe1ea2d02161b5dc446fb/uwu.m3u8”,
“isM3U8”: true,
“quality”: “Yameii · 720p eng”,
“isDub”: true
},
{
“url”: “https://vault-14.kwikie.ru/stream/14/04/896052169f3a63b0b052502e4ffb0b7371bcf59a72998697c73dbf8927787754/uwu.m3u8”,
“isM3U8”: true,
“quality”: “Yameii · 1080p eng”,
“isDub”: true
}
]

anime.ejs

<div class="col-lg-6 videoplayer no_variable_height">
    <video id="video-player" controls width="640" height="360"
        poster="https://myproxy.com/proxy-image?url=<%= animeData.animePoster %>">
    </video>

    <select id="quality-selector"></select> <!-- Quality selection dropdown -->
</div>

anime.ejs javascript

document.addEventListener("DOMContentLoaded", () => {
    var player = videojs("video-player", {
        controls: true,
        autoplay: false,
        preload: "auto",
        fluid: true, // Makes it responsive
        controlBar: {
            volumePanel: { inline: false }, // Show volume controls
            pictureInPictureToggle: true, // Enable PiP
            fullscreenToggle: true
        }
    });

    // Add Quality Selector Plugin
    player.qualityLevels().on("addqualitylevel", function(event) {
        var qualityLevel = event.qualityLevel;
        qualityLevel.enabled = qualityLevel.height >= 720; // Enable HD by default
    });

    // Speed Control
    player.controlBar.addChild("PlaybackRateMenuButton", {});
});

Result:
Current Result