Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ jobs:
- name: Lint files
run: bun run lint

- name: Build dependencies first
run: |
bun run workspace:core build
bun run workspace:react build

- name: Typecheck files
run: bun run typecheck

Expand All @@ -48,7 +53,7 @@ jobs:
uses: ./.github/actions/setup

- name: Build package
run: bun run prepare
run: bun run build

build-web:
runs-on: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"useIgnoreFile": false
},
"files": {
"include": ["src/**/*", "example/src/**/*"],
"include": ["src/**/*", "example/src/**/*", "packages/**/*"],
"ignoreUnknown": false,
"ignore": ["lib", "node_modules", "ios", "android"]
"ignore": ["lib", "node_modules", "ios", "android", "dist"]
},
"formatter": {
"enabled": true,
Expand Down
501 changes: 430 additions & 71 deletions bun.lock

Large diffs are not rendered by default.

29 changes: 17 additions & 12 deletions example/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
const path = require('node:path');
const { getConfig } = require('react-native-builder-bob/babel-config');
const pkg = require('../package.json');

const root = path.resolve(__dirname, '..');

module.exports = (api) => {
api.cache(true);

return getConfig(
{
presets: ['babel-preset-expo'],
},
{ root, pkg },
);
return {
presets: ['babel-preset-expo'],
plugins: [
[
'module-resolver',
{
root: ['./'],
alias: {
'react-native-youtube-bridge': '../packages/react-native-youtube-bridge/src/index',
'@react-native-youtube-bridge/core': '../packages/core/src/index',
'@react-native-youtube-bridge/react': '../packages/react/src/index',
},
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
},
],
],
};
};
356 changes: 118 additions & 238 deletions example/bun.lock

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions example/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,4 @@ function createMonorepoMetroConfig(dirname, options = {}) {
return config;
}

module.exports = createMonorepoMetroConfig(__dirname, {
packageName: 'react-native-youtube-bridge',
});
module.exports = createMonorepoMetroConfig(__dirname);
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"devDependencies": {
"@babel/core": "^7.20.0",
"react-native-builder-bob": "^0.40.12"
"babel-plugin-module-resolver": "^5.0.2"
},
"private": true
}
2 changes: 1 addition & 1 deletion example/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"extends": "expo/tsconfig.base",
"compilerOptions": {
"paths": {
"react-native-youtube-bridge": ["../src/index"],
"react-native-youtube-bridge": ["../packages/react-native-youtube-bridge/src/index"]
}
}
}
2 changes: 1 addition & 1 deletion lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pre-commit:
run: bun run lint
types:
glob: "*.{js,ts, jsx, tsx}"
run: npx tsc
run: bun run typecheck
Comment on lines 8 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix glob pattern spacing in types hook

The glob pattern "*.{js,ts, jsx, tsx}" contains spaces that will prevent matching .jsx and .tsx. Align it with the lint glob: "*.{js,ts,jsx,tsx}".

🤖 Prompt for AI Agents
In lefthook.yml at lines 8 to 9, the glob pattern for the `types` hook includes
spaces inside the braces, which breaks matching for `.jsx` and `.tsx` files.
Remove the spaces so the pattern reads `"*.{js,ts,jsx,tsx}"` to correctly match
all intended file extensions.

