This commit is contained in:
AleAtDev 2025-04-22 20:42:16 +00:00 committed by GitHub
commit 68d446f558
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
460 changed files with 5480 additions and 6300 deletions

View File

@ -1,17 +1,15 @@
# The format: SPOTIFY_SECRETS=
# SPOTIFY_SECRETS=clintId1:clientSecret1,clientId2:clientSecret2
SPOTIFY_SECRETS=$SPOTIFY_SECRETS
# 0 or 1 # 0 (false)/1 (true)
# 0 = disable
# 1 = enable
ENABLE_UPDATE_CHECK=$ENABLE_UPDATE_CHECK
LASTFM_API_KEY=$LASTFM_API_KEY ENABLE_UPDATE_CHECK=1
LASTFM_API_SECRET=$LASTFM_API_SECRET
LASTFM_API_KEY=
LASTFM_API_SECRET=
# Release channel. Can be: nightly, stable # Release channel. Can be: nightly, stable
RELEASE_CHANNEL=$RELEASE_CHANNEL RELEASE_CHANNEL=stable
HIDE_DONATIONS=$HIDE_DONATIONS # 0 (false)/1 (true)
DISABLE_SPOTIFY_IMAGES=$DISABLE_SPOTIFY_IMAGES HIDE_DONATIONS=1
DISABLE_SPOTIFY_IMAGES=0

5
.gitignore vendored
View File

@ -18,7 +18,7 @@
# The .vscode folder contains launch configuration and tasks you configure in # The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line # VS Code which you may wish to be included in version control, so this line
# is commented out by default. # is commented out by default.
#.vscode/ .vscode/
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
**/doc/api/ **/doc/api/
@ -83,3 +83,6 @@ tm.json
android/build android/build
android/app/.cxx android/app/.cxx
# Build dir
build

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
# Code of Conduct - Spotube # Code of Conduct - SpoTube
## Our Pledge ## Our Pledge
@ -18,20 +18,20 @@ community include:
* Being respectful of differing opinions, viewpoints, and experiences * Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback * Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes, * Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience and learning from the experience
* Focusing on what is best not just for us as individuals, but for the * Focusing on what is best not just for us as individuals, but for the
overall community overall community
Examples of unacceptable behavior include: Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or * The use of sexualized language or imagery, and sexual attention or
advances advances
* Trolling, insulting or derogatory comments, and personal or political attacks * Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment * Public or private harassment
* Publishing others' private information, such as a physical or email * Publishing others' private information, such as a physical or email
address, without their explicit permission address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a * Other conduct which could reasonably be considered inappropriate in a
professional setting professional setting
## Our Responsibilities ## Our Responsibilities

View File

