From b9bb109f4a68379a1c1ed72d505d6b09e15ff847 Mon Sep 17 00:00:00 2001 From: Ahmed Sbai <30757139+sbaiahmed1@users.noreply.github.com> Date: Mon, 31 Mar 2025 07:44:10 +0200 Subject: [PATCH] chore: linting fixes && github actions for linting (#612) --- .github/workflows/lint.yaml | 28 +++ README.md | 1 + app/(auth)/(tabs)/(custom-links)/index.tsx | 4 +- app/(auth)/(tabs)/(favorites)/_layout.tsx | 2 +- app/(auth)/(tabs)/(home)/_layout.tsx | 2 +- .../(tabs)/(home)/downloads/[seriesId].tsx | 2 +- app/(auth)/(tabs)/(home)/sessions/index.tsx | 36 ++- .../(tabs)/(home)/settings/logs/page.tsx | 107 +++++---- .../(home)/settings/marlin-search/page.tsx | 2 +- .../(home)/settings/optimized-server/page.tsx | 2 +- .../actors/[actorId].tsx | 2 +- .../collections/[collectionId].tsx | 5 +- .../items/page.tsx | 22 +- .../jellyseerr/company/[companyId].tsx | 8 +- .../jellyseerr/genre/[genreId].tsx | 2 +- .../jellyseerr/page.tsx | 2 +- .../livetv/guide.tsx | 2 +- .../series/[id].tsx | 58 +++-- app/(auth)/(tabs)/(libraries)/[libraryId].tsx | 5 +- app/(auth)/(tabs)/(libraries)/_layout.tsx | 10 +- app/(auth)/(tabs)/(libraries)/index.tsx | 2 +- app/(auth)/(tabs)/(search)/_layout.tsx | 4 +- app/(auth)/(tabs)/(search)/index.tsx | 226 +++++++++--------- app/(auth)/(tabs)/_layout.tsx | 12 +- app/_layout.tsx | 37 +-- app/login.tsx | 20 +- augmentations/number.ts | 4 +- biome.json | 13 +- components/Button.tsx | 4 +- components/ContinueWatchingPoster.tsx | 55 +++-- components/ItemContent.tsx | 30 ++- components/ItemTechnicalDetails.tsx | 2 +- components/MoreMoviesWithActor.tsx | 3 +- components/PlayButton.tsx | 4 +- components/PlayButton.tv.tsx | 4 +- components/WatchedIndicator.tsx | 2 +- components/__tests__/ThemedText-test.tsx | 2 +- components/_template.tsx | 2 +- components/common/Dropdown.tsx | 4 +- components/common/HorrizontalScroll.tsx | 10 +- .../common/InfiniteHorrizontalScroll.tsx | 7 +- components/common/ItemImage.tsx | 2 +- components/common/LargePoster.tsx | 2 +- components/common/Text.tsx | 16 +- components/common/VerticalSkeleton.tsx | 8 +- components/downloads/ActiveDownloads.tsx | 4 +- components/downloads/SeriesCard.tsx | 2 +- components/filters/FilterButton.tsx | 2 +- components/filters/FilterSheet.tsx | 10 +- components/home/ScrollingCollectionList.tsx | 2 +- components/inputs/Stepper.tsx | 5 +- components/jellyseerr/JellyseerrIndexPage.tsx | 8 +- .../jellyseerr/JellyseerrStatusIcon.tsx | 2 +- components/jellyseerr/ParallaxSlideShow.tsx | 6 +- components/jellyseerr/RequestModal.tsx | 2 +- components/jellyseerr/discover/GenreSlide.tsx | 2 +- .../discover/RecentRequestsSlide.tsx | 2 +- components/jellyseerr/discover/Slide.tsx | 2 +- components/posters/EpisodePoster.tsx | 6 +- components/posters/ItemPoster.tsx | 2 +- components/posters/JellyseerrPoster.tsx | 2 +- components/posters/MoviePoster.tsx | 6 +- components/posters/ParentPoster.tsx | 2 +- components/posters/Poster.tsx | 2 +- components/posters/SeriesPoster.tsx | 4 +- components/search/LoadingSkeleton.tsx | 4 +- components/series/NextItemButton.tsx | 2 +- components/series/SeasonPicker.tsx | 2 +- components/settings/Dashboard.tsx | 2 +- components/settings/DownloadSettings.tsx | 2 +- components/settings/HomeIndex.tsx | 18 +- components/settings/OptimizedServerForm.tsx | 2 +- components/settings/StorageSettings.tsx | 4 +- .../video-player/controls/EpisodeList.tsx | 2 +- .../video-player/controls/SliderScrubbter.tsx | 2 +- .../controls/contexts/VideoContext.tsx | 2 +- .../video-player/controls/useTapDetection.tsx | 4 +- components/vlc/VideoDebugInfo.tsx | 22 +- hooks/useDownloadedFileOpener.ts | 2 +- hooks/useImageColors.ts | 4 +- hooks/useJellyseerr.ts | 55 ++--- modules/VlcPlayer.types.ts | 4 +- modules/VlcPlayerView.tsx | 10 +- package.json | 6 +- plugins/withChangeNativeAndroidTextToWhite.js | 4 +- plugins/withTrustLocalCerts.js | 4 +- providers/DownloadProvider.tv.tsx | 2 +- providers/JellyfinProvider.tsx | 16 +- scripts/symlink-native-dirs.js | 8 +- utils/OrientationLockConverter.ts | 1 - utils/_jellyseerr/useJellyseerrCanRequest.ts | 4 +- utils/atoms/primaryColor.ts | 2 +- utils/bToMb.ts | 7 +- utils/bitrate.ts | 2 +- utils/collectionTypeToItemType.ts | 4 +- utils/getItemImage.ts | 6 +- utils/hls/parseM3U8ForSubtitles.ts | 12 +- utils/jellyfin/image/getBackdropUrl.ts | 3 +- utils/jellyfin/image/getLogoImageUrlById.ts | 2 +- utils/jellyfin/image/getPrimaryImageUrl.ts | 2 +- utils/jellyfin/media/getStreamUrl.ts | 49 ++-- utils/log.tsx | 2 +- utils/streamRanker.ts | 36 ++- utils/textTools.ts | 2 +- utils/time.ts | 7 +- 105 files changed, 604 insertions(+), 570 deletions(-) create mode 100644 .github/workflows/lint.yaml diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 00000000..d63811e7 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,28 @@ +name: Lint + +on: + pull_request: + branches: [ develop, master ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '20.x' + + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Run linting checks + run: bun run check diff --git a/README.md b/README.md index cd578d84..30f63546 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ We welcome any help to make Streamyfin better. If you'd like to contribute, plea 1. Use node `>20` 2. Install dependencies `bun i && bun run submodule-reload` 3. Make sure you have xcode and/or android studio installed. (follow the guides for expo: https://docs.expo.dev/workflow/android-studio-emulator/) +4. Install BiomeJS extension in VSCode/Your IDE (https://biomejs.dev/) 4. run `npm run prebuild` 5. Create an expo dev build by running `npm run ios` or `npm run android`. This will open a simulator on your computer and run the app. diff --git a/app/(auth)/(tabs)/(custom-links)/index.tsx b/app/(auth)/(tabs)/(custom-links)/index.tsx index 251b12e6..d6b34fb2 100644 --- a/app/(auth)/(tabs)/(custom-links)/index.tsx +++ b/app/(auth)/(tabs)/(custom-links)/index.tsx @@ -26,11 +26,11 @@ export default function menuLinks() { const getMenuLinks = useCallback(async () => { try { const response = await api?.axiosInstance.get( - api?.basePath + "/web/config.json", + `${api?.basePath}/web/config.json`, ); const config = response?.data; - if (!config && !config.hasOwnProperty("menuLinks")) { + if (!config && !Object.hasOwn(config, "menuLinks")) { console.error("Menu links not found"); return; } diff --git a/app/(auth)/(tabs)/(favorites)/_layout.tsx b/app/(auth)/(tabs)/(favorites)/_layout.tsx index ba0844d8..82df4a12 100644 --- a/app/(auth)/(tabs)/(favorites)/_layout.tsx +++ b/app/(auth)/(tabs)/(favorites)/_layout.tsx @@ -17,7 +17,7 @@ export default function SearchLayout() { backgroundColor: "black", }, headerBlurEffect: "prominent", - headerTransparent: Platform.OS === "ios" ? true : false, + headerTransparent: Platform.OS === "ios", headerShadowVisible: false, }} /> diff --git a/app/(auth)/(tabs)/(home)/_layout.tsx b/app/(auth)/(tabs)/(home)/_layout.tsx index 0d533ac9..86ae2cbe 100644 --- a/app/(auth)/(tabs)/(home)/_layout.tsx +++ b/app/(auth)/(tabs)/(home)/_layout.tsx @@ -32,7 +32,7 @@ export default function IndexLayout() { {!Platform.isTV && ( <> - {user && user.Policy?.IsAdministrator && } + {user?.Policy?.IsAdministrator && } )} diff --git a/app/(auth)/(tabs)/(home)/downloads/[seriesId].tsx b/app/(auth)/(tabs)/(home)/downloads/[seriesId].tsx index 59d111f4..9e617d67 100644 --- a/app/(auth)/(tabs)/(home)/downloads/[seriesId].tsx +++ b/app/(auth)/(tabs)/(home)/downloads/[seriesId].tsx @@ -29,7 +29,7 @@ export default function page() { try { return ( downloadedFiles - ?.filter((f) => f.item.SeriesId == seriesId) + ?.filter((f) => f.item.SeriesId === seriesId) ?.sort( (a, b) => a?.item.ParentIndexNumber! - b.item.ParentIndexNumber!, ) || [] diff --git a/app/(auth)/(tabs)/(home)/sessions/index.tsx b/app/(auth)/(tabs)/(home)/sessions/index.tsx index 590d89db..6c589f40 100644 --- a/app/(auth)/(tabs)/(home)/sessions/index.tsx +++ b/app/(auth)/(tabs)/(home)/sessions/index.tsx @@ -36,7 +36,7 @@ export default function page() { ); - if (!sessions || sessions.length == 0) + if (!sessions || sessions.length === 0) return ( @@ -175,7 +175,7 @@ const SessionCard = ({ session }: SessionCardProps) => { { const videoStream = useMemo(() => { return session.NowPlayingItem?.MediaStreams?.filter( - (s) => s.Type == "Video", + (s) => s.Type === "Video", )[0]; }, [session]); @@ -318,7 +318,7 @@ const TranscodingView = ({ session }: SessionCardProps) => { const isTranscoding = useMemo(() => { return ( - session.PlayState?.PlayMethod == "Transcode" && session.TranscodingInfo + session.PlayState?.PlayMethod === "Transcode" && session.TranscodingInfo ); }, [session.PlayState?.PlayMethod, session.TranscodingInfo]); @@ -341,9 +341,7 @@ const TranscodingView = ({ session }: SessionCardProps) => { codec: session.TranscodingInfo?.VideoCodec, }} isTranscoding={ - isTranscoding && !session.TranscodingInfo?.IsVideoDirect - ? true - : false + !!(isTranscoding && !session.TranscodingInfo?.IsVideoDirect) } /> @@ -360,24 +358,20 @@ const TranscodingView = ({ session }: SessionCardProps) => { audioChannels: session.TranscodingInfo?.AudioChannels?.toString(), }} isTranscoding={ - isTranscoding && !session.TranscodingInfo?.IsVideoDirect - ? true - : false + !!(isTranscoding && !session.TranscodingInfo?.IsVideoDirect) } /> {subtitleStream && ( - <> - - + )} ); diff --git a/app/(auth)/(tabs)/(home)/settings/logs/page.tsx b/app/(auth)/(tabs)/(home)/settings/logs/page.tsx index 1e90983e..df09611b 100644 --- a/app/(auth)/(tabs)/(home)/settings/logs/page.tsx +++ b/app/(auth)/(tabs)/(home)/settings/logs/page.tsx @@ -1,73 +1,77 @@ +import { Loader } from "@/components/Loader"; import { Text } from "@/components/common/Text"; -import {LogLevel, useLog, writeErrorLog} from "@/utils/log"; +import { FilterButton } from "@/components/filters/FilterButton"; +import { LogLevel, useLog, writeErrorLog } from "@/utils/log"; +import * as FileSystem from "expo-file-system"; +import { useNavigation } from "expo-router"; +import * as Sharing from "expo-sharing"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; -import {ScrollView, TouchableOpacity, View} from "react-native"; +import { ScrollView, TouchableOpacity, View } from "react-native"; import Collapsible from "react-native-collapsible"; -import React, {useCallback, useEffect, useMemo, useState} from "react"; -import {FilterButton} from "@/components/filters/FilterButton"; -import {useNavigation} from "expo-router"; -import * as FileSystem from 'expo-file-system'; -import * as Sharing from 'expo-sharing'; -import {Loader} from "@/components/Loader"; export default function page() { const navigation = useNavigation(); const { logs } = useLog(); const { t } = useTranslation(); - const defaultLevels: LogLevel[] = ["INFO", "ERROR", "DEBUG", "WARN"] + const defaultLevels: LogLevel[] = ["INFO", "ERROR", "DEBUG", "WARN"]; const codeBlockStyle = { - backgroundColor: '#000', + backgroundColor: "#000", padding: 10, - fontFamily: 'monospace', - maxHeight: 300 - } + fontFamily: "monospace", + maxHeight: 300, + }; - const [loading, setLoading] = useState(false) - const [state, setState] = useState>({}) + const [loading, setLoading] = useState(false); + const [state, setState] = useState>({}); const [order, setOrder] = useState<"asc" | "desc">("desc"); const [levels, setLevels] = useState(defaultLevels); const filteredLogs = useMemo( - () => logs - ?.filter(log => levels.includes(log.level)) - // Already in asc order as they are recorded. just reverse for desc - ?.[order === "desc" ? "reverse" : "concat"]?.(), - [logs, order, levels] - ) + () => + logs + ?.filter((log) => levels.includes(log.level)) + ?.[ + // Already in asc order as they are recorded. just reverse for desc + order === "desc" ? "reverse" : "concat" + ]?.(), + [logs, order, levels], + ); // Sharing it as txt while its formatted allows us to share it with many more applications const share = useCallback(async () => { - const uri = FileSystem.documentDirectory + "logs.txt" + const uri = `${FileSystem.documentDirectory}logs.txt`; - setLoading(true) + setLoading(true); FileSystem.writeAsStringAsync(uri, JSON.stringify(filteredLogs)) .then(() => { - setLoading(false) - Sharing.shareAsync(uri, {mimeType: "txt", UTI: "txt"}) + setLoading(false); + Sharing.shareAsync(uri, { mimeType: "txt", UTI: "txt" }); }) - .catch((e) => writeErrorLog("Something went wrong attempting to export", e)) - .finally(() => setLoading(false)) - }, [filteredLogs]) + .catch((e) => + writeErrorLog("Something went wrong attempting to export", e), + ) + .finally(() => setLoading(false)); + }, [filteredLogs]); useEffect(() => { navigation.setOptions({ - headerRight: () => ( - loading - ? - : ( + headerRight: () => + loading ? ( + + ) : ( {t("home.settings.logs.export_logs")} - ) - ), + ), }); }, [share, loading]); return ( <> - + {filteredLogs?.map((log, index) => ( - + setState((v) => ({...v, [log.timestamp]: !v[log.timestamp]}))} + onPress={() => + setState((v) => ({ + ...v, + [log.timestamp]: !v[log.timestamp], + })) + } > - + + `} + > {log.level} - {new Date(log.timestamp).toLocaleString()} + + {new Date(log.timestamp).toLocaleString()} + {log.message} @@ -121,14 +130,14 @@ export default function page() { {log.data && ( <> {!state[log.timestamp] && ( - {t("home.settings.logs.click_for_more_info")} + + {t("home.settings.logs.click_for_more_info")} + )} - - - - {JSON.stringify(log.data, null, 2)} - + + + {JSON.stringify(log.data, null, 2)} diff --git a/app/(auth)/(tabs)/(home)/settings/marlin-search/page.tsx b/app/(auth)/(tabs)/(home)/settings/marlin-search/page.tsx index c13390da..f061afbb 100644 --- a/app/(auth)/(tabs)/(home)/settings/marlin-search/page.tsx +++ b/app/(auth)/(tabs)/(home)/settings/marlin-search/page.tsx @@ -93,7 +93,7 @@ export default function page() { showText={!pluginSettings?.searchEngine?.locked} className='mt-2 flex flex-col rounded-xl overflow-hidden pl-4 bg-neutral-900 px-4' > - + {t("home.settings.plugins.marlin_search.url")} diff --git a/app/(auth)/(tabs)/(home)/settings/optimized-server/page.tsx b/app/(auth)/(tabs)/(home)/settings/optimized-server/page.tsx index 1c53d7e2..9fbc0a23 100644 --- a/app/(auth)/(tabs)/(home)/settings/optimized-server/page.tsx +++ b/app/(auth)/(tabs)/(home)/settings/optimized-server/page.tsx @@ -31,7 +31,7 @@ export default function page() { return; } - const updatedUrl = newVal.endsWith("/") ? newVal : newVal + "/"; + const updatedUrl = newVal.endsWith("/") ? newVal : `${newVal}/`; updateSettings({ optimizedVersionsServerUrl: updatedUrl, diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/actors/[actorId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/actors/[actorId].tsx index 1486581d..1e898c33 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/actors/[actorId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/actors/[actorId].tsx @@ -133,7 +133,7 @@ const page: React.FC = () => { queryFn={fetchItems} queryKey={["actor", "movies", actorId]} /> - + ); diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx index f1b48cbf..6add1ede 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/collections/[collectionId].tsx @@ -157,9 +157,8 @@ const page: React.FC = () => { if (accumulatedItems < totalItems) { return lastPage?.Items?.length * pages.length; - } else { - return undefined; } + return undefined; }, initialPageParam: 0, enabled: !!api && !!user?.Id && !!collection, @@ -412,7 +411,7 @@ const page: React.FC = () => { width: 10, height: 10, }} - > + /> )} /> ); diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/items/page.tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/items/page.tsx index 1f9d322b..b7c39f9f 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/items/page.tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/items/page.tsx @@ -93,19 +93,19 @@ const Page: React.FC = () => { height: item?.Type === "Episode" ? 300 : 450, }} className='bg-transparent rounded-lg mb-4 w-full' - > - - - + /> + + + - - - + + + - - - - + + + + {item && } diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx index 1f4b139d..8e744ee0 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/company/[companyId].tsx @@ -33,9 +33,11 @@ export default function page() { }; return jellyseerrApi?.discover( - (type == DiscoverSliderType.NETWORKS - ? Endpoints.DISCOVER_TV_NETWORK - : Endpoints.DISCOVER_MOVIES_STUDIO) + `/${companyId}`, + `${ + type === DiscoverSliderType.NETWORKS + ? Endpoints.DISCOVER_TV_NETWORK + : Endpoints.DISCOVER_MOVIES_STUDIO + }/${companyId}`, params, ); }, diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx index 0d94a9a5..368bc127 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/genre/[genreId].tsx @@ -36,7 +36,7 @@ export default function page() { }; return jellyseerrApi?.discover( - type == DiscoverSliderType.MOVIE_GENRES + type === DiscoverSliderType.MOVIE_GENRES ? Endpoints.DISCOVER_MOVIES : Endpoints.DISCOVER_TV, params, diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx index 845a7676..6629ef55 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx @@ -240,7 +240,7 @@ const Page: React.FC = () => { g.name) || []} /> {isLoading || isFetching ? ( - +