Skip to content

Perf improvements#91

Merged
bartholomej merged 1 commit intomasterfrom
perf-improv
Feb 23, 2026
Merged

Perf improvements#91
bartholomej merged 1 commit intomasterfrom
perf-improv

Conversation

@bartholomej
Copy link
Copy Markdown
Owner

@bartholomej bartholomej commented Feb 23, 2026

Description

Performance improvements

Type of change

  • Bug fix
  • New feature
  • Refactoring (no functional changes)
  • Code style update
  • Build / CI related changes
  • Documentation update
  • Tests
  • Other

Related Issues

Checklist

  • I have performed a self-review of my code
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works

Summary by CodeRabbit

  • Refactor
    • Consolidated search result mapping to reduce duplication and simplify movie/TV processing.
    • Cached creator birthday/place/age lookups to avoid repeated work and speed creator rendering.
    • Precomputed localized creator labels to eliminate redundant localization calls.
    • Streamlined user ratings and reviews handling by clarifying and centralizing parameter usage.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 23, 2026

Warning

Rate limit exceeded

@bartholomej has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 32 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 694e415 and 32c2265.

📒 Files selected for processing (5)
  • src/helpers/movie.helper.ts
  • src/services/creator.service.ts
  • src/services/search.service.ts
  • src/services/user-ratings.service.ts
  • src/services/user-reviews.service.ts
📝 Walkthrough

Walkthrough

Refactors and micro-optimizations across helpers and services: precomputes localized creator labels, caches creator birthday info, centralizes movie-to-DTO mapping, and threads film type parameters into user-ratings and user-reviews builder methods (call sites updated accordingly).

Changes

Cohort / File(s) Summary
Movie helper
src/helpers/movie.helper.ts
Precomputes localized creator group labels (key→label pairs) and replaces repeated inline localization lookups in creators parsing.
Creator service
src/services/creator.service.ts
Caches getCreatorBirthdayInfo(asideEl) result in buildCreator and reuses it for birthday, birthplace and age fields to avoid repeated calls.
Search service
src/services/search.service.ts
Adds a reusable movieMapper to construct CSFDSearchMovie objects; replaces per-item pushes with map + spread for movies and TV series.
User ratings & reviews
src/services/user-ratings.service.ts, src/services/user-reviews.service.ts
Adds CSFDFilmTypes import and changes buildUserRatings / buildUserReviews signatures to accept type; updates all call sites to pass the computed type and uses the parameter instead of re-deriving it.

Sequence Diagram(s)

(none)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐇 I hopped through code with careful paws,

Cached birthdays, trimmed repeated calls.
Labels precomputed, mappers found their tune,
Types carried softly, like a silver moon.
✨ Hop, refactor, flourish — and debug soon!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete; it provides only "Performance improvements" as detail and lacks specifics about what was optimized, why, or the expected impact. Expand the Description section with concrete details: list the files modified, explain the specific optimizations (e.g., precomputed labels, function result caching), quantify expected improvements, and clarify the motivation.
Title check ❓ Inconclusive The title "Perf improvements" is vague and generic, using non-descriptive terms that don't convey specific information about which performance optimizations were made. Use a more specific title that identifies the primary optimization, such as "Refactor: precompute localized labels and cache expensive function calls" or "Optimize: reduce redundant localization and service calls".
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch perf-improv

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/services/search.service.ts (1)

63-74: Consider applying the same mapper pattern to the users block for consistency.

Movies and TV series now use .map() + spread, but users still uses forEach + push. A userMapper + users.push(...usersNode.map(userMapper)) would keep the style uniform. Low priority — purely a style nit.

