From 256f0e0136d609bba4758735eec1495b71b7e1e4 Mon Sep 17 00:00:00 2001 From: 4gray Date: Sun, 8 Mar 2026 20:01:42 +0100 Subject: [PATCH] refactor(nx): update repository structure Introduce new libraries to improve the boundaries and dependencies in mono repo --- apps/web/project.json | 2 +- apps/web/src/app/app.config.ts | 8 +- apps/web/src/app/app.routes.ts | 2 +- .../category-content-view.component.html | 0 .../category-content-view.component.scss | 0 .../category-content-view.component.ts | 18 +- .../navigation/navigation.component.html | 0 .../navigation/navigation.component.scss | 0 .../navigation/navigation.component.ts | 8 +- .../web/src/app/services/downloads.service.ts | 429 +----------------- apps/web/src/app/services/electron.service.ts | 2 +- apps/web/src/app/services/pwa.service.ts | 2 +- .../app/services/settings-store.service.ts | 110 +---- .../grid-list/grid-list.component.ts | 2 +- apps/web/src/app/shared/components/index.ts | 17 +- .../src/app/shared/styles/_content-grid.scss | 4 +- .../src/app/shared/styles/_portal-layout.scss | 4 +- .../src/app/shared/styles/portal-sidebar.scss | 4 +- .../favorites-button.component.ts | 4 +- .../recently-viewed.component.ts | 22 +- ...lker-collection-channels-list.component.ts | 6 +- .../stalker-favorites.component.ts | 22 +- .../stalker-inline-detail.component.html | 0 .../stalker-inline-detail.component.ts | 8 +- .../stalker-live-stream-layout.component.ts | 16 +- .../stalker-main-container.component.ts | 8 +- .../stalker-search.component.ts | 18 +- .../stalker-series-view.component.ts | 12 +- .../stalker-shell/stalker-shell.component.ts | 12 +- apps/web/src/app/stalker/stalker.routes.ts | 10 +- .../workspace/favorites-context.service.ts | 36 +- .../global-favorites-page.component.ts | 4 +- .../workspace-context-panel.component.ts | 8 +- ...space-favorites-context-panel.component.ts | 2 +- .../workspace-shell.component.spec.ts | 2 +- .../workspace/workspace-shell.component.ts | 6 +- .../account-info/account-info.component.ts | 6 +- .../category-management-dialog.component.ts | 2 +- .../favorites/favorites.component.ts | 18 +- .../live-stream-layout.component.ts | 10 +- .../player-dialog/player-dialog.component.ts | 2 +- .../portal-channels-list.component.ts | 8 +- .../recently-added.component.ts | 6 +- .../global-recently-viewed.component.ts | 2 +- .../recently-viewed.component.ts | 18 +- .../global-search-results.component.ts | 2 +- .../search-results.component.spec.ts | 2 +- .../search-results.component.ts | 16 +- .../season-container.component.ts | 6 +- .../serial-details.component.ts | 2 +- .../src/app/xtream-electron/services/index.ts | 2 - .../vod-details-route.component.ts | 4 +- .../vod-details/vod-details.component.ts | 2 +- .../xtream-main-container.component.ts | 8 +- .../xtream-shell/xtream-shell.component.ts | 8 +- .../src/app/xtream-electron/xtream.routes.ts | 10 +- eslint.config.mjs | 76 +++- libs/m3u-state/project.json | 2 +- libs/portal/downloads/feature/project.json | 13 + libs/portal/downloads/feature/src/index.ts | 1 + .../feature/src/lib}/downloads.component.html | 0 .../feature/src/lib}/downloads.component.scss | 0 .../feature/src/lib}/downloads.component.ts | 19 +- libs/portal/downloads/feature/tsconfig.json | 28 ++ .../downloads/feature/tsconfig.lib.json | 12 + libs/portal/shared/ui/project.json | 13 + libs/portal/shared/ui/src/index.ts | 10 + .../category-view.component.html | 0 .../category-view.component.scss | 2 +- .../category-view/category-view.component.ts | 0 .../content-card/content-card.component.html | 0 .../content-card/content-card.component.scss | 0 .../content-card/content-card.component.ts | 0 .../favorites-layout.component.html | 0 .../favorites-layout.component.scss | 2 +- .../favorites-layout.component.ts | 2 +- .../playlist-error-view.component.html | 0 .../playlist-error-view.component.scss | 0 .../playlist-error-view.component.ts | 0 ...ortal-collection-live-shell.component.html | 0 ...ortal-collection-live-shell.component.scss | 0 .../portal-collection-live-shell.component.ts | 0 .../portal-collection-shell.component.html | 0 .../portal-collection-shell.component.ts | 0 .../portal-empty-state.component.html | 0 .../portal-empty-state.component.scss | 0 .../portal-empty-state.component.ts | 0 .../search-form/search-form.component.html | 0 .../search-form/search-form.component.ts | 0 .../search-layout.component.html | 0 .../search-layout.component.scss | 0 .../search-layout/search-layout.component.ts | 0 .../portal-rail-links.component.html | 0 .../portal-rail-links.component.scss | 0 .../navigation/portal-rail-links.component.ts | 2 +- .../ui/src/lib/styles/_content-grid.scss | 3 + .../ui/src/lib/styles/_portal-layout.scss | 3 + .../ui/src/lib/styles/portal-sidebar.scss | 3 + libs/portal/shared/ui/tsconfig.json | 28 ++ libs/portal/shared/ui/tsconfig.lib.json | 12 + libs/portal/shared/util/jest.config.ts | 21 + libs/portal/shared/util/project.json | 21 + libs/portal/shared/util/src/index.ts | 7 + .../util/src/lib/favorites-context.service.ts | 35 ++ .../shared/util/src/lib}/logger.spec.ts | 20 +- .../portal/shared/util/src/lib}/logger.ts | 13 +- .../lib}/navigation/portal-rail-links.spec.ts | 0 .../src/lib}/navigation/portal-rail-links.ts | 0 .../navigation/portal-route.utils.spec.ts | 0 .../src/lib}/navigation/portal-route.utils.ts | 0 .../lib}/portal-collection-context.spec.ts | 6 +- .../src/lib}/portal-collection-context.ts | 2 +- .../src/lib}/portal-collection-items.spec.ts | 0 .../util/src/lib}/portal-collection-items.ts | 0 .../shared/util/src/lib/portal-player.ts | 29 ++ libs/portal/shared/util/src/test-setup.ts | 6 + libs/portal/shared/util/tsconfig.json | 31 ++ libs/portal/shared/util/tsconfig.lib.json | 12 + libs/portal/shared/util/tsconfig.spec.json | 17 + .../portal/stalker/data-access/jest.config.ts | 21 + libs/portal/stalker/data-access/project.json | 21 + libs/portal/stalker/data-access/src/index.ts | 7 + .../data-access/src/lib}/models/index.ts | 0 .../models/stalker-category-item.interface.ts | 0 .../models/stalker-content-item.interface.ts | 0 .../models/stalker-favorite-item.interface.ts | 0 .../models/stalker-itv-channel.interface.ts | 0 .../lib}/models/stalker-season.interface.ts | 0 .../stalker-serial-details.interface.ts | 0 .../models/stalker-vod-details.interface.ts | 0 .../models/stalker-vod-series.interface.ts | 0 .../src/lib}/stalker-content-types.ts | 0 .../src/lib}/stalker-live-playback.utils.ts | 0 .../src/lib}/stalker-series.adapters.spec.ts | 0 .../src/lib}/stalker-series.adapters.ts | 0 .../src/lib}/stalker-vod.utils.spec.ts | 0 .../data-access/src/lib}/stalker-vod.utils.ts | 0 .../src/lib}/stalker.store.compat.spec.ts | 11 +- .../data-access/src/lib}/stalker.store.ts | 0 .../src/lib}/stores/features/index.ts | 0 .../features/with-stalker-content.feature.ts | 2 +- .../features/with-stalker-epg.feature.ts | 0 .../with-stalker-favorites.feature.ts | 0 .../features/with-stalker-player.feature.ts | 6 +- .../features/with-stalker-portal.feature.ts | 2 +- .../features/with-stalker-recent.feature.ts | 2 +- .../with-stalker-selection.feature.ts | 0 .../features/with-stalker-series.feature.ts | 2 +- .../data-access/src/lib}/stores/index.ts | 0 .../src/lib}/stores/utils/index.ts | 0 .../stores/utils/stalker-content-mappers.ts | 0 .../src/lib}/stores/utils/stalker-sorting.ts | 0 .../stalker/data-access/src/test-setup.ts | 6 + libs/portal/stalker/data-access/tsconfig.json | 31 ++ .../stalker/data-access/tsconfig.lib.json | 12 + .../stalker/data-access/tsconfig.spec.json | 17 + libs/portal/xtream/data-access/project.json | 13 + libs/portal/xtream/data-access/src/index.ts | 7 + .../account-info/account-info.interface.ts | 0 .../electron-xtream-data-source.ts | 0 .../src/lib}/data-sources/index.ts | 0 .../data-sources/pwa-xtream-data-source.ts | 2 +- .../xtream-data-source.interface.ts | 0 .../src/lib}/services/epg-queue.service.ts | 2 +- .../lib}/services/favorite-item.interface.ts | 0 .../src/lib}/services/favorites.service.ts | 0 .../data-access/src/lib/services/index.ts | 5 + .../src/lib}/services/xtream-api.service.ts | 2 +- .../src/lib}/services/xtream-url.service.ts | 2 +- .../src/lib}/stores/features/index.ts | 0 .../stores/features/with-content.feature.ts | 2 +- .../lib}/stores/features/with-epg.feature.ts | 2 +- .../with-playback-positions.feature.ts | 0 .../stores/features/with-player.feature.ts | 4 +- .../stores/features/with-portal.feature.ts | 2 +- .../stores/features/with-search.feature.ts | 2 +- .../stores/features/with-selection.feature.ts | 0 .../data-access/src/lib}/stores/index.ts | 0 .../src/lib}/stores/xtream.store.ts | 2 +- .../src/lib}/with-favorites.feature.ts | 2 +- .../data-access/src/lib}/with-recent-items.ts | 2 +- .../data-access/src/lib}/xtream-state.ts | 0 libs/portal/xtream/data-access/tsconfig.json | 28 ++ .../xtream/data-access/tsconfig.lib.json | 12 + libs/services/project.json | 2 +- libs/services/src/index.ts | 2 + libs/services/src/lib/downloads.service.ts | 424 +++++++++++++++++ .../src/lib/settings-store.service.ts | 109 +++++ libs/shared/interfaces/project.json | 2 +- libs/shared/m3u-utils/project.json | 2 +- libs/ui/components/project.json | 2 +- libs/ui/pipes/project.json | 2 +- libs/ui/remote-control/project.json | 2 +- libs/ui/shared-portals/project.json | 4 +- .../dashboard/data-access/project.json | 2 +- libs/workspace/dashboard/feature/project.json | 2 +- libs/workspace/dashboard/ui/project.json | 2 +- tsconfig.base.json | 18 +- 198 files changed, 1384 insertions(+), 815 deletions(-) rename apps/web/src/app/{xtream-electron => portal-shared}/category-content-view/category-content-view.component.html (100%) rename apps/web/src/app/{xtream-electron => portal-shared}/category-content-view/category-content-view.component.scss (100%) rename apps/web/src/app/{xtream-electron => portal-shared}/category-content-view/category-content-view.component.ts (97%) rename apps/web/src/app/{xtream-electron => portal-shared}/navigation/navigation.component.html (100%) rename apps/web/src/app/{xtream-electron => portal-shared}/navigation/navigation.component.scss (100%) rename apps/web/src/app/{xtream-electron => portal-shared}/navigation/navigation.component.ts (92%) rename apps/web/src/app/{shared/components => stalker}/stalker-inline-detail/stalker-inline-detail.component.html (100%) rename apps/web/src/app/{shared/components => stalker}/stalker-inline-detail/stalker-inline-detail.component.ts (78%) delete mode 100644 apps/web/src/app/xtream-electron/services/index.ts create mode 100644 libs/portal/downloads/feature/project.json create mode 100644 libs/portal/downloads/feature/src/index.ts rename {apps/web/src/app/xtream-electron/downloads => libs/portal/downloads/feature/src/lib}/downloads.component.html (100%) rename {apps/web/src/app/xtream-electron/downloads => libs/portal/downloads/feature/src/lib}/downloads.component.scss (100%) rename {apps/web/src/app/xtream-electron/downloads => libs/portal/downloads/feature/src/lib}/downloads.component.ts (96%) create mode 100644 libs/portal/downloads/feature/tsconfig.json create mode 100644 libs/portal/downloads/feature/tsconfig.lib.json create mode 100644 libs/portal/shared/ui/project.json create mode 100644 libs/portal/shared/ui/src/index.ts rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/category-view/category-view.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/category-view/category-view.component.scss (96%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/category-view/category-view.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/content-card/content-card.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/content-card/content-card.component.scss (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/content-card/content-card.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/favorites-layout/favorites-layout.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/favorites-layout/favorites-layout.component.scss (97%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/favorites-layout/favorites-layout.component.ts (96%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/playlist-error-view/playlist-error-view.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/playlist-error-view/playlist-error-view.component.scss (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/playlist-error-view/playlist-error-view.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-collection-live-shell/portal-collection-live-shell.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-collection-live-shell/portal-collection-live-shell.component.scss (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-collection-live-shell/portal-collection-live-shell.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-collection-shell/portal-collection-shell.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-collection-shell/portal-collection-shell.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-empty-state/portal-empty-state.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-empty-state/portal-empty-state.component.scss (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/portal-empty-state/portal-empty-state.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/search-form/search-form.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/search-form/search-form.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/search-layout/search-layout.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/search-layout/search-layout.component.scss (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/components/search-layout/search-layout.component.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/navigation/portal-rail-links.component.html (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/navigation/portal-rail-links.component.scss (100%) rename {apps/web/src/app/shared => libs/portal/shared/ui/src/lib}/navigation/portal-rail-links.component.ts (95%) create mode 100644 libs/portal/shared/ui/src/lib/styles/_content-grid.scss create mode 100644 libs/portal/shared/ui/src/lib/styles/_portal-layout.scss create mode 100644 libs/portal/shared/ui/src/lib/styles/portal-sidebar.scss create mode 100644 libs/portal/shared/ui/tsconfig.json create mode 100644 libs/portal/shared/ui/tsconfig.lib.json create mode 100644 libs/portal/shared/util/jest.config.ts create mode 100644 libs/portal/shared/util/project.json create mode 100644 libs/portal/shared/util/src/index.ts create mode 100644 libs/portal/shared/util/src/lib/favorites-context.service.ts rename {apps/web/src/app/shared/utils => libs/portal/shared/util/src/lib}/logger.spec.ts (83%) rename {apps/web/src/app/shared/utils => libs/portal/shared/util/src/lib}/logger.ts (94%) rename {apps/web/src/app/shared => libs/portal/shared/util/src/lib}/navigation/portal-rail-links.spec.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/util/src/lib}/navigation/portal-rail-links.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/util/src/lib}/navigation/portal-route.utils.spec.ts (100%) rename {apps/web/src/app/shared => libs/portal/shared/util/src/lib}/navigation/portal-route.utils.ts (100%) rename {apps/web/src/app/shared/utils => libs/portal/shared/util/src/lib}/portal-collection-context.spec.ts (94%) rename {apps/web/src/app/shared/utils => libs/portal/shared/util/src/lib}/portal-collection-context.ts (93%) rename {apps/web/src/app/shared/utils => libs/portal/shared/util/src/lib}/portal-collection-items.spec.ts (100%) rename {apps/web/src/app/shared/utils => libs/portal/shared/util/src/lib}/portal-collection-items.ts (100%) create mode 100644 libs/portal/shared/util/src/lib/portal-player.ts create mode 100644 libs/portal/shared/util/src/test-setup.ts create mode 100644 libs/portal/shared/util/tsconfig.json create mode 100644 libs/portal/shared/util/tsconfig.lib.json create mode 100644 libs/portal/shared/util/tsconfig.spec.json create mode 100644 libs/portal/stalker/data-access/jest.config.ts create mode 100644 libs/portal/stalker/data-access/project.json create mode 100644 libs/portal/stalker/data-access/src/index.ts rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/index.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-category-item.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-content-item.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-favorite-item.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-itv-channel.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-season.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-serial-details.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-vod-details.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/models/stalker-vod-series.interface.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker-content-types.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker-live-playback.utils.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker-series.adapters.spec.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker-series.adapters.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker-vod.utils.spec.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker-vod.utils.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker.store.compat.spec.ts (94%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stalker.store.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/index.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-content.feature.ts (99%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-epg.feature.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-favorites.feature.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-player.feature.ts (99%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-portal.feature.ts (98%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-recent.feature.ts (98%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-selection.feature.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/features/with-stalker-series.feature.ts (99%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/index.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/utils/index.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/utils/stalker-content-mappers.ts (100%) rename {apps/web/src/app/stalker => libs/portal/stalker/data-access/src/lib}/stores/utils/stalker-sorting.ts (100%) create mode 100644 libs/portal/stalker/data-access/src/test-setup.ts create mode 100644 libs/portal/stalker/data-access/tsconfig.json create mode 100644 libs/portal/stalker/data-access/tsconfig.lib.json create mode 100644 libs/portal/stalker/data-access/tsconfig.spec.json create mode 100644 libs/portal/xtream/data-access/project.json create mode 100644 libs/portal/xtream/data-access/src/index.ts rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/account-info/account-info.interface.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/data-sources/electron-xtream-data-source.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/data-sources/index.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/data-sources/pwa-xtream-data-source.ts (99%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/data-sources/xtream-data-source.interface.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/services/epg-queue.service.ts (98%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/services/favorite-item.interface.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/services/favorites.service.ts (100%) create mode 100644 libs/portal/xtream/data-access/src/lib/services/index.ts rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/services/xtream-api.service.ts (99%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/services/xtream-url.service.ts (96%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/index.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/with-content.feature.ts (99%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/with-epg.feature.ts (98%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/with-playback-positions.feature.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/with-player.feature.ts (98%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/with-portal.feature.ts (98%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/with-search.feature.ts (98%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/features/with-selection.feature.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/index.ts (100%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/stores/xtream.store.ts (99%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/with-favorites.feature.ts (98%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/with-recent-items.ts (99%) rename {apps/web/src/app/xtream-electron => libs/portal/xtream/data-access/src/lib}/xtream-state.ts (100%) create mode 100644 libs/portal/xtream/data-access/tsconfig.json create mode 100644 libs/portal/xtream/data-access/tsconfig.lib.json create mode 100644 libs/services/src/lib/downloads.service.ts create mode 100644 libs/services/src/lib/settings-store.service.ts diff --git a/apps/web/project.json b/apps/web/project.json index 07bdb1a66..b99cbff71 100644 --- a/apps/web/project.json +++ b/apps/web/project.json @@ -4,7 +4,7 @@ "projectType": "application", "prefix": "app", "sourceRoot": "apps/web/src", - "tags": [], + "tags": ["scope:app", "type:app"], "targets": { "build": { "executor": "@angular/build:application", diff --git a/apps/web/src/app/app.config.ts b/apps/web/src/app/app.config.ts index 1bc6b86ff..1ae8aff9c 100644 --- a/apps/web/src/app/app.config.ts +++ b/apps/web/src/app/app.config.ts @@ -20,13 +20,15 @@ import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { PlaylistEffects, playlistReducer } from 'm3u-state'; import { NgxIndexedDBModule, NgxIndexedDBService } from 'ngx-indexed-db'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { PORTAL_PLAYER } from '@iptvnator/portal/shared/util'; +import { provideXtreamDataSource } from '@iptvnator/portal/xtream/data-access'; import { DataService } from 'services'; import { dbConfig } from 'shared-interfaces'; import { AppConfig } from '../environments/environment'; import { routes } from './app.routes'; import { ElectronService } from './services/electron.service'; +import { PlayerService } from './services/player.service'; import { PwaService } from './services/pwa.service'; -import { provideXtreamDataSource } from './xtream-electron/data-sources'; // AoT requires an exported function for factories export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { @@ -85,6 +87,10 @@ export const appConfig: ApplicationConfig = { useFactory: DataFactory, deps: [NgxIndexedDBService, HttpClient], }, + { + provide: PORTAL_PLAYER, + useExisting: PlayerService, + }, ...provideXtreamDataSource(), ], }; diff --git a/apps/web/src/app/app.routes.ts b/apps/web/src/app/app.routes.ts index 7b418c7bd..43b57eec9 100644 --- a/apps/web/src/app/app.routes.ts +++ b/apps/web/src/app/app.routes.ts @@ -76,7 +76,7 @@ export const routes: Routes = [ path: 'downloads', data: { layout: 'workspace' }, loadComponent: () => - import('./xtream-electron/downloads/downloads.component').then( + import('@iptvnator/portal/downloads/feature').then( (c) => c.DownloadsComponent ), }, diff --git a/apps/web/src/app/xtream-electron/category-content-view/category-content-view.component.html b/apps/web/src/app/portal-shared/category-content-view/category-content-view.component.html similarity index 100% rename from apps/web/src/app/xtream-electron/category-content-view/category-content-view.component.html rename to apps/web/src/app/portal-shared/category-content-view/category-content-view.component.html diff --git a/apps/web/src/app/xtream-electron/category-content-view/category-content-view.component.scss b/apps/web/src/app/portal-shared/category-content-view/category-content-view.component.scss similarity index 100% rename from apps/web/src/app/xtream-electron/category-content-view/category-content-view.component.scss rename to apps/web/src/app/portal-shared/category-content-view/category-content-view.component.scss diff --git a/apps/web/src/app/xtream-electron/category-content-view/category-content-view.component.ts b/apps/web/src/app/portal-shared/category-content-view/category-content-view.component.ts similarity index 97% rename from apps/web/src/app/xtream-electron/category-content-view/category-content-view.component.ts rename to apps/web/src/app/portal-shared/category-content-view/category-content-view.component.ts index e1de868e6..b4c2777e3 100644 --- a/apps/web/src/app/xtream-electron/category-content-view/category-content-view.component.ts +++ b/apps/web/src/app/portal-shared/category-content-view/category-content-view.component.ts @@ -28,9 +28,9 @@ import { DownloadsService } from '../../services/downloads.service'; import { ExternalPlaybackService } from '../../services/external-playback.service'; import { PlayerService } from '../../services/player.service'; import { GridListComponent } from '../../shared/components/grid-list/grid-list.component'; -import { PlaylistErrorViewComponent } from '../../shared/components/playlist-error-view/playlist-error-view.component'; -import { createLogger } from '../../shared/utils/logger'; -import { StalkerVodSource } from '../../stalker/models'; +import { PlaylistErrorViewComponent } from '@iptvnator/portal/shared/ui'; +import { createLogger } from '@iptvnator/portal/shared/util'; +import { StalkerVodSource } from '@iptvnator/portal/stalker/data-access'; import { StalkerSeriesViewComponent } from '../../stalker/stalker-series-view/stalker-series-view.component'; import { buildStalkerSelectedVodItem, @@ -40,12 +40,12 @@ import { normalizeStalkerEntityId, normalizeStalkerEntityIdAsNumber, toggleStalkerVodFavorite, -} from '../../stalker/stalker-vod.utils'; -import { StalkerStore } from '../../stalker/stalker.store'; -import { XTREAM_DATA_SOURCE } from '../data-sources'; -import { XtreamCategorySortMode } from '../stores/features/with-selection.feature'; -import { XtreamStore } from '../stores/xtream.store'; -import { VodDetailsComponent } from '../vod-details/vod-details.component'; +} from '@iptvnator/portal/stalker/data-access'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; +import { XTREAM_DATA_SOURCE } from '@iptvnator/portal/xtream/data-access'; +import { XtreamCategorySortMode } from '@iptvnator/portal/xtream/data-access'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { VodDetailsComponent } from '../../xtream-electron/vod-details/vod-details.component'; const SORT_STORAGE_KEY = 'xtream-category-sort-mode'; diff --git a/apps/web/src/app/xtream-electron/navigation/navigation.component.html b/apps/web/src/app/portal-shared/navigation/navigation.component.html similarity index 100% rename from apps/web/src/app/xtream-electron/navigation/navigation.component.html rename to apps/web/src/app/portal-shared/navigation/navigation.component.html diff --git a/apps/web/src/app/xtream-electron/navigation/navigation.component.scss b/apps/web/src/app/portal-shared/navigation/navigation.component.scss similarity index 100% rename from apps/web/src/app/xtream-electron/navigation/navigation.component.scss rename to apps/web/src/app/portal-shared/navigation/navigation.component.scss diff --git a/apps/web/src/app/xtream-electron/navigation/navigation.component.ts b/apps/web/src/app/portal-shared/navigation/navigation.component.ts similarity index 92% rename from apps/web/src/app/xtream-electron/navigation/navigation.component.ts rename to apps/web/src/app/portal-shared/navigation/navigation.component.ts index 6873a922a..17012fea4 100644 --- a/apps/web/src/app/xtream-electron/navigation/navigation.component.ts +++ b/apps/web/src/app/portal-shared/navigation/navigation.component.ts @@ -10,10 +10,10 @@ import { PlaylistInfoComponent } from 'components'; import { selectPlaylistById } from 'm3u-state'; import { Playlist } from 'shared-interfaces'; import { SettingsComponent } from '../../settings/settings.component'; -import { AccountInfoComponent } from '../account-info/account-info.component'; -import { XtreamStore } from '../stores/xtream.store'; -import { buildPortalRailLinks } from '../../shared/navigation/portal-rail-links'; -import { PortalRailLinksComponent } from '../../shared/navigation/portal-rail-links.component'; +import { AccountInfoComponent } from '../../xtream-electron/account-info/account-info.component'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { buildPortalRailLinks } from '@iptvnator/portal/shared/util'; +import { PortalRailLinksComponent } from '@iptvnator/portal/shared/ui'; @Component({ selector: 'app-navigation', diff --git a/apps/web/src/app/services/downloads.service.ts b/apps/web/src/app/services/downloads.service.ts index 992c3a45d..23f7206d3 100644 --- a/apps/web/src/app/services/downloads.service.ts +++ b/apps/web/src/app/services/downloads.service.ts @@ -1,424 +1,5 @@ -import { computed, inject, Injectable, OnDestroy, signal } from '@angular/core'; -import { SettingsStore } from './settings-store.service'; - -export type DownloadStatus = - | 'queued' - | 'downloading' - | 'completed' - | 'failed' - | 'canceled'; - -export interface DownloadItem { - id: number; - playlistId: string; - xtreamId: number; - contentType: 'vod' | 'episode'; - seriesXtreamId?: number; - seasonNumber?: number; - episodeNumber?: number; - title: string; - url: string; - fileName?: string; - filePath?: string; - posterUrl?: string; - status: DownloadStatus; - bytesDownloaded?: number; - totalBytes?: number; - errorMessage?: string; - createdAt?: string; - updatedAt?: string; -} - -@Injectable({ providedIn: 'root' }) -export class DownloadsService implements OnDestroy { - private readonly settingsStore = inject(SettingsStore); - private unsubscribe?: () => void; - - /** Signal for the list of downloads */ - readonly downloads = signal([]); - - /** Whether the download feature is available (Electron only) */ - readonly isAvailable = computed(() => !!window.electron?.downloadsGetList); - - /** Whether there are any downloads */ - readonly hasDownloads = computed(() => this.downloads().length > 0); - - /** Active downloads count */ - readonly activeCount = computed( - () => - this.downloads().filter( - (d) => d.status === 'queued' || d.status === 'downloading' - ).length - ); - - /** Completed downloads count */ - readonly completedCount = computed( - () => this.downloads().filter((d) => d.status === 'completed').length - ); - - /** Failed downloads count */ - readonly failedCount = computed( - () => - this.downloads().filter( - (d) => d.status === 'failed' || d.status === 'canceled' - ).length - ); - - /** Current download folder */ - readonly downloadFolder = signal(''); - - constructor() { - this.init(); - } - - private async init() { - if (!this.isAvailable()) { - return; - } - - // Load initial download list - await this.loadDownloads(); - - // Load download folder - await this.loadDownloadFolder(); - - // Subscribe to download updates - this.unsubscribe = window.electron.onDownloadsUpdate(() => { - this.loadDownloads(); - }); - } - - ngOnDestroy() { - this.unsubscribe?.(); - } - - /** - * Load downloads from the backend - */ - async loadDownloads(playlistId?: string): Promise { - if (!this.isAvailable()) return; - - try { - const list = await window.electron.downloadsGetList(playlistId); - this.downloads.set(list); - } catch (error) { - console.error('[DownloadsService] Error loading downloads:', error); - } - } - - /** - * Load or resolve download folder - */ - async loadDownloadFolder(): Promise { - if (!this.isAvailable()) return ''; - - // First check settings - const storedFolder = this.settingsStore.getDownloadFolder?.(); - if (storedFolder) { - this.downloadFolder.set(storedFolder); - return storedFolder; - } - - // Fall back to default - try { - const defaultFolder = - await window.electron.downloadsGetDefaultFolder(); - this.downloadFolder.set(defaultFolder); - return defaultFolder; - } catch (error) { - console.error( - '[DownloadsService] Error getting default folder:', - error - ); - return ''; - } - } - - /** - * Start a new download - */ - async startDownload(data: { - playlistId: string; - xtreamId: number; - contentType: 'vod' | 'episode'; - title: string; - url: string; - posterUrl?: string; - headers?: { userAgent?: string; referer?: string; origin?: string }; - seriesXtreamId?: number; - seasonNumber?: number; - episodeNumber?: number; - // Playlist info for auto-creation if needed (Stalker playlists) - playlistName?: string; - playlistType?: 'xtream' | 'stalker' | 'm3u-file' | 'm3u-text' | 'm3u-url'; - serverUrl?: string; - portalUrl?: string; - macAddress?: string; - }): Promise<{ success: boolean; id?: number; error?: string }> { - if (!this.isAvailable()) { - return { success: false, error: 'Downloads not available' }; - } - - const folder = await this.loadDownloadFolder(); - if (!folder) { - return { success: false, error: 'No download folder configured' }; - } - - try { - const result = await window.electron.downloadsStart({ - ...data, - downloadFolder: folder, - }); - return result; - } catch (error) { - console.error('[DownloadsService] Error starting download:', error); - return { - success: false, - error: error instanceof Error ? error.message : String(error), - }; - } - } - - /** - * Cancel a download - */ - async cancelDownload( - downloadId: number - ): Promise<{ success: boolean; error?: string }> { - if (!this.isAvailable()) { - return { success: false, error: 'Downloads not available' }; - } - - try { - return await window.electron.downloadsCancel(downloadId); - } catch (error) { - console.error( - '[DownloadsService] Error canceling download:', - error - ); - return { - success: false, - error: error instanceof Error ? error.message : String(error), - }; - } - } - - /** - * Retry a failed download - */ - async retryDownload( - downloadId: number - ): Promise<{ success: boolean; error?: string }> { - if (!this.isAvailable()) { - return { success: false, error: 'Downloads not available' }; - } - - const folder = await this.loadDownloadFolder(); - if (!folder) { - return { success: false, error: 'No download folder configured' }; - } - - try { - return await window.electron.downloadsRetry(downloadId, folder); - } catch (error) { - console.error( - '[DownloadsService] Error retrying download:', - error - ); - return { - success: false, - error: error instanceof Error ? error.message : String(error), - }; - } - } - - /** - * Remove a download from the list - */ - async removeDownload( - downloadId: number - ): Promise<{ success: boolean; error?: string }> { - if (!this.isAvailable()) { - return { success: false, error: 'Downloads not available' }; - } - - try { - return await window.electron.downloadsRemove(downloadId); - } catch (error) { - console.error( - '[DownloadsService] Error removing download:', - error - ); - return { - success: false, - error: error instanceof Error ? error.message : String(error), - }; - } - } - - /** - * Play a downloaded file - */ - async playDownload( - filePath: string - ): Promise<{ success: boolean; error?: string }> { - if (!this.isAvailable()) { - return { success: false, error: 'Downloads not available' }; - } - - try { - return await window.electron.downloadsPlayFile(filePath); - } catch (error) { - console.error('[DownloadsService] Error playing file:', error); - return { - success: false, - error: error instanceof Error ? error.message : String(error), - }; - } - } - - /** - * Reveal file in system file manager - */ - async revealFile( - filePath: string - ): Promise<{ success: boolean; error?: string }> { - if (!this.isAvailable()) { - return { success: false, error: 'Downloads not available' }; - } - - try { - return await window.electron.downloadsRevealFile(filePath); - } catch (error) { - console.error('[DownloadsService] Error revealing file:', error); - return { - success: false, - error: error instanceof Error ? error.message : String(error), - }; - } - } - - /** - * Select a new download folder - */ - async selectFolder(): Promise { - if (!this.isAvailable()) { - return null; - } - - try { - const folder = await window.electron.downloadsSelectFolder(); - if (folder) { - this.downloadFolder.set(folder); - // Save to settings - await this.settingsStore.updateSettings({ downloadFolder: folder }); - } - return folder; - } catch (error) { - console.error( - '[DownloadsService] Error selecting folder:', - error - ); - return null; - } - } - - /** - * Clear completed/failed downloads - */ - async clearCompleted( - playlistId?: string - ): Promise<{ success: boolean }> { - if (!this.isAvailable()) { - return { success: false }; - } - - try { - return await window.electron.downloadsClearCompleted(playlistId); - } catch (error) { - console.error( - '[DownloadsService] Error clearing completed:', - error - ); - return { success: false }; - } - } - - /** - * Get download progress as percentage - */ - getProgressPercent(item: DownloadItem): number { - if (!item.totalBytes || item.totalBytes === 0) { - return 0; - } - return Math.round( - ((item.bytesDownloaded || 0) / item.totalBytes) * 100 - ); - } - - /** - * Get download item by xtreamId and playlistId - */ - getDownloadByContent( - xtreamId: number, - playlistId: string, - contentType: 'vod' | 'episode' - ): DownloadItem | undefined { - return this.downloads().find( - (d) => - d.xtreamId === xtreamId && - d.playlistId === playlistId && - d.contentType === contentType - ); - } - - /** - * Check if content is downloaded (completed status) - */ - isDownloaded( - xtreamId: number, - playlistId: string, - contentType: 'vod' | 'episode' - ): boolean { - const download = this.getDownloadByContent(xtreamId, playlistId, contentType); - return download?.status === 'completed' && !!download.filePath; - } - - /** - * Check if content is currently downloading or queued - */ - isDownloading( - xtreamId: number, - playlistId: string, - contentType: 'vod' | 'episode' - ): boolean { - const download = this.getDownloadByContent(xtreamId, playlistId, contentType); - return download?.status === 'downloading' || download?.status === 'queued'; - } - - /** - * Get the file path for a downloaded content item - */ - getDownloadedFilePath( - xtreamId: number, - playlistId: string, - contentType: 'vod' | 'episode' - ): string | undefined { - const download = this.getDownloadByContent(xtreamId, playlistId, contentType); - if (download?.status === 'completed') { - return download.filePath; - } - return undefined; - } - - /** - * Format bytes to human readable string - */ - formatBytes(bytes: number): string { - if (bytes === 0) return '0 B'; - const k = 1024; - const sizes = ['B', 'KB', 'MB', 'GB']; - const i = Math.floor(Math.log(bytes) / Math.log(k)); - return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; - } -} +export { + DownloadsService, + type DownloadItem, + type DownloadStatus, +} from 'services'; diff --git a/apps/web/src/app/services/electron.service.ts b/apps/web/src/app/services/electron.service.ts index 3029a3c43..74af394ce 100644 --- a/apps/web/src/app/services/electron.service.ts +++ b/apps/web/src/app/services/electron.service.ts @@ -18,7 +18,7 @@ import { AppConfig } from '../../environments/environment'; import { createPortalDebugRequestContext, logPortalDebugEvent, -} from '../shared/utils/logger'; +} from '@iptvnator/portal/shared/util'; @Injectable({ providedIn: 'root', diff --git a/apps/web/src/app/services/pwa.service.ts b/apps/web/src/app/services/pwa.service.ts index 13be1257c..54e2a81b6 100644 --- a/apps/web/src/app/services/pwa.service.ts +++ b/apps/web/src/app/services/pwa.service.ts @@ -25,7 +25,7 @@ import { createPortalDebugSuccessEvent, logPortalDebugEvent, logPortalDebugRequest, -} from '../shared/utils/logger'; +} from '@iptvnator/portal/shared/util'; @Injectable({ providedIn: 'root', diff --git a/apps/web/src/app/services/settings-store.service.ts b/apps/web/src/app/services/settings-store.service.ts index 3211d39b0..74279bf7a 100644 --- a/apps/web/src/app/services/settings-store.service.ts +++ b/apps/web/src/app/services/settings-store.service.ts @@ -1,109 +1 @@ -import { inject } from '@angular/core'; -import { - patchState, - signalStore, - withHooks, - withMethods, - withState, -} from '@ngrx/signals'; -import { StorageMap } from '@ngx-pwa/local-storage'; -import { firstValueFrom } from 'rxjs'; -import { - Language, - Settings, - STORE_KEY, - StreamFormat, - Theme, - VideoPlayer, -} from 'shared-interfaces'; - -const DEFAULT_SETTINGS: Settings = { - player: VideoPlayer.VideoJs, - streamFormat: StreamFormat.M3u8StreamFormat, - language: Language.ENGLISH, - showCaptions: false, - showExternalPlaybackBar: true, - theme: Theme.LightTheme, - mpvPlayerPath: '', - mpvReuseInstance: false, - vlcPlayerPath: '', - remoteControl: false, - remoteControlPort: 8765, - epgUrl: [], - downloadFolder: '', -}; - -export const SettingsStore = signalStore( - { providedIn: 'root' }, - withState(DEFAULT_SETTINGS), - withMethods((store, storage = inject(StorageMap)) => ({ - async loadSettings() { - try { - const stored = await firstValueFrom( - storage.get(STORE_KEY.Settings) - ); - if (stored) { - patchState(store, { - ...DEFAULT_SETTINGS, - ...(stored as Settings), - }); - } - } catch (error) { - console.error('Failed to load settings:', error); - // Keep default settings if loading fails - } - }, - - async updateSettings(settings: Partial) { - patchState(store, settings); - // Save the complete settings object, not just the partial update - const completeSettings = this.getSettings(); - try { - await firstValueFrom( - storage.set(STORE_KEY.Settings, completeSettings) - ); - } catch (error) { - console.error('Failed to save settings:', error); - throw error; - } - }, - - getSettings() { - return { - player: store.player(), - streamFormat: store.streamFormat(), - language: store.language(), - showCaptions: store.showCaptions(), - showExternalPlaybackBar: store.showExternalPlaybackBar(), - theme: store.theme(), - mpvPlayerPath: store.mpvPlayerPath(), - mpvReuseInstance: store.mpvReuseInstance(), - vlcPlayerPath: store.vlcPlayerPath(), - remoteControl: store.remoteControl(), - remoteControlPort: store.remoteControlPort(), - epgUrl: store.epgUrl(), - downloadFolder: store.downloadFolder(), - }; - }, - - getDownloadFolder() { - return store.downloadFolder(); - }, - - getPlayer() { - return store.player(); - }, - - isEmbeddedPlayer() { - return ( - store.player() === VideoPlayer.VideoJs || - store.player() === VideoPlayer.Html5Player - ); - }, - })), - withHooks({ - onInit(store) { - store.loadSettings(); - }, - }) -); +export { SettingsStore } from 'services'; diff --git a/apps/web/src/app/shared/components/grid-list/grid-list.component.ts b/apps/web/src/app/shared/components/grid-list/grid-list.component.ts index 10624d7d9..98631974f 100644 --- a/apps/web/src/app/shared/components/grid-list/grid-list.component.ts +++ b/apps/web/src/app/shared/components/grid-list/grid-list.component.ts @@ -4,7 +4,7 @@ import { MatIcon } from '@angular/material/icon'; import { MatPaginatorModule, PageEvent } from '@angular/material/paginator'; import { MatTooltip } from '@angular/material/tooltip'; import { TranslatePipe } from '@ngx-translate/core'; -import { PlaylistErrorViewComponent } from '../playlist-error-view/playlist-error-view.component'; +import { PlaylistErrorViewComponent } from '@iptvnator/portal/shared/ui'; import { ProgressCapsuleComponent } from '../../../xtream-electron/shared/progress-capsule/progress-capsule.component'; import { WatchedBadgeComponent } from '../../../xtream-electron/shared/watched-badge/watched-badge.component'; diff --git a/apps/web/src/app/shared/components/index.ts b/apps/web/src/app/shared/components/index.ts index 0848e6ae4..0119ab68a 100644 --- a/apps/web/src/app/shared/components/index.ts +++ b/apps/web/src/app/shared/components/index.ts @@ -1,7 +1,12 @@ -export * from './category-view/category-view.component'; -export * from './content-card/content-card.component'; +export { + CategoryViewComponent, + ContentCardComponent, + FavoritesLayoutComponent, + PlaylistErrorViewComponent, + PortalCollectionLiveShellComponent, + PortalCollectionShellComponent, + PortalEmptyStateComponent, + SearchFormComponent, + SearchLayoutComponent, +} from '@iptvnator/portal/shared/ui'; export * from './header/header.component'; -export * from './playlist-error-view/playlist-error-view.component'; -export * from './portal-collection-shell/portal-collection-shell.component'; -export * from './portal-empty-state/portal-empty-state.component'; -export * from './stalker-inline-detail/stalker-inline-detail.component'; diff --git a/apps/web/src/app/shared/styles/_content-grid.scss b/apps/web/src/app/shared/styles/_content-grid.scss index 9babd1776..d611bf0f8 100644 --- a/apps/web/src/app/shared/styles/_content-grid.scss +++ b/apps/web/src/app/shared/styles/_content-grid.scss @@ -1,3 +1 @@ -// Canonical source: libs/ui/styles/_content-grid.scss -// This stub forwards the mixins for components that @use this file directly. -@forward '../../../../../../libs/ui/styles/content-grid'; +@forward '../../../../../../libs/portal/shared/ui/src/lib/styles/content-grid'; diff --git a/apps/web/src/app/shared/styles/_portal-layout.scss b/apps/web/src/app/shared/styles/_portal-layout.scss index 2425988ef..6f3a668d5 100644 --- a/apps/web/src/app/shared/styles/_portal-layout.scss +++ b/apps/web/src/app/shared/styles/_portal-layout.scss @@ -1,3 +1 @@ -// Canonical source: libs/ui/styles/_portal-layout.scss -// This stub forwards the mixin for components that @use this file directly. -@forward '../../../../../../libs/ui/styles/portal-layout'; +@forward '../../../../../../libs/portal/shared/ui/src/lib/styles/portal-layout'; diff --git a/apps/web/src/app/shared/styles/portal-sidebar.scss b/apps/web/src/app/shared/styles/portal-sidebar.scss index 0534acf3b..95c30ea1f 100644 --- a/apps/web/src/app/shared/styles/portal-sidebar.scss +++ b/apps/web/src/app/shared/styles/portal-sidebar.scss @@ -1,3 +1 @@ -// Canonical source: libs/ui/styles/_portal-sidebar.scss -// This stub forwards the rules for components that @use this file directly. -@forward '../../../../../../libs/ui/styles/portal-sidebar'; +@forward '../../../../../../libs/portal/shared/ui/src/lib/styles/portal-sidebar'; diff --git a/apps/web/src/app/stalker/favorites-button/favorites-button.component.ts b/apps/web/src/app/stalker/favorites-button/favorites-button.component.ts index f5332c020..44c448d17 100644 --- a/apps/web/src/app/stalker/favorites-button/favorites-button.component.ts +++ b/apps/web/src/app/stalker/favorites-button/favorites-button.component.ts @@ -4,8 +4,8 @@ import { MatIconModule } from '@angular/material/icon'; import { TranslateModule } from '@ngx-translate/core'; import { BehaviorSubject, map, switchMap } from 'rxjs'; import { PlaylistsService } from 'services'; -import { StalkerStore } from '../stalker.store'; -import { matchesFavoriteById } from '../stalker-vod.utils'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; +import { matchesFavoriteById } from '@iptvnator/portal/stalker/data-access'; @Component({ selector: 'app-favorites-button', diff --git a/apps/web/src/app/stalker/recently-viewed/recently-viewed.component.ts b/apps/web/src/app/stalker/recently-viewed/recently-viewed.component.ts index 99914cea6..17808cd84 100644 --- a/apps/web/src/app/stalker/recently-viewed/recently-viewed.component.ts +++ b/apps/web/src/app/stalker/recently-viewed/recently-viewed.component.ts @@ -11,25 +11,25 @@ import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { PlaylistsService } from 'services'; import { EpgItem, VodDetailsItem } from 'shared-interfaces'; import { PlayerService } from '../../services/player.service'; -import { PortalCollectionLiveShellComponent } from '../../shared/components/portal-collection-live-shell/portal-collection-live-shell.component'; +import { PortalCollectionLiveShellComponent } from '@iptvnator/portal/shared/ui'; import { PortalCollectionMode, PortalCollectionShellComponent, PortalCollectionShellLayout, -} from '../../shared/components/portal-collection-shell/portal-collection-shell.component'; -import { StalkerInlineDetailComponent } from '../../shared/components/stalker-inline-detail/stalker-inline-detail.component'; +} from '@iptvnator/portal/shared/ui'; +import { StalkerInlineDetailComponent } from '../stalker-inline-detail/stalker-inline-detail.component'; import { isWorkspaceLayoutRoute, queryParamSignal, -} from '../../shared/navigation/portal-route.utils'; -import { createPortalCollectionContext } from '../../shared/utils/portal-collection-context'; +} from '@iptvnator/portal/shared/util'; +import { createPortalCollectionContext } from '@iptvnator/portal/shared/util'; import { buildStandardCollectionCategories, filterCollectionBucket, -} from '../../shared/utils/portal-collection-items'; -import { createLogger } from '../../shared/utils/logger'; -import { FavoritesContextService } from '../../workspace/favorites-context.service'; -import { StalkerSelectedVodItem, StalkerVodSource } from '../models'; +} from '@iptvnator/portal/shared/util'; +import { createLogger } from '@iptvnator/portal/shared/util'; +import { FavoritesContextService } from '@iptvnator/portal/shared/util'; +import { StalkerSelectedVodItem, StalkerVodSource } from '@iptvnator/portal/stalker/data-access'; import { clearStalkerDetailViewState, createStalkerInlineDetailState, @@ -40,9 +40,9 @@ import { isSelectedStalkerVodFavorite, normalizeStalkerVodDetailsItem, toggleStalkerVodFavorite, -} from '../stalker-vod.utils'; +} from '@iptvnator/portal/stalker/data-access'; import { StalkerCollectionChannelsListComponent } from '../stalker-collection-channels-list/stalker-collection-channels-list.component'; -import { StalkerStore } from '../stalker.store'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; const STALKER_RECENT_LAYOUT: Omit< PortalCollectionShellLayout, diff --git a/apps/web/src/app/stalker/stalker-collection-channels-list/stalker-collection-channels-list.component.ts b/apps/web/src/app/stalker/stalker-collection-channels-list/stalker-collection-channels-list.component.ts index cf9650e00..c0c2e1c76 100644 --- a/apps/web/src/app/stalker/stalker-collection-channels-list/stalker-collection-channels-list.component.ts +++ b/apps/web/src/app/stalker/stalker-collection-channels-list/stalker-collection-channels-list.component.ts @@ -13,9 +13,9 @@ import { MatIconModule } from '@angular/material/icon'; import { TranslatePipe } from '@ngx-translate/core'; import { ChannelListItemComponent } from 'components'; import { EpgItem, EpgProgram } from 'shared-interfaces'; -import { StalkerVodSource } from '../models'; -import { normalizeStalkerEntityId } from '../stalker-vod.utils'; -import { StalkerStore } from '../stalker.store'; +import { StalkerVodSource } from '@iptvnator/portal/stalker/data-access'; +import { normalizeStalkerEntityId } from '@iptvnator/portal/stalker/data-access'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; @Component({ selector: 'app-stalker-collection-channels-list', diff --git a/apps/web/src/app/stalker/stalker-favorites/stalker-favorites.component.ts b/apps/web/src/app/stalker/stalker-favorites/stalker-favorites.component.ts index c8e5fa734..1c9894d01 100644 --- a/apps/web/src/app/stalker/stalker-favorites/stalker-favorites.component.ts +++ b/apps/web/src/app/stalker/stalker-favorites/stalker-favorites.component.ts @@ -11,22 +11,22 @@ import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { PlaylistsService } from 'services'; import { EpgItem, VodDetailsItem } from 'shared-interfaces'; import { PlayerService } from '../../services/player.service'; -import { PortalCollectionLiveShellComponent } from '../../shared/components/portal-collection-live-shell/portal-collection-live-shell.component'; +import { PortalCollectionLiveShellComponent } from '@iptvnator/portal/shared/ui'; import { PortalCollectionMode, PortalCollectionShellComponent, PortalCollectionShellLayout, -} from '../../shared/components/portal-collection-shell/portal-collection-shell.component'; -import { StalkerInlineDetailComponent } from '../../shared/components/stalker-inline-detail/stalker-inline-detail.component'; -import { queryParamSignal } from '../../shared/navigation/portal-route.utils'; -import { createPortalCollectionContext } from '../../shared/utils/portal-collection-context'; +} from '@iptvnator/portal/shared/ui'; +import { StalkerInlineDetailComponent } from '../stalker-inline-detail/stalker-inline-detail.component'; +import { queryParamSignal } from '@iptvnator/portal/shared/util'; +import { createPortalCollectionContext } from '@iptvnator/portal/shared/util'; import { buildStandardCollectionCategories, filterCollectionBucket, -} from '../../shared/utils/portal-collection-items'; -import { createLogger } from '../../shared/utils/logger'; -import { FavoritesContextService } from '../../workspace/favorites-context.service'; -import { StalkerFavoriteItem } from '../models'; +} from '@iptvnator/portal/shared/util'; +import { createLogger } from '@iptvnator/portal/shared/util'; +import { FavoritesContextService } from '@iptvnator/portal/shared/util'; +import { StalkerFavoriteItem } from '@iptvnator/portal/stalker/data-access'; import { clearStalkerDetailViewState, createStalkerInlineDetailState, @@ -38,9 +38,9 @@ import { normalizeStalkerEntityId, normalizeStalkerFavoriteItem, toggleStalkerVodFavorite, -} from '../stalker-vod.utils'; +} from '@iptvnator/portal/stalker/data-access'; import { StalkerCollectionChannelsListComponent } from '../stalker-collection-channels-list/stalker-collection-channels-list.component'; -import { StalkerStore } from '../stalker.store'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; const STALKER_FAVORITES_LAYOUT: PortalCollectionShellLayout = {}; diff --git a/apps/web/src/app/shared/components/stalker-inline-detail/stalker-inline-detail.component.html b/apps/web/src/app/stalker/stalker-inline-detail/stalker-inline-detail.component.html similarity index 100% rename from apps/web/src/app/shared/components/stalker-inline-detail/stalker-inline-detail.component.html rename to apps/web/src/app/stalker/stalker-inline-detail/stalker-inline-detail.component.html diff --git a/apps/web/src/app/shared/components/stalker-inline-detail/stalker-inline-detail.component.ts b/apps/web/src/app/stalker/stalker-inline-detail/stalker-inline-detail.component.ts similarity index 78% rename from apps/web/src/app/shared/components/stalker-inline-detail/stalker-inline-detail.component.ts rename to apps/web/src/app/stalker/stalker-inline-detail/stalker-inline-detail.component.ts index 409c6cb4e..49430b645 100644 --- a/apps/web/src/app/shared/components/stalker-inline-detail/stalker-inline-detail.component.ts +++ b/apps/web/src/app/stalker/stalker-inline-detail/stalker-inline-detail.component.ts @@ -5,11 +5,11 @@ import { input, output, } from '@angular/core'; -import { ExternalPlaybackService } from '../../../services/external-playback.service'; +import { ExternalPlaybackService } from '../../services/external-playback.service'; import { VodDetailsItem } from 'shared-interfaces'; -import { VodDetailsComponent } from '../../../xtream-electron/vod-details/vod-details.component'; -import { StalkerSelectedVodItem } from '../../../stalker/models/stalker-favorite-item.interface'; -import { StalkerSeriesViewComponent } from '../../../stalker/stalker-series-view/stalker-series-view.component'; +import { VodDetailsComponent } from '../../xtream-electron/vod-details/vod-details.component'; +import { StalkerSelectedVodItem } from '@iptvnator/portal/stalker/data-access'; +import { StalkerSeriesViewComponent } from '../stalker-series-view/stalker-series-view.component'; @Component({ selector: 'app-stalker-inline-detail', diff --git a/apps/web/src/app/stalker/stalker-live-stream-layout/stalker-live-stream-layout.component.ts b/apps/web/src/app/stalker/stalker-live-stream-layout/stalker-live-stream-layout.component.ts index 68e82b99c..0bb05b0c6 100644 --- a/apps/web/src/app/stalker/stalker-live-stream-layout/stalker-live-stream-layout.component.ts +++ b/apps/web/src/app/stalker/stalker-live-stream-layout/stalker-live-stream-layout.component.ts @@ -31,22 +31,22 @@ import { EpgItem, EpgProgram } from 'shared-interfaces'; import { EpgViewComponent, WebPlayerViewComponent } from 'shared-portals'; import { PlayerService } from '../../services/player.service'; import { SettingsStore } from '../../services/settings-store.service'; -import { CategoryViewComponent } from '../../shared/components/category-view/category-view.component'; -import { PlaylistErrorViewComponent } from '../../shared/components/playlist-error-view/playlist-error-view.component'; -import { PortalEmptyStateComponent } from '../../shared/components/portal-empty-state/portal-empty-state.component'; -import { isWorkspaceLayoutRoute } from '../../shared/navigation/portal-route.utils'; +import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; +import { PlaylistErrorViewComponent } from '@iptvnator/portal/shared/ui'; +import { PortalEmptyStateComponent } from '@iptvnator/portal/shared/ui'; +import { isWorkspaceLayoutRoute } from '@iptvnator/portal/shared/util'; import { getAdjacentChannelItem, getChannelItemByNumber, } from '../../shared/services/remote-channel-navigation.util'; -import { createLogger } from '../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { StalkerCategoryItem, StalkerFavoriteItem, StalkerItvChannel, -} from '../models'; -import { normalizeStalkerEntityId } from '../stalker-vod.utils'; -import { StalkerStore } from '../stalker.store'; +} from '@iptvnator/portal/stalker/data-access'; +import { normalizeStalkerEntityId } from '@iptvnator/portal/stalker/data-access'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; @Component({ selector: 'app-stalker-live-stream-layout', diff --git a/apps/web/src/app/stalker/stalker-main-container.component.ts b/apps/web/src/app/stalker/stalker-main-container.component.ts index 7ce78f3c2..68b46c931 100644 --- a/apps/web/src/app/stalker/stalker-main-container.component.ts +++ b/apps/web/src/app/stalker/stalker-main-container.component.ts @@ -5,10 +5,10 @@ import { MatPaginatorModule } from '@angular/material/paginator'; import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { PlaylistSwitcherComponent, ResizableDirective } from 'components'; -import { CategoryViewComponent } from '../shared/components/category-view/category-view.component'; -import { PlaylistErrorViewComponent } from '../shared/components/playlist-error-view/playlist-error-view.component'; -import { isWorkspaceLayoutRoute } from '../shared/navigation/portal-route.utils'; -import { StalkerStore } from './stalker.store'; +import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; +import { PlaylistErrorViewComponent } from '@iptvnator/portal/shared/ui'; +import { isWorkspaceLayoutRoute } from '@iptvnator/portal/shared/util'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; @Component({ selector: 'app-stalker-main-container', diff --git a/apps/web/src/app/stalker/stalker-search/stalker-search.component.ts b/apps/web/src/app/stalker/stalker-search/stalker-search.component.ts index 0fa6aace5..126136ce5 100644 --- a/apps/web/src/app/stalker/stalker-search/stalker-search.component.ts +++ b/apps/web/src/app/stalker/stalker-search/stalker-search.component.ts @@ -12,20 +12,20 @@ import { StalkerPortalActions, VodDetailsItem, } from 'shared-interfaces'; -import { ContentCardComponent } from '../../shared/components/content-card/content-card.component'; -import { SearchLayoutComponent } from '../../shared/components/search-layout/search-layout.component'; -import { StalkerInlineDetailComponent } from '../../shared/components/stalker-inline-detail/stalker-inline-detail.component'; -import { StalkerContentTypes } from '../stalker-content-types'; -import { StalkerStore } from '../stalker.store'; +import { ContentCardComponent } from '@iptvnator/portal/shared/ui'; +import { SearchLayoutComponent } from '@iptvnator/portal/shared/ui'; +import { StalkerInlineDetailComponent } from '../stalker-inline-detail/stalker-inline-detail.component'; +import { StalkerContentTypes } from '@iptvnator/portal/stalker/data-access'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; import { isWorkspaceLayoutRoute, queryParamSignal, -} from '../../shared/navigation/portal-route.utils'; -import { createLogger } from '../../shared/utils/logger'; +} from '@iptvnator/portal/shared/util'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { StalkerSelectedVodItem, StalkerVodSource, -} from '../models'; +} from '@iptvnator/portal/stalker/data-access'; import { buildStalkerSelectedVodItem, clearStalkerDetailViewState, @@ -36,7 +36,7 @@ import { isSelectedStalkerVodFavorite, isStalkerSeriesFlag, toggleStalkerVodFavorite, -} from '../stalker-vod.utils'; +} from '@iptvnator/portal/stalker/data-access'; interface StalkerFilter { key: string; diff --git a/apps/web/src/app/stalker/stalker-series-view/stalker-series-view.component.ts b/apps/web/src/app/stalker/stalker-series-view/stalker-series-view.component.ts index b2ade7a73..f7ef847ac 100644 --- a/apps/web/src/app/stalker/stalker-series-view/stalker-series-view.component.ts +++ b/apps/web/src/app/stalker/stalker-series-view/stalker-series-view.component.ts @@ -11,14 +11,14 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { FavoritesButtonComponent } from '../favorites-button/favorites-button.component'; import { ContentHeroComponent } from 'components'; -import { StalkerStore } from '../stalker.store'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; import { SeasonContainerComponent } from '../../xtream-electron/season-container/season-container.component'; import { ResolvedPortalPlayback, XtreamSerieEpisode, } from 'shared-interfaces'; -import { XtreamStore } from '../../xtream-electron/stores/xtream.store'; -import { createLogger } from '../../shared/utils/logger'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { getVodSeriesSeasonKey, isVodSeriesItem, @@ -29,9 +29,9 @@ import { StalkerMappedEpisode, StalkerSeriesSeasonVm, VodSeriesSeasonVm, -} from '../stalker-series.adapters'; -import { StalkerSelectedVodItem, StalkerVodSource } from '../models'; -import { normalizeStalkerVodDetailsItem } from '../stalker-vod.utils'; +} from '@iptvnator/portal/stalker/data-access'; +import { StalkerSelectedVodItem, StalkerVodSource } from '@iptvnator/portal/stalker/data-access'; +import { normalizeStalkerVodDetailsItem } from '@iptvnator/portal/stalker/data-access'; import { PlayerService } from '../../services/player.service'; import { ExternalPlaybackService } from '../../services/external-playback.service'; import { PortalInlinePlayerComponent } from '../../shared/components/portal-inline-player/portal-inline-player.component'; diff --git a/apps/web/src/app/stalker/stalker-shell/stalker-shell.component.ts b/apps/web/src/app/stalker/stalker-shell/stalker-shell.component.ts index d14ea2452..571efdf5c 100644 --- a/apps/web/src/app/stalker/stalker-shell/stalker-shell.component.ts +++ b/apps/web/src/app/stalker/stalker-shell/stalker-shell.component.ts @@ -9,15 +9,15 @@ import { import { Store } from '@ngrx/store'; import { PlaylistActions, selectPlaylistById } from 'm3u-state'; import { map, switchMap } from 'rxjs'; -import { PortalRailSection } from '../../shared/navigation/portal-rail-links'; +import { PortalRailSection } from '@iptvnator/portal/shared/util'; import { isWorkspaceLayoutRoute, resolveCurrentPortalSection, -} from '../../shared/navigation/portal-route.utils'; -import { createLogger } from '../../shared/utils/logger'; -import { NavigationComponent } from '../../xtream-electron/navigation/navigation.component'; -import { XtreamStore } from '../../xtream-electron/stores/xtream.store'; -import { StalkerStore } from '../stalker.store'; +} from '@iptvnator/portal/shared/util'; +import { createLogger } from '@iptvnator/portal/shared/util'; +import { NavigationComponent } from '../../portal-shared/navigation/navigation.component'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; @Component({ selector: 'app-stalker-shell', diff --git a/apps/web/src/app/stalker/stalker.routes.ts b/apps/web/src/app/stalker/stalker.routes.ts index 0a783e153..04d9c2173 100644 --- a/apps/web/src/app/stalker/stalker.routes.ts +++ b/apps/web/src/app/stalker/stalker.routes.ts @@ -28,7 +28,7 @@ export const stalkerRoutes: Route[] = [ }, loadComponent: () => import( - '../xtream-electron/category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), }, { @@ -39,7 +39,7 @@ export const stalkerRoutes: Route[] = [ }, loadComponent: () => import( - '../xtream-electron/category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), }, ], @@ -68,7 +68,7 @@ export const stalkerRoutes: Route[] = [ path: '', loadComponent: () => import( - '../xtream-electron/category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), data: { api: 'stalker', @@ -79,7 +79,7 @@ export const stalkerRoutes: Route[] = [ path: ':categoryId', loadComponent: () => import( - '../xtream-electron/category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), data: { api: 'stalker', @@ -113,7 +113,7 @@ export const stalkerRoutes: Route[] = [ path: 'downloads', loadComponent: () => import( - '../xtream-electron/downloads/downloads.component' + '@iptvnator/portal/downloads/feature' ).then((c) => c.DownloadsComponent), }, ], diff --git a/apps/web/src/app/workspace/favorites-context.service.ts b/apps/web/src/app/workspace/favorites-context.service.ts index fc4186e4d..e95285d1c 100644 --- a/apps/web/src/app/workspace/favorites-context.service.ts +++ b/apps/web/src/app/workspace/favorites-context.service.ts @@ -1,35 +1 @@ -import { Injectable, signal } from '@angular/core'; -import { XtreamCategory } from 'shared-interfaces'; - -/** - * Lightweight service that bridges the favorites/recently-viewed routed - * components (inside the router-outlet) with the WorkspaceShellComponent - * (the outer shell that renders the context panel aside). - * - * The routed component pushes its category list here via an effect; - * the workspace shell reads it to populate the context panel. - */ -@Injectable({ providedIn: 'root' }) -export class FavoritesContextService { - /** Category list managed by the active routed component (Favorites / RecentlyViewed). */ - readonly categories = signal([]); - - /** Currently selected category id — shared between panel and content. */ - readonly selectedCategoryId = signal('all'); - - /** Called by the context panel when the user clicks a category. */ - setCategoryId(id: string): void { - this.selectedCategoryId.set(id); - } - - /** Called by the routed component to push its category list into the panel. */ - setCategories(categories: XtreamCategory[]): void { - this.categories.set(categories); - } - - /** Reset to defaults when navigating away from favorites/recent sections. */ - reset(): void { - this.categories.set([]); - this.selectedCategoryId.set('all'); - } -} +export { FavoritesContextService } from '@iptvnator/portal/shared/util'; diff --git a/apps/web/src/app/workspace/global-favorites/global-favorites-page.component.ts b/apps/web/src/app/workspace/global-favorites/global-favorites-page.component.ts index 797a5ffef..d8a674a4c 100644 --- a/apps/web/src/app/workspace/global-favorites/global-favorites-page.component.ts +++ b/apps/web/src/app/workspace/global-favorites/global-favorites-page.component.ts @@ -29,8 +29,8 @@ import { import { EpgViewComponent } from 'shared-portals'; import { PlayerService } from '../../services/player.service'; import { SettingsStore } from '../../services/settings-store.service'; -import { XtreamApiService } from '../../xtream-electron/services/xtream-api.service'; -import { XtreamUrlService } from '../../xtream-electron/services/xtream-url.service'; +import { XtreamApiService } from '@iptvnator/portal/xtream/data-access'; +import { XtreamUrlService } from '@iptvnator/portal/xtream/data-access'; import { GlobalFavoritesListComponent } from './global-favorites-list.component'; import { GlobalFavoritesService } from './global-favorites.service'; import { UnifiedFavoriteChannel } from './unified-favorite-channel.interface'; diff --git a/apps/web/src/app/workspace/workspace-context-panel.component.ts b/apps/web/src/app/workspace/workspace-context-panel.component.ts index 4c8d3f70f..b8657fab8 100644 --- a/apps/web/src/app/workspace/workspace-context-panel.component.ts +++ b/apps/web/src/app/workspace/workspace-context-panel.component.ts @@ -5,14 +5,14 @@ import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatTooltip } from '@angular/material/tooltip'; import { Router } from '@angular/router'; -import { CategoryViewComponent } from '../shared/components/category-view/category-view.component'; -import { PlaylistErrorViewComponent } from '../shared/components/playlist-error-view/playlist-error-view.component'; -import { StalkerStore } from '../stalker/stalker.store'; +import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; +import { PlaylistErrorViewComponent } from '@iptvnator/portal/shared/ui'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; import { CategoryManagementDialogComponent, CategoryManagementDialogData, } from '../xtream-electron/category-management-dialog/category-management-dialog.component'; -import { XtreamStore } from '../xtream-electron/stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; type WorkspaceProvider = 'xtreams' | 'stalker' | 'playlists'; diff --git a/apps/web/src/app/workspace/workspace-favorites-context-panel.component.ts b/apps/web/src/app/workspace/workspace-favorites-context-panel.component.ts index dd4c824bf..a76df9927 100644 --- a/apps/web/src/app/workspace/workspace-favorites-context-panel.component.ts +++ b/apps/web/src/app/workspace/workspace-favorites-context-panel.component.ts @@ -1,5 +1,5 @@ import { Component, computed, inject } from '@angular/core'; -import { CategoryViewComponent } from '../shared/components/category-view/category-view.component'; +import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; import { FavoritesContextService } from './favorites-context.service'; /** diff --git a/apps/web/src/app/workspace/workspace-shell.component.spec.ts b/apps/web/src/app/workspace/workspace-shell.component.spec.ts index d4100e4cf..15a44a7d7 100644 --- a/apps/web/src/app/workspace/workspace-shell.component.spec.ts +++ b/apps/web/src/app/workspace/workspace-shell.component.spec.ts @@ -8,7 +8,7 @@ import { PlaylistsService } from 'services'; import { DownloadsService } from '../services/downloads.service'; import { ExternalPlaybackService } from '../services/external-playback.service'; import { SettingsStore } from '../services/settings-store.service'; -import { XtreamStore } from '../xtream-electron/stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; import { FavoritesContextService } from './favorites-context.service'; import { SettingsContextService } from './settings-context.service'; import { WorkspaceShellComponent } from './workspace-shell.component'; diff --git a/apps/web/src/app/workspace/workspace-shell.component.ts b/apps/web/src/app/workspace/workspace-shell.component.ts index 260e2fda8..7c575bf60 100644 --- a/apps/web/src/app/workspace/workspace-shell.component.ts +++ b/apps/web/src/app/workspace/workspace-shell.component.ts @@ -43,12 +43,12 @@ import { ExternalPlaybackDockComponent } from '../shared/components/external-pla import { buildPortalRailLinks, PortalRailLink, -} from '../shared/navigation/portal-rail-links'; -import { PortalRailLinksComponent } from '../shared/navigation/portal-rail-links.component'; +} from '@iptvnator/portal/shared/util'; +import { PortalRailLinksComponent } from '@iptvnator/portal/shared/ui'; import { AccountInfoComponent } from '../xtream-electron/account-info/account-info.component'; import { GlobalRecentlyViewedComponent } from '../xtream-electron/recently-viewed/global-recently-viewed.component'; import { GlobalSearchResultsComponent } from '../xtream-electron/search-results/global-search-results.component'; -import { XtreamStore } from '../xtream-electron/stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; import { FavoritesContextService } from './favorites-context.service'; import { SettingsContextService } from './settings-context.service'; import { diff --git a/apps/web/src/app/xtream-electron/account-info/account-info.component.ts b/apps/web/src/app/xtream-electron/account-info/account-info.component.ts index f463a92a3..cb84be1cc 100644 --- a/apps/web/src/app/xtream-electron/account-info/account-info.component.ts +++ b/apps/web/src/app/xtream-electron/account-info/account-info.component.ts @@ -5,9 +5,9 @@ import { MatListModule } from '@angular/material/list'; import { Store } from '@ngrx/store'; import { TranslatePipe } from '@ngx-translate/core'; import { selectActivePlaylist } from 'm3u-state'; -import { XtreamApiService } from '../services/xtream-api.service'; -import { XtreamAccountInfo } from './account-info.interface'; -import { createLogger } from '../../shared/utils/logger'; +import { XtreamApiService } from '@iptvnator/portal/xtream/data-access'; +import { XtreamAccountInfo } from '@iptvnator/portal/xtream/data-access'; +import { createLogger } from '@iptvnator/portal/shared/util'; @Component({ selector: 'app-account-info', diff --git a/apps/web/src/app/xtream-electron/category-management-dialog/category-management-dialog.component.ts b/apps/web/src/app/xtream-electron/category-management-dialog/category-management-dialog.component.ts index 69b6319ba..d93d149c7 100644 --- a/apps/web/src/app/xtream-electron/category-management-dialog/category-management-dialog.component.ts +++ b/apps/web/src/app/xtream-electron/category-management-dialog/category-management-dialog.component.ts @@ -14,7 +14,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBar } from '@angular/material/snack-bar'; import { TranslatePipe } from '@ngx-translate/core'; import { DatabaseService, XCategoryFromDb } from 'services'; -import { createLogger } from '../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; export interface CategoryManagementDialogData { playlistId: string; diff --git a/apps/web/src/app/xtream-electron/favorites/favorites.component.ts b/apps/web/src/app/xtream-electron/favorites/favorites.component.ts index 9f2d13e3d..a91a17ab9 100644 --- a/apps/web/src/app/xtream-electron/favorites/favorites.component.ts +++ b/apps/web/src/app/xtream-electron/favorites/favorites.component.ts @@ -16,23 +16,23 @@ import { TranslatePipe } from '@ngx-translate/core'; import { selectActivePlaylist } from 'm3u-state'; import { BehaviorSubject, switchMap } from 'rxjs'; import { PlayerService } from '../../services/player.service'; -import { PortalCollectionLiveShellComponent } from '../../shared/components/portal-collection-live-shell/portal-collection-live-shell.component'; +import { PortalCollectionLiveShellComponent } from '@iptvnator/portal/shared/ui'; import { PortalCollectionMode, PortalCollectionShellComponent, PortalCollectionShellLayout, -} from '../../shared/components/portal-collection-shell/portal-collection-shell.component'; -import { queryParamSignal } from '../../shared/navigation/portal-route.utils'; -import { createPortalCollectionContext } from '../../shared/utils/portal-collection-context'; +} from '@iptvnator/portal/shared/ui'; +import { queryParamSignal } from '@iptvnator/portal/shared/util'; +import { createPortalCollectionContext } from '@iptvnator/portal/shared/util'; import { buildStandardCollectionCategories, filterCollectionBucket, -} from '../../shared/utils/portal-collection-items'; -import { FavoritesContextService } from '../../workspace/favorites-context.service'; +} from '@iptvnator/portal/shared/util'; +import { FavoritesContextService } from '@iptvnator/portal/shared/util'; import { PortalChannelsListComponent } from '../portal-channels-list/portal-channels-list.component'; -import { FavoriteItem } from '../services/favorite-item.interface'; -import { FavoritesService } from '../services/favorites.service'; -import { XtreamStore } from '../stores/xtream.store'; +import { FavoriteItem } from '@iptvnator/portal/xtream/data-access'; +import { FavoritesService } from '@iptvnator/portal/xtream/data-access'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; const XTREAM_FAVORITES_LAYOUT: PortalCollectionShellLayout = {}; const XTREAM_COLLECTION_LABELS = { diff --git a/apps/web/src/app/xtream-electron/live-stream-layout/live-stream-layout.component.ts b/apps/web/src/app/xtream-electron/live-stream-layout/live-stream-layout.component.ts index b22be80bd..2a1e2ab52 100644 --- a/apps/web/src/app/xtream-electron/live-stream-layout/live-stream-layout.component.ts +++ b/apps/web/src/app/xtream-electron/live-stream-layout/live-stream-layout.component.ts @@ -27,9 +27,9 @@ import { PlaylistSwitcherComponent, ResizableDirective } from 'components'; import { XtreamCategory } from 'shared-interfaces'; import { EpgViewComponent, WebPlayerViewComponent } from 'shared-portals'; import { SettingsStore } from '../../services/settings-store.service'; -import { CategoryViewComponent } from '../../shared/components/category-view/category-view.component'; -import { PortalEmptyStateComponent } from '../../shared/components/portal-empty-state/portal-empty-state.component'; -import { isWorkspaceLayoutRoute } from '../../shared/navigation/portal-route.utils'; +import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; +import { PortalEmptyStateComponent } from '@iptvnator/portal/shared/ui'; +import { isWorkspaceLayoutRoute } from '@iptvnator/portal/shared/util'; import { getAdjacentChannelItem, getChannelItemByNumber, @@ -39,8 +39,8 @@ import { CategoryManagementDialogData, } from '../category-management-dialog/category-management-dialog.component'; import { PortalChannelsListComponent } from '../portal-channels-list/portal-channels-list.component'; -import { FavoritesService } from '../services/favorites.service'; -import { XtreamStore } from '../stores/xtream.store'; +import { FavoritesService } from '@iptvnator/portal/xtream/data-access'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; type LiveChannelSortMode = 'server' | 'name-asc' | 'name-desc'; const LIVE_CHANNEL_SORT_STORAGE_KEY = 'xtream-live-channel-sort-mode'; diff --git a/apps/web/src/app/xtream-electron/player-dialog/player-dialog.component.ts b/apps/web/src/app/xtream-electron/player-dialog/player-dialog.component.ts index 2efc1fd40..89688db6e 100644 --- a/apps/web/src/app/xtream-electron/player-dialog/player-dialog.component.ts +++ b/apps/web/src/app/xtream-electron/player-dialog/player-dialog.component.ts @@ -8,7 +8,7 @@ import { MatTooltip } from '@angular/material/tooltip'; import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { PlayerContentInfo } from 'shared-interfaces'; import { WebPlayerViewComponent } from 'shared-portals'; -import { XtreamStore } from '../stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; export interface PlayerDialogData { streamUrl: string; diff --git a/apps/web/src/app/xtream-electron/portal-channels-list/portal-channels-list.component.ts b/apps/web/src/app/xtream-electron/portal-channels-list/portal-channels-list.component.ts index 3b1efbad4..3ac10e531 100644 --- a/apps/web/src/app/xtream-electron/portal-channels-list/portal-channels-list.component.ts +++ b/apps/web/src/app/xtream-electron/portal-channels-list/portal-channels-list.component.ts @@ -29,10 +29,10 @@ import { XtreamItem, } from 'shared-interfaces'; import { ChannelListItemComponent } from 'components'; -import { EpgQueueService } from '../services/epg-queue.service'; -import { XtreamCredentials } from '../services/xtream-api.service'; -import { FavoritesService } from '../services/favorites.service'; -import { XtreamStore } from '../stores/xtream.store'; +import { EpgQueueService } from '@iptvnator/portal/xtream/data-access'; +import { XtreamCredentials } from '@iptvnator/portal/xtream/data-access'; +import { FavoritesService } from '@iptvnator/portal/xtream/data-access'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; type LiveChannelSortMode = 'server' | 'name-asc' | 'name-desc'; diff --git a/apps/web/src/app/xtream-electron/recently-added/recently-added.component.ts b/apps/web/src/app/xtream-electron/recently-added/recently-added.component.ts index ca046f63f..2051820f6 100644 --- a/apps/web/src/app/xtream-electron/recently-added/recently-added.component.ts +++ b/apps/web/src/app/xtream-electron/recently-added/recently-added.component.ts @@ -1,9 +1,9 @@ import { Component, computed, inject } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslatePipe } from '@ngx-translate/core'; -import { ContentCardComponent } from '../../shared/components/content-card/content-card.component'; -import { XtreamStore } from '../stores/xtream.store'; -import { ContentType } from '../xtream-state'; +import { ContentCardComponent } from '@iptvnator/portal/shared/ui'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { ContentType } from '@iptvnator/portal/xtream/data-access'; @Component({ selector: 'app-recently-added', diff --git a/apps/web/src/app/xtream-electron/recently-viewed/global-recently-viewed.component.ts b/apps/web/src/app/xtream-electron/recently-viewed/global-recently-viewed.component.ts index f204311cc..46d561b5d 100644 --- a/apps/web/src/app/xtream-electron/recently-viewed/global-recently-viewed.component.ts +++ b/apps/web/src/app/xtream-electron/recently-viewed/global-recently-viewed.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { RecentlyViewedComponent } from './recently-viewed.component'; -import { XtreamStore } from '../stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; @Component({ selector: 'app-global-recently-viewed', diff --git a/apps/web/src/app/xtream-electron/recently-viewed/recently-viewed.component.ts b/apps/web/src/app/xtream-electron/recently-viewed/recently-viewed.component.ts index bdbdfa622..7a4764611 100644 --- a/apps/web/src/app/xtream-electron/recently-viewed/recently-viewed.component.ts +++ b/apps/web/src/app/xtream-electron/recently-viewed/recently-viewed.component.ts @@ -21,28 +21,28 @@ import groupBy from 'lodash/groupBy'; import { firstValueFrom } from 'rxjs'; import { DatabaseService, PlaylistsService } from 'services'; import { PlayerService } from '../../services/player.service'; -import { ContentCardComponent } from '../../shared/components/content-card/content-card.component'; +import { ContentCardComponent } from '@iptvnator/portal/shared/ui'; import { PortalCollectionLiveShellComponent, -} from '../../shared/components/portal-collection-live-shell/portal-collection-live-shell.component'; +} from '@iptvnator/portal/shared/ui'; import { PortalCollectionMode, PortalCollectionShellComponent, PortalCollectionShellLayout, -} from '../../shared/components/portal-collection-shell/portal-collection-shell.component'; +} from '@iptvnator/portal/shared/ui'; import { isWorkspaceLayoutRoute, queryParamSignal, -} from '../../shared/navigation/portal-route.utils'; -import { createPortalCollectionContext } from '../../shared/utils/portal-collection-context'; +} from '@iptvnator/portal/shared/util'; +import { createPortalCollectionContext } from '@iptvnator/portal/shared/util'; import { buildStandardCollectionCategories, filterCollectionBucket, -} from '../../shared/utils/portal-collection-items'; -import { createLogger } from '../../shared/utils/logger'; -import { FavoritesContextService } from '../../workspace/favorites-context.service'; +} from '@iptvnator/portal/shared/util'; +import { createLogger } from '@iptvnator/portal/shared/util'; +import { FavoritesContextService } from '@iptvnator/portal/shared/util'; import { PortalChannelsListComponent } from '../portal-channels-list/portal-channels-list.component'; -import { XtreamStore } from '../stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; const XTREAM_RECENT_LAYOUT: Omit< PortalCollectionShellLayout, diff --git a/apps/web/src/app/xtream-electron/search-results/global-search-results.component.ts b/apps/web/src/app/xtream-electron/search-results/global-search-results.component.ts index 6d56e0882..865366eee 100644 --- a/apps/web/src/app/xtream-electron/search-results/global-search-results.component.ts +++ b/apps/web/src/app/xtream-electron/search-results/global-search-results.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { SearchResultsComponent } from './search-results.component'; -import { XtreamStore } from '../stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; @Component({ selector: 'app-global-search-results', diff --git a/apps/web/src/app/xtream-electron/search-results/search-results.component.spec.ts b/apps/web/src/app/xtream-electron/search-results/search-results.component.spec.ts index 25dd601c5..015e9f054 100644 --- a/apps/web/src/app/xtream-electron/search-results/search-results.component.spec.ts +++ b/apps/web/src/app/xtream-electron/search-results/search-results.component.spec.ts @@ -4,7 +4,7 @@ import { ActivatedRoute, Router, convertToParamMap } from '@angular/router'; import { of } from 'rxjs'; import { DatabaseService } from 'services'; import { SearchResultsComponent } from './search-results.component'; -import { XtreamStore } from '../stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; class MockXtreamStore { readonly searchTerm = signal(''); diff --git a/apps/web/src/app/xtream-electron/search-results/search-results.component.ts b/apps/web/src/app/xtream-electron/search-results/search-results.component.ts index ce9345bcc..e66fd7794 100644 --- a/apps/web/src/app/xtream-electron/search-results/search-results.component.ts +++ b/apps/web/src/app/xtream-electron/search-results/search-results.component.ts @@ -23,17 +23,17 @@ import { ActivatedRoute, Router } from '@angular/router'; import { TranslatePipe } from '@ngx-translate/core'; import groupBy from 'lodash/groupBy'; import { DatabaseService } from 'services'; -import { ContentCardComponent } from '../../shared/components/content-card/content-card.component'; -import { SearchLayoutComponent } from '../../shared/components/search-layout/search-layout.component'; +import { ContentCardComponent } from '@iptvnator/portal/shared/ui'; +import { SearchLayoutComponent } from '@iptvnator/portal/shared/ui'; import { isWorkspaceLayoutRoute, queryParamSignal, -} from '../../shared/navigation/portal-route.utils'; -import { createLogger } from '../../shared/utils/logger'; -import { XtreamContentItem } from '../data-sources/xtream-data-source.interface'; -import { SearchFilters } from '../stores/features/with-search.feature'; -import { XtreamStore } from '../stores/xtream.store'; -import { ContentType } from '../xtream-state'; +} from '@iptvnator/portal/shared/util'; +import { createLogger } from '@iptvnator/portal/shared/util'; +import { XtreamContentItem } from '@iptvnator/portal/xtream/data-access'; +import { SearchFilters } from '@iptvnator/portal/xtream/data-access'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { ContentType } from '@iptvnator/portal/xtream/data-access'; interface SearchResultsData { isGlobalSearch: boolean; diff --git a/apps/web/src/app/xtream-electron/season-container/season-container.component.ts b/apps/web/src/app/xtream-electron/season-container/season-container.component.ts index 16ccaf673..0b5db08f2 100644 --- a/apps/web/src/app/xtream-electron/season-container/season-container.component.ts +++ b/apps/web/src/app/xtream-electron/season-container/season-container.component.ts @@ -7,12 +7,12 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatTooltipModule } from '@angular/material/tooltip'; import { TranslateModule } from '@ngx-translate/core'; import { XtreamSerieEpisode, XtreamSerieEpisodeInfo } from 'shared-interfaces'; -import { XtreamStore } from '../stores/xtream.store'; -import { StalkerStore } from '../../stalker/stalker.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; import { ProgressCapsuleComponent } from '../shared/progress-capsule/progress-capsule.component'; import { WatchedBadgeComponent } from '../shared/watched-badge/watched-badge.component'; import { DownloadsService } from '../../services/downloads.service'; -import { createLogger } from '../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; type EpisodeViewMode = 'grid' | 'list'; const EPISODE_VIEW_MODE_KEY = 'iptvnator_episode_view_mode'; diff --git a/apps/web/src/app/xtream-electron/serial-details/serial-details.component.ts b/apps/web/src/app/xtream-electron/serial-details/serial-details.component.ts index 0cfda0846..c075b8cfe 100644 --- a/apps/web/src/app/xtream-electron/serial-details/serial-details.component.ts +++ b/apps/web/src/app/xtream-electron/serial-details/serial-details.component.ts @@ -14,7 +14,7 @@ import { PlayerService } from '../../services/player.service'; import { ExternalPlaybackService } from '../../services/external-playback.service'; import { PortalInlinePlayerComponent } from '../../shared/components/portal-inline-player/portal-inline-player.component'; import { SeasonContainerComponent } from '../season-container/season-container.component'; -import { XtreamStore } from '../stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; @Component({ selector: 'app-serial-details', diff --git a/apps/web/src/app/xtream-electron/services/index.ts b/apps/web/src/app/xtream-electron/services/index.ts deleted file mode 100644 index 76fcc2ad2..000000000 --- a/apps/web/src/app/xtream-electron/services/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './xtream-api.service'; -export * from './xtream-url.service'; diff --git a/apps/web/src/app/xtream-electron/vod-details/vod-details-route.component.ts b/apps/web/src/app/xtream-electron/vod-details/vod-details-route.component.ts index 39c2f32ab..8689bee6e 100644 --- a/apps/web/src/app/xtream-electron/vod-details/vod-details-route.component.ts +++ b/apps/web/src/app/xtream-electron/vod-details/vod-details-route.component.ts @@ -23,9 +23,9 @@ import { ExternalPlaybackService } from '../../services/external-playback.servic import { PlayerService } from '../../services/player.service'; import { SettingsStore } from '../../services/settings-store.service'; import { PortalInlinePlayerComponent } from '../../shared/components/portal-inline-player/portal-inline-player.component'; -import { XtreamStore } from '../stores/xtream.store'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; import { SafePipe } from '@iptvnator/pipes'; -import { createLogger } from '../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; /** * Route-based VOD details container for Xtream. diff --git a/apps/web/src/app/xtream-electron/vod-details/vod-details.component.ts b/apps/web/src/app/xtream-electron/vod-details/vod-details.component.ts index e3901ffd7..df47a9c6a 100644 --- a/apps/web/src/app/xtream-electron/vod-details/vod-details.component.ts +++ b/apps/web/src/app/xtream-electron/vod-details/vod-details.component.ts @@ -19,7 +19,7 @@ import { import { DownloadsService } from '../../services/downloads.service'; import { ExternalPlaybackService } from '../../services/external-playback.service'; import { SafePipe } from '@iptvnator/pipes'; -import { StalkerStore } from '../../stalker/stalker.store'; +import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; import { PortalInlinePlayerComponent } from '../../shared/components/portal-inline-player/portal-inline-player.component'; /** diff --git a/apps/web/src/app/xtream-electron/xtream-main-container.component.ts b/apps/web/src/app/xtream-electron/xtream-main-container.component.ts index 767062c12..d1df7f8d2 100644 --- a/apps/web/src/app/xtream-electron/xtream-main-container.component.ts +++ b/apps/web/src/app/xtream-electron/xtream-main-container.component.ts @@ -11,14 +11,14 @@ import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { PlaylistSwitcherComponent, ResizableDirective } from 'components'; import { XtreamCategory } from 'shared-interfaces'; -import { CategoryViewComponent } from '../shared/components/category-view/category-view.component'; -import { isWorkspaceLayoutRoute } from '../shared/navigation/portal-route.utils'; +import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; +import { isWorkspaceLayoutRoute } from '@iptvnator/portal/shared/util'; import { CategoryManagementDialogComponent, CategoryManagementDialogData, } from './category-management-dialog/category-management-dialog.component'; -import { XtreamStore } from './stores/xtream.store'; -import { XtreamCategorySortMode } from './stores/features/with-selection.feature'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; +import { XtreamCategorySortMode } from '@iptvnator/portal/xtream/data-access'; const XTREAM_CATEGORY_SORT_STORAGE_KEY = 'xtream-category-sort-mode'; diff --git a/apps/web/src/app/xtream-electron/xtream-shell/xtream-shell.component.ts b/apps/web/src/app/xtream-electron/xtream-shell/xtream-shell.component.ts index c50652df0..344ca5ba2 100644 --- a/apps/web/src/app/xtream-electron/xtream-shell/xtream-shell.component.ts +++ b/apps/web/src/app/xtream-electron/xtream-shell/xtream-shell.component.ts @@ -10,14 +10,14 @@ import { Store } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; import { PlaylistActions } from 'm3u-state'; import { filter } from 'rxjs'; -import { PortalRailSection } from '../../shared/navigation/portal-rail-links'; +import { PortalRailSection } from '@iptvnator/portal/shared/util'; import { isWorkspaceLayoutRoute, resolveCurrentPortalSection, -} from '../../shared/navigation/portal-route.utils'; +} from '@iptvnator/portal/shared/util'; import { LoadingOverlayComponent } from '../loading-overlay/loading-overlay.component'; -import { NavigationComponent } from '../navigation/navigation.component'; -import { XtreamStore } from '../stores/xtream.store'; +import { NavigationComponent } from '../../portal-shared/navigation/navigation.component'; +import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; @Component({ templateUrl: './xtream-shell.component.html', diff --git a/apps/web/src/app/xtream-electron/xtream.routes.ts b/apps/web/src/app/xtream-electron/xtream.routes.ts index 771c8312d..5d93ca960 100644 --- a/apps/web/src/app/xtream-electron/xtream.routes.ts +++ b/apps/web/src/app/xtream-electron/xtream.routes.ts @@ -40,14 +40,14 @@ export const xtreamRoutes: Route[] = [ path: '', loadComponent: () => import( - './category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), }, { path: ':categoryId', loadComponent: () => import( - './category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), }, { @@ -70,14 +70,14 @@ export const xtreamRoutes: Route[] = [ path: '', loadComponent: () => import( - './category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), }, { path: ':categoryId', loadComponent: () => import( - './category-content-view/category-content-view.component' + '../portal-shared/category-content-view/category-content-view.component' ).then((c) => c.CategoryContentViewComponent), }, { @@ -120,7 +120,7 @@ export const xtreamRoutes: Route[] = [ { path: 'downloads', loadComponent: () => - import('./downloads/downloads.component').then( + import('@iptvnator/portal/downloads/feature').then( (c) => c.DownloadsComponent ), }, diff --git a/eslint.config.mjs b/eslint.config.mjs index 57cb63f61..a3d6364b2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -17,8 +17,80 @@ export default [ allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$'], depConstraints: [ { - sourceTag: '*', - onlyDependOnLibsWithTags: ['*'], + sourceTag: 'type:app', + onlyDependOnLibsWithTags: [ + 'type:feature', + 'type:ui', + 'type:data-access', + 'type:util', + ], + }, + { + sourceTag: 'type:feature', + onlyDependOnLibsWithTags: [ + 'type:feature', + 'type:ui', + 'type:data-access', + 'type:util', + ], + }, + { + sourceTag: 'type:ui', + onlyDependOnLibsWithTags: [ + 'type:ui', + 'type:data-access', + 'type:util', + ], + }, + { + sourceTag: 'type:data-access', + onlyDependOnLibsWithTags: [ + 'type:data-access', + 'type:util', + ], + }, + { + sourceTag: 'type:util', + onlyDependOnLibsWithTags: ['type:util'], + }, + { + sourceTag: 'domain:portal-shared', + onlyDependOnLibsWithTags: [ + 'domain:portal-shared', + 'domain:m3u', + 'domain:playback', + 'scope:shared', + 'scope:portal', + ], + }, + { + sourceTag: 'domain:xtream', + onlyDependOnLibsWithTags: [ + 'domain:xtream', + 'domain:portal-shared', + 'domain:m3u', + 'scope:shared', + ], + }, + { + sourceTag: 'domain:stalker', + onlyDependOnLibsWithTags: [ + 'domain:stalker', + 'domain:portal-shared', + 'domain:m3u', + 'scope:shared', + ], + }, + { + sourceTag: 'domain:workspace', + onlyDependOnLibsWithTags: [ + 'domain:workspace', + 'domain:portal-shared', + 'domain:xtream', + 'domain:stalker', + 'domain:m3u', + 'scope:shared', + ], }, ], }, diff --git a/libs/m3u-state/project.json b/libs/m3u-state/project.json index 16c1b37af..3b07e511b 100644 --- a/libs/m3u-state/project.json +++ b/libs/m3u-state/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/m3u-state/src", "prefix": "lib", "projectType": "library", - "tags": [], + "tags": ["scope:playlist", "domain:m3u", "type:data-access"], "targets": { "test": { "executor": "@nx/jest:jest", diff --git a/libs/portal/downloads/feature/project.json b/libs/portal/downloads/feature/project.json new file mode 100644 index 000000000..305cabdde --- /dev/null +++ b/libs/portal/downloads/feature/project.json @@ -0,0 +1,13 @@ +{ + "name": "portal-downloads-feature", + "$schema": "../../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/portal/downloads/feature/src", + "prefix": "lib", + "projectType": "library", + "tags": ["scope:portal", "domain:portal-shared", "type:feature"], + "targets": { + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/portal/downloads/feature/src/index.ts b/libs/portal/downloads/feature/src/index.ts new file mode 100644 index 000000000..0499a3ee2 --- /dev/null +++ b/libs/portal/downloads/feature/src/index.ts @@ -0,0 +1 @@ +export * from './lib/downloads.component'; diff --git a/apps/web/src/app/xtream-electron/downloads/downloads.component.html b/libs/portal/downloads/feature/src/lib/downloads.component.html similarity index 100% rename from apps/web/src/app/xtream-electron/downloads/downloads.component.html rename to libs/portal/downloads/feature/src/lib/downloads.component.html diff --git a/apps/web/src/app/xtream-electron/downloads/downloads.component.scss b/libs/portal/downloads/feature/src/lib/downloads.component.scss similarity index 100% rename from apps/web/src/app/xtream-electron/downloads/downloads.component.scss rename to libs/portal/downloads/feature/src/lib/downloads.component.scss diff --git a/apps/web/src/app/xtream-electron/downloads/downloads.component.ts b/libs/portal/downloads/feature/src/lib/downloads.component.ts similarity index 96% rename from apps/web/src/app/xtream-electron/downloads/downloads.component.ts rename to libs/portal/downloads/feature/src/lib/downloads.component.ts index b7af85450..abbeb1da3 100644 --- a/apps/web/src/app/xtream-electron/downloads/downloads.component.ts +++ b/libs/portal/downloads/feature/src/lib/downloads.component.ts @@ -14,22 +14,23 @@ import { ActivatedRoute, Router } from '@angular/router'; import { TranslatePipe } from '@ngx-translate/core'; import { ResizableDirective } from 'components'; import { firstValueFrom, map } from 'rxjs'; -import { DatabaseService, PlaylistsService } from 'services'; import { - DownloadItem, + DatabaseService, + type DownloadItem, DownloadsService, -} from '../../services/downloads.service'; -import { CategoryViewComponent } from '../../shared/components/category-view/category-view.component'; + PlaylistsService, +} from 'services'; +import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; import { isWorkspaceLayoutRoute, queryParamSignal, -} from '../../shared/navigation/portal-route.utils'; -import { createPortalCollectionContext } from '../../shared/utils/portal-collection-context'; +} from '@iptvnator/portal/shared/util'; +import { createPortalCollectionContext } from '@iptvnator/portal/shared/util'; import { buildStandardCollectionCategories, filterCollectionBucket, -} from '../../shared/utils/portal-collection-items'; -import { FavoritesContextService } from '../../workspace/favorites-context.service'; +} from '@iptvnator/portal/shared/util'; +import { FavoritesContextService } from '@iptvnator/portal/shared/util'; type PortalSource = 'xtream' | 'stalker'; const DOWNLOAD_COLLECTION_LABELS = { @@ -44,7 +45,7 @@ const DOWNLOAD_COLLECTION_LABELS = { templateUrl: './downloads.component.html', styleUrls: [ './downloads.component.scss', - '../../shared/styles/portal-sidebar.scss', + '../../../../shared/ui/src/lib/styles/portal-sidebar.scss', ], changeDetection: ChangeDetectionStrategy.OnPush, imports: [ diff --git a/libs/portal/downloads/feature/tsconfig.json b/libs/portal/downloads/feature/tsconfig.json new file mode 100644 index 000000000..7d33479d8 --- /dev/null +++ b/libs/portal/downloads/feature/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "isolatedModules": true, + "target": "es2022", + "moduleResolution": "bundler", + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "emitDecoratorMetadata": false, + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/portal/downloads/feature/tsconfig.lib.json b/libs/portal/downloads/feature/tsconfig.lib.json new file mode 100644 index 000000000..7fba372dc --- /dev/null +++ b/libs/portal/downloads/feature/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/portal/shared/ui/project.json b/libs/portal/shared/ui/project.json new file mode 100644 index 000000000..758ca8fd4 --- /dev/null +++ b/libs/portal/shared/ui/project.json @@ -0,0 +1,13 @@ +{ + "name": "portal-shared-ui", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/portal/shared/ui/src", + "prefix": "lib", + "projectType": "library", + "tags": ["scope:portal", "domain:portal-shared", "type:ui"], + "targets": { + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/portal/shared/ui/src/index.ts b/libs/portal/shared/ui/src/index.ts new file mode 100644 index 000000000..e802a0003 --- /dev/null +++ b/libs/portal/shared/ui/src/index.ts @@ -0,0 +1,10 @@ +export * from './lib/components/category-view/category-view.component'; +export * from './lib/components/content-card/content-card.component'; +export * from './lib/components/favorites-layout/favorites-layout.component'; +export * from './lib/components/playlist-error-view/playlist-error-view.component'; +export * from './lib/components/portal-collection-live-shell/portal-collection-live-shell.component'; +export * from './lib/components/portal-collection-shell/portal-collection-shell.component'; +export * from './lib/components/portal-empty-state/portal-empty-state.component'; +export * from './lib/components/search-form/search-form.component'; +export * from './lib/components/search-layout/search-layout.component'; +export * from './lib/navigation/portal-rail-links.component'; diff --git a/apps/web/src/app/shared/components/category-view/category-view.component.html b/libs/portal/shared/ui/src/lib/components/category-view/category-view.component.html similarity index 100% rename from apps/web/src/app/shared/components/category-view/category-view.component.html rename to libs/portal/shared/ui/src/lib/components/category-view/category-view.component.html diff --git a/apps/web/src/app/shared/components/category-view/category-view.component.scss b/libs/portal/shared/ui/src/lib/components/category-view/category-view.component.scss similarity index 96% rename from apps/web/src/app/shared/components/category-view/category-view.component.scss rename to libs/portal/shared/ui/src/lib/components/category-view/category-view.component.scss index 6636ada5c..50f56ada8 100644 --- a/apps/web/src/app/shared/components/category-view/category-view.component.scss +++ b/libs/portal/shared/ui/src/lib/components/category-view/category-view.component.scss @@ -1,4 +1,4 @@ -@use '../../../../nav-list.scss'; +@use '../../../../../../../../apps/web/src/nav-list.scss'; :host { display: block; diff --git a/apps/web/src/app/shared/components/category-view/category-view.component.ts b/libs/portal/shared/ui/src/lib/components/category-view/category-view.component.ts similarity index 100% rename from apps/web/src/app/shared/components/category-view/category-view.component.ts rename to libs/portal/shared/ui/src/lib/components/category-view/category-view.component.ts diff --git a/apps/web/src/app/shared/components/content-card/content-card.component.html b/libs/portal/shared/ui/src/lib/components/content-card/content-card.component.html similarity index 100% rename from apps/web/src/app/shared/components/content-card/content-card.component.html rename to libs/portal/shared/ui/src/lib/components/content-card/content-card.component.html diff --git a/apps/web/src/app/shared/components/content-card/content-card.component.scss b/libs/portal/shared/ui/src/lib/components/content-card/content-card.component.scss similarity index 100% rename from apps/web/src/app/shared/components/content-card/content-card.component.scss rename to libs/portal/shared/ui/src/lib/components/content-card/content-card.component.scss diff --git a/apps/web/src/app/shared/components/content-card/content-card.component.ts b/libs/portal/shared/ui/src/lib/components/content-card/content-card.component.ts similarity index 100% rename from apps/web/src/app/shared/components/content-card/content-card.component.ts rename to libs/portal/shared/ui/src/lib/components/content-card/content-card.component.ts diff --git a/apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.html b/libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.html similarity index 100% rename from apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.html rename to libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.html diff --git a/apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.scss b/libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.scss similarity index 97% rename from apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.scss rename to libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.scss index b1ca43ae4..c1a3d1f47 100644 --- a/apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.scss +++ b/libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.scss @@ -1,5 +1,5 @@ @use '@angular/material' as mat; -@use '../../../shared/styles/content-grid' as grid; +@use '../../styles/content-grid' as grid; :host { display: flex; diff --git a/apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.ts b/libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.ts similarity index 96% rename from apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.ts rename to libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.ts index c009a4fd5..b39e18881 100644 --- a/apps/web/src/app/shared/components/favorites-layout/favorites-layout.component.ts +++ b/libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.ts @@ -5,7 +5,7 @@ import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute } from '@angular/router'; import { TranslatePipe } from '@ngx-translate/core'; import { PlaylistSwitcherComponent, ResizableDirective } from 'components'; -import { isWorkspaceLayoutRoute } from '../../navigation/portal-route.utils'; +import { isWorkspaceLayoutRoute } from '@iptvnator/portal/shared/util'; import { CategoryViewComponent } from '../category-view/category-view.component'; import { ContentCardComponent } from '../content-card/content-card.component'; diff --git a/apps/web/src/app/shared/components/playlist-error-view/playlist-error-view.component.html b/libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.html similarity index 100% rename from apps/web/src/app/shared/components/playlist-error-view/playlist-error-view.component.html rename to libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.html diff --git a/apps/web/src/app/shared/components/playlist-error-view/playlist-error-view.component.scss b/libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.scss similarity index 100% rename from apps/web/src/app/shared/components/playlist-error-view/playlist-error-view.component.scss rename to libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.scss diff --git a/apps/web/src/app/shared/components/playlist-error-view/playlist-error-view.component.ts b/libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.ts similarity index 100% rename from apps/web/src/app/shared/components/playlist-error-view/playlist-error-view.component.ts rename to libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.ts diff --git a/apps/web/src/app/shared/components/portal-collection-live-shell/portal-collection-live-shell.component.html b/libs/portal/shared/ui/src/lib/components/portal-collection-live-shell/portal-collection-live-shell.component.html similarity index 100% rename from apps/web/src/app/shared/components/portal-collection-live-shell/portal-collection-live-shell.component.html rename to libs/portal/shared/ui/src/lib/components/portal-collection-live-shell/portal-collection-live-shell.component.html diff --git a/apps/web/src/app/shared/components/portal-collection-live-shell/portal-collection-live-shell.component.scss b/libs/portal/shared/ui/src/lib/components/portal-collection-live-shell/portal-collection-live-shell.component.scss similarity index 100% rename from apps/web/src/app/shared/components/portal-collection-live-shell/portal-collection-live-shell.component.scss rename to libs/portal/shared/ui/src/lib/components/portal-collection-live-shell/portal-collection-live-shell.component.scss diff --git a/apps/web/src/app/shared/components/portal-collection-live-shell/portal-collection-live-shell.component.ts b/libs/portal/shared/ui/src/lib/components/portal-collection-live-shell/portal-collection-live-shell.component.ts similarity index 100% rename from apps/web/src/app/shared/components/portal-collection-live-shell/portal-collection-live-shell.component.ts rename to libs/portal/shared/ui/src/lib/components/portal-collection-live-shell/portal-collection-live-shell.component.ts diff --git a/apps/web/src/app/shared/components/portal-collection-shell/portal-collection-shell.component.html b/libs/portal/shared/ui/src/lib/components/portal-collection-shell/portal-collection-shell.component.html similarity index 100% rename from apps/web/src/app/shared/components/portal-collection-shell/portal-collection-shell.component.html rename to libs/portal/shared/ui/src/lib/components/portal-collection-shell/portal-collection-shell.component.html diff --git a/apps/web/src/app/shared/components/portal-collection-shell/portal-collection-shell.component.ts b/libs/portal/shared/ui/src/lib/components/portal-collection-shell/portal-collection-shell.component.ts similarity index 100% rename from apps/web/src/app/shared/components/portal-collection-shell/portal-collection-shell.component.ts rename to libs/portal/shared/ui/src/lib/components/portal-collection-shell/portal-collection-shell.component.ts diff --git a/apps/web/src/app/shared/components/portal-empty-state/portal-empty-state.component.html b/libs/portal/shared/ui/src/lib/components/portal-empty-state/portal-empty-state.component.html similarity index 100% rename from apps/web/src/app/shared/components/portal-empty-state/portal-empty-state.component.html rename to libs/portal/shared/ui/src/lib/components/portal-empty-state/portal-empty-state.component.html diff --git a/apps/web/src/app/shared/components/portal-empty-state/portal-empty-state.component.scss b/libs/portal/shared/ui/src/lib/components/portal-empty-state/portal-empty-state.component.scss similarity index 100% rename from apps/web/src/app/shared/components/portal-empty-state/portal-empty-state.component.scss rename to libs/portal/shared/ui/src/lib/components/portal-empty-state/portal-empty-state.component.scss diff --git a/apps/web/src/app/shared/components/portal-empty-state/portal-empty-state.component.ts b/libs/portal/shared/ui/src/lib/components/portal-empty-state/portal-empty-state.component.ts similarity index 100% rename from apps/web/src/app/shared/components/portal-empty-state/portal-empty-state.component.ts rename to libs/portal/shared/ui/src/lib/components/portal-empty-state/portal-empty-state.component.ts diff --git a/apps/web/src/app/shared/components/search-form/search-form.component.html b/libs/portal/shared/ui/src/lib/components/search-form/search-form.component.html similarity index 100% rename from apps/web/src/app/shared/components/search-form/search-form.component.html rename to libs/portal/shared/ui/src/lib/components/search-form/search-form.component.html diff --git a/apps/web/src/app/shared/components/search-form/search-form.component.ts b/libs/portal/shared/ui/src/lib/components/search-form/search-form.component.ts similarity index 100% rename from apps/web/src/app/shared/components/search-form/search-form.component.ts rename to libs/portal/shared/ui/src/lib/components/search-form/search-form.component.ts diff --git a/apps/web/src/app/shared/components/search-layout/search-layout.component.html b/libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.html similarity index 100% rename from apps/web/src/app/shared/components/search-layout/search-layout.component.html rename to libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.html diff --git a/apps/web/src/app/shared/components/search-layout/search-layout.component.scss b/libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.scss similarity index 100% rename from apps/web/src/app/shared/components/search-layout/search-layout.component.scss rename to libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.scss diff --git a/apps/web/src/app/shared/components/search-layout/search-layout.component.ts b/libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.ts similarity index 100% rename from apps/web/src/app/shared/components/search-layout/search-layout.component.ts rename to libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.ts diff --git a/apps/web/src/app/shared/navigation/portal-rail-links.component.html b/libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.html similarity index 100% rename from apps/web/src/app/shared/navigation/portal-rail-links.component.html rename to libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.html diff --git a/apps/web/src/app/shared/navigation/portal-rail-links.component.scss b/libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.scss similarity index 100% rename from apps/web/src/app/shared/navigation/portal-rail-links.component.scss rename to libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.scss diff --git a/apps/web/src/app/shared/navigation/portal-rail-links.component.ts b/libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.ts similarity index 95% rename from apps/web/src/app/shared/navigation/portal-rail-links.component.ts rename to libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.ts index b19254eb6..c52c784f1 100644 --- a/apps/web/src/app/shared/navigation/portal-rail-links.component.ts +++ b/libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.ts @@ -8,7 +8,7 @@ import { RouterLink, RouterLinkActive, } from '@angular/router'; -import { PortalRailLink, PortalRailSection } from './portal-rail-links'; +import { PortalRailLink, PortalRailSection } from '@iptvnator/portal/shared/util'; @Component({ selector: 'app-portal-rail-links', diff --git a/libs/portal/shared/ui/src/lib/styles/_content-grid.scss b/libs/portal/shared/ui/src/lib/styles/_content-grid.scss new file mode 100644 index 000000000..4c4ecc264 --- /dev/null +++ b/libs/portal/shared/ui/src/lib/styles/_content-grid.scss @@ -0,0 +1,3 @@ +// Canonical source: libs/ui/styles/_content-grid.scss +// This stub forwards the mixins for components that @use this file directly. +@forward '../../../../../../../libs/ui/styles/content-grid'; diff --git a/libs/portal/shared/ui/src/lib/styles/_portal-layout.scss b/libs/portal/shared/ui/src/lib/styles/_portal-layout.scss new file mode 100644 index 000000000..f55178146 --- /dev/null +++ b/libs/portal/shared/ui/src/lib/styles/_portal-layout.scss @@ -0,0 +1,3 @@ +// Canonical source: libs/ui/styles/_portal-layout.scss +// This stub forwards the mixin for components that @use this file directly. +@forward '../../../../../../../libs/ui/styles/portal-layout'; diff --git a/libs/portal/shared/ui/src/lib/styles/portal-sidebar.scss b/libs/portal/shared/ui/src/lib/styles/portal-sidebar.scss new file mode 100644 index 000000000..bcf319b34 --- /dev/null +++ b/libs/portal/shared/ui/src/lib/styles/portal-sidebar.scss @@ -0,0 +1,3 @@ +// Canonical source: libs/ui/styles/_portal-sidebar.scss +// This stub forwards the rules for components that @use this file directly. +@forward '../../../../../../../libs/ui/styles/portal-sidebar'; diff --git a/libs/portal/shared/ui/tsconfig.json b/libs/portal/shared/ui/tsconfig.json new file mode 100644 index 000000000..7d33479d8 --- /dev/null +++ b/libs/portal/shared/ui/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "isolatedModules": true, + "target": "es2022", + "moduleResolution": "bundler", + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "emitDecoratorMetadata": false, + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/portal/shared/ui/tsconfig.lib.json b/libs/portal/shared/ui/tsconfig.lib.json new file mode 100644 index 000000000..7fba372dc --- /dev/null +++ b/libs/portal/shared/ui/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/portal/shared/util/jest.config.ts b/libs/portal/shared/util/jest.config.ts new file mode 100644 index 000000000..f720a5e32 --- /dev/null +++ b/libs/portal/shared/util/jest.config.ts @@ -0,0 +1,21 @@ +export default { + displayName: 'portal-shared-util', + preset: '../../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../../coverage/libs/portal/shared/util', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/libs/portal/shared/util/project.json b/libs/portal/shared/util/project.json new file mode 100644 index 000000000..7b1fc5e5b --- /dev/null +++ b/libs/portal/shared/util/project.json @@ -0,0 +1,21 @@ +{ + "name": "portal-shared-util", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/portal/shared/util/src", + "prefix": "lib", + "projectType": "library", + "tags": ["scope:portal", "domain:portal-shared", "type:util"], + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/portal/shared/util/jest.config.ts", + "tsConfig": "libs/portal/shared/util/tsconfig.spec.json" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/portal/shared/util/src/index.ts b/libs/portal/shared/util/src/index.ts new file mode 100644 index 000000000..ebe1cd1e8 --- /dev/null +++ b/libs/portal/shared/util/src/index.ts @@ -0,0 +1,7 @@ +export * from './lib/favorites-context.service'; +export * from './lib/logger'; +export * from './lib/portal-player'; +export * from './lib/portal-collection-context'; +export * from './lib/portal-collection-items'; +export * from './lib/navigation/portal-rail-links'; +export * from './lib/navigation/portal-route.utils'; diff --git a/libs/portal/shared/util/src/lib/favorites-context.service.ts b/libs/portal/shared/util/src/lib/favorites-context.service.ts new file mode 100644 index 000000000..fc4186e4d --- /dev/null +++ b/libs/portal/shared/util/src/lib/favorites-context.service.ts @@ -0,0 +1,35 @@ +import { Injectable, signal } from '@angular/core'; +import { XtreamCategory } from 'shared-interfaces'; + +/** + * Lightweight service that bridges the favorites/recently-viewed routed + * components (inside the router-outlet) with the WorkspaceShellComponent + * (the outer shell that renders the context panel aside). + * + * The routed component pushes its category list here via an effect; + * the workspace shell reads it to populate the context panel. + */ +@Injectable({ providedIn: 'root' }) +export class FavoritesContextService { + /** Category list managed by the active routed component (Favorites / RecentlyViewed). */ + readonly categories = signal([]); + + /** Currently selected category id — shared between panel and content. */ + readonly selectedCategoryId = signal('all'); + + /** Called by the context panel when the user clicks a category. */ + setCategoryId(id: string): void { + this.selectedCategoryId.set(id); + } + + /** Called by the routed component to push its category list into the panel. */ + setCategories(categories: XtreamCategory[]): void { + this.categories.set(categories); + } + + /** Reset to defaults when navigating away from favorites/recent sections. */ + reset(): void { + this.categories.set([]); + this.selectedCategoryId.set('all'); + } +} diff --git a/apps/web/src/app/shared/utils/logger.spec.ts b/libs/portal/shared/util/src/lib/logger.spec.ts similarity index 83% rename from apps/web/src/app/shared/utils/logger.spec.ts rename to libs/portal/shared/util/src/lib/logger.spec.ts index 90c0ed4c6..1691cae71 100644 --- a/apps/web/src/app/shared/utils/logger.spec.ts +++ b/libs/portal/shared/util/src/lib/logger.spec.ts @@ -1,4 +1,3 @@ -import { AppConfig } from '../../../environments/environment'; import { createPortalDebugErrorEvent, createPortalDebugRequestContext, @@ -8,23 +7,26 @@ import { } from './logger'; describe('portal debug logger', () => { - const originalProduction = AppConfig.production; + const globalWithNgDevMode = globalThis as typeof globalThis & { + ngDevMode?: boolean; + }; + const originalNgDevMode = globalWithNgDevMode.ngDevMode; beforeEach(() => { - AppConfig.production = false; - jest.spyOn(console, 'groupCollapsed').mockImplementation(() => {}); - jest.spyOn(console, 'groupEnd').mockImplementation(() => {}); - jest.spyOn(console, 'log').mockImplementation(() => {}); - jest.spyOn(console, 'error').mockImplementation(() => {}); + globalWithNgDevMode.ngDevMode = true; + jest.spyOn(console, 'groupCollapsed').mockImplementation(() => undefined); + jest.spyOn(console, 'groupEnd').mockImplementation(() => undefined); + jest.spyOn(console, 'log').mockImplementation(() => undefined); + jest.spyOn(console, 'error').mockImplementation(() => undefined); }); afterEach(() => { - AppConfig.production = originalProduction; + globalWithNgDevMode.ngDevMode = originalNgDevMode; jest.restoreAllMocks(); }); it('does not log when production is enabled', () => { - AppConfig.production = true; + globalWithNgDevMode.ngDevMode = false; const context = createPortalDebugRequestContext({ provider: 'xtream', diff --git a/apps/web/src/app/shared/utils/logger.ts b/libs/portal/shared/util/src/lib/logger.ts similarity index 94% rename from apps/web/src/app/shared/utils/logger.ts rename to libs/portal/shared/util/src/lib/logger.ts index 5b9e6d85e..3bf74f493 100644 --- a/apps/web/src/app/shared/utils/logger.ts +++ b/libs/portal/shared/util/src/lib/logger.ts @@ -1,4 +1,3 @@ -import { AppConfig } from '../../../environments/environment'; import { PortalDebugEvent, PortalDebugProvider, @@ -12,9 +11,17 @@ export interface Logger { error: (...args: unknown[]) => void; } +function isProductionBuild(): boolean { + const globalWithNgDevMode = globalThis as typeof globalThis & { + ngDevMode?: boolean; + }; + + return globalWithNgDevMode.ngDevMode === false; +} + export function createLogger(scope: string): Logger { const prefix = `[${scope}]`; - const debugEnabled = !AppConfig.production; + const debugEnabled = !isProductionBuild(); return { debug: (...args: unknown[]) => { @@ -49,7 +56,7 @@ export interface PortalDebugRequestContext { let portalRequestSequence = 0; function isPortalDebugEnabled(): boolean { - return !AppConfig.production; + return !isProductionBuild(); } function getNow(): number { diff --git a/apps/web/src/app/shared/navigation/portal-rail-links.spec.ts b/libs/portal/shared/util/src/lib/navigation/portal-rail-links.spec.ts similarity index 100% rename from apps/web/src/app/shared/navigation/portal-rail-links.spec.ts rename to libs/portal/shared/util/src/lib/navigation/portal-rail-links.spec.ts diff --git a/apps/web/src/app/shared/navigation/portal-rail-links.ts b/libs/portal/shared/util/src/lib/navigation/portal-rail-links.ts similarity index 100% rename from apps/web/src/app/shared/navigation/portal-rail-links.ts rename to libs/portal/shared/util/src/lib/navigation/portal-rail-links.ts diff --git a/apps/web/src/app/shared/navigation/portal-route.utils.spec.ts b/libs/portal/shared/util/src/lib/navigation/portal-route.utils.spec.ts similarity index 100% rename from apps/web/src/app/shared/navigation/portal-route.utils.spec.ts rename to libs/portal/shared/util/src/lib/navigation/portal-route.utils.spec.ts diff --git a/apps/web/src/app/shared/navigation/portal-route.utils.ts b/libs/portal/shared/util/src/lib/navigation/portal-route.utils.ts similarity index 100% rename from apps/web/src/app/shared/navigation/portal-route.utils.ts rename to libs/portal/shared/util/src/lib/navigation/portal-route.utils.ts diff --git a/apps/web/src/app/shared/utils/portal-collection-context.spec.ts b/libs/portal/shared/util/src/lib/portal-collection-context.spec.ts similarity index 94% rename from apps/web/src/app/shared/utils/portal-collection-context.spec.ts rename to libs/portal/shared/util/src/lib/portal-collection-context.spec.ts index 97f869cea..ddfbbd756 100644 --- a/apps/web/src/app/shared/utils/portal-collection-context.spec.ts +++ b/libs/portal/shared/util/src/lib/portal-collection-context.spec.ts @@ -5,7 +5,7 @@ import { signal, } from '@angular/core'; import { TestBed } from '@angular/core/testing'; -import { FavoritesContextService } from '../../workspace/favorites-context.service'; +import { FavoritesContextService } from './favorites-context.service'; import { createPortalCollectionContext } from './portal-collection-context'; describe('portal-collection-context', () => { @@ -33,6 +33,7 @@ describe('portal-collection-context', () => { categories, }) ); + TestBed.flushEffects(); bridge.setCategoryId('all'); @@ -78,6 +79,7 @@ describe('portal-collection-context', () => { enabled: () => false, }) ); + TestBed.flushEffects(); bridge.setCategoryId('movie'); @@ -114,10 +116,12 @@ describe('portal-collection-context', () => { categories, }) ); + TestBed.flushEffects(); ctx.setCategoryId('movie'); childInjector.destroy(); + TestBed.flushEffects(); expect(ctx.categories()).toEqual([]); expect(ctx.selectedCategoryId()).toBe('all'); diff --git a/apps/web/src/app/shared/utils/portal-collection-context.ts b/libs/portal/shared/util/src/lib/portal-collection-context.ts similarity index 93% rename from apps/web/src/app/shared/utils/portal-collection-context.ts rename to libs/portal/shared/util/src/lib/portal-collection-context.ts index 2c7de38a6..f3169057d 100644 --- a/apps/web/src/app/shared/utils/portal-collection-context.ts +++ b/libs/portal/shared/util/src/lib/portal-collection-context.ts @@ -1,6 +1,6 @@ import { DestroyRef, Signal, effect, inject } from '@angular/core'; import { XtreamCategory } from 'shared-interfaces'; -import { FavoritesContextService } from '../../workspace/favorites-context.service'; +import { FavoritesContextService } from './favorites-context.service'; export interface PortalCollectionContextBridge { readonly selectedCategoryId: Signal; diff --git a/apps/web/src/app/shared/utils/portal-collection-items.spec.ts b/libs/portal/shared/util/src/lib/portal-collection-items.spec.ts similarity index 100% rename from apps/web/src/app/shared/utils/portal-collection-items.spec.ts rename to libs/portal/shared/util/src/lib/portal-collection-items.spec.ts diff --git a/apps/web/src/app/shared/utils/portal-collection-items.ts b/libs/portal/shared/util/src/lib/portal-collection-items.ts similarity index 100% rename from apps/web/src/app/shared/utils/portal-collection-items.ts rename to libs/portal/shared/util/src/lib/portal-collection-items.ts diff --git a/libs/portal/shared/util/src/lib/portal-player.ts b/libs/portal/shared/util/src/lib/portal-player.ts new file mode 100644 index 000000000..8ad88ebb8 --- /dev/null +++ b/libs/portal/shared/util/src/lib/portal-player.ts @@ -0,0 +1,29 @@ +import { InjectionToken } from '@angular/core'; +import { + ExternalPlayerSession, + ResolvedPortalPlayback, +} from 'shared-interfaces'; + +export interface PortalPlayer { + openPlayer( + streamUrl: string, + title: string, + thumbnail?: string | null, + hideExternalInfoDialog?: boolean, + isLiveContent?: boolean, + userAgent?: string, + referer?: string, + origin?: string, + contentInfo?: unknown, + startTime?: number, + headers?: Record + ): Promise; + openResolvedPlayback( + playback: ResolvedPortalPlayback, + hideExternalInfoDialog?: boolean + ): Promise; +} + +export const PORTAL_PLAYER = new InjectionToken( + 'PORTAL_PLAYER' +); diff --git a/libs/portal/shared/util/src/test-setup.ts b/libs/portal/shared/util/src/test-setup.ts new file mode 100644 index 000000000..0d88648e3 --- /dev/null +++ b/libs/portal/shared/util/src/test-setup.ts @@ -0,0 +1,6 @@ +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv({ + errorOnUnknownElements: true, + errorOnUnknownProperties: true, +}); diff --git a/libs/portal/shared/util/tsconfig.json b/libs/portal/shared/util/tsconfig.json new file mode 100644 index 000000000..dd63ae991 --- /dev/null +++ b/libs/portal/shared/util/tsconfig.json @@ -0,0 +1,31 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "isolatedModules": true, + "target": "es2022", + "moduleResolution": "bundler", + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "emitDecoratorMetadata": false, + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/portal/shared/util/tsconfig.lib.json b/libs/portal/shared/util/tsconfig.lib.json new file mode 100644 index 000000000..7fba372dc --- /dev/null +++ b/libs/portal/shared/util/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/portal/shared/util/tsconfig.spec.json b/libs/portal/shared/util/tsconfig.spec.json new file mode 100644 index 000000000..c0bb248be --- /dev/null +++ b/libs/portal/shared/util/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "module": "commonjs", + "target": "es2016", + "types": ["jest", "node"], + "moduleResolution": "node10" + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/libs/portal/stalker/data-access/jest.config.ts b/libs/portal/stalker/data-access/jest.config.ts new file mode 100644 index 000000000..9122c4e43 --- /dev/null +++ b/libs/portal/stalker/data-access/jest.config.ts @@ -0,0 +1,21 @@ +export default { + displayName: 'portal-stalker-data-access', + preset: '../../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../../coverage/libs/portal/stalker/data-access', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/libs/portal/stalker/data-access/project.json b/libs/portal/stalker/data-access/project.json new file mode 100644 index 000000000..9481498da --- /dev/null +++ b/libs/portal/stalker/data-access/project.json @@ -0,0 +1,21 @@ +{ + "name": "portal-stalker-data-access", + "$schema": "../../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/portal/stalker/data-access/src", + "prefix": "lib", + "projectType": "library", + "tags": ["scope:portal", "domain:stalker", "type:data-access"], + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/portal/stalker/data-access/jest.config.ts", + "tsConfig": "libs/portal/stalker/data-access/tsconfig.spec.json" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/portal/stalker/data-access/src/index.ts b/libs/portal/stalker/data-access/src/index.ts new file mode 100644 index 000000000..5af73ebfc --- /dev/null +++ b/libs/portal/stalker/data-access/src/index.ts @@ -0,0 +1,7 @@ +export * from './lib/models'; +export * from './lib/stores'; +export * from './lib/stalker-content-types'; +export * from './lib/stalker-live-playback.utils'; +export * from './lib/stalker-series.adapters'; +export * from './lib/stalker-vod.utils'; +export * from './lib/stalker.store'; diff --git a/apps/web/src/app/stalker/models/index.ts b/libs/portal/stalker/data-access/src/lib/models/index.ts similarity index 100% rename from apps/web/src/app/stalker/models/index.ts rename to libs/portal/stalker/data-access/src/lib/models/index.ts diff --git a/apps/web/src/app/stalker/models/stalker-category-item.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-category-item.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-category-item.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-category-item.interface.ts diff --git a/apps/web/src/app/stalker/models/stalker-content-item.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-content-item.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-content-item.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-content-item.interface.ts diff --git a/apps/web/src/app/stalker/models/stalker-favorite-item.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-favorite-item.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-favorite-item.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-favorite-item.interface.ts diff --git a/apps/web/src/app/stalker/models/stalker-itv-channel.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-itv-channel.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-itv-channel.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-itv-channel.interface.ts diff --git a/apps/web/src/app/stalker/models/stalker-season.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-season.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-season.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-season.interface.ts diff --git a/apps/web/src/app/stalker/models/stalker-serial-details.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-serial-details.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-serial-details.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-serial-details.interface.ts diff --git a/apps/web/src/app/stalker/models/stalker-vod-details.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-vod-details.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-vod-details.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-vod-details.interface.ts diff --git a/apps/web/src/app/stalker/models/stalker-vod-series.interface.ts b/libs/portal/stalker/data-access/src/lib/models/stalker-vod-series.interface.ts similarity index 100% rename from apps/web/src/app/stalker/models/stalker-vod-series.interface.ts rename to libs/portal/stalker/data-access/src/lib/models/stalker-vod-series.interface.ts diff --git a/apps/web/src/app/stalker/stalker-content-types.ts b/libs/portal/stalker/data-access/src/lib/stalker-content-types.ts similarity index 100% rename from apps/web/src/app/stalker/stalker-content-types.ts rename to libs/portal/stalker/data-access/src/lib/stalker-content-types.ts diff --git a/apps/web/src/app/stalker/stalker-live-playback.utils.ts b/libs/portal/stalker/data-access/src/lib/stalker-live-playback.utils.ts similarity index 100% rename from apps/web/src/app/stalker/stalker-live-playback.utils.ts rename to libs/portal/stalker/data-access/src/lib/stalker-live-playback.utils.ts diff --git a/apps/web/src/app/stalker/stalker-series.adapters.spec.ts b/libs/portal/stalker/data-access/src/lib/stalker-series.adapters.spec.ts similarity index 100% rename from apps/web/src/app/stalker/stalker-series.adapters.spec.ts rename to libs/portal/stalker/data-access/src/lib/stalker-series.adapters.spec.ts diff --git a/apps/web/src/app/stalker/stalker-series.adapters.ts b/libs/portal/stalker/data-access/src/lib/stalker-series.adapters.ts similarity index 100% rename from apps/web/src/app/stalker/stalker-series.adapters.ts rename to libs/portal/stalker/data-access/src/lib/stalker-series.adapters.ts diff --git a/apps/web/src/app/stalker/stalker-vod.utils.spec.ts b/libs/portal/stalker/data-access/src/lib/stalker-vod.utils.spec.ts similarity index 100% rename from apps/web/src/app/stalker/stalker-vod.utils.spec.ts rename to libs/portal/stalker/data-access/src/lib/stalker-vod.utils.spec.ts diff --git a/apps/web/src/app/stalker/stalker-vod.utils.ts b/libs/portal/stalker/data-access/src/lib/stalker-vod.utils.ts similarity index 100% rename from apps/web/src/app/stalker/stalker-vod.utils.ts rename to libs/portal/stalker/data-access/src/lib/stalker-vod.utils.ts diff --git a/apps/web/src/app/stalker/stalker.store.compat.spec.ts b/libs/portal/stalker/data-access/src/lib/stalker.store.compat.spec.ts similarity index 94% rename from apps/web/src/app/stalker/stalker.store.compat.spec.ts rename to libs/portal/stalker/data-access/src/lib/stalker.store.compat.spec.ts index 6d251025e..364d7bfb7 100644 --- a/apps/web/src/app/stalker/stalker.store.compat.spec.ts +++ b/libs/portal/stalker/data-access/src/lib/stalker.store.compat.spec.ts @@ -1,13 +1,14 @@ import { TestBed } from '@angular/core/testing'; import { MatSnackBar } from '@angular/material/snack-bar'; +import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; import { of } from 'rxjs'; +import { PORTAL_PLAYER } from '@iptvnator/portal/shared/util'; import { DataService, PlaylistsService, StalkerSessionService, } from 'services'; -import { PlayerService } from '../services/player.service'; import { StalkerStore } from './stalker.store'; describe('StalkerStore API compatibility smoke', () => { @@ -32,7 +33,7 @@ describe('StalkerStore API compatibility smoke', () => { }, }, { - provide: PlayerService, + provide: PORTAL_PLAYER, useValue: { openPlayer: jest.fn(), openResolvedPlayback: jest.fn(), @@ -49,6 +50,12 @@ describe('StalkerStore API compatibility smoke', () => { ), }, }, + { + provide: Store, + useValue: { + dispatch: jest.fn(), + }, + }, { provide: MatSnackBar, useValue: { diff --git a/apps/web/src/app/stalker/stalker.store.ts b/libs/portal/stalker/data-access/src/lib/stalker.store.ts similarity index 100% rename from apps/web/src/app/stalker/stalker.store.ts rename to libs/portal/stalker/data-access/src/lib/stalker.store.ts diff --git a/apps/web/src/app/stalker/stores/features/index.ts b/libs/portal/stalker/data-access/src/lib/stores/features/index.ts similarity index 100% rename from apps/web/src/app/stalker/stores/features/index.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/index.ts diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-content.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-content.feature.ts similarity index 99% rename from apps/web/src/app/stalker/stores/features/with-stalker-content.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-content.feature.ts index 5b76f4c3e..6516eff93 100644 --- a/apps/web/src/app/stalker/stores/features/with-stalker-content.feature.ts +++ b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-content.feature.ts @@ -14,7 +14,7 @@ import { STALKER_REQUEST, StalkerPortalActions, } from 'shared-interfaces'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { StalkerCategoryItem, StalkerContentItem, diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-epg.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-epg.feature.ts similarity index 100% rename from apps/web/src/app/stalker/stores/features/with-stalker-epg.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-epg.feature.ts diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-favorites.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-favorites.feature.ts similarity index 100% rename from apps/web/src/app/stalker/stores/features/with-stalker-favorites.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-favorites.feature.ts diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-player.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-player.feature.ts similarity index 99% rename from apps/web/src/app/stalker/stores/features/with-stalker-player.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-player.feature.ts index c29fe39af..c188fd2a0 100644 --- a/apps/web/src/app/stalker/stores/features/with-stalker-player.feature.ts +++ b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-player.feature.ts @@ -4,6 +4,7 @@ import { signalStoreFeature, withMethods } from '@ngrx/signals'; import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; import { PlaylistActions } from 'm3u-state'; +import { PORTAL_PLAYER } from '@iptvnator/portal/shared/util'; import { DataService, PlaylistsService, StalkerSessionService } from 'services'; import { Playlist, @@ -13,8 +14,7 @@ import { StalkerPortalActions, StalkerPortalItem, } from 'shared-interfaces'; -import { PlayerService } from '../../../services/player.service'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { StalkerContentTypes } from '../../stalker-content-types'; import { buildStalkerExternalPlaybackHeaders, @@ -63,7 +63,7 @@ export function withStalkerPlayer() { store, dataService = inject(DataService), playlistService = inject(PlaylistsService), - playerService = inject(PlayerService), + playerService = inject(PORTAL_PLAYER), stalkerSession = inject(StalkerSessionService), snackBar = inject(MatSnackBar), translate = inject(TranslateService), diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-portal.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-portal.feature.ts similarity index 98% rename from apps/web/src/app/stalker/stores/features/with-stalker-portal.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-portal.feature.ts index 4b3652275..9869f043c 100644 --- a/apps/web/src/app/stalker/stores/features/with-stalker-portal.feature.ts +++ b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-portal.feature.ts @@ -8,7 +8,7 @@ import { } from '@ngrx/signals'; import { Playlist, PlaylistMeta, STALKER_REQUEST } from 'shared-interfaces'; import { DataService, StalkerSessionService } from 'services'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; /** * Portal/session state and methods. diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-recent.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-recent.feature.ts similarity index 98% rename from apps/web/src/app/stalker/stores/features/with-stalker-recent.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-recent.feature.ts index 1c34487eb..c858ecbcc 100644 --- a/apps/web/src/app/stalker/stores/features/with-stalker-recent.feature.ts +++ b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-recent.feature.ts @@ -4,7 +4,7 @@ import { Store } from '@ngrx/store'; import { PlaylistActions } from 'm3u-state'; import { PlaylistsService } from 'services'; import { PlaylistMeta } from 'shared-interfaces'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; /** * Recently-viewed concern methods. diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-selection.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-selection.feature.ts similarity index 100% rename from apps/web/src/app/stalker/stores/features/with-stalker-selection.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-selection.feature.ts diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-series.feature.ts b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-series.feature.ts similarity index 99% rename from apps/web/src/app/stalker/stores/features/with-stalker-series.feature.ts rename to libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-series.feature.ts index 7e9a5c4e5..ae011cb27 100644 --- a/apps/web/src/app/stalker/stores/features/with-stalker-series.feature.ts +++ b/libs/portal/stalker/data-access/src/lib/stores/features/with-stalker-series.feature.ts @@ -19,7 +19,7 @@ import { sortEpisodesByNumber, sortVodSeriesSeasonsByNumber, } from '../utils'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; /** * Regular-series and VOD-series feature state. diff --git a/apps/web/src/app/stalker/stores/index.ts b/libs/portal/stalker/data-access/src/lib/stores/index.ts similarity index 100% rename from apps/web/src/app/stalker/stores/index.ts rename to libs/portal/stalker/data-access/src/lib/stores/index.ts diff --git a/apps/web/src/app/stalker/stores/utils/index.ts b/libs/portal/stalker/data-access/src/lib/stores/utils/index.ts similarity index 100% rename from apps/web/src/app/stalker/stores/utils/index.ts rename to libs/portal/stalker/data-access/src/lib/stores/utils/index.ts diff --git a/apps/web/src/app/stalker/stores/utils/stalker-content-mappers.ts b/libs/portal/stalker/data-access/src/lib/stores/utils/stalker-content-mappers.ts similarity index 100% rename from apps/web/src/app/stalker/stores/utils/stalker-content-mappers.ts rename to libs/portal/stalker/data-access/src/lib/stores/utils/stalker-content-mappers.ts diff --git a/apps/web/src/app/stalker/stores/utils/stalker-sorting.ts b/libs/portal/stalker/data-access/src/lib/stores/utils/stalker-sorting.ts similarity index 100% rename from apps/web/src/app/stalker/stores/utils/stalker-sorting.ts rename to libs/portal/stalker/data-access/src/lib/stores/utils/stalker-sorting.ts diff --git a/libs/portal/stalker/data-access/src/test-setup.ts b/libs/portal/stalker/data-access/src/test-setup.ts new file mode 100644 index 000000000..0d88648e3 --- /dev/null +++ b/libs/portal/stalker/data-access/src/test-setup.ts @@ -0,0 +1,6 @@ +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv({ + errorOnUnknownElements: true, + errorOnUnknownProperties: true, +}); diff --git a/libs/portal/stalker/data-access/tsconfig.json b/libs/portal/stalker/data-access/tsconfig.json new file mode 100644 index 000000000..dd63ae991 --- /dev/null +++ b/libs/portal/stalker/data-access/tsconfig.json @@ -0,0 +1,31 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "isolatedModules": true, + "target": "es2022", + "moduleResolution": "bundler", + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "emitDecoratorMetadata": false, + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/portal/stalker/data-access/tsconfig.lib.json b/libs/portal/stalker/data-access/tsconfig.lib.json new file mode 100644 index 000000000..7fba372dc --- /dev/null +++ b/libs/portal/stalker/data-access/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/portal/stalker/data-access/tsconfig.spec.json b/libs/portal/stalker/data-access/tsconfig.spec.json new file mode 100644 index 000000000..c0bb248be --- /dev/null +++ b/libs/portal/stalker/data-access/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "module": "commonjs", + "target": "es2016", + "types": ["jest", "node"], + "moduleResolution": "node10" + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/libs/portal/xtream/data-access/project.json b/libs/portal/xtream/data-access/project.json new file mode 100644 index 000000000..e4283185d --- /dev/null +++ b/libs/portal/xtream/data-access/project.json @@ -0,0 +1,13 @@ +{ + "name": "portal-xtream-data-access", + "$schema": "../../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/portal/xtream/data-access/src", + "prefix": "lib", + "projectType": "library", + "tags": ["scope:portal", "domain:xtream", "type:data-access"], + "targets": { + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/portal/xtream/data-access/src/index.ts b/libs/portal/xtream/data-access/src/index.ts new file mode 100644 index 000000000..78a8a65b9 --- /dev/null +++ b/libs/portal/xtream/data-access/src/index.ts @@ -0,0 +1,7 @@ +export * from './lib/account-info/account-info.interface'; +export * from './lib/data-sources'; +export * from './lib/services'; +export * from './lib/stores'; +export * from './lib/with-favorites.feature'; +export { withRecentItems } from './lib/with-recent-items'; +export * from './lib/xtream-state'; diff --git a/apps/web/src/app/xtream-electron/account-info/account-info.interface.ts b/libs/portal/xtream/data-access/src/lib/account-info/account-info.interface.ts similarity index 100% rename from apps/web/src/app/xtream-electron/account-info/account-info.interface.ts rename to libs/portal/xtream/data-access/src/lib/account-info/account-info.interface.ts diff --git a/apps/web/src/app/xtream-electron/data-sources/electron-xtream-data-source.ts b/libs/portal/xtream/data-access/src/lib/data-sources/electron-xtream-data-source.ts similarity index 100% rename from apps/web/src/app/xtream-electron/data-sources/electron-xtream-data-source.ts rename to libs/portal/xtream/data-access/src/lib/data-sources/electron-xtream-data-source.ts diff --git a/apps/web/src/app/xtream-electron/data-sources/index.ts b/libs/portal/xtream/data-access/src/lib/data-sources/index.ts similarity index 100% rename from apps/web/src/app/xtream-electron/data-sources/index.ts rename to libs/portal/xtream/data-access/src/lib/data-sources/index.ts diff --git a/apps/web/src/app/xtream-electron/data-sources/pwa-xtream-data-source.ts b/libs/portal/xtream/data-access/src/lib/data-sources/pwa-xtream-data-source.ts similarity index 99% rename from apps/web/src/app/xtream-electron/data-sources/pwa-xtream-data-source.ts rename to libs/portal/xtream/data-access/src/lib/data-sources/pwa-xtream-data-source.ts index 6367228b6..cffe2ee83 100644 --- a/apps/web/src/app/xtream-electron/data-sources/pwa-xtream-data-source.ts +++ b/libs/portal/xtream/data-access/src/lib/data-sources/pwa-xtream-data-source.ts @@ -5,7 +5,7 @@ import { XtreamSerieItem, XtreamVodStream, } from 'shared-interfaces'; -import { createLogger } from '../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { CategoryType, StreamType, diff --git a/apps/web/src/app/xtream-electron/data-sources/xtream-data-source.interface.ts b/libs/portal/xtream/data-access/src/lib/data-sources/xtream-data-source.interface.ts similarity index 100% rename from apps/web/src/app/xtream-electron/data-sources/xtream-data-source.interface.ts rename to libs/portal/xtream/data-access/src/lib/data-sources/xtream-data-source.interface.ts diff --git a/apps/web/src/app/xtream-electron/services/epg-queue.service.ts b/libs/portal/xtream/data-access/src/lib/services/epg-queue.service.ts similarity index 98% rename from apps/web/src/app/xtream-electron/services/epg-queue.service.ts rename to libs/portal/xtream/data-access/src/lib/services/epg-queue.service.ts index 760e71acb..d051a8f87 100644 --- a/apps/web/src/app/xtream-electron/services/epg-queue.service.ts +++ b/libs/portal/xtream/data-access/src/lib/services/epg-queue.service.ts @@ -2,7 +2,7 @@ import { inject, Injectable, OnDestroy } from '@angular/core'; import { Subject } from 'rxjs'; import { EpgItem } from 'shared-interfaces'; import { XtreamApiService, XtreamCredentials } from './xtream-api.service'; -import { createLogger } from '../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; interface CacheEntry { data: EpgItem[]; diff --git a/apps/web/src/app/xtream-electron/services/favorite-item.interface.ts b/libs/portal/xtream/data-access/src/lib/services/favorite-item.interface.ts similarity index 100% rename from apps/web/src/app/xtream-electron/services/favorite-item.interface.ts rename to libs/portal/xtream/data-access/src/lib/services/favorite-item.interface.ts diff --git a/apps/web/src/app/xtream-electron/services/favorites.service.ts b/libs/portal/xtream/data-access/src/lib/services/favorites.service.ts similarity index 100% rename from apps/web/src/app/xtream-electron/services/favorites.service.ts rename to libs/portal/xtream/data-access/src/lib/services/favorites.service.ts diff --git a/libs/portal/xtream/data-access/src/lib/services/index.ts b/libs/portal/xtream/data-access/src/lib/services/index.ts new file mode 100644 index 000000000..676af82ab --- /dev/null +++ b/libs/portal/xtream/data-access/src/lib/services/index.ts @@ -0,0 +1,5 @@ +export * from './epg-queue.service'; +export * from './favorite-item.interface'; +export * from './favorites.service'; +export * from './xtream-api.service'; +export * from './xtream-url.service'; diff --git a/apps/web/src/app/xtream-electron/services/xtream-api.service.ts b/libs/portal/xtream/data-access/src/lib/services/xtream-api.service.ts similarity index 99% rename from apps/web/src/app/xtream-electron/services/xtream-api.service.ts rename to libs/portal/xtream/data-access/src/lib/services/xtream-api.service.ts index a2bfe6ca4..5274e4562 100644 --- a/apps/web/src/app/xtream-electron/services/xtream-api.service.ts +++ b/libs/portal/xtream/data-access/src/lib/services/xtream-api.service.ts @@ -215,7 +215,7 @@ export class XtreamApiService { async getShortEpg( credentials: XtreamCredentials, streamId: number, - limit: number = 10 + limit = 10 ): Promise { const response: EpgResponse = await this.sendRequest( credentials.serverUrl, diff --git a/apps/web/src/app/xtream-electron/services/xtream-url.service.ts b/libs/portal/xtream/data-access/src/lib/services/xtream-url.service.ts similarity index 96% rename from apps/web/src/app/xtream-electron/services/xtream-url.service.ts rename to libs/portal/xtream/data-access/src/lib/services/xtream-url.service.ts index c3e874b6c..e54ea65c6 100644 --- a/apps/web/src/app/xtream-electron/services/xtream-url.service.ts +++ b/libs/portal/xtream/data-access/src/lib/services/xtream-url.service.ts @@ -3,7 +3,7 @@ import { XtreamSerieEpisode, XtreamVodDetails, } from 'shared-interfaces'; -import { SettingsStore } from '../../services/settings-store.service'; +import { SettingsStore } from 'services'; import { XtreamCredentials } from './xtream-api.service'; /** diff --git a/apps/web/src/app/xtream-electron/stores/features/index.ts b/libs/portal/xtream/data-access/src/lib/stores/features/index.ts similarity index 100% rename from apps/web/src/app/xtream-electron/stores/features/index.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/index.ts diff --git a/apps/web/src/app/xtream-electron/stores/features/with-content.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.ts similarity index 99% rename from apps/web/src/app/xtream-electron/stores/features/with-content.feature.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.ts index 291bc5fd1..5867ac103 100644 --- a/apps/web/src/app/xtream-electron/stores/features/with-content.feature.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.ts @@ -12,7 +12,7 @@ import { XtreamSerieItem, XtreamVodStream, } from 'shared-interfaces'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { XTREAM_DATA_SOURCE, XtreamCategoryFromDb, diff --git a/apps/web/src/app/xtream-electron/stores/features/with-epg.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-epg.feature.ts similarity index 98% rename from apps/web/src/app/xtream-electron/stores/features/with-epg.feature.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/with-epg.feature.ts index f34272f0e..70e5a9e65 100644 --- a/apps/web/src/app/xtream-electron/stores/features/with-epg.feature.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-epg.feature.ts @@ -10,7 +10,7 @@ import { XtreamApiService, XtreamCredentials, } from '../../services/xtream-api.service'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; /** * EPG state for managing Electronic Program Guide data diff --git a/apps/web/src/app/xtream-electron/stores/features/with-playback-positions.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-playback-positions.feature.ts similarity index 100% rename from apps/web/src/app/xtream-electron/stores/features/with-playback-positions.feature.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/with-playback-positions.feature.ts diff --git a/apps/web/src/app/xtream-electron/stores/features/with-player.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-player.feature.ts similarity index 98% rename from apps/web/src/app/xtream-electron/stores/features/with-player.feature.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/with-player.feature.ts index b8cdd587e..191c9bdcc 100644 --- a/apps/web/src/app/xtream-electron/stores/features/with-player.feature.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-player.feature.ts @@ -5,8 +5,8 @@ import { withMethods, withState, } from '@ngrx/signals'; +import { PORTAL_PLAYER } from '@iptvnator/portal/shared/util'; import { XtreamSerieEpisode, XtreamVodDetails } from 'shared-interfaces'; -import { PlayerService } from '../../../services/player.service'; import { XtreamCredentials } from '../../services/xtream-api.service'; import { XtreamUrlService } from '../../services/xtream-url.service'; @@ -40,7 +40,7 @@ export function withPlayer() { withMethods((store) => { const urlService = inject(XtreamUrlService); - const playerService = inject(PlayerService); + const playerService = inject(PORTAL_PLAYER); /** * Helper to get credentials from parent store diff --git a/apps/web/src/app/xtream-electron/stores/features/with-portal.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.ts similarity index 98% rename from apps/web/src/app/xtream-electron/stores/features/with-portal.feature.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.ts index e41b6bda7..3362848b3 100644 --- a/apps/web/src/app/xtream-electron/stores/features/with-portal.feature.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-portal.feature.ts @@ -17,7 +17,7 @@ import { XtreamCredentials, } from '../../services/xtream-api.service'; import { PortalStatusType } from '../../xtream-state'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; /** * Portal state for managing playlist and portal status diff --git a/apps/web/src/app/xtream-electron/stores/features/with-search.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-search.feature.ts similarity index 98% rename from apps/web/src/app/xtream-electron/stores/features/with-search.feature.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/with-search.feature.ts index 5493fc8be..3c25d0d4a 100644 --- a/apps/web/src/app/xtream-electron/stores/features/with-search.feature.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/features/with-search.feature.ts @@ -10,7 +10,7 @@ import { XTREAM_DATA_SOURCE, XtreamContentItem, } from '../../data-sources/xtream-data-source.interface'; -import { createLogger } from '../../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; /** * Search filters configuration diff --git a/apps/web/src/app/xtream-electron/stores/features/with-selection.feature.ts b/libs/portal/xtream/data-access/src/lib/stores/features/with-selection.feature.ts similarity index 100% rename from apps/web/src/app/xtream-electron/stores/features/with-selection.feature.ts rename to libs/portal/xtream/data-access/src/lib/stores/features/with-selection.feature.ts diff --git a/apps/web/src/app/xtream-electron/stores/index.ts b/libs/portal/xtream/data-access/src/lib/stores/index.ts similarity index 100% rename from apps/web/src/app/xtream-electron/stores/index.ts rename to libs/portal/xtream/data-access/src/lib/stores/index.ts diff --git a/apps/web/src/app/xtream-electron/stores/xtream.store.ts b/libs/portal/xtream/data-access/src/lib/stores/xtream.store.ts similarity index 99% rename from apps/web/src/app/xtream-electron/stores/xtream.store.ts rename to libs/portal/xtream/data-access/src/lib/stores/xtream.store.ts index 387e458ea..5b664956b 100644 --- a/apps/web/src/app/xtream-electron/stores/xtream.store.ts +++ b/libs/portal/xtream/data-access/src/lib/stores/xtream.store.ts @@ -13,7 +13,7 @@ import { XTREAM_DATA_SOURCE } from '../data-sources/xtream-data-source.interface import { XtreamApiService } from '../services/xtream-api.service'; // Import new feature stores -import { createLogger } from '../../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; import { withContent, withEpg, diff --git a/apps/web/src/app/xtream-electron/with-favorites.feature.ts b/libs/portal/xtream/data-access/src/lib/with-favorites.feature.ts similarity index 98% rename from apps/web/src/app/xtream-electron/with-favorites.feature.ts rename to libs/portal/xtream/data-access/src/lib/with-favorites.feature.ts index f4ee5bd07..b03286529 100644 --- a/apps/web/src/app/xtream-electron/with-favorites.feature.ts +++ b/libs/portal/xtream/data-access/src/lib/with-favorites.feature.ts @@ -7,7 +7,7 @@ import { } from '@ngrx/signals'; import { DatabaseService } from 'services'; import { FavoritesService } from './services/favorites.service'; -import { createLogger } from '../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; export const withFavorites = function () { const logger = createLogger('withFavorites'); diff --git a/apps/web/src/app/xtream-electron/with-recent-items.ts b/libs/portal/xtream/data-access/src/lib/with-recent-items.ts similarity index 99% rename from apps/web/src/app/xtream-electron/with-recent-items.ts rename to libs/portal/xtream/data-access/src/lib/with-recent-items.ts index c4690a56d..4ed45561c 100644 --- a/apps/web/src/app/xtream-electron/with-recent-items.ts +++ b/libs/portal/xtream/data-access/src/lib/with-recent-items.ts @@ -16,7 +16,7 @@ import { normalizeStalkerDate, PortalRecentItem, } from 'shared-interfaces'; -import { createLogger } from '../shared/utils/logger'; +import { createLogger } from '@iptvnator/portal/shared/util'; export interface RecentlyViewedItem extends PortalRecentItem { /** @deprecated Redundant — always equals `id`. Retained for compat. */ diff --git a/apps/web/src/app/xtream-electron/xtream-state.ts b/libs/portal/xtream/data-access/src/lib/xtream-state.ts similarity index 100% rename from apps/web/src/app/xtream-electron/xtream-state.ts rename to libs/portal/xtream/data-access/src/lib/xtream-state.ts diff --git a/libs/portal/xtream/data-access/tsconfig.json b/libs/portal/xtream/data-access/tsconfig.json new file mode 100644 index 000000000..7d33479d8 --- /dev/null +++ b/libs/portal/xtream/data-access/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "isolatedModules": true, + "target": "es2022", + "moduleResolution": "bundler", + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "emitDecoratorMetadata": false, + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/portal/xtream/data-access/tsconfig.lib.json b/libs/portal/xtream/data-access/tsconfig.lib.json new file mode 100644 index 000000000..7fba372dc --- /dev/null +++ b/libs/portal/xtream/data-access/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/services/project.json b/libs/services/project.json index 244e639ed..5b00320c0 100644 --- a/libs/services/project.json +++ b/libs/services/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/services/src", "prefix": "lib", "projectType": "library", - "tags": [], + "tags": ["scope:shared", "type:data-access"], "targets": { "test": { "executor": "@nx/jest:jest", diff --git a/libs/services/src/index.ts b/libs/services/src/index.ts index 29bd6de02..ad09928c0 100644 --- a/libs/services/src/index.ts +++ b/libs/services/src/index.ts @@ -1,8 +1,10 @@ export * from './lib/data.service'; export * from './lib/database-electron.service'; +export * from './lib/downloads.service'; export * from './lib/epg.service'; export * from './lib/playback-position.service'; export * from './lib/playlists.service'; export * from './lib/portal-status.service'; +export * from './lib/settings-store.service'; export * from './lib/sort.service'; export * from './lib/stalker-session.service'; diff --git a/libs/services/src/lib/downloads.service.ts b/libs/services/src/lib/downloads.service.ts new file mode 100644 index 000000000..992c3a45d --- /dev/null +++ b/libs/services/src/lib/downloads.service.ts @@ -0,0 +1,424 @@ +import { computed, inject, Injectable, OnDestroy, signal } from '@angular/core'; +import { SettingsStore } from './settings-store.service'; + +export type DownloadStatus = + | 'queued' + | 'downloading' + | 'completed' + | 'failed' + | 'canceled'; + +export interface DownloadItem { + id: number; + playlistId: string; + xtreamId: number; + contentType: 'vod' | 'episode'; + seriesXtreamId?: number; + seasonNumber?: number; + episodeNumber?: number; + title: string; + url: string; + fileName?: string; + filePath?: string; + posterUrl?: string; + status: DownloadStatus; + bytesDownloaded?: number; + totalBytes?: number; + errorMessage?: string; + createdAt?: string; + updatedAt?: string; +} + +@Injectable({ providedIn: 'root' }) +export class DownloadsService implements OnDestroy { + private readonly settingsStore = inject(SettingsStore); + private unsubscribe?: () => void; + + /** Signal for the list of downloads */ + readonly downloads = signal([]); + + /** Whether the download feature is available (Electron only) */ + readonly isAvailable = computed(() => !!window.electron?.downloadsGetList); + + /** Whether there are any downloads */ + readonly hasDownloads = computed(() => this.downloads().length > 0); + + /** Active downloads count */ + readonly activeCount = computed( + () => + this.downloads().filter( + (d) => d.status === 'queued' || d.status === 'downloading' + ).length + ); + + /** Completed downloads count */ + readonly completedCount = computed( + () => this.downloads().filter((d) => d.status === 'completed').length + ); + + /** Failed downloads count */ + readonly failedCount = computed( + () => + this.downloads().filter( + (d) => d.status === 'failed' || d.status === 'canceled' + ).length + ); + + /** Current download folder */ + readonly downloadFolder = signal(''); + + constructor() { + this.init(); + } + + private async init() { + if (!this.isAvailable()) { + return; + } + + // Load initial download list + await this.loadDownloads(); + + // Load download folder + await this.loadDownloadFolder(); + + // Subscribe to download updates + this.unsubscribe = window.electron.onDownloadsUpdate(() => { + this.loadDownloads(); + }); + } + + ngOnDestroy() { + this.unsubscribe?.(); + } + + /** + * Load downloads from the backend + */ + async loadDownloads(playlistId?: string): Promise { + if (!this.isAvailable()) return; + + try { + const list = await window.electron.downloadsGetList(playlistId); + this.downloads.set(list); + } catch (error) { + console.error('[DownloadsService] Error loading downloads:', error); + } + } + + /** + * Load or resolve download folder + */ + async loadDownloadFolder(): Promise { + if (!this.isAvailable()) return ''; + + // First check settings + const storedFolder = this.settingsStore.getDownloadFolder?.(); + if (storedFolder) { + this.downloadFolder.set(storedFolder); + return storedFolder; + } + + // Fall back to default + try { + const defaultFolder = + await window.electron.downloadsGetDefaultFolder(); + this.downloadFolder.set(defaultFolder); + return defaultFolder; + } catch (error) { + console.error( + '[DownloadsService] Error getting default folder:', + error + ); + return ''; + } + } + + /** + * Start a new download + */ + async startDownload(data: { + playlistId: string; + xtreamId: number; + contentType: 'vod' | 'episode'; + title: string; + url: string; + posterUrl?: string; + headers?: { userAgent?: string; referer?: string; origin?: string }; + seriesXtreamId?: number; + seasonNumber?: number; + episodeNumber?: number; + // Playlist info for auto-creation if needed (Stalker playlists) + playlistName?: string; + playlistType?: 'xtream' | 'stalker' | 'm3u-file' | 'm3u-text' | 'm3u-url'; + serverUrl?: string; + portalUrl?: string; + macAddress?: string; + }): Promise<{ success: boolean; id?: number; error?: string }> { + if (!this.isAvailable()) { + return { success: false, error: 'Downloads not available' }; + } + + const folder = await this.loadDownloadFolder(); + if (!folder) { + return { success: false, error: 'No download folder configured' }; + } + + try { + const result = await window.electron.downloadsStart({ + ...data, + downloadFolder: folder, + }); + return result; + } catch (error) { + console.error('[DownloadsService] Error starting download:', error); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } + } + + /** + * Cancel a download + */ + async cancelDownload( + downloadId: number + ): Promise<{ success: boolean; error?: string }> { + if (!this.isAvailable()) { + return { success: false, error: 'Downloads not available' }; + } + + try { + return await window.electron.downloadsCancel(downloadId); + } catch (error) { + console.error( + '[DownloadsService] Error canceling download:', + error + ); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } + } + + /** + * Retry a failed download + */ + async retryDownload( + downloadId: number + ): Promise<{ success: boolean; error?: string }> { + if (!this.isAvailable()) { + return { success: false, error: 'Downloads not available' }; + } + + const folder = await this.loadDownloadFolder(); + if (!folder) { + return { success: false, error: 'No download folder configured' }; + } + + try { + return await window.electron.downloadsRetry(downloadId, folder); + } catch (error) { + console.error( + '[DownloadsService] Error retrying download:', + error + ); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } + } + + /** + * Remove a download from the list + */ + async removeDownload( + downloadId: number + ): Promise<{ success: boolean; error?: string }> { + if (!this.isAvailable()) { + return { success: false, error: 'Downloads not available' }; + } + + try { + return await window.electron.downloadsRemove(downloadId); + } catch (error) { + console.error( + '[DownloadsService] Error removing download:', + error + ); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } + } + + /** + * Play a downloaded file + */ + async playDownload( + filePath: string + ): Promise<{ success: boolean; error?: string }> { + if (!this.isAvailable()) { + return { success: false, error: 'Downloads not available' }; + } + + try { + return await window.electron.downloadsPlayFile(filePath); + } catch (error) { + console.error('[DownloadsService] Error playing file:', error); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } + } + + /** + * Reveal file in system file manager + */ + async revealFile( + filePath: string + ): Promise<{ success: boolean; error?: string }> { + if (!this.isAvailable()) { + return { success: false, error: 'Downloads not available' }; + } + + try { + return await window.electron.downloadsRevealFile(filePath); + } catch (error) { + console.error('[DownloadsService] Error revealing file:', error); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } + } + + /** + * Select a new download folder + */ + async selectFolder(): Promise { + if (!this.isAvailable()) { + return null; + } + + try { + const folder = await window.electron.downloadsSelectFolder(); + if (folder) { + this.downloadFolder.set(folder); + // Save to settings + await this.settingsStore.updateSettings({ downloadFolder: folder }); + } + return folder; + } catch (error) { + console.error( + '[DownloadsService] Error selecting folder:', + error + ); + return null; + } + } + + /** + * Clear completed/failed downloads + */ + async clearCompleted( + playlistId?: string + ): Promise<{ success: boolean }> { + if (!this.isAvailable()) { + return { success: false }; + } + + try { + return await window.electron.downloadsClearCompleted(playlistId); + } catch (error) { + console.error( + '[DownloadsService] Error clearing completed:', + error + ); + return { success: false }; + } + } + + /** + * Get download progress as percentage + */ + getProgressPercent(item: DownloadItem): number { + if (!item.totalBytes || item.totalBytes === 0) { + return 0; + } + return Math.round( + ((item.bytesDownloaded || 0) / item.totalBytes) * 100 + ); + } + + /** + * Get download item by xtreamId and playlistId + */ + getDownloadByContent( + xtreamId: number, + playlistId: string, + contentType: 'vod' | 'episode' + ): DownloadItem | undefined { + return this.downloads().find( + (d) => + d.xtreamId === xtreamId && + d.playlistId === playlistId && + d.contentType === contentType + ); + } + + /** + * Check if content is downloaded (completed status) + */ + isDownloaded( + xtreamId: number, + playlistId: string, + contentType: 'vod' | 'episode' + ): boolean { + const download = this.getDownloadByContent(xtreamId, playlistId, contentType); + return download?.status === 'completed' && !!download.filePath; + } + + /** + * Check if content is currently downloading or queued + */ + isDownloading( + xtreamId: number, + playlistId: string, + contentType: 'vod' | 'episode' + ): boolean { + const download = this.getDownloadByContent(xtreamId, playlistId, contentType); + return download?.status === 'downloading' || download?.status === 'queued'; + } + + /** + * Get the file path for a downloaded content item + */ + getDownloadedFilePath( + xtreamId: number, + playlistId: string, + contentType: 'vod' | 'episode' + ): string | undefined { + const download = this.getDownloadByContent(xtreamId, playlistId, contentType); + if (download?.status === 'completed') { + return download.filePath; + } + return undefined; + } + + /** + * Format bytes to human readable string + */ + formatBytes(bytes: number): string { + if (bytes === 0) return '0 B'; + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; + } +} diff --git a/libs/services/src/lib/settings-store.service.ts b/libs/services/src/lib/settings-store.service.ts new file mode 100644 index 000000000..3211d39b0 --- /dev/null +++ b/libs/services/src/lib/settings-store.service.ts @@ -0,0 +1,109 @@ +import { inject } from '@angular/core'; +import { + patchState, + signalStore, + withHooks, + withMethods, + withState, +} from '@ngrx/signals'; +import { StorageMap } from '@ngx-pwa/local-storage'; +import { firstValueFrom } from 'rxjs'; +import { + Language, + Settings, + STORE_KEY, + StreamFormat, + Theme, + VideoPlayer, +} from 'shared-interfaces'; + +const DEFAULT_SETTINGS: Settings = { + player: VideoPlayer.VideoJs, + streamFormat: StreamFormat.M3u8StreamFormat, + language: Language.ENGLISH, + showCaptions: false, + showExternalPlaybackBar: true, + theme: Theme.LightTheme, + mpvPlayerPath: '', + mpvReuseInstance: false, + vlcPlayerPath: '', + remoteControl: false, + remoteControlPort: 8765, + epgUrl: [], + downloadFolder: '', +}; + +export const SettingsStore = signalStore( + { providedIn: 'root' }, + withState(DEFAULT_SETTINGS), + withMethods((store, storage = inject(StorageMap)) => ({ + async loadSettings() { + try { + const stored = await firstValueFrom( + storage.get(STORE_KEY.Settings) + ); + if (stored) { + patchState(store, { + ...DEFAULT_SETTINGS, + ...(stored as Settings), + }); + } + } catch (error) { + console.error('Failed to load settings:', error); + // Keep default settings if loading fails + } + }, + + async updateSettings(settings: Partial) { + patchState(store, settings); + // Save the complete settings object, not just the partial update + const completeSettings = this.getSettings(); + try { + await firstValueFrom( + storage.set(STORE_KEY.Settings, completeSettings) + ); + } catch (error) { + console.error('Failed to save settings:', error); + throw error; + } + }, + + getSettings() { + return { + player: store.player(), + streamFormat: store.streamFormat(), + language: store.language(), + showCaptions: store.showCaptions(), + showExternalPlaybackBar: store.showExternalPlaybackBar(), + theme: store.theme(), + mpvPlayerPath: store.mpvPlayerPath(), + mpvReuseInstance: store.mpvReuseInstance(), + vlcPlayerPath: store.vlcPlayerPath(), + remoteControl: store.remoteControl(), + remoteControlPort: store.remoteControlPort(), + epgUrl: store.epgUrl(), + downloadFolder: store.downloadFolder(), + }; + }, + + getDownloadFolder() { + return store.downloadFolder(); + }, + + getPlayer() { + return store.player(); + }, + + isEmbeddedPlayer() { + return ( + store.player() === VideoPlayer.VideoJs || + store.player() === VideoPlayer.Html5Player + ); + }, + })), + withHooks({ + onInit(store) { + store.loadSettings(); + }, + }) +); diff --git a/libs/shared/interfaces/project.json b/libs/shared/interfaces/project.json index 966385880..43852e560 100644 --- a/libs/shared/interfaces/project.json +++ b/libs/shared/interfaces/project.json @@ -3,7 +3,7 @@ "$schema": "../../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "libs/shared/interfaces/src", "projectType": "library", - "tags": ["shared"], + "tags": ["scope:shared", "type:util"], "targets": { "build": { "executor": "@nx/js:tsc", diff --git a/libs/shared/m3u-utils/project.json b/libs/shared/m3u-utils/project.json index 845f6d809..165cdb9b0 100644 --- a/libs/shared/m3u-utils/project.json +++ b/libs/shared/m3u-utils/project.json @@ -3,7 +3,7 @@ "$schema": "../../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "libs/shared/m3u-utils/src", "projectType": "library", - "tags": ["shared", "m3u"], + "tags": ["scope:playlist", "domain:m3u", "type:util"], "targets": { "build": { "executor": "@nx/js:tsc", diff --git a/libs/ui/components/project.json b/libs/ui/components/project.json index 0e83737f5..55efd3a60 100644 --- a/libs/ui/components/project.json +++ b/libs/ui/components/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/ui/components/src", "prefix": "lib", "projectType": "library", - "tags": ["ui"], + "tags": ["scope:shared", "type:ui"], "targets": { "test": { "executor": "@nx/jest:jest", diff --git a/libs/ui/pipes/project.json b/libs/ui/pipes/project.json index 6a8401559..a773c8d92 100644 --- a/libs/ui/pipes/project.json +++ b/libs/ui/pipes/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/ui/pipes/src", "prefix": "lib", "projectType": "library", - "tags": [], + "tags": ["scope:shared", "type:util"], "targets": { "test": { "executor": "@nx/jest:jest", diff --git a/libs/ui/remote-control/project.json b/libs/ui/remote-control/project.json index d5257af8e..db4b0d92f 100644 --- a/libs/ui/remote-control/project.json +++ b/libs/ui/remote-control/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/ui/remote-control/src", "prefix": "lib", "projectType": "library", - "tags": [], + "tags": ["scope:shared", "domain:playback", "type:ui"], "targets": { "test": { "executor": "@nx/jest:jest", diff --git a/libs/ui/shared-portals/project.json b/libs/ui/shared-portals/project.json index 568eeb322..62acfff61 100644 --- a/libs/ui/shared-portals/project.json +++ b/libs/ui/shared-portals/project.json @@ -5,7 +5,9 @@ "prefix": "lib", "projectType": "library", "tags": [ - "ui" + "scope:portal", + "domain:portal-shared", + "type:ui" ], "targets": { "test": { diff --git a/libs/workspace/dashboard/data-access/project.json b/libs/workspace/dashboard/data-access/project.json index 550cc44cd..d72c78f8d 100644 --- a/libs/workspace/dashboard/data-access/project.json +++ b/libs/workspace/dashboard/data-access/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/workspace/dashboard/data-access/src", "prefix": "lib", "projectType": "library", - "tags": [], + "tags": ["scope:workspace", "domain:workspace", "type:data-access"], "targets": { "test": { "executor": "@nx/jest:jest", diff --git a/libs/workspace/dashboard/feature/project.json b/libs/workspace/dashboard/feature/project.json index a31f59117..7021b7f55 100644 --- a/libs/workspace/dashboard/feature/project.json +++ b/libs/workspace/dashboard/feature/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/workspace/dashboard/feature/src", "prefix": "lib", "projectType": "library", - "tags": [], + "tags": ["scope:workspace", "domain:workspace", "type:feature"], "targets": { "lint": { "executor": "@nx/eslint:lint" diff --git a/libs/workspace/dashboard/ui/project.json b/libs/workspace/dashboard/ui/project.json index 6964ed157..b61565f1f 100644 --- a/libs/workspace/dashboard/ui/project.json +++ b/libs/workspace/dashboard/ui/project.json @@ -4,7 +4,7 @@ "sourceRoot": "libs/workspace/dashboard/ui/src", "prefix": "lib", "projectType": "library", - "tags": [], + "tags": ["scope:workspace", "domain:workspace", "type:ui"], "targets": { "lint": { "executor": "@nx/eslint:lint" diff --git a/tsconfig.base.json b/tsconfig.base.json index 73b61c512..bac3b7b4d 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -15,6 +15,21 @@ "skipDefaultLibCheck": true, "baseUrl": ".", "paths": { + "@iptvnator/portal/downloads/feature": [ + "libs/portal/downloads/feature/src/index.ts" + ], + "@iptvnator/portal/shared/ui": [ + "libs/portal/shared/ui/src/index.ts" + ], + "@iptvnator/portal/shared/util": [ + "libs/portal/shared/util/src/index.ts" + ], + "@iptvnator/portal/stalker/data-access": [ + "libs/portal/stalker/data-access/src/index.ts" + ], + "@iptvnator/portal/xtream/data-access": [ + "libs/portal/xtream/data-access/src/index.ts" + ], "@iptvnator/pipes": ["libs/ui/pipes/src/index.ts"], "@package": ["./package.json"], "components": ["libs/ui/components/src/index.ts"], @@ -25,9 +40,6 @@ "shared-portals": ["libs/ui/shared-portals/src/index.ts"], "remote-control": ["libs/ui/remote-control/src/index.ts"], "database": ["libs/shared/database/src/index.ts"], - "xtream-store": [ - "apps/web/src/app/xtream-electron/stores/xtream.store.ts" - ], "workspace-dashboard-feature": [ "libs/workspace/dashboard/feature/src/index.ts" ],