diff --git a/.dockerignore b/.dockerignore
index 55fee41a5..ddfd15179 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,3 +2,5 @@ build
dist
.dart_tool
.idea
+.github
+.git
\ No newline at end of file
diff --git a/.github/Dockerfile b/.github/Dockerfile
index e4dacb0e9..007d1a6e7 100644
--- a/.github/Dockerfile
+++ b/.github/Dockerfile
@@ -1,32 +1,27 @@
ARG FLUTTER_VERSION
-ARG BUILD_VERSION
-FROM --platform=arm64 fischerscode/flutter-sudo:${FLUTTER_VERSION}
+FROM --platform=linux/arm64 krtirtho/flutter_distributor_arm64:${FLUTTER_VERSION}
-WORKDIR /app
+ARG BUILD_VERSION
-# Install dependencies
-RUN sudo apt-get update &&\
- sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp25 libsecret-1-dev libjsoncpp-dev libnotify-bin libnotify-dev mpv libmpv-dev rpm &&\
- sudo rm -rf /var/lib/apt/lists/*
+WORKDIR /app
COPY . .
-RUN sudo chown -R $(whoami) /app
+RUN chown -R $(whoami) /app
RUN flutter pub get &&\
flutter config --enable-linux-desktop &&\
flutter pub get &&\
dart run build_runner build --delete-conflicting-outputs
-RUN dart pub global activate flutter_distributor &&\
- alias dpkg-deb="dpkg-deb --Zxz" &&\
- flutter_distributor package --platform=linux --targets=deb &&\
- flutter_distributor package --platform=linux --targets=rpm
+RUN alias dpkg-deb="dpkg-deb --Zxz" &&\
+ flutter_distributor package --platform=linux --targets=deb
RUN make tar VERSION=${BUILD_VERSION} ARCH=arm64 PKG_ARCH=aarch64
RUN mv build/spotube-linux-*-aarch64.tar.xz dist/ &&\
- mv dist/**/spotube-*-linux.deb dist/Spotube-linux-aarch64.deb &&\
- mv dist/**/spotube-*-linux.rpm dist/Spotube-linux-aarch64.rpm
\ No newline at end of file
+ mv dist/**/spotube-*-linux.deb dist/Spotube-linux-aarch64.deb
+
+CMD [ "sleep", "5000000" ]
\ No newline at end of file
diff --git a/.github/Dockerfile.flutter_distributor b/.github/Dockerfile.flutter_distributor
new file mode 100644
index 000000000..952b9158e
--- /dev/null
+++ b/.github/Dockerfile.flutter_distributor
@@ -0,0 +1,23 @@
+FROM --platform=linux/arm64 ubuntu:22.04
+
+ARG FLUTTER_VERSION
+
+RUN apt-get clean &&\
+ apt-get update &&\
+ apt-get install -y bash curl file git unzip xz-utils zip libglu1-mesa cmake tar clang ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp25 libsecret-1-dev libjsoncpp-dev libnotify-bin libnotify-dev mpv libmpv-dev rpm && \
+ rm -rf /var/lib/apt/lists/*
+
+WORKDIR /home/flutter
+
+RUN git clone https://github.com/flutter/flutter.git -b ${FLUTTER_VERSION} --single-branch flutter-sdk
+
+RUN flutter-sdk/bin/flutter precache
+
+RUN flutter-sdk/bin/flutter config --no-analytics
+
+ENV PATH="$PATH:/home/flutter/flutter-sdk/bin"
+ENV PATH="$PATH:/home/flutter/flutter-sdk/bin/cache/dart-sdk/bin"
+ENV PATH="$PATH:/home/flutter/.pub-cache/bin"
+ENV PUB_CACHE="/home/flutter/.pub-cache"
+
+RUN dart pub global activate flutter_distributor
\ No newline at end of file
diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml
index c77531550..c7fcbf446 100644
--- a/.github/workflows/spotube-release-binary.yml
+++ b/.github/workflows/spotube-release-binary.yml
@@ -207,35 +207,36 @@ jobs:
limit-access-to-actor: true
linux_arm:
- runs-on: macos-14
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Get current date
+ id: date
+ run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
- - name: Install Docker
- run: brew install --cask docker
+ - name: Install Dependencies
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y pkg-config make python3-pip python3-setuptools
- name: Replace pubspec version and BUILD_VERSION Env (nightly)
if: ${{ inputs.channel == 'nightly' }}
run: |
- brew install yq
+ curl -sS https://webi.sh/yq | sh
yq -i '.version |= sub("\+\d+", "+${{ inputs.channel }}.")' pubspec.yaml
yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml
echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV
-
- name: BUILD_VERSION Env (stable)
if: ${{ inputs.channel == 'stable' }}
run: |
echo "BUILD_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
- - name: Get current date
- id: date
- run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
-
- - name: Replace Version in files
- run: |
- sed -i '' 's|%{{APPDATA_RELEASE}}%||' linux/com.github.KRTirtho.Spotube.appdata.xml
-
- name: Create Stable .env
if: ${{ inputs.channel == 'stable' }}
run: echo '${{ secrets.DOTENV_RELEASE }}' > .env
@@ -244,20 +245,42 @@ jobs:
if: ${{ inputs.channel == 'nightly' }}
run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env
- - name: Build Linux Arm
+ - name: Replace Version in files
+ run: |
+ sed -i 's|%{{APPDATA_RELEASE}}%||' linux/com.github.KRTirtho.Spotube.appdata.xml
+
+ - name: Build Binaries (stable)
+ if: ${{ inputs.channel == 'stable' }}
+ run: |
+ docker buildx build --platform=linux/arm64 -f .github/Dockerfile . --build-arg FLUTTER_VERSION=${{env.FLUTTER_VERSION}} --build-arg BUILD_VERSION=${{env.BUILD_VERSION}} -t krtirtho/spotube_linux_arm:latest --load
+
+ - name: Build Binaries (nightly)
+ if: ${{ inputs.channel == 'nightly' }}
run: |
- docker build -t spotube-linux-arm -f .github/Dockerfile . --build-arg BUILD_VERSION=${{ env.BUILD_VERSION }} --build-arg FLUTTER_VERSION=${{ env.FLUTTER_VERSION }}
- docker create --name spotube-linux-arm spotube-linux-arm
- docker cp spotube-linux-arm:/app/dist .
- docker rm -f spotube-linux-arm
+ docker buildx build --platform=linux/arm64 -f .github/Dockerfile . --build-arg FLUTTER_VERSION=${{env.FLUTTER_VERSION}} --build-arg BUILD_VERSION=nightly -t krtirtho/spotube_linux_arm:latest --load
+ - name: Copy the built packages
+ run: |
+ docker images ls
+ docker create --name spotube_linux_arm krtirtho/spotube_linux_arm:latest
+ docker cp spotube_linux_arm:/app/dist/ dist/
+
+ - uses: actions/upload-artifact@v3
+ if: ${{ inputs.channel == 'stable' }}
+ with:
+ if-no-files-found: error
+ name: Spotube-Release-Binaries
+ path: |
+ dist/Spotube-linux-aarch64.deb
+ dist/spotube-linux-${{ env.BUILD_VERSION }}-aarch64.tar.xz
+
- uses: actions/upload-artifact@v3
+ if: ${{ inputs.channel == 'nightly' }}
with:
if-no-files-found: error
name: Spotube-Release-Binaries
path: |
dist/Spotube-linux-aarch64.deb
- dist/Spotube-linux-aarch64.rpm
dist/spotube-linux-nightly-aarch64.tar.xz
- name: Debug With SSH When fails
@@ -266,7 +289,6 @@ jobs:
with:
limit-access-to-actor: true
-
android:
runs-on: ubuntu-latest
steps:
@@ -275,6 +297,13 @@ jobs:
with:
cache: true
flutter-version: ${{ env.FLUTTER_VERSION }}
+ - name: Setup Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'zulu'
+ java-version: '17'
+ cache: 'gradle'
+ check-latest: true
- name: Install Dependencies
run: |
diff --git a/lib/components/root/update_dialog.dart b/lib/components/root/update_dialog.dart
new file mode 100644
index 000000000..f5388aa1f
--- /dev/null
+++ b/lib/components/root/update_dialog.dart
@@ -0,0 +1,46 @@
+import 'package:flutter/material.dart';
+import 'package:spotube/components/shared/links/anchor_button.dart';
+import 'package:url_launcher/url_launcher_string.dart';
+import 'package:version/version.dart';
+
+class RootAppUpdateDialog extends StatelessWidget {
+ final Version? version;
+ const RootAppUpdateDialog({super.key, this.version});
+
+ @override
+ Widget build(BuildContext context) {
+ const url = "https://spotube.krtirtho.dev/downloads";
+ return AlertDialog(
+ title: const Text("Spotube has an update"),
+ actions: [
+ FilledButton(
+ child: const Text("Download Now"),
+ onPressed: () => launchUrlString(
+ url,
+ mode: LaunchMode.externalApplication,
+ ),
+ ),
+ ],
+ content: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text("Spotube v$version has been released"),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Text("Read the latest "),
+ AnchorButton(
+ "release notes",
+ style: const TextStyle(color: Colors.blue),
+ onTap: () => launchUrlString(
+ url,
+ mode: LaunchMode.externalApplication,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/hooks/configurators/use_update_checker.dart b/lib/hooks/configurators/use_update_checker.dart
deleted file mode 100644
index 7b937efbf..000000000
--- a/lib/hooks/configurators/use_update_checker.dart
+++ /dev/null
@@ -1,100 +0,0 @@
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:http/http.dart' as http;
-import 'package:spotube/collections/env.dart';
-
-import 'package:spotube/components/shared/links/anchor_button.dart';
-import 'package:spotube/hooks/controllers/use_package_info.dart';
-import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
-import 'package:url_launcher/url_launcher_string.dart';
-import 'package:version/version.dart';
-
-void useUpdateChecker(WidgetRef ref) {
- final isCheckUpdateEnabled =
- ref.watch(userPreferencesProvider.select((s) => s.checkUpdate));
- final packageInfo = usePackageInfo(
- appName: 'Spotube',
- packageName: 'spotube',
- );
- final Future> Function() checkUpdate = useCallback(
- () async {
- final value = await http.get(
- Uri.parse(
- "https://api.github.com/repos/KRTirtho/spotube/releases/latest"),
- );
- final tagName =
- (jsonDecode(value.body)["tag_name"] as String).replaceAll("v", "");
- final currentVersion = packageInfo.version == "Unknown"
- ? null
- : Version.parse(packageInfo.version);
- final latestVersion =
- tagName == "nightly" ? null : Version.parse(tagName);
- return [currentVersion, latestVersion];
- },
- [packageInfo.version],
- );
-
- final context = useContext();
-
- download(String url) => launchUrlString(
- url,
- mode: LaunchMode.externalApplication,
- );
-
- useEffect(() {
- if (!Env.enableUpdateChecker) return;
- if (!isCheckUpdateEnabled) return null;
- checkUpdate().then((value) {
- final currentVersion = value.first;
- final latestVersion = value.last;
- if (currentVersion == null ||
- latestVersion == null ||
- (latestVersion.isPreRelease && !currentVersion.isPreRelease) ||
- (!latestVersion.isPreRelease && currentVersion.isPreRelease)) return;
- if (latestVersion <= currentVersion) return;
- showDialog(
- context: context,
- barrierDismissible: true,
- barrierColor: Colors.black26,
- builder: (context) {
- const url =
- "https://spotube.krtirtho.dev/downloads";
- return AlertDialog(
- title: const Text("Spotube has an update"),
- actions: [
- FilledButton(
- child: const Text("Download Now"),
- onPressed: () => download(url),
- ),
- ],
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text("Spotube v${value.last} has been released"),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text("Read the latest "),
- AnchorButton(
- "release notes",
- style: const TextStyle(color: Colors.blue),
- onTap: () => launchUrlString(
- url,
- mode: LaunchMode.externalApplication,
- ),
- ),
- ],
- ),
- ],
- ),
- );
- },
- );
- });
- return null;
- }, [packageInfo, isCheckUpdateEnabled]);
-}
diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart
index f3ed6571e..42bf3f695 100644
--- a/lib/pages/root/root_app.dart
+++ b/lib/pages/root/root_app.dart
@@ -14,13 +14,13 @@ import 'package:spotube/components/root/sidebar.dart';
import 'package:spotube/components/root/spotube_navigation_bar.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/hooks/configurators/use_endless_playback.dart';
-import 'package:spotube/hooks/configurators/use_update_checker.dart';
import 'package:spotube/provider/connect/server.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/connectivity_adapter.dart';
import 'package:spotube/utils/persisted_state_notifier.dart';
import 'package:spotube/utils/platform.dart';
+import 'package:spotube/utils/service_utils.dart';
const rootPaths = {
"/": 0,
@@ -46,6 +46,8 @@ class RootApp extends HookConsumerWidget {
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
+ ServiceUtils.checkForUpdates(context, ref);
+
final sharedPreferences = await SharedPreferences.getInstance();
if (sharedPreferences.getBool(kIsUsingEncryption) == false &&
@@ -160,7 +162,6 @@ class RootApp extends HookConsumerWidget {
}, [downloader]);
// checks for latest version of the application
- useUpdateChecker(ref);
useEndlessPlayback(ref);
diff --git a/lib/provider/authentication_provider.dart b/lib/provider/authentication_provider.dart
index a82f82c0c..c94f4f3ee 100644
--- a/lib/provider/authentication_provider.dart
+++ b/lib/provider/authentication_provider.dart
@@ -1,10 +1,12 @@
import 'dart:async';
-import 'dart:convert';
+import 'dart:io';
import 'package:collection/collection.dart';
-import 'package:flutter_inappwebview/flutter_inappwebview.dart';
+import 'package:dio/dio.dart';
+import 'package:dio/io.dart';
+import 'package:flutter_inappwebview/flutter_inappwebview.dart'
+ hide X509Certificate;
import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:http/http.dart';
import 'package:spotube/collections/routes.dart';
import 'package:spotube/components/shared/dialogs/prompt_dialog.dart';
import 'package:spotube/extensions/context.dart';
@@ -18,6 +20,18 @@ class AuthenticationCredentials {
bool get isExpired => DateTime.now().isAfter(expiration);
+ static final Dio dio = () {
+ final dio = Dio();
+
+ (dio.httpClientAdapter as IOHttpClientAdapter)
+ .createHttpClient = () => HttpClient()
+ ..badCertificateCallback = (X509Certificate cert, String host, int port) {
+ return host.endsWith("spotify.com") && port == 443;
+ };
+
+ return dio;
+ }();
+
AuthenticationCredentials({
required this.cookie,
required this.accessToken,
@@ -30,21 +44,23 @@ class AuthenticationCredentials {
.split("; ")
.firstWhereOrNull((c) => c.trim().startsWith("sp_dc="))
?.trim();
- final res = await get(
+ final res = await dio.getUri(
Uri.parse(
"https://open.spotify.com/get_access_token?reason=transport&productType=web_player",
),
- headers: {
- "Cookie": spDc ?? "",
- "User-Agent":
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"
- },
+ options: Options(
+ headers: {
+ "Cookie": spDc ?? "",
+ "User-Agent":
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"
+ },
+ ),
);
- final body = jsonDecode(res.body);
+ final body = res.data;
- if (res.statusCode >= 400) {
+ if ((res.statusCode ?? 500) >= 400) {
throw Exception(
- "Failed to get access token: ${body['error'] ?? res.reasonPhrase}",
+ "Failed to get access token: ${body['error'] ?? res.statusMessage}",
);
}
diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart
index 88c528966..30c92e1d7 100644
--- a/lib/utils/service_utils.dart
+++ b/lib/utils/service_utils.dart
@@ -1,10 +1,10 @@
import 'dart:convert';
-import 'package:flutter/widgets.dart' hide Element;
import 'package:go_router/go_router.dart';
-import 'package:html/dom.dart';
+import 'package:html/dom.dart' hide Text;
import 'package:spotify/spotify.dart';
import 'package:spotube/components/library/user_local_tracks.dart';
+import 'package:spotube/components/root/update_dialog.dart';
import 'package:spotube/models/logger.dart';
import 'package:http/http.dart' as http;
import 'package:spotube/models/lyrics.dart';
@@ -14,6 +14,16 @@ import 'package:spotube/utils/primitive_utils.dart';
import 'package:collection/collection.dart';
import 'package:html/parser.dart' as parser;
+import 'dart:async';
+
+import 'package:flutter/material.dart' hide Element;
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:package_info_plus/package_info_plus.dart';
+import 'package:spotube/collections/env.dart';
+
+import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
+import 'package:version/version.dart';
+
abstract class ServiceUtils {
static final logger = getLogger("ServiceUtils");
@@ -318,4 +328,42 @@ abstract class ServiceUtils {
}
});
}
+
+ static Future checkForUpdates(
+ BuildContext context,
+ WidgetRef ref,
+ ) async {
+ if (!Env.enableUpdateChecker) return;
+ if (!ref.read(userPreferencesProvider.select((s) => s.checkUpdate))) return;
+
+ final packageInfo = await PackageInfo.fromPlatform();
+
+ final value = await http.get(
+ Uri.parse(
+ "https://api.github.com/repos/KRTirtho/spotube/releases/latest",
+ ),
+ );
+ final tagName =
+ (jsonDecode(value.body)["tag_name"] as String).replaceAll("v", "");
+ final currentVersion = packageInfo.version == "Unknown"
+ ? null
+ : Version.parse(packageInfo.version);
+ final latestVersion = tagName == "nightly" ? null : Version.parse(tagName);
+
+ if (currentVersion == null ||
+ latestVersion == null ||
+ (latestVersion.isPreRelease && !currentVersion.isPreRelease) ||
+ (!latestVersion.isPreRelease && currentVersion.isPreRelease)) return;
+
+ if (latestVersion <= currentVersion || !context.mounted) return;
+
+ showDialog(
+ context: context,
+ barrierDismissible: true,
+ barrierColor: Colors.black26,
+ builder: (context) {
+ return RootAppUpdateDialog(version: latestVersion);
+ },
+ );
+ }
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 62c20c354..20acd3d45 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -153,6 +153,7 @@ flutter:
uses-material-design: true
assets:
- assets/
+ - assets/ca/
- assets/tutorial/
- assets/logos/
- LICENSE