Correctly configure eslint & fix general issues
All checks were successful
Build and Push Container / build (push) Successful in 1m7s
All checks were successful
Build and Push Container / build (push) Successful in 1m7s
This commit is contained in:
parent
3b3f66645e
commit
ca0760ccb4
30
.eslintrc.js
30
.eslintrc.js
@ -1,29 +1,21 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
env: {
|
root: true,
|
||||||
browser: true,
|
|
||||||
es6: true,
|
|
||||||
node: true,
|
|
||||||
},
|
|
||||||
extends: ['prettier'],
|
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaFeatures: {
|
tsconfigRootDir: __dirname,
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
ecmaVersion: 2018,
|
|
||||||
sourceType: 'module',
|
|
||||||
project: './tsconfig.json',
|
project: './tsconfig.json',
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: ['@typescript-eslint'],
|
||||||
'@typescript-eslint/eslint-plugin',
|
extends: [
|
||||||
'prettier',
|
'prettier',
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
],
|
],
|
||||||
|
ignorePatterns: ['.eslintrc.js'],
|
||||||
rules: {
|
rules: {
|
||||||
camelcase: 'error',
|
'@typescript-eslint/unbound-method': 'off',
|
||||||
'@typescript-eslint/return-await': 'off',
|
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||||
'@typescript-eslint/camelcase': 'off',
|
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||||
'no-param-reassign': ['error', { props: false }],
|
|
||||||
'no-underscore-dangle': ['error', { allow: ['_id'] }],
|
|
||||||
},
|
},
|
||||||
reportUnusedDisableDirectives: true,
|
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,20 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 10.7.1
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '20.10.0'
|
||||||
|
|
||||||
|
- name: Lint & Test
|
||||||
|
run: |
|
||||||
|
pnpm install
|
||||||
|
pnpm run lint
|
||||||
|
pnpm run check
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
|
10
README.md
10
README.md
@ -11,7 +11,15 @@ pnpm run compile
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
Create a `config.json` in the root directory of the project, or alongside the script. It should look like the below example, you can add as many webhooks as you want. The Check Interval is how often the script will check for updates, in seconds.
|
Create a `config.json` in the root directory of the project, or alongside the script. It should look like the below example, you can add as many webhooks as you want, and as many MangaDex manga IDs as you want.
|
||||||
|
|
||||||
|
Manga IDs can be retrieved from the URL of the manga page on MangaDex, or by using the API.
|
||||||
|
|
||||||
|
```
|
||||||
|
https://mangadex.org/title/<manga-id>/<manga-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
The Check Interval is how often the script will check for updates, in seconds.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
13
package.json
13
package.json
@ -7,7 +7,9 @@
|
|||||||
"compile": "esbuild src/index.ts --bundle --outfile=.out/build.js --minify --sourcemap --platform=node --external:esbuild",
|
"compile": "esbuild src/index.ts --bundle --outfile=.out/build.js --minify --sourcemap --platform=node --external:esbuild",
|
||||||
"compile:watch": "esbuild src/index.ts --bundle --outfile=.out/build.js --sourcemap --platform=node --external:esbuild --watch",
|
"compile:watch": "esbuild src/index.ts --bundle --outfile=.out/build.js --sourcemap --platform=node --external:esbuild --watch",
|
||||||
"run": "node .out/build.js",
|
"run": "node .out/build.js",
|
||||||
"run:watch": "node --watch .out/build.js"
|
"run:watch": "node --watch .out/build.js",
|
||||||
|
"lint": "eslint src --ext .ts",
|
||||||
|
"check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "pfych <contact@pfy.ch>",
|
"author": "pfych <contact@pfy.ch>",
|
||||||
@ -16,15 +18,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash-es": "4.17.12",
|
"@types/lodash-es": "4.17.12",
|
||||||
"@types/node": "22.14.1",
|
"@types/node": "22.14.1",
|
||||||
"@typescript-eslint/eslint-plugin": "7.0.2",
|
|
||||||
"@typescript-eslint/parser": "7.0.2",
|
|
||||||
"@typescript-eslint/typescript-estree": "8.22.0",
|
|
||||||
"axios": "1.8.4",
|
"axios": "1.8.4",
|
||||||
"esbuild": "0.25.2",
|
"esbuild": "0.25.2",
|
||||||
"eslint": "8.25.0",
|
"@typescript-eslint/eslint-plugin": "7.2.0",
|
||||||
|
"@typescript-eslint/parser": "7.2.0",
|
||||||
|
"eslint": "8.57.0",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-import": "2.29.1",
|
|
||||||
"eslint-plugin-prettier": "5.1.3",
|
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"prettier": "3.5.3",
|
"prettier": "3.5.3",
|
||||||
"typescript": "5.8.3"
|
"typescript": "5.8.3"
|
||||||
|
1345
pnpm-lock.yaml
1345
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -21,14 +21,14 @@ export class lazyKv {
|
|||||||
|
|
||||||
async get<T>(key: string, fallback?: T): Promise<T> {
|
async get<T>(key: string, fallback?: T): Promise<T> {
|
||||||
const data = await readFile(this.path, 'utf-8');
|
const data = await readFile(this.path, 'utf-8');
|
||||||
const json = JSON.parse(data);
|
const json = JSON.parse(data) as Record<string, T>;
|
||||||
|
|
||||||
return json[key] ?? (fallback || null);
|
return json[key] ?? (fallback || null);
|
||||||
}
|
}
|
||||||
|
|
||||||
async set<T>(key: string, value: T): Promise<void> {
|
async set<T>(key: string, value: T): Promise<void> {
|
||||||
const data = await readFile(this.path, 'utf-8');
|
const data = await readFile(this.path, 'utf-8');
|
||||||
const json = JSON.parse(data);
|
const json = JSON.parse(data) as Record<string, T>;
|
||||||
|
|
||||||
json[key] = value;
|
json[key] = value;
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ export class lazyKv {
|
|||||||
|
|
||||||
async delete(key: string): Promise<void> {
|
async delete(key: string): Promise<void> {
|
||||||
const data = await readFile(this.path, 'utf-8');
|
const data = await readFile(this.path, 'utf-8');
|
||||||
const json = JSON.parse(data);
|
const json = JSON.parse(data) as Record<string, unknown>;
|
||||||
|
|
||||||
delete json[key];
|
delete json[key];
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ void (async () => {
|
|||||||
|
|
||||||
const manga = await getManga(mangaId);
|
const manga = await getManga(mangaId);
|
||||||
const chapters = await getAllChapters(mangaId);
|
const chapters = await getAllChapters(mangaId);
|
||||||
const latestChapter = await getLatestChapter(chapters);
|
const latestChapter = getLatestChapter(chapters);
|
||||||
const cover = await getCover(manga);
|
const cover = await getCover(manga);
|
||||||
|
|
||||||
if (lastChapterId !== latestChapter.id) {
|
if (lastChapterId !== latestChapter.id) {
|
||||||
@ -68,6 +68,6 @@ void (async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setInterval(async () => checkForUpdates(), checkInterval * 1000);
|
setInterval(() => void checkForUpdates(), checkInterval * 1000);
|
||||||
await checkForUpdates();
|
await checkForUpdates();
|
||||||
})();
|
})();
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { sleep } from '../utils/sleep';
|
import { sleep } from '../utils/sleep';
|
||||||
import { Chapter } from '../types';
|
import { Chapter } from '../types';
|
||||||
|
import { getUserAgent } from '../utils/user-agent';
|
||||||
|
|
||||||
export const getAllChapters = async (id: string): Promise<Chapter[]> => {
|
export const getAllChapters = async (id: string): Promise<Chapter[]> => {
|
||||||
let nextPage = false;
|
let nextPage = false;
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
|
|
||||||
let chapters: Chapter[] = [];
|
const chapters: Chapter[] = [];
|
||||||
do {
|
do {
|
||||||
const response = await axios.get<{
|
const response = await axios.get<{
|
||||||
data: Chapter[];
|
data: Chapter[];
|
||||||
@ -19,8 +20,7 @@ export const getAllChapters = async (id: string): Promise<Chapter[]> => {
|
|||||||
offset,
|
offset,
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent':
|
'User-Agent': getUserAgent(),
|
||||||
'Personal Chapter Update Tracker (Maintained by: https://pfy.ch)',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -41,9 +41,7 @@ export const getAllChapters = async (id: string): Promise<Chapter[]> => {
|
|||||||
return chapters;
|
return chapters;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getLatestChapter = async (
|
export const getLatestChapter = (chapters: Chapter[]): Chapter => {
|
||||||
chapters: Chapter[],
|
|
||||||
): Promise<Chapter> => {
|
|
||||||
let latestFoundByChapterNumber = {
|
let latestFoundByChapterNumber = {
|
||||||
id: '',
|
id: '',
|
||||||
chapter: 0,
|
chapter: 0,
|
||||||
@ -63,5 +61,5 @@ export const getLatestChapter = async (
|
|||||||
|
|
||||||
return chapters.find(
|
return chapters.find(
|
||||||
(chapter) => chapter.id === latestFoundByChapterNumber.id,
|
(chapter) => chapter.id === latestFoundByChapterNumber.id,
|
||||||
) as Chapter;
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Manga } from './manga';
|
import { Manga } from '../types';
|
||||||
|
import { getUserAgent } from '../utils/user-agent';
|
||||||
|
|
||||||
export const getCover = async (manga: Manga): Promise<string> => {
|
export const getCover = async (manga: Manga): Promise<string> => {
|
||||||
const coverId = Object.values(manga.relationships).find(
|
const coverId = Object.values(manga.relationships).find(
|
||||||
@ -10,15 +11,13 @@ export const getCover = async (manga: Manga): Promise<string> => {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await axios.get(
|
const response = await axios.get<{
|
||||||
`https://api.mangadex.org/cover/${coverId}`,
|
data: { attributes: { fileName: string } };
|
||||||
{
|
}>(`https://api.mangadex.org/cover/${coverId}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent':
|
'User-Agent': getUserAgent(),
|
||||||
'Personal Chapter Update Tracker (Maintained by: https://pfy.ch)',
|
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
return `https://mangadex.org/covers/${manga.id}/${response.data.data.attributes.fileName}`;
|
return `https://mangadex.org/covers/${manga.id}/${response.data.data.attributes.fileName}`;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Manga } from '../types';
|
import { Manga } from '../types';
|
||||||
|
import { getUserAgent } from '../utils/user-agent';
|
||||||
|
|
||||||
export const getManga = async (id: string): Promise<Manga> => {
|
export const getManga = async (id: string): Promise<Manga> => {
|
||||||
const response = await axios.get<{
|
const response = await axios.get<{
|
||||||
@ -9,8 +10,7 @@ export const getManga = async (id: string): Promise<Manga> => {
|
|||||||
total: number;
|
total: number;
|
||||||
}>(`https://api.mangadex.org/manga/${id}`, {
|
}>(`https://api.mangadex.org/manga/${id}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent':
|
'User-Agent': getUserAgent(),
|
||||||
'Personal Chapter Update Tracker (Maintained by: https://pfy.ch)',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
6
src/utils/user-agent.ts
Normal file
6
src/utils/user-agent.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export const getUserAgent = () => {
|
||||||
|
return (
|
||||||
|
process.env.USER_AGENT ||
|
||||||
|
'Personal Chapter Update Tracker (https://git.pfy.ch/pfych/chapter-tracker)'
|
||||||
|
);
|
||||||
|
};
|
@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Manga } from '../mangadex/manga';
|
import { Chapter, Manga } from '../types';
|
||||||
import { Chapter } from '../mangadex/chapters';
|
|
||||||
|
|
||||||
export const sendWebhook = async (args: {
|
export const sendWebhook = async (args: {
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"target": "es5",
|
||||||
"lib": ["dom", "dom.iterable", "es2021"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"sourceMap": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": false,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
@ -13,8 +14,8 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"outDir": "./out",
|
"jsx": "preserve"
|
||||||
},
|
},
|
||||||
"include": ["**/*.tsx", "**/*.ts"],
|
"include": ["**/*.ts"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user