diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 994b33e..13f3a9d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v2 with: - version: 8 + version: 10 - name: Install dependencies run: pnpm install @@ -39,28 +39,19 @@ jobs: - name: Update manifest version run: | - # Update version in manifest.json - sed -i 's/"version": "[^"]*"/"version": "${{ steps.version.outputs.VERSION }}"/' src/manifest.json - echo "Updated manifest.json:" - cat src/manifest.json + VERSION=${{ steps.version.outputs.VERSION }} + sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" src/manifest.chrome.json + sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" src/manifest.firefox.json + echo "Updated manifest.chrome.json:" + cat src/manifest.chrome.json + echo "Updated manifest.firefox.json:" + cat src/manifest.firefox.json - - name: Build extension - run: pnpm build + - name: Build Chrome extension + run: pnpm build:chrome - - name: Create release zip - run: | - # Create "Reels Master" directory with dist contents - mkdir -p "release/Reels Master" - cp -r dist/* "release/Reels Master/" - - # Create zip file - cd release - zip -r ../ReelsMaster.zip "Reels Master" - cd .. - - # Show zip contents - echo "Zip contents:" - unzip -l ReelsMaster.zip + - name: Build Firefox extension + run: pnpm build:firefox - name: Create Release Draft uses: softprops/action-gh-release@v1 @@ -68,7 +59,9 @@ jobs: draft: true name: Reels Master v${{ steps.version.outputs.VERSION }} tag_name: ${{ github.ref_name }} - files: ReelsMaster.zip + files: | + reels-master-chrome.zip + reels-master-firefox.zip generate_release_notes: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index b56526c..f9163c2 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,11 @@ "description": "Chrome extension for Instagram Reels with volume control and download functionality", "main": "index.js", "scripts": { - "dev": "vite build --watch", - "build": "vite build", + "dev": "BROWSER=chrome vite build --watch", + "dev:firefox": "BROWSER=firefox vite build --watch", + "build": "pnpm build:chrome && pnpm build:firefox", + "build:chrome": "BROWSER=chrome vite build", + "build:firefox": "BROWSER=firefox vite build", "bundle": "vite build && node scripts/bundle.js", "type-check": "tsc --noEmit" }, diff --git a/src/background/service-worker.ts b/src/background/service-worker.ts index 6943c1c..ee0e6e1 100644 --- a/src/background/service-worker.ts +++ b/src/background/service-worker.ts @@ -1,4 +1,6 @@ // Background Service Worker for Reels Master +import browser from 'webextension-polyfill'; + console.log('Reels Master: Background service worker loaded'); const ENCODING_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; @@ -19,16 +21,14 @@ function extractShortcode(url: string): string | null { return match ? match[1] : null; } -chrome.runtime.onInstalled.addListener(() => { +browser.runtime.onInstalled.addListener(() => { console.log('Reels Master: Extension installed'); }); -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message.type === 'DOWNLOAD_REEL') { - handleDownload(message.url) - .then(result => sendResponse(result)) - .catch(error => sendResponse({ success: false, error: error.message })); - return true; +browser.runtime.onMessage.addListener((message: unknown) => { + const msg = message as { type: string; url: string }; + if (msg.type === 'DOWNLOAD_REEL') { + return handleDownload(msg.url); } }); @@ -79,7 +79,7 @@ async function handleDownload(reelUrl: string): Promise<{ success: boolean; down console.log('Reels Master: Found video URL, starting download'); - await chrome.downloads.download({ + await browser.downloads.download({ url: videoUrl, filename: `reel_${shortcode}_${Date.now()}.mp4`, }); @@ -132,7 +132,7 @@ async function tryGraphQLFallback(shortcode: string, headers: Record { - if (result.volume !== undefined) { - this.storedVolume = result.volume; - } - if (result.muted !== undefined) { - this.storedMuted = result.muted; - } - this.applyVolumeToAllVideos(); - this.updateAllSliders(); - }); + private async loadSettings(): Promise { + const result = await browser.storage.local.get(['volume', 'muted']); + if (result.volume !== undefined) { + this.storedVolume = result.volume as number; } + if (result.muted !== undefined) { + this.storedMuted = result.muted as boolean; + } + this.applyVolumeToAllVideos(); + this.updateAllSliders(); } private saveSettings(): void { - if (typeof chrome !== 'undefined' && chrome.storage?.local) { - chrome.storage.local.set({ - volume: this.storedVolume, - muted: this.storedMuted - }); - } + browser.storage.local.set({ + volume: this.storedVolume, + muted: this.storedMuted + }); } private start(): void { @@ -459,10 +455,10 @@ class ReelsMaster { console.log('Reels Master: Sending download request to background for', reelUrl); - const response = await chrome.runtime.sendMessage({ + const response = await browser.runtime.sendMessage({ type: 'DOWNLOAD_REEL', url: reelUrl - }); + }) as { success: boolean; error?: string }; console.log('Reels Master: Background response', response); diff --git a/src/manifest.json b/src/manifest.chrome.json similarity index 100% rename from src/manifest.json rename to src/manifest.chrome.json diff --git a/src/manifest.firefox.json b/src/manifest.firefox.json new file mode 100644 index 0000000..9f107e8 --- /dev/null +++ b/src/manifest.firefox.json @@ -0,0 +1,27 @@ +{ + "manifest_version": 3, + "name": "Reels Master", + "version": "1.1.2", + "description": "Enhance your Instagram experience with Reels Master - download reels, seek through videos, and more!", + "background": { + "service_worker": "background/background.js" + }, + "homepage_url": "https://shiftyspace.ru", + "author": "ShiftyX1", + "content_scripts": [ + { + "matches": ["*://*.instagram.com/*"], + "js": ["content/content.js"], + "css": ["assets/content.css"], + "run_at": "document_end" + } + ], + "permissions": ["storage", "downloads"], + "host_permissions": ["*://*.instagram.com/*", "*://*.cdninstagram.com/*", "https://i.instagram.com/*", "*://*.fbcdn.net/*"], + "browser_specific_settings": { + "gecko": { + "id": "reels-master@shiftyspace.ru", + "strict_min_version": "121.0" + } + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 9f8474f..a2f916d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "target": "ES2020", "module": "ESNext", - "lib": ["ES2020", "DOM"], + "lib": ["ES2020", "DOM", "DOM.Iterable"], "moduleResolution": "bundler", "resolveJsonModule": true, "esModuleInterop": true, @@ -12,7 +12,7 @@ "strict": true, "noEmit": true, "isolatedModules": true, - "types": ["chrome", "node"] + "types": ["webextension-polyfill", "node"] }, "include": ["src/**/*", "vite.config.ts"], "exclude": ["node_modules", "dist"] diff --git a/vite.config.ts b/vite.config.ts index d996df0..19a3396 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,6 +3,8 @@ import { resolve } from 'path'; import { copyFileSync, existsSync } from 'fs'; import AdmZip from 'adm-zip'; +const browser = process.env.BROWSER || 'chrome'; + export default defineConfig({ build: { outDir: 'dist', @@ -25,10 +27,10 @@ export default defineConfig({ closeBundle() { try { copyFileSync( - resolve(__dirname, 'src/manifest.json'), + resolve(__dirname, `src/manifest.${browser}.json`), resolve(__dirname, 'dist/manifest.json') ); - console.log('✓ Copied manifest.json'); + console.log(`✓ Copied manifest.${browser}.json`); } catch (err) { console.error('Error copying manifest.json:', err); } @@ -44,8 +46,8 @@ export default defineConfig({ if (existsSync(distPath)) { zip.addLocalFolder(distPath); - zip.writeZip(resolve(__dirname, 'reels-master.zip')); - console.log('Created reels-master.zip'); + zip.writeZip(resolve(__dirname, `reels-master-${browser}.zip`)); + console.log(`Created reels-master-${browser}.zip`); } } catch (err) { console.error('Error creating zip:', err);