@skills-store/rednote 0.1.14 → 0.1.16

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.
@@ -289,6 +289,96 @@ const rednotePostCommentSchema = new EntitySchema({
289
289
  }
290
290
  ]
291
291
  });
292
+ const rednoteProfileSchema = new EntitySchema({
293
+ name: 'RednoteProfileRecord',
294
+ tableName: 'rednote_profiles',
295
+ columns: {
296
+ id: {
297
+ type: String,
298
+ primary: true,
299
+ length: 16
300
+ },
301
+ userId: {
302
+ name: 'userid',
303
+ type: String
304
+ },
305
+ nickname: {
306
+ type: String,
307
+ nullable: true
308
+ },
309
+ desc: {
310
+ type: 'text',
311
+ nullable: true
312
+ },
313
+ avatar: {
314
+ type: String,
315
+ nullable: true
316
+ },
317
+ ipLocation: {
318
+ name: 'ip_location',
319
+ type: String,
320
+ nullable: true
321
+ },
322
+ gender: {
323
+ type: String,
324
+ nullable: true
325
+ },
326
+ follows: {
327
+ type: String,
328
+ nullable: true
329
+ },
330
+ fans: {
331
+ type: String,
332
+ nullable: true
333
+ },
334
+ interaction: {
335
+ type: String,
336
+ nullable: true
337
+ },
338
+ tags: {
339
+ type: 'simple-json',
340
+ nullable: true
341
+ },
342
+ fetchedAt: {
343
+ name: 'fetched_at',
344
+ type: Date
345
+ },
346
+ instanceName: {
347
+ name: 'instance_name',
348
+ type: String
349
+ },
350
+ raw: {
351
+ type: 'simple-json',
352
+ nullable: true
353
+ },
354
+ createdAt: {
355
+ name: 'created_at',
356
+ type: Date,
357
+ createDate: true
358
+ }
359
+ },
360
+ indices: [
361
+ {
362
+ name: 'IDX_rednote_profiles_userid_instance',
363
+ columns: [
364
+ 'userId',
365
+ 'instanceName'
366
+ ]
367
+ },
368
+ {
369
+ name: 'IDX_rednote_profiles_fetched_at',
370
+ columns: [
371
+ 'fetchedAt'
372
+ ]
373
+ },
374
+ {
375
+ name: 'IDX_rednote_profiles_instance',
376
+ columns: [
377
+ 'instanceName'
378
+ ]
379
+ }
380
+ ]
381
+ });
292
382
  let dataSourcePromise = null;
293
383
  function createRecordId() {
294
384
  return nanoid(16);
@@ -360,7 +450,8 @@ async function initializeDataSource() {
360
450
  entities: [
361
451
  rednotePostSchema,
362
452
  rednotePostDetailSchema,
363
- rednotePostCommentSchema
453
+ rednotePostCommentSchema,
454
+ rednoteProfileSchema
364
455
  ],
365
456
  synchronize: true,
366
457
  logging: false,
@@ -576,3 +667,98 @@ export async function findPersistedPostUrlByRecordId(instanceName, id) {
576
667
  });
577
668
  return row?.url ?? null;
578
669
  }
