itube-specs 0.0.795 → 0.0.796

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.
Files changed (107) hide show
  1. package/composables/fetch/use-fetch-categories-by-letter.ts +15 -15
  2. package/composables/fetch/use-fetch-categories-by-phrase.ts +18 -18
  3. package/composables/fetch/use-fetch-categories-group-by-letter.ts +13 -13
  4. package/composables/fetch/use-fetch-channels-by-model.ts +18 -18
  5. package/composables/fetch/use-fetch-channels-by-name.ts +15 -15
  6. package/composables/fetch/use-fetch-channels-by-network-name.ts +30 -30
  7. package/composables/fetch/use-fetch-channels.ts +31 -31
  8. package/composables/fetch/use-fetch-dictionaries-countries.ts +13 -13
  9. package/composables/fetch/use-fetch-dictionaries-genders.ts +13 -13
  10. package/composables/fetch/use-fetch-groups-categories-lazy.ts +15 -15
  11. package/composables/fetch/use-fetch-groups-categories.ts +13 -13
  12. package/composables/fetch/use-fetch-model-by-name.ts +15 -15
  13. package/composables/fetch/use-fetch-models-by-category.ts +17 -17
  14. package/composables/fetch/use-fetch-models-by-channel.ts +17 -17
  15. package/composables/fetch/use-fetch-models-by-letter.ts +40 -40
  16. package/composables/fetch/use-fetch-models-by-phrases.ts +32 -32
  17. package/composables/fetch/use-fetch-models-by-tag.ts +1 -1
  18. package/composables/fetch/use-fetch-models-related.ts +24 -24
  19. package/composables/fetch/use-fetch-models.ts +38 -38
  20. package/composables/fetch/use-fetch-multi-suggest.ts +27 -27
  21. package/composables/fetch/use-fetch-playlists-by-id.ts +15 -15
  22. package/composables/fetch/use-fetch-playlists-by-niche.ts +30 -30
  23. package/composables/fetch/use-fetch-playlists-get-videos-by-id.ts +29 -29
  24. package/composables/fetch/use-fetch-related-searches.ts +11 -11
  25. package/composables/fetch/use-fetch-related-videos.ts +27 -27
  26. package/composables/fetch/use-fetch-top-chips-models.ts +15 -15
  27. package/composables/fetch/use-fetch-top-models.ts +19 -19
  28. package/composables/fetch/use-fetch-top-random-categories.ts +13 -13
  29. package/composables/fetch/use-fetch-top-random-full.ts +17 -17
  30. package/composables/fetch/use-fetch-video-referer-phrases.ts +34 -34
  31. package/composables/fetch/use-fetch-videos-by-categories.ts +34 -34
  32. package/composables/fetch/use-fetch-videos-by-channel.ts +34 -34
  33. package/composables/fetch/use-fetch-videos-by-model-and-channel.ts +40 -40
  34. package/composables/fetch/use-fetch-videos-by-model-and-tag.ts +40 -40
  35. package/composables/fetch/use-fetch-videos-by-model.ts +34 -34
  36. package/composables/fetch/use-fetch-videos-by-tag.ts +34 -34
  37. package/composables/fetch/use-fetch-videos-search-by-niche.ts +32 -32
  38. package/composables/use-api-fetcher-no-cache.ts +24 -24
  39. package/composables/use-api-fetcher.ts +19 -19
  40. package/composables/use-get-videos-filter-request.ts +28 -28
  41. package/composables/use-lang.ts +8 -8
  42. package/composables/use-meta.ts +54 -54
  43. package/composables/use-noindex.ts +8 -8
  44. package/composables/use-report-popup.ts +19 -19
  45. package/lib/contact-forms-scheme.ts +92 -92
  46. package/lib/contacts/report-issue-items.ts +3 -3
  47. package/lib/contacts/report-malware-items.ts +4 -4
  48. package/lib/contacts/report-reasons-items.ts +10 -10
  49. package/lib/contacts/report-wrong-items.ts +4 -4
  50. package/lib/report-forms-scheme.ts +259 -259
  51. package/lib/scheme/categories-navigation.ts +8 -8
  52. package/lib/scheme/select-added-items.ts +41 -41
  53. package/lib/scheme/select-duration-items.ts +35 -35
  54. package/nuxt.config.ts +18 -18
  55. package/package.json +1 -1
  56. package/runtime/constants/adverts.ts +5 -5
  57. package/runtime/constants/async-data.ts +57 -57
  58. package/runtime/constants/languages.ts +12 -12
  59. package/runtime/constants/niche.ts +3 -3
  60. package/runtime/constants/playlist-type.ts +2 -2
  61. package/runtime/utils/check-device-width.ts +18 -18
  62. package/runtime/utils/cleaners/clean-mini-category-card.ts +5 -5
  63. package/runtime/utils/cleaners/clean-model-card.ts +20 -20
  64. package/runtime/utils/cleaners/clean-video-data.ts +50 -50
  65. package/runtime/utils/converters/convert-date-to-timestamp.ts +22 -22
  66. package/runtime/utils/converters/convert-query-categories.ts +2 -2
  67. package/runtime/utils/converters/convert-string-array-to-chips.ts +6 -6
  68. package/runtime/utils/converters/convert-string.ts +0 -0
  69. package/runtime/utils/server/age.ts +55 -55
  70. package/runtime/utils/server/api-helper.ts +26 -26
  71. package/runtime/utils/server/get-url-with-proxied-params.ts +3 -3
  72. package/runtime/utils/server/server-api-helper.ts +15 -15
  73. package/runtime/utils/validate-email.ts +2 -2
  74. package/services/api/categories.service.ts +222 -222
  75. package/services/api/dictionaries.service.ts +28 -28
  76. package/services/api/models.service.ts +297 -297
  77. package/types/authorization-forms.d.ts +8 -8
  78. package/types/burger-menu-item.d.ts +5 -5
  79. package/types/change-email-form.d.ts +1 -1
  80. package/types/change-password-form.d.ts +2 -2
  81. package/types/chips-item.d.ts +8 -8
  82. package/types/contacts-scheme.d.ts +9 -9
  83. package/types/country.d.ts +5 -5
  84. package/types/fluid-player.d.ts +176 -176
  85. package/types/gender.d.ts +4 -4
  86. package/types/group-categories.d.ts +10 -10
  87. package/types/info-chips.d.ts +2 -2
  88. package/types/model-card.d.ts +15 -15
  89. package/types/model-filter-payload.d.ts +2 -2
  90. package/types/model-filter.d.ts +10 -10
  91. package/types/model-group.d.ts +4 -4
  92. package/types/model-tag.d.ts +3 -3
  93. package/types/playlist-short.d.ts +2 -2
  94. package/types/playlist-video-form.d.ts +7 -7
  95. package/types/popular-tags.d.ts +2 -2
  96. package/types/raw/raw-playlist-user.d.ts +20 -20
  97. package/types/raw/raw-thumbs-urls.d.ts +2 -2
  98. package/types/raw/raw-video-card.d.ts +70 -70
  99. package/types/raw/raw-video-data.d.ts +50 -50
  100. package/types/recovery-password-form.d.ts +2 -2
  101. package/types/report-request.d.ts +2 -2
  102. package/types/report-scheme.d.ts +18 -18
  103. package/types/request-filters.d.ts +10 -10
  104. package/types/request-pagination.d.ts +2 -2
  105. package/types/search-top-models.d.ts +4 -4
  106. package/types/site.d.ts +15 -15
  107. package/types/thumbs-urls.d.ts +1 -1
@@ -1,39 +1,39 @@
1
1
  import type { ISelectItem } from '../../types';
2
2
 
3
3
  export const selectDurationItems: Array<ISelectItem> = [
4
- {
5
- title: 'all',
6
- key: 'duration',
7
- value: 'all',
8
- },
9
- {
10
- title: 'less_10_minutes',
11
- key: 'duration',
12
- value: '600',
13
- query: '599s',
14
- },
15
- {
16
- title: '10_30_minutes',
17
- key: 'duration',
18
- value: '1800',
19
- query: ['600s', '1800s'],
20
- },
21
- {
22
- title: '30_45_minutes',
23
- key: 'duration',
24
- value: '2700',
25
- query: ['1800s', '2700s'],
26
- },
27
- {
28
- title: '45_1_hours',
29
- key: 'duration',
30
- value: '3600',
31
- query: ['2700s', '3600s'],
32
- },
33
- {
34
- title: 'other_1_hours',
35
- key: 'duration',
36
- value: '3601',
37
- query: '3601s',
38
- },
4
+ {
5
+ title: 'all',
6
+ key: 'duration',
7
+ value: 'all',
8
+ },
9
+ {
10
+ title: 'less_10_minutes',
11
+ key: 'duration',
12
+ value: '600',
13
+ query: '599s',
14
+ },
15
+ {
16
+ title: '10_30_minutes',
17
+ key: 'duration',
18
+ value: '1800',
19
+ query: ['600s', '1800s'],
20
+ },
21
+ {
22
+ title: '30_45_minutes',
23
+ key: 'duration',
24
+ value: '2700',
25
+ query: ['1800s', '2700s'],
26
+ },
27
+ {
28
+ title: '45_1_hours',
29
+ key: 'duration',
30
+ value: '3600',
31
+ query: ['2700s', '3600s'],
32
+ },
33
+ {
34
+ title: 'other_1_hours',
35
+ key: 'duration',
36
+ value: '3601',
37
+ query: '3601s',
38
+ },
39
39
  ];
package/nuxt.config.ts CHANGED
@@ -2,22 +2,22 @@ import { fileURLToPath } from 'node:url';
2
2
  import { defineNuxtConfig } from 'nuxt/config';
3
3
 
4
4
  export default defineNuxtConfig({
5
- modules: ['@nuxt/eslint', '@nuxt/icon', '@nuxtjs/i18n'],
6
- imports: {
7
- dirs: ['composables/**']
8
- },
9
- eslint: {
10
- config: {
11
- // Use the generated ESLint config for lint root project as well
12
- rootDir: fileURLToPath(new URL('..', import.meta.url))
13
- }
14
- },
15
- components: {
16
- dirs: [
17
- {
18
- path: './components',
19
- pathPrefix: true
20
- }
21
- ]
22
- },
5
+ modules: ['@nuxt/eslint', '@nuxt/icon', '@nuxtjs/i18n'],
6
+ imports: {
7
+ dirs: ['composables/**']
8
+ },
9
+ eslint: {
10
+ config: {
11
+ // Use the generated ESLint config for lint root project as well
12
+ rootDir: fileURLToPath(new URL('..', import.meta.url))
13
+ }
14
+ },
15
+ components: {
16
+ dirs: [
17
+ {
18
+ path: './components',
19
+ pathPrefix: true
20
+ }
21
+ ]
22
+ },
23
23
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.795",
4
+ "version": "0.0.796",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
@@ -1,8 +1,8 @@
1
1
  import type { Niche } from './niche';
2
2
 
3
3
  export const AdSpotType = {
4
- Primary: 0,
5
- Secondary: 1,
4
+ Primary: 0,
5
+ Secondary: 1,
6
6
  } as const;
7
7
 
8
8
  export type AdSpotType = typeof AdSpotType[keyof typeof AdSpotType];
@@ -10,9 +10,9 @@ export type AdSpotType = typeof AdSpotType[keyof typeof AdSpotType];
10
10
  export type AdsConfigType = Partial<Record<Niche, Record<AdSpotType, number | string>>>;
11
11
 
12
12
  export const AdBannerType = {
13
- NativeBottom: 'NativeBottom',
14
- NativePlayer: 'NativePlayer',
15
- NTV: 'NTV',
13
+ NativeBottom: 'NativeBottom',
14
+ NativePlayer: 'NativePlayer',
15
+ NTV: 'NTV',
16
16
  } as const;
17
17
 
18
18
  export type AdBannerType = typeof AdBannerType[keyof typeof AdBannerType];
@@ -1,61 +1,61 @@
1
1
  export const AsyncData = {
2
- Videos: 'videos',
3
- Video: 'video',
4
- VideosByTag: 'videos-by-tag',
5
- VideosByChannel: 'videos-by-channel',
6
- VideosByCategory: 'videos-by-category',
7
- VideosByModel: 'videos-by-model',
8
- VideosBySearch: 'videos-by-search',
9
- ModelsVideos: 'models-videos',
10
- ModelsByPhrases: 'models-phrases',
11
- Models: 'models',
12
- ModelsByFirstLetter: 'models-by-first-letter',
13
- ModelsByFirstLetterChips: 'models-by-first-letter-chips',
14
- RelatedVideos: 'related-videos',
15
- RefererPhrases: 'referer-phrases-video',
16
- AsideVideos: 'aside-videos',
17
- TopModels: 'top-models',
18
- TopModelsMore: 'top-models-more',
19
- TopChipsModels: 'top-chips-models',
20
- Model: 'model',
21
- ModelSTop: 'models-top',
22
- ModelsByName: 'models-by-name',
23
- Channels: 'channels',
24
- Channel: 'channel',
25
- ChannelByName: 'channel-by-name',
26
- ChannelsByNetworkName: 'channel-by-network-name',
27
- Categories: 'categories',
28
- CategoriesByPhrase: 'categories-by-phrase',
29
- CategoriesByName: 'categories-by-name',
30
- GroupsCategoriesFilter: 'groups-categories-filter',
31
- GroupsCategoriesByLetter: 'groups-categories-by-letter',
32
- GroupsCategoriesByLetterChips: 'groups-categories-by-letter-chips',
33
- RelatedSearch: 'related-search',
34
- MultiSuggestSearch: 'multi-suggest-search',
35
- MultiSuggestRouteSearch: 'multi-suggest-route-search',
36
- CategoriesByLetter: 'categories-by-letter',
37
- CategoriesTopRandom: 'categories-top-random',
38
- CategoriesRelated: 'categories-related',
39
- CategoriesTopRandomFull: 'categories-top-random-full',
40
- CategoriesTopRandomFooter: 'categories-top-random-footer',
41
- Countries: 'countries',
42
- Genders: 'genders',
43
- GetPlaylists: 'get-playlists',
44
- GetPlaylistsVideo: 'get-playlists-video',
45
- GetPlaylistsByNiche: 'get-playlists-by-niche',
46
- GetPlaylistsLikeNiche: 'get-playlists-like-niche',
47
- PostPlaylists: 'post-playlists',
48
- Profile: 'profile',
49
- PlaylistById: 'playlist-by-id',
50
- SetPlaylistView: 'set-playlist-view',
51
- PopularTagsByModel: 'popular-tags-by-model',
52
- PopularTagsByChannel: 'popular-tags-by-channel',
53
- ChannelsByModel: 'channels-by-model',
54
- VideosByModelAndChannel: 'videos-by-model-and-channel',
55
- VideosByModelAndTag: 'videos-by-model-and-tag',
56
- ModelsByCategory: 'models-by-category',
57
- ModelsByChannel: 'models-by-channel',
58
- ModelsByTag: 'models-by-tag',
2
+ Videos: 'videos',
3
+ Video: 'video',
4
+ VideosByTag: 'videos-by-tag',
5
+ VideosByChannel: 'videos-by-channel',
6
+ VideosByCategory: 'videos-by-category',
7
+ VideosByModel: 'videos-by-model',
8
+ VideosBySearch: 'videos-by-search',
9
+ ModelsVideos: 'models-videos',
10
+ ModelsByPhrases: 'models-phrases',
11
+ Models: 'models',
12
+ ModelsByFirstLetter: 'models-by-first-letter',
13
+ ModelsByFirstLetterChips: 'models-by-first-letter-chips',
14
+ RelatedVideos: 'related-videos',
15
+ RefererPhrases: 'referer-phrases-video',
16
+ AsideVideos: 'aside-videos',
17
+ TopModels: 'top-models',
18
+ TopModelsMore: 'top-models-more',
19
+ TopChipsModels: 'top-chips-models',
20
+ Model: 'model',
21
+ ModelSTop: 'models-top',
22
+ ModelsByName: 'models-by-name',
23
+ Channels: 'channels',
24
+ Channel: 'channel',
25
+ ChannelByName: 'channel-by-name',
26
+ ChannelsByNetworkName: 'channel-by-network-name',
27
+ Categories: 'categories',
28
+ CategoriesByPhrase: 'categories-by-phrase',
29
+ CategoriesByName: 'categories-by-name',
30
+ GroupsCategoriesFilter: 'groups-categories-filter',
31
+ GroupsCategoriesByLetter: 'groups-categories-by-letter',
32
+ GroupsCategoriesByLetterChips: 'groups-categories-by-letter-chips',
33
+ RelatedSearch: 'related-search',
34
+ MultiSuggestSearch: 'multi-suggest-search',
35
+ MultiSuggestRouteSearch: 'multi-suggest-route-search',
36
+ CategoriesByLetter: 'categories-by-letter',
37
+ CategoriesTopRandom: 'categories-top-random',
38
+ CategoriesRelated: 'categories-related',
39
+ CategoriesTopRandomFull: 'categories-top-random-full',
40
+ CategoriesTopRandomFooter: 'categories-top-random-footer',
41
+ Countries: 'countries',
42
+ Genders: 'genders',
43
+ GetPlaylists: 'get-playlists',
44
+ GetPlaylistsVideo: 'get-playlists-video',
45
+ GetPlaylistsByNiche: 'get-playlists-by-niche',
46
+ GetPlaylistsLikeNiche: 'get-playlists-like-niche',
47
+ PostPlaylists: 'post-playlists',
48
+ Profile: 'profile',
49
+ PlaylistById: 'playlist-by-id',
50
+ SetPlaylistView: 'set-playlist-view',
51
+ PopularTagsByModel: 'popular-tags-by-model',
52
+ PopularTagsByChannel: 'popular-tags-by-channel',
53
+ ChannelsByModel: 'channels-by-model',
54
+ VideosByModelAndChannel: 'videos-by-model-and-channel',
55
+ VideosByModelAndTag: 'videos-by-model-and-tag',
56
+ ModelsByCategory: 'models-by-category',
57
+ ModelsByChannel: 'models-by-channel',
58
+ ModelsByTag: 'models-by-tag',
59
59
  } as const;
60
60
 
61
61
  export type AsyncData = typeof AsyncData[keyof typeof AsyncData];
@@ -1,22 +1,22 @@
1
1
  export const Language = {
2
- English: 'en',
3
- German: 'de',
4
- Spanish: 'es',
5
- Korean: 'ko',
6
- Japanese: 'ja',
7
- Italian: 'it',
8
- French: 'fr',
9
- Russian: 'ru',
10
- Chinese: 'zh',
2
+ English: 'en',
3
+ German: 'de',
4
+ Spanish: 'es',
5
+ Korean: 'ko',
6
+ Japanese: 'ja',
7
+ Italian: 'it',
8
+ French: 'fr',
9
+ Russian: 'ru',
10
+ Chinese: 'zh',
11
11
  } as const;
12
12
 
13
13
  export type Language = typeof Language[keyof typeof Language];
14
14
 
15
15
  const languageHeaderMap: Partial<Record<Language, string>> = {
16
- [Language.Japanese]: 'jp',
17
- [Language.Chinese]: 'ch',
16
+ [Language.Japanese]: 'jp',
17
+ [Language.Chinese]: 'ch',
18
18
  };
19
19
 
20
20
  export function toHeaderLanguage(lang: Language): string {
21
- return languageHeaderMap[lang] ?? lang;
21
+ return languageHeaderMap[lang] ?? lang;
22
22
  }
@@ -1,8 +1,8 @@
1
1
  /** Тип ниши */
2
2
  export const Niche = {
3
- Straight: 'straight',
4
- Gay: 'gay',
5
- Shemale: 'shemale',
3
+ Straight: 'straight',
4
+ Gay: 'gay',
5
+ Shemale: 'shemale',
6
6
  } as const;
7
7
 
8
8
  export type Niche = typeof Niche[keyof typeof Niche];
@@ -1,6 +1,6 @@
1
1
  export const PlaylistType = {
2
- Public: 'public',
3
- Private: 'private',
2
+ Public: 'public',
3
+ Private: 'private',
4
4
  } as const;
5
5
 
6
6
  export type PlaylistType = typeof PlaylistType[keyof typeof PlaylistType];
@@ -2,27 +2,27 @@ import { useBreakpoints } from '@vueuse/core';
2
2
  import type { CssBreakpoints } from '../../types';
3
3
 
4
4
  function breakpoints(breakpoints: Record<CssBreakpoints, number>) {
5
- return useBreakpoints(
6
- {
7
- xs: breakpoints.xs,
8
- sm: breakpoints.sm,
9
- md: breakpoints.md,
10
- lg: breakpoints.lg,
11
- xl: breakpoints.xl,
12
- }
13
- );
5
+ return useBreakpoints(
6
+ {
7
+ xs: breakpoints.xs,
8
+ sm: breakpoints.sm,
9
+ md: breakpoints.md,
10
+ lg: breakpoints.lg,
11
+ xl: breakpoints.xl,
12
+ }
13
+ );
14
14
  }
15
15
 
16
16
  /**
17
- * Возвращает реактивные флаги isMobile и isTablet на основе переданных breakpoints.
18
- * @param projectBreakpoints - набор брейкпоинтов проекта (xs, sm, md, lg, xl) в пикселях
19
- */
17
+ * Возвращает реактивные флаги isMobile и isTablet на основе переданных breakpoints.
18
+ * @param projectBreakpoints - набор брейкпоинтов проекта (xs, sm, md, lg, xl) в пикселях
19
+ */
20
20
  export const checkDeviceWidth = (projectBreakpoints: Record<CssBreakpoints, number>) => {
21
- const isMobile = breakpoints(projectBreakpoints).smaller('sm');
22
- const isTablet = breakpoints(projectBreakpoints).smaller('md');
21
+ const isMobile = breakpoints(projectBreakpoints).smaller('sm');
22
+ const isTablet = breakpoints(projectBreakpoints).smaller('md');
23
23
 
24
- return ({
25
- isMobile,
26
- isTablet
27
- });
24
+ return ({
25
+ isMobile,
26
+ isTablet
27
+ });
28
28
  };
@@ -2,9 +2,9 @@ import type { IRawCategoryCard, IMiniCategoryCard } from '../../../types';
2
2
 
3
3
  /** Нормализует сырую карточку категории к компактному типу IMiniCategoryCard. */
4
4
  export const cleanMiniCategoryCard = (card: IRawCategoryCard): IMiniCategoryCard => ({
5
- name: card.name || '',
6
- title: card.title || '',
7
- isTop: card.is_top || false,
8
- videosCount: card.videosCount || 0,
9
- icon: card.icon,
5
+ name: card.name || '',
6
+ title: card.title || '',
7
+ isTop: card.is_top || false,
8
+ videosCount: card.videosCount || 0,
9
+ icon: card.icon,
10
10
  });
@@ -6,24 +6,24 @@ const age = (card: IRawModelCard) => card.parameters?.find(item => item.name ===
6
6
 
7
7
  /** Нормализует сырую карточку модели к типу IModelCard, включая параметры (возраст, рост, вес) и страну. */
8
8
  export const cleanModelCard = (card: IRawModelCard): IModelCard => ({
9
- title: card.title || '',
10
- videosCount: card.videos_count || 0,
11
- thumbUrl: card.video_thumb_urls?.webp?.[ThumbSize.Small] || '',
12
- primaryImageUrl: card.primary_image_url || '',
13
- guid: card.guid || '',
14
- country: {
15
- title: card.parameters?.find(item => item.name === 'birthplace_country')?.values?.[0]?.title || '',
16
- name: card.parameters?.find(item => item.name === 'birthplace_country')?.values?.[0]?.name || '',
17
- },
18
- parameters: [
19
- ...(card.parameters?.filter(item => parameterNames.includes(item.name) && item.values?.length).map((item: IModelParameter) => ({
20
- title: item.name,
21
- value: item.values?.[0]?.title,
22
- })) ?? []),
23
- ...(age(card) ? [{
24
- title: 'age',
25
- value: age(card),
26
- }] : []),
27
- ],
28
- lastVideoAddedAt: card.last_video_added_at,
9
+ title: card.title || '',
10
+ videosCount: card.videos_count || 0,
11
+ thumbUrl: card.video_thumb_urls?.webp?.[ThumbSize.Small] || '',
12
+ primaryImageUrl: card.primary_image_url || '',
13
+ guid: card.guid || '',
14
+ country: {
15
+ title: card.parameters?.find(item => item.name === 'birthplace_country')?.values?.[0]?.title || '',
16
+ name: card.parameters?.find(item => item.name === 'birthplace_country')?.values?.[0]?.name || '',
17
+ },
18
+ parameters: [
19
+ ...(card.parameters?.filter(item => parameterNames.includes(item.name) && item.values?.length).map((item: IModelParameter) => ({
20
+ title: item.name,
21
+ value: item.values?.[0]?.title,
22
+ })) ?? []),
23
+ ...(age(card) ? [{
24
+ title: 'age',
25
+ value: age(card),
26
+ }] : []),
27
+ ],
28
+ lastVideoAddedAt: card.last_video_added_at,
29
29
  });
@@ -2,69 +2,69 @@ import type { IRawVideoData, IVideoData, ISceneGroup, ITimelineGroup } from '../
2
2
 
3
3
  // «locations» → «Locations», «living_room» → «Living room».
4
4
  const humanize = (value?: string | null): string => {
5
- const text = (value ?? '').replace(/_/g, ' ').trim();
6
- return text ? text.charAt(0).toUpperCase() + text.slice(1) : text;
5
+ const text = (value ?? '').replace(/_/g, ' ').trim();
6
+ return text ? text.charAt(0).toUpperCase() + text.slice(1) : text;
7
7
  };
8
8
 
9
9
  // timelines_groups ({ name, actions:[{ duration?, title }] }) → sceneGroups ({ id, title, scenes:[{ start, title }] }).
10
10
  const cleanTimelineGroups = (raw: ITimelineGroup[] | null): ISceneGroup[] | null => {
11
- if (!Array.isArray(raw)) return null;
11
+ if (!Array.isArray(raw)) return null;
12
12
 
13
- const groups = raw
14
- .filter((group) => Array.isArray(group?.actions) && group.actions.length > 0)
15
- .map((group) => ({
16
- id: group.name || '',
17
- title: humanize(group.name),
18
- scenes: group.actions
19
- .filter((action) => action?.title)
20
- .map((action) => ({
21
- start: Number(action.duration) || 0,
22
- title: humanize(action.title),
23
- })),
24
- }))
25
- .filter((group) => group.scenes.length > 0);
13
+ const groups = raw
14
+ .filter((group) => Array.isArray(group?.actions) && group.actions.length > 0)
15
+ .map((group) => ({
16
+ id: group.name || '',
17
+ title: humanize(group.name),
18
+ scenes: group.actions
19
+ .filter((action) => action?.title)
20
+ .map((action) => ({
21
+ start: Number(action.duration) || 0,
22
+ title: humanize(action.title),
23
+ })),
24
+ }))
25
+ .filter((group) => group.scenes.length > 0);
26
26
 
27
- return groups.length ? groups : null;
27
+ return groups.length ? groups : null;
28
28
  };
29
29
 
30
30
  // hotspots (string[]) → number[] (значения кривой популярности по корзинам).
31
31
  const cleanHotspots = (raw: string[] | null): number[] | null => {
32
- if (!Array.isArray(raw)) return null;
32
+ if (!Array.isArray(raw)) return null;
33
33
 
34
- const values = raw.map(Number).filter((value) => Number.isFinite(value));
35
- return values.length ? values : null;
34
+ const values = raw.map(Number).filter((value) => Number.isFinite(value));
35
+ return values.length ? values : null;
36
36
  };
37
37
 
38
38
  /** Нормализует сырые данные видео к типу IVideoData. */
39
39
  export const cleanVideoData = (data: IRawVideoData): IVideoData => ({
40
- guid: data.guid || '',
41
- md5: data.md5 || '',
42
- quality: data.quality || '',
43
- duration: data.duration || 0,
44
- title: data.title || '',
45
- header: data.header || '',
46
- views: data.views || 0,
47
- likes: data.likes || 0,
48
- id: data.id || '',
49
- tags: data.tags || [],
50
- models: data.models || [],
51
- categories: data.categories || [],
52
- actions: data.actions || null,
53
- channelName: data.channel?.name || '',
54
- channelAvatar: data.channel?.avatar_url || '',
55
- url: data.url || '',
56
- previewUrl: data.preview_url || '',
57
- thumbUrls: data.thumb_urls ? {
58
- webp: data.thumb_urls.webp,
59
- } : undefined,
60
- vttUrl: data.vtt_url || '',
61
- vttSpriteUrl: data.vtt_sprite_url || '',
62
- created: data.created || 0,
63
- videoUrl: data.video_url || '',
64
- isDeleted: data.is_deleted || false,
65
- thumbNum: data.thumb_number || 0,
66
- description: data.description || '',
67
- dislikes: data.dislikes || 0,
68
- hotspots: cleanHotspots(data.hotspots),
69
- timelinesGroups: cleanTimelineGroups(data.timelines_groups),
40
+ guid: data.guid || '',
41
+ md5: data.md5 || '',
42
+ quality: data.quality || '',
43
+ duration: data.duration || 0,
44
+ title: data.title || '',
45
+ header: data.header || '',
46
+ views: data.views || 0,
47
+ likes: data.likes || 0,
48
+ id: data.id || '',
49
+ tags: data.tags || [],
50
+ models: data.models || [],
51
+ categories: data.categories || [],
52
+ actions: data.actions || null,
53
+ channelName: data.channel?.name || '',
54
+ channelAvatar: data.channel?.avatar_url || '',
55
+ url: data.url || '',
56
+ previewUrl: data.preview_url || '',
57
+ thumbUrls: data.thumb_urls ? {
58
+ webp: data.thumb_urls.webp,
59
+ } : undefined,
60
+ vttUrl: data.vtt_url || '',
61
+ vttSpriteUrl: data.vtt_sprite_url || '',
62
+ created: data.created || 0,
63
+ videoUrl: data.video_url || '',
64
+ isDeleted: data.is_deleted || false,
65
+ thumbNum: data.thumb_number || 0,
66
+ description: data.description || '',
67
+ dislikes: data.dislikes || 0,
68
+ hotspots: cleanHotspots(data.hotspots),
69
+ timelinesGroups: cleanTimelineGroups(data.timelines_groups),
70
70
  });
@@ -1,31 +1,31 @@
1
1
  /** Возвращает функции для конвертации дат: toUnix ("yyyy-MM-dd" → timestamp) и fromUnix (timestamp → "yyyy-MM-dd"). */
2
2
  export const convertDateToTimestamp = () => {
3
- const toUnix = (dateStr: string): number | null => {
4
- const [year, month, day] = dateStr.split('-').map(Number);
5
- if (!day || !month || !year) {
6
- return null;
7
- }
3
+ const toUnix = (dateStr: string): number | null => {
4
+ const [year, month, day] = dateStr.split('-').map(Number);
5
+ if (!day || !month || !year) {
6
+ return null;
7
+ }
8
8
 
9
- const date = new Date(Date.UTC(year, month - 1, day));
10
- if (isNaN(date.getTime())) {
11
- return null;
12
- }
9
+ const date = new Date(Date.UTC(year, month - 1, day));
10
+ if (isNaN(date.getTime())) {
11
+ return null;
12
+ }
13
13
 
14
- return Math.floor(date.getTime() / 1000);
15
- };
14
+ return Math.floor(date.getTime() / 1000);
15
+ };
16
16
 
17
- const fromUnix = (timestamp: number): string => {
18
- const date = new Date(timestamp * 1000);
17
+ const fromUnix = (timestamp: number): string => {
18
+ const date = new Date(timestamp * 1000);
19
19
 
20
- const yyyy = date.getUTCFullYear();
21
- const mm = String(date.getUTCMonth() + 1).padStart(2, '0');
22
- const dd = String(date.getUTCDate()).padStart(2, '0');
20
+ const yyyy = date.getUTCFullYear();
21
+ const mm = String(date.getUTCMonth() + 1).padStart(2, '0');
22
+ const dd = String(date.getUTCDate()).padStart(2, '0');
23
23
 
24
- return `${yyyy}-${mm}-${dd}`;
25
- };
24
+ return `${yyyy}-${mm}-${dd}`;
25
+ };
26
26
 
27
- return {
28
- toUnix,
29
- fromUnix,
30
- };
27
+ return {
28
+ toUnix,
29
+ fromUnix,
30
+ };
31
31
  };
@@ -1,6 +1,6 @@
1
1
  import type { RouteLocationNormalizedLoaded } from 'vue-router';
2
2
  /** Конвертирует категории из query-параметра в читаемую строку с заглавными буквами (до 3 категорий). */
3
3
  export function convertQueryCategories(route: RouteLocationNormalizedLoaded) {
4
- const MAX_CATEGORIES = 3;
5
- return String(route.query[ 'categories' ])?.split(',').map(item => item.split('_')[ 1 ]).map(item => item?.charAt(0).toUpperCase() + item?.slice(1)).slice(0, MAX_CATEGORIES).join(', ');
4
+ const MAX_CATEGORIES = 3;
5
+ return String(route.query[ 'categories' ])?.split(',').map(item => item.split('_')[ 1 ]).map(item => item?.charAt(0).toUpperCase() + item?.slice(1)).slice(0, MAX_CATEGORIES).join(', ');
6
6
  }
@@ -2,10 +2,10 @@ import type { IChipsItem } from '../../../types';
2
2
 
3
3
  /** Конвертирует массив строк в чипсы IChipsItem; строку '#' заменяет на 'post'. */
4
4
  export function convertStringArrayToChips(array: string[], prefix: string, resetPath: string): IChipsItem[] {
5
- return array.map((item) => ({
6
- title: item.toLowerCase() === '#' ? 'post' : item,
7
- value: item.toLowerCase() === '#' ? 'post' : item,
8
- prefix: prefix,
9
- resetPath: resetPath,
10
- }));
5
+ return array.map((item) => ({
6
+ title: item.toLowerCase() === '#' ? 'post' : item,
7
+ value: item.toLowerCase() === '#' ? 'post' : item,
8
+ prefix: prefix,
9
+ resetPath: resetPath,
10
+ }));
11
11
  }