Skip to content

Commit

Permalink
fix: lintings
Browse files Browse the repository at this point in the history
  • Loading branch information
avallete committed Jul 22, 2024
1 parent 7cc139b commit 1fefa68
Show file tree
Hide file tree
Showing 17 changed files with 70 additions and 80 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const unitTestsExtends = ['plugin:ava/recommended']
const cypressTestsExtends = ['plugin:cypress/recommended', 'eslint-config-sinon', 'plugin:chai-friendly/recommended']
const cypressTestsExtends = ['plugin:cypress/recommended', 'plugin:chai-friendly/recommended']
const commonExtends = ['plugin:prettier/recommended', 'plugin:unicorn/recommended', 'plugin:sonarjs/recommended']
const tsExtends = ['airbnb-typescript/base', ...commonExtends]
const jsExtends = ['airbnb-base', ...commonExtends]
Expand Down Expand Up @@ -60,6 +60,7 @@ const TS_OVERRIDE = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.eslint.json',
// eslint-disable-next-line unicorn/prefer-module
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
Expand All @@ -72,6 +73,7 @@ const TS_OVERRIDE = {
overrides: [UNIT_TESTS_TS_OVERRIDE, CYPRESS_TS_OVERRIDE],
}

// eslint-disable-next-line unicorn/prefer-module
module.exports = {
extends: jsExtends,
overrides: [UNIT_TESTS_JS_OVERRIDE, CYPRESS_JS_OVERRIDE, TS_OVERRIDE],
Expand Down
15 changes: 3 additions & 12 deletions .nycrc
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
{
"extends": "@istanbuljs/nyc-config-typescript",
"check-coverage": true,
"include": [
"src/**",
"metadata.ts"
],
"exclude": [
"dist/**",
"cypress/**",
"test/**"
],
"reporter": [
"text"
],
"include": ["src/**", "metadata.ts"],
"exclude": ["dist/**", "cypress/**", "test/**"],
"reporter": ["text"],
"lines": 70,
"branches": 70,
"statements": 70
Expand Down
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
## [1.7.1](https://github.com/avallete/yt-playlists-delete-enhancer/compare/v1.7.0...v1.7.1) (2024-05-12)


### Bug Fixes

* api continuation requests ([#242](https://github.com/avallete/yt-playlists-delete-enhancer/issues/242)) ([87c238b](https://github.com/avallete/yt-playlists-delete-enhancer/commit/87c238b4d25777172d99f7c80475563cbae6e3ec))
- api continuation requests ([#242](https://github.com/avallete/yt-playlists-delete-enhancer/issues/242)) ([87c238b](https://github.com/avallete/yt-playlists-delete-enhancer/commit/87c238b4d25777172d99f7c80475563cbae6e3ec))

# [1.7.0](https://github.com/avallete/yt-playlists-delete-enhancer/compare/v1.6.2...v1.7.0) (2024-05-06)

Expand Down
3 changes: 2 additions & 1 deletion cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable unicorn/prefer-module */
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
Expand All @@ -12,7 +13,7 @@
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
// eslint-disable-next-line import/no-extraneous-dependencies
const path = require('path')
const path = require('node:path')

const DIST_PATH = path.resolve(path.join(__dirname, '..', '..', 'dist'))

Expand Down
19 changes: 10 additions & 9 deletions src/components/remove-video-enhancer-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@ export default class RemoveVideoEnhancerApp extends Component<Properties, State>
await removeWatchHistoryForVideo(this.props.config, videoId)
removeWatchedFromPlaylistUI(videoId)
const { playlist } = this.state
playlist?.continuations[0].videos.forEach((v) => {
if (v.videoId === videoId) {
v.percentDurationWatched = 0
if (playlist) {
for (const v of playlist.continuations[0].videos) {
if (v.videoId === videoId) {
v.percentDurationWatched = 0
}
}
})
} else {
throw new Error('Playlist not found')
}
} catch (error) {
this.setState({ ...this.state, errorMessages: [(error as Error).message] })
}
Expand All @@ -55,7 +59,7 @@ export default class RemoveVideoEnhancerApp extends Component<Properties, State>
if (playlist && playlist.continuations[0].videos.length > 0) {
const [toDeleteVideos, toKeepVideos] = partition(
playlist.continuations[0].videos,
(v) => v.percentDurationWatched >= watchTimeValue
(v) => v.percentDurationWatched >= watchTimeValue,
)
if (toDeleteVideos.length > 0) {
try {
Expand Down Expand Up @@ -88,10 +92,7 @@ export default class RemoveVideoEnhancerApp extends Component<Properties, State>
}

shouldComponentUpdate(nextProperties: Properties) {
if (nextProperties.playlistName !== this.state?.playlist?.playlistId) {
return true
}
return false
return nextProperties.playlistName !== this.state?.playlist?.playlistId
}

async componentDidUpdate(previousProperties: Properties) {
Expand Down
7 changes: 2 additions & 5 deletions src/components/remove-video-enhancer-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ export const REMOVE_BUTTON_ALT = 'Remove button to start removing videos'

function validate(value: any): boolean {
const numberValue = Number(value)
if (Number.isSafeInteger(numberValue) && numberValue >= 0 && numberValue <= 100) {
return true
}
return false
return !!(Number.isSafeInteger(numberValue) && numberValue >= 0 && numberValue <= 100)
}

function RemoveVideoEnhancerContainer({
Expand Down Expand Up @@ -70,7 +67,7 @@ function RemoveVideoEnhancerContainer({
onClick: removeVideo,
}),
],
element
element,
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/list-map-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function listMapSearch<T, U, K extends keyof any>(
needles: Array<T>,
haystack: Array<U>,
needleKeyGetter: (item: T) => K,
haystackKeyGetter: (item: U) => K
haystackKeyGetter: (item: U) => K,
): Record<K, U> | false {
const searchMap: Record<K, U | undefined> = {} as Record<K, U>
// We cannot found all our needles into our haystack
Expand Down
2 changes: 2 additions & 0 deletions src/operations/actions/remove-videos-from-playlist-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export function removeVideoFromPlaylistUI(videoId: string) {
removeVideosFromPlaylist([{ videoId, percentDurationWatched: 100 }])
decrementNumberOfVideosInPlaylist(1)
} catch (error) {
// eslint-disable-next-line no-console
console.error(error)
// If an error occurs while trying to dynamically update the UI
// reload the page to update the UI
Expand All @@ -19,6 +20,7 @@ export default function removeVideosFromPlaylistUI(toDeleteVideos: PlaylistVideo
removeVideosFromPlaylist(toDeleteVideos)
decrementNumberOfVideosInPlaylist(toDeleteVideos.length)
} catch (error) {
// eslint-disable-next-line no-console
console.error(error)
// If an error occurs while trying to dynamically update the UI
// reload the page to update the UI
Expand Down
5 changes: 1 addition & 4 deletions src/operations/conditions/is-on-playlist-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ const PLAYLIST_URL_PATHNAME = '/playlist'

const isOnPlaylistPage: Condition = (window_: Window): boolean => {
const url = new URL(window_.location.href)
if (url.pathname === PLAYLIST_URL_PATHNAME) {
return true
}
return false
return url.pathname === PLAYLIST_URL_PATHNAME
}

export default isOnPlaylistPage
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function decrementNumberOfVideosInPlaylist(value: number) {
// - The "There are no videos in this playlist yet" text
// - The "No videos" text
// Both strings are not part of the `yt.msgs_` object to use for localization
// eslint-disable-next-line no-console
console.log('empty playlist reload')
window.location.reload()
}
Expand Down
4 changes: 2 additions & 2 deletions src/operations/ui/remove-videos-from-playlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function removeVideoWithYtAction(videoId: String) {
],
returnValue: [],
},
})
}),
)
}

Expand All @@ -32,7 +32,7 @@ export default function removeVideosFromPlaylist(videosToDelete: PlaylistVideo[]
uniqueVideosToDelete,
playlistVideoRendererNodes,
(video) => video.videoId,
(node) => node.data.videoId
(node) => node.data.videoId,
)
// if all videos to remove are present in the UI
if (searchMap) {
Expand Down
52 changes: 25 additions & 27 deletions src/yt-api.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import sha1 from 'sha1'
import { YTConfigData, PlaylistVideo, Playlist, PlaylistContinuation } from './youtube'
import { PlaylistNotEditableError, PlaylistEmptyError } from '~src/errors'
import { YTConfigData, PlaylistVideo, Playlist, PlaylistContinuation } from './youtube'

type YTHeaderKey =
| 'X-Goog-Visitor-Id'
// eslint-disable-next-line radar/no-duplicate-string
| 'X-YouTube-Client-Name'
// eslint-disable-next-line radar/no-duplicate-string
| 'X-YouTube-Client-Version'
| 'X-YouTube-Device'
| 'X-YouTube-Identity-Token'
Expand Down Expand Up @@ -45,6 +43,7 @@ const API_REQUIRED_HEADERS: HeaderKey[] = [
function generateSAPISIDHASH(origin: string, sapisid: string, date: Date = new Date()): string {
const roundedTimestamp = Math.floor(date.getTime() / 1000)
// deepcode ignore InsecureHash: we need to replicate youtube webapp behavior
// eslint-disable-next-line sonarjs/no-nested-template-literals
return `${roundedTimestamp}_${sha1(`${roundedTimestamp} ${sapisid} ${origin}`)}`
}

Expand Down Expand Up @@ -72,21 +71,19 @@ function generateRequestHeaders(config: YTConfigData, headerKeys: HeaderKey[] =
}

function extractPlaylistVideoListRendererContents(playlistVideoListContents: Array<any>): PlaylistVideo[] {
return playlistVideoListContents.map(
(item): PlaylistVideo => {
return {
videoId: item.playlistVideoRenderer.videoId,
percentDurationWatched:
item.playlistVideoRenderer.thumbnailOverlays[1].thumbnailOverlayResumePlaybackRenderer
?.percentDurationWatched || 0,
}
return playlistVideoListContents.map((item): PlaylistVideo => {
return {
videoId: item.playlistVideoRenderer.videoId,
percentDurationWatched:
item.playlistVideoRenderer.thumbnailOverlays[1].thumbnailOverlayResumePlaybackRenderer
?.percentDurationWatched || 0,
}
)
})
}

function extractPlaylistContinuation(playlistContents: Array<any>): PlaylistContinuation {
// ContinuationToken should be in the last item of the playlist contents
const lastItem = playlistContents[playlistContents.length - 1]
const lastItem = playlistContents.at(-1)
if (lastItem && lastItem.continuationItemRenderer) {
// Remove last item from playlist contents since it contain continuationItem
playlistContents.pop()
Expand All @@ -113,8 +110,10 @@ async function fetchPlaylistInitialData(config: YTConfigData, playlistName: stri
method: 'GET',
mode: 'cors',
})
const data = (await response.json()).response.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content
.sectionListRenderer.contents[0].itemSectionRenderer.contents[0].playlistVideoListRenderer
const respJson = await response.json()
const data =
respJson.response.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer
.contents[0].itemSectionRenderer.contents[0].playlistVideoListRenderer

if (!data) {
throw PlaylistEmptyError
Expand All @@ -130,7 +129,7 @@ async function fetchPlaylistInitialData(config: YTConfigData, playlistName: stri

async function fetchPlaylistContinuation(
config: YTConfigData,
continuation: PlaylistContinuation
continuation: PlaylistContinuation,
): Promise<PlaylistContinuation> {
const url = new URL(`${API_GET_PLAYLIST_VIDEOS_URL}`)
const headers = generateRequestHeaders(config, API_V1_REQUIRED_HEADERS)
Expand All @@ -152,19 +151,20 @@ async function fetchPlaylistContinuation(
method: 'POST',
mode: 'cors',
})
const data = (await response.json()).onResponseReceivedActions[0].appendContinuationItemsAction.continuationItems
const responseJson = await response.json()
const data = responseJson.onResponseReceivedActions[0].appendContinuationItemsAction.continuationItems
return extractPlaylistContinuation(data)
}

export async function fetchAllPlaylistContent(config: YTConfigData, playlistName: string): Promise<Playlist> {
const playlist = await fetchPlaylistInitialData(config, playlistName)
if (playlist.isEditable) {
// If all data has been retrieved, the last continuation item token will be undefined
while (playlist.continuations[playlist.continuations.length - 1].continuationToken !== undefined) {
while (playlist.continuations.at(-1)?.continuationToken !== undefined) {
playlist.continuations.push(
// We need the next continuationToken to launch the next request
// eslint-disable-next-line no-await-in-loop
await fetchPlaylistContinuation(config, playlist.continuations[playlist.continuations.length - 1])
await fetchPlaylistContinuation(config, playlist.continuations.at(-1)!),
)
}
// Merge all the videos into a single PlaylistContinuation
Expand Down Expand Up @@ -193,9 +193,10 @@ async function getRemoveFromHistoryToken(videoId: string): Promise<string> {
if (!matchedData || !matchedData[1]) throw new Error('Failed to parse initData')
const initData = JSON.parse(matchedData[1])

const groups = initData?.contents?.twoColumnBrowseResultsRenderer?.tabs?.[0]?.tabRenderer?.content?.sectionListRenderer?.contents
.map((group: { itemSectionRenderer: object }) => group.itemSectionRenderer)
.filter(Boolean)
const groups =
initData?.contents?.twoColumnBrowseResultsRenderer?.tabs?.[0]?.tabRenderer?.content?.sectionListRenderer?.contents
.map((group: { itemSectionRenderer: object }) => group.itemSectionRenderer)
.filter(Boolean)

let matchingVideo
for (const item of groups) {
Expand Down Expand Up @@ -264,7 +265,7 @@ export async function removeWatchHistoryForVideo(config: YTConfigData, videoId:
export async function removeVideosFromPlaylist(
config: YTConfigData,
playlistId: string,
videosToRemove: PlaylistVideo[]
videosToRemove: PlaylistVideo[],
): Promise<boolean> {
const url = new URL(`${API_EDIT_PLAYLIST_VIDEOS_URL}`)
const headers = generateRequestHeaders(config, API_V1_REQUIRED_HEADERS)
Expand Down Expand Up @@ -292,8 +293,5 @@ export async function removeVideosFromPlaylist(
mode: 'cors',
})
const data = await response.json()
if (data.status !== 'STATUS_SUCCEEDED') {
return true
}
return false
return data.status !== 'STATUS_SUCCEEDED'
}
1 change: 1 addition & 0 deletions test/_setup-browser-environment.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// eslint-disable-next-line unicorn/prefer-module
const browserEnv = require('browser-env')

browserEnv()
8 changes: 4 additions & 4 deletions test/metadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,25 @@ test.afterEach(() => {
test('generateDownloadUrlFromRepositoryUrl: should extract repo from github ssh url', (t) => {
t.is(
generateDownloadUrlFromRepositoryUrl('[email protected]:some-user/my-repo.git'),
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`,
)
})
test('generateDownloadUrlFromRepositoryUrl: should extract repo from github https url', (t) => {
t.is(
generateDownloadUrlFromRepositoryUrl('https://github.com/some-user/my-repo.git'),
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`,
)
})
test('generateDownloadUrlFromRepositoryUrl: should extract repo from git:// url', (t) => {
t.is(
generateDownloadUrlFromRepositoryUrl('git://github.com/some-user/my-repo.git'),
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`,
)
})
test('generateDownloadUrlFromRepositoryUrl: should extract repo from git+ssh:// url', (t) => {
t.is(
generateDownloadUrlFromRepositoryUrl('git+ssh://github.com/some-user/my-repo.git'),
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`
`https://raw.githubusercontent.com/some-user/my-repo/stubreleaseBranch/stubid.user.js`,
)
})
test('generateDownloadUrlFromRepositoryUrl: should return empty string if non-git url', (t) => {
Expand Down
6 changes: 3 additions & 3 deletions test/src/lib/get-elements-by-xpaths.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test.beforeEach(() => {
</ol>
</span>
<div id='42'></div>
</div>
</div>,
)
container = result.container
})
Expand All @@ -34,7 +34,7 @@ test.serial('getElementsByXpath: should return array with the matching nodes in
<li>One</li>
<li>Two</li>
<li>Three</li>
</>
</>,
)
const expected = [
expectedSnap.container.childNodes.item(0),
Expand All @@ -53,7 +53,7 @@ test.serial('getElementsByXpath: should work without parent element and use docu
<li>One</li>
<li>Two</li>
<li>Three</li>
</>
</>,
)
const expected = [
expectedSnap.container.childNodes.item(0),
Expand Down
Loading

0 comments on commit 1fefa68

Please sign in to comment.