Optional refactor
-    usersNode.forEach((m) => {
-      const url = getUserUrl(m);
-      users.push({
-        id: parseIdFromUrl(url),
-        user: getUser(m),
-        userRealName: getUserRealName(m),
-        avatar: getAvatar(m),
-        url: `${baseUrl}${url}`
-      });
-    });
+    const userMapper = (m: HTMLElement): CSFDSearchUser => {
+      const url = getUserUrl(m);
+      return {
+        id: parseIdFromUrl(url),
+        user: getUser(m),
+        userRealName: getUserRealName(m),
+        avatar: getAvatar(m),
+        url: `${baseUrl}${url}`
+      };
+    };
+
+    users.push(...usersNode.map(userMapper));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/search.service.ts` around lines 63 - 74, Replace the users
forEach block with a mapper function to match the tvSeries pattern: create a
userMapper that accepts a node (same shape as used in usersNode) and returns an
object with id: parseIdFromUrl(getUserUrl(m)), user: getUser(m), userRealName:
getUserRealName(m), avatar: getAvatar(m), url: `${baseUrl}${getUserUrl(m)}`,
then replace the forEach+push loop by users.push(...usersNode.map(userMapper))
so usersNode, getUserUrl, parseIdFromUrl, getUser, getUserRealName, getAvatar,
baseUrl and the users array are used consistently.
src/helpers/movie.helper.ts (1)

344-348: Array.from is redundant here.

node-html-parser's querySelectorAll already returns HTMLElement[]. The Array.from wrap is harmless but unnecessary.

Also, the return type is declared as HTMLElement, but the function can return undefined (when find has no match, ?.parentNode yields undefined). The as HTMLElement cast silently converts this. Callers do guard with ?., so it works in practice, but a more honest signature would be HTMLElement | undefined.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/helpers/movie.helper.ts` around lines 344 - 348, The helper getBoxContent
unnecessarily wraps el.querySelectorAll in Array.from and unsafely casts the
possibly-undefined result to HTMLElement; remove the redundant Array.from and
change the function signature to return HTMLElement | undefined, and stop
force-casting the result—let headers be the querySelectorAll result and return
headers.find(... )?.parentNode (typed as possibly undefined) so callers can
continue to guard with optional chaining.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/helpers/movie.helper.ts`:
- Around line 344-348: The helper getBoxContent unnecessarily wraps
el.querySelectorAll in Array.from and unsafely casts the possibly-undefined
result to HTMLElement; remove the redundant Array.from and change the function
signature to return HTMLElement | undefined, and stop force-casting the
result—let headers be the querySelectorAll result and return headers.find(...
)?.parentNode (typed as possibly undefined) so callers can continue to guard
with optional chaining.

In `@src/services/search.service.ts`:
- Around line 63-74: Replace the users forEach block with a mapper function to
match the tvSeries pattern: create a userMapper that accepts a node (same shape
as used in usersNode) and returns an object with id:
parseIdFromUrl(getUserUrl(m)), user: getUser(m), userRealName:
getUserRealName(m), avatar: getAvatar(m), url: `${baseUrl}${getUserUrl(m)}`,
then replace the forEach+push loop by users.push(...usersNode.map(userMapper))
so usersNode, getUserUrl, parseIdFromUrl, getUser, getUserRealName, getAvatar,
baseUrl and the users array are used consistently.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05ec0e4 and 1127445.

📒 Files selected for processing (5)
  • src/helpers/movie.helper.ts
  • src/services/creator.service.ts
  • src/services/search.service.ts
  • src/services/user-ratings.service.ts
  • src/services/user-reviews.service.ts

@bartholomej bartholomej force-pushed the perf-improv branch 2 times, most recently from 694e415 to 2732b0d Compare February 23, 2026 11:56
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/helpers/movie.helper.ts (1)

304-317: Solid optimization; consider adding break to short-circuit the inner scan.

The precomputation of localizedLabels correctly reduces getLocalizedCreatorLabel calls from O(groups × keys) to O(keys) per invocation — good improvement.

Two minor follow-ups worth considering:

  1. The inner for...of over localizedLabels has no break after a match, so all 10 labels are still checked even once a group is matched. Since each DOM <h4> corresponds to at most one creator category (for a fixed language), a break is safe and makes the intent clearer.
  2. getLocalizedCreatorLabel is still called 10 times per getMovieCreators invocation (once per key), each time allocating the full three-language labels dictionary. Computing the language-specific sub-record once before the keys.map(...) could eliminate those repeated allocations entirely.
♻️ Optional: early-exit on match + single-pass label resolution
+  const lang = options?.language || 'cs';
+  // Resolve once: pick the language sub-record, fall back to Czech
+  // (mirrors the existing fallback logic inside getLocalizedCreatorLabel)
+  // If you prefer to keep the helper encapsulated, just add the break below.
+
   const localizedLabels = keys.map((key) => ({
     key,
-    label: getLocalizedCreatorLabel(options?.language, key) as string
+    label: getLocalizedCreatorLabel(lang, key) as string
   }));

   for (const group of groups) {
     const text = group.textContent.trim();
     for (const { key, label } of localizedLabels) {
       if (text.includes(label)) {
         if (group.parentNode) {
           creators[key] = parseMoviePeople(group.parentNode as HTMLElement);
         }
+        break; // each h4 maps to at most one creator category
       }
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/helpers/movie.helper.ts` around lines 304 - 317, The inner scan over
localizedLabels should short-circuit once a match is found and also avoid
repeated allocations from getLocalizedCreatorLabel: compute the
language-specific label map once (call getLocalizedCreatorLabel or equivalent to
build a per-language dictionary before keys.map) and use that in
localizedLabels, then inside the groups loop, after assigning creators[key] =
parseMoviePeople(group.parentNode as HTMLElement) add a break to stop checking
other labels for that group; update references to localizedLabels, keys.map,
getLocalizedCreatorLabel, groups, creators, and parseMoviePeople accordingly.
src/services/search.service.ts (1)

