itube-specs 0.0.962 → 0.0.964

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.
@@ -145,8 +145,9 @@ function getValue(item: { title?: string; value?: string }) {
145
145
  object-fit: cover;
146
146
  object-position: center top;
147
147
 
148
- @include from-br(sm) {
149
- transition: var(--transition) transform;
148
+ /* Наезд картинки вдвое медленнее остальных переходов карточки — так в макете. */
149
+ @media (hover: hover) {
150
+ transition: .3s var(--ease-in-out) transform;
150
151
  }
151
152
  }
152
153
 
@@ -179,7 +180,7 @@ function getValue(item: { title?: string; value?: string }) {
179
180
  overflow: hidden;
180
181
  text-transform: capitalize;
181
182
 
182
- @include from-br(sm) {
183
+ @media (hover: hover) {
183
184
  transition: var(--transition) color;
184
185
  }
185
186
  }
@@ -0,0 +1,31 @@
1
+ import type { Language } from '../../runtime';
2
+ import { AsyncData } from '../../runtime';
3
+ import type { IVideoCard, PaginatedResponse } from '../../types';
4
+
5
+ export const useFetchVectorRelatedVideos = async (
6
+ apiMethod: (...args: any[]) => Promise<PaginatedResponse<IVideoCard>>
7
+ ) => {
8
+ const lang = useLang() as Language;
9
+ const mobile = !!useState<boolean>('isMobile').value;
10
+ const limit = mobile ? 6 : 14;
11
+ const slug = useSlug();
12
+ const key = AsyncData.VectorRelatedVideos;
13
+ const stateKey = computed(() => `data-${key}-${slug.value}-${lang}`);
14
+
15
+ const { data, status, error } = await useAsyncData<PaginatedResponse<IVideoCard>>(
16
+ stateKey.value,
17
+ () => {
18
+ if (!slug.value) return Promise.resolve(null as unknown as PaginatedResponse<IVideoCard>);
19
+
20
+ return useApiFetcher<PaginatedResponse<IVideoCard>>(
21
+ stateKey.value,
22
+ apiMethod,
23
+ limit,
24
+ lang,
25
+ slug.value
26
+ )();
27
+ }
28
+ );
29
+
30
+ return { data, status, error };
31
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.962",
4
+ "version": "0.0.964",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
@@ -34,6 +34,10 @@ const featureFlags = useRuntimeConfig().public.featureFlags;
34
34
 
35
35
  const pageName = useGetPureRouteName();
36
36
 
37
+ const fetchRelated = featureFlags.VectorRelatedVideosEnabled
38
+ ? useFetchVectorRelatedVideos(featureFlags.FetchByUrlEnabled ? VideosApiService.getVectorRelatedVideosByUrl : VideosApiService.getVectorRelatedVideosById)
39
+ : useFetchRelatedVideos(featureFlags.FetchByUrlEnabled ? VideosApiService.getRelatedVideosByUrl : VideosApiService.getRelatedVideosById);
40
+
37
41
  const [
38
42
  { data: videoData, status: statusVideo },
39
43
  { data: relatedVideos, status },
@@ -41,7 +45,7 @@ const [
41
45
  { data: dataModels },
42
46
  ] = await Promise.all([
43
47
  useFetchVideo(featureFlags.FetchByUrlEnabled ? VideosApiService.getVideoByUrl : VideosApiService.getVideoById),
44
- useFetchRelatedVideos(featureFlags.FetchByUrlEnabled ? VideosApiService.getRelatedVideosByUrl : VideosApiService.getRelatedVideosById),
48
+ fetchRelated,
45
49
  useFetchRelatedSearch(SearchApiService.getPhrases),
46
50
  useFetchTopModels(ModelsApiService.getTop, 24, AsyncData.TopModelsMore, String(pageName)),
47
51
  ]);
@@ -12,6 +12,7 @@ export const AsyncData = {
12
12
  ModelsByFirstLetter: 'models-by-first-letter',
13
13
  ModelsByFirstLetterChips: 'models-by-first-letter-chips',
14
14
  RelatedVideos: 'related-videos',
15
+ VectorRelatedVideos: 'vector-related-videos',
15
16
  RefererPhrases: 'referer-phrases-video',
16
17
  AsideVideos: 'aside-videos',
17
18
  TopModels: 'top-models',
@@ -0,0 +1,33 @@
1
+ import type { IVideoCard, IRawVideoCard } from '../../../../types';
2
+ import { trackExternalCall } from '../../../utils/metrics';
3
+ import { cleanVideoCard } from '../../../../runtime';
4
+
5
+ export default defineEventHandler(async (event) => {
6
+ const apiUrl = process.env.NUXT_PUBLIC_API_DOMAIN;
7
+
8
+ const query = getQuery(event);
9
+ const queryString = new URLSearchParams(query as Record<string, string>).toString();
10
+ const id = getRouterParam(event, 'id');
11
+ const url = `${apiUrl}/v1/videos-vectors/${id}/related${queryString ? `?${queryString}` : ''}`;
12
+
13
+ const clientHeaders = event.node.req.headers as HeadersInit;
14
+
15
+ // similarity service is optional: its outage must not take the whole video page down
16
+ const rawData = await trackExternalCall('video-vector-related', () =>
17
+ apiFetch(url, {
18
+ method: 'GET',
19
+ headers: clientHeaders,
20
+ })
21
+ ).catch(() => null);
22
+
23
+ const items: IRawVideoCard[] = rawData?.data?.items || [];
24
+
25
+ const cleanedItems: IVideoCard[] = items.map(cleanVideoCard);
26
+
27
+ return {
28
+ currentPage: rawData?.data?.current_page,
29
+ allPages: rawData?.data?.all_pages,
30
+ total: rawData?.data?.total,
31
+ items: cleanedItems,
32
+ };
33
+ });
@@ -0,0 +1,31 @@
1
+ import type { IVideoCard, IRawVideoCard } from '../../../../types';
2
+ import { trackExternalCall } from '../../../utils/metrics';
3
+ import { cleanVideoCard, getUrlWithProxiedParams } from '../../../../runtime';
4
+
5
+ export default defineEventHandler(async (event) => {
6
+ const apiUrl = process.env.NUXT_PUBLIC_API_DOMAIN;
7
+
8
+ const slug = getRouterParam(event, 'url');
9
+ const url = getUrlWithProxiedParams(`${apiUrl}/v1/videos-vectors/url/${slug}/related`, event);
10
+
11
+ const clientHeaders = event.node.req.headers as HeadersInit;
12
+
13
+ // similarity service is optional: its outage must not take the whole video page down
14
+ const rawData = await trackExternalCall('video-vector-related', () =>
15
+ apiFetch(url, {
16
+ method: 'GET',
17
+ headers: clientHeaders,
18
+ })
19
+ ).catch(() => null);
20
+
21
+ const items: IRawVideoCard[] = rawData?.data?.items || [];
22
+
23
+ const cleanedItems: IVideoCard[] = items.map(cleanVideoCard);
24
+
25
+ return {
26
+ currentPage: rawData?.data?.current_page,
27
+ allPages: rawData?.data?.all_pages,
28
+ total: rawData?.data?.total,
29
+ items: cleanedItems,
30
+ };
31
+ });
@@ -189,6 +189,53 @@ export class VideosApiService {
189
189
  );
190
190
  }
191
191
 
192
+ static async getVectorRelatedVideosById(
193
+ limit: number,
194
+ lang: Language,
195
+ id: string,
196
+ niche = NicheHelper.getSiteDefaultNiche(),
197
+ ): Promise<PaginatedResponse<IVideoCard>> {
198
+ return await ApiHelper.fetch(
199
+ `/videos/get-vector-related-videos-by-id/${id}`,
200
+ {
201
+ method: 'GET',
202
+ headers: {
203
+ 'X-Niche': niche,
204
+ 'X-Language': toHeaderLanguage(lang),
205
+ 'X-Cache-Time': '259200',
206
+ 'Content-Type': 'application/json',
207
+ },
208
+ params: {
209
+ limit,
210
+ },
211
+ },
212
+ useRuntimeConfig(),
213
+ );
214
+ }
215
+ static async getVectorRelatedVideosByUrl(
216
+ limit: number,
217
+ lang: Language,
218
+ url: string,
219
+ niche = NicheHelper.getSiteDefaultNiche(),
220
+ ): Promise<PaginatedResponse<IVideoCard>> {
221
+ return await ApiHelper.fetch(
222
+ `/videos/get-vector-related-videos-by-url/${url}`,
223
+ {
224
+ method: 'GET',
225
+ headers: {
226
+ 'X-Niche': niche,
227
+ 'X-Language': toHeaderLanguage(lang),
228
+ 'X-Cache-Time': '259200',
229
+ 'Content-Type': 'application/json',
230
+ },
231
+ params: {
232
+ limit,
233
+ },
234
+ },
235
+ useRuntimeConfig(),
236
+ );
237
+ }
238
+
192
239
  static async getVideoById(
193
240
  lang: Language,
194
241
  id: string,