reupload after migration

This commit is contained in:
ITmodulo 2023-03-19 02:20:36 +00:00
parent 9478f29c29
commit 5639101bac
22 changed files with 3381 additions and 7 deletions

17
.gitignore vendored
View File

@ -1,13 +1,15 @@
# ---> Go
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
Sonically
*Sonically
Sonically*
*Sonically.debug
Sonically.debug*
# Test binary, built with `go test -c`
*.test
@ -18,6 +20,11 @@
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
# Personal data dir dynamicly created by App
.Sonically/**
.Sonically
# Build Environment Test and Backup Dir
build_environment/backup
build_environment/test

View File

@ -0,0 +1,38 @@
platform: linux/arm64
pipeline:
build:
image: golang:alpine
when:
event: tag
environment:
GOOS: linux
GOARCH: arm64
CGO_ENABLED: "1"
commands:
- "apk -U upgrade"
- "apk add \
protobuf-dev \
musl-dev \
protoc \
build-base \
pkgconfig \
gtk4.0-dev \
glib-dev \
gdk-pixbuf-dev \
opusfile-dev \
libnotify-dev \
portaudio-dev \
gobject-introspection-dev"
- "go build -tags netgo -o sonically_linux_musl-${CI_COMMIT_TAG##v}~aarch64"
- "sha512sum sonically_linux_musl-${CI_COMMIT_TAG##v}~aarch64 > sonically_linux_musl-${CI_COMMIT_TAG##v}~aarch64-sha512.sum"
- "sha256sum sonically_linux_musl-${CI_COMMIT_TAG##v}~aarch64 > sonically_linux_musl-${CI_COMMIT_TAG##v}~aarch64-sha256.sum"
- "md5sum sonically_linux_musl-${CI_COMMIT_TAG##v}~aarch64 > sonically_linux_musl-${CI_COMMIT_TAG##v}~aarch64-md5.sum"
publish:
image: plugins/gitea-release
settings:
base_url: https://git.itmodulo.eu
api_key:
from_secret: gitea_akey
files: sonically_linux_musl*
when:
event: tag

View File

@ -0,0 +1,40 @@
platform: linux/amd64
pipeline:
build:
image: debian:bookworm
when:
event: tag
environment:
GOOS: linux
GOARCH: amd64
CGO_ENABLED: "1"
PATH: /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/go/bin
commands:
- "apt-get update && apt-get upgrade -y && apt-get install wget git -y"
- "wget -q https://go.dev/dl/go1.18.3.linux-amd64.tar.gz && tar -zxf go1.18.3.linux-amd64.tar.gz -C /usr/local/ && go version"
- "apt-get install -y \
build-essential \
protobuf-compiler \
gcc \
upx \
pkg-config \
libgtk-4-dev \
libglib2.0-dev \
libopusfile-dev \
libnotify-dev \
libportaudio2 \
portaudio19-dev \
libgraphene-1.0-dev"
- "go build -tags netgo -o sonically_linux_glibc-${CI_COMMIT_TAG##v}~x86_64"
- "sha512sum sonically_linux_glibc-${CI_COMMIT_TAG##v}~x86_64 > sonically_linux_glibc-${CI_COMMIT_TAG##v}~x86_64-sha512.sum"
- "sha256sum sonically_linux_glibc-${CI_COMMIT_TAG##v}~x86_64 > sonically_linux_glibc-${CI_COMMIT_TAG##v}~x86_64-sha256.sum"
- "md5sum sonically_linux_glibc-${CI_COMMIT_TAG##v}~x86_64 > sonically_linux_glibc-${CI_COMMIT_TAG##v}~x86_64-md5.sum"
publish:
image: plugins/gitea-release
settings:
base_url: https://git.itmodulo.eu
api_key:
from_secret: gitea_akey
files: sonically_linux_glibc*
when:
event: tag

View File

@ -0,0 +1,38 @@
platform: linux/amd64
pipeline:
build:
image: golang:alpine
when:
event: tag
environment:
GOOS: linux
GOARCH: amd64
CGO_ENABLED: "1"
commands:
- "apk -U upgrade"
- "apk add \
protobuf-dev \
musl-dev \
protoc \
build-base \
pkgconfig \
gtk4.0-dev \
glib-dev \
gdk-pixbuf-dev \
opusfile-dev \
libnotify-dev \
portaudio-dev \
gobject-introspection-dev"
- "go build -tags netgo -o sonically_linux_musl-${CI_COMMIT_TAG##v}~x86_64"
- "sha512sum sonically_linux_musl-${CI_COMMIT_TAG##v}~x86_64 > sonically_linux_musl-${CI_COMMIT_TAG##v}~x86_64-sha512.sum"
- "sha256sum sonically_linux_musl-${CI_COMMIT_TAG##v}~x86_64 > sonically_linux_musl-${CI_COMMIT_TAG##v}~x86_64-sha256.sum"
- "md5sum sonically_linux_musl-${CI_COMMIT_TAG##v}~x86_64 > sonically_linux_musl-${CI_COMMIT_TAG##v}~x86_64-md5.sum"
publish:
image: plugins/gitea-release
settings:
base_url: https://git.itmodulo.eu
api_key:
from_secret: gitea_akey
files: sonically_linux_musl*
when:
event: tag

View File

@ -0,0 +1,40 @@
platform: linux/arm64
pipeline:
build:
image: debian:bookworm
when:
event: tag
environment:
GOOS: linux
GOARCH: arm64
CGO_ENABLED: "1"
PATH: /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/go/bin
commands:
- "apt-get update && apt-get upgrade -y && apt-get install wget git -y"
- "wget -q https://go.dev/dl/go1.18.3.linux-arm64.tar.gz && tar -zxf go1.18.3.linux-arm64.tar.gz -C /usr/local/ && go version"
- "apt-get install -y \
build-essential \
protobuf-compiler \
gcc \
upx \
pkg-config \
libgtk-4-dev \
libglib2.0-dev \
libopusfile-dev \
libnotify-dev \
libportaudio2 \
portaudio19-dev \
libgraphene-1.0-dev"
- "go build -tags netgo -o sonically_linux_glibc-${CI_COMMIT_TAG##v}~aarch64"
- "sha512sum sonically_linux_glibc-${CI_COMMIT_TAG##v}~aarch64 > sonically_linux_glibc-${CI_COMMIT_TAG##v}~aarch64-sha512.sum"
- "sha256sum sonically_linux_glibc-${CI_COMMIT_TAG##v}~aarch64 > sonically_linux_glibc-${CI_COMMIT_TAG##v}~aarch64-sha256.sum"
- "md5sum sonically_linux_glibc-${CI_COMMIT_TAG##v}~aarch64 > sonically_linux_glibc-${CI_COMMIT_TAG##v}~aarch64-md5.sum"
publish:
image: plugins/gitea-release
settings:
base_url: https://git.itmodulo.eu
api_key:
from_secret: gitea_akey
files: sonically_linux_glibc*
when:
event: tag

View File

@ -1,3 +1,29 @@
# Sonically
![Sonically logo](https://static.itmodulo.eu/files/l/sonically.svg)
GUI native Subsonic API client optimized for mobile outdoor usage on *nix platforms like pmOS, Mobian.
# Sonically [BETA]
## Status
***!!! SUSPENDED !!!***
I was forced to go back to Android, Sonically is not priority there.
I'm looking forwared to switch to pmOS again, I'll probably do so in the mid of 2023 and development will restart ;)
## Info
1. **Priority**: GTK4 is cool but not ideal, especially in go. I'll switch to something else. Probably native (for go) Fyne UI Toolkit. This should unlock seeking.
2. **Priority**: Clean code
3. Proxy settings, Lyrics self-fetching will be removed. This is non-goal now. You self-host you trust your server, you trust this app as it **should** connect only to this server. If you want more goodies, use advanced server implementation.
4. Since upcoming fix [*read important below]* I'll start using branches, at least 2, master and develop.
5. Packaging probably own repo.
## Installation
I lost somwhere working all binaries from 2022. Forgive me that.
Please compile yourself for now.
**Important**. First commit on this repo probably won't compile as it depends on LyricsApiGoExtneded that I don't longer care, also fscache may be broken. I'll try to fix that in the meantime.
**Hint** You may look into APKBUILD if you use pmOS, it should contain reciepe for building apkand
## Configuration
Ensure you have keyring named login. If no create it using e.g. seahorse.
Recommended settings are opus 128, buffer 4096 (probably only working, as some values may be hardcoded)

29
README.md.backup Normal file
View File

@ -0,0 +1,29 @@
![Sonically logo](https://static.itmodulo.eu/files/l/sonically.svg)
# Sonically [BETA]
## Status
***!!! SUSPENDED !!!***
I was forced to go back to Android, Sonically is not priority there.
I'm looking forwared to switch to pmOS again, I'll probably do so in the mid of 2023 and development will restart ;)
## Info
1. **Priority**: GTK4 is cool but not ideal, especially in go. I'll switch to something else. Probably native (for go) Fyne UI Toolkit. This should unlock seeking.
2. **Priority**: Clean code
3. Proxy settings, Lyrics self-fetching will be removed. This is non-goal now. You self-host you trust your server, you trust this app as it **should** connect only to this server. If you want more goodies, use advanced server implementation.
4. Since upcoming fix [*read important below]* I'll start using branches, at least 2, master and develop.
5. Packaging probably own repo.
## Installation
I lost somwhere working all binaries from 2022. Forgive me that.
Please compile yourself for now.
**Important**. First commit on this repo probably won't compile as it depends on LyricsApiGoExtneded that I don't longer care, also fscache may be broken. I'll try to fix that in the meantime.
**Hint** You may look into APKBUILD if you use pmOS, it should contain reciepe for building apkand
## Configuration
Ensure you have keyring named login. If no create it using e.g. seahorse.
Recommended settings are opus 128, buffer 4096 (probably only working, as some values may be hardcoded)

381
audio_player.go Normal file
View File

@ -0,0 +1,381 @@
package main
import (
"errors"
"fmt"
"io"
"os"
"os/signal"
"runtime"
"time"
// "math"
"strconv"
"git.itmodulo.eu/LibrariesGo/lyrics-api-go-extended"
"github.com/TheCreeper/go-notify"
// "github.com/disintegration/imaging"
"github.com/diamondburned/gotk4/pkg/core/glib"
// "github.com/djherbis/fscache"
"github.com/gordonklaus/portaudio"
// "github.com/diamondburned/gotk4/pkg/gdk/v4"
// "github.com/delucks/go-subsonic"
"github.com/hraban/opus"
)
const rate float64 = 48000
const channels uint8 = 2
var PlayAudio bool = true // Used for play pause
var EndPlayer bool = false // Used for ending recursion
var StreamChanged bool = false
func PlayPort() {
nodeID := MainQueue[NowPlayingIndex]
songdata, _ := CurrentClient.GetSong(nodeID)
albmdata, _ := CurrentClient.GetAlbum(songdata.AlbumID)
// go glib.IdleAdd(FindSubtitles(songdata.Artist, songdata.Title))
TotalTime = songdata.Duration
// Async Gui update needed by GTK
var SetPlayingGuiData = func() {
MainArtistLabel.SetLabel(songdata.Artist)
MainSongTitleLabel.SetLabel(songdata.Title)
MainAlbumLabel.SetLabel(songdata.Album)
MainTotalTimeLabel.SetLabel(DurationToReadable(songdata.Duration))
DownloadCoverArtFullSize(albmdata.CoverArt)
var imgpath string = GetRunDir() + MainDir + DataDir + "/" + albmdata.CoverArt + ".jpg"
MainAlbumCover.SetFromFile(imgpath)
// path2 := os.UserHomeDir + MainDir + DataDir + "/" + albmdata.CoverArt + "-b.jpg"
// blu, err := os.Open(imgpath)
// if err != nil {
// LogOnError(err)
// }
// defer blu.Close()
// img, _, err := image.Decode(blu)
// if err != nil {
// LogOnError(err)
// }
// dstImage := imaging.Blur(img, MainSettings.BlurRadius)
// err = imaging.Save(dstImage, path2)
// if err != nil {
// LogOnError(err)
// }
// AD1
// MainAlbumCover.SetFromPixbuf(pixbuf)
MainPlayPauseButton.SetLabel("❚❚")
}
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, os.Kill)
// param := map[string]string{
// "maxBitRate": strconv.Itoa(int(MainSettings.Bitrate)),
// "MainFormat": MainSettings.Codec,
// "transcodings": MainSettings.Codec,
// "estimateContentLength": "true",
// }
portaudio.Initialize()
defer portaudio.Terminate()
// create the cache, keys expire after 1 hour.
// var ReadMaster fscache.ReadAtCloser
// var WriteMaster io.WriteCloser
// IsCached := CurrentCache.Exists(nodeID)
ReadMaster, _, _ = CurrentCache.Get(nodeID)
// if !IsCached {
// reader, _ := CurrentClient.Stream(nodeID, param)
// go Backgroundread(reader, WriteMaster)
// } else {
// fmt.Println("Playing ", songdata.Artist, " - ", songdata.Title, " from cache")
// }
// Writing needs to be implemented in diffrenet place
// Here we use only reader
//AD2
OpusStr, err := opus.NewStream(ReadMaster)
chk(err)
result := <-AudioControlChan
fmt.Println("Result of channel is: ", result)
CurrentStream, _ := portaudio.OpenDefaultStream(0, 2, rate, portaudio.FramesPerBufferUnspecified, &Out)
// LogOnError(err)
EndPlayer = false
StreamChanged = true
PlayAudio = true
MainNotification := notify.NewNotification("Playing", songdata.Artist+": "+songdata.Title)
MainNotification.Timeout = 2000
if _, err := MainNotification.Show(); err != nil {
return
}
go glib.IdleAdd(SetPlayingGuiData)
MainAdjustment.Configure(float64(0), float64(0), float64(1), float64(1), float64(10), float64(0))
// chk(CurrentStream.Start())
for !EndPlayer {
if PlayAudio {
if StreamChanged {
CurrentStream.Start()
StreamChanged = false
}
_, err := OpusStr.Read(Out)
DrawnTime += float64(1920 / rate / 2)
glib.IdleAdd(UpdatePBar())
if (err == io.EOF) || (err == io.ErrUnexpectedEOF) || (TimeInPrecent >= 1.01) || (err == portaudio.StreamIsStopped) || (err == portaudio.TimedOut) {
fmt.Println("EOF", NowPlayingIndex, len(MainQueue)) // TODO Stram recover when unexpected
err = CurrentStream.Stop()
glib.IdleAdd(SetZeroTime())
defer CurrentStream.Close()
Out = make([]int16, 1920)
notify.CloseNotification(MainNotification.ReplacesID)
if NowPlayingIndex+1 < len(MainQueue) {
fmt.Println("Playing next song")
NowPlayingIndex++
go StartCaching(MainQueue[NowPlayingIndex])
if NowPlayingIndex+1 <= len(MainQueue)-1 {
// fmt.Println(songdata.Title, " +1 needs to be downloaded")
go CachingWaiter(MainQueue[NowPlayingIndex], MainQueue[NowPlayingIndex+1], 5)
}
if NowPlayingIndex+2 <= len(MainQueue)-1 {
// fmt.Println(songdata.Title, " +2 needs to be downloaded")
go CachingWaiter(MainQueue[NowPlayingIndex+1], MainQueue[NowPlayingIndex+2], 5)
}
go PlayPort() // Run new gouroutine to let func complete
EndPlayer = true
break
} else if (NowPlayingIndex + 1) == len(MainQueue) {
fmt.Println("End playing")
CurrentStream.Close()
EndPlayer = true
break
}
} else {
// if (err != portaudio.OutputUnderflowed && err != nil) {
// fmt.Println(err)
// }
err := CurrentStream.Write()
if err != nil {
// LogOnError(err)
}
}
} else {
StreamChanged = true
CurrentStream.Stop()
}
select {
case <-sig:
CurrentStream.Close()
EndPlayer = true
break
default:
}
}
PlayAudio = false
glib.IdleAdd(SetZeroTime())
fmt.Println("End playport")
AudioControlChan <- true
}
func Backgroundread(reader io.Reader, w io.WriteCloser, id string) {
fmt.Println("DEBUG: backgroundread ", id)
DownloadSyncGroup.Add(1)
readBuffer := make([]byte, MainSettings.DownladBufferSize)
for {
n, err := reader.Read(readBuffer)
if err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
w.Write(readBuffer[:n])
break
} else {
fmt.Println(err)
}
}
w.Write(readBuffer[:n])
}
w.Close()
runtime.GC()
DownloadSyncGroup.Done()
fmt.Println("Ended downloading ", id)
CachingMap[id] = true
}
func CachingWaiter(idBlocking string, idNext string, waitTime int) {
isDownloaded, exists := CachingMap[idBlocking]
if !isDownloaded || !exists {
if waitTime == 0 {
waitTime = 3
}
time.Sleep(time.Duration(waitTime) * time.Second)
CachingWaiter(idBlocking, idNext, waitTime-1)
} else if isDownloaded && exists {
go StartCaching(idNext)
} else if !isDownloaded && exists {
return
}
}
func StartCaching(songID string) {
// songdata, _ := CurrentClient.GetSong(songID)
// albmdata, _ := CurrentClient.GetAlbum(songdata.AlbumID)
param := map[string]string{
"maxBitRate": strconv.Itoa(int(MainSettings.Bitrate)),
"MainFormat": MainSettings.Codec,
"transcodings": MainSettings.Codec,
"estimateContentLength": "true",
}
cacheExists := CurrentCache.Exists(songID)
_, WriteMaster, _ = CurrentCache.Get(songID)
if !cacheExists {
reader, _ := CurrentClient.Stream(songID, param)
// go DownloadCoverArtFullSize(albmdata.CoverArt)
Backgroundread(reader, WriteMaster, songID)
} else {
fmt.Println("Playing from cache")
}
}
// GTK Async gui update
func UpdatePBar() func() {
var up = func() {
TimeInPrecent = float64(DrawnTime / float64(TotalTime))
MainTimeLeft.SetText(DurationToReadable(TotalTime - int(float64(DrawnTime))))
MainTimeDrawnLabel.SetText(DurationToReadable(int(float64(DrawnTime))))
MainAdjustment.SetValue(float64(DrawnTime / float64(TotalTime)))
}
return up
}
// GTK Async gui update
func SetZeroTime() func() {
TotalTime = 0
DrawnTime = 0
TimeInPrecent = 0.0
var up = func() {
MainPlayPauseButton.SetLabel("▶")
MainTimeLeft.SetText(":")
MainTimeDrawnLabel.SetText(":")
MainAdjustment.SetValue(TimeInPrecent)
MainTotalTimeLabel.SetLabel(":")
MainArtistLabel.SetLabel(":")
MainSongTitleLabel.SetLabel(":")
MainAlbumLabel.SetLabel(":")
}
return up
}
func chk(err error) {
if err != nil {
panic(err)
}
}
func DurationToReadable(dur int) string {
min := dur / 60
sec := dur % 60
if min >= 60 {
hr := dur / 3600
min = (dur - (hr * 3600)) / 60
sec = (dur - (hr * 3600) - (min * 60))
return (PrefixZeroLook(hr) + ":" + PrefixZeroLook(min) + ":" + PrefixZeroLook(sec))
}
return (PrefixZeroLook(min) + ":" + PrefixZeroLook(sec))
}
func PrefixZeroLook(localInt int) string {
if localInt < 10 {
return ("0" + strconv.Itoa(localInt))
} else {
return strconv.Itoa(localInt)
}
}
func Exists(name string) bool {
_, err := os.Stat(name)
if err == nil {
return true
}
if errors.Is(err, os.ErrNotExist) {
return false
}
return false
}
func FindSubtitles(artist string, song string) func() {
// TODO Repair
var fun = func() {
l := lyrics.New(*MetadataClient, lyrics.WithAllProviders())
lyric, err := l.Search(artist, song)
buf := MainSubtitlesTextView.Buffer()
if err != nil {
fmt.Printf("Lyrics for %v-%v were not found", artist, song)
buf.SetText("Not found")
}
buf.SetText(lyric)
MainSubtitlesTextView.SetBuffer(buf)
}
return fun
}
// AD1
// pixbuf2, err = gdk.PixbufNewFromFileAtSize(path2, w, h)
// gtk.LayoutNew()
// var css string = `
// GtkWindow {
// background-color: red;
// background-repeat: no-repeat;
// background-size: cover;
// background-position: center center;
// `
// var csscustom = `background-image: url("` + imgpath + `");
// }`
// var csscustom = `background-size: cover; background-color: red;
// }`
// fmt.Println(css + csscustom)
// prov, err := gtk.CssProviderNew()
// LogOnError(err)
// err = prov.LoadFromData(css + csscustom)
// LogOnError(err)
// scrn, err := gdk.ScreenGetDefault()
// LogOnError(err)
// gtk.AddProviderForScreen(scrn, prov, 1)
// MainWindow.ShowAll()
// LogFatalOnError(err)
// AD2
// path := os.UserHomeDir + MainDir + DataDir + "/" + nodeID.(string) + ".opus"
// var OpusStr *opus.Stream
// if !Exists(path) {
// f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
// chk(err)
// tee := io.TeeReader(reader, f)
// OpusStr, err = opus.NewStream(tee)
// } else {

24
error_handling.go Normal file
View File

@ -0,0 +1,24 @@
package main
import "log"
func PanicOnError(err error) {
if err != nil {
panic(err)
}
}
func LogFatalOnError(err error) {
if err != nil {
// log.Fatalln(err)
panic(err)
}
}
func LogOnError(err error) {
if err != nil {
log.Println(err)
// panic(err)
}
}

33
go.mod Normal file
View File

@ -0,0 +1,33 @@
module git.itmodulo.eu/LinuxOnMobile/Sonically
go 1.18
require (
git.itmodulo.eu/LibrariesGo/lyrics-api-go-extended v0.1.45-0.20220502211740-bdde16173c5c
github.com/TheCreeper/go-notify v0.2.0
github.com/delucks/go-subsonic v0.0.0-20220623171311-8b0662f9f006
github.com/diamondburned/gotk4/pkg v0.0.0-20220529201008-66c7fe5d2b7c
github.com/djherbis/fscache v0.10.1
github.com/gordonklaus/portaudio v0.0.0-20220320131553-cc649ad523c1
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/hraban/opus v0.0.0-20220302220929-eeacdbcb92d0
github.com/zalando/go-keyring v0.2.1
)
require (
github.com/PuerkitoBio/goquery v1.8.0 // indirect
github.com/alessio/shellescape v1.4.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gosimple/slug v1.12.0 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
golang.org/x/net v0.0.0-20220630215102-69896b714898 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect
gopkg.in/djherbis/atime.v1 v1.0.0 // indirect
gopkg.in/djherbis/stream.v1 v1.3.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

87
go.sum Normal file
View File

@ -0,0 +1,87 @@
git.itmodulo.eu/LibrariesGo/lyrics-api-go-extended v0.1.45-0.20220502211740-bdde16173c5c h1:rMlCwAUtUci5aHwQ/vnN8x5k6veHEQ39qstNTBqDZOg=
git.itmodulo.eu/LibrariesGo/lyrics-api-go-extended v0.1.45-0.20220502211740-bdde16173c5c/go.mod h1:UvHix+BErO9l3dealuksQRc2RYWXSCqxUo3HurXPGvs=
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/TheCreeper/go-notify v0.2.0 h1:akzlSD8IWx+uOZqGNwS0FYsThYuw11JkXsYiQXY5kgo=
github.com/TheCreeper/go-notify v0.2.0/go.mod h1:paZnY8fMbaOyZLQWJitGWAMrO5ot3Ow7id47cyEL1KA=
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/delucks/go-subsonic v0.0.0-20220623171311-8b0662f9f006 h1:hFXcR3r0Vsnr+mMMwMrgm+mlAR18k/AuuEvNuMbNuSQ=
github.com/delucks/go-subsonic v0.0.0-20220623171311-8b0662f9f006/go.mod h1:vnbEuj6Z20PLcHB4rrLQAOXGMjtULfMGhRVSFPcSdUo=
github.com/diamondburned/gotk4/pkg v0.0.0-20220529201008-66c7fe5d2b7c h1:d09K0Y9HQ6/WLlFlH11dPt9TdDLIOxlztHaLUOpKa04=
github.com/diamondburned/gotk4/pkg v0.0.0-20220529201008-66c7fe5d2b7c/go.mod h1:rLH6FHos690jFgAM/GYEpMykuE/9NmN6zOvFlr8JTvE=
github.com/djherbis/fscache v0.10.1 h1:hDv+RGyvD+UDKyRYuLoVNbuRTnf2SrA2K3VyR1br9lk=
github.com/djherbis/fscache v0.10.1/go.mod h1:yyPYtkNnnPXsW+81lAcQS6yab3G2CRfnPLotBvtbf0c=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gordonklaus/portaudio v0.0.0-20220320131553-cc649ad523c1 h1:FgUJ91JoMbS5qWXdIpnHta1hLtw1X8n2ek5JRED3R1I=
github.com/gordonklaus/portaudio v0.0.0-20220320131553-cc649ad523c1/go.mod h1:HfYnZi/ARQKG0dwH5HNDmPCHdLiFiBf+SI7DbhW7et4=
github.com/gosimple/slug v1.12.0 h1:xzuhj7G7cGtd34NXnW/yF0l+AGNfWqwgh/IXgFy7dnc=
github.com/gosimple/slug v1.12.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hraban/opus v0.0.0-20220302220929-eeacdbcb92d0 h1:kWEAL53h9DdQ2Utz2vKhgLutpSS1L6WDB37xv1VMKwU=
github.com/hraban/opus v0.0.0-20220302220929-eeacdbcb92d0/go.mod h1:YQQXrWHN3JEvCtw5ImyTCcPeU/ZLo/YMA+TpB64XdrU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/zalando/go-keyring v0.2.1 h1:MBRN/Z8H4U5wEKXiD67YbDAr5cj/DOStmSga70/2qKc=
github.com/zalando/go-keyring v0.2.1/go.mod h1:g63M2PPn0w5vjmEbwAX3ib5I+41zdm4esSETOn9Y6Dw=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220622184535-263ec571b305 h1:dAgbJ2SP4jD6XYfMNLVj0BF21jo2PjChrtGaAvF5M3I=
golang.org/x/net v0.0.0-20220622184535-263ec571b305/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw=
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 h1:wEZYwx+kK+KlZ0hpvP2Ls1Xr4+RWnlzGFwPP0aiDjIU=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/djherbis/atime.v1 v1.0.0 h1:eMRqB/JrLKocla2PBPKgQYg/p5UG4L6AUAs92aP7F60=
gopkg.in/djherbis/atime.v1 v1.0.0/go.mod h1:hQIUStKmJfvf7xdh/wtK84qe+DsTV5LnA9lzxxtPpJ8=
gopkg.in/djherbis/stream.v1 v1.3.1 h1:uGfmsOY1qqMjQQphhRBSGLyA9qumJ56exkRu9ASTjCw=
gopkg.in/djherbis/stream.v1 v1.3.1/go.mod h1:aEV8CBVRmSpLamVJfM903Npic1IKmb2qS30VAZ+sssg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

1452
gui.go Normal file

File diff suppressed because it is too large Load Diff

116
librarybox_actions.go Normal file
View File

@ -0,0 +1,116 @@
package main
import (
// "github.com/delucks/go-subsonic"
// "fmt"
"github.com/diamondburned/gotk4/pkg/core/glib"
)
func DownloadPlaylist() {
for child := PlayListListBox.FirstChild(); child != nil; {
PlayListListBox.Remove(child)
child = PlayListListBox.FirstChild()
}
param := map[string]string{}
playlists, err := CurrentClient.GetPlaylists(param)
LogOnError(err)
for i, item := range playlists {
playlist, _ := CurrentClient.GetPlaylist(item.ID)
PlaylistCached = append(PlaylistCached, item.ID)
pat := GetRunDir() + MainDir + InfDir + "/" + item.ID
SerializePlaylist(*playlist, pat)
var upstream = func() {
CreateImagelessPlaylistListBoxRow(PlayListListBox, playlist.Name, DurationToReadable(playlist.Duration), i, playlist.Entry)
}
glib.IdleAdd(upstream)
}
}
func GetPlaylist() {
for child := PlayListListBox.FirstChild(); child != nil; {
PlayListListBox.Remove(child)
child = PlayListListBox.FirstChild()
}
for i, id := range PlaylistCached {
// fmt.Printf("{}",item)
item := DeSerializePlaylist(GetRunDir() + MainDir + InfDir + "/" + id)
var upstream = func() {
CreateImagelessPlaylistListBoxRow(PlayListListBox, item.Name, DurationToReadable(item.Duration), i, item.Entry)
}
glib.IdleAdd(upstream)
}
}
// func RefreshPlaylist() {
// for child := PlayListListBox.FirstChild(); child != nil; {
// PlayListListBox.Remove(child)
// child = PlayListListBox.FirstChild()
// }
// param := map[string]string{}
// playlists, err := CurrentClient.GetPlaylists(param)
// LogOnError(err)
// for i, item := range playlists {
// playlist, _ := CurrentClient.GetPlaylist(item.ID)
// CreateImagelessPlaylistListBoxRow(PlayListListBox, playlist.Name, DurationToReadable(playlist.Duration), i, playlist.Entry)
// }
// }
func DownloadLib() {
param := map[string]string{}
artistID3, err := CurrentClient.GetArtists(param)
LogFatalOnError(err)
for _, indx := range artistID3.Index {
for j, artist := range indx.Artist {
art, _ := CurrentClient.GetArtist(artist.ID)
ArtistsCached = append(ArtistsCached, artist.ID)
SerializeArtist(*art, GetRunDir()+MainDir+InfDir+"/"+artist.ID)
var upstream = func() {
CreatelessListArtistBoxRow(QueueListBoxLibrary, art.Name, j, art.Album, art.ID)
}
glib.IdleAdd(upstream)
}
}
}
func GetLib() {
for child := QueueListBoxLibrary.FirstChild(); child != nil; {
QueueListBoxLibrary.Remove(child)
child = QueueListBoxLibrary.FirstChild()
}
for j, id := range ArtistsCached {
art := DeSerializeArtist(GetRunDir() + MainDir + InfDir + "/" + id)
var upstream = func() {
CreatelessListArtistBoxRow(QueueListBoxLibrary, art.Name, j, art.Album, art.ID)
}
glib.IdleAdd(upstream)
}
}
// func RefreshLib() {
// for child := QueueListBoxLibrary.FirstChild(); child != nil; {
// QueueListBoxLibrary.Remove(child)
// child = QueueListBoxLibrary.FirstChild()
// }
// param := map[string]string{}
// artistID3, err := CurrentClient.GetArtists(param)
// LogFatalOnError(err)
// for _, indx := range artistID3.Index {
// for j, artist := range indx.Artist {
// art, _ := CurrentClient.GetArtist(artist.ID)
// CreatelessListArtistBoxRow(QueueListBoxLibrary, art.Name, j, art.Album)
// }
// }
// }

39
package/alpine/APKBUILD Normal file
View File

@ -0,0 +1,39 @@
# Contributor: ITmodulo <hello@xmpp.itmodulo.eu>
# Maintainer: ITmodulo <hello@xmpp.itmodulo.eu>
pkgname="sonically"
reponame="Sonically"
organization="LinuxOnMobile"
githost="https://git.itmodulo.eu"
pkgver=0.4.1
pkgrel=0
pkgdesc="Subsonic API compatible streaming client made in GTK. It is suitable for desktop and mobile"
url="$githost/$organization/$reponame"
arch="x86_64 aarch64"
options="net !check" # for downloading Go modules, no checks available
license="GPL-3.0-or-later"
depends="portaudio opusfile libnotify glib gtk4.0 gobject-introspection"
makedepends="go portaudio-dev opusfile-dev libnotify-dev glib-dev gtk4.0-dev gobject-introspection-dev"
source="$reponame-$pkgver.tar.gz::$githost/$organization/$reponame/archive/$pkgver.tar.gz"
builddir="$srcdir/$pkgname-$pkgver"
prepare() {
default_prepare()
mkdir -p "$builddir"
}
build() {
# GOARCH should be set automaticaly by OS
cd "$srcdir"/"$pkgname"
CGO_ENABLED="1" GOOS="linux" go build -tags netgo -o "$builddir"/"$pkgname"
}
package() {
# Place built executable in PATH
install -Dm755 "$builddir"/"$pkgname" "$pkgdir"/usr/bin/"$pkgname"
# Copy .svg logo to system
install -Dm644 "$srcdir"/"$pkgname"/"$pkgname".svg "$pkgdir"/usr/share/pixmaps/"$pkgname".svg
# Copy .desktop file to to system
install -Dm755 "$srcdir"/"$pkgname"/"$pkgname".desktop "$pkgdir"/usr/share/applications/eu.itmodulo."$pkgname".desktop
}

89
pictures_actions.go Normal file
View File

@ -0,0 +1,89 @@
package main
import (
"fmt"
// "image"
"image/jpeg"
// "bytes"
"log"
"os"
"strconv"
// "github.com/esimov/stackblur-go"
// "github.com/diamondburned/gotk4/pkg/gtk/v4"
// "github.com/diamondburned/gotk4/pkg/gdkpixbuf/v2"
// "github.com/diamondburned/gotk4/pkg/cairo"
// "github.com/diamondburned/gotk4/pkg/gdk/v4"
// "github.com/diamondburned/gotkit/gtkutil/imgutil"
)
func DownloadCoverArtFullSize(coverID string) {
path := GetRunDir() + MainDir + DataDir + "/" + coverID + ".jpg"
fil, err1 := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0664)
defer fil.Close()
if err1 != nil {
//
param := map[string]string{"size": strconv.Itoa(int(MainSettings.Coversize))}
img, _ := CurrentClient.GetCoverArt(coverID, param)
fmt.Println("No such album downloaded: ", coverID)
f, err := os.Create(path)
// fb, err := os.Create(path2)
PanicOnError(err)
defer f.Close()
if err = jpeg.Encode(f, img, nil); err != nil {
log.Printf("failed to encode: %v", err)
}
// w, h := MainAlbumCover.GetSizeRequest()
// catFile, err := os.Open(path)
// if err != nil {
// panic(err)
// }
// defer catFile.Close()
// _, _, err = image.Decode(catFile)
// if err != nil {
// panic(err)
// }
// cat, err := jpeg.Decode(catFile)
// if err != nil {
// panic(err)
// }
// fmt.Println(cat)
// sig := make(chan struct{})
// img2 := stackblur.Process(cat, uint32(w), uint32(h), uint32(30), sig)
// select {
// case <-sig:
// jpeg.Encode(fb, img2, nil)
// }
} else {
fmt.Println("Album present: ", coverID)
}
}
// func LoadImageToByteArray(path string) []byte {
// f, err := os.Open(path)
// if err != nil {
// LogOnError(err)
// }
// defer f.Close()
// buf := new(bytes.Buffer)
// img, err := jpeg.Decode(f)
// err = jpeg.Encode(buf,img,nil)
// if err != nil {
// LogOnError(err)
// }
// return buf.Bytes()
// }

65
searchbox_actions.go Normal file
View File

@ -0,0 +1,65 @@
package main
import (
// "log"
"strconv"
// "fmt"
// "github.com/diamondburned/gotk4/pkg/core/glib"
// "github.com/diamondburned/gotk4/pkg/gdk/v4"
// "github.com/diamondburned/gotk4/pkg/gtk/v4"
// "github.com/diamondburned/gotkit/gtkutil"
)
// var PlayNode string
// var pool *parallel = parallel.NewParallel()
func Search() {
for child := SearchListBoxResult.FirstChild(); child != nil; {
SearchListBoxResult.Remove(child)
child = SearchListBoxResult.FirstChild()
}
artistCount := 0
albumCount := 0
songCount := 0
if SearchTabSongCheckButton.Active() {
songCount = 20
}
if SearchTabAlbumCheckButton.Active() {
albumCount = 20
}
if SearchTabArtistCheckButton.Active() {
artistCount = 20
}
q := SearchTabSearchEntry.Text()
param := map[string]string{
"artistCount": strconv.Itoa(artistCount),
// "artistOffset": "0",
"albumCount": strconv.Itoa(albumCount),
// "albumOffset": "0",
"songCount": strconv.Itoa(songCount),
// "songOffset": "0",
// "musicFolderId": "",
}
if q != "" {
result, err := CurrentClient.Search3(q, param)
LogFatalOnError(err)
var j = 0
for _, item := range result.Song {
j++
CreateImagelessSongListBoxRow(SearchListBoxResult, item.Title, item.Artist, DurationToReadable(item.Duration), j, item.ID)
}
for _, item := range result.Album {
j++
album, _ := CurrentClient.GetAlbum(item.ID)
CreateImagelessAlbumListBoxRow(SearchListBoxResult, album.Name, album.Artist, DurationToReadable(album.Duration), j, album.Song)
}
for _, item := range result.Artist {
j++
artist, _ := CurrentClient.GetArtist(item.ID)
CreatelessListArtistBoxRow(SearchListBoxResult, artist.Name, j, artist.Album, item.ID)
}
}
}

351
settings.go Normal file
View File

@ -0,0 +1,351 @@
package main
import (
"encoding/gob"
"fmt"
"github.com/delucks/go-subsonic"
"github.com/diamondburned/gotk4/pkg/core/glib"
// "io"
"log"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
// "github.com/diamondburned/gotk4/pkg/gtk/v4"
"github.com/djherbis/fscache"
"github.com/zalando/go-keyring"
)
func TestConnButtonClicked() {
clientt := CreateUser(HttpSettings)
_, err := clientt.GetGenres()
if err != nil {
var up = func() bool {
SettingsTabUserStatusLabel.SetText("✗ ")
return false
}
glib.IdleAdd(up)
} else {
var up = func() bool {
SettingsTabUserStatusLabel.SetText("✓ ")
return false
}
glib.IdleAdd(up)
}
}
func CreateUser(httpsettings *http.Client) subsonic.Client {
server := SettingsTabUserServerEntry.Text()
username := SettingsTabUserUsernameEntry.Text()
device := SettingsTabUserDeviceNameEntry.Text()
pass := SettingsTabUserPasswordEntry.Text()
clientt := subsonic.Client{
Client: httpsettings,
BaseUrl: server,
User: username,
ClientName: device,
}
clientt.Authenticate(pass)
return clientt
}
type User struct {
User string
Url string
}
type Settings struct {
//User
Users [10]User
PlayerName string
//Local
DeleteOnClose bool
Coversize int16
BlurRadius int8
HideHeaderBar bool
//Transcoding
Codec string
Bitrate int16
DownladBufferSize int16
//Net
UseStreamingProxy bool
StreamingProxy string
AuthStreamingProxy bool
StreamingProxyUser string
// Metadata
MetadataType string
UseMetadataProxy bool
MetadataProxy string
AuthMetadataProxy bool
MetadataProxyUser string
}
// type SonicallyStream struct {
// ReadMaster fscache.ReadAtCloser
// WriteMaster io.WriteCloser
// }
func Serialize(obj Settings, path string) {
dataFile, err1 := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0664)
defer dataFile.Close()
if err1 == nil {
os.Remove(path)
}
dataFile, _ = os.Create(path)
e := gob.NewEncoder(dataFile)
if err := e.Encode(obj); err != nil {
LogFatalOnError(err)
}
dataFile.Close()
}
func DeSerialize(path string) Settings {
dataFile, err := os.Open(path)
if err != nil {
PanicOnError(err)
}
var sett Settings
dataDecoder := gob.NewDecoder(dataFile)
err = dataDecoder.Decode(&sett)
if err != nil {
PanicOnError(err)
}
dataFile.Close()
return sett
}
func SerializeArtist(obj subsonic.ArtistID3, path string) {
dataFile, err1 := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0664)
defer dataFile.Close()
if err1 == nil {
os.Remove(path)
}
dataFile, _ = os.Create(path)
e := gob.NewEncoder(dataFile)
if err := e.Encode(obj); err != nil {
LogFatalOnError(err)
}
dataFile.Close()
}
func DeSerializeArtist(path string) subsonic.ArtistID3 {
dataFile, err := os.Open(path)
if err != nil {
PanicOnError(err)
}
var sett subsonic.ArtistID3
dataDecoder := gob.NewDecoder(dataFile)
err = dataDecoder.Decode(&sett)
if err != nil {
PanicOnError(err)
}
dataFile.Close()
return sett
}
func SerializePlaylist(obj subsonic.Playlist, path string) {
dataFile, err1 := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0664)
defer dataFile.Close()
if err1 == nil {
os.Remove(path)
}
dataFile, _ = os.Create(path)
e := gob.NewEncoder(dataFile)
if err := e.Encode(obj); err != nil {
LogFatalOnError(err)
}
dataFile.Close()
}
func DeSerializePlaylist(path string) subsonic.Playlist {
dataFile, err := os.Open(path)
if err != nil {
PanicOnError(err)
}
var sett subsonic.Playlist
dataDecoder := gob.NewDecoder(dataFile)
err = dataDecoder.Decode(&sett)
if err != nil {
PanicOnError(err)
}
dataFile.Close()
return sett
}
func Init() {
fil, err1 := os.OpenFile(settingsPath, os.O_APPEND|os.O_WRONLY, 0664)
defer fil.Close()
if err1 == nil {
MainSettings = DeSerialize(settingsPath)
UserList = MainSettings.Users
UserDeserialized = MainSettings.Users[0]
clientt := subsonic.Client{
Client: HttpSettings,
BaseUrl: UserDeserialized.Url,
User: UserDeserialized.User,
ClientName: MainSettings.PlayerName,
}
sec, err := keyring.Get(UserDeserialized.Url, UserDeserialized.User)
if err == nil {
clientt.Authenticate(sec)
CurrentClient = clientt
SettingsTabUserUsernameEntry.SetText(UserDeserialized.User)
SettingsTabUserPasswordEntry.SetText(sec)
SettingsTabUserDeviceNameEntry.SetText(MainSettings.PlayerName)
SettingsTabUserServerEntry.SetText(UserDeserialized.Url)
SettingsTabAppDeleteSwitch.SetActive(MainSettings.DeleteOnClose)
SettingsTabAppHideHeaderBarSwitch.SetActive(MainSettings.HideHeaderBar)
SettingsTabAppCoverSizeEntry.SetText(strconv.Itoa(int(MainSettings.Coversize)))
SettingsTabAppBlurRadiusEntry.SetText(strconv.Itoa(int(MainSettings.BlurRadius)))
SettingsTabAppBitrateEntry.SetText(strconv.Itoa(int(MainSettings.Bitrate)))
SettingsTabAppBufferSizeEntry.SetText(strconv.Itoa(int(MainSettings.DownladBufferSize)))
SettingsTabAppStreamingProxySwitch.SetActive(MainSettings.UseStreamingProxy)
if MainSettings.UseStreamingProxy == true {
SettingsTabAppStreamingProxyEntry.SetText(MainSettings.StreamingProxy)
// var temptrans *http.Transport
var protocol, parsed string
if strings.Contains(MainSettings.StreamingProxy, "https") {
protocol = "https://"
parsed = MainSettings.StreamingProxy[8:]
} else if strings.Contains(MainSettings.StreamingProxy, "socks5") {
protocol = "socks5://"
parsed = MainSettings.StreamingProxy[9:]
} else if strings.Contains(MainSettings.StreamingProxy, "http") && !strings.Contains(MainSettings.StreamingProxy, "https") {
protocol = "http://"
parsed = MainSettings.StreamingProxy[7:]
} else {
log.Fatal("Unsupported protocol")
}
if SettingsTabAppAuthStreamingProxySwitch.Active() == true {
sec2, err := keyring.Get(MainSettings.StreamingProxy, MainSettings.StreamingProxyUser)
if err != nil {
log.Fatal("Error getting from keyring")
}
SettingsTabAppStreamingProxyUsernameEntry.SetText(MainSettings.StreamingProxyUser)
SettingsTabAppStreamingProxyPassEntry.SetText(sec2)
fullURL := protocol + MainSettings.StreamingProxyUser + ":" + sec2 + "@" + parsed
//adding the proxy settings to the Transport object
parsedurl, _ := url.Parse(fullURL)
HttpSettings = &http.Client{Timeout: time.Second * 10, Transport: &http.Transport{Proxy: http.ProxyURL(parsedurl)}}
} else {
// fullURL := protocol + MainSettings.StreamingProxyUser + "@" + parsed
parsedurl, _ := url.Parse(MainSettings.StreamingProxy)
// temptrans :=
HttpSettings = &http.Client{Timeout: time.Second * 10, Transport: &http.Transport{Proxy: http.ProxyURL(parsedurl)}}
}
//adding the Transport object to the http Client
// HttpSettings.Transport
}
SettingsTabAppMetadataProxySwitch.SetActive(MainSettings.UseMetadataProxy)
if MainSettings.UseMetadataProxy == true {
SettingsTabAppMetadataProxyEntry.SetText(MainSettings.MetadataProxy)
// var temptrans2 *http.Transport
var protocol, parsed string
if strings.Contains(MainSettings.MetadataProxy, "https") {
protocol = "https://"
parsed = MainSettings.MetadataProxy[8:]
} else if strings.Contains(MainSettings.MetadataProxy, "socks5") {
protocol = "socks5://"
parsed = MainSettings.MetadataProxy[9:]
} else if strings.Contains(MainSettings.MetadataProxy, "http") && !strings.Contains(MainSettings.MetadataProxy, "https") {
protocol = "http://"
parsed = MainSettings.MetadataProxy[7:]
} else {
log.Fatal("Unsupported protocol")
}
if SettingsTabAppAuthMetadataProxySwitch.Active() == true {
sec3, err := keyring.Get(MainSettings.MetadataProxy, MainSettings.MetadataProxyUser)
if err != nil {
log.Fatal("Error getting from keyring")
}
SettingsTabAppMetadataProxyUsernameEntry.SetText(MainSettings.MetadataProxyUser)
SettingsTabAppMetadataProxyPassEntry.SetText(sec3)
fullURL := protocol + MainSettings.MetadataProxyUser + ":" + sec3 + "@" + parsed
//adding the proxy settings to the Transport object
parsedurl2, err := url.Parse(fullURL)
MetadataClient = &http.Client{Timeout: time.Second * 10, Transport: &http.Transport{Proxy: http.ProxyURL(parsedurl2)}}
} else {
// fullURL := protocol + MainSettings.StreamingProxyUser + "@" + parsed
parsedurl2, _ := url.Parse(MainSettings.MetadataProxy)
MetadataClient = &http.Client{Timeout: time.Second * 10, Transport: &http.Transport{Proxy: http.ProxyURL(parsedurl2)}}
}
//adding the Transport object to the http Client
}
if MainSettings.Codec == "opus" {
SettingsTabAppCodecComboBoxTest.SetActive(0)
} else if MainSettings.Codec == "flac" {
SettingsTabAppCodecComboBoxTest.SetActive(1)
} else if MainSettings.Codec == "ogg" {
SettingsTabAppCodecComboBoxTest.SetActive(2)
} else if MainSettings.Codec == "mp3" {
SettingsTabAppCodecComboBoxTest.SetActive(3)
}
// HERE
if MainSettings.MetadataType == "None" {
SettingsTabAppMetadataComboBoxTest.SetActive(0)
} else if MainSettings.MetadataType == "Server" {
SettingsTabAppMetadataComboBoxTest.SetActive(1)
} else if MainSettings.MetadataType == "Sonically" {
SettingsTabAppMetadataComboBoxTest.SetActive(2)
}
if MainSettings.HideHeaderBar {
MainWindow.SetDecorated(false)
}
log.Print("Sucessfully set user from deserialzed content")
cacheDir := GetRunDir() + MainDir + DataDir + "/.cache"
CurrentCache, err = fscache.New(cacheDir, 0755, time.Hour*24)
if err != nil {
log.Fatal(err.Error())
}
}
} else {
MainDirC := GetRunDir() + MainDir
if _, err := os.Stat(MainDir); os.IsNotExist(err) {
os.Mkdir(MainDirC, 0744)
os.Mkdir(MainDirC+DataDir, 0744)
os.Mkdir(MainDirC+InfDir, 0744)
os.Mkdir(MainDirC+SettingsDir, 0744)
fmt.Println("Directory tree created")
}
}
}

243
shared_objects.go Normal file
View File

@ -0,0 +1,243 @@
package main
import (
"io"
"net/http"
"os"
"sync"
"github.com/TheCreeper/go-notify"
"github.com/delucks/go-subsonic"
"github.com/diamondburned/gotk4/pkg/gtk/v4"
// "github.com/diamondburned/gotk4/pkg/gdk/v4"
// "github.com/diamondburned/gotk4/pkg/core/glib"
"github.com/djherbis/fscache"
// "github.com/emirpasic/gods/lists/arraylist"
"github.com/gordonklaus/portaudio"
"github.com/hraban/opus"
)
func GetRunDir() string {
rundirGet, _ := os.UserHomeDir()
return rundirGet
}
// Dirs
const MainDir string = "/.Sonically"
const DataDir string = "/data"
const SettingsDir string = "/Settings"
const InfDir string = "/inf"
var CurrentClient subsonic.Client
var CurrentStream *portaudio.Stream
var MainQueue []string
var NowPlayingIndex int = 0
var UserList [10]User
var UserDeserialized User
var MainSettings Settings
var DownloadSyncGroup sync.WaitGroup
var TotalTime int = 0
var DrawnTime float64 = float64(0.0)
var Out []int16 = make([]int16, 1920)
// var ReadBuffer []byte
// var MasterStramSlice map[string]SonicallyStream
var CachingMap map[string]bool = make(map[string]bool)
var TimeInPrecent float64 = 0.0
var CurrentCache fscache.Cache
var AudioControlChan chan bool
var OpusStr *opus.Stream
var ReadMaster fscache.ReadAtCloser
var WriteMaster io.WriteCloser
var ArtistsCached []string
var PlaylistCached []string
var TempArtist string = ""
var EnterArtist bool
// UI widgets declaration
var MainWindow *gtk.ApplicationWindow
var LyricsNotebook *gtk.Notebook
var LyricsScrolledWindow *gtk.ScrolledWindow
var MainFlowbox *gtk.FlowBox
var MainFlowBoxChild1 *gtk.FlowBoxChild
var MainFlowBoxChild2 *gtk.FlowBoxChild
var MainFlowBoxChild3 *gtk.FlowBoxChild
var MainFlowBoxChild4 *gtk.FlowBoxChild
var MainGridFlowBoxChild2 *gtk.Grid
var MainGridFlowBoxChild4 *gtk.Grid
var MainGridFlowBoxChild2Grid *gtk.Grid
var MainLeftSeparator *gtk.Separator
var MainRightSeparator *gtk.Separator
var MainScale *gtk.Scale
var MainScaleGrid *gtk.Grid
var QueueMasterBox *gtk.Box
var QueueSearchControlBox *gtk.Grid
var QueueFlowBox *gtk.FlowBox
var QueueScrolledWindow *gtk.ScrolledWindow
var QueueSaveButton *gtk.Button
var QueueClearButton *gtk.Button
var QueueShuffleButton *gtk.Button
var QueueFlowBoxChild1 *gtk.FlowBoxChild
var SearchFlowBox *gtk.FlowBox
var SearchFlowBoxChild1 *gtk.FlowBoxChild
var SearchMasterBox *gtk.Box
var SearchControlBox *gtk.Grid
var SearchScrolledWindow *gtk.ScrolledWindow
var LibraryFlowBox1 *gtk.FlowBox
var LibraryFlowBox2 *gtk.FlowBox
var LibraryFlowBox3 *gtk.FlowBox
var LibraryFlowBox4 *gtk.FlowBox
var LibraryPlaylistMainBox *gtk.Box
var LibraryStarredMainBox *gtk.Box
var LibraryLibraryMainBox *gtk.Box
var LibraryPodcastMainBox *gtk.Box
var LibraryFlowBox1Child1 *gtk.FlowBoxChild
var LibraryFlowBox2Child1 *gtk.FlowBoxChild
var LibraryFlowBox3Child1 *gtk.FlowBoxChild
var LibraryFlowBox4Child1 *gtk.FlowBoxChild
var LibraryPlaylistMainControlGrid *gtk.Grid
var LibraryStarredMainControlGrid *gtk.Grid
var LibraryLibraryMainControlGrid *gtk.Grid
var LibraryPodcastMainControlGrid *gtk.Grid
var LibraryPlaylistBackButton *gtk.Button
var LibraryPlaylistRefreshButton *gtk.Button
var LibraryStarredBackButton *gtk.Button
var LibraryStarredRefreshButton *gtk.Button
var LibraryLibraryBackButton *gtk.Button
var LibraryLibraryRefreshButton *gtk.Button
var LibraryPodcastBackButton *gtk.Button
var LibraryPodcastRefreshButton *gtk.Button
var LibraryStarredListBox *gtk.ListBox
var LibraryPodcastListBox *gtk.ListBox
var LibraryPlaylistMainScrolledWindow *gtk.ScrolledWindow
var LibraryPodcastListBoxScrolledWindow *gtk.ScrolledWindow
var LibraryStarredListBoxScrolledWindow *gtk.ScrolledWindow
var QueueListBoxLibraryScrolledWindow *gtk.ScrolledWindow
var SettingsFlowBox *gtk.FlowBox
var SettingsTabUserUsernameEntry *gtk.Entry
var SettingsTabUserServerEntry *gtk.Entry
var SettingsTabUserDeviceNameEntry *gtk.Entry
var SettingsTabUserPasswordEntry *gtk.Entry
var SettingsTabUserStatusLabel *gtk.Label
var SearchTabSearchEntry *gtk.SearchEntry
var SearchTabSongCheckButton *gtk.CheckButton
var SearchTabAlbumCheckButton *gtk.CheckButton
var SearchTabArtistCheckButton *gtk.CheckButton
var SearchListBoxResult *gtk.ListBox
var PlayListListBox *gtk.ListBox
var MainSongTitleLabel *gtk.Label
var MainArtistLabel *gtk.Label
var MainAlbumLabel *gtk.Label
var MainTimeDrawnLabel *gtk.Label
var MainTimeLeft *gtk.Label
var MainAdjustment *gtk.Adjustment
var SettingsTabAppDeleteSwitch *gtk.Switch
var SettingsTabAppCodecComboBoxTest *gtk.ComboBoxText
// var SettingsTabAppRetrievingComboBoxText *gtk.ComboBoxText
var SettingsTabAppCacheEntry *gtk.Entry
var QueueListBox *gtk.ListBox
var MainAlbumCover *gtk.Image
var MainPlayPauseButton *gtk.Button
var MainPreviousButton *gtk.Button
var MainNextButton *gtk.Button
var MainRepeatButton *gtk.Button
var MainStarredButton *gtk.Button
var MainSubtitlesTextView *gtk.TextView
var MainTotalTimeLabel *gtk.Label
var LibraryNotebook *gtk.Notebook
var MainNotebook *gtk.Notebook
var QueueListBoxLibrary *gtk.ListBox
var SettingsTabAppCoverSizeEntry *gtk.Entry
var SettingsTabAppBlurRadiusEntry *gtk.Entry
var SettingsTabAppBitrateEntry *gtk.Entry
var SettingsTabAppBufferSizeEntry *gtk.Entry
var SettingsTabAppStreamingProxySwitch *gtk.Switch
var SettingsTabAppStreamingProxyEntry *gtk.Entry
var SettingsTabAppAuthStreamingProxySwitch *gtk.Switch
var SettingsTabAppStreamingProxyUsernameEntry *gtk.Entry
var SettingsTabAppStreamingProxyPassEntry *gtk.Entry
var SettingsTabAppMetadataProxySwitch *gtk.Switch
var SettingsTabAppMetadataProxyEntry *gtk.Entry
var SettingsTabAppAuthMetadataProxySwitch *gtk.Switch
var SettingsTabAppMetadataProxyUsernameEntry *gtk.Entry
var SettingsTabAppMetadataProxyPassEntry *gtk.Entry
var SettingsAccountsFlowBox *gtk.FlowBox
var SettingsAccountFlowboxChild1 *gtk.FlowBoxChild
var SettingsAccountFlowboxChild2 *gtk.FlowBoxChild
var SettingsNotebook *gtk.Notebook
var SettingsAccountBox *gtk.Box
var SettingsAccountLoginGrid *gtk.Grid
var SettingsAccountButtonsGrid *gtk.Grid
var SettingsAccountUserListbox *gtk.ListBox
var SettingsAppFlowBox *gtk.FlowBox
var SettingsCreditsFlowBox *gtk.FlowBox
var SettingsAccountUsernameLabel *gtk.Label
var SettingsAccountPasswordLabel *gtk.Label
var SettingsAccountPLayerNameLabel *gtk.Label
var SettingsAccountServerLabel *gtk.Label
var SettingsAccountTestButton *gtk.Button
var SettingsAccountSaveButton *gtk.Button
var SettingsAccountLoadButton *gtk.Button
// var SettingsAppScrolledWindow *gtk.ScrolledWindow
var SettingsAppFlowBoxChild1 *gtk.FlowBoxChild
var SettingsAppFlowBoxChild2 *gtk.FlowBoxChild
var SettingsAppFlowBoxChild3 *gtk.FlowBoxChild
var SettingsAppFlowBoxChild4 *gtk.FlowBoxChild
var SettingsAppGrid1 *gtk.Grid
var SettingsAppGrid2 *gtk.Grid
var SettingsAppGrid3 *gtk.Grid
var SettingsAppGrid4 *gtk.Grid
var SettingsAppLabelGrid4 *gtk.Label
var SettingsAppLabelGrid4Metadata *gtk.Label
var SettingsTabAppMetadataComboBoxTest *gtk.ComboBoxText
var SettingsAppLabelGrid1 *gtk.Label
var SettingsAppLabelGrid2 *gtk.Label
var SettingsAppLabelGrid3 *gtk.Label
var SettingsAppLabelGrid1DeleteOnClose *gtk.Label
var SettingsAppLabelGrid1CoverSideSize *gtk.Label
var SettingsAppLabelGrid1BackgroundBlurRadius *gtk.Label
var SettingsAppLabelGrid2Codec *gtk.Label
var SettingsAppLabelGrid2Bitrate *gtk.Label
var SettingsAppLabelGrid2DownloadBufferSize *gtk.Label
var SettingsTabAppHideHeaderBarSwitch *gtk.Switch
var SettingsAppLabelHideHeaderBar *gtk.Label
var SettingsAccountScrolledWindow *gtk.ScrolledWindow
var SettingsAppScrolledWindow *gtk.ScrolledWindow
var SettingsCreditsScrolledWindow *gtk.ScrolledWindow
var SettingsAppLabelGrid3UseProxyForStreaming *gtk.Label
var SettingsAppLabelGrid3AuthenticateStreamingProxy *gtk.Label
var SettingsAppLabelGrid3UseProxyForMetadata *gtk.Label
var SettingsAppLabelGrid3AuthenticateMetadataProxy *gtk.Label
var SettingsCreditsFlowBoxChild1 *gtk.FlowBoxChild
var SettingsCreditsLabel1 *gtk.Label
var MetadataClient *http.Client
var HttpSettings *http.Client
// var one gtk.EventBox
// LIBNOTIFY
var MainNotification notify.Notification

59
slice_utils.go Normal file
View File

@ -0,0 +1,59 @@
package main
// Slice Utils instead of ArrayList
// Returns Index of T
func SliceIndexOf[T comparable](slc []T, el T) int {
for i, x := range slc {
if x == el {
return i
}
}
return -1
}
// Swap T1 and T2 at indexes
func SliceSwapAtIndexes[T comparable](slc []T, el int, el2 int) {
x := slc[el]
slc[el] = slc[el2]
slc[el2] = x
}
// Returns true if Slice contains T
func SliceContains[T comparable](slc []T, el T) bool {
for _, x := range slc {
if x == el {
return true
}
}
return false
}
// Remove T if exists
func SliceRemove[T comparable](slc []T, el T) []T {
res := SliceIndexOf(slc, el)
if res != -1 {
return SliceRemoveAt(slc, res)
}
return slc
}
func SliceRemoveAt[T comparable](slc []T, el int) []T {
for i := el; i <= len(slc)-2; i++ {
slc[i] = slc[i+1]
}
// x:= (len(slc)-2)
// slc = append([]T(nil), slc[:x]...)
return slc[:(len(slc) - 1)]
}
func SliceInsertAt[T comparable](slc []T, el T, pos int) {
slc = append(slc, slc[len(slc)-1])
for i := len(slc) - 2; i > pos; i-- {
slc[i] = slc[i-1]
}
}
func SliceClear[T comparable](slc []T) []T {
return []T{}
}

8
sonically.desktop Normal file
View File

@ -0,0 +1,8 @@
[Desktop Entry]
Encoding=UTF-8
Version=0.4.1
Type=Application
Terminal=false
Exec=/usr/bin/sonically
Name=Sonically
Icon=/usr/share/pixmaps/sonically.svg

110
sonically.go Normal file
View File

@ -0,0 +1,110 @@
package main
import (
// "net/http"
"os"
"path/filepath"
"runtime"
"github.com/TheCreeper/go-notify"
"github.com/diamondburned/gotk4/pkg/gtk/v4"
"github.com/hashicorp/go-retryablehttp"
// "github.com/diamondburned/gotk4/pkg/core/glib"
// "github.com/hashicorp/go-retryablehttp"
)
// Widely used, conditionally created objects
var ifDelete bool = true
var delDir string
var settingsPath string = (GetRunDir() + MainDir + SettingsDir + "/gob")
// var mainWaitGroup sync.WaitGroup
// This is where app starts
func main() {
app := gtk.NewApplication("eu.itmodulo.sonically", 0)
app.ConnectActivate(func() { activate(app) })
if code := app.Run(os.Args); code > 0 {
os.Exit(code)
}
}
// This is func that initates GUI, deserializez data
func activate(app *gtk.Application) {
AudioControlChan = make(chan bool) // Initate goroutine channel
MainWindow = gtk.NewApplicationWindow(app)
MainWindow.SetTitle("Sonically")
SetUpGui()
x := retryablehttp.NewClient()
x.RetryMax = 15
x.Logger = nil
y := retryablehttp.NewClient()
y.RetryMax = 20
y.Logger = nil
// All widgets put together
HttpSettings = x.StandardClient() // Default client for connection
MetadataClient = y.StandardClient() // Default client for connection
Init() // Set up account
MainWindow.ConnectCloseRequest(closeApp)
MainWindow.Resizable()
MainWindow.Show()
// Background Read User Library, to speedup later loading
if MainSettings.Bitrate != 0 {
go DownloadLib()
go DownloadPlaylist()
}
}
func closeApp() bool {
if CurrentCache != nil {
CurrentCache.Clean()
}
if MainSettings.DeleteOnClose {
delDir = GetRunDir() + MainDir + DataDir + "/"
d, err := os.Open(delDir)
if err != nil {
PanicOnError(err)
}
defer d.Close()
names, err := d.Readdirnames(-1)
if err != nil {
PanicOnError(err)
}
for _, name := range names {
err = os.RemoveAll(filepath.Join(delDir, name))
if err != nil {
PanicOnError(err)
}
}
}
delDir = GetRunDir() + MainDir + InfDir + "/"
d, err := os.Open(delDir)
if err != nil {
PanicOnError(err)
}
defer d.Close()
names, err := d.Readdirnames(-1)
if err != nil {
PanicOnError(err)
}
for _, name := range names {
err = os.RemoveAll(filepath.Join(delDir, name))
if err != nil {
PanicOnError(err)
}
}
notify.CloseNotification(MainNotification.ReplacesID)
runtime.GC()
return false
}

99
sonically.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB