@irfanshadikrishad/anilist 1.2.1-forbidden.1 → 1.2.1-forbidden.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -52
- package/bin/helpers/auth.d.ts +14 -3
- package/bin/helpers/auth.js +400 -222
- package/bin/helpers/lists.d.ts +4 -1
- package/bin/helpers/lists.js +247 -114
- package/bin/helpers/queries.d.ts +6 -3
- package/bin/helpers/queries.js +22 -3
- package/bin/helpers/types.d.ts +241 -4
- package/bin/helpers/validation.d.ts +29 -0
- package/bin/helpers/validation.js +117 -0
- package/bin/helpers/workers.d.ts +7 -5
- package/bin/helpers/workers.js +62 -6
- package/bin/index.js +34 -3
- package/package.json +84 -80
- package/assets/binance.jpg +0 -0
package/bin/helpers/types.d.ts
CHANGED
|
@@ -121,6 +121,29 @@ interface MediaEntry {
|
|
|
121
121
|
status: string;
|
|
122
122
|
hiddenFromStatusLists: boolean;
|
|
123
123
|
}
|
|
124
|
+
interface SaveTextActivityResponse {
|
|
125
|
+
data?: {
|
|
126
|
+
SaveTextActivity: {
|
|
127
|
+
id: number;
|
|
128
|
+
userId: number;
|
|
129
|
+
text: string;
|
|
130
|
+
createdAt: number;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
errors?: {
|
|
134
|
+
message: string;
|
|
135
|
+
}[];
|
|
136
|
+
}
|
|
137
|
+
interface MediaListCollectionResponse {
|
|
138
|
+
data?: {
|
|
139
|
+
MediaListCollection: {
|
|
140
|
+
lists: MediaList[];
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
errors?: {
|
|
144
|
+
message: string;
|
|
145
|
+
}[];
|
|
146
|
+
}
|
|
124
147
|
interface List {
|
|
125
148
|
name: string;
|
|
126
149
|
entries: MediaEntry[];
|
|
@@ -171,9 +194,9 @@ interface Myself {
|
|
|
171
194
|
}[];
|
|
172
195
|
}
|
|
173
196
|
interface DateMonthYear {
|
|
174
|
-
day?:
|
|
175
|
-
month?:
|
|
176
|
-
year?:
|
|
197
|
+
day?: number;
|
|
198
|
+
month?: number;
|
|
199
|
+
year?: number;
|
|
177
200
|
}
|
|
178
201
|
interface AnimeDetails {
|
|
179
202
|
data?: {
|
|
@@ -197,6 +220,17 @@ interface AnimeDetails {
|
|
|
197
220
|
message: string;
|
|
198
221
|
}[];
|
|
199
222
|
}
|
|
223
|
+
interface SaveMediaListEntryResponse {
|
|
224
|
+
data?: {
|
|
225
|
+
SaveMediaListEntry: {
|
|
226
|
+
id: number;
|
|
227
|
+
status: string;
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
errors?: {
|
|
231
|
+
message: string;
|
|
232
|
+
}[];
|
|
233
|
+
}
|
|
200
234
|
interface MediaListEntry {
|
|
201
235
|
id?: number;
|
|
202
236
|
media: {
|
|
@@ -212,4 +246,207 @@ interface MediaListEntry {
|
|
|
212
246
|
hiddenFromStatusLists?: boolean;
|
|
213
247
|
private?: boolean;
|
|
214
248
|
}
|
|
215
|
-
|
|
249
|
+
interface TheActivity {
|
|
250
|
+
type: string;
|
|
251
|
+
id: number;
|
|
252
|
+
message?: string;
|
|
253
|
+
createdAt: number;
|
|
254
|
+
recipient?: {
|
|
255
|
+
id: number;
|
|
256
|
+
name: string;
|
|
257
|
+
};
|
|
258
|
+
isLiked?: boolean;
|
|
259
|
+
user?: {
|
|
260
|
+
id?: number;
|
|
261
|
+
name?: string;
|
|
262
|
+
};
|
|
263
|
+
messenger?: {
|
|
264
|
+
name: string;
|
|
265
|
+
};
|
|
266
|
+
media?: {
|
|
267
|
+
title?: {
|
|
268
|
+
userPreferred: string;
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
progress?: string | null;
|
|
272
|
+
status?: string;
|
|
273
|
+
}
|
|
274
|
+
type UserActivitiesResponse = {
|
|
275
|
+
data?: {
|
|
276
|
+
Page: {
|
|
277
|
+
activities: Activity[];
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
errors?: {
|
|
281
|
+
message: string;
|
|
282
|
+
}[];
|
|
283
|
+
};
|
|
284
|
+
type UserResponse = {
|
|
285
|
+
data?: {
|
|
286
|
+
User: {
|
|
287
|
+
id: number;
|
|
288
|
+
name: string;
|
|
289
|
+
siteUrl: string;
|
|
290
|
+
donatorTier: string;
|
|
291
|
+
donatorBadge: string;
|
|
292
|
+
createdAt: number;
|
|
293
|
+
updatedAt: number;
|
|
294
|
+
isBlocked: boolean;
|
|
295
|
+
isFollower: boolean;
|
|
296
|
+
isFollowing: boolean;
|
|
297
|
+
options: {
|
|
298
|
+
profileColor: string;
|
|
299
|
+
timezone: string;
|
|
300
|
+
};
|
|
301
|
+
statistics: {
|
|
302
|
+
anime: {
|
|
303
|
+
count: number;
|
|
304
|
+
episodesWatched: number;
|
|
305
|
+
minutesWatched: number;
|
|
306
|
+
};
|
|
307
|
+
manga: {
|
|
308
|
+
count: number;
|
|
309
|
+
chaptersRead: number;
|
|
310
|
+
volumesRead: number;
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
errors?: {
|
|
316
|
+
message: string;
|
|
317
|
+
}[];
|
|
318
|
+
};
|
|
319
|
+
type UserFollower = {
|
|
320
|
+
data?: {
|
|
321
|
+
Page: {
|
|
322
|
+
pageInfo: {
|
|
323
|
+
total: number;
|
|
324
|
+
perPage: number;
|
|
325
|
+
currentPage: number;
|
|
326
|
+
lastPage: number;
|
|
327
|
+
hasNextPage: boolean;
|
|
328
|
+
};
|
|
329
|
+
followers: User[];
|
|
330
|
+
};
|
|
331
|
+
};
|
|
332
|
+
errors?: {
|
|
333
|
+
message: string;
|
|
334
|
+
}[];
|
|
335
|
+
};
|
|
336
|
+
type User = {
|
|
337
|
+
id: number;
|
|
338
|
+
name: string;
|
|
339
|
+
avatar: {
|
|
340
|
+
large: string;
|
|
341
|
+
medium: string;
|
|
342
|
+
};
|
|
343
|
+
bannerImage: string;
|
|
344
|
+
isFollower: boolean;
|
|
345
|
+
isFollowing: boolean;
|
|
346
|
+
};
|
|
347
|
+
type UserFollowing = {
|
|
348
|
+
data?: {
|
|
349
|
+
Page: {
|
|
350
|
+
pageInfo: {
|
|
351
|
+
total: number;
|
|
352
|
+
perPage: number;
|
|
353
|
+
currentPage: number;
|
|
354
|
+
lastPage: number;
|
|
355
|
+
hasNextPage: boolean;
|
|
356
|
+
};
|
|
357
|
+
following: User[];
|
|
358
|
+
};
|
|
359
|
+
};
|
|
360
|
+
errors?: {
|
|
361
|
+
message: string;
|
|
362
|
+
}[];
|
|
363
|
+
};
|
|
364
|
+
type AnimeSearchResponse = {
|
|
365
|
+
data?: {
|
|
366
|
+
Page: {
|
|
367
|
+
media: {
|
|
368
|
+
id: number;
|
|
369
|
+
title: MediaTitle;
|
|
370
|
+
startDate: DateMonthYear;
|
|
371
|
+
episodes: number;
|
|
372
|
+
status: string;
|
|
373
|
+
description: string;
|
|
374
|
+
}[];
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
errors?: {
|
|
378
|
+
message: string;
|
|
379
|
+
}[];
|
|
380
|
+
};
|
|
381
|
+
type LikeActivityResponse = {
|
|
382
|
+
data?: {
|
|
383
|
+
ToggleLike: {
|
|
384
|
+
id: number;
|
|
385
|
+
};
|
|
386
|
+
};
|
|
387
|
+
errors?: {
|
|
388
|
+
message: string;
|
|
389
|
+
}[];
|
|
390
|
+
};
|
|
391
|
+
type SpecificUserActivitiesResponse = {
|
|
392
|
+
data?: {
|
|
393
|
+
Page: {
|
|
394
|
+
pageInfo: {
|
|
395
|
+
total: number;
|
|
396
|
+
perPage: number;
|
|
397
|
+
currentPage: number;
|
|
398
|
+
lastPage: number;
|
|
399
|
+
hasNextPage: boolean;
|
|
400
|
+
};
|
|
401
|
+
activities: TheActivity[];
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
errors?: {
|
|
405
|
+
message: string;
|
|
406
|
+
}[];
|
|
407
|
+
};
|
|
408
|
+
type DeleteActivityResponse = {
|
|
409
|
+
data?: {
|
|
410
|
+
DeleteMediaListEntry: {
|
|
411
|
+
deleted: boolean;
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
errors?: {
|
|
415
|
+
message: string;
|
|
416
|
+
}[];
|
|
417
|
+
};
|
|
418
|
+
type ToggleFollowResponse = {
|
|
419
|
+
data?: {
|
|
420
|
+
ToggleFollow: {
|
|
421
|
+
id: number;
|
|
422
|
+
name: string;
|
|
423
|
+
isFollower: boolean;
|
|
424
|
+
isFollowing: boolean;
|
|
425
|
+
};
|
|
426
|
+
};
|
|
427
|
+
errors?: {
|
|
428
|
+
message: string;
|
|
429
|
+
}[];
|
|
430
|
+
};
|
|
431
|
+
type DeleteMediaListResponse = {
|
|
432
|
+
data?: {
|
|
433
|
+
DeleteMediaListEntry: {
|
|
434
|
+
deleted: boolean;
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
errors?: {
|
|
438
|
+
message: string;
|
|
439
|
+
}[];
|
|
440
|
+
};
|
|
441
|
+
type Activity = {
|
|
442
|
+
id: number;
|
|
443
|
+
type: string;
|
|
444
|
+
status: string;
|
|
445
|
+
progress: number | null;
|
|
446
|
+
media: {
|
|
447
|
+
id?: number;
|
|
448
|
+
title: MediaTitle;
|
|
449
|
+
};
|
|
450
|
+
createdAt: number;
|
|
451
|
+
};
|
|
452
|
+
export { Activity, AniListMediaStatus, AnimeDetails, AnimeList, AnimeSearchResponse, DateMonthYear, DeleteActivityResponse, DeleteMangaResponse, DeleteMediaListResponse, LikeActivityResponse, List, MALAnimeStatus, MALAnimeXML, MALMangaStatus, MalIdToAnilistIdResponse, MediaEntry, MediaList, MediaListCollectionResponse, MediaListEntry, MediaTitle, MediaWithProgress, Myself, SaveMediaListEntryResponse, SaveTextActivityResponse, SpecificUserActivitiesResponse, TheActivity, ToggleFollowResponse, User, UserActivitiesResponse, UserFollower, UserFollowing, UserResponse, saveAnimeWithProgressResponse, };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare class Validate {
|
|
2
|
+
/**
|
|
3
|
+
* Validate importable JSON file
|
|
4
|
+
* @param data string
|
|
5
|
+
* @returns boolean
|
|
6
|
+
*/
|
|
7
|
+
static Import_JSON(data: {
|
|
8
|
+
id: number;
|
|
9
|
+
}[]): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Validate if MyAnimeList Anime XML file is valid or not
|
|
12
|
+
* @param xmlData string
|
|
13
|
+
* @returns boolean
|
|
14
|
+
*/
|
|
15
|
+
static Import_AnimeXML(xmlData: string): Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* Validate if MyAnimeList Anime XML file is valid or not
|
|
18
|
+
* @param xmlData string
|
|
19
|
+
* @returns boolean
|
|
20
|
+
*/
|
|
21
|
+
static Import_MangaXML(xmlData: string): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Validate AniDB json-large file
|
|
24
|
+
* @param file string of anidb json-large
|
|
25
|
+
* @returns boolean
|
|
26
|
+
*/
|
|
27
|
+
static Import_AniDBJSONLarge(file: string): Promise<boolean>;
|
|
28
|
+
}
|
|
29
|
+
export { Validate };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { parseStringPromise } from "xml2js";
|
|
11
|
+
class Validate {
|
|
12
|
+
/**
|
|
13
|
+
* Validate importable JSON file
|
|
14
|
+
* @param data string
|
|
15
|
+
* @returns boolean
|
|
16
|
+
*/
|
|
17
|
+
static Import_JSON(data) {
|
|
18
|
+
return (Array.isArray(data) &&
|
|
19
|
+
data.every((item) => typeof item === "object" && item !== null && "id" in item));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate if MyAnimeList Anime XML file is valid or not
|
|
23
|
+
* @param xmlData string
|
|
24
|
+
* @returns boolean
|
|
25
|
+
*/
|
|
26
|
+
static Import_AnimeXML(xmlData) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
try {
|
|
29
|
+
const result = yield parseStringPromise(xmlData, { explicitArray: false });
|
|
30
|
+
if (!result || !result.myanimelist) {
|
|
31
|
+
console.error("Invalid XML structure: Missing 'myanimelist' root element.");
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const animeList = result.myanimelist.anime;
|
|
35
|
+
if (!animeList) {
|
|
36
|
+
console.error("Invalid XML structure: Missing 'anime' elements.");
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const animeArray = Array.isArray(animeList) ? animeList : [animeList];
|
|
40
|
+
const isValid = animeArray.every((anime) => {
|
|
41
|
+
const isValidId = anime.series_animedb_id && !isNaN(Number(anime.series_animedb_id));
|
|
42
|
+
const hasRequiredFields = anime.series_title && anime.my_status;
|
|
43
|
+
return isValidId && hasRequiredFields;
|
|
44
|
+
});
|
|
45
|
+
if (!isValid) {
|
|
46
|
+
console.error("Validation failed: Some anime entries are missing required fields or have invalid IDs.");
|
|
47
|
+
}
|
|
48
|
+
return isValid;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error("Error parsing or validating XML:", error);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Validate if MyAnimeList Anime XML file is valid or not
|
|
58
|
+
* @param xmlData string
|
|
59
|
+
* @returns boolean
|
|
60
|
+
*/
|
|
61
|
+
static Import_MangaXML(xmlData) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
try {
|
|
64
|
+
const result = yield parseStringPromise(xmlData, { explicitArray: false });
|
|
65
|
+
if (!result || !result.myanimelist) {
|
|
66
|
+
console.error("Invalid XML structure: Missing 'myanimelist' root element.");
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const mangaList = result.myanimelist.manga;
|
|
70
|
+
if (!mangaList) {
|
|
71
|
+
console.error("Invalid XML structure: Missing 'manga' elements.");
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const mangaArray = Array.isArray(mangaList) ? mangaList : [mangaList];
|
|
75
|
+
const isValid = mangaArray.every((manga) => {
|
|
76
|
+
const isValidId = manga.manga_mangadb_id && !isNaN(Number(manga.manga_mangadb_id));
|
|
77
|
+
const hasRequiredFields = manga.manga_title && manga.my_status;
|
|
78
|
+
return isValidId && hasRequiredFields;
|
|
79
|
+
});
|
|
80
|
+
if (!isValid) {
|
|
81
|
+
console.error("Validation failed: Some manga entries are missing required fields or have invalid IDs.");
|
|
82
|
+
}
|
|
83
|
+
return isValid;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error("Error parsing or validating XML:", error);
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Validate AniDB json-large file
|
|
93
|
+
* @param file string of anidb json-large
|
|
94
|
+
* @returns boolean
|
|
95
|
+
*/
|
|
96
|
+
static Import_AniDBJSONLarge(file) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
try {
|
|
99
|
+
if (!(file === null || file === void 0 ? void 0 : file.trim())) {
|
|
100
|
+
console.error("File content is empty or invalid.");
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const obj3ct = JSON.parse(file);
|
|
104
|
+
if (!obj3ct || !Array.isArray(obj3ct.anime)) {
|
|
105
|
+
console.error("Invalid JSON structure: Missing or malformed 'anime' array.");
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.error("Failed to parse JSON file:", error);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export { Validate };
|
package/bin/helpers/workers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MALAnimeStatus, MALMangaStatus, MediaWithProgress } from "./types.js";
|
|
1
|
+
import { MALAnimeStatus, MALMangaStatus, MediaWithProgress, TheActivity } from "./types.js";
|
|
2
2
|
declare const aniListEndpoint = "https://graphql.anilist.co";
|
|
3
3
|
declare const redirectUri = "https://anilist.co/api/v2/oauth/pin";
|
|
4
4
|
declare function getTitle(title: {
|
|
@@ -6,9 +6,9 @@ declare function getTitle(title: {
|
|
|
6
6
|
romaji?: string;
|
|
7
7
|
}): string;
|
|
8
8
|
declare function formatDateObject(dateObj: {
|
|
9
|
-
day?:
|
|
10
|
-
month?:
|
|
11
|
-
year?:
|
|
9
|
+
day?: number;
|
|
10
|
+
month?: number;
|
|
11
|
+
year?: number;
|
|
12
12
|
} | null): string;
|
|
13
13
|
declare function getNextSeasonAndYear(): {
|
|
14
14
|
nextSeason: string;
|
|
@@ -36,4 +36,6 @@ declare function createAnimeListXML(mediaWithProgress: MediaWithProgress[]): Pro
|
|
|
36
36
|
declare function createMangaListXML(mediaWithProgress: MediaWithProgress[]): Promise<string>;
|
|
37
37
|
declare function getCurrentPackageVersion(): string | null;
|
|
38
38
|
declare function timestampToTimeAgo(timestamp: number): string;
|
|
39
|
-
|
|
39
|
+
declare function activityBy(activity: TheActivity): string;
|
|
40
|
+
declare const anidbToanilistMapper: (romanjiName: string, year: number, englishName?: string) => Promise<number | null>;
|
|
41
|
+
export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
|
package/bin/helpers/workers.js
CHANGED
|
@@ -17,7 +17,9 @@ import { homedir } from "os";
|
|
|
17
17
|
import { join } from "path";
|
|
18
18
|
import process from "process";
|
|
19
19
|
import { Auth } from "./auth.js";
|
|
20
|
-
import {
|
|
20
|
+
import { fetcher } from "./fetcher.js";
|
|
21
|
+
import { animeSearchQuery } from "./queries.js";
|
|
22
|
+
import { MALAnimeStatus, MALMangaStatus, } from "./types.js";
|
|
21
23
|
const aniListEndpoint = `https://graphql.anilist.co`;
|
|
22
24
|
const redirectUri = "https://anilist.co/api/v2/oauth/pin";
|
|
23
25
|
function getTitle(title) {
|
|
@@ -160,12 +162,13 @@ function selectFile(fileType) {
|
|
|
160
162
|
return answers.fileName;
|
|
161
163
|
}
|
|
162
164
|
else {
|
|
163
|
-
|
|
165
|
+
console.error(`\nNo importable ${fileType} file(s) found in download folder.`);
|
|
166
|
+
return null;
|
|
164
167
|
}
|
|
165
168
|
}
|
|
166
169
|
catch (error) {
|
|
167
170
|
console.error("\nError selecting file:", error);
|
|
168
|
-
|
|
171
|
+
return null;
|
|
169
172
|
}
|
|
170
173
|
});
|
|
171
174
|
}
|
|
@@ -224,7 +227,9 @@ function createAnimeListXML(mediaWithProgress) {
|
|
|
224
227
|
PAUSED: MALAnimeStatus.ON_HOLD,
|
|
225
228
|
DROPPED: MALAnimeStatus.DROPPED,
|
|
226
229
|
};
|
|
227
|
-
|
|
230
|
+
// Filter out anime without malId
|
|
231
|
+
const filteredMedia = mediaWithProgress.filter((anime) => anime.malId);
|
|
232
|
+
const xmlEntries = filteredMedia.map((anime) => {
|
|
228
233
|
const malId = anime.malId;
|
|
229
234
|
const progress = anime.progress;
|
|
230
235
|
const episodes = anime.episodes;
|
|
@@ -257,7 +262,9 @@ function createMangaListXML(mediaWithProgress) {
|
|
|
257
262
|
PAUSED: MALMangaStatus.ON_HOLD,
|
|
258
263
|
DROPPED: MALMangaStatus.DROPPED,
|
|
259
264
|
};
|
|
260
|
-
|
|
265
|
+
// Filter out manga without malId
|
|
266
|
+
const filteredMedia = mediaWithProgress.filter((manga) => manga.malId);
|
|
267
|
+
const xmlEntries = filteredMedia.map((manga) => {
|
|
261
268
|
const malId = manga.malId;
|
|
262
269
|
const progress = manga.progress;
|
|
263
270
|
const chapters = manga.chapters;
|
|
@@ -314,4 +321,53 @@ function timestampToTimeAgo(timestamp) {
|
|
|
314
321
|
return `${years} year${years === 1 ? "" : "s"} ago`;
|
|
315
322
|
}
|
|
316
323
|
}
|
|
317
|
-
|
|
324
|
+
function activityBy(activity) {
|
|
325
|
+
var _a, _b, _c, _d;
|
|
326
|
+
if ((_a = activity === null || activity === void 0 ? void 0 : activity.messenger) === null || _a === void 0 ? void 0 : _a.name) {
|
|
327
|
+
return `[${activity.id}]\t${activity.messenger.name} messaged ${activity.recipient.name}`;
|
|
328
|
+
}
|
|
329
|
+
else if ((_c = (_b = activity === null || activity === void 0 ? void 0 : activity.media) === null || _b === void 0 ? void 0 : _b.title) === null || _c === void 0 ? void 0 : _c.userPreferred) {
|
|
330
|
+
if (activity.progress) {
|
|
331
|
+
return `[${activity.id}]\t${activity.user.name} ${activity.status} ${activity.progress} of ${activity.media.title.userPreferred}`;
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
return `[${activity.id}]\t${activity.user.name} ${activity.status} ${activity.media.title.userPreferred}`;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else if ((_d = activity === null || activity === void 0 ? void 0 : activity.user) === null || _d === void 0 ? void 0 : _d.name) {
|
|
338
|
+
return `[${activity.id}]\t${activity.user.name}`;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
return `[${activity === null || activity === void 0 ? void 0 : activity.id}] ???`;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const anidbToanilistMapper = (romanjiName, year, englishName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
345
|
+
const fetchAnime = (search) => __awaiter(void 0, void 0, void 0, function* () {
|
|
346
|
+
var _a;
|
|
347
|
+
try {
|
|
348
|
+
const response = yield fetcher(animeSearchQuery, {
|
|
349
|
+
search,
|
|
350
|
+
perPage: 50,
|
|
351
|
+
});
|
|
352
|
+
return ((_a = response.data) === null || _a === void 0 ? void 0 : _a.Page.media) || [];
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
console.error("Error fetching AniList data:", error);
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
// Search using romanjiName first
|
|
360
|
+
let results = yield fetchAnime(romanjiName);
|
|
361
|
+
// If no results, fallback to englishName
|
|
362
|
+
if (!results.length && englishName) {
|
|
363
|
+
results = yield fetchAnime(englishName);
|
|
364
|
+
}
|
|
365
|
+
// Match using year
|
|
366
|
+
for (const anime of results) {
|
|
367
|
+
if (anime.startDate.year === year) {
|
|
368
|
+
return anime.id;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
});
|
|
373
|
+
export { activityBy, anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
|
package/bin/index.js
CHANGED
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
import { Command } from "commander";
|
|
12
12
|
import process from "process";
|
|
13
|
-
import { Auth } from "./helpers/auth.js";
|
|
13
|
+
import { Auth, Social } from "./helpers/auth.js";
|
|
14
14
|
import { AniList } from "./helpers/lists.js";
|
|
15
15
|
import { getCurrentPackageVersion } from "./helpers/workers.js";
|
|
16
16
|
const cli = new Command();
|
|
@@ -206,8 +206,39 @@ cli
|
|
|
206
206
|
cli
|
|
207
207
|
.command("autolike")
|
|
208
208
|
.alias("al")
|
|
209
|
+
.option("-2, --v2", "Like the activities", false)
|
|
210
|
+
.option("-c, --count <number>", "Number of activities to like", "25")
|
|
209
211
|
.description("Autolike following or global activities.")
|
|
210
|
-
.action(() => __awaiter(void 0,
|
|
211
|
-
|
|
212
|
+
.action((_a) => __awaiter(void 0, [_a], void 0, function* ({ v2, count }) {
|
|
213
|
+
if (v2) {
|
|
214
|
+
yield Auth.LikeFollowingActivityV2(count);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
yield Auth.AutoLike();
|
|
218
|
+
}
|
|
219
|
+
}));
|
|
220
|
+
cli
|
|
221
|
+
.command("social")
|
|
222
|
+
.alias("sol")
|
|
223
|
+
.description("Automate your process")
|
|
224
|
+
.option("-f, --follow", "Follow the user whos following you.", false)
|
|
225
|
+
.option("-u, --unfollow", "Unfollow the user whos not following you.", false)
|
|
226
|
+
.action((_a) => __awaiter(void 0, [_a], void 0, function* ({ follow, unfollow }) {
|
|
227
|
+
if (!follow && !unfollow) {
|
|
228
|
+
console.error(`\nMust select an option, either --follow or --unfollow`);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
if (yield Auth.isLoggedIn()) {
|
|
232
|
+
if (follow) {
|
|
233
|
+
yield Social.follow();
|
|
234
|
+
}
|
|
235
|
+
else if (unfollow) {
|
|
236
|
+
yield Social.unfollow();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
console.error(`\nPlease login to use this feature.`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
212
243
|
}));
|
|
213
244
|
cli.parse(process.argv);
|