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

Logos, Splashscreen and README #74

Merged
merged 12 commits into from
May 10, 2024
Merged
30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Bug report
about: Tell us about a bug or an unexpected behaviour
title: ''
labels: Bug
assignees: Arthi-chaud

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Version**
- [ ] Does this happen on the latest version of the application?

**Additional context**
Add any other context about the problem here.
20 changes: 20 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: Feature
assignees: Arthi-chaud

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
44 changes: 44 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Source: https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes

changelog:
exclude:
labels:
- dependencies
categories:
- title: App
labels:
- front
- front/web
- front/mobile
- title: API
labels:
- api
- title: Scanner
labels:
- scanner
- title: Matcher
labels:
- matcher
- title: Exciting New Features 🎉
labels:
- feature
- Basic
- title: Improvement, Optmizations & Enhancements 👍
labels:
- Enhancement/Optimization
- title: Fixes & Patches 🩹
labels:
- bug
- title: Security 🛡
labels:
- security
- title: Documentation 📖
labels:
- Documentation
- title: CI/CD ⚙
labels:
- dockerization
- ci
- title: Other Changes 🔀
labels:
- "*"
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
# Blee
![Blee](./assets/banner.png)

Enjoy your Concert movies, Music Videos and music DVD Extras, all in one place
### Enjoy your Concert movies, Music Videos and DVD Extras, all in one place

Blee is a personal video server and application to enjoy your music videos, concerts and DVD Extra files anywhere, anytime you want. This project is made by and for music collectors.
It is an alternative to Plex for handling music videos and concert films.

In Blee, *movies* can be grouped into *packages*. A package can have 0, 1 or more movies, along with an unlimited number of *extras*.

## Features

- Automatic Scan
- For Concerts, access a song directly using its chapter
- Customisable Regex-based file identification
- Playback with Live Transcoding
- Poster Download
- Uses TMDB (Optional)
- Automatically identify the types of Extras (Interview, Music Video, etc.), compatible with Plex's style (e.g. `-interview`)

Keep track of the upcoming features with the [project's issues](https://github.com/Arthi-chaud/Blee/issues)

## Screenshots

![Package](./assets/screenshots/package.png)

More screenshots [here](./assets/screenshots/)
Binary file added assets/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icon.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/package.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/player.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion front/lib/api/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class APIClient {

String buildTranscoderUrl(String transcoderRoute) {
if (kDebugMode) {
return 'http://localhost:7666$transcoderRoute';
return 'http://0.0.0.0:7666$transcoderRoute';
}
return "$_host/transcoder$transcoderRoute";
}
Expand Down
4 changes: 4 additions & 0 deletions front/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:blee/ui/src/breakpoints.dart';
import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:blee/router.dart';
import 'package:go_router/go_router.dart';
Expand All @@ -8,6 +9,8 @@ import 'theme.dart';

void main() {
// usePathUrlStrategy();
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
GoRouter.optionURLReflectsImperativeAPIs = true;
runApp(const ProviderScope(
child: MyApp(),
Expand All @@ -21,6 +24,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
final brightness = View.of(context).platformDispatcher.platformBrightness;
MaterialTheme theme = MaterialTheme();
FlutterNativeSplash.remove();
return MaterialApp.router(
title: 'Blee',
debugShowCheckedModeBanner: false,
Expand Down
8 changes: 8 additions & 0 deletions front/lib/navigation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
)),
appBar: AppBar(
centerTitle: false,
leadingWidth: ResponsiveBreakpoints.of(context)
.largerOrEqualTo(BreakpointEnum.sm.name)
? 56 + 16
: null,
leading: Padding(
padding: const EdgeInsets.only(left: 8, top: 8, bottom: 8),
child: Image.asset('web/icons/Icon-192.png'),
),
title: const Text(
'Blee',
style: TextStyle(
Expand Down
48 changes: 31 additions & 17 deletions front/lib/pages/src/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import 'package:go_router/go_router.dart';
import 'package:video_player/video_player.dart';
import 'package:collection/collection.dart';
import 'package:mediametadata/mediametadata.dart';
import 'package:uuid/uuid.dart';

class PlayerPage extends ConsumerStatefulWidget {
final clientId = const Uuid().v4();
final String? extraUuid;
final String? movieUuid;
final int? startPosition;
const PlayerPage(
{super.key, this.movieUuid, this.extraUuid, this.startPosition});
PlayerPage({super.key, this.movieUuid, this.extraUuid, this.startPosition});

@override
PlayerPageState createState() => PlayerPageState();
Expand Down Expand Up @@ -47,14 +48,12 @@ class PlayerPageState extends ConsumerState<PlayerPage> {
_controller?.dispose();
}

void _onPlayerInit(PlayerMetadata metadata) {
if (widget.startPosition == null) {
_controller!.play();
} else {
_controller!
.seekTo(Duration(seconds: widget.startPosition!))
.then((_) => _controller!.play());
}
void _onPlayerInit(PlayerMetadata metadata, int? startPos) {
_controller!.play().then((_) {
if (widget.startPosition != null) {
_controller!.seekTo(Duration(seconds: widget.startPosition!));
}
});
_controller!.addListener(() {
// If we are in a movie
if (metadata.chapters.isNotEmpty) {
Expand Down Expand Up @@ -99,17 +98,32 @@ class PlayerPageState extends ConsumerState<PlayerPage> {
});
}

VideoPlayerController setupPlayer(PlayerMetadata metadata,
{StreamMode streamMode = StreamMode.hls}) {
void _reinitPlayer(StreamMode streamMode, PlayerMetadata metadata) async {
final previousPos =
_controller?.value.position.inSeconds ?? widget.startPosition;
if (_controller != null) {
await _controller!.pause();
await _controller!.dispose();
}
final baseUrl = ref.read(apiClientProvider).buildTranscoderUrl(
"/${base64Encode(utf8.encode(metadata.videoFile.path))}");
return VideoPlayerController.networkUrl(
setState(() {
_controller = VideoPlayerController.networkUrl(
Uri.parse(streamMode == StreamMode.direct
? '$baseUrl/direct'
: '$baseUrl/master.m3u8'),
//TODO
httpHeaders: {"X-CLIENT-ID": "A"})
..initialize().then((_) => _onPlayerInit(metadata));
httpHeaders: {"X-CLIENT-ID": widget.clientId},
)..initialize()
.then((_) => _onPlayerInit(metadata, previousPos))
.onError((error, stackTrace) {
if (streamMode == StreamMode.hls) {
// ignore: avoid_print
print("COULD NOT PLAY VIDEO");
} else {
_reinitPlayer(StreamMode.hls, metadata);
}
});
});
}

void _refreshMediaMetadata(PlayerMetadata m) {
Expand All @@ -133,8 +147,8 @@ class PlayerPageState extends ConsumerState<PlayerPage> {
_refreshMediaMetadata(m);
setState(() {
flowStep = PlayerFlowStep.loadingPlayer;
_controller = setupPlayer(m);
});
_reinitPlayer(StreamMode.direct, m);
}
},
error: (_, __) {
Expand Down
Loading
Loading