@ -1,48 +1,62 @@
# Contributing to Spotube # Contributing to SpoTube
First off, thanks for taking the time to contribute! ❤️ First off, thanks for taking the time to contribute!
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉 All types of contributions are encouraged and valued.
See the [Table of Contents](#table-of-contents) for different ways
to help and details about how this project handles them.
Please make sure to read the relevant section before making
your contribution.
It will make it a lot easier for us maintainers and smooth out the experience for all involved.
The
community looks forward to your contributions.
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: > And if you like the project, but just don't have time to contribute, that's fine.
> There are other easy ways to support
> the project and show your appreciation, which we would also be thrilled about:
> >
> - Star the project > - Star the project
> - Tweet about it > - Tweet about it
> - Refer this project in your project's readme > - Refer this project to your project's readme
> - Mention the project at local meetups and tell your friends/colleagues > - Mention the project at local meetups and tell your friends/colleagues
## Table of Contents ## Table of Contents
- [Contributing to Spotube](#contributing-to-spotube) - [Contributing to SpoTube](#contributing-to-spotube)
- [Table of Contents](#table-of-contents) - [Table of Contents](#table-of-contents)
- [Code of Conduct](#code-of-conduct) - [Code of Conduct](#code-of-conduct)
- [I Have a Question](#i-have-a-question) - [I Have a Question](#i-have-a-question)
- [I Want To Contribute](#i-want-to-contribute) - [I Want To Contribute](#i-want-to-contribute)
- [Reporting Bugs](#reporting-bugs) - [Reporting Bugs](#reporting-bugs)
- [Before Submitting a Bug Report](#before-submitting-a-bug-report) - [Before Submitting a Bug Report](#before-submitting-a-bug-report)
- [How Do I Submit a Good Bug Report?](#how-do-i-submit-a-good-bug-report) - [How Do I Submit a Good Bug Report?](#how-do-i-submit-a-good-bug-report)
- [Suggesting Enhancements](#suggesting-enhancements) - [Suggesting Enhancements](#suggesting-enhancements)
- [Before Submitting an Enhancement](#before-submitting-an-enhancement) - [Before Submitting an Enhancement](#before-submitting-an-enhancement)
- [How Do I Submit a Good Enhancement Suggestion?](#how-do-i-submit-a-good-enhancement-suggestion) - [How Do I Submit a Good Enhancement Suggestion?](#how-do-i-submit-a-good-enhancement-suggestion)
- [Your First Code Contribution](#your-first-code-contribution) - [Your First Code Contribution](#your-first-code-contribution)
- [Submit Translations](#submit-translations) - [Submit Translations](#submit-translations)
## Code of Conduct ## Code of Conduct
This project and everyone participating in it is governed by the This project and everyone participating in it is governed by the
[Spotube Code of Conduct](https://github.com/KRTirtho/spotube/blob/master/CODE_OF_CONDUCT.md). [SpoTube Code of Conduct](https://github.com/KRTirtho/spotube/blob/master/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable behavior By participating, you are expected to uphold this code. Please report unacceptable behavior
to krtirtho@gmail.com. to krtirtho@gmail.com.
## I Have a Question ## I Have a Question
> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/KRTirtho/spotube#readme). > If you want to ask a question, we assume that you have read the
> available [Documentation](https://github.com/KRTirtho/spotube#readme).
Before you ask a question, it is best to search for existing [Issues](https://github.com/KRTirtho/spotube/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. Before you ask a question, it is best to search for existing [Issues](https://github.com/KRTirtho/spotube/issues) that
might help you.
In case you have found a suitable issue and still need clarification, you can write your question in
this issue.
It is also advisable to search the internet for answers first.
If you then still feel the need to ask a question and need clarification, we recommend the following: If you then still feel the need to ask a question and need clarification, we recommend the following:
- Open an [Discussion](https://github.com/KRTirtho/spotube/discussions/new) with the question label. - Open a [Discussion](https://github.com/KRTirtho/spotube/discussions/new) with the question label.
- Provide as much context as you can about what you're running into. - Provide as much context as you can about what you're running into.
- Provide project and platform versions (flutter, dart, pub, linux etc..), depending on what seems relevant. - Provide project and platform versions (flutter, dart, pub, linux etc..), depending on what seems relevant.
@ -52,18 +66,28 @@ We will then take care of the issue as soon as possible.
> ### Legal Notice > ### Legal Notice
> >
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. > When contributing to this project, you must agree that you have authored 100% of the content, that you have the
> necessary rights to the content and that the content you contribute may be provided under the project license.
### Reporting Bugs ### Reporting Bugs
#### Before Submitting a Bug Report #### Before Submitting a Bug Report
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. A good bug report shouldn't leave others needing to chase you up for more information.
Therefore, we ask you to
investigate carefully, collect information and describe the issue in detail in your report.
Please complete the
following steps in advance to help us fix any potential bug as fast as possible.
- Make sure that you are using the latest version. - Make sure that you are using the latest version.
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/KRTirtho/spotube#readme). If you are looking for support, you might want to check [this section](#i-have-a-question)). - Determine if your bug is really a bug and not an error on your side, e.g., using incompatible environment
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/KRTirtho/spotubeissues?q=label%3Abug). components/versions (Make sure that you have read the [documentation](https://github.com/KRTirtho/spotube#readme). If
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue. you are looking for support, you might want to check [this section](#i-have-a-question)).
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there
is not already a bug report existing for your bug or error in
the [bug tracker](https://github.com/KRTirtho/spotubeissues?q=label%3Abug).
- Also make sure to search the internet (including Stack Overflow) to see if users outside the GitHub community have
discussed the issue.
- Collect information about the bug: - Collect information about the bug:
- Stack trace (Traceback) - Stack trace (Traceback)
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM) - OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
@ -73,33 +97,57 @@ A good bug report shouldn't leave others needing to chase you up for more inform
#### How Do I Submit a Good Bug Report? #### How Do I Submit a Good Bug Report?
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to > You must never report security related issues, vulnerabilities or bugs, including sensitive information to the issue
> tracker, or elsewhere in public.
> Instead, sensitive bugs must be sent by email to
We use GitHub issues to track bugs and errors. If you run into an issue with the project: We use GitHub issues to track bugs and errors. If you run into an issue with the project:
- Open an [Issue](https://github.com/KRTirtho/spotube/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) <list>
- Explain the behavior you would expect and the actual behavior. <li><p>Open an <a href="https://github.com/KRTirtho/spotube/issues/new">Issue</a>.
- Please provide as much context as possible and describe the _reproduction steps_ that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. (Since we can't be sure at this point whether it is a
- Provide the information you collected in the previous section. bug or not, we ask you not to talk about a bug yet and not to label the issue.)</p></li>
<li><p>Explain the behavior you would expect and the actual behavior.</p></li>
<li><p>Please provide as much context as possible and describe the <emphasis>reproduction steps</emphasis> that someone else can follow to
recreate the issue on their own.
This usually includes your code.
For good bug reports, you should isolate the problem
and create a reduced test case.</p></li>
<li><p>Provide the information you collected in the previous section.</p></li>
</list>
Once it's filed: Once it's filed:
- The project team will label the issue accordingly. - The project team will label the issue accordingly.
- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced. - A team member will try to reproduce the issue with your provided steps.
- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution). If there are no reproduction steps or no
obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`.
Bugs
with the `needs-repro` tag will not be addressed until they are reproduced.
- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as
`critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution).
### Suggesting Enhancements ### Suggesting Enhancements
This section guides you through submitting an enhancement suggestion for Spotube, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. This section guides you through submitting an enhancement suggestion for Spotube, **including completely new features
and minor improvements to existing functionality**.
Following these guidelines will help maintainers and the community
to understand your suggestion and find related suggestions.
<!-- omit in toc --> <!-- omit in toc -->
#### Before Submitting an Enhancement #### Before Submitting an Enhancement
- Make sure that you are using the latest version. <list>
- Read the [documentation](https://github.com/KRTirtho/spotube#readme) carefully and find out if the functionality is already covered, maybe by an individual configuration. <li><p>Make sure that you are using the latest version.</p></li>
- Perform a [search](https://github.com/KRTirtho/spotube/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. <li><p>Read the <a href="https://github.com/KRTirtho/spotube#readme">documentation</a> carefully and find out if the functionality is
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset already covered, maybe by an individual configuration.</p></li>
<li><p>Perform a <a href="https://github.com/KRTirtho/spotube/issues">search</a> to see if the enhancement has already been suggested.
If it has, add a comment to the existing issue instead of opening a new one.</p></li>
<li><p>Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to
convince the project's developers of the merits of this feature. Keep in mind that we want features that will be
useful to the majority of our users and not just a small subset</p></li>
</list>
<!-- omit in toc --> <!-- omit in toc -->
@ -109,9 +157,19 @@ Enhancement suggestions are tracked as [GitHub issues](https://github.com/KRTirt
- Use a **clear and descriptive title** for the issue to identify the suggestion. - Use a **clear and descriptive title** for the issue to identify the suggestion.
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible. - Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you. - **Describe the current behavior** and **explain which behavior you expected to see instead** and why.
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. <!-- this should only be included if the project has a GUI --> At this point,
- **Explain why this enhancement would be useful** to most Spotube users. You may also want to point out the other projects that solved it better and which could serve as inspiration. you can also tell which alternatives do not work for you.
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part
which the suggestion is related to.
You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS
and Windows, and [this tool](https://github.com/colinkeenan/silentcast)
or [this tool](https://github.com/GNOME/byzanz) on
Linux.
<!-- this should only be included if the project has a GUI -->
- **Explain why this enhancement would be useful** to most Spotube users.
You may also want to point out the other
projects that solved it better and which could serve as inspiration.
### Your First Code Contribution ### Your First Code Contribution
@ -121,46 +179,52 @@ Do the following:
- Download the latest Flutter SDK (>=3.16.0) & enable desktop support - Download the latest Flutter SDK (>=3.16.0) & enable desktop support
- Install Development dependencies in linux - Install Development dependencies in linux
- Debian (>=12/Bookworm)/Ubuntu - Debian (>=12/Bookworm)/Ubuntu
```bash ```bash
$ apt-get install mpv libmpv-dev libappindicator3-1 gir1.2-appindicator3-0.1 libappindicator3-dev libsecret-1-0 libjsoncpp25 libsecret-1-dev libjsoncpp-dev libnotify-bin libnotify-dev avahi-daemon avahi-discover avahi-utils libnss-mdns mdns-scan libwebkit2gtk-4.1-0 libwebkit2gtk-4.1-dev libsoup-3.0-0 libsoup-3.0-dev sudo apt-get install libmpv-dev libappindicator3-1 gir1.2-appindicator3-0.1 libappindicator3-dev libsecret-1-0 libjsoncpp-dev libsecret-1-dev libjsoncpp-dev libnotify-bin libnotify-dev libnss-mdns mdns-scan libwebkit2gtk-4.1-0 libwebkit2gtk-4.1-dev libsoup-3.0-0 libsoup-3.0-dev
``` ```
- Use `libjsoncpp1` instead of `libjsoncpp25` (for Ubuntu < 22.04) - Use `libjsoncpp1` instead of `libjsoncpp25` (for Ubuntu < 22.04)
- Arch/Manjaro - Arch/Manjaro
```bash ```bash
yay -S mpv libappindicator-gtk3 libsecret jsoncpp libnotify avahi nss-mdns mdns-scan webkit2gtk-4.1 libsoup3 yay -S mpv libappindicator-gtk3 libsecret jsoncpp libnotify avahi nss-mdns mdns-scan webkit2gtk-4.1 libsoup3
``` ```
- Fedora - Fedora
```bash ```bash
dnf install mpv mpv-devel libappindicator-gtk3 libappindicator-gtk3-devel libsecret libsecret-devel jsoncpp jsoncpp-devel libnotify libnotify-devel avahi mdns-scan nss-mdns webkit2gtk4.1 webkit2gtk4.1-devel libsoup3 libsoup3-devel sudo dnf install mpv mpv-devel libappindicator-gtk3 libappindicator-gtk3-devel libsecret libsecret-devel jsoncpp jsoncpp-devel libnotify libnotify-devel avahi mdns-scan nss-mdns webkit2gtk4.1 webkit2gtk4.1-devel libsoup3 libsoup3-devel
``` ```
- Clone the Repo - Clone the Repo
- Create a `.env` in root of the project following the `.env.example` template - Create a `.env` in root of the project following the `.env.example` template
- Now run the following to bootstrap the project - Now run the following to bootstrap the project
```bash ```bash
flutter pub get && dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns
``` ```
- Finally run these following commands in the root of the project to start the Spotube Locally - Finally, run these following commands in the root of the project to start the Spotube Locally
```bash ```bash
flutter run -d <window|macos|linux|(<android-device-id>)> flutter run # -d [device]
``` ```
Do debugging/testing/build etc then submit to us with PR against the development branch (dev) & we'll review your code Do `debugging/testing/build` etc. then submit to us with PR against the `dev` branch, and we'll review your code
### Submit Translations ### Submit Translations
Make sure you're familiar with [Flutter localization](https://docs.flutter.dev/ui/accessibility-and-localization/internationalization). Then, you can start translating the app by following these steps: Make sure you're familiar
with [Flutter localization](https://docs.flutter.dev/ui/accessibility-and-localization/internationalization).
Then, you
can start translating the app by following these steps:
- Do all the steps in [Your First Code Contribution](#your-first-code-contribution) - Do all the steps in [Your First Code Contribution](#your-first-code-contribution)
- Make sure application starts in debug mode - Make sure the application starts in debug mode
- Now, in `lib/l10n/app_<2-letter code of your language>.arb` (create if not exists) add necessary translations - Now, in `lib/l10n/app_<2-letter code of your language>.arb` (create if not exists) add the necessary translations
> (You can follow the `lib/l10n/app_en.arb` for reference) > (You can follow the `lib/l10n/app_en.arb` for reference)
- If you're adding missing translations, you can check the `/untranslated_messages.json` file to see which messages are missing in your native locale - If you're adding missing translations, you can check the `/untranslated_messages.json` file to see which messages are
- If you added entirely new translations: missing in your native locale
- Add `const Locale('<2-letter language code>', '<2-letter ISO country code>')` in `lib/l10n/l10n.dart`'s `static final all = [...]` variable - If you add entirely new translations:
- Uncomment the Map entry of your locale from `lib/collections/language_codes.dart`'s `static final Map isoLangs = {` variable - Add `const Locale('<2-letter language code>', '<2-letter ISO country code>')` in `lib/l10n/l10n.dart`'s
- Now restart (hot restart if running already) the app in debug mode & go to "Settings" > "Language" & see if your locale shows up `static final all = [...]` variable
- If it does, select it & see if the app is translated properly - Uncomment the Map entry of your locale from `lib/collections/language_codes.dart`'s
- Now git commit the changes & push `static final Map isoLangs = {` variable
- Now restart (hot restart if running already) the app in debug mode & go to "Settings" > "Language" & see if your
locale shows up
- If it does, select it and see if the app is translated properly
- Now git commit changes and push
- Finally, submit a PR against the development branch (dev) & we'll review your code - Finally, submit a PR against the development branch (dev) & we'll review your code

View File

@ -1,59 +1,80 @@
**Privacy Policy** **Privacy Policy**
Kingkor Roy Tirtho built the Spotube app as an Open Source app. This SERVICE is provided by Kingkor Roy Tirtho at no cost and is intended for use as is. Kingkor Roy Tirtho built the SpoTube app as an Open Source app. This SERVICE is provided by Kingkor Roy Tirtho at no
cost and is intended for use as is.
This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use my Service. This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal
Information if anyone decided to use my Service.
If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that I collect is used for providing and improving the Service. I will not use or share your information with anyone except as described in this Privacy Policy. If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The
Personal Information that I collect is used for providing and improving the Service. I will not use or share your
information with anyone except as described in this Privacy Policy.
The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which are accessible at Spotube unless otherwise defined in this Privacy Policy. The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which are accessible at
SpoTube unless otherwise defined in this Privacy Policy.
**Information Collection and Use** **Information Collection and Use**
For a better experience, while using our Service, I may require you to provide us with certain personally identifiable information. The information that I request will be retained on your device and is not collected by me in any way. For a better experience, while using our Service, I may require you to provide us with certain personally identifiable
information. The information that I request will be retained on your device and is not collected by me in any way.
The app does use third-party services that may collect information used to identify you. The app does use third-party services that may collect information used to identify you.
Link to the privacy policy of third-party service providers used by the app Link to the privacy policy of third-party service providers used by the app
* [Google Play Services](https://www.google.com/policies/privacy/) * [Google Play Services](https://www.google.com/policies/privacy/)
**Log Data** **Log Data**
Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other statistics. But none of this info leaves your device. It's stored in a log-file on your device only accessible to you. Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system
version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other
statistics. But none of this info leaves your device. It's stored in a log-file on your device only accessible to you.
**Cookies** **Cookies**
Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory. Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to
your browser from the websites that you visit and are stored on your device's internal memory.
This Service does not use these “cookies” explicitly. How ever the some services may use cookies for their cause (e.g. improvement) but you can deny them once asked This Service does not use these “cookies” explicitly. How ever the some services may use cookies for their cause (e.g.
improvement) but you can deny them once asked
**Service Providers** **Service Providers**
I may employ third-party companies and individuals due to the following reasons: I may employ third-party companies and individuals due to the following reasons:
* To facilitate our Service; * To facilitate our Service;
* To provide the Service on our behalf; * To provide the Service on our behalf;
* To perform Service-related services; or * To perform Service-related services; or
* To assist us in analyzing how our Service is used. * To assist us in analyzing how our Service is used.
I want to inform users of this Service that these third parties have access to their Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose. I want to inform users of this Service that these third parties have access to their Personal Information. The reason is
to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information
for any other purpose.
**Security** **Security**
I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and I cannot guarantee its absolute security. I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means
of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100%
secure and reliable, and I cannot guarantee its absolute security.
**Links to Other Sites** **Links to Other Sites**
This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services. This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site.
Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of
these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of
any third-party sites or services.
**Childrens Privacy** **Childrens Privacy**
These Services do not address anyone under the age of 13. I do not knowingly collect personally identifiable information from children under 13 years of age. In the case I discover that a child under 13 has provided me with personal information, I immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact me so that I will be able to do the necessary actions. These Services do not address anyone under the age of 13. I do not knowingly collect personally identifiable information
from children under 13 years of age. In the case I discover that a child under 13 has provided me with personal
information, I immediately delete this from our servers. If you are a parent or guardian and you are aware that your
child has provided us with personal information, please contact me so that I will be able to do the necessary actions.
**Changes to This Privacy Policy** **Changes to This Privacy Policy**
I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page. I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any
changes. I will notify you of any changes by posting the new Privacy Policy on this page.
This policy is effective as of 2022-04-01 This policy is effective as of 2022-04-01

472
README.md
View File

@ -1,11 +1,11 @@
<div align="center"> <div align="center">
<img width="600" src="assets/spotube_banner.png" alt="Spotube Logo"> <img width="124" src="assets/spotube-logo-stable-notWallpaper.png" alt="Spotube Logo">
An open source, cross-platform Spotify client compatible across multiple platforms<br /> An open source, cross-platform Spotify client compatible across multiple platforms<br />
utilizing Spotify's data API and YouTube, Piped.video or JioSaavn as an audio source,<br /> utilizing Spotify's data API and YouTube, piped.video or JioSaavn as an audio source,<br />
eliminating the need for Spotify Premium eliminating the need for Spotify Premium
Btw it's not just another Electron app 😉 Btw it's not just another Electron app
<a href="https://spotube.krtirtho.dev"><img alt="Visit the website" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/website_vector.svg"></a> <a href="https://spotube.krtirtho.dev"><img alt="Visit the website" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/website_vector.svg"></a>
<a href="https://discord.gg/uJ94vxB6vg"><img alt="Discord Server" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/social/discord-plural_vector.svg"></a> <a href="https://discord.gg/uJ94vxB6vg"><img alt="Discord Server" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/social/discord-plural_vector.svg"></a>
@ -19,36 +19,38 @@ Btw it's not just another Electron app 😉
--- ---
![Spotube Desktop](assets/spotube-screenshot.png) [//]: # (![SpoTube Desktop]&#40;&#41;)
![Spotube Mobile](assets/mobile-screenshots/combined.png) [//]: # (![SpoTube Mobile]&#40;assets/mobile-screenshots/combined.png&#41;)
</div> </div>
## 🌃 Features ## Features
- 🚫 No ads, thanks to the use of public & free Spotify and YT Music APIs¹ - No ads, thanks to the use of public & free Spotify and YT Music APIs¹
- ⬇️ Freely downloadable tracks - Freely downloadable tracks
- 🖥️ 📱 Cross-platform support - Cross-platform support
- 🪶 Small size & less data usage - Small size & fewer data usage
- 🕵️ Anonymous/guest login - Anonymous/guest login
- 🕒 Time synced lyrics - Time synced lyrics
- No telemetry, diagnostics or user data collection - No telemetry, diagnostics or user data collection
- 🚀 Native performance - Native performance
- 📖 Open source/libre software - Open source/libre software
- 🔉 Playback control is done locally, not on the server - Playback control is done locally, not on the server
**¹** It is still **recommended** to support creators by engaging with their YouTube channels/Spotify tracks (or preferably by buying their merch/concert tickets/physical media). **¹** It is still **recommended** to support creators by engaging with their YouTube channels/Spotify tracks (or
preferably by buying their merch/concert tickets/physical media).
### Unsupported features ### Unsupported features
- 🗣️ **Spotify Shows & Podcasts:** Shows and Podcasts will <ins>**never be supported**</ins> because the audio tracks are <ins>_only_</ins> available on Spotify and accessing them would require Spotify Premium. - **Spotify Shows & Podcasts:** Shows and Podcasts will <ins>**never be supported**</ins> because the audio tracks
- 🎧 **Spotify Listen Along:** [Coming soon!](https://github.com/KRTirtho/spotube/issues/8) are <ins>_only_</ins> available on Spotify and accessing them would require Spotify Premium.
- **Spotify Listen Along:** [Coming soon!](https://github.com/KRTirtho/spotube/issues/8)
## 📜 ⬇️ Installation guide ## Installation guide
New versions usually release every 3-4 months.<br /> New versions usually release every 3-4 months.<br />
This handy table lists all the methods you can use to install Spotube: This handy table lists all the methods you can use to install SpoTube:
<table> <table>
<tr> <tr>
@ -176,17 +178,18 @@ brew install --cask spotube
</tr> </tr>
</table> </table>
### 🔄 Nightly Builds ### Nightly Builds
Grab the latest nightly builds of Spotube [from the GitHub Releases](https://github.com/KRTirtho/spotube/releases/tag/nightly). Grab the latest nightly builds of
Spotube [from the GitHub Releases](https://github.com/KRTirtho/spotube/releases/tag/nightly).
## 🕳️ Building from source ## Building from source
<a href="https://github.com/KRTirtho/spotube/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/KRTirtho/spotube/spotube-release-binary.yml?+label=Build%20Status"></a> <a href="https://github.com/KRTirtho/spotube/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/KRTirtho/spotube/spotube-release-binary.yml?+label=Build%20Status"></a>
You can compile Spotube's source code by [following these instructions](CONTRIBUTION.md#your-first-code-contribution). You can compile SpoTube's source code by [following these instructions](CONTRIBUTION.md#your-first-code-contribution).
## 👥 The Spotube team ## The Spotube team
- [Kingkor Roy Tirtho](https://github.com/KRTirtho) - The Founder, Maintainer and Lead Developer - [Kingkor Roy Tirtho](https://github.com/KRTirtho) - The Founder, Maintainer and Lead Developer
- [RaptaG](https://github.com/RaptaG) - The GitHub Moderator and Community Manager - [RaptaG](https://github.com/RaptaG) - The GitHub Moderator and Community Manager
@ -195,159 +198,292 @@ You can compile Spotube's source code by [following these instructions](CONTRIBU
- [Piotr Rogowski](https://github.com/karniv00l) - The MacOS Developer - [Piotr Rogowski](https://github.com/karniv00l) - The MacOS Developer
- [Rusty Apple](https://github.com/RustyApple) - The Mysterious Unknown Guy - [Rusty Apple](https://github.com/RustyApple) - The Mysterious Unknown Guy
## 💼 License ## License
Spotube is open source and licensed under the [BSD-4-Clause](/LICENSE) License. Spotube is open source and licensed under the [BSD-4-Clause](/LICENSE) License.
If you are concerned, you can [read the reason of choosing this license](https://dev.to/krtirtho/choosing-open-source-license-wisely-1m3p). If you are concerned, you
can [read the reason of choosing this license](https://dev.to/krtirtho/choosing-open-source-license-wisely-1m3p).
<details> <details>
<summary> <summary>
<h2><code>[Click to show]</code> 🙏 Services/Package/Plugin Credits</h2> <h2><code>[Click to show]</code></h2>
</summary> </summary>
## Services/Package/Plugin Credits
### Services ### Services
1. [Flutter](https://flutter.dev) - Flutter transforms the app development process. Build, test, and deploy beautiful mobile, web, desktop, and embedded apps from a single codebase 1. [Flutter](https://flutter.dev) - Flutter transforms the app development process. Build, test, and deploy beautiful
1. [MPV](https://mpv.io) - mpv is a free (as in freedom) media player for the command line. It supports a wide variety of media file formats, audio and video codecs, and subtitle types. mobile, web, desktop, and embedded apps from a single codebase
1. [Spotify API](https://developer.spotify.com/documentation/web-api) - The Spotify Web API is a RESTful API that provides access to Spotify data 2. [MPV](https://mpv.io) - mpv is a free (as in freedom) media player for the command line. It supports a wide variety
1. [Piped](https://piped-docs.kavin.rocks/) - Piped is a privacy friendly alternative YouTube frontend, which is efficient and scalable by design. of media file formats, audio and video codecs, and subtitle types.
1. [Invidious](https://invidious.io/) - Invidious is an open source alternative front-end to YouTube. 3. [Spotify API](https://developer.spotify.com/documentation/web-api) - The Spotify Web API is a REST API that
1. [YouTube](https://youtube.com/) - YouTube is an American online video-sharing platform headquartered in San Bruno, California. Three former PayPal employees—Chad Hurley, Steve Chen, and Jawed Karim—created the service in February 2005 provides access to Spotify data
1. [yt-dlp](https://github.com/yt-dlp/yt-dlp) - A feature-rich command-line audio/video downloader 4. [Piped](https://piped-docs.kavin.rocks/) - Piped is a privacy-friendly alternative YouTube frontend, which is
1. [NewPipeExtractor](https://github.com/TeamNewPipe/NewPipeExtractor) - NewPipe's core library for extracting data from streaming sites efficient and scalable by design.
1. [JioSaavn](https://www.jiosaavn.com) - JioSaavn is an Indian online music streaming service and a digital distributor of Bollywood, English and other regional Indian music across the world. Since it was founded in 2007 as Saavn, the company has acquired rights to over 5 crore (50 million) music tracks in 15 languages 5. [Invidious](https://invidious.io/) - Invidious is an open source alternative front-end to YouTube.
1. [SongLink](https://song.link) - SongLink is a free smart link service that helps you share music with your audience. It's a one-stop-shop for creating smart links for music, podcasts, and other audio content 6. [YouTube](https://youtube.com/) - YouTube is an American online video-sharing platform headquartered in San Bruno,
1. [LRCLib](https://lrclib.net/) - A public synced lyric API California. Three former PayPal employees—Chad Hurley, Steve Chen, and Jawed Karim—created the service in February
1. [Linux](https://www.linux.org) - Linux is a family of open-source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991, by Linus Torvalds. Linux is typically packaged in a Linux distribution 2005
1. [AUR](https://aur.archlinux.org) - AUR stands for Arch User Repository. It is a community-driven repository for Arch-based Linux distributions users 1. [yt-dlp](https://github.com/yt-dlp/yt-dlp) - A feature-rich command-line audio/video downloader
1. [Flatpak](https://flatpak.org) - Flatpak is a utility for software deployment and package management for Linux 1. [NewPipeExtractor](https://github.com/TeamNewPipe/NewPipeExtractor) - NewPipe's core library for extracting data
1. [SponsorBlock](https://sponsor.ajay.app) - SponsorBlock is an open-source crowdsourced browser extension and open API for skipping sponsor segments in YouTube videos. from streaming sites
1. [Inno Setup](https://jrsoftware.org/isinfo.php) - Inno Setup is a free installer for Windows programs by Jordan Russell and Martijn Laan 7. [JioSaavn](https://www.jiosaavn.com) - JioSaavn is an Indian online music streaming service and a digital distributor
1. [F-Droid](https://f-droid.org) - F-Droid is an installable catalogue of FOSS (Free and Open Source Software) applications for the Android platform. The client makes it easy to browse, install, and keep track of updates on your device of Bollywood, English and other regional Indian music across the world. Since it was founded in 2007 as Saavn, the
1. [LastFM](https://last.fm) - Last.fm is a music streaming and discovery platform that helps users discover and share new music. It tracks users' music listening habits across many devices and platforms. company has acquired rights to over 5 corer (50 million) music tracks in 15 languages
8. [SongLink](https://song.link) - SongLink is a free smart link service that helps you share music with your audience.
It's a one-stop-shop for creating smart links for music, podcasts, and other audio content
9. [LRCLib](https://lrclib.net/) - A public synced lyric API
10. [Linux](https://www.linux.org) - Linux is a family of open-source Unix-like operating systems based on the Linux
kernel, an operating system kernel first released on September 17, 1991, by Linus Torvalds. Linux is typically
packaged in a Linux distribution
11. [AUR](https://aur.archlinux.org) - AUR stands for Arch User Repository. It is a community-driven repository for
Arch-based Linux distributions users
12. [Flatpak](https://flatpak.org) - Flatpak is a utility for software deployment and package management for Linux
13. [SponsorBlock](https://sponsor.ajay.app) - SponsorBlock is an open-source crowd-sourced browser extension and open API
for skipping sponsor segments in YouTube videos.
14. [Inno Setup](https://jrsoftware.org/isinfo.php) - Inno Setup is a free installer for Windows programs by Jordan
Russell and Martijn Laan
15. [F-Droid](https://f-droid.org) - F-Droid is an installable catalogue of FOSS (Free and Open Source Software)
applications for the Android platform. The client makes it easy to browse, install, and keep track of updates on your
device
16. [LastFM](https://last.fm) - Last.fm is a music streaming and discovery platform that helps users discover and share
new music. It tracks users' music listening habits across many devices and platforms.
### Dependencies ### Dependencies
1. [app_links](https://github.com/llfbandit/app_links) - Android App Links, Deep Links, iOs Universal Links and Custom URL schemes handler for Flutter (desktop included). 1. [app_links](https://github.com/llfbandit/app_links) - Android App Links, Deep Links, iOs Universal Links and Custom
1. [args](https://pub.dev/packages/args) - Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options. URL schemes handler for Flutter (desktop included).
1. [async](https://pub.dev/packages/async) - Utility functions and classes related to the 'dart:async' library. 2. [args](https://pub.dev/packages/args) - Library for defining parsers for parsing raw command-line arguments into a
1. [audio_service](https://pub.dev/packages/audio_service) - Flutter plugin to play audio in the background while the screen is off. set of options and values using GNU and POSIX style options.
1. [audio_service_mpris](https://github.com/bdrazhzhov/audio-service-mpris) - audio_service platform interface supporting Media Player Remote Interfacing Specification. 3. [async](https://pub.dev/packages/async) - Utility functions and classes related to the 'dart:async' library.
1. [audio_session](https://github.com/ryanheise/audio_session) - Sets the iOS audio session category and Android audio attributes for your app, and manages your app's audio focus, mixing and ducking behaviour. 4. [audio_service](https://pub.dev/packages/audio_service) - Flutter plugin to play audio in the background while the
1. [auto_route](https://github.com/Milad-Akarie/auto_route_library) - AutoRoute is a declarative routing solution, where everything needed for navigation is automatically generated for you. screen is off.
1. [auto_size_text](https://github.com/leisim/auto_size_text) - Flutter widget that automatically resizes text to fit perfectly within its bounds. 5. [audio_service_mpris](https://github.com/bdrazhzhov/audio-service-mpris) - audio_service platform interface
1. [bonsoir](https://bonsoir.skyost.eu) - A Zeroconf library that allows you to discover network services and to broadcast your own. Based on Apple Bonjour and Android NSD. supporting Media Player Remote Interfacing Specification.
1. [cached_network_image](https://github.com/Baseflow/flutter_cached_network_image) - Flutter library to load and cache network images. Can also be used with placeholder and error widgets. 6. [audio_session](https://github.com/ryanheise/audio_session) - Sets the iOS audio session category and Android audio
1. [connectivity_plus](https://github.com/fluttercommunity/plus_plugins) - Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. attributes for your app, and manages your app's audio focus, mixing and ducking behaviour.
1. [device_info_plus](https://github.com/fluttercommunity/plus_plugins) - Flutter plugin providing detailed information about the device (make, model, etc.), and Android or iOS version the app is running on. 7. [auto_route](https://github.com/Milad-Akarie/auto_route_library) - AutoRoute is a declarative routing solution, where
1. [dio](https://github.com/cfug/dio) - A powerful HTTP networking package,supports Interceptors,Aborting and canceling a request,Custom adapters, Transformers, etc. everything needed for navigation is automatically generated for you.
1. [drift](https://drift.simonbinder.eu/) - Drift is a reactive library to store relational data in Dart and Flutter applications. 8. [auto_size_text](https://github.com/leisim/auto_size_text) - Flutter widget that automatically resizes text to fit
1. [duration](https://github.com/desktop-dart/duration) - Utilities to make working with 'Duration's easier. Formats duration in human readable form and also parses duration in human readable form to Dart's Duration. perfectly within its bounds.
1. [encrypt](https://pub.dev/packages/encrypt) - A set of high-level APIs over PointyCastle for two-way cryptography. 9. [bonsoir](https://bonsoir.skyost.eu) - A Zeroconf library that allows you to discover network services and to
1. [envied](https://github.com/petercinibulk/envied) - Explicitly reads environment variables into a dart file from a .env file for more security and faster start up times. broadcast your own. Based on Apple Bonjour and Android NSD.
1. [file_picker](https://github.com/miguelpruivo/plugins_flutter_file_picker) - A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support. 10. [cached_network_image](https://github.com/Baseflow/flutter_cached_network_image) - Flutter library to load and cache
1. [file_selector](https://pub.dev/packages/file_selector) - Flutter plugin for opening and saving files, or selecting directories, using native file selection UI. network images. Can also be used with placeholder and error widgets.
1. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a collection of familiar, friendly and modern icons from Microsoft. 11. [connectivity_plus](https://github.com/fluttercommunity/plus_plugins) - Flutter plugin for discovering the state of
1. [flutter_cache_manager](https://github.com/Baseflow/flutter_cache_manager/tree/develop/flutter_cache_manager) - Generic cache manager for flutter. Saves web files on the storages of the device and saves the cache info using sqflite. the network (Wi-Fi & mobile/cellular) connectivity on Android and iOS.
1. [flutter_discord_rpc](https://pub.dev/packages/flutter_discord_rpc) - Discord RPC support for Flutter desktop platforms 12. [device_info_plus](https://github.com/fluttercommunity/plus_plugins) - Flutter plugin providing detailed information
1. [flutter_displaymode](https://github.com/ajinasokan/flutter_displaymode) - A Flutter plugin to set display mode (resolution, refresh rate) on Android platform. Allows to enable high refresh rate on supported devices. about the device (make, model, etc.), and Android or iOS version the app is running on.
1. [flutter_feather_icons](https://github.com/muj-programmer/flutter_feather_icons) - Feather is a collection of simply beautiful open source icons. Each icon is designed on a 24x24 grid with an emphasis on simplicity, consistency and usability. 13. [dio](https://github.com/cfug/dio) - A powerful HTTP networking package,supports Interceptors,Aborting and canceling
1. [flutter_form_builder](https://github.com/flutter-form-builder-ecosystem) - This package helps in creation of forms in Flutter by removing the boilerplate code, reusing validation, react to changes, and collect final user input. a request,Custom adapters, Transformers, etc.
1. [flutter_hooks](https://github.com/rrousselGit/flutter_hooks) - A flutter implementation of React hooks. It adds a new kind of widget with enhanced code reuse. 14. [drift](https://drift.simonbinder.eu/) - Drift is a reactive library to store relational data in Dart and Flutter
1. [flutter_inappwebview](https://inappwebview.dev/) - A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. applications.
1. [flutter_native_splash](https://pub.dev/packages/flutter_native_splash) - Customize Flutter's default white native splash screen with background color and splash image. Supports dark mode, full screen, and more. 15. [duration](https://github.com/desktop-dart/duration) - Utilities to make working with 'Duration's easier. Formats
1. [flutter_riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze. duration in human-readable form and also parses duration in human-readable form to Dart's Duration.
1. [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) - Flutter Secure Storage provides API to store data in secure storage. Keychain is used in iOS, KeyStore based solution is used in Android. 16. [encrypt](https://pub.dev/packages/encrypt) - A set of high-level APIs over PointyCastle for two-way cryptography.
1. [flutter_sharing_intent](https://github.com/bhagat-techind/flutter_sharing_intent.git) - A flutter plugin that allow flutter apps to receive photos, videos, text, urls or any other file types from another app. 17. [envied](https://github.com/petercinibulk/envied) - Explicitly reads environment variables into a dart file from a
1. [flutter_undraw](https://github.com/KRTirtho/flutter_undraw) - Undraw.co Illustrations for Flutter with customization options .env file for more security and faster start up times.
1. [form_builder_validators](https://github.com/flutter-form-builder-ecosystem) - Form Builder Validators set of validators for FlutterFormBuilder. Provides common validators and a way to make your own. 18. [file_picker](https://github.com/miguelpruivo/plugins_flutter_file_picker) - A package that allows you to use a
1. [form_validator](https://github.com/TheMisir/form-validator) - Simplest form validation library for flutter's form field widgets native file explorer to pick single or multiple absolute file paths, with extension filtering support.
1. [freezed_annotation](https://pub.dev/packages/freezed_annotation) - Annotations for the freezed code-generator. This package does nothing without freezed too. 19. [file_selector](https://pub.dev/packages/file_selector) - Flutter plugin for opening and saving files, or selecting
1. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package in Dart, to suit all your fuzzy string matching/searching needs! directories, using native file selection UI.
1. [gap](https://github.com/letsar/gap) - Flutter widgets for easily adding gaps inside Flex widgets such as Columns and Rows or scrolling views. 20. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a
1. [google_fonts](https://pub.dev/packages/google_fonts) - A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling. collection of familiar, friendly and modern icons from Microsoft.
1. [home_widget](https://pub.dev/packages/home_widget) - A plugin to provide a common interface for creating HomeScreen Widgets for Android and iOS. 21. [flutter_cache_manager](https://github.com/Baseflow/flutter_cache_manager/tree/develop/flutter_cache_manager) -
1. [hooks_riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze. Generic cache manager for flutter. Saves web files on the storages of the device and saves the cache info using
1. [html](https://pub.dev/packages/html) - APIs for parsing and manipulating HTML content outside the browser. sqlite.
1. [html_unescape](https://github.com/filiph/html_unescape) - A small library for un-escaping HTML. Supports all Named Character References, Decimal Character References and Hexadecimal Character References. 22. [flutter_discord_rpc](https://pub.dev/packages/flutter_discord_rpc) - Discord RPC support for Flutter desktop
1. [http](https://pub.dev/packages/http) - A composable, multi-platform, Future-based API for HTTP requests. platforms
1. [image_picker](https://pub.dev/packages/image_picker) - Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. 23. [flutter_displaymode](https://github.com/ajinasokan/flutter_displaymode) - A Flutter plugin to set display mode (
1. [intl](https://pub.dev/packages/intl) - Contains code to deal with internationalized/localized messages, date and number formatting and parsing, bi-directional text, and other internationalization issues. resolution, refresh rate) on Android platform. Allows to enable high refresh rate on supported devices.
1. [invidious](https://pub.dev/packages/invidious) - Invidious API client for Dart and Flutter. 24. [flutter_feather_icons](https://github.com/muj-programmer/flutter_feather_icons) - Feather is a collection of simply
1. [jiosaavn](https://github.com/KRTirtho/jiosaavn) - Unofficial API client for jiosaavn.com beautiful open source icons. Each icon is designed on a 24x24 grid with an emphasis on simplicity, consistency and
1. [json_annotation](https://pub.dev/packages/json_annotation) - Classes and helper functions that support JSON code generation via the `json_serializable` package. usability.
1. [local_notifier](https://github.com/leanflutter/local_notifier) - This plugin allows Flutter desktop apps to displaying local notifications. 25. [flutter_form_builder](https://github.com/flutter-form-builder-ecosystem) - This package helps in creation of forms
1. [logger](https://pub.dev/packages/logger) - Small, easy to use and extensible logger which prints beautiful logs. in Flutter by removing the boilerplate code, reusing validation, react to changes, and collect final user input.
1. [logging](https://pub.dev/packages/logging) - Provides APIs for debugging and error logging, similar to loggers in other languages, such as the Closure JS Logger and java.util.logging.Logger. 26. [flutter_hooks](https://github.com/rrousselGit/flutter_hooks) - A flutter implementation of React hooks. It adds a
1. [lrc](https://pub.dev/packages/lrc) - A Dart-only package that creates, parses, and handles LRC, which is a format that stores song lyrics. new kind of widget with enhanced code reuse.
1. [media_kit](https://github.com/media-kit/media-kit) - A cross-platform video player & audio player for Flutter & Dart. Performant, stable, feature-proof & modular. 27. [flutter_inappwebview](https://inappwebview.dev/) - A Flutter plugin that allows you to add an inline webview, to use
1. [media_kit_libs_audio](https://github.com/media-kit/media-kit.git) - package:media_kit audio (only) playback native libraries for all platforms. a headless webview, and to open an in-app browser window.
1. [metadata_god](https://pub.dev/packages/metadata_god) - Plugin for retrieving and writing audio tags/metadata from audio files 28. [flutter_native_splash](https://pub.dev/packages/flutter_native_splash) - Customize Flutter's default white native
1. [mime](https://pub.dev/packages/mime) - Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. splash screen with background color and splash image. Supports dark mode, full screen, and more.
1. [open_file](https://pub.dev/packages/open_file) - A plug-in that can call native APP to open files with string result in flutter, support iOS(UTI) / android(intent) / PC(ffi) / web(dart:html) 29. [flutter_riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with
1. [package_info_plus](https://github.com/fluttercommunity/plus_plugins) - Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. asynchronous code a breeze.
1. [palette_generator](https://pub.dev/packages/palette_generator) - Flutter package for generating palette colors from a source image. 30. [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) - Flutter Secure Storage provides API to
1. [path](https://pub.dev/packages/path) - A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web. store data in secure storage. Keychain is used in iOS, KeyStore based solution is used in Android.
1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. 31. [flutter_sharing_intent](https://github.com/bhagat-techind/flutter_sharing_intent.git) - A flutter plugin that allow
1. [permission_handler](https://pub.dev/packages/permission_handler) - Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. flutter apps to receive photos, videos, text, urls or any other file types from another app.
1. [piped_client](https://github.com/KRTirtho/piped_client) - API Client for piped.video 32. [flutter_undraw](https://github.com/KRTirtho/flutter_undraw) - Undraw.co Illustrations for Flutter with customization
1. [riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze. options
1. [scroll_to_index](https://github.com/quire-io/scroll-to-index) - Scroll to a specific child of any scrollable widget in Flutter 33. [form_builder_validators](https://github.com/flutter-form-builder-ecosystem) - Form Builder Validators set of
1. [shadcn_flutter](https://github.com/sunarya-thito/shadcn_flutter) - Beautifully designed components from Shadcn/UI is now available for Flutter validators for FlutterFormBuilder. Provides common validators and a way to make your own.
1. [shared_preferences](https://pub.dev/packages/shared_preferences) - Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. 34. [form_validator](https://github.com/TheMisir/form-validator) - Simplest form validation library for flutter's form
1. [shelf](https://pub.dev/packages/shelf) - A model for web server middleware that encourages composition and easy reuse. field widgets
1. [shelf_router](https://pub.dev/packages/shelf_router) - A convenient request router for the shelf web-framework, with support for URL-parameters, nested routers and routers generated from source annotations. 35. [freezed_annotation](https://pub.dev/packages/freezed_annotation) - Annotations for the freezed code-generator. This
1. [shelf_web_socket](https://pub.dev/packages/shelf_web_socket) - A shelf handler that wires up a listener for every connection. package does nothing without freezed too.
1. [simple_icons](https://teavelopment.com/) - The Simple Icon pack available as Flutter Icons. Provides over 1500 Free SVG icons for popular brands. 36. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package
1. [skeletonizer](https://github.com/Milad-Akarie/skeletonizer) - Converts already built widgets into skeleton loaders with no extra effort. in Dart, to suit all your fuzzy string matching/searching needs!
1. [sliding_up_panel](https://github.com/akshathjain/sliding_up_panel) - A draggable Flutter widget that makes implementing a SlidingUpPanel much easier! 37. [gap](https://github.com/letsar/gap) - Flutter widgets for easily adding gaps inside Flex widgets such as Columns and
1. [sliver_tools](https://github.com/Kavantix) - A set of useful sliver tools that are missing from the flutter framework Rows or scrolling views.
1. [smtc_windows](https://pub.dev/packages/smtc_windows) - Windows `SystemMediaTransportControls` implementation for Flutter giving access to Windows OS Media Control applet. 38. [google_fonts](https://pub.dev/packages/google_fonts) - A Flutter package to use fonts from fonts.google.com.
1. [spotify](https://github.com/rinukkusu/spotify-dart) - An incomplete dart library for interfacing with the Spotify Web API. Supports HTTP fetching, caching, and asset bundling.
1. [sqlite3](https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3) - Provides lightweight yet convenient bindings to SQLite by using dart:ffi 39. [home_widget](https://pub.dev/packages/home_widget) - A plugin to provide a common interface for creating HomeScreen
1. [sqlite3_flutter_libs](https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3_flutter_libs) - Flutter plugin to include native sqlite3 libraries with your app Widgets for Android and iOS.
1. [stroke_text](https://github.com/MohamedAbd0/stroke_text) - A Simple Flutter plugin for applying stroke (border) style to a text widget 40. [hooks_riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with
1. [system_theme](https://github.com/bdlukaa/system_theme/tree/master/system_theme) - A plugin to get the current system theme info. Supports Android, Web, Windows, Linux and macOS asynchronous code a breeze.
1. [test](https://pub.dev/packages/test) - A full featured library for writing and running Dart tests across platforms. 41. [html](https://pub.dev/packages/html) - APIs for parsing and manipulating HTML content outside the browser.
1. [timezone](https://pub.dev/packages/timezone) - Time zone database and time zone aware DateTime. 42. [html_unescape](https://github.com/filiph/html_unescape) - A small library for un-escaping HTML. Supports all Named
1. [titlebar_buttons](https://github.com/gtk-flutter/titlebar_buttons) - A package which provides most of the titlebar buttons from windows, linux and macos. Character References, Decimal Character References and Hexadecimal Character References.
1. [tray_manager](https://github.com/leanflutter/tray_manager) - This plugin allows Flutter desktop apps to defines system tray. 43. [http](https://pub.dev/packages/http) - A composable, multi-platform, Future-based API for HTTP requests.
1. [url_launcher](https://pub.dev/packages/url_launcher) - Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. 44. [image_picker](https://pub.dev/packages/image_picker) - Flutter plugin for selecting images from the Android and iOS
1. [uuid](https://pub.dev/packages/uuid) - RFC4122 (v1, v4, v5, v6, v7, v8) UUID Generator and Parser for Dart image library, and taking new pictures with the camera.
1. [version](https://github.com/dartninja/version) - Provides a simple class for parsing and comparing semantic versions as defined by http://semver.org/ 45. [intl](https://pub.dev/packages/intl) - Contains code to deal with internationalized/localized messages, date and
1. [very_good_infinite_list](https://github.com/VeryGoodOpenSource/very_good_infinite_list) - A library for easily displaying paginated data, created by Very Good Ventures. Great for activity feeds, news feeds, and more. number formatting and parsing, bidirectional text, and other internationalization issues.
1. [visibility_detector](https://pub.dev/packages/visibility_detector) - A widget that detects the visibility of its child and notifies a callback. 46. [invidious](https://pub.dev/packages/invidious) - Invidious API client for Dart and Flutter.
1. [web_socket_channel](https://pub.dev/packages/web_socket_channel) - StreamChannel wrappers for WebSockets. Provides a cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying StreamChannel. 47. [jiosaavn](https://github.com/KRTirtho/jiosaavn) - Unofficial API client for jiosaavn.com
1. [wikipedia_api](https://github.com/KRTirtho/wikipedia_api) - Wikipedia API for dart and flutter 48. [json_annotation](https://pub.dev/packages/json_annotation) - Classes and helper functions that support JSON code
1. [win32_registry](https://pub.dev/packages/win32_registry) - A package that provides a friendly Dart API for accessing the Windows Registry. generation via the `json_serializable` package.
1. [window_manager](https://github.com/leanflutter/window_manager) - This plugin allows Flutter desktop apps to resizing and repositioning the window. 49. [local_notifier](https://github.com/leanflutter/local_notifier) - This plugin allows Flutter desktop apps to
1. [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) - A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key. displaying local notifications.
1. [http_parser](https://pub.dev/packages/http_parser) - A platform-independent package for parsing and serializing HTTP formats. 50. [logger](https://pub.dev/packages/logger) - Small, easy to use and extensible logger which prints beautiful logs.
1. [collection](https://pub.dev/packages/collection) - Collections and utilities functions and classes related to collections. 51. [logging](https://pub.dev/packages/logging) - Provides APIs for debugging and error logging, similar to loggers in
1. [otp_util](https://github.com/dushiling) - otp_util is a dart package to generate and verify one-time passwords,it It provides two methods TOPT and HOTP.They are Time-based OTPs and Counter-based OTPs. other languages, such as the Closure JS Logger and java.util.logging.Logger.
1. [dio_http2_adapter](https://github.com/cfug/dio) - An adapter that combines HTTP/2 and dio. Supports reusing connections, header compression, etc. 52. [lrc](https://pub.dev/packages/lrc) - A Dart-only package that creates, parses, and handles LRC, which is a format
1. [build_runner](https://pub.dev/packages/build_runner) - A build system for Dart code generation and modular compilation. that stores song lyrics.
1. [envied_generator](https://github.com/petercinibulk/envied) - Generator for the Envied package. See https://pub.dev/packages/envied. 53. [media_kit](https://github.com/media-kit/media-kit) - A cross-platform video player & audio player for Flutter &
1. [flutter_gen_runner](https://github.com/FlutterGen/flutter_gen) - The Flutter code generator for your assets, fonts, colors, … — Get rid of all String-based APIs. Dart. Performant, stable, feature-proof & modular.
1. [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) - A package which simplifies the task of updating your Flutter app's launcher icon. 54. [media_kit_libs_audio](https://github.com/media-kit/media-kit.git) - package:media_kit audio (only) playback native
1. [flutter_lints](https://pub.dev/packages/flutter_lints) - Recommended lints for Flutter apps, packages, and plugins to encourage good coding practices. libraries for all platforms.
1. [json_serializable](https://pub.dev/packages/json_serializable) - Automatically generate code for converting to and from JSON by annotating Dart classes. 55. [metadata_god](https://pub.dev/packages/metadata_god) - Plugin for retrieving and writing audio tags/metadata from
1. [freezed](https://pub.dev/packages/freezed) - Code generation for immutable classes that has a simple syntax/API without compromising on the features. audio files
1. [process_run](https://github.com/tekartik/process_run.dart/blob/master/packages/process_run) - Process run helpers for Linux/Win/Mac and which like feature for finding executables. 56. [mime](https://pub.dev/packages/mime) - Utilities for handling media (MIME) types, including determining a type from
1. [pubspec_parse](https://pub.dev/packages/pubspec_parse) - Simple package for parsing pubspec.yaml files with a type-safe API and rich error reporting. a file extension and file contents.
1. [pub_api_client](https://github.com/leoafarias/pub_api_client) - An API Client for Pub to interact with public package information. 57. [open_file](https://pub.dev/packages/open_file) - A plug-in that can call native APP to open files with string result
1. [xml](https://github.com/renggli/dart-xml) - A lightweight library for parsing, traversing, querying, transforming and building XML documents. in flutter, support iOS(UTI) / android(intent) / PC(ffi) / web(dart:html)
1. [io](https://pub.dev/packages/io) - Utilities for the Dart VM Runtime including support for ANSI colors, file copying, and standard exit code values. 58. [package_info_plus](https://github.com/fluttercommunity/plus_plugins) - Flutter plugin for querying information about
1. [drift_dev](https://drift.simonbinder.eu/) - Dev-dependency for users of drift. Contains the generator and development tools. the application package, such as CFBundleVersion on iOS or versionCode on Android.
1. [auto_route_generator](https://github.com/Milad-Akarie/auto_route_library) - AutoRoute is a declarative routing solution, where everything needed for navigation is automatically generated for you. 59. [palette_generator](https://pub.dev/packages/palette_generator) - Flutter package for generating palette colors from
1. [desktop_webview_window](https://github.com/MixinNetwork/flutter-plugins/tree/main/packages/desktop_webview_window) - Show a webview window on your flutter desktop application. a source image.
1. [disable_battery_optimization](https://github.com/pvsvamsi/Disable-Battery-Optimizations) - Flutter plugin to check and disable battery optimizations. Also shows custom steps to disable the optimizations in devices like mi, xiaomi, samsung, oppo, huawei, oneplus etc 60. [path](https://pub.dev/packages/path) - A string-based path manipulation library. All the path operations you know
1. [draggable_scrollbar](https://github.com/fluttercommunity/flutter-draggable-scrollbar) - A scrollbar that can be dragged for quickly navigation through a vertical list. Additional option is showing label next to scrollthumb with information about current item. and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web.
1. [flutter_broadcasts](https://github.com/KRTirtho/flutter_broadcasts.git) - A plugin for sending and receiving broadcasts with Android intents and iOS notifications. 61. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host
1. [scrobblenaut](https://github.com/Nebulino/Scrobblenaut) - A deadly simple LastFM API Wrapper for Dart. So deadly simple that it's gonna hit the mark. platform file systems, such as the temp and app data directories.
1. [yt_dlp_dart](https://github.com/KRTirtho/yt_dlp_dart.git) - yt-dlp binding in Dart 62. [permission_handler](https://pub.dev/packages/permission_handler) - Permission plugin for Flutter. This plugin
1. [flutter_new_pipe_extractor](https://github.com/KRTirtho/flutter_new_pipe_extractor) - NewPipeExtractor binding for Flutter (Android only) provides a cross-platform (iOS, Android) API to request and check permissions.
63. [piped_client](https://github.com/KRTirtho/piped_client) - API Client for piped.video
64. [riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with
asynchronous code a breeze.
65. [scroll_to_index](https://github.com/quire-io/scroll-to-index) - Scroll to a specific child of any scrollable widget
in Flutter
66. [shadcn_flutter](https://github.com/sunarya-thito/shadcn_flutter) - Beautifully designed components from Shadcn/UI is
now available for Flutter
67. [shared_preferences](https://pub.dev/packages/shared_preferences) - Flutter plugin for reading and writing simple
key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.
68. [shelf](https://pub.dev/packages/shelf) - A model for web server middleware that encourages composition and easy
reuse.
69. [shelf_router](https://pub.dev/packages/shelf_router) - A convenient request router for the shelf web-framework, with
support for URL-parameters, nested routers and routers generated from source annotations.
70. [shelf_web_socket](https://pub.dev/packages/shelf_web_socket) - A shelf handler that wires up a listener for every
connection.
71. [simple_icons](https://teavelopment.com/) - The Simple Icon pack available as Flutter Icons. Provides over 1500 Free
SVG icons for popular brands.
72. [skeletonizer](https://github.com/Milad-Akarie/skeletonizer) - Converts already built widgets into skeleton loaders
with no extra effort.
73. [sliding_up_panel](https://github.com/akshathjain/sliding_up_panel) - A draggable Flutter widget that makes
implementing a SlidingUpPanel much easier!
74. [sliver_tools](https://github.com/Kavantix) - A set of useful sliver tools that are missing from the flutter
framework
75. [smtc_windows](https://pub.dev/packages/smtc_windows) - Windows `SystemMediaTransportControls` implementation for
Flutter giving access to Windows OS Media Control applet.
76. [spotify](https://github.com/rinukkusu/spotify-dart) - An incomplete dart library for interfacing with the Spotify
Web API.
77. [sqlite3](https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3) - Provides lightweight yet convenient bindings
to SQLite by using dart:ffi
78. [sqlite3_flutter_libs](https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3_flutter_libs) - Flutter plugin to
include native sqlite3 libraries with your app
79. [stroke_text](https://github.com/MohamedAbd0/stroke_text) - A Simple Flutter plugin for applying stroke (border)
style to a text widget
80. [system_theme](https://github.com/bdlukaa/system_theme/tree/master/system_theme) - A plugin to get the current system
theme info. Supports Android, Web, Windows, Linux and macOS
81. [test](https://pub.dev/packages/test) - A full featured library for writing and running Dart tests across platforms.
82. [timezone](https://pub.dev/packages/timezone) - Time zone database and time zone aware DateTime.
83. [titlebar_buttons](https://github.com/gtk-flutter/titlebar_buttons) - A package which provides most of the titlebar
buttons from windows, linux and macOS.
84. [tray_manager](https://github.com/leanflutter/tray_manager) - This plugin allows Flutter desktop apps to defines
system tray.
85. [url_launcher](https://pub.dev/packages/url_launcher) - Flutter plugin for launching a URL. Supports web, phone, SMS,
and email schemes.
86. [uuid](https://pub.dev/packages/uuid) - RFC4122 (v1, v4, v5, v6, v7, v8) UUID Generator and Parser for Dart
87. [version](https://github.com/dartninja/version) - Provides a simple class for parsing and comparing semantic versions
as defined by http://semver.org/
88. [very_good_infinite_list](https://github.com/VeryGoodOpenSource/very_good_infinite_list) - A library for easily
displaying paginated data, created by Very Good Ventures. Great for activity feeds, news feeds, and more.
89. [visibility_detector](https://pub.dev/packages/visibility_detector) - A widget that detects the visibility of its
child and notifies a callback.
90. [web_socket_channel](https://pub.dev/packages/web_socket_channel) - StreamChannel wrappers for WebSockets. Provides a
cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying
StreamChannel.
91. [wikipedia_api](https://github.com/KRTirtho/wikipedia_api) - Wikipedia API for dart and flutter
92. [win32_registry](https://pub.dev/packages/win32_registry) - A package that provides a friendly Dart API for accessing
the Windows Registry.
93. [window_manager](https://github.com/leanflutter/window_manager) - This plugin allows Flutter desktop apps to resizing
and repositioning the window.
94. [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) - A port in dart of the youtube explode
library. Supports several API functions without the need of YouTube API Key.
95. [http_parser](https://pub.dev/packages/http_parser) - A platform-independent package for parsing and serializing HTTP
formats.
96. [collection](https://pub.dev/packages/collection) - Collections and utilities functions and classes related to
collections.
97. [otp_util](https://github.com/dushiling) - otp_util is a dart package to generate and verify one-time passwords, it
provides two methods TOPT and HOTP.They are Time-based OTPs and Counter-based OTPs.
98. [dio_http2_adapter](https://github.com/cfug/dio) - An adapter that combines HTTP/2 and dio. Supports reusing
connections, header compression, etc.
99. [build_runner](https://pub.dev/packages/build_runner) - A build system for Dart code generation and modular
compilation.
100. [envied_generator](https://github.com/petercinibulk/envied) - Generator for the Envied package.
See https://pub.dev/packages/envied.
101. [flutter_gen_runner](https://github.com/FlutterGen/flutter_gen) - The Flutter code generator for your assets, fonts,
colors, … — Get rid of all String-based APIs.
102. [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) - A package which simplifies the
task of updating your Flutter app's launcher icon.
103. [flutter_lints](https://pub.dev/packages/flutter_lints) - Recommended lints for Flutter apps, packages, and plugins
to encourage good coding practices.
104. [json_serializable](https://pub.dev/packages/json_serializable) - Automatically generate code for converting to and
from JSON by annotating Dart classes.
105. [freezed](https://pub.dev/packages/freezed) - Code generation for immutable classes that has a simple syntax/API
without compromising on the features.
106. [process_run](https://github.com/tekartik/process_run.dart/blob/master/packages/process_run) - Process run helpers
for Linux/Win/Mac and which like feature for finding executables.
107. [pubspec_parse](https://pub.dev/packages/pubspec_parse) - Simple package for parsing pubspec.yaml files with a
type-safe API and rich error reporting.
108. [pub_api_client](https://github.com/leoafarias/pub_api_client) - An API Client for Pub to interact with public
package information.
109. [xml](https://github.com/renggli/dart-xml) - A lightweight library for parsing, traversing, querying, transforming
and building XML documents.
110. [io](https://pub.dev/packages/io) - Utilities for the Dart VM Runtime including support for ANSI colors, file
copying, and standard exit code values.
111. [drift_dev](https://drift.simonbinder.eu/) - Dev-dependency for users of drift. Contains the generator and
development tools.
112. [auto_route_generator](https://github.com/Milad-Akarie/auto_route_library) - AutoRoute is a declarative routing
solution, where everything needed for navigation is automatically generated for you.
113. [desktop_webview_window](https://github.com/MixinNetwork/flutter-plugins/tree/main/packages/desktop_webview_window) -
Show a webview window on your flutter desktop application.
114. [disable_battery_optimization](https://github.com/pvsvamsi/Disable-Battery-Optimizations) - Flutter plugin to check
and disable battery optimizations. Also shows custom steps to disable the optimizations in devices like me, xiaomi,
samsung, oppo, huawei, oneplus etc
115. [draggable_scrollbar](https://github.com/fluttercommunity/flutter-draggable-scrollbar) - A scrollbar that can be
dragged for quickly navigation through a vertical list. Additional option is showing label next to scrollthumb with
information about current item.
116. [flutter_broadcasts](https://github.com/KRTirtho/flutter_broadcasts.git) - A plugin for sending and receiving
broadcasts with Android intents and iOS notifications.
117. [scrobblenaut](https://github.com/Nebulino/Scrobblenaut) - A deadly simple LastFM API Wrapper for Dart. So deadly
simple that it's going to hit the mark.
118. [yt_dlp_dart](https://github.com/KRTirtho/yt_dlp_dart.git) - yt-dlp binding in Dart
119. [flutter_new_pipe_extractor](https://github.com/KRTirtho/flutter_new_pipe_extractor) - NewPipeExtractor binding for
Flutter (Android only)
</details> </details>
<div align="center"><h4>© Copyright Spotube 2024</h4></div> <div align="center"><h4>© Copyright Spotube 2025</h4></div>

3
android/.gitignore vendored
View File

@ -5,9 +5,10 @@ gradle-wrapper.jar
/gradlew.bat /gradlew.bat
/local.properties /local.properties
GeneratedPluginRegistrant.java GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore. # Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app # See https://flutter.dev/to/reference-keystore
key.properties key.properties
**/*.keystore **/*.keystore
**/*.jks **/*.jks

View File

@ -1,139 +0,0 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
def composeVersion = "1.4.8"
android {
namespace "oss.krtirtho.spotube"
compileSdkVersion 35
ndkVersion = "27.0.12077973"
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion "$composeVersion" // Correlates with org.jetbrains.kotlin.android plugin in settings.gradle
}
defaultConfig {
applicationId "oss.krtirtho.spotube"
minSdkVersion 24
targetSdkVersion 35
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.release
}
}
flavorDimensions "default"
productFlavors {
nightly {
dimension "default"
resValue "string", "app_name_en", "Spotube Nightly"
applicationIdSuffix ".nightly"
versionNameSuffix "-nightly"
signingConfig signingConfigs.release
}
dev {
dimension "default"
resValue "string", "app_name_en", "Spotube Dev"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
signingConfig signingConfigs.release
}
stable {
dimension "default"
resValue "string", "app_name_en", "Spotube"
signingConfig signingConfigs.release
}
}
packagingOptions {
resources.excludes += "DebugProbesKt.bin"
}
}
flutter {
source '../..'
}
def glanceVersion = "1.1.1"
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
// other deps so just ignore
implementation 'com.android.support:multidex:2.0.1'
implementation "androidx.glance:glance-appwidget:$glanceVersion"
implementation "androidx.glance:glance-appwidget-preview:$glanceVersion"
implementation "androidx.glance:glance-preview:$glanceVersion"
implementation "androidx.glance:glance-material3:$glanceVersion"
implementation "androidx.glance:glance-material:$glanceVersion"
implementation "androidx.work:work-runtime-ktx:2.8.1"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"
implementation 'com.google.code.gson:gson:2.11.0'
}

View File

@ -0,0 +1,44 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "oss.krtirtho.spotube"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "oss.krtirtho.spotube"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View File

@ -1,21 +0,0 @@
-keep class androidx.lifecycle.DefaultLifecycleObserver
-keepnames class kotlinx.serialization.** { *; }
-keepnames class oss.krtirtho.spotube.glance.models.** { *; }
-keep @kotlinx.serialization.Serializable class *
-keepclassmembers class ** {
@kotlinx.serialization.* <fields>;
}
## We don't need beans
-dontwarn java.beans.BeanDescriptor
-dontwarn java.beans.BeanInfo
-dontwarn java.beans.IntrospectionException
-dontwarn java.beans.Introspector
-dontwarn java.beans.PropertyDescriptor
## Rules for NewPipeExtractor
-keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; }
-keep class org.mozilla.javascript.** { *; }
-keep class org.mozilla.classfile.ClassFileWriter
-dontwarn org.mozilla.javascript.tools.**

View File

@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Flutter needs it to communicate with the running application <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET"/>
</manifest> </manifest>

View File

@ -1,141 +1,45 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="spotube"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2"/>
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
<uses-permission android:name="android.permission.INTERNET" /> In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<uses-permission android:name="android.permission.WAKE_LOCK" /> <queries>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <intent>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <action android:name="android.intent.action.PROCESS_TEXT"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <data android:mimeType="text/plain"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> </intent>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> </queries>
</manifest>
<queries>
<!-- If your app opens https URLs -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
</queries>
<application
android:name="${applicationName}"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name_en"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true">
<!-- Enable Impeller -->
<!-- <meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" /> -->
<activity
android:name="com.ryanheise.audioservice.AudioServiceActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleInstance"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize">
<!--
Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI.
-->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="open.spotify.com"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "spotify:// -->
<data android:scheme="spotify" />
<data android:scheme="spotube" />
</intent-filter>
<intent-filter>
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
</intent-filter>
</activity>
<!-- AudioService Config -->
<service
android:name="com.ryanheise.audioservice.AudioService"
android:exported="true"
android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<receiver
android:name="com.ryanheise.audioservice.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<!-- =================== -->
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
<!-- Home Widget config -->
<receiver
android:name=".glance.HomePlayerWidgetReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/home_player_widget_config" />
</receiver>
<receiver
android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"
android:exported="true">
<intent-filter>
<action android:name="es.antonborri.home_widget.action.BACKGROUND" />
</intent-filter>
</receiver>
<service
android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- =================== -->
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

View File

@ -1,25 +0,0 @@
// Generated file.
//
// If you wish to remove Flutter's multidex support, delete this entire file.
//
// Modifications to this file should be done in a copy under a different name
// as this file may be regenerated.
package io.flutter.app;
import android.app.Application;
import android.content.Context;
import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex;
/**
* Extension of {@link android.app.Application}, adding multidex support.
*/
public class FlutterMultiDexApplication extends Application {
@Override
@CallSuper
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

View File

@ -2,5 +2,4 @@ package oss.krtirtho.spotube
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() { class MainActivity : FlutterActivity()
}

View File

@ -1,207 +0,0 @@
package oss.krtirtho.spotube.glance
import HomeWidgetGlanceState
import HomeWidgetGlanceStateDefinition
import android.R
import android.content.Context
import android.graphics.drawable.Icon
import android.net.Uri
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.LocalSize
import androidx.glance.action.ActionParameters
import androidx.glance.action.actionParametersOf
import androidx.glance.action.clickable
import androidx.glance.background
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.SizeMode
import androidx.glance.appwidget.action.ActionCallback
import androidx.glance.appwidget.action.actionRunCallback
import androidx.glance.appwidget.background
import androidx.glance.appwidget.components.CircleIconButton
import androidx.glance.appwidget.components.Scaffold
import androidx.glance.appwidget.cornerRadius
import androidx.glance.appwidget.provideContent
import androidx.glance.background
import androidx.glance.currentState
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.Column
import androidx.glance.layout.ContentScale
import androidx.glance.layout.Row
import androidx.glance.layout.Spacer
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.layout.size
import androidx.glance.preview.ExperimentalGlancePreviewApi
import androidx.glance.preview.Preview
import androidx.glance.state.GlanceStateDefinition
import com.google.gson.Gson
import es.antonborri.home_widget.HomeWidgetBackgroundIntent
import es.antonborri.home_widget.actionStartActivity
import oss.krtirtho.spotube.MainActivity
import oss.krtirtho.spotube.glance.models.Track
import oss.krtirtho.spotube.glance.widgets.FlutterAssetImageProvider
import oss.krtirtho.spotube.glance.widgets.TrackDetailsView
import oss.krtirtho.spotube.glance.widgets.TrackProgress
val gson = Gson()
val serverAddressKey = ActionParameters.Key<String>("serverAddress")
class Breakpoints {
companion object {
val SMALL_SQUARE = DpSize(100.dp, 100.dp)
val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
val BIG_SQUARE = DpSize(250.dp, 250.dp)
}
}
class HomePlayerWidget : GlanceAppWidget() {
override val sizeMode = SizeMode.Responsive(
setOf(
Breakpoints.SMALL_SQUARE,
Breakpoints.HORIZONTAL_RECTANGLE,
Breakpoints.BIG_SQUARE
)
)
override val stateDefinition: GlanceStateDefinition<*>?
get() = HomeWidgetGlanceStateDefinition()
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
GlanceContent(context, currentState())
}
}
@OptIn(ExperimentalGlancePreviewApi::class)
@Preview(widthDp = 100, heightDp = 100)
@Composable
private fun GlanceContent(context: Context, currentState: HomeWidgetGlanceState) {
val prefs = currentState.preferences
val size = LocalSize.current
val activeTrackStr = prefs.getString("activeTrack", null)
val isPlaying = prefs.getBoolean("isPlaying", false)
val playbackServerAddress = prefs.getString("playbackServerAddress", null) ?: ""
var activeTrack: Track? = null
if (activeTrackStr != null) {
activeTrack = gson.fromJson(activeTrackStr, Track::class.java)
}
val playIcon = Icon.createWithResource(context, R.drawable.ic_media_play);
val pauseIcon = Icon.createWithResource(context, R.drawable.ic_media_pause);
val previousIcon = Icon.createWithResource(context, R.drawable.ic_media_previous);
val nextIcon = Icon.createWithResource(context, R.drawable.ic_media_next);
GlanceTheme {
Box(
modifier = GlanceModifier
.fillMaxSize()
.cornerRadius(8.dp)
.background(
color = GlanceTheme.colors.surface.getColor(context)
)
.clickable {
actionStartActivity<MainActivity>(context)
}
,
) {
Box(
modifier = GlanceModifier
.background(
color =
GlanceTheme.colors.surface.getColor(context)
.copy(alpha = 0.5f),
)
.fillMaxSize(),
) {}
Column(
modifier = GlanceModifier.padding(top = 10.dp, start = 10.dp, end = 10.dp)
) {
Row(verticalAlignment = Alignment.Vertical.CenterVertically) {
TrackDetailsView(activeTrack)
}
Spacer(modifier = GlanceModifier.size(6.dp))
if (size != Breakpoints.SMALL_SQUARE) {
TrackProgress(prefs)
}
Spacer(modifier = GlanceModifier.size(6.dp))
Row(
modifier = GlanceModifier.fillMaxWidth(),
horizontalAlignment = Alignment.Horizontal.CenterHorizontally
) {
CircleIconButton(
imageProvider = ImageProvider(previousIcon),
contentDescription = "Previous",
onClick = actionRunCallback<PreviousAction>(
parameters = actionParametersOf(serverAddressKey to playbackServerAddress)
)
)
Spacer(modifier = GlanceModifier.size(6.dp))
CircleIconButton(
imageProvider =
if (isPlaying) ImageProvider(pauseIcon)
else ImageProvider(playIcon),
contentDescription = "Play/Pause",
onClick = actionRunCallback<PlayPauseAction>(
parameters = actionParametersOf(serverAddressKey to playbackServerAddress)
)
)
Spacer(modifier = GlanceModifier.size(6.dp))
CircleIconButton(
imageProvider = ImageProvider(nextIcon),
contentDescription = "Previous",
onClick = actionRunCallback<NextAction>(
parameters = actionParametersOf(
serverAddressKey to playbackServerAddress
)
)
)
}
}
}
}
}
}
class PlayPauseAction : InteractiveAction("toggle-playback")
class NextAction : InteractiveAction("next")
class PreviousAction : InteractiveAction("previous")
abstract class InteractiveAction(val command: String) : ActionCallback {
override suspend fun onAction(
context: Context,
glanceId: GlanceId,
parameters: ActionParameters
) {
val serverAddress = parameters[serverAddressKey] ?: ""
Log.d("HomePlayerWidget", "Sending command $command to $serverAddress")
if (serverAddress == null || serverAddress.isEmpty()) {
return
}
val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(
context,
Uri.parse("spotube://playback/$command?serverAddress=$serverAddress")
)
backgroundIntent.send()
}
}

View File

@ -1,7 +0,0 @@
package oss.krtirtho.spotube.glance
import HomeWidgetGlanceWidgetReceiver
class HomePlayerWidgetReceiver : HomeWidgetGlanceWidgetReceiver<HomePlayerWidget>() {
override val glanceAppWidget = HomePlayerWidget()
}

View File

@ -1,40 +0,0 @@
package oss.krtirtho.spotube.glance.models
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable
@Serializable
data class AlbumSimple(
@SerializedName("album_type")
val albumType: AlbumType?,
@SerializedName("available_markets")
val availableMarkets: List<Market>?,
val href: String?,
val id: String?,
val images: List<Image>?,
val name: String?,
@SerializedName("release_date")
val releaseDate: String?,
@SerializedName("release_date_precision")
val releaseDatePrecision: DatePrecision?,
val type: String?,
val uri: String?,
)
@Serializable
enum class AlbumType {
album,
single,
compilation
}
enum class DatePrecision {
year,
month,
day
}

View File

@ -1,25 +0,0 @@
package oss.krtirtho.spotube.glance.models
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable
@Serializable
data class Artist(
val href: String?,
val id: String?,
val name: String?,
val type: String?,
val uri: String?,
val followers: Followers?,
val genres: List<String>?,
val images: List<Image>?,
@SerializedName("popularity")
val popularity: Int?
)
@Serializable
data class Followers(
val total: Int?
)

View File

@ -1,10 +0,0 @@
package oss.krtirtho.spotube.glance.models
import kotlinx.serialization.Serializable
@Serializable
data class Image(
val height: Int?,
val width: Int?,
val path: String,
)

View File

@ -1,37 +0,0 @@
package oss.krtirtho.spotube.glance.models
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable
import kotlin.time.Duration.Companion.milliseconds
@Serializable
data class Track(
val album: AlbumSimple?, val artists: List<Artist>?,
@SerializedName("available_markets") val availableMarkets: List<Market>?,
@SerializedName("disc_number") val discNumber: Int?,
@SerializedName("duration_ms") val durationMs: Int,
val explicit: Boolean?, val href: String?, val id: String?,
@SerializedName("is_playable") val isPlayable: Boolean?,
val name: String?,
@SerializedName("popularity") val popularity: Int?,
@SerializedName("preview_url") val previewUrl: String?,
@SerializedName("track_number") val trackNumber: Int?,
val type: String?, val uri: String?
) {
val duration: kotlin.time.Duration
get() = durationMs.toLong().milliseconds
}
enum class Market {
AD, AE, AF, AG, AI, AL, AM, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BL, BM, BN, BO, BQ, BR, BS, BT, BV, BW, BY, BZ, CA, CC, CD, CF, CG, CH, CI, CK, CL, CM, CN, CO, CR, CU, CV, CW, CX, CY, CZ, DE, DJ, DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, ET, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, IO, IQ, IR, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KP, KR, KW, KY, KZ, LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY, MA, MC, MD, ME, MF, MG, MH, MK, ML, MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NI, NL, NO, NP, NR, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PS, PT, PW, PY, QA, RE, RO, RS, RU, RW, SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SR, SS, ST, SV, SX, SY, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, UM, US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, XK, YE, YT, ZA, ZM, ZW,
}

View File

@ -1,14 +0,0 @@
package oss.krtirtho.spotube.glance.widgets
import android.graphics.BitmapFactory
import android.util.Base64
import androidx.glance.ImageProvider
@Suppress("FunctionName")
fun Base64ImageProvider(base64: String): ImageProvider {
var bytes = Base64.decode(base64, Base64.DEFAULT);
var bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size);
return ImageProvider(bitmap)
}

View File

@ -1,14 +0,0 @@
package oss.krtirtho.spotube.glance.widgets
import android.content.Context
import android.graphics.BitmapFactory
import androidx.glance.ImageProvider
@Suppress("FunctionName")
fun FlutterAssetImageProvider(context: Context, path: String): ImageProvider {
var inputStream = context.assets.open("flutter_assets/$path")
return ImageProvider(
BitmapFactory.decodeStream(inputStream)
)
}

View File

@ -1,78 +0,0 @@
package oss.krtirtho.spotube.glance.widgets
import android.graphics.BitmapFactory
import android.net.Uri
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.LocalContext
import androidx.glance.LocalSize
import androidx.glance.appwidget.cornerRadius
import androidx.glance.layout.Alignment
import androidx.glance.layout.Row
import androidx.glance.layout.Column
import androidx.glance.layout.ContentScale
import androidx.glance.layout.Spacer
import androidx.glance.layout.size
import androidx.glance.text.FontWeight
import androidx.glance.text.Text
import androidx.glance.text.TextStyle
import oss.krtirtho.spotube.glance.Breakpoints
import oss.krtirtho.spotube.glance.models.Track
@Composable
fun TrackDetailsView(activeTrack: Track?) {
val context = LocalContext.current
val size = LocalSize.current
val artistStr = activeTrack?.artists?.map { it.name }?.joinToString(", ") ?: "<No Artist>"
val imgLocalPath = activeTrack?.album?.images?.get(0)?.path;
val title = activeTrack?.name ?: "<No Track>"
Image(
provider =
if (imgLocalPath == null)
ImageProvider(
BitmapFactory.decodeResource(
context.resources,
android.R.drawable.ic_delete
)
)
else ImageProvider(BitmapFactory.decodeFile(imgLocalPath)),
contentDescription = "Album Art",
modifier = GlanceModifier.cornerRadius(8.dp)
.size(
if (size.height < 200.dp) 50.dp
else 100.dp
),
contentScale = ContentScale.Fit
)
Spacer(modifier = GlanceModifier.size(6.dp))
Column {
Text(
text = title,
style = TextStyle(
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = GlanceTheme.colors.onBackground
),
)
if (size != Breakpoints.SMALL_SQUARE) {
Spacer(modifier = GlanceModifier.size(6.dp))
Text(
text = artistStr,
style = TextStyle(
fontSize = 14.sp,
color = GlanceTheme.colors.onBackground
),
)
}
}
}

View File

@ -1,77 +0,0 @@
package oss.krtirtho.spotube.glance.widgets
import android.content.SharedPreferences
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.LocalSize
import androidx.glance.appwidget.LinearProgressIndicator
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.layout.Spacer
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.size
import androidx.glance.text.Text
import androidx.glance.text.TextStyle
import kotlin.math.max
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import oss.krtirtho.spotube.glance.Breakpoints
fun Duration.format(): String {
return this.toComponents { hour, minutes, seconds, nanoseconds ->
var paddedSeconds = seconds.toString().padStart(2, '0')
var paddedMinutes = minutes.toString().padStart(2, '0')
var paddedHour = hour.toString().padStart(2, '0')
if (hour == 0L) {
"$paddedMinutes:$paddedSeconds"
} else {
"$paddedHour:$paddedMinutes:$paddedSeconds"
}
}
}
@Composable
fun TrackProgress(prefs: SharedPreferences) {
val size = LocalSize.current
val position = prefs.getInt("position", 0).seconds
var duration = prefs.getInt("duration", 0).seconds
var progress = position.inWholeSeconds.toFloat() / max(duration.inWholeSeconds.toFloat(), 1.0f)
var textStyle =
TextStyle(
color = GlanceTheme.colors.onBackground,
)
if (size == Breakpoints.HORIZONTAL_RECTANGLE) {
Row(modifier = GlanceModifier.fillMaxWidth()) {
Text(text = position.format(), style = textStyle)
Spacer(modifier = GlanceModifier.size(6.dp))
LinearProgressIndicator(
progress = progress,
modifier = GlanceModifier.defaultWeight(),
color = GlanceTheme.colors.primary,
backgroundColor = GlanceTheme.colors.primaryContainer,
)
Spacer(modifier = GlanceModifier.size(6.dp))
Text(text = duration.format(), style = textStyle)
}
} else {
Column(modifier = GlanceModifier.fillMaxWidth()) {
LinearProgressIndicator(
progress = progress,
modifier = GlanceModifier.fillMaxWidth(),
color = GlanceTheme.colors.primary,
backgroundColor = GlanceTheme.colors.primaryContainer,
)
Spacer(modifier = GlanceModifier.size(6.dp))
Row(modifier = GlanceModifier.fillMaxWidth()) {
Text(text = position.format(), style = textStyle)
Spacer(modifier = GlanceModifier.defaultWeight())
Text(text = duration.format(), style = textStyle)
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item> <item android:drawable="?android:colorBackground"/>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item> <!-- You can insert your own image assets here -->
<item> <!-- <item>
<bitmap android:gravity="center" android:src="@drawable/splash"/> <bitmap
</item> android:gravity="center"
<item> android:src="@mipmap/launch_image" />
<bitmap android:gravity="bottom" android:src="@drawable/branding"/> </item> -->
</item>
</layer-list> </layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

View File

@ -1,27 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="762"
android:viewportHeight="762">
<path
android:pathData="M309.08,370.99L309.08,479.87C309.08,486.36 314.33,491.6 320.83,491.6C327.31,491.6 332.58,486.36 332.58,479.87L332.58,370.99C332.58,364.51 327.31,359.26 320.83,359.26C314.33,359.26 309.08,364.51 309.08,370.99Z"
android:strokeLineJoin="miter"
android:strokeWidth="14"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="M254.59,491.73L280.46,491.73L280.46,362.47C280.53,361.85 280.64,361.23 280.64,360.6C280.64,304.83 325.72,259.46 381.12,259.46C436.51,259.46 481.59,304.83 481.59,360.6C481.59,361.45 481.71,362.27 481.84,363.1L481.84,491.73L507.71,491.73C525.72,491.73 540.33,476.65 540.33,458.03L540.33,390.62C540.33,375.26 530.37,362.33 516.78,358.26C515.53,284.17 455.17,224.26 381.12,224.26C307.05,224.26 246.69,284.18 245.45,358.29C231.88,362.36 221.96,375.29 221.96,390.63L221.96,458.03C221.96,476.64 236.56,491.73 254.59,491.73Z"
android:strokeLineJoin="miter"
android:strokeWidth="20"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="M431.08,370.99L431.08,479.87C431.08,486.36 436.33,491.6 442.83,491.6C449.31,491.6 454.58,486.36 454.58,479.87L454.58,370.99C454.58,364.51 449.31,359.26 442.83,359.26C436.33,359.26 431.08,364.51 431.08,370.99Z"
android:strokeLineJoin="miter"
android:strokeWidth="14"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
</vector>

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item> <item android:drawable="@android:color/white"/>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item> <!-- You can insert your own image assets here -->
<item> <!-- <item>
<bitmap android:gravity="center" android:src="@drawable/splash"/> <bitmap
</item> android:gravity="center"
<item> android:src="@mipmap/launch_image" />
<bitmap android:gravity="bottom" android:src="@drawable/branding"/> </item> -->
</item>
</layer-list> </layer-list>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#000000</item>
<item name="android:windowSplashScreenBrandingImage">@drawable/android12branding</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
<item name="android:windowSplashScreenIconBackgroundColor">#000000</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -3,12 +3,8 @@
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your This theme determines the color of the Android Window while your

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#000000</item>
<item name="android:windowSplashScreenBrandingImage">@drawable/android12branding</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
<item name="android:windowSplashScreenIconBackgroundColor">#000000</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#242832</color>
</resources>

View File

@ -3,12 +3,8 @@
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your This theme determines the color of the Android Window while your

View File

@ -1,3 +0,0 @@
<automotiveApp>
<uses name="media" />
</automotiveApp>

View File

@ -1,7 +0,0 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout"
android:minWidth="100dp"
android:minHeight="100dp"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="10000">
</appwidget-provider>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Some files were not shown because too many files have changed in this diff Show More