670
+ export async function persistProfile(input) {
671
+ const { instanceName, result } = input;
672
+ const { profile } = result;
673
+ const { user, notes, userId, url, fetchedAt } = profile;
674
+ const dataSource = await initializeRednoteDatabase();
675
+ await dataSource.transaction(async (manager)=>{
676
+ const profileRepository = manager.getRepository(rednoteProfileSchema);
677
+ const postRepository = manager.getRepository(rednotePostSchema);
678
+ await profileRepository.save(profileRepository.create({
679
+ id: createRecordId(),
680
+ userId,
681
+ nickname: user.nickname,
682
+ desc: user.desc,
683
+ avatar: user.avatar,
684
+ ipLocation: user.ipLocation,
685
+ gender: user.gender,
686
+ follows: toCountString(user.follows),
687
+ fans: toCountString(user.fans),
688
+ interaction: toCountString(user.interaction),
689
+ tags: user.tags,
690
+ fetchedAt: new Date(fetchedAt),
691
+ instanceName,
692
+ raw: user
693
+ }));
694
+ if (notes.length > 0) {
695
+ const noteIds = uniqueStrings(notes.map((note)=>note.id));
696
+ const existingRows = noteIds.length > 0 ? await postRepository.find({
697
+ where: {
698
+ instanceName,
699
+ noteId: In(noteIds)
700
+ }
701
+ }) : [];
702
+ const existingMap = new Map(existingRows.map((row)=>[
703
+ row.noteId,
704
+ row
705
+ ]));
706
+ const entities = notes.map((post)=>{
707
+ const existing = existingMap.get(post.id);
708
+ const image = extractPrimaryImage(post);
709
+ const authorNickname = firstNonEmpty(post.noteCard.user.nickname, post.noteCard.user.nickName);
710
+ return postRepository.create({
711
+ id: existing?.id ?? createRecordId(),
712
+ noteId: post.id,
713
+ title: coalesceValue(post.noteCard.displayTitle, existing?.title),
714
+ url: coalesceValue(post.url, existing?.url),
715
+ image: coalesceValue(image, existing?.image),
716
+ likeCount: coalesceValue(toCountString(post.noteCard.interactInfo.likedCount), existing?.likeCount),
717
+ commentCount: coalesceValue(toCountString(post.noteCard.interactInfo.commentCount), existing?.commentCount),
718
+ collectedCount: coalesceValue(toCountString(post.noteCard.interactInfo.collectedCount), existing?.collectedCount),
719
+ sharedCount: coalesceValue(toCountString(post.noteCard.interactInfo.sharedCount), existing?.sharedCount),
720
+ authorId: coalesceValue(post.noteCard.user.userId, existing?.authorId),
721
+ authorNickname: coalesceValue(authorNickname, existing?.authorNickname),
722
+ modelType: coalesceValue(post.modelType, existing?.modelType),
723
+ xsecToken: coalesceValue(post.xsecToken, existing?.xsecToken),
724
+ instanceName,
725
+ raw: post,
726
+ ...existing?.createdAt ? {
727
+ createdAt: existing.createdAt
728
+ } : {}
729
+ });
730
+ });
731
+ await postRepository.save(entities);
732
+ }
733
+ });
734
+ }
735
+ export async function getProfileHistory(instanceName, userId, options) {
736
+ const dataSource = await initializeRednoteDatabase();
737
+ const repository = dataSource.getRepository(rednoteProfileSchema);
738
+ const rows = await repository.find({
739
+ where: {
740
+ instanceName,
741
+ userId
742
+ },
743
+ order: {
744
+ fetchedAt: 'DESC'
745
+ },
746
+ take: options?.limit ?? 100
747
+ });
748
+ return rows.map((row)=>({
749
+ id: row.id,
750
+ userId: row.userId,
751
+ nickname: row.nickname,
752
+ desc: row.desc,
753
+ avatar: row.avatar,
754
+ ipLocation: row.ipLocation,
755
+ gender: row.gender,
756
+ follows: row.follows,
757
+ fans: row.fans,
758
+ interaction: row.interaction,
759
+ tags: row.tags,
760
+ fetchedAt: row.fetchedAt,
761
+ instanceName: row.instanceName,
762
+ createdAt: row.createdAt
763
+ }));
764
+ }
@@ -23,6 +23,9 @@ Usage:
23
23
  Options:
24
24
  --instance NAME Show status for a custom instance or default browser instance
25
25
  -h, --help Show this help
26
+
27
+ Notes:
28
+ When called without --instance, it uses the last connected instance from data.json (lastConnect).
26
29
  `);
27
30
  }
28
31
  function toInstanceState(instance) {
@@ -136,6 +139,7 @@ export async function getRednoteStatus(target) {
136
139
  checked
137
140
  });
138
141
  rednote = {
142
+ userId: checked.userId,
139
143
  loginStatus: checked.loginStatus,
140
144
  lastLoginAt: checked.lastLoginAt
141
145
  };
@@ -103,6 +103,7 @@ Usage:
103
103
  bun ./scripts/browser/connect-browser.ts [--instance NAME] [--browser chrome|edge|chromium|brave] [--user-data-dir PATH] [--force] [--port 9222]
104
104
 
105
105
  Notes:
106
+ When called without --instance, it uses the last connected instance from data.json (lastConnect).
106
107
  When using --instance without --port, the stored instance port from data.json is used.
107
108
  If no stored port exists yet, a random free port is assigned and saved for next time.
108
109
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skills-store/rednote",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {