Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Artist Page + Make project ready for prod #69

Merged
merged 15 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
TMDB_API_KEY=
# Port on which Blee will be exposed
PUBLIC_PORT=
# Database. Fill in the missing fields with secure values
POSTGRES_USER=
POSTGRES_PASSWORD=
Expand Down
154 changes: 154 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
x-transcoder: &transcoder-base
image: ghcr.io/zoriya/kyoo_transcoder:4.5.0
networks:
default:
aliases:
- transcoder
restart: unless-stopped
environment:
- GOCODER_PREFIX=/videos
volumes:
- ${DATA_DIR}:/videos:ro
- ${CACHE_ROOT}:/cache
- metadata:/metadata

# This compose allows to build the whole project in a "production"-like environment
services:
front:
image: arthichaud/blee-front:edge
restart: on-failure
depends_on:
api:
condition: service_healthy
environment:
- PORT=3000
ports:
- "3000:3000"
api:
image: arthichaud/blee-api:edge
ports:
- "8000:8000"
restart: on-failure
depends_on:
db:
condition: service_healthy
mq:
condition: service_healthy
volumes:
- data:${CONFIG_DIR}
environment:
- POSTGRES_HOST=db
- POSTGRES_PORT=5432
- RABBIT_HOST=mq
- RABBIT_PORT=5672
env_file:
- .env
healthcheck:
test: ["CMD-SHELL", "wget -qO- localhost:8000"]
interval: 5s
retries: 3
mq:
image: rabbitmq:3.13-alpine
environment:
- RABBITMQ_DEFAULT_USER=${RABBIT_USER}
- RABBITMQ_DEFAULT_PASS=${RABBIT_PASS}
healthcheck:
test: rabbitmq-diagnostics -q ping
interval: 10s
timeout: 3s
retries: 10
scanner:
image: arthichaud/blee-scanner:edge
depends_on:
api:
condition: service_healthy
volumes:
- ${DATA_DIR}:/videos:ro
- ./scanner.json:/app/scanner.json
environment:
- API_URL=http://api:8000
- WATCH_DIR=/videos
- SCANNER_API_KEY=${SCANNER_API_KEY}
- CONFIG_DIR=/app
matcher:
image: arthichaud/blee-matcher:edge
restart: on-failure
depends_on:
api:
condition: service_healthy
environment:
- RABBIT_HOST=mq
- RABBIT_PORT=5672
- API_URL=http://api:8000
- MATCHER_API_KEY=${MATCHER_API_KEY}
env_file:
- .env
db:
image: postgres:alpine3.16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 3s
timeout: 5s
retries: 5
env_file:
- .env
expose:
- 5432
volumes:
- db:/var/lib/postgresql/data
nginx:
restart: on-failure
image: nginx:1.24.0-alpine
depends_on:
api:
condition: service_started
front:
condition: service_started
ports:
- ${PUBLIC_PORT}:5000
environment:
- PORT=5000
- FRONT_URL=http://front:3000
- SERVER_URL=http://api:8000
- TRANSCODER_URL=http://transcoder:7666
volumes:
- ./nginx.conf.template:/etc/nginx/templates/blee.conf.template:ro
transcoder:
<<: *transcoder-base
profiles: ['', 'cpu']

transcoder-nvidia:
<<: *transcoder-base
deploy:
resources:
reservations:
devices:
- capabilities: [gpu]
environment:
- GOCODER_PREFIX=/video
- GOCODER_HWACCEL=nvidia
profiles: ['nvidia']

transcoder-vaapi:
<<: *transcoder-base
devices:
- /dev/dri:/dev/dri
environment:
- GOCODER_PREFIX=/video
- GOCODER_HWACCEL=vaapi
- GOCODER_VAAPI_RENDERER=${GOCODER_VAAPI_RENDERER:-/dev/dri/renderD128}
profiles: ['vaapi']
# qsv is the same setup as vaapi but with the hwaccel env var different
transcoder-qsv:
<<: *transcoder-base
devices:
- /dev/dri:/dev/dri
environment:
- GOCODER_PREFIX=/video
- GOCODER_HWACCEL=qsv
- GOCODER_VAAPI_RENDERER=${GOCODER_VAAPI_RENDERER:-/dev/dri/renderD128}
profiles: ['qsv']
volumes:
db:
data:
metadata:
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ services:
front:
condition: service_started
ports:
- 5000:5000
- ${PUBLIC_PORT}:5000
environment:
- PORT=5000
- FRONT_URL=http://front:3000
Expand Down
4 changes: 2 additions & 2 deletions front/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ WORKDIR $APP

RUN flutter clean
RUN flutter pub get
RUN dart run build_runner build
RUN flutter build web
RUN dart run build_runner build --delete-conflicting-outputs
RUN flutter build web --release --source-maps

FROM nginx:1.25.2-alpine
COPY --from=build-env /app/build/web /etc/nginx/html
Expand Down
42 changes: 34 additions & 8 deletions front/lib/api/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import 'package:http/http.dart' as http;
enum RequestType { get, post, put, delete }

class APIClient {
String _host = Uri.base.toString();
String _host =
Uri.base.toString().substring(0, Uri.base.toString().indexOf('/#/'));

final http.Client client = http.Client();

Expand All @@ -20,7 +21,14 @@ class APIClient {

String buildImageUrl(String uuid) {
final route = "/images/$uuid";
return _host + (kDebugMode ? route : "api$route");
return _host + (kDebugMode ? route : "/api$route");
}

String buildTranscoderUrl(String transcoderRoute) {
if (kDebugMode) {
return 'http://localhost:7666$transcoderRoute';
}
return "$_host/transcoder$transcoderRoute";
}

Future<Artist> getArtist(String uuid) async {
Expand Down Expand Up @@ -49,13 +57,21 @@ class APIClient {
}

Future<Page<Package>> getPackages(
{PageQuery page = const PageQuery()}) async {
var responseBody = await _request(
RequestType.get, '/packages?take=${page.take}&skip=${page.skip}');
{PageQuery page = const PageQuery(), String? artistUuid}) async {
var responseBody = await _request(RequestType.get,
'/packages?artist=${artistUuid ?? ''}&take=${page.take}&skip=${page.skip}');
return Page.fromJson(
responseBody, (x) => Package.fromJson(x as Map<String, dynamic>));
}

Future<Page<Artist>> getArtists(
{PageQuery page = const PageQuery(), String? package}) async {
var responseBody = await _request(RequestType.get,
'/artists?package=$package&take=${page.take}&skip=${page.skip}');
return Page.fromJson(
responseBody, (x) => Artist.fromJson(x as Map<String, dynamic>));
}

Future<Page<ExternalId>> getPackageExternalIds(String packageUuid,
{PageQuery page = const PageQuery()}) async {
var responseBody = await _request(RequestType.get,
Expand All @@ -64,6 +80,14 @@ class APIClient {
responseBody, (x) => ExternalId.fromJson(x as Map<String, dynamic>));
}

Future<Page<ExternalId>> getArtistExternalIds(String artistUuid,
{PageQuery page = const PageQuery()}) async {
var responseBody = await _request(RequestType.get,
'/external_ids?artist=$artistUuid&take=${page.take}&skip=${page.skip}');
return Page.fromJson(
responseBody, (x) => ExternalId.fromJson(x as Map<String, dynamic>));
}

Future<Page<Movie>> getMovies(String packageUuid) async {
var responseBody =
await _request(RequestType.get, '/movies?package=$packageUuid');
Expand All @@ -79,9 +103,11 @@ class APIClient {
}

Future<Page<Extra>> getExtras(
{String? packageUuid, PageQuery page = const PageQuery()}) async {
{String? packageUuid,
String? artistUuid,
PageQuery page = const PageQuery()}) async {
var responseBody = await _request(RequestType.get,
'/extras?package=$packageUuid&take=${page.take}&skip=${page.skip}');
'/extras?package=$packageUuid&artist=$artistUuid&take=${page.take}&skip=${page.skip}');
return Page.fromJson(
responseBody, (x) => Extra.fromJson(x as Map<String, dynamic>));
}
Expand All @@ -92,7 +118,7 @@ class APIClient {
params ?? {};
http.Response response;
Uri fullRoute = Uri.parse(_host +
(kDebugMode ? route : "api$route") +
(kDebugMode ? route : "/api$route") +
(params == null ? "" : "?${Uri(queryParameters: params).query}"));
final Map<String, String> headers = {
'Content-type': 'application/json',
Expand Down
58 changes: 49 additions & 9 deletions front/lib/navigation.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:blee/ui/src/breakpoints.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:responsive_framework/responsive_framework.dart';

class ScaffoldWithNavBar extends StatefulWidget {
final String location;
Expand All @@ -14,7 +16,7 @@ class ScaffoldWithNavBar extends StatefulWidget {
}

class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
int _currentIndex = 0;
int _currentIndex = 1;

@override
void initState() {
Expand All @@ -29,6 +31,11 @@ class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
}

static const List<MyNavigationDestination> tabs = [
MyNavigationDestination(
icon: FaIcon(FontAwesomeIcons.user),
label: 'Artists',
initialLocation: '/artists',
),
MyNavigationDestination(
icon: FaIcon(FontAwesomeIcons.film),
label: 'Movies',
Expand All @@ -44,14 +51,42 @@ class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(child: widget.child),
bottomNavigationBar: NavigationBar(
destinations: tabs,
onDestinationSelected: (int index) {
_goOtherTab(context, index);
},
selectedIndex: _currentIndex,
body: SafeArea(
child: Row(
children: [
ResponsiveBreakpoints.of(context)
.largerOrEqualTo(BreakpointEnum.sm.name)
? NavigationRail(
labelType: NavigationRailLabelType.all,
onDestinationSelected: (int index) {
_goOtherTab(context, index);
},
destinations: tabs
.map((tab) => tab.toRailDestination(context))
.toList(),
selectedIndex: _currentIndex)
: Container(),
Expanded(child: widget.child)
],
)),
appBar: AppBar(
centerTitle: false,
title: const Text(
'Blee',
style: TextStyle(
fontWeight: FontWeight.w900, fontStyle: FontStyle.italic),
),
),
bottomNavigationBar: ResponsiveBreakpoints.of(context)
.smallerOrEqualTo(BreakpointEnum.xs.name)
? NavigationBar(
destinations: tabs,
onDestinationSelected: (int index) {
_goOtherTab(context, index);
},
selectedIndex: _currentIndex,
)
: null,
);
}

Expand All @@ -73,6 +108,11 @@ class MyNavigationDestination extends NavigationDestination {
{super.key,
required this.initialLocation,
required super.icon,
super.selectedIcon,
required super.label})
: super(selectedIcon: icon);
: super();
NavigationRailDestination toRailDestination(BuildContext context) {
return NavigationRailDestination(
icon: icon, label: Text(label), selectedIcon: selectedIcon);
}
}
Loading
Loading