more changes
This commit is contained in:
parent
e40f82f636
commit
7aa2dee280
17
app.go
17
app.go
@ -98,6 +98,19 @@ func (a *App) startup(ctx context.Context, logger logger.Logger) {
|
||||
}
|
||||
|
||||
// Greet returns a greeting for the given name
|
||||
func (a *App) Greet(name string) string {
|
||||
return fmt.Sprintf("Hello %s, It's show time!", name)
|
||||
func (a *App) Greet(token string) string {
|
||||
// Create fansly API instance
|
||||
fanslyAPI := handlers.NewFanslyAPIController(token, a.Logger)
|
||||
|
||||
// Get the user info
|
||||
account, accountErr := fanslyAPI.GetMe()
|
||||
if accountErr != nil {
|
||||
return "Failed to get account info: " + accountErr.Error()
|
||||
}
|
||||
|
||||
// Print the response we got
|
||||
a.Logger.Info(fmt.Sprintf("[Greet] Account info: %+v", account))
|
||||
|
||||
// Return the greeting
|
||||
return fmt.Sprintf("Hello %s! You have %d fans and %d posts likes.", account.Username, account.FollowCount, account.PostLikes)
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
import {useState} from 'react';
|
||||
import { useState } from 'react';
|
||||
import logo from './assets/images/logo-universal.png';
|
||||
import './App.css';
|
||||
import {Greet} from "../wailsjs/go/main/App";
|
||||
import { Greet } from '../wailsjs/go/main/App';
|
||||
|
||||
function App() {
|
||||
const [resultText, setResultText] = useState("Please enter your name below 👇");
|
||||
const [resultText, setResultText] = useState(
|
||||
'Enter your fansly API token, then press Go!',
|
||||
);
|
||||
const [name, setName] = useState('');
|
||||
const updateName = (e: any) => setName(e.target.value);
|
||||
const updateResultText = (result: string) => setResultText(result);
|
||||
@ -14,15 +16,26 @@ function App() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="App">
|
||||
<img src={logo} id="logo" alt="logo"/>
|
||||
<div id="result" className="result">{resultText}</div>
|
||||
<div id="input" className="input-box">
|
||||
<input id="name" className="input" onChange={updateName} autoComplete="off" name="input" type="text"/>
|
||||
<button className="btn" onClick={greet}>Greet</button>
|
||||
<div id='App'>
|
||||
<img src={logo} id='logo' alt='logo' />
|
||||
<div id='result' className='result'>
|
||||
{resultText}
|
||||
</div>
|
||||
<div id='input' className='input-box'>
|
||||
<input
|
||||
id='name'
|
||||
className='input'
|
||||
onChange={updateName}
|
||||
autoComplete='off'
|
||||
name='input'
|
||||
type='text'
|
||||
/>
|
||||
<button className='btn' onClick={greet}>
|
||||
Go!
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default App
|
||||
export default App;
|
||||
|
111
handlers/fansly.go
Normal file
111
handlers/fansly.go
Normal file
@ -0,0 +1,111 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"FanslySync/structs"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
)
|
||||
|
||||
type FanslyAPIController struct {
|
||||
client *http.Client
|
||||
token string
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// New creates a new Fansly client with the provided token (optional).
|
||||
func NewFanslyAPIController(token string, log logger.Logger) *FanslyAPIController {
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
return &FanslyAPIController{
|
||||
client: client,
|
||||
token: token,
|
||||
logger: log,
|
||||
}
|
||||
}
|
||||
|
||||
// GET issues a GET to /api/v1/{path}, optionally adding the Auth header,
|
||||
// and unmarshals the JSON response into the result parameter.
|
||||
func (f *FanslyAPIController) GET(path string, needsAuth bool, out interface{}) error {
|
||||
// build request
|
||||
url := "https://apiv3.fansly.com/api/v1/" + path
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
f.logger.Error("[FanslyAPIController] NewRequest GET " + path + ": " + err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
// Set headers
|
||||
req.Header.Set("User-Agent", "FanslySync/3.0 sticks@teamhydra.dev")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
// set auth
|
||||
if needsAuth && f.token != "" {
|
||||
req.Header.Set("Authorization", f.token)
|
||||
}
|
||||
|
||||
// send
|
||||
resp, err := f.client.Do(req)
|
||||
if err != nil {
|
||||
f.logger.Error("[FanslyAPIController] Do GET " + path + ": " + err.Error())
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// non-200
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
f.logger.Error(fmt.Sprintf("[FanslyAPIController] GET %s failed: %s", path, resp.Status))
|
||||
// read body for logs
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
f.logger.Info("[FanslyAPIController] Response body: " + string(body))
|
||||
return fmt.Errorf("unexpected status %s", resp.Status)
|
||||
}
|
||||
|
||||
// 200 ok, log
|
||||
f.logger.Debug(fmt.Sprintf("[FanslyAPIController] GET %s succeeded: %s", path, resp.Status))
|
||||
|
||||
// read body and unmarshal
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
f.logger.Error("[FanslyAPIController] Request was OK, but failed to read body: " + err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
// unmarshal into our expected response type
|
||||
err = json.Unmarshal(body, &out)
|
||||
if err != nil {
|
||||
f.logger.Error("[FanslyAPIController] GET " + path + " failed to unmarshal response: " + err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetToken updates the authorization token for subsequent requests.
|
||||
func (f *FanslyAPIController) SetToken(token string) {
|
||||
f.token = token
|
||||
}
|
||||
|
||||
// Returns the current user's account information from the Fansly API.
|
||||
//
|
||||
// Will error if the token is not set or the request fails.
|
||||
//
|
||||
// Returns a FanslyAccount struct containing the account information.
|
||||
func (f *FanslyAPIController) GetMe() (*structs.FanslyAccount, error) {
|
||||
var response structs.FanslyBaseResponse[structs.FanslyAccountResponse]
|
||||
|
||||
err := f.GET("account/me", true, &response)
|
||||
if err != nil {
|
||||
f.logger.Error("[FanslyAPIController] GetMe failed: " + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the account info
|
||||
return &response.Response.Account, nil
|
||||
}
|
@ -5,6 +5,10 @@ type FanslyBaseResponse[T any] struct {
|
||||
Response T `json:"response"` // The response data, type of T
|
||||
}
|
||||
|
||||
type FanslyAccountResponse struct {
|
||||
Account FanslyAccount `json:"account"`
|
||||
}
|
||||
|
||||
type FanslyFollowResponse struct {
|
||||
Followers []struct {
|
||||
FollowerID string `json:"followerId"` // The ID of the follower
|
||||
@ -50,4 +54,23 @@ type Subscription struct {
|
||||
PromoStatus any `json:"promoStatus"`
|
||||
PromoStartsAt any `json:"promoStartsAt"`
|
||||
PromoEndsAt any `json:"promoEndsAt"`
|
||||
}
|
||||
}
|
||||
|
||||
type FanslyAccount struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
Flags int `json:"flags"`
|
||||
Version int `json:"version"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
FollowCount int `json:"followCount"`
|
||||
SubscriberCount int `json:"subscriberCount"`
|
||||
AccountMediaLikes int `json:"accountMediaLikes"`
|
||||
StatusID int `json:"statusId"`
|
||||
LastSeenAt int `json:"lastSeenAt"`
|
||||
About string `json:"about,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
PostLikes int `json:"postLikes"`
|
||||
ProfileAccess bool `json:"profileAccess"`
|
||||
}
|
||||
|
35
structs/sync.go
Normal file
35
structs/sync.go
Normal file
@ -0,0 +1,35 @@
|
||||
package structs
|
||||
|
||||
type SyncProgressEvent struct {
|
||||
// The current step of the sync process.
|
||||
Step string `json:"step"`
|
||||
// The current percent done of the sync process.
|
||||
PercentDone int `json:"percent_done"`
|
||||
// The current count of the current step of the sync process.
|
||||
Count int `json:"current_count"`
|
||||
// The total count of the current step of the sync process.
|
||||
TotalCount int `json:"total_count"`
|
||||
// Are we complete?
|
||||
Complete bool `json:"complete"`
|
||||
}
|
||||
|
||||
type PasteDataReply struct {
|
||||
// The ID of the paste.
|
||||
Id string `json:"id"`
|
||||
|
||||
// The content of the paste.
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type PastePutResponse struct {
|
||||
// If Error is not empty, the request failed.
|
||||
Error string `json:"error"`
|
||||
|
||||
// If the request was successful, this will of type PasteDataReply.
|
||||
// If the request was not successful, this will be empty.
|
||||
Payload PasteDataReply `json:"payload"`
|
||||
}
|
||||
|
||||
type PastePayload struct {
|
||||
Content string `json:"content"`
|
||||
}
|
@ -64,18 +64,19 @@ func (m *multiLogger) Fatal(message string) {
|
||||
|
||||
// NewRuntimeFileLogger returns a logger that writes all output both to
|
||||
//
|
||||
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_latest.log
|
||||
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_latest.log (or OS equivalent)
|
||||
//
|
||||
// and to a timestamped file
|
||||
//
|
||||
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_YYYY-MM-DD_HH-MM-SS.log
|
||||
// $XDG_CONFIG_HOME/FanslySync/logs/runtime_YYYY-MM-DD_HH-MM-SS.log (or OS equivalent)
|
||||
//
|
||||
// It also deletes any timestamped logs older than 14 days.
|
||||
//
|
||||
// The returned logger implements github.com/wailsapp/wails/v2/pkg/logger.Logger
|
||||
// and will be used by Wails for all Go-side logging.
|
||||
func NewRuntimeFileLogger() (logger.Logger, error) {
|
||||
// 1) Ensure log directory exists
|
||||
// Make sure the log directory exists
|
||||
// We use $XDG_CONFIG_HOME/FanslySync/logs/runtime_latest.log or OS equivalent for $XDG_CONFIG_HOME
|
||||
cfgDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot determine user config dir: %w", err)
|
||||
@ -85,7 +86,8 @@ func NewRuntimeFileLogger() (logger.Logger, error) {
|
||||
return nil, fmt.Errorf("cannot create log directory: %w", err)
|
||||
}
|
||||
|
||||
// 2) Prune old timestamped logs (>14 days)
|
||||
// Prune old logs
|
||||
// We keep logs for 14 days, so delete any logs older than that
|
||||
cutoff := time.Now().Add(-14 * 24 * time.Hour)
|
||||
entries, _ := os.ReadDir(logDir)
|
||||
for _, e := range entries {
|
||||
@ -101,17 +103,17 @@ func NewRuntimeFileLogger() (logger.Logger, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Build paths for timestamped + latest
|
||||
ts := time.Now().Format("2006-01-02_15-04-05")
|
||||
tsPath := filepath.Join(logDir, fmt.Sprintf("runtime_%s.log", ts))
|
||||
latestPath := filepath.Join(logDir, "runtime_latest.log")
|
||||
|
||||
// 4) Create both loggers
|
||||
// Create loggers to attach to the multiLogger
|
||||
tsLogger := logger.NewFileLogger(tsPath)
|
||||
latestLogger := logger.NewFileLogger(latestPath)
|
||||
termLogger := logger.NewDefaultLogger()
|
||||
|
||||
// 5) Fan-out into a multiLogger
|
||||
// Spread into a multiLogger
|
||||
// This will fan out all log messages to all three loggers
|
||||
multi := &multiLogger{
|
||||
targets: []logger.Logger{tsLogger, latestLogger, termLogger},
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user