diff --git a/.vscodeignore b/.vscodeignore index 8a67662..0408f9e 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -5,6 +5,7 @@ **/*.map **/*.ts **/tsconfig.json +lab media/res media/vscodeignore node_modules diff --git a/CHANGELOG.md b/CHANGELOG.md index 1022b6e..17b5488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,35 +17,45 @@ Check [Keep a Changelog](http://keepachangelog.com) for recommendations on how t - Shelljs vs Execa - Support for other sites +## [2.1.0] - July 2024 +- Fix Spotify and YouTube Music due to its UI change +- webpack 5.92.1 compiled successfully in 10241 ms +- 20 files, 1.4MB, 1.91.0 + +### Note +- Updating this project to 3.0 was rough, so here is the minor release +- The Puppeteer@22 was having undesired bugs and behaviors +- Adding puppeteer-extra on top of it = more strange behaviors +- Why does Webpack's behavior change? - it doesn't combine files anymore + ## [2.0.0] - December 2021 - Add new feature - treeview - Rewrite/refactor most of the code - 30+ commits - New float button style - old vs new in Windows
-- Fix Spotify bug due to it's style class's changes +- Fix Spotify bug due to its style class's changes - Fix site English version issue - observes another DOM element to update playback status - Merge play and pause commands into one toggle function - Move most of the minor inject action to inject script instead - Re-config project's configs like eslint, tsconfig, vscode setting, and webpack (.js -> .ts) - Rename directories: icon -> media, scripts -> inject -- Playback icons is sync with the site's playback icons which was behaved contrarily before +- Playback icons are synced with the site's playback icons, which behaved contrarily before - Webpack 5.65.0 compiled successfully in 9980 ms - 15 files, 1.39MB, 1.63.0 ### Note -#### This release mostly has more significant impact on the dev side rather than like a product update. - -#### One funny thing is that the picture in README.md accounts for a large part of this extension's size. +- This release mostly has a more significant impact on the dev side rather than a product update. +- One funny thing is that the picture in README.md accounts for a large part of this extension's size. #### [MediaSession](https://developer.mozilla.org/en-US/docs/Web/API/MediaSession) -- Soundcloud does update `playbackState` but only call `set` for from press play -- Spotify does call `set` to update metadata but playbackState always *none* +- Soundcloud does update `playbackState` but only calls `set` from pressing play +- Spotify does call `set` to update metadata, but playbackState always *none* - Youtube and YTmusic update `playbackState` consistent with proxy `set` event #### Puppeteer -- Seem Puppeteer doesn't keep track pages/tabs' order -- If click too quick, this shows up: `Error: Execution context is not available in detached frame "about:blank" (are you trying to evaluate?)` +- It seems like Puppeteer doesn't keep track of pages/tabs' order +- If clicking too quickly, this shows up: `Error: Execution context is not available in detached frame "about:blank" (are you trying to evaluate?)` Waiting and try/catch was fruitless ## [1.4.0] - October 2020 @@ -58,7 +68,7 @@ Check [Keep a Changelog](http://keepachangelog.com) for recommendations on how t ## [1.3.0] - February 2020 - Add [ignoreDisableSync](https://github.com/puppeteer/puppeteer/blob/0b1777e73cb1e83ece9e09b7b51d11b798def06f/lib/Launcher.js#L277) setting [#3](https://github.com/lanly-dev/VSCode-LMPTM/issues/3#issuecomment-572180371), [#5](https://github.com/lanly-dev/VSCode-LMPTM/issues/5) - Remove [Adblocker](https://github.com/cliqz-oss/adblocker/tree/master/packages/adblocker-puppeteer) - New version breaks webpack build -- Ignore [disable extension flag from puppeteer](https://github.com/puppeteer/puppeteer/blob/0b1777e73cb1e83ece9e09b7b51d11b798def06f/lib/Launcher.js#L270) +- Ignore [disable extension flag from Puppeteer](https://github.com/puppeteer/puppeteer/blob/0b1777e73cb1e83ece9e09b7b51d11b798def06f/lib/Launcher.js#L270) - Switch tslint to eslint in development - 11 files, 141.77KB, 1.42.0 diff --git a/README.md b/README.md index 2f3d961..200b0c9 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ -# LetMePlayTheMusic README +# [LetMePlayTheMusic](https://marketplace.visualstudio.com/items?itemName=lanly-dev.letmeplaythemusic) -[![Version](https://vsmarketplacebadge.apphb.com/version-short/lanly-dev.letmeplaythemusic.svg)](https://marketplace.visualstudio.com/items?itemName=lanly-dev.letmeplaythemusic) - -Tired or get annoyed from switching windows in order to pause or skip a song?\ +Are you tired or annoyed from switching windows in order to pause or skip a song?\ Doesn't want to or lazy to install the extra official players to the system?\ Or perhaps your keyboard doesn't have the handy media hotkeys?\ -Wanted to stay focus on your programing instead of those shortcomings above? +Do you want to stay focused on your programming instead of those shortcomings above? If yes, you are in luck!\ -This extension launches a Chrome/Chromium browser to the 4 popular music sites and you can control the playback from within your favorite Visual Studio Code editor. +This extension launches a Chrome/Chromium browser to the 4 popular music sites, and you can control the playback from within your favorite Visual Studio Code editor. >Extra [use case](https://github.com/lanly-dev/VSCode-LMPTM/issues/8#issuecomment-661796089) - you could use this extension to follow programming tutorials on Youtube with the handy seek forward/backward key shortcuts. @@ -17,7 +15,7 @@ This extension launches a Chrome/Chromium browser to the 4 popular music sites a ## Features -Supports SoundCloud, Spotify, Youtube and Youtube Music +Supports SoundCloud, Spotify, YouTube, and YouTube Music ## Requirements Required Chromium-based browser @@ -25,24 +23,26 @@ Required Chromium-based browser ## Extension Settings * `lmptm.browserPath`: Specify custom browser executable file path. * `lmptm.ignoreDisableSync`: Ignore --disable-sync, this option is specifically for [Brave](https://brave.com) browser. -* `lmptm.incognitoMode`: Specify whether to launch browser in incognito/private mode. +* `lmptm.incognitoMode`: Specify whether to launch the browser in incognito/private mode. * `lmptm.startPages`: Starting tabs. -* `lmptm.userData`: Specify if the extension could store browser's user data, if enabled, user data directory setting is required. -* `lmptm.userDataDirectory`: Specify [user data directory](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md), this will be ignored if **User Data** setting is unchecked. +* `lmptm.userData`: Specify if the extension could store the browser's user data; if enabled, a user-data directory setting is required. +* `lmptm.userDataDirectory`: Specify [user data directory](https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md). This setting will be ignored if **User Data** setting is unchecked. ## Known Issues - Does not work with Opera browser -- Won't be able to login Youtube and SoundCloud(email method) +- Won't be able to log into YouTube and SoundCloud(email method) ## Release Notes +### 2.1.0 +- Fix Spotify and YouTube Music for its UI changes + ### 2.0.0 -- Add treeview - so now the the app can switch between tabs - 1. The page has to be picked before being able to use in the treeview +- Fix Spotify bugs for its UI changes +- Add treeview - so now the app can switch between tabs + 1. The page has to be picked before being able to be used in the treeview 2. You can select the treeview items that have the play/pause icon 3. The emoji ⛏️ means the tab is currently picked - 4. First click switches the picked icon to target tab, later clicks toggles playing/paused status of the target tab media's playback - -- Fix spotify bugs due to it's new UI changes + 4. The first click switches the picked icon to the target tab, and the clicks that come after toggle the playing/paused status of the target tab media's playback ### 1.4.0 - Add key shortcuts @@ -52,7 +52,7 @@ Required Chromium-based browser ### 1.3.0 - Remove adblocker -- Enable adding extensions for browser +- Enable adding extensions for the browser - Add ignoreDisableSync setting option in order to able to launch [Brave](https://brave.com) browser ### 1.2.0 diff --git a/package.json b/package.json index 896664c..1e73882 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,10 @@ "displayName": "Let Me Play The Music", "description": "Playback control buttons for the popular music sites", "homepage": "https://github.com/lanly-dev/VSCode-LMPTM", - "version": "2.0.0", + "version": "2.1.0", "publisher": "lanly-dev", "engines": { - "vscode": "^1.63.0" + "vscode": "^1.91.0" }, "extensionKind": [ "ui" @@ -129,26 +129,26 @@ }, "devDependencies": { "@types/copy-webpack-plugin": "^8.0.1", - "@types/karma-chrome-launcher": "^3.1.1", - "@types/node": "^16.11.13", + "@types/karma-chrome-launcher": "^3.1.4", + "@types/node": "^20.14.10", "@types/puppeteer-core": "^5.4.0", - "@types/shelljs": "^0.8.9", - "@types/vscode": "^1.63.0", - "@typescript-eslint/eslint-plugin": "^5.7.0", - "@typescript-eslint/parser": "^5.7.0", - "copy-webpack-plugin": "^10.1.0", - "css-minimizer-webpack-plugin": "^3.2.0", + "@types/shelljs": "^0.8.15", + "@types/vscode": "^1.91.0", + "@typescript-eslint/eslint-plugin": "^7.15.0", + "@typescript-eslint/parser": "^7.15.0", + "copy-webpack-plugin": "^12.0.2", + "css-minimizer-webpack-plugin": "^7.0.0", "eslint": "^8.4.1", - "shelljs": "^0.8.4", - "ts-loader": "^9.2.6", - "ts-node": "^10.4.0", - "typescript": "^4.5.4", + "shelljs": "^0.8.5", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "typescript": "^5.5.3", "vsce": "^2.5.1", - "webpack": "^5.65.0", - "webpack-cli": "^4.9.1" + "webpack": "^5.92.1", + "webpack-cli": "^5.1.4" }, "dependencies": { - "karma-chrome-launcher": "^3.1.0", + "karma-chrome-launcher": "^3.2.0", "puppeteer-core": "^13.0.0" }, "repository": { diff --git a/src/browser.ts b/src/browser.ts index 57d79e6..717b48e 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -2,15 +2,15 @@ import * as path from 'path' import * as puppeteer from 'puppeteer-core' import * as vscode from 'vscode' -import { Buttons } from './buttons' -import { TreeviewProvider } from './treeview' -import { WhichChrome } from './whichChrome' import { Entry } from './interfaces' -import { HTTPResponse } from 'puppeteer-core' + +import Buttons from './buttons' +import TreeviewProvider from './treeview' +import WhichChrome from './whichChrome' const SEEK_MSG = 'Seeking backward/forward function is only work for Youtube videos. 💡' const STATE_MSG = 'Please select the tab/page that either in playing or paused. 💡' -export class Browser { +export default class Browser { public static activeBrowser: Browser | undefined public static cssPath: string public static jsPath: string @@ -127,8 +127,9 @@ export class Browser { await this.selectedPage.keyboard.up('ShiftLeft') break case 'spotify': - // @ts-ignore - this.selectedPage.evaluate(() => spotifyAction('skip')) + await this.selectedPage.keyboard.down('ControlLeft') + await this.selectedPage.keyboard.press('ArrowRight') + await this.selectedPage.keyboard.up('ControlLeft') break case 'youtube': await this.selectedPage.keyboard.down('ShiftLeft') @@ -149,8 +150,9 @@ export class Browser { await this.selectedPage.keyboard.up('ShiftLeft') break case 'spotify': - // @ts-ignore - this.selectedPage.evaluate(() => spotifyAction('back')) + await this.selectedPage.keyboard.down('ControlLeft') + await this.selectedPage.keyboard.press('ArrowLeft') + await this.selectedPage.keyboard.up('ControlLeft') break case 'youtube': this.selectedPage.goBack() @@ -204,7 +206,7 @@ export class Browser { private async launchPages() { const links: string[] | undefined = vscode.workspace.getConfiguration().get('lmptm.startPages') if (links && links.length) { - const p: Promise[] = [] + const p: Promise[] = [] links.forEach(async (e: string) => { const pg = await this.newPage() await pg.setDefaultNavigationTimeout(0) @@ -295,6 +297,7 @@ export class Browser { } private async pageChanged(page: puppeteer.Page) { + // @ts-ignore await page.waitForNetworkIdle() // this somehow prevents navigation error const pageURL = page.url() const brand = this.musicBrandCheck(pageURL) diff --git a/src/buttons.ts b/src/buttons.ts index 6ea6ab9..9a4862f 100644 --- a/src/buttons.ts +++ b/src/buttons.ts @@ -1,6 +1,6 @@ import { window, StatusBarItem, StatusBarAlignment } from 'vscode' -export class Buttons { +export default class Buttons { private playButton: StatusBarItem private skipButton: StatusBarItem private backButton: StatusBarItem diff --git a/src/extension.ts b/src/extension.ts index 6521bbd..45903f0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,8 +1,9 @@ import { commands, window, ExtensionContext } from 'vscode' -import { Browser } from './browser' -import { Buttons } from './buttons' import { Entry } from './interfaces' -import { TreeviewProvider } from './treeview' + +import Browser from './browser' +import Buttons from './buttons' +import TreeviewProvider from './treeview' export function activate(context: ExtensionContext) { const buttons = new Buttons() diff --git a/src/inject/script.js b/src/inject/script.js index 0948fad..3540060 100644 --- a/src/inject/script.js +++ b/src/inject/script.js @@ -11,9 +11,8 @@ const playButtonAttrs = { }, spotify: { css: 'button[data-testid="control-button-playpause"]', - cssAll5Btns: '.player-controls button', cssTitle: 'div[data-testid="now-playing-widget"]', - play: 'M4.018 14L14.41 8 4.018 2z' + play: 'M3 1.713a.7.7 0 0 1 1.05-.607l10.89 6.288a.7.7 0 0 1 0 1.212L4.05 14.894A.7.7 0 0 1 3 14.288V1.713z' }, youtube: { css: '.ytp-play-button' }, ytmusic: { css: '#play-pause-button' } @@ -69,8 +68,7 @@ function click() { } brand = 'youtube' } else if (href.includes('music.youtube.com')) { - const e = 'ytmusic-app-layout[player-visible_] > [slot=player-bar]' - if (!document.querySelectorAll(e)[0]) { + if (!href.includes('/watch')) { btnPick.disabled = true return void showInfo(btnPick, 'ytmusic') } @@ -187,23 +185,9 @@ function showInfo(btnPick, brand) { btnTimeoutReset(btnPick) } -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function spotifyAction(action) { - const { cssAll5Btns } = playButtonAttrs.spotify - const actionBtn = document.querySelectorAll(cssAll5Btns) - switch (action) { - case 'skip': - actionBtn[3].click() - break - case 'back': - actionBtn[1].click() - break - } -} - function btnTimeoutReset(btnPick) { setTimeout(() => { - btnPick.innerHTML = '⛏️ Pick?' + btnPick.innerHTML = PICK_MSG btnPick.className = 'btn-pick-float' btnPick.disabled = false }, 3000) @@ -211,7 +195,7 @@ function btnTimeoutReset(btnPick) { function reset() { const btnPick = document.querySelector('.btn-pick-float') - btnPick.innerHTML = '⛏️ Pick?' + btnPick.innerHTML = PICK_MSG btnPick.className = 'btn-pick-float' sessionStorage.removeItem('lmptm') } diff --git a/src/treeview.ts b/src/treeview.ts index 0f9e259..3056af9 100644 --- a/src/treeview.ts +++ b/src/treeview.ts @@ -1,8 +1,8 @@ -import { Browser } from './browser' -import { Event, EventEmitter, ThemeIcon, TreeDataProvider, TreeItem, window } from 'vscode' import { Entry } from './interfaces' +import { Event, EventEmitter, ThemeIcon, TreeDataProvider, TreeItem, window } from 'vscode' +import Browser from './browser' -export class TreeviewProvider implements TreeDataProvider { +export default class TreeviewProvider implements TreeDataProvider { public static tvProvider: TreeviewProvider private _onDidChangeTreeData: EventEmitter = new EventEmitter() diff --git a/src/whichChrome.ts b/src/whichChrome.ts index 1ec37e9..5f00cfa 100644 --- a/src/whichChrome.ts +++ b/src/whichChrome.ts @@ -1,14 +1,9 @@ 'use strict' - -interface Paths { - [key: string]: string -} - import * as karmaChromeLauncher from 'karma-chrome-launcher' -export class WhichChrome { +export default class WhichChrome { public static getPaths() { - const chromePaths: Paths = {} + const chromePaths: { [key: string]: string } = {} Object.keys(karmaChromeLauncher).forEach(key => { if (key.indexOf('launcher:') !== 0) return // @ts-ignore diff --git a/webpack.config.ts b/webpack.config.ts index dfe72ce..7c558aa 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -20,6 +20,7 @@ export default { externals: { vscode: 'commonjs vscode', // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ bufferutil: 'commonjs bufferutil', // https://github.com/websockets/ws/issues/1220#issuecomment-433066790 + // eslint-disable-next-line @typescript-eslint/naming-convention 'utf-8-validate': 'commonjs utf-8-validate' }, resolve: {