Browse Source

add v2 channels table (#708)

* change mock api port; fix cors

* fix version request

* accept base url env var

* tweak colors

* fix version service

* add basic channels list

* fix auto page title for ts classes

* add GET /api/channels
pull/709/head
Jason Dove 3 years ago committed by GitHub
parent
commit
4b9781dad4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      ErsatzTV.Application/Channels/Mapper.cs
  2. 5
      ErsatzTV.Application/Channels/Queries/GetAllChannelsForApi.cs
  3. 21
      ErsatzTV.Application/Channels/Queries/GetAllChannelsForApiHandler.cs
  4. 9
      ErsatzTV.Core/Api/Channels/ChannelResponseModel.cs
  5. 20
      ErsatzTV/Controllers/Api/ChannelController.cs
  6. 96
      ErsatzTV/client-app/package-lock.json
  7. 1
      ErsatzTV/client-app/package.json
  8. 1
      ErsatzTV/client-app/src/App.vue
  9. 3
      ErsatzTV/client-app/src/mixins/autoPageTitle.js
  10. 6
      ErsatzTV/client-app/src/models/Channel.ts
  11. 3
      ErsatzTV/client-app/src/plugins/vuetify.ts
  12. 4
      ErsatzTV/client-app/src/router/index.js
  13. 3
      ErsatzTV/client-app/src/services/AbstractApiService.ts
  14. 17
      ErsatzTV/client-app/src/services/ChannelService.ts
  15. 6
      ErsatzTV/client-app/src/services/VersionService.ts
  16. 37
      ErsatzTV/client-app/src/views/ChannelsPage.vue
  17. 1
      ErsatzTV/client-app/tsconfig.json
  18. 33
      api/ersatztv-mock-api.json

24
ErsatzTV.Application/Channels/Mapper.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Api.Channels;
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Application.Channels;
@ -19,11 +20,26 @@ internal static class Mapper @@ -19,11 +20,26 @@ internal static class Mapper
channel.FallbackFillerId,
channel.Playouts?.Count ?? 0);
internal static ChannelResponseModel ProjectToResponseModel(Channel channel) =>
new(
channel.Id,
channel.Number,
channel.Name,
channel.FFmpegProfile.Name,
channel.PreferredLanguageCode,
GetStreamingMode(channel));
private static string GetLogo(Channel channel) =>
Optional(channel.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Logo))
.Match(a => a.Path, string.Empty);
private static string GetWatermark(Channel channel) =>
Optional(channel.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Watermark))
.Match(a => a.Path, string.Empty);
private static string GetStreamingMode(Channel channel) =>
channel.StreamingMode switch
{
StreamingMode.TransportStream => "MPEG-TS (Legacy)",
StreamingMode.TransportStreamHybrid => "MPEG-TS",
StreamingMode.HttpLiveStreamingDirect => "HLS Direct",
StreamingMode.HttpLiveStreamingSegmenter => "HLS Segmenter",
_ => throw new ArgumentOutOfRangeException()
};
}

5
ErsatzTV.Application/Channels/Queries/GetAllChannelsForApi.cs

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
using ErsatzTV.Core.Api.Channels;
namespace ErsatzTV.Application.Channels;
public record GetAllChannelsForApi : IRequest<List<ChannelResponseModel>>;

21
ErsatzTV.Application/Channels/Queries/GetAllChannelsForApiHandler.cs

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
using ErsatzTV.Core.Api.Channels;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using static ErsatzTV.Application.Channels.Mapper;
namespace ErsatzTV.Application.Channels;
public class GetAllChannelsForApiHandler : IRequestHandler<GetAllChannelsForApi, List<ChannelResponseModel>>
{
private readonly IChannelRepository _channelRepository;
public GetAllChannelsForApiHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository;
public async Task<List<ChannelResponseModel>> Handle(
GetAllChannelsForApi request,
CancellationToken cancellationToken)
{
IEnumerable<Channel> channels = Optional(await _channelRepository.GetAll()).Flatten();
return channels.Map(ProjectToResponseModel).ToList();
}
}

9
ErsatzTV.Core/Api/Channels/ChannelResponseModel.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
namespace ErsatzTV.Core.Api.Channels;
public record ChannelResponseModel(
int Id,
string Number,
string Name,
string FFmpegProfile,
string Language,
string StreamingMode);

20
ErsatzTV/Controllers/Api/ChannelController.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
using ErsatzTV.Application.Channels;
using ErsatzTV.Core.Api.Channels;
using MediatR;
using Microsoft.AspNetCore.Mvc;
namespace ErsatzTV.Controllers.Api;
[ApiController]
public class ChannelController
{
private readonly IMediator _mediator;
public ChannelController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet("/api/channels")]
public async Task<List<ChannelResponseModel>> GetAll() => await _mediator.Send(new GetAllChannelsForApi());
}

96
ErsatzTV/client-app/package-lock.json generated

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
"pinia": "^2.0.11",
"roboto-fontface": "*",
"vue": "^2.6.14",
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.2.0",
"vuetify": "^2.6.0"
},
@ -3025,7 +3026,7 @@ @@ -3025,7 +3026,7 @@
"version": "1.4.9",
"resolved": "https://registry.npmjs.org/@vue/composition-api/-/composition-api-1.4.9.tgz",
"integrity": "sha512-l6YOeg5LEXmfPqyxAnBaCv1FMRw0OGKJ4m6nOWRm6ngt5TuHcj5ZoBRN+LXh3J0u6Ur3C4VA+RiKT+M0eItr/g==",
"dev": true,
"devOptional": true,
"peerDependencies": {
"vue": ">= 2.5 < 3"
}
@ -9444,7 +9445,6 @@ @@ -9444,7 +9445,6 @@
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true,
"optional": true,
"bin": {
"prettier": "bin-prettier.js"
},
@ -11144,7 +11144,7 @@ @@ -11144,7 +11144,7 @@
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
"dev": true,
"devOptional": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -11280,6 +11280,15 @@ @@ -11280,6 +11280,15 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
},
"node_modules/vue-class-component": {
"version": "7.2.6",
"resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-7.2.6.tgz",
"integrity": "sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==",
"peer": true,
"peerDependencies": {
"vue": "^2.0.0"
}
},
"node_modules/vue-cli-plugin-vuetify": {
"version": "2.4.7",
"resolved": "https://registry.npmmirror.com/vue-cli-plugin-vuetify/-/vue-cli-plugin-vuetify-2.4.7.tgz",
@ -11527,6 +11536,15 @@ @@ -11527,6 +11536,15 @@
"node": ">=8"
}
},
"node_modules/vue-property-decorator": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz",
"integrity": "sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ==",
"peerDependencies": {
"vue": "*",
"vue-class-component": "*"
}
},
"node_modules/vue-router": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.2.0.tgz",
@ -14344,7 +14362,8 @@ @@ -14344,7 +14362,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.1.tgz",
"integrity": "sha512-5J/n+Ht4r2eVuncwCXcZPHzYCz/2haktle4WcggWiKeg3jSQVUJbjviPBs6sOo3y/LG3CEfZMP9bPJjVDbexpQ==",
"dev": true
"dev": true,
"requires": {}
},
"@vue/cli-service": {
"version": "5.0.1",
@ -14556,7 +14575,8 @@ @@ -14556,7 +14575,8 @@
"version": "1.4.9",
"resolved": "https://registry.npmjs.org/@vue/composition-api/-/composition-api-1.4.9.tgz",
"integrity": "sha512-l6YOeg5LEXmfPqyxAnBaCv1FMRw0OGKJ4m6nOWRm6ngt5TuHcj5ZoBRN+LXh3J0u6Ur3C4VA+RiKT+M0eItr/g==",
"dev": true
"devOptional": true,
"requires": {}
},
"@vue/devtools-api": {
"version": "6.0.12",
@ -14777,13 +14797,15 @@ @@ -14777,13 +14797,15 @@
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
"dev": true
"dev": true,
"requires": {}
},
"acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true
"dev": true,
"requires": {}
},
"acorn-walk": {
"version": "8.2.0",
@ -14852,7 +14874,8 @@ @@ -14852,7 +14874,8 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
"dev": true,
"requires": {}
},
"ansi-colors": {
"version": "4.1.1",
@ -15869,7 +15892,8 @@ @@ -15869,7 +15892,8 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
"integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
"dev": true
"dev": true,
"requires": {}
},
"csso": {
"version": "4.2.0",
@ -16417,7 +16441,8 @@ @@ -16417,7 +16441,8 @@
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
"integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
"dev": true
"dev": true,
"requires": {}
},
"eslint-plugin-prettier": {
"version": "4.0.0",
@ -17454,7 +17479,8 @@ @@ -17454,7 +17479,8 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
"dev": true
"dev": true,
"requires": {}
},
"ieee754": {
"version": "1.2.1",
@ -18975,25 +19001,29 @@ @@ -18975,25 +19001,29 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.0.tgz",
"integrity": "sha512-L0IKF4jAshRyn03SkEO6ar/Ipz2oLywVbg2THf2EqqdNkBwmVMxuTR/RoAltOw4piiaLt3gCAdrbAqmTBInmhg==",
"dev": true
"dev": true,
"requires": {}
},
"postcss-discard-duplicates": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
"integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
"dev": true
"dev": true,
"requires": {}
},
"postcss-discard-empty": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.0.tgz",
"integrity": "sha512-782T/buGgb3HOuHOJAHpdyKzAAKsv/BxWqsutnZ+QsiHEcDkY7v+6WWdturuBiSal6XMOO1p1aJvwXdqLD5vhA==",
"dev": true
"dev": true,
"requires": {}
},
"postcss-discard-overridden": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
"integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
"dev": true
"dev": true,
"requires": {}
},
"postcss-loader": {
"version": "6.2.1",
@ -19083,7 +19113,8 @@ @@ -19083,7 +19113,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
"dev": true
"dev": true,
"requires": {}
},
"postcss-modules-local-by-default": {
"version": "4.0.0",
@ -19118,7 +19149,8 @@ @@ -19118,7 +19149,8 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
"integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
"dev": true
"dev": true,
"requires": {}
},
"postcss-normalize-display-values": {
"version": "5.1.0",
@ -19268,8 +19300,7 @@ @@ -19268,8 +19300,7 @@
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true,
"optional": true
"dev": true
},
"prettier-linter-helpers": {
"version": "1.0.0",
@ -20546,7 +20577,7 @@ @@ -20546,7 +20577,7 @@
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
"dev": true
"devOptional": true
},
"unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
@ -20648,6 +20679,13 @@ @@ -20648,6 +20679,13 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
},
"vue-class-component": {
"version": "7.2.6",
"resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-7.2.6.tgz",
"integrity": "sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==",
"peer": true,
"requires": {}
},
"vue-cli-plugin-vuetify": {
"version": "2.4.7",
"resolved": "https://registry.npmmirror.com/vue-cli-plugin-vuetify/-/vue-cli-plugin-vuetify-2.4.7.tgz",
@ -20673,7 +20711,8 @@ @@ -20673,7 +20711,8 @@
"vue-demi": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.12.1.tgz",
"integrity": "sha512-QL3ny+wX8c6Xm1/EZylbgzdoDolye+VpCXRhI2hug9dJTP3OUJ3lmiKN3CsVV3mOJKwFi0nsstbgob0vG7aoIw=="
"integrity": "sha512-QL3ny+wX8c6Xm1/EZylbgzdoDolye+VpCXRhI2hug9dJTP3OUJ3lmiKN3CsVV3mOJKwFi0nsstbgob0vG7aoIw==",
"requires": {}
},
"vue-eslint-parser": {
"version": "8.3.0",
@ -20813,6 +20852,12 @@ @@ -20813,6 +20852,12 @@
}
}
},
"vue-property-decorator": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz",
"integrity": "sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ==",
"requires": {}
},
"vue-router": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.2.0.tgz",
@ -20855,7 +20900,8 @@ @@ -20855,7 +20900,8 @@
"vuetify": {
"version": "2.6.4",
"resolved": "https://registry.npmmirror.com/vuetify/-/vuetify-2.6.4.tgz",
"integrity": "sha512-2wEzU/Gz39gQCxK93xoiWPKCHQUnyUKWd81wB7Q7hfYJWu5QOWQXYlF0X/BgUZzf8IOyHWKiSNEAfEe9OE3b4w=="
"integrity": "sha512-2wEzU/Gz39gQCxK93xoiWPKCHQUnyUKWd81wB7Q7hfYJWu5QOWQXYlF0X/BgUZzf8IOyHWKiSNEAfEe9OE3b4w==",
"requires": {}
},
"vuetify-loader": {
"version": "1.7.3",
@ -21194,7 +21240,8 @@ @@ -21194,7 +21240,8 @@
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
"dev": true
"dev": true,
"requires": {}
}
}
},
@ -21321,7 +21368,8 @@ @@ -21321,7 +21368,8 @@
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
"dev": true
"dev": true,
"requires": {}
},
"y18n": {
"version": "5.0.8",

1
ErsatzTV/client-app/package.json

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
"pinia": "^2.0.11",
"roboto-fontface": "*",
"vue": "^2.6.14",
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.2.0",
"vuetify": "^2.6.0"
},

1
ErsatzTV/client-app/src/App.vue

@ -25,7 +25,6 @@ export default Vue.extend({ @@ -25,7 +25,6 @@ export default Vue.extend({
</script>
<style>
main {
background-color: black;
background-attachment: fixed;
background-repeat: no-repeat;
-webkit-background-size: cover;

3
ErsatzTV/client-app/src/mixins/autoPageTitle.js

@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
if (title) {
return typeof title === 'function' ? title.call(vm) : title;
}
if (vm._data.title) {
return vm._data.title;
}
}
export default {

6
ErsatzTV/client-app/src/models/Channel.ts

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
export interface Channel {
id: number;
number: string;
name: string;
streamingMode: string;
}

3
ErsatzTV/client-app/src/plugins/vuetify.ts

@ -17,7 +17,8 @@ export default new Vuetify({ @@ -17,7 +17,8 @@ export default new Vuetify({
error: colors.red,
warning: colors.orange,
info: colors.lightBlue,
success: colors.green
success: colors.green,
background: '#121212'
}
},
options: {

4
ErsatzTV/client-app/src/router/index.js

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import HomePage from '../views/HomePage.vue';
import ChannelsPage from '../views/ChannelsPage.vue';
Vue.use(VueRouter);
@ -17,9 +18,10 @@ const routes = [ @@ -17,9 +18,10 @@ const routes = [
{
path: '/channels',
name: 'Channels',
component: ChannelsPage,
meta: {
icon: 'mdi-broadcast',
disabled: true
disabled: false
}
},
{

3
ErsatzTV/client-app/src/services/AbstractApiService.ts

@ -10,7 +10,8 @@ export abstract class AbstractApiService { @@ -10,7 +10,8 @@ export abstract class AbstractApiService {
protected constructor(
protected readonly path?: string,
protected readonly baseURL: string = '/'
protected readonly baseURL: string = process.env.VUE_APP_ETV_BASE_URL ??
'/'
) {
if (path) {
this.baseURL += path;

17
ErsatzTV/client-app/src/services/ChannelService.ts

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
import { AbstractApiService } from './AbstractApiService';
import { Channel } from '@/models/Channel';
class ChannelApiService extends AbstractApiService {
public constructor() {
super();
}
public getAll(): Promise<Channel[]> {
return this.http
.get('/api/channels')
.then(this.handleResponse.bind(this))
.catch(this.handleError.bind(this));
}
}
export const channelApiService: ChannelApiService = new ChannelApiService();

6
ErsatzTV/client-app/src/services/VersionService.ts

@ -2,13 +2,13 @@ @@ -2,13 +2,13 @@
class VersionApiService extends AbstractApiService {
public constructor() {
super('/api/version');
super();
}
public version(): Promise<string> {
return this.http
.get('')
.then(this.handleResponse)
.get('/api/version')
.then(this.handleResponse.bind(this))
.catch(this.handleError.bind(this));
}
}

37
ErsatzTV/client-app/src/views/ChannelsPage.vue

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
<template>
<div>
<v-data-table
:headers="headers"
:items="channels"
:sort-by="['number']"
class="elevation-1"
></v-data-table>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import { Channel } from '@/models/Channel';
import { channelApiService } from '@/services/ChannelService';
@Component({ components: {} })
export default class Channels extends Vue {
private channels: Channel[] = [];
private headers = [
{ text: 'Number', value: 'number' },
{ text: 'Logo', value: 'logo' },
{ text: 'Name', value: 'name' },
{ text: 'Language', value: 'language' },
{ text: 'Mode', value: 'streamingMode' },
{ text: 'FFmpeg Profile', value: 'ffmpegProfile' }
];
title: string = 'Channels';
async mounted(): Promise<void> {
this.channels = await channelApiService.getAll();
}
}
</script>

1
ErsatzTV/client-app/tsconfig.json

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
"module": "esnext",
"strict": true,
"allowJs": true,
"experimentalDecorators": true,
"jsx": "preserve",
"moduleResolution": "node",
"skipLibCheck": true,

33
api/ersatztv-mock-api.json

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
"name": "ErsatzTV (copy)",
"endpointPrefix": "",
"latency": 0,
"port": 3000,
"port": 8409,
"hostname": "0.0.0.0",
"routes": [
{
@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
"responses": [
{
"uuid": "4fc6ab6f-6a1b-4084-8bb2-94f00d62840c",
"body": "[\n {{#repeat (faker 'datatype.number' min=1 max=5)}}\n { \n \"id\": {{@index}},\n \"number\": {{faker 'datatype.number' min=1 max=25}},\n \"name\": \"{{faker 'hacker.adjective'}} {{faker 'hacker.noun'}}\",\n \"group\": \"\",\n \"categories\": [],\n \"ffmpegProfileId\": 1,\n \"logo\": \"\",\n \"language\": \"{{oneOf (array '' 'eng')}}\",\n \"streamingMode\": \"{{oneOf (array 'HLS Segmenter' 'MPEG-TS')}}\"\n }\n {{/repeat}}\n]",
"body": "[\n {{#repeat (faker 'datatype.number' min=1 max=5)}}\n { \n \"id\": {{@index}},\n \"number\": {{faker 'datatype.number' min=1 max=25}},\n \"name\": \"{{faker 'hacker.adjective'}} {{faker 'hacker.noun'}}\",\n \"group\": \"\",\n \"categories\": [],\n \"ffmpegProfile\": \"1080 h264\",\n \"logo\": \"\",\n \"language\": \"{{oneOf (array '' 'eng')}}\",\n \"streamingMode\": \"{{oneOf (array 'HLS Segmenter' 'MPEG-TS')}}\"\n }\n {{/repeat}}\n]",
"latency": 0,
"statusCode": 200,
"label": "",
@ -56,6 +56,31 @@ @@ -56,6 +56,31 @@
"enabled": true,
"randomResponse": false,
"sequentialResponse": false
},
{
"uuid": "83dcafd5-74f6-4e5e-b9ae-3435a1541e8b",
"documentation": "",
"method": "get",
"endpoint": "api/version",
"responses": [
{
"uuid": "73ae76ef-09db-472a-8db8-10a90d4c3664",
"body": "develop",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [],
"filePath": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false
}
],
"enabled": true,
"randomResponse": false,
"sequentialResponse": false
}
],
"proxyMode": false,
@ -75,6 +100,10 @@ @@ -75,6 +100,10 @@
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Access-Control-Allow-Origin",
"value": "*"
}
],
"proxyReqHeaders": [

Loading…
Cancel
Save