mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-12-06 07:29:42 +00:00
Compare commits
No commits in common. "fda2257119a57116315ab2a84b23e81a559b13fb" and "e1fa9efa14ef6a95d55a57089e9fccad1bb90d61" have entirely different histories.
fda2257119
...
e1fa9efa14
46
.github/workflows/spotube-publish-binary.yml
vendored
46
.github/workflows/spotube-publish-binary.yml
vendored
@ -12,10 +12,10 @@ on:
|
||||
type: boolean
|
||||
default: true
|
||||
jobs:
|
||||
description: Jobs to run (flathub,aur,winget,chocolatey)
|
||||
description: Jobs to run (flathub,aur,winget,chocolatey,playstore)
|
||||
required: true
|
||||
type: string
|
||||
default: "flathub,aur,winget,chocolatey"
|
||||
default: "flathub,aur,winget,chocolatey,playstore"
|
||||
|
||||
jobs:
|
||||
flathub:
|
||||
@ -112,26 +112,26 @@ jobs:
|
||||
- name: Tagname (workflow dispatch)
|
||||
run: echo 'TAG_NAME=${{inputs.version}}' >> $GITHUB_ENV
|
||||
|
||||
# - uses: robinraju/release-downloader@main
|
||||
# with:
|
||||
# repository: KRTirtho/spotube
|
||||
# tag: v${{ env.TAG_NAME }}
|
||||
# tarBall: false
|
||||
# zipBall: false
|
||||
# out-file-path: dist
|
||||
# fileName: "Spotube-playstore-all-arch.aab"
|
||||
- uses: robinraju/release-downloader@main
|
||||
with:
|
||||
repository: KRTirtho/spotube
|
||||
tag: v${{ env.TAG_NAME }}
|
||||
tarBall: false
|
||||
zipBall: false
|
||||
out-file-path: dist
|
||||
fileName: "Spotube-playstore-all-arch.aab"
|
||||
|
||||
# - name: Create service-account.json
|
||||
# run: |
|
||||
# echo "${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_BASE64 }}" | base64 -d > service-account.json
|
||||
- name: Create service-account.json
|
||||
run: |
|
||||
echo "${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_BASE64 }}" | base64 -d > service-account.json
|
||||
|
||||
# - name: Upload Android Release to Play Store
|
||||
# if: ${{!inputs.dry_run}}
|
||||
# uses: r0adkll/upload-google-play@v1
|
||||
# with:
|
||||
# serviceAccountJson: ./service-account.json
|
||||
# releaseFiles: ./dist/Spotube-playstore-all-arch.aab
|
||||
# packageName: oss.krtirtho.spotube
|
||||
# track: production
|
||||
# status: draft
|
||||
# releaseName: ${{ env.TAG_NAME }}
|
||||
- name: Upload Android Release to Play Store
|
||||
if: ${{!inputs.dry_run}}
|
||||
uses: r0adkll/upload-google-play@v1
|
||||
with:
|
||||
serviceAccountJson: ./service-account.json
|
||||
releaseFiles: ./dist/Spotube-playstore-all-arch.aab
|
||||
packageName: oss.krtirtho.spotube
|
||||
track: production
|
||||
status: draft
|
||||
releaseName: ${{ env.TAG_NAME }}
|
||||
|
||||
9
.github/workflows/spotube-release-binary.yml
vendored
9
.github/workflows/spotube-release-binary.yml
vendored
@ -49,6 +49,7 @@ jobs:
|
||||
arch: all
|
||||
files: |
|
||||
build/Spotube-android-all-arch.apk
|
||||
build/Spotube-playstore-all-arch.aab
|
||||
- os: windows-latest
|
||||
platform: windows
|
||||
arch: x86
|
||||
@ -76,14 +77,6 @@ jobs:
|
||||
cache: true
|
||||
git-source: https://github.com/flutter/flutter.git
|
||||
|
||||
- name: free disk space
|
||||
if: ${{ matrix.platform == 'android' }}
|
||||
run: |
|
||||
sudo swapoff -a
|
||||
sudo rm -f /swapfile
|
||||
sudo apt clean
|
||||
docker rmi $(docker image ls -aq)
|
||||
df -h
|
||||
- name: Setup Java
|
||||
if: ${{matrix.platform == 'android'}}
|
||||
uses: actions/setup-java@v4
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -2,7 +2,9 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:xml/xml.dart';
|
||||
|
||||
import '../../core/env.dart';
|
||||
import 'common.dart';
|
||||
@ -22,6 +24,39 @@ class AndroidBuildCommand extends Command with BuildCommandCommonSteps {
|
||||
"flutter build apk --flavor ${CliEnv.channel.name}",
|
||||
);
|
||||
|
||||
await dotEnvFile.writeAsString(
|
||||
"\nENABLE_UPDATE_CHECK=0"
|
||||
"\nHIDE_DONATIONS=1",
|
||||
mode: FileMode.append,
|
||||
);
|
||||
|
||||
final androidManifestFile = File(
|
||||
join(cwd.path, "android", "app", "src", "main", "AndroidManifest.xml"));
|
||||
|
||||
final androidManifestXml =
|
||||
XmlDocument.parse(await androidManifestFile.readAsString());
|
||||
|
||||
final deletingElement =
|
||||
androidManifestXml.findAllElements("meta-data").firstWhereOrNull(
|
||||
(el) =>
|
||||
el.getAttribute("android:name") ==
|
||||
"com.google.android.gms.car.application",
|
||||
);
|
||||
|
||||
deletingElement?.parent?.children.remove(deletingElement);
|
||||
|
||||
await androidManifestFile.writeAsString(
|
||||
androidManifestXml.toXmlString(pretty: true),
|
||||
);
|
||||
|
||||
await shell.run(
|
||||
"""
|
||||
dart run build_runner clean
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
flutter build appbundle --flavor ${CliEnv.channel.name}
|
||||
""",
|
||||
);
|
||||
|
||||
final ogApkFile = File(
|
||||
join(
|
||||
"build",
|
||||
@ -36,6 +71,22 @@ class AndroidBuildCommand extends Command with BuildCommandCommonSteps {
|
||||
join(cwd.path, "build", "Spotube-android-all-arch.apk"),
|
||||
);
|
||||
|
||||
final ogAppbundleFile = File(
|
||||
join(
|
||||
cwd.path,
|
||||
"build",
|
||||
"app",
|
||||
"outputs",
|
||||
"bundle",
|
||||
"${CliEnv.channel.name}Release",
|
||||
"app-${CliEnv.channel.name}-release.aab",
|
||||
),
|
||||
);
|
||||
|
||||
await ogAppbundleFile.copy(
|
||||
join(cwd.path, "build", "Spotube-playstore-all-arch.aab"),
|
||||
);
|
||||
|
||||
stdout.writeln("✅ Built Android Apk and Appbundle");
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,8 +83,6 @@ Future<void> main(List<String> rawArgs) async {
|
||||
// force High Refresh Rate on some Android devices (like One Plus)
|
||||
if (kIsAndroid) {
|
||||
await FlutterDisplayMode.setHighRefreshRate();
|
||||
}
|
||||
if (kIsAndroid || kIsDesktop) {
|
||||
await NewPipeExtractor.init();
|
||||
}
|
||||
|
||||
|
||||
@ -19,10 +19,10 @@ import 'package:spotube/services/kv_store/kv_store.dart';
|
||||
import 'package:flutter/widgets.dart' hide Table, Key, View;
|
||||
import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart';
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:spotube/services/logger/logger.dart';
|
||||
import 'package:spotube/services/youtube_engine/newpipe_engine.dart';
|
||||
import 'package:spotube/services/youtube_engine/youtube_explode_engine.dart';
|
||||
import 'package:spotube/services/youtube_engine/yt_dlp_engine.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
import 'package:sqlite3/sqlite3.dart';
|
||||
import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
||||
|
||||
@ -212,14 +212,26 @@ class AppDatabase extends _$AppDatabase {
|
||||
);
|
||||
},
|
||||
from9To10: (m, schema) async {
|
||||
await m.dropColumn(schema.preferencesTable, "piped_instance");
|
||||
await m.dropColumn(schema.preferencesTable, "invidious_instance");
|
||||
await m.addColumn(
|
||||
schema.sourceMatchTable,
|
||||
sourceMatchTable.sourceInfo,
|
||||
);
|
||||
await customStatement("DROP INDEX IF EXISTS uniq_track_match;");
|
||||
await m.dropColumn(schema.sourceMatchTable, "source_id");
|
||||
try {
|
||||
await m
|
||||
.dropColumn(schema.preferencesTable, "piped_instance")
|
||||
.catchError((e) {});
|
||||
await m
|
||||
.dropColumn(schema.preferencesTable, "invidious_instance")
|
||||
.catchError((e) {});
|
||||
await m
|
||||
.addColumn(
|
||||
schema.sourceMatchTable,
|
||||
sourceMatchTable.sourceInfo,
|
||||
)
|
||||
.catchError((e) {});
|
||||
await m
|
||||
.dropColumn(schema.sourceMatchTable, "source_id")
|
||||
.catchError((e) {});
|
||||
} catch (e) {
|
||||
AppLogger.log.e(e);
|
||||
return;
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@ -111,9 +111,7 @@ class PreferencesTable extends Table {
|
||||
localLibraryLocation: [],
|
||||
themeMode: ThemeMode.system,
|
||||
audioSourceId: null,
|
||||
youtubeClientEngine: kIsIOS
|
||||
? YoutubeClientEngine.youtubeExplode
|
||||
: YoutubeClientEngine.newPipe,
|
||||
youtubeClientEngine: YoutubeClientEngine.youtubeExplode,
|
||||
discordPresence: true,
|
||||
endlessPlayback: true,
|
||||
enableConnect: false,
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
part of '../database.dart';
|
||||
|
||||
@TableIndex(
|
||||
name: "uniq_track_match",
|
||||
columns: {#trackId, #sourceInfo, #sourceType},
|
||||
unique: true,
|
||||
)
|
||||
class SourceMatchTable extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get trackId => text()();
|
||||
|
||||
@ -4,7 +4,6 @@ import 'dart:io';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
@ -102,11 +101,7 @@ class MetadataPluginNotifier extends AsyncNotifier<MetadataPluginState> {
|
||||
|
||||
final plugins = await database.pluginsTable.select().get();
|
||||
|
||||
final pluginState = await toStatePlugins(plugins);
|
||||
|
||||
await _loadDefaultPlugins(pluginState);
|
||||
|
||||
return pluginState;
|
||||
return await toStatePlugins(plugins);
|
||||
}
|
||||
|
||||
Future<MetadataPluginState> toStatePlugins(
|
||||
@ -176,45 +171,6 @@ class MetadataPluginNotifier extends AsyncNotifier<MetadataPluginState> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadDefaultPlugins(MetadataPluginState pluginState) async {
|
||||
const plugins = [
|
||||
"spotube-plugin-musicbrainz-listenbrainz",
|
||||
"spotube-plugin-youtube-audio",
|
||||
];
|
||||
|
||||
for (final plugin in plugins) {
|
||||
final byteData = await rootBundle.load(
|
||||
"assets/plugins/$plugin/plugin.smplug",
|
||||
);
|
||||
final pluginConfig =
|
||||
await extractPluginArchive(byteData.buffer.asUint8List());
|
||||
try {
|
||||
await addPlugin(pluginConfig);
|
||||
} on MetadataPluginException catch (e) {
|
||||
if (e.errorCode == MetadataPluginErrorCode.duplicatePlugin &&
|
||||
await isPluginUpdate(pluginConfig)) {
|
||||
final oldConfig = pluginState.plugins
|
||||
.firstWhereOrNull((p) => p.slug == pluginConfig.slug);
|
||||
if (oldConfig == null) continue;
|
||||
final isDefaultMetadata =
|
||||
oldConfig == pluginState.defaultMetadataPluginConfig;
|
||||
final isDefaultAudioSource =
|
||||
oldConfig == pluginState.defaultAudioSourcePluginConfig;
|
||||
|
||||
await removePlugin(pluginConfig);
|
||||
await addPlugin(pluginConfig);
|
||||
|
||||
if (isDefaultMetadata) {
|
||||
await setDefaultMetadataPlugin(pluginConfig);
|
||||
}
|
||||
if (isDefaultAudioSource) {
|
||||
await setDefaultAudioSourcePlugin(pluginConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Uri _getGithubReleasesUrl(String repoUrl) {
|
||||
final parsedUri = Uri.parse(repoUrl);
|
||||
final uri = parsedUri.replace(
|
||||
@ -417,19 +373,11 @@ class MetadataPluginNotifier extends AsyncNotifier<MetadataPluginState> {
|
||||
repository: Value(plugin.repository),
|
||||
// Setting the very first plugin as the default plugin
|
||||
selectedForMetadata: Value(
|
||||
(state.valueOrNull?.plugins
|
||||
.where(
|
||||
(d) => d.abilities.contains(PluginAbilities.metadata))
|
||||
.isEmpty ??
|
||||
true) &&
|
||||
(state.valueOrNull?.plugins.isEmpty ?? true) &&
|
||||
plugin.abilities.contains(PluginAbilities.metadata),
|
||||
),
|
||||
selectedForAudioSource: Value(
|
||||
(state.valueOrNull?.plugins
|
||||
.where((d) =>
|
||||
d.abilities.contains(PluginAbilities.audioSource))
|
||||
.isEmpty ??
|
||||
true) &&
|
||||
(state.valueOrNull?.plugins.isEmpty ?? true) &&
|
||||
plugin.abilities.contains(PluginAbilities.audioSource),
|
||||
),
|
||||
),
|
||||
@ -472,27 +420,6 @@ class MetadataPluginNotifier extends AsyncNotifier<MetadataPluginState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> isPluginUpdate(PluginConfiguration newPlugin) async {
|
||||
final pluginRes = await (database.pluginsTable.select()
|
||||
..where(
|
||||
(tbl) =>
|
||||
tbl.name.equals(newPlugin.name) &
|
||||
tbl.author.equals(newPlugin.author),
|
||||
)
|
||||
..limit(1))
|
||||
.get();
|
||||
|
||||
if (pluginRes.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final oldPlugin = pluginRes.first;
|
||||
final oldPluginApiVersion = Version.parse(oldPlugin.pluginApiVersion);
|
||||
final newPluginApiVersion = Version.parse(newPlugin.pluginApiVersion);
|
||||
|
||||
return newPluginApiVersion > oldPluginApiVersion;
|
||||
}
|
||||
|
||||
Future<void> updatePlugin(
|
||||
PluginConfiguration plugin,
|
||||
PluginUpdateAvailable update,
|
||||
|
||||
@ -6,7 +6,7 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
|
||||
class NewPipeEngine implements YouTubeEngine {
|
||||
static bool get isAvailableForPlatform => kIsAndroid || kIsDesktop;
|
||||
static bool get isAvailableForPlatform => kIsAndroid;
|
||||
|
||||
AudioOnlyStreamInfo _parseAudioStream(AudioStream stream, String videoId) {
|
||||
return AudioOnlyStreamInfo(
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_new_pipe_extractor/flutter_new_pipe_extractor_plugin.h>
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
#include <flutter_timezone/flutter_timezone_plugin.h>
|
||||
#include <gtk/gtk_plugin.h>
|
||||
@ -31,9 +30,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_new_pipe_extractor_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterNewPipeExtractorPlugin");
|
||||
flutter_new_pipe_extractor_plugin_register_with_registrar(flutter_new_pipe_extractor_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_webview_window
|
||||
file_selector_linux
|
||||
flutter_new_pipe_extractor
|
||||
flutter_secure_storage_linux
|
||||
flutter_timezone
|
||||
gtk
|
||||
|
||||
@ -15,7 +15,6 @@ import device_info_plus
|
||||
import file_picker
|
||||
import file_selector_macos
|
||||
import flutter_inappwebview_macos
|
||||
import flutter_new_pipe_extractor
|
||||
import flutter_secure_storage_macos
|
||||
import flutter_timezone
|
||||
import irondash_engine_context
|
||||
@ -45,7 +44,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||
FlutterNewPipeExtractorPlugin.register(with: registry.registrar(forPlugin: "FlutterNewPipeExtractorPlugin"))
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin"))
|
||||
IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin"))
|
||||
|
||||
@ -955,7 +955,7 @@ packages:
|
||||
description:
|
||||
path: "."
|
||||
ref: HEAD
|
||||
resolved-ref: "898fd4ebcef77f5177b08aa6f9b9047bd02c6b9b"
|
||||
resolved-ref: d4d71545111c8ca6c91f0040091c42d74cce1762
|
||||
url: "https://github.com/KRTirtho/flutter_new_pipe_extractor.git"
|
||||
source: git
|
||||
version: "0.1.0"
|
||||
@ -2002,10 +2002,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: random_user_agents
|
||||
sha256: "95647149687167e82a7b39e1b4616fdebb574981b71b6f0cfca21b69f36293a8"
|
||||
sha256: "19facde509a2482dababb454faf2aceff797a6ae08e80f91268c0c8a7420f03b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.17"
|
||||
version: "1.0.15"
|
||||
recase:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -2821,7 +2821,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
xml:
|
||||
dependency: transitive
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: xml
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
|
||||
@ -177,6 +177,7 @@ dev_dependencies:
|
||||
process_run: ^0.14.2
|
||||
pubspec_parse: ^1.3.0
|
||||
pub_api_client: ^3.0.0
|
||||
xml: ^6.5.0
|
||||
io: ^1.0.4
|
||||
drift_dev: ^2.21.0
|
||||
auto_route_generator: ^9.0.0
|
||||
@ -227,8 +228,6 @@ flutter:
|
||||
- assets/branding/spotube-logo.png
|
||||
- assets/branding/spotube-logo-light.png
|
||||
- assets/branding/spotube-logo.ico
|
||||
- assets/plugins/spotube-plugin-musicbrainz-listenbrainz/plugin.smplug
|
||||
- assets/plugins/spotube-plugin-youtube-audio/plugin.smplug
|
||||
- LICENSE
|
||||
- packages/flutter_undraw/assets/undraw/access_denied.svg
|
||||
- packages/flutter_undraw/assets/undraw/fixing_bugs.svg
|
||||
|
||||
@ -12,7 +12,6 @@
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
|
||||
#include <flutter_new_pipe_extractor/flutter_new_pipe_extractor_plugin_c_api.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <flutter_timezone/flutter_timezone_plugin_c_api.h>
|
||||
#include <irondash_engine_context/irondash_engine_context_plugin_c_api.h>
|
||||
@ -40,8 +39,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
|
||||
FlutterNewPipeExtractorPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterNewPipeExtractorPluginCApi"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
FlutterTimezonePluginCApiRegisterWithRegistrar(
|
||||
|
||||
@ -9,7 +9,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_webview_window
|
||||
file_selector_windows
|
||||
flutter_inappwebview_windows
|
||||
flutter_new_pipe_extractor
|
||||
flutter_secure_storage_windows
|
||||
flutter_timezone
|
||||
irondash_engine_context
|
||||
|
||||
Loading…
Reference in New Issue
Block a user