diff --git a/.eslintrc.js b/.eslintrc.js index 8dd7b439..c6a61d5c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -81,10 +81,6 @@ module.exports = { 'react/jsx-one-expression-per-line': 'off', 'react/react-in-jsx-scope': 'off', 'react/no-unescaped-entities': 'off', - // no. - radix: 'off', - // && and ||? maybe. math operators? no. learn math. - 'no-mixed-operators': 'off', // i dont do this, but one line arrow functions interpreted I'm returning even though i dont use return. 'no-return-assign': 'off', 'no-param-reassign': 'off', @@ -93,8 +89,6 @@ module.exports = { 'no-bitwise': 'off', // for the convenience to work with stupid async chrome API calls. 'no-await-in-loop': 'off', - // actually a feature not oversight. no. - 'no-fallthrough': 'off', 'jsx-a11y/click-events-have-key-events': 'off', // no. its readable. 'no-nested-ternary': 'off', diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index 2298bf3e..e9b13a2f 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -31,7 +31,6 @@ jobs: - name: yarn build run: | - yarn ci:format yarn build zip -r NoxPlayer.zip build @@ -42,3 +41,26 @@ jobs: zipFilePath: 'NoxPlayer.zip' crxFilePath: 'NoxPlayer.crx' privateKey: ${{ secrets.PEM_KEY }} + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup Yarn + uses: threeal/setup-yarn-action@v2.0.0 + + - name: Install dependencies + run: yarn; git submodule update --init --recursive + + - name: yarn ci + run: | + yarn ci:format + yarn ci:lint diff --git a/src/azusa-player-mobile b/src/azusa-player-mobile index cd88f69b..a3f148d0 160000 --- a/src/azusa-player-mobile +++ b/src/azusa-player-mobile @@ -1 +1 @@ -Subproject commit cd88f69b7deb0b5aa0b92c2905a6c27ce1115e83 +Subproject commit a3f148d0e371a5c1ba41a0ebbc209ab15dec5d7e diff --git a/src/components/Playlist/PlaylistHeader/PlaylistSelectButton.tsx b/src/components/Playlist/PlaylistHeader/PlaylistSelectButton.tsx index 89f5f07f..bab5291f 100644 --- a/src/components/Playlist/PlaylistHeader/PlaylistSelectButton.tsx +++ b/src/components/Playlist/PlaylistHeader/PlaylistSelectButton.tsx @@ -24,7 +24,7 @@ interface Props { usePlaylist: UsePlaylist; } -export default function ({ usePlaylist }: Props) { +export default function PlaylistSelectBtn({ usePlaylist }: Props) { const onClick = () => { if (usePlaylist.checking) { usePlaylist.resetSelected(); diff --git a/src/components/Playlist/PlaylistHeader/PlaylistSortButton.tsx b/src/components/Playlist/PlaylistHeader/PlaylistSortButton.tsx index 4a5bbf07..935d445b 100644 --- a/src/components/Playlist/PlaylistHeader/PlaylistSortButton.tsx +++ b/src/components/Playlist/PlaylistHeader/PlaylistSortButton.tsx @@ -18,7 +18,7 @@ interface Props { playlist: NoxMedia.Playlist; } -export default function ({ sortPlaylist, playlist }: Props) { +export default function PlaylistSortButton({ sortPlaylist, playlist }: Props) { const [showDialog, setShowDialog] = React.useState(false); const [ascending, setAscending] = React.useState(false); const sortOptions = Object.values(SortOptions); diff --git a/src/components/Playlist/SongMenu.js b/src/components/Playlist/SongMenu.js index d9bafa8e..8634411b 100644 --- a/src/components/Playlist/SongMenu.js +++ b/src/components/Playlist/SongMenu.js @@ -1,4 +1,4 @@ -/* eslint-disable react/jsx-no-bind */ +/* eslint-disable */ import React from 'react'; import { Menu, Item, Separator, useContextMenu } from 'react-contexify'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; diff --git a/src/components/Playlist/hooks/usePlaylistPaginated.ts b/src/components/Playlist/hooks/usePlaylistPaginated.ts index 104ac771..f45221f1 100644 --- a/src/components/Playlist/hooks/usePlaylistPaginated.ts +++ b/src/components/Playlist/hooks/usePlaylistPaginated.ts @@ -69,8 +69,9 @@ export default (playlist: NoxMedia.Playlist): UsePlaylistP => { resetToFirstPage = false, songList = getCurrentRow(), ) => { - for (let i = 0, n = songList.length; i < n; i++) { - if (songList[i]!.id === currentPlayingId) { + // eslint-disable-next-line no-restricted-syntax + for (const [i, v] of songList.entries()) { + if (v.id === currentPlayingId) { return setPage(Math.floor(i / defaultRowsPerPage)); } } diff --git a/src/components/Playlists/Playlists.tsx b/src/components/Playlists/Playlists.tsx index ecf39532..9f2b6286 100644 --- a/src/components/Playlists/Playlists.tsx +++ b/src/components/Playlists/Playlists.tsx @@ -8,7 +8,7 @@ import Search from './PlaylistsHeader/Search'; import PlaylistHeaderButtons from './PlaylistsHeader/PlaylistHeaderButtons'; import PlaylistList from './PlaylistsList/PlaylistList'; -export default function () { +export default function Playlists() { const playlistCRUD = usePlaylistCRUD(); const { colorTheme } = useApp((state) => state.playerStyle); const AddFavIcon = { diff --git a/src/components/Playlists/PlaylistsHeader/PlaylistHeaderButtons.tsx b/src/components/Playlists/PlaylistsHeader/PlaylistHeaderButtons.tsx index 7ee74110..d122b458 100644 --- a/src/components/Playlists/PlaylistsHeader/PlaylistHeaderButtons.tsx +++ b/src/components/Playlists/PlaylistsHeader/PlaylistHeaderButtons.tsx @@ -11,7 +11,7 @@ interface Props { sx: SxProps; color?: string; } -export default function ({ sx, color }: Props) { +export default function PlaylistHeaderButtons({ sx, color }: Props) { return ( diff --git a/src/components/Playlists/PlaylistsList/PlaylistList.tsx b/src/components/Playlists/PlaylistsList/PlaylistList.tsx index 58eef45a..05440160 100644 --- a/src/components/Playlists/PlaylistsList/PlaylistList.tsx +++ b/src/components/Playlists/PlaylistsList/PlaylistList.tsx @@ -47,6 +47,7 @@ export default function PlaylistList({ playlistCRUD }: Props) { const favoritePlaylist = useNoxSetting((state) => state.favoritePlaylist); // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-vars const _ = useNoxSetting((state) => state.playlistShouldReRender); const { playlists, @@ -97,7 +98,7 @@ export default function PlaylistList({ playlistCRUD }: Props) { )} - {(provided, _snapshot) => ( + {(provided) => (
{playlistIds.map((item, index) => ( { + const onOptionSet = (_: any, newValue?: NoxLyric.NoxFetchedLyric) => { if (newValue === undefined) return; searchAndSetCurrentLyric(0, [newValue]); }; diff --git a/src/components/menus/DummyMenu.tsx b/src/components/menus/DummyMenu.tsx index 7f786624..d0e99efe 100644 --- a/src/components/menus/DummyMenu.tsx +++ b/src/components/menus/DummyMenu.tsx @@ -1,3 +1,4 @@ +/* eslint-disable */ import React from 'react'; import { Menu, Item, useContextMenu } from 'react-contexify'; import TerminalIcon from '@mui/icons-material/Terminal'; diff --git a/src/components/menus/PlaylistMenu.tsx b/src/components/menus/PlaylistMenu.tsx index 25d6b4f8..599f93f2 100644 --- a/src/components/menus/PlaylistMenu.tsx +++ b/src/components/menus/PlaylistMenu.tsx @@ -1,4 +1,4 @@ -/* eslint-disable react/jsx-no-bind */ +/* eslint-disable */ import React from 'react'; import { Menu, Item, useContextMenu } from 'react-contexify'; import YoutubeSearchedForIcon from '@mui/icons-material/YoutubeSearchedFor'; diff --git a/src/components/setting/sync/DropboxAuth.ts b/src/components/setting/sync/DropboxAuth.ts index d10624ae..e9f41768 100644 --- a/src/components/setting/sync/DropboxAuth.ts +++ b/src/components/setting/sync/DropboxAuth.ts @@ -37,7 +37,8 @@ let dbx = new _Dropbox({ * @param {function} errorHandling */ const getAuth = async ( - callback = (_v?: string) => checkAuthentication(dbx).then(console.debug), + callback: (v: string) => Promise = () => + checkAuthentication(dbx).then(console.debug), errorHandling = console.error, ) => chrome.identity.launchWebAuthFlow( @@ -62,7 +63,7 @@ const getAuth = async ( ); const loginDropbox = async ( - callback = async (_v?: string) => {}, + callback: () => Promise = async () => {}, errorCallback = console.error, ) => { try { diff --git a/src/components/setting/sync/GenericSyncButton.tsx b/src/components/setting/sync/GenericSyncButton.tsx index 7d1eafa3..358dc9f6 100644 --- a/src/components/setting/sync/GenericSyncButton.tsx +++ b/src/components/setting/sync/GenericSyncButton.tsx @@ -32,7 +32,7 @@ function ImportSyncFavButton({ sx, }: ImportPropsR) { // @ts-ignore - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const { enqueueSnackbar } = useSnackbar(); const [loading, setLoading] = useState(false); const errorHandling = ( @@ -82,7 +82,7 @@ function ImportSyncFavButton({ function ExportSyncFavButton({ noxBackup, login, sx }: ExportPropsR) { // @ts-ignore - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const { enqueueSnackbar } = useSnackbar(); const [loading, setLoading] = useState(false); const errorHandling = (e: Error) => { @@ -127,7 +127,7 @@ function ExportSyncFavButton({ noxBackup, login, sx }: ExportPropsR) { ); } -export default function ({ +export default function GenericSyncBtn({ restoreFromUint8Array, login, noxBackup, diff --git a/src/components/setting/sync/GiteeAuth.ts b/src/components/setting/sync/GiteeAuth.ts index 374096ab..9777062a 100644 --- a/src/components/setting/sync/GiteeAuth.ts +++ b/src/components/setting/sync/GiteeAuth.ts @@ -12,7 +12,7 @@ const clientSecret = process.env.GITEE_SECRET; const redirectURI = chrome.identity.getRedirectURL(); export const getAuth = async ( - callback = (_v?: string) => + callback: (v: string) => Promise = () => checkAuthentication(authToken).then(console.debug), errorHandling = logger.error, ) => diff --git a/src/components/setting/sync/GithubAuth.ts b/src/components/setting/sync/GithubAuth.ts index 71ed78e1..82fdd5f2 100644 --- a/src/components/setting/sync/GithubAuth.ts +++ b/src/components/setting/sync/GithubAuth.ts @@ -12,7 +12,7 @@ const clientSecret = process.env.GITHUB_SECRET; const redirectURI = chrome.identity.getRedirectURL(); export const getAuth = async ( - callback = (_v?: string) => + callback: (v: string) => Promise = () => checkAuthentication(authToken).then(console.debug), errorHandling = logger.error, ) => diff --git a/src/components/setting/sync/LocalSyncButton.tsx b/src/components/setting/sync/LocalSyncButton.tsx index f8172912..d05654d1 100644 --- a/src/components/setting/sync/LocalSyncButton.tsx +++ b/src/components/setting/sync/LocalSyncButton.tsx @@ -17,11 +17,9 @@ export function ExportFavButton({ AddFavIcon }: SyncFavButtonProps) { // alls sync buttons are loaded/unloaded depending on the current sync setting; // thus they all must have exactly the same states for react to mount and unmount to another set. // even though they are not used. - // @ts-ignore - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); - // @ts-ignore - const dummy = enqueueSnackbar; - // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { enqueueSnackbar } = useSnackbar(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [loading, setLoading] = useState(false); return ( @@ -36,11 +34,9 @@ export function ExportFavButton({ AddFavIcon }: SyncFavButtonProps) { } export function ImportFavButton({ AddFavIcon }: SyncFavButtonProps) { - // @ts-ignore - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); - // @ts-ignore - const dummy = enqueueSnackbar; - // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { enqueueSnackbar } = useSnackbar(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [loading, setLoading] = useState(false); return ( diff --git a/src/components/setting/sync/PersonalSyncButton.tsx b/src/components/setting/sync/PersonalSyncButton.tsx index 95b46ab6..403708ea 100644 --- a/src/components/setting/sync/PersonalSyncButton.tsx +++ b/src/components/setting/sync/PersonalSyncButton.tsx @@ -21,7 +21,7 @@ export function ImportSyncFavButton({ }: SyncFavButtonProps) { const { initializeFromSync } = useInitializeStore(); // @ts-ignore - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const { enqueueSnackbar } = useSnackbar(); const [loading, setLoading] = useState(false); const errorHandling = ( @@ -70,7 +70,7 @@ export function ExportSyncFavButton({ cloudAddress = '', }: SyncFavButtonProps) { // @ts-ignore - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const { enqueueSnackbar } = useSnackbar(); const [loading, setLoading] = useState(false); const errorHandling = (e: Object) => { diff --git a/src/hooks/useLyric.ts b/src/hooks/useLyric.ts index f8f03d44..03d38671 100644 --- a/src/hooks/useLyric.ts +++ b/src/hooks/useLyric.ts @@ -25,15 +25,14 @@ export default (currSong: NoxMedia.Song) => { }; const loadLocalLrc = async ( - lyricPromise: Promise, + lyricPromise: Promise, ) => { const localLrcColle = getLrcFromLocal(currSong); return usedLyric.loadLocalLrc(getLrcFromLocal(currSong), async () => - searchAndSetCurrentLyric( - undefined, - await lyricPromise, - (await localLrcColle)?.lrcDetail, - ), + searchAndSetCurrentLyric({ + resolvedLrcOptions: await lyricPromise, + resolvedLyric: (await localLrcColle)?.lrcDetail, + }), ); }; @@ -43,13 +42,7 @@ export default (currSong: NoxMedia.Song) => { song, lrc, currentTimeOffset, - }: { - resolvedLrc?: NoxNetwork.NoxFetchedLyric; - newLrcDetail?: Partial; - lrc: string; - song: NoxMedia.Song; - currentTimeOffset: number; - }) => { + }: NoxLyric.UpdateLyricMapping) => { if (resolvedLrc) { const lyricDeatail: NoxMedia.LyricDetail = { songId: song.id, @@ -65,19 +58,19 @@ export default (currSong: NoxMedia.Song) => { } }; - const searchAndSetCurrentLyric = ( + const searchAndSetCurrentLyric = ({ index = 0, resolvedLrcOptions = usedLyric.lrcOptions, - resolvedLyric?: NoxMedia.LyricDetail, - mSong = currSong, - ) => - usedLyric.searchAndSetCurrentLyric( + resolvedLyric, + song = currSong, + }: NoxLyric.SearchLyricL) => + usedLyric.searchAndSetCurrentLyric({ updateLyricMapping, index, resolvedLrcOptions, resolvedLyric, - mSong, - ); + song, + }); const initTrackLrcLoad = () => usedLyric.initTrackLrcLoad( diff --git a/src/hooks/usePlayback.ts b/src/hooks/usePlayback.ts index 75281357..28dd8497 100644 --- a/src/hooks/usePlayback.ts +++ b/src/hooks/usePlayback.ts @@ -63,9 +63,7 @@ export default () => { const musicSrcParser = async (v: NoxMedia.Song) => { try { const resolvedUrl = await fetchPlayUrlPromise({ song: v }); - if (false) { - return currentAudioInst?.playNext?.(); - } + // return currentAudioInst?.playNext?.(); parseR128Gain(v, async () => resolvedUrl); return resolvedUrl.url; } catch (e) { diff --git a/src/popup/wdyr.ts b/src/popup/wdyr.ts index 00e8b6e4..6b112198 100644 --- a/src/popup/wdyr.ts +++ b/src/popup/wdyr.ts @@ -2,6 +2,7 @@ import React from 'react'; if (process.env.DEV === 'dev') { + // eslint-disable-next-line import/no-extraneous-dependencies, global-require const whyDidYouRender = require('@welldone-software/why-did-you-render'); whyDidYouRender(React, { trackAllPureComponents: true, diff --git a/src/utils/mediafetch/ytbvideo.ts b/src/utils/mediafetch/ytbvideo.ts index f598e285..01c9a335 100644 --- a/src/utils/mediafetch/ytbvideo.ts +++ b/src/utils/mediafetch/ytbvideo.ts @@ -12,6 +12,7 @@ const resolveURL = async (song: NoxMedia.Song) => { let maxAudioQualityStream = { bitrate: 0, url: '' }; const formats = extractedVideoInfo.adaptive_formats ?? extractedVideoInfo.formats ?? []; + // eslint-disable-next-line no-restricted-syntax for (const videoStream of formats) { if ( videoStream.has_audio && diff --git a/src/utils/rgba2rgb.ts b/src/utils/rgba2rgb.ts index 51f22da9..f40ecc4f 100644 --- a/src/utils/rgba2rgb.ts +++ b/src/utils/rgba2rgb.ts @@ -6,7 +6,7 @@ export default function rgba2rgb(rgbaVal: string) { // rgba(30,30,30,0.5) -> #303030 const extracted = /rgba\((\d+),(\d+),(\d+),.+\)/.exec(rgbaVal)!; - const toHex = (val: string) => parseInt(val).toString(16); + const toHex = (val: string) => parseInt(val, 10).toString(16); try { return `#${toHex(extracted[1]!).padStart(2, '0')}${toHex( extracted[2]!, diff --git a/src/utils/types/NoxMedia.d.ts b/src/utils/types/NoxMedia.d.ts index 63053638..6eaf18eb 100644 --- a/src/utils/types/NoxMedia.d.ts +++ b/src/utils/types/NoxMedia.d.ts @@ -1,4 +1,4 @@ -// @eslint-disable-next-line @typescript-eslint/no-unused-vars +// eslint-disable-next-line @typescript-eslint/no-unused-vars namespace NoxMediaChrome { // this is a special audio intance that is passed from react-music-player // TODO: fill in the types diff --git a/src/utils/versionupdater/versionupdater.ts b/src/utils/versionupdater/versionupdater.ts index 87386b6e..4aef4eae 100644 --- a/src/utils/versionupdater/versionupdater.ts +++ b/src/utils/versionupdater/versionupdater.ts @@ -50,12 +50,14 @@ export default async () => { const currVer = getVersion(); const updatedString = `Noxplayer is updated from ${oldVer} to ${currVer}! \nRead what's new in settings.\n电闹播放器更新了!去帮助里更新说明看更新了什么鬼玩意儿。`; let updated = false; + // eslint-disable-next-line no-restricted-syntax for (const update of updates) { if (needUpdate(oldVerParsed, update[0])) { await update[1](); updated = true; } } + // eslint-disable-next-line no-alert if (updated) alert(updatedString); saveItem('nox-version', currVer); };