commit-msg:
parallel: true
commands:
Expand Down
95 changes: 15 additions & 80 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,17 @@
{
"name": "react-native-youtube-bridge",
"version": "0.4.3",
"name": "@react-native-youtube-bridge/root",
"description": "🎥 Easy-to-use YouTube player for React Native with cross-platform support",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
"exports": {
".": {
"source": "./src/index.tsx",
"types": "./lib/typescript/src/index.d.ts",
"default": "./lib/module/index.js"
},
"./package.json": "./package.json"
},
"files": [
"lib",
"android",
"ios",
"cpp",
"*.podspec",
"react-native.config.js",
"!ios/build",
"!android/build",
"!android/gradle",
"!android/gradlew",
"!android/gradlew.bat",
"!android/local.properties",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__",
"!**/.*"
],
"private": true,
"scripts": {
"example": "bun --cwd example",
"test": "jest",
"typecheck": "tsc",
"lint": "biome check --write .",
"clean": "del-cli lib",
"prepare": "bob build",
"workspace:core": "bun run --filter @react-native-youtube-bridge/core",
"workspace:react": "bun run --filter @react-native-youtube-bridge/react",
"workspace:web": "bun run --filter @react-native-youtube-bridge/web",
"workspace:react-native-youtube-bridge": "bun run --filter react-native-youtube-bridge",
"typecheck": "bun run --filter @react-native-youtube-bridge/core typecheck && bun run --filter @react-native-youtube-bridge/react typecheck && bun run --filter @react-native-youtube-bridge/web typecheck && bun run --filter react-native-youtube-bridge typecheck",
"build": "bun run --filter @react-native-youtube-bridge/core build && bun run --filter @react-native-youtube-bridge/react build && bun run --filter @react-native-youtube-bridge/web build && bun run --filter react-native-youtube-bridge build",
"lint": "biome format packages/** --write",
"release": "changeset version && changeset publish"
},
"keywords": [
Expand All @@ -49,6 +24,9 @@
"youtube-iframe-api",
"react-native-youtube-iframe"
],
"workspaces": [
"packages/*"
],
"repository": {
"type": "git",
"url": "git+https://github.com/react-native-bridges/react-native-youtube-bridge.git"
Expand All @@ -59,67 +37,24 @@
"url": "https://github.com/react-native-bridges/react-native-youtube-bridge/issues"
},
"homepage": "https://github.com/react-native-bridges/react-native-youtube-bridge#readme",
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@changesets/cli": "^2.29.4",
"@commitlint/config-conventional": "^19.6.0",
"@evilmartians/lefthook": "^1.5.0",
"@react-native/babel-preset": "0.78.2",
"@types/jest": "^29.5.5",
"@types/react": "^19.0.12",
"@types/node": "^22.0.0",
"commitlint": "^19.6.1",
"del-cli": "^5.1.0",
"jest": "^29.7.0",
"react": "19.0.0",
"react-native": "0.79.3",
"react-native-builder-bob": "^0.40.12",
"react-native-webview": "^13.15.0",
"typescript": "^5.8.3"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-native": ">=0.60.0",
"react-native-webview": ">=11.0.0"
},
"packageManager": "bun@1.2.15",
"jest": {
"preset": "react-native",
"modulePathIgnorePatterns": [
"<rootDir>/example/node_modules",
"<rootDir>/web/node_modules",
"<rootDir>/lib/"
]
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"react-native-builder-bob": {
"source": "src",
"output": "lib",
"targets": [
[
"module",
{
"esm": true,
"configFile": true
}
],
[
"typescript",
{
"project": "tsconfig.build.json"
}
]
]
},
"create-react-native-library": {
"languages": "js",
"type": "library",
"version": "0.50.3"
"jest": {
"modulePathIgnorePatterns": ["lib", "node_modules"]
}
}
9 changes: 9 additions & 0 deletions packages/core/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { IframeApiType } from './src/types/iframe';

declare global {
interface Window {
YT: IframeApiType;
onYouTubeIframeAPIReady: () => void;
_ytApiPromise: Promise<void>;
}
}
47 changes: 47 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "@react-native-youtube-bridge/core",
"version": "0.0.1",
"description": "Core package for react-native-youtube-bridge",
"private": true,
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"files": ["dist", "package.json"],
"scripts": {
"build": "tsdown",
"typecheck": "tsc --noEmit"
},
"keywords": [
"react-native",
"ios",
"android",
"youtube",
"react-native-youtube",
"react-native-youtube-bridge",
"youtube-iframe-api",
"react-native-youtube-iframe"
],
"repository": {
"type": "git",
"url": "git+https://github.com/react-native-bridges/react-native-youtube-bridge.git"
},
"author": "saseungmin <dbd02169@naver.com> (https://github.com/saseungmin)",
"license": "MIT",
"bugs": {
"url": "https://github.com/react-native-bridges/react-native-youtube-bridge/issues"
},
"homepage": "https://github.com/react-native-bridges/react-native-youtube-bridge#readme",
"publishConfig": {
"access": "public"
},
"devDependencies": {
"tsdown": "^0.12.8"
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { YouTubePlayer } from '../types/iframe';
import { ERROR_CODES, type PlayerEvents, PlayerState, type YoutubePlayerProps } from '../types/youtube';
import { validateVideoId } from '../utils/validate';
import { ERROR_CODES } from './constants';
import { type PlayerEvents, PlayerState, type YoutubePlayerConfig } from './types';
import type { YouTubePlayer } from './types/iframe';
import { validateVideoId } from './utils';

type PlayerConfig = Omit<YoutubePlayerProps, 'source'> & {
type PlayerConfig = Omit<YoutubePlayerConfig, 'source'> & {
videoId: string;
};

class YouTubePlayerCore {
class YoutubePlayerCore {
private player: YouTubePlayer | null = null;
private progressInterval: NodeJS.Timeout | null = null;
private callbacks: PlayerEvents = {};
Expand Down Expand Up @@ -48,7 +49,7 @@ class YouTubePlayerCore {
return;
}

window.onYouTubeIframeAPIReady = () => {
window.window.onYouTubeIframeAPIReady = () => {
resolve();
};

Expand Down Expand Up @@ -371,4 +372,4 @@ class YouTubePlayerCore {
}
}

export default YouTubePlayerCore;
export default YoutubePlayerCore;
15 changes: 15 additions & 0 deletions packages/core/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const ERROR_CODES = {
2: 'INVALID_PARAMETER_VALUE',
5: 'HTML5_PLAYER_ERROR',
100: 'VIDEO_NOT_FOUND_OR_PRIVATE',
101: 'EMBEDDED_PLAYBACK_NOT_ALLOWED',
150: 'EMBEDDED_RESTRICTED',
1000: 'FAILED_TO_PARSE_WEBVIEW_MESSAGE',
1001: 'WEBVIEW_LOADING_ERROR',
1002: 'INVALID_YOUTUBE_VIDEO_ID',
1003: 'FAILED_TO_LOAD_YOUTUBE_API',
1004: 'UNKNOWN_ERROR',
} as const;

export const MATCH_URL_YOUTUBE =
/(?:youtu\.be\/|youtube(?:-nocookie|education)?\.com\/(?:embed\/|v\/|watch\/|watch\?v=|watch\?.+&v=|shorts\/|live\/))((\w|-){11})/;
16 changes: 16 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export {
type PlayerEvents,
type PlayerInfo,
PlayerState,
type YouTubeError,
type ProgressData,
type YoutubePlayerVars,
type PlaybackQuality,
type YoutubePlayerConfig,
type YouTubeSource,
type PlayerControls,
} from './types';
export type { MessageData } from './types/webview';
export { default as YoutubePlayerCore } from './YoutubePlayerCore';
export { escapeHtml, extractVideoIdFromUrl, safeNumber, validateVideoId } from './utils';
export { ERROR_CODES } from './constants';
17 changes: 4 additions & 13 deletions src/types/iframe.d.ts → packages/core/src/types/iframe.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import type { ERROR_CODES, PlaybackQuality, PlayerInfo, PlayerState, YouTubeError } from './youtube';
import type { PlaybackQuality, PlayerInfo, PlayerState } from '.';
import type { ERROR_CODES } from '../constants';

declare global {
interface Window {
YT: IframeApiType;
onYouTubeIframeAPIReady: () => void;
_ytApiPromise: Promise<void>;
}
export interface IframeApiType {
Player: { new (elementId: string, options: Options): YouTubePlayer };
}

export type EventType =
Expand Down Expand Up @@ -159,10 +156,4 @@ export interface YouTubePlayer {
setVolume(volume: number): Promise<void>;
stopVideo(): Promise<void>;
unMute(): Promise<void>;
on(eventType: 'onStateChange', listener: (event: CustomEvent & { data: number }) => void): void;
on(eventType: EventType, listener: (event: CustomEvent) => void): void;
}

export interface IframeApiType {
Player: { new (elementId: string, options: Options): YouTubePlayer };
}
Loading