43-74: Clean deduplication via movieMapper; usersNode block is slightly inconsistent.

The movieMapper closure is a well-placed refactor — it eliminates the duplicated inline object construction for movies and TV series, and baseUrl captured in the closure is a const so there's no stale-reference risk.

The usersNode.forEach block (lines 63–72) is the only remaining call site that still uses the push-inside-forEach pattern rather than the new push(...node.map(mapper)) style. Not a bug, but worth aligning for consistency in a follow-up.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/search.service.ts` around lines 43 - 74, The usersNode.forEach
block is inconsistent with the refactor that introduced movieMapper; create a
userMapper (or reuse a closure) that builds the user object (using getUserUrl,
parseIdFromUrl, getUser, getUserRealName, getAvatar and baseUrl) and replace the
forEach push pattern with users.push(...usersNode.map(userMapper)) to match the
movies/tvSeries style and remove the push-inside-forEach anti-pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/helpers/movie.helper.ts`:
- Around line 304-317: The inner scan over localizedLabels should short-circuit
once a match is found and also avoid repeated allocations from
getLocalizedCreatorLabel: compute the language-specific label map once (call
getLocalizedCreatorLabel or equivalent to build a per-language dictionary before
keys.map) and use that in localizedLabels, then inside the groups loop, after
assigning creators[key] = parseMoviePeople(group.parentNode as HTMLElement) add
a break to stop checking other labels for that group; update references to
localizedLabels, keys.map, getLocalizedCreatorLabel, groups, creators, and
parseMoviePeople accordingly.

In `@src/services/search.service.ts`:
- Around line 43-74: The usersNode.forEach block is inconsistent with the
refactor that introduced movieMapper; create a userMapper (or reuse a closure)
that builds the user object (using getUserUrl, parseIdFromUrl, getUser,
getUserRealName, getAvatar and baseUrl) and replace the forEach push pattern
with users.push(...usersNode.map(userMapper)) to match the movies/tvSeries style
and remove the push-inside-forEach anti-pattern.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1127445 and 694e415.

📒 Files selected for processing (5)
  • src/helpers/movie.helper.ts
  • src/services/creator.service.ts
  • src/services/search.service.ts
  • src/services/user-ratings.service.ts
  • src/services/user-reviews.service.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/services/creator.service.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant