itube-specs 0.0.1057 → 0.0.1058
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/SITE_UPDATES.md
CHANGED
|
@@ -11,6 +11,20 @@
|
|
|
11
11
|
коммиты до бампа); `npm run patch` сам проставит ей номер версии. Формат пункта: что сделать и где,
|
|
12
12
|
кому именно (всем / сайтам с N), что будет, если не сделать.
|
|
13
13
|
|
|
14
|
+
## 0.0.1058 — 2026-10-30
|
|
15
|
+
|
|
16
|
+
- **Всем — к сведению:** новый ключ `appConfig.channelTagsSource` (по умолчанию `'popular'` — как было, популярные теги
|
|
17
|
+
роликов канала). `'channel'` — теги самого канала из его карточки, без тегов блока нет, запрос популярных тегов не
|
|
18
|
+
идёт. Делать ничего не надо; videosection-redesign ставит `'channel'`.
|
|
19
|
+
|
|
20
|
+
- **Всем, срочно к сведению:** в 0.0.1056 страница поиска (`/search/{q}`, страница слоя и сайтовые на
|
|
21
|
+
`useSearchRelatedPhrases()`) падала с 500 — композабл звал `useAppConfig` после `await`, вне контекста Nuxt. Починено,
|
|
22
|
+
делать ничего не надо — обновиться.
|
|
23
|
+
|
|
24
|
+
- **Всем — к сведению:** ролики плейлиста приходят целиком (до 200) — `getVideosByPlaylist` слал `limit=100`, которого
|
|
25
|
+
ручка не знает, и получал только первые 20: на плеере плейлиста список, «следующий» и перемешивание ходили по 20,
|
|
26
|
+
счётчик показывал `N/20`. Теперь `per-page` (по умолчанию 200, как на плеере videosection.com). Делать ничего не надо.
|
|
27
|
+
|
|
14
28
|
## 0.0.1056 — 2026-10-30
|
|
15
29
|
|
|
16
30
|
- **Всем — к сведению:** починена `/search/{q}/models` — метод получал аргументы не в том порядке (фраза уходила в
|
package/app.config.ts
CHANGED
|
@@ -17,6 +17,9 @@ export default defineAppConfig({
|
|
|
17
17
|
/** Есть ли у сайта сгруппированный вид категорий (`/categories` — группы, `/categories/all` — A–Z).
|
|
18
18
|
* `false` — `/categories` сам список A–Z: `CategoryNav` без табов Grouped / A-Z, «All» ведёт на `/categories`. */
|
|
19
19
|
categoriesGrouped: true,
|
|
20
|
+
/** Чипсы тегов на странице канала: `popular` — популярные теги роликов канала (`popular-tags-by-channel-name`),
|
|
21
|
+
* `channel` — теги самого канала из его карточки (`tags`), нет тегов — нет блока (как на videosection.com). */
|
|
22
|
+
channelTagsSource: 'popular' as 'popular' | 'channel',
|
|
20
23
|
/** Порядок выдачи без `?sort` (значение `order` API). `null` — дефолт слоя, `''` — `order` не передавать (дефолт
|
|
21
24
|
* API). Вкладки сортировок не меняет. */
|
|
22
25
|
defaultOrders: {
|
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import type { ComputedRef } from 'vue';
|
|
1
|
+
import type { ComputedRef, Ref } from 'vue';
|
|
2
2
|
import { SearchApiService } from '../../services/api/search.service';
|
|
3
|
+
import type { IRelatedPhrases } from '../../types';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Фразы для чипсов страницы поиска (`useSearchPage`), без самой фразы поиска. С `appConfig.relatedSearches.queryLimit`
|
|
6
7
|
* — топ похожих на запрос (`/video/related-searches`), без него — общие фразы (`/search/phrases`). Порядок —
|
|
7
|
-
* `useRelatedPhrases`.
|
|
8
|
+
* `useRelatedPhrases`. Всё, что требует контекста Nuxt, вызывается до `await`: после него в обычной функции контекста нет.
|
|
8
9
|
*/
|
|
9
10
|
export async function useSearchRelatedPhrases(): Promise<ComputedRef<string[]>> {
|
|
10
11
|
const { queryLimit } = useAppConfig().relatedSearches;
|
|
11
12
|
const query = useSlug();
|
|
13
|
+
const source = shallowRef<Ref<IRelatedPhrases | string[] | null | undefined> | null>(null);
|
|
14
|
+
|
|
15
|
+
const phrases = useRelatedPhrases(() => {
|
|
16
|
+
const value = source.value?.value;
|
|
17
|
+
const items = Array.isArray(value) ? value : value?.items;
|
|
18
|
+
return items?.filter(item => (typeof item === 'string' ? item : item.query) !== query.value);
|
|
19
|
+
}, useRelatedSearchLimit('queryLimit'));
|
|
12
20
|
|
|
13
21
|
const { data } = queryLimit === null
|
|
14
22
|
? await useFetchRelatedSearch(SearchApiService.getPhrases)
|
|
15
23
|
: await useFetchRelatedSearchesByQuery(SearchApiService.getRelatedSearches, query);
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return items?.filter(item => (typeof item === 'string' ? item : item.query) !== query.value);
|
|
21
|
-
}, useRelatedSearchLimit('queryLimit'));
|
|
25
|
+
source.value = data;
|
|
26
|
+
|
|
27
|
+
return phrases;
|
|
22
28
|
}
|
|
@@ -7,13 +7,14 @@ import { VideosApiService } from '../../services/api/videos.service';
|
|
|
7
7
|
import type { IBreadcrumbItem, IChipsItem, IPopularTags, INavLinkItem } from '../../types';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Данные страницы канала: карточка канала, видео, популярные
|
|
10
|
+
* Данные страницы канала: карточка канала, видео, популярные теги (при `appConfig.channelTagsSource: 'popular'`). Только запросы — их можно запускать в
|
|
11
11
|
* `Promise.all` вместе с запросами одной страницы (модели канала). Каналы сети зависят от карточки, их страница
|
|
12
12
|
* запрашивает после. Разметку страница держит свою, логику — `useChannelPage()`.
|
|
13
13
|
*/
|
|
14
14
|
export async function useChannelPageData() {
|
|
15
15
|
const lang = useLang() as Language;
|
|
16
16
|
const redirectLegacySlug = useLegacySlugRedirect('channel', name => ChannelsApiService.getChannelsByName(lang, name).then(Boolean));
|
|
17
|
+
const popularTags = useAppConfig().channelTagsSource !== 'channel';
|
|
17
18
|
|
|
18
19
|
const [
|
|
19
20
|
{ data: cardInfo, status },
|
|
@@ -22,7 +23,9 @@ export async function useChannelPageData() {
|
|
|
22
23
|
] = await Promise.all([
|
|
23
24
|
useFetchChannelsByName(ChannelsApiService.getChannelsByName),
|
|
24
25
|
useFetchVideosByChannel(VideosApiService.getListByNicheAndChannel),
|
|
25
|
-
|
|
26
|
+
popularTags
|
|
27
|
+
? useFetchPopularTagsByChannelName(VideosApiService.popularTagsByChannelName)
|
|
28
|
+
: { data: ref<IPopularTags[] | null>(null) },
|
|
26
29
|
]);
|
|
27
30
|
|
|
28
31
|
if (!cardInfo.value) await redirectLegacySlug();
|
|
@@ -76,9 +79,14 @@ export function useChannelPage(
|
|
|
76
79
|
{ name: title.value },
|
|
77
80
|
]);
|
|
78
81
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
const fromChannel = useAppConfig().channelTagsSource === 'channel';
|
|
83
|
+
|
|
84
|
+
const channelTags = computed<IChipsItem[]>(() => (fromChannel
|
|
85
|
+
? (cardInfo.value?.tags || [])
|
|
86
|
+
: (channelTagsData.value || []).map((item: IPopularTags) => item.title)
|
|
87
|
+
).map(tag => ({
|
|
88
|
+
title: tag,
|
|
89
|
+
value: tag,
|
|
82
90
|
prefix: 'tag',
|
|
83
91
|
})));
|
|
84
92
|
|
package/package.json
CHANGED
|
@@ -78,11 +78,13 @@ export class PlaylistsApiService {
|
|
|
78
78
|
);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/** Ролики плейлиста. Размер страницы — `per-page` (`limit` ручка не знает); без него в `pagination` — 200, весь
|
|
82
|
+
* плейлист одной страницей, как на плеере плейлиста videosection.com. */
|
|
81
83
|
static async getVideosByPlaylist(
|
|
82
84
|
id: string,
|
|
83
85
|
pagination: RequestPagination,
|
|
84
86
|
lang: Language,
|
|
85
|
-
|
|
87
|
+
perPage = 200,
|
|
86
88
|
): Promise<PaginatedResponse<IVideoCard>> {
|
|
87
89
|
return await ApiHelper.fetch(
|
|
88
90
|
`/playlist/get-playlist-videos-by-id/${id}`,
|
|
@@ -94,7 +96,7 @@ export class PlaylistsApiService {
|
|
|
94
96
|
'Content-Type': 'application/json',
|
|
95
97
|
},
|
|
96
98
|
params: {
|
|
97
|
-
|
|
99
|
+
'per-page': perPage,
|
|
98
100
|
...pagination,
|
|
99
101
|
},
|
|
100
102
|
},
|