Add updated Goondex logos
This commit is contained in:
parent
99d72c4758
commit
e3d253ba92
50
.air.toml
Normal file
50
.air.toml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Air configuration for Goondex live reload
|
||||
# See: https://github.com/air-verse/air
|
||||
|
||||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "./tmp/goondex"
|
||||
cmd = "go build -o ./tmp/goondex ./cmd/goondex"
|
||||
delay = 1000
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata", "docs", ".git", "node_modules"]
|
||||
exclude_file = []
|
||||
exclude_regex = ["_test.go"]
|
||||
exclude_unchanged = false
|
||||
follow_symlink = false
|
||||
full_bin = ""
|
||||
# Watch all web-related files for changes
|
||||
include_dir = []
|
||||
include_ext = ["go", "tpl", "tmpl", "html", "css", "js"]
|
||||
include_file = []
|
||||
kill_delay = "0s"
|
||||
log = "build-errors.log"
|
||||
poll = false
|
||||
poll_interval = 0
|
||||
post_cmd = []
|
||||
pre_cmd = []
|
||||
rerun = false
|
||||
rerun_delay = 500
|
||||
send_interrupt = false
|
||||
stop_on_error = false
|
||||
|
||||
[color]
|
||||
app = ""
|
||||
build = "yellow"
|
||||
main = "magenta"
|
||||
runner = "green"
|
||||
watcher = "cyan"
|
||||
|
||||
[log]
|
||||
main_only = false
|
||||
time = true
|
||||
|
||||
[misc]
|
||||
clean_on_exit = false
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = false
|
||||
keep_scroll = true
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -21,6 +21,12 @@
|
|||
/cache/
|
||||
/tmp/
|
||||
|
||||
# Node modules (Bootstrap)
|
||||
node_modules/
|
||||
|
||||
# Air live reload
|
||||
build-errors.log
|
||||
|
||||
# Media & Assets (images, galleries, downloads)
|
||||
# Ignore all assets except logos and README
|
||||
/assets/*
|
||||
|
|
|
|||
64
Makefile
Normal file
64
Makefile
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
.PHONY: help dev build run clean install-deps install-air test
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@echo "Goondex Development Commands:"
|
||||
@echo ""
|
||||
@echo " make dev - Start development server with live reload (Air)"
|
||||
@echo " make build - Build production binary"
|
||||
@echo " make run - Run production binary"
|
||||
@echo " make clean - Clean build artifacts"
|
||||
@echo " make install-deps - Install all dependencies"
|
||||
@echo " make install-air - Install Air for live reload"
|
||||
@echo " make test - Run tests"
|
||||
@echo ""
|
||||
|
||||
# Development with Air (live reload)
|
||||
dev: install-air
|
||||
air
|
||||
|
||||
# Build production binary
|
||||
build:
|
||||
@echo "Building Goondex..."
|
||||
@mkdir -p bin
|
||||
go build -o ./bin/goondex ./cmd/goondex
|
||||
@echo "Built: ./bin/goondex"
|
||||
|
||||
# Run production build
|
||||
run: build
|
||||
./bin/goondex serve
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
@echo "Cleaning build artifacts..."
|
||||
rm -rf tmp/
|
||||
rm -rf bin/
|
||||
rm -f build-errors.log
|
||||
@echo "Cleaned!"
|
||||
|
||||
# Install all dependencies
|
||||
install-deps: install-air
|
||||
@echo "All dependencies installed!"
|
||||
|
||||
# Install Air for live reload
|
||||
install-air:
|
||||
@if ! command -v air >/dev/null 2>&1; then \
|
||||
echo "Installing Air..."; \
|
||||
go install github.com/air-verse/air@latest; \
|
||||
echo "Air installed! Make sure ~/go/bin is in your PATH"; \
|
||||
else \
|
||||
echo "Air is already installed"; \
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
test:
|
||||
go test -v ./...
|
||||
|
||||
# Database migrations (if needed in future)
|
||||
migrate-up:
|
||||
@echo "Running migrations..."
|
||||
# Add migration commands here
|
||||
|
||||
migrate-down:
|
||||
@echo "Rolling back migrations..."
|
||||
# Add rollback commands here
|
||||
|
|
@ -8,6 +8,8 @@ Goondex ingests metadata from external sources (ThePornDB, etc.), normalizes it,
|
|||
|
||||
**v0.1.0-dev2** - TPDB Integration Release
|
||||
|
||||
> Note: TPDB import/sync commands are temporarily disabled. Use the Adult Empire commands (`goondex adultemp ...`) to build your directory for now.
|
||||
|
||||
## Features (v0.1.0-dev2)
|
||||
|
||||
- ✅ SQLite database with WAL mode for performers, studios, scenes, and tags
|
||||
|
|
@ -160,6 +162,13 @@ go build -o bin/goondex ./cmd/goondex
|
|||
go run ./cmd/goondex performer-search "test"
|
||||
```
|
||||
|
||||
### Scripts
|
||||
|
||||
- `source scripts/env.sh` - Pin Go caches inside the repo (recommended before building)
|
||||
- `scripts/build.sh` - Build the CLI (`bin/goondex`)
|
||||
- `ADDR=localhost:8788 scripts/run.sh` - Build (if needed) and start the web UI
|
||||
- `scripts/test.sh` - Run `go test ./cmd/... ./internal/...`
|
||||
|
||||
### Building & Rebuilding the CLI
|
||||
|
||||
The Goondex binary is not rebuilt automatically—whenever you change Go files (especially under `cmd/goondex` or `internal/*`), rebuild before re-running commands.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
)
|
||||
|
||||
const tpdbAPIKeyEnvVar = "TPDB_API_KEY"
|
||||
const tpdbEnabled = false
|
||||
|
||||
var (
|
||||
dbPath string
|
||||
|
|
@ -48,7 +49,7 @@ func init() {
|
|||
rootCmd.AddCommand(versionCmd)
|
||||
performerSearchCmd.Flags().Bool("show-bio", false, "Show performer bio in search results")
|
||||
performerGetCmd.Flags().Bool("show-bio", false, "Show performer bio")
|
||||
webCmd.Flags().String("addr", "localhost:8080", "Address to listen on")
|
||||
webCmd.Flags().String("addr", "localhost:8788", "Address to listen on")
|
||||
|
||||
// Sync command flags
|
||||
syncCmd.PersistentFlags().Bool("force", false, "Force sync even if rate limit not met")
|
||||
|
|
@ -58,8 +59,8 @@ func init() {
|
|||
// Import command with subcommands
|
||||
var importCmd = &cobra.Command{
|
||||
Use: "import",
|
||||
Short: "Import data from external sources (TPDB)",
|
||||
Long: `Import performers, studios, and scenes from ThePornDB into your local database.`,
|
||||
Short: "Import data (Adult Empire available; TPDB disabled)",
|
||||
Long: `Adult Empire import commands are available. TPDB bulk import commands are temporarily disabled while we focus on Adult Empire data.`,
|
||||
}
|
||||
|
||||
var importAllCmd = &cobra.Command{
|
||||
|
|
@ -151,20 +152,10 @@ func init() {
|
|||
// Sync command with subcommands
|
||||
var syncCmd = &cobra.Command{
|
||||
Use: "sync",
|
||||
Short: "Sync and update existing data from TPDB",
|
||||
Long: `Update existing performers, studios, and scenes with latest data from ThePornDB.
|
||||
Short: "Sync and update existing data (TPDB disabled for now)",
|
||||
Long: `TPDB-based sync is temporarily disabled while we prioritize Adult Empire as the main source.
|
||||
|
||||
Rate limiting is enforced to prevent excessive API calls:
|
||||
- Default minimum interval: 1 hour
|
||||
- Recommended interval: 24 hours
|
||||
- Use --force to override rate limiting
|
||||
|
||||
Examples:
|
||||
goondex sync all # Sync all entities (with 1h rate limit)
|
||||
goondex sync all --interval 24h # Sync all entities (24h rate limit)
|
||||
goondex sync all --force # Force sync, ignore rate limit
|
||||
goondex sync performers # Sync only performers
|
||||
goondex sync status # View last sync times`,
|
||||
Existing sync commands are left in place for when TPDB is re-enabled, but they will currently return a disabled message.`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
@ -445,6 +436,10 @@ func formatDuration(d time.Duration) string {
|
|||
}
|
||||
|
||||
func getTPDBAPIKey() (string, error) {
|
||||
if !tpdbEnabled {
|
||||
return "", fmt.Errorf("TPDB integration is disabled. Use Adult Empire commands (e.g., 'goondex adultemp search-performer' and 'goondex adultemp scrape-performer <url>') to import data instead.")
|
||||
}
|
||||
|
||||
apiKey := os.Getenv(tpdbAPIKeyEnvVar)
|
||||
if apiKey == "" {
|
||||
return "", fmt.Errorf("%s environment variable is not set.\n%s", tpdbAPIKeyEnvVar, apiKeySetupInstructions())
|
||||
|
|
@ -499,9 +494,9 @@ var versionCmd = &cobra.Command{
|
|||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("Goondex v0.1.0-dev5")
|
||||
fmt.Println("Features:")
|
||||
fmt.Println(" • TPDB integration with auto-import & bulk commands")
|
||||
fmt.Println(" • Adult Empire scraper (scenes & performers)")
|
||||
fmt.Println(" • Multi-source data merging")
|
||||
fmt.Println(" • TPDB commands temporarily disabled (Adult Empire-only mode)")
|
||||
fmt.Println(" • Multi-source data merging (when TPDB is re-enabled)")
|
||||
fmt.Println(" • Grid-based web UI with GX components")
|
||||
fmt.Println(" • Performer/studio/scene management")
|
||||
},
|
||||
|
|
@ -509,7 +504,7 @@ var versionCmd = &cobra.Command{
|
|||
|
||||
var performerSearchCmd = &cobra.Command{
|
||||
Use: "performer-search [query]",
|
||||
Short: "Search for performers (auto-fetches from TPDB if not in local database)",
|
||||
Short: "Search for performers (imports from Adult Empire if missing locally)",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
query := args[0]
|
||||
|
|
@ -527,55 +522,60 @@ var performerSearchCmd = &cobra.Command{
|
|||
return fmt.Errorf("search failed: %w", err)
|
||||
}
|
||||
|
||||
// If no local results, try fetching from TPDB
|
||||
// If no local results, pull the top Adult Empire match
|
||||
if len(performers) == 0 {
|
||||
fmt.Printf("No local results found. Searching TPDB for '%s'...\n", query)
|
||||
fmt.Printf("No local results found. Searching Adult Empire for '%s'...\n", query)
|
||||
|
||||
apiKey, err := getTPDBAPIKey()
|
||||
scraper, err := adultemp.NewScraper()
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ %s\n", err)
|
||||
return nil
|
||||
return fmt.Errorf("failed to create Adult Empire scraper: %w", err)
|
||||
}
|
||||
|
||||
scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
|
||||
tpdbPerformers, err := scraper.SearchPerformers(context.Background(), query)
|
||||
results, err := scraper.SearchPerformersByName(context.Background(), query)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ TPDB search failed: %v\n", err)
|
||||
fmt.Printf("⚠ Adult Empire search failed: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(tpdbPerformers) == 0 {
|
||||
fmt.Println("No performers found on TPDB either.")
|
||||
if len(results) == 0 {
|
||||
fmt.Println("No performers found on Adult Empire either.")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d performer(s) on TPDB. Fetching full details...\n\n", len(tpdbPerformers))
|
||||
fmt.Printf("Found %d performer(s) on Adult Empire. Importing the top match...\n\n", len(results))
|
||||
|
||||
// Import from TPDB with enriched data
|
||||
imported := 0
|
||||
for _, p := range tpdbPerformers {
|
||||
// Fetch full details for this performer
|
||||
fullPerformer, err := scraper.GetPerformerByID(context.Background(), p.SourceID)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ Failed to fetch details for %s: %v\n", p.Name, err)
|
||||
// Fall back to search result
|
||||
fullPerformer = &p
|
||||
}
|
||||
|
||||
if err := store.Create(fullPerformer); err != nil {
|
||||
fmt.Printf("⚠ Failed to import %s: %v\n", fullPerformer.Name, err)
|
||||
continue
|
||||
}
|
||||
imported++
|
||||
// Import only the top result to avoid wrong matches; use search-performer for manual selection
|
||||
top := results[0]
|
||||
performerData, err := scraper.ScrapePerformerByURL(context.Background(), top.URL)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ Failed to fetch Adult Empire details: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Search again to get the imported performers with their IDs
|
||||
performer := scraper.ConvertPerformerToModel(performerData)
|
||||
if err := store.Create(performer); err != nil {
|
||||
fmt.Printf("⚠ Failed to import %s: %v\n", performer.Name, err)
|
||||
} else {
|
||||
fmt.Printf("✓ Imported %s from Adult Empire\n", performer.Name)
|
||||
}
|
||||
|
||||
// Search again to get the imported performer with their ID
|
||||
performers, err = store.Search(query)
|
||||
if err != nil {
|
||||
return fmt.Errorf("search failed after import: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✓ Imported %d performer(s)\n\n", imported)
|
||||
if len(performers) == 0 {
|
||||
fmt.Println("No performers matched locally even after Adult Empire import.")
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(results) > 1 {
|
||||
fmt.Println("Tip: run 'goondex adultemp search-performer \"<name>\"' to pick a different match.")
|
||||
}
|
||||
|
||||
imported := 1
|
||||
fmt.Printf("\n✓ Imported %d performer(s)\n\n", imported)
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d performer(s):\n\n", len(performers))
|
||||
|
|
@ -916,7 +916,7 @@ var performerGetCmd = &cobra.Command{
|
|||
|
||||
var studioSearchCmd = &cobra.Command{
|
||||
Use: "studio-search [query]",
|
||||
Short: "Search for studios (auto-fetches from TPDB if not in local database)",
|
||||
Short: "Search for studios (local database only; TPDB disabled)",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
query := args[0]
|
||||
|
|
@ -933,49 +933,6 @@ var studioSearchCmd = &cobra.Command{
|
|||
return fmt.Errorf("search failed: %w", err)
|
||||
}
|
||||
|
||||
// If no local results, try fetching from TPDB
|
||||
if len(studios) == 0 {
|
||||
fmt.Printf("No local results found. Searching TPDB for '%s'...\n", query)
|
||||
|
||||
apiKey, err := getTPDBAPIKey()
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ %s\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
|
||||
tpdbStudios, err := scraper.SearchStudios(context.Background(), query)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ TPDB search failed: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(tpdbStudios) == 0 {
|
||||
fmt.Println("No studios found on TPDB either.")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d studio(s) on TPDB. Importing...\n\n", len(tpdbStudios))
|
||||
|
||||
// Import from TPDB
|
||||
imported := 0
|
||||
for _, s := range tpdbStudios {
|
||||
if err := store.Create(&s); err != nil {
|
||||
fmt.Printf("⚠ Failed to import %s: %v\n", s.Name, err)
|
||||
continue
|
||||
}
|
||||
imported++
|
||||
}
|
||||
|
||||
// Search again to get the imported studios with their IDs
|
||||
studios, err = store.Search(query)
|
||||
if err != nil {
|
||||
return fmt.Errorf("search failed after import: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✓ Imported %d studio(s)\n\n", imported)
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d studio(s):\n\n", len(studios))
|
||||
for _, s := range studios {
|
||||
fmt.Printf("ID: %d\n", s.ID)
|
||||
|
|
@ -1079,7 +1036,7 @@ var studioGetCmd = &cobra.Command{
|
|||
|
||||
var sceneSearchCmd = &cobra.Command{
|
||||
Use: "scene-search [query]",
|
||||
Short: "Search for scenes (auto-fetches from TPDB if not in local database)",
|
||||
Short: "Search for scenes (local database only; TPDB disabled)",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
query := args[0]
|
||||
|
|
@ -1096,55 +1053,6 @@ var sceneSearchCmd = &cobra.Command{
|
|||
return fmt.Errorf("search failed: %w", err)
|
||||
}
|
||||
|
||||
// If no local results, try fetching from TPDB
|
||||
if len(scenes) == 0 {
|
||||
fmt.Printf("No local results found. Searching TPDB for '%s'...\n", query)
|
||||
|
||||
apiKey, err := getTPDBAPIKey()
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ %s\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
|
||||
tpdbScenes, err := scraper.SearchScenes(context.Background(), query)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠ TPDB search failed: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(tpdbScenes) == 0 {
|
||||
fmt.Println("No scenes found on TPDB either.")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d scene(s) on TPDB. Importing (basic metadata only)...\n\n", len(tpdbScenes))
|
||||
|
||||
// Import scenes (simplified - just scene metadata, no relationships)
|
||||
imported := 0
|
||||
for _, sc := range tpdbScenes {
|
||||
// Clear relationships to avoid complexity in auto-import
|
||||
sc.Performers = nil
|
||||
sc.Tags = nil
|
||||
sc.Studio = nil
|
||||
sc.StudioID = nil
|
||||
|
||||
if err := store.Create(&sc); err != nil {
|
||||
fmt.Printf("⚠ Failed to import %s: %v\n", sc.Title, err)
|
||||
continue
|
||||
}
|
||||
imported++
|
||||
}
|
||||
|
||||
// Search again to get the imported scenes with their IDs
|
||||
scenes, err = store.Search(query)
|
||||
if err != nil {
|
||||
return fmt.Errorf("search failed after import: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✓ Imported %d scene(s) (use 'import scene' for full metadata with relationships)\n\n", imported)
|
||||
}
|
||||
|
||||
fmt.Printf("Found %d scene(s):\n\n", len(scenes))
|
||||
for _, sc := range scenes {
|
||||
fmt.Printf("ID: %d\n", sc.ID)
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@ sources:
|
|||
- name: "tpdb"
|
||||
baseURL: "https://api.theporndb.net"
|
||||
apiKey: "${TPDB_API_KEY}"
|
||||
enabled: true
|
||||
enabled: false # Temporarily disabled (Adult Empire-only mode)
|
||||
priority: 1
|
||||
options:
|
||||
includeMalePerformers: true
|
||||
skipMultipleMatches: true
|
||||
|
||||
- name: "ae"
|
||||
baseURL: "https://example-ae.site/api"
|
||||
baseURL: "https://www.adultempire.com"
|
||||
apiKey: "${AE_API_KEY}"
|
||||
enabled: false
|
||||
enabled: true
|
||||
priority: 2
|
||||
options:
|
||||
includeMalePerformers: true
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
Complete command-line interface documentation for Goondex.
|
||||
|
||||
> TPDB import and sync commands are temporarily disabled. Use Adult Empire commands (prefixed with `goondex adultemp ...`) to search and import new data.
|
||||
|
||||
## Global Flags
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -565,6 +565,30 @@ type APIResponse struct {
|
|||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
const tpdbEnabled = false
|
||||
const tpdbDisabledMessage = "TPDB integration is disabled. Use the Adult Empire CLI commands to import and enrich data for now."
|
||||
|
||||
func tpdbAPIKey() (string, error) {
|
||||
if !tpdbEnabled {
|
||||
return "", fmt.Errorf(tpdbDisabledMessage)
|
||||
}
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
return "", fmt.Errorf("TPDB_API_KEY not configured")
|
||||
}
|
||||
|
||||
return apiKey, nil
|
||||
}
|
||||
|
||||
func writeTPDBError(w http.ResponseWriter, err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: err.Error()})
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Server) handleAPIImportPerformer(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
|
|
@ -579,9 +603,8 @@ func (s *Server) handleAPIImportPerformer(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -634,9 +657,8 @@ func (s *Server) handleAPIImportStudio(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -684,9 +706,8 @@ func (s *Server) handleAPIImportScene(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -773,9 +794,8 @@ func (s *Server) handleAPISync(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
json.NewDecoder(r.Body).Decode(&req)
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -801,6 +821,10 @@ func (s *Server) handleAPISync(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func (s *Server) handleAPISyncStatus(w http.ResponseWriter, r *http.Request) {
|
||||
if writeTPDBError(w, fmt.Errorf(tpdbDisabledMessage)) {
|
||||
return
|
||||
}
|
||||
|
||||
scraper := tpdb.NewScraper("https://api.theporndb.net", "")
|
||||
service := sync.NewService(s.db, scraper)
|
||||
|
||||
|
|
@ -829,9 +853,8 @@ func (s *Server) handleAPIBulkImportAll(w http.ResponseWriter, r *http.Request)
|
|||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -859,9 +882,8 @@ func (s *Server) handleAPIBulkImportPerformers(w http.ResponseWriter, r *http.Re
|
|||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -889,9 +911,8 @@ func (s *Server) handleAPIBulkImportStudios(w http.ResponseWriter, r *http.Reque
|
|||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -919,9 +940,8 @@ func (s *Server) handleAPIBulkImportScenes(w http.ResponseWriter, r *http.Reques
|
|||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if writeTPDBError(w, err) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -947,9 +967,9 @@ func (s *Server) handleAPIBulkImportPerformersProgress(w http.ResponseWriter, r
|
|||
w.Header().Set("Connection", "keep-alive")
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
fmt.Fprintf(w, "data: {\"error\": \"TPDB_API_KEY not configured\"}\n\n")
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "data: {\"error\": \"%s\"}\n\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -990,9 +1010,9 @@ func (s *Server) handleAPIBulkImportStudiosProgress(w http.ResponseWriter, r *ht
|
|||
w.Header().Set("Connection", "keep-alive")
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
fmt.Fprintf(w, "data: {\"error\": \"TPDB_API_KEY not configured\"}\n\n")
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "data: {\"error\": \"%s\"}\n\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1033,9 +1053,9 @@ func (s *Server) handleAPIBulkImportScenesProgress(w http.ResponseWriter, r *htt
|
|||
w.Header().Set("Connection", "keep-alive")
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
apiKey := os.Getenv("TPDB_API_KEY")
|
||||
if apiKey == "" {
|
||||
fmt.Fprintf(w, "data: {\"error\": \"TPDB_API_KEY not configured\"}\n\n")
|
||||
apiKey, err := tpdbAPIKey()
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "data: {\"error\": \"%s\"}\n\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -507,6 +507,23 @@ main.container {
|
|||
color: var(--color-brand);
|
||||
}
|
||||
|
||||
.empty-import-actions {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.empty-import-actions .action-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
justify-content: center;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.empty-import-actions .hint {
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
/* Detail views */
|
||||
.breadcrumb {
|
||||
margin-bottom: 1.5rem;
|
||||
|
|
|
|||
|
|
@ -24,14 +24,15 @@
|
|||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="2.1896304"
|
||||
inkscape:cx="898.55348"
|
||||
inkscape:cy="158.70258"
|
||||
inkscape:cx="884.39583"
|
||||
inkscape:cy="34.252356"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1048"
|
||||
inkscape:window-height="1011"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1">
|
||||
inkscape:current-layer="g9"
|
||||
showgrid="false">
|
||||
<inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
|
|
@ -48,6 +49,20 @@
|
|||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" />
|
||||
<inkscape:grid
|
||||
id="grid3"
|
||||
units="px"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingx="1"
|
||||
spacingy="1"
|
||||
empcolor="#0099e5"
|
||||
empopacity="0.30196078"
|
||||
color="#0099e5"
|
||||
opacity="0.14901961"
|
||||
empspacing="5"
|
||||
enabled="true"
|
||||
visible="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1" />
|
||||
|
|
@ -58,29 +73,80 @@
|
|||
<path
|
||||
id="path26"
|
||||
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#ff5fa2;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
|
||||
d="m 89.6071,50.4885 c -23.10416,0 -39.60743,16.69024 -39.60743,39.51149 0,22.82124 16.50328,39.51151 39.60743,39.51151 22.06683,0 39.04336,-15.65212 39.04336,-37.90755 v -3.39592 h -40.6473 v 8.57996 h 30.08354 c -1.13163,13.67388 -12.63408,23.85962 -28.0997,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.44569,-30.45956 29.89167,-30.45956 12.91947,0 23.57566,7.07122 26.68766,16.59581 h 10.75176 C 123.27385,61.70793 108.84487,50.48851 89.6071,50.4885 Z m 83.73122,0 c -22.91553,0 -39.79544,16.69024 -39.79544,39.51149 0,22.82124 16.97586,39.51151 39.89139,39.51151 11.29137,0 21.11695,-4.05219 28.18029,-10.89376 7.08654,6.84157 16.93497,10.89376 28.22632,10.89376 22.91556,0 39.79544,-16.69026 39.79544,-39.51151 0,-22.82124 -16.97196,-39.51149 -39.88752,-39.51149 -11.29138,0 -21.11698,4.05217 -28.18029,10.89376 -7.08655,-6.84159 -16.9388,-10.89376 -28.23019,-10.89376 z m 156.5227,1.32 v 59.3152 L 284.12556,52.28048 h -9.23996 v 75.53498 h 9.89995 V 68.50023 l 45.73537,58.84324 h 9.3359 V 51.80846 Z m 18.51061,0.47198 v 75.53499 h 26.7796 c 26.0276,0 41.1193,-15.1812 41.1193,-37.71954 0,-0.52548 -0.01,-1.04807 -0.027,-1.56558 -0.041,-1.2646 -0.1283,-2.50346 -0.2647,-3.71824 h -0.01 c -2.2059,-19.60648 -16.8839,-32.53165 -40.82,-32.53165 z m 74.6754,0 v 75.53499 h 54.5072 v -8.77182 h -44.6073 V 93.5839 h 40.4593 v -8.77179 h -40.4593 V 61.04843 h 43.7593 v -8.76795 z m 60.6582,0 26.3116,37.34349 -27.2555,38.1915 h 11.5998 l 21.9717,-30.93156 21.8797,30.93156 h 11.7878 l -27.3476,-38.47545 26.4036,-37.05954 h -11.5039 l -21.0277,29.79956 -20.8436,-29.79956 z m -310.36688,7.25996 c 9.05961,0 16.87419,3.48312 22.25184,9.3704 -3.60762,5.99921 -5.63683,13.17524 -5.63683,21.08915 0,7.89949 2.03062,15.06595 5.64066,21.05848 -5.36636,5.89579 -13.15175,9.40112 -22.15972,9.40112 -17.2574,0 -29.98763,-12.73069 -29.98763,-30.4596 0,-17.8232 12.63428,-30.45955 29.89168,-30.45955 z m 56.41046,0 c 17.25739,0 29.98763,12.63635 29.98763,30.45955 0,17.72891 -12.73244,30.45958 -29.89553,30.45958 -9.05209,0 -16.85927,-3.50401 -22.23648,-9.39344 3.59921,-5.99469 5.62531,-13.16204 5.62531,-21.06614 0,-7.91897 -2.04458,-15.09915 -5.67135,-21.10067 5.35263,-5.88029 13.13673,-9.35888 22.19042,-9.35888 z m 128.52272,1.60391 h 17.1637 c 17.2271,0 28.4182,8.55424 30.4864,23.66776 h -23.3339 v 8.77179 h 23.5335 c 0.098,-1.12825 0.1497,-2.29113 0.1497,-3.48797 0,1.19665 -0.052,2.35989 -0.1497,3.48797 -1.4059,16.20741 -12.7883,25.27173 -30.686,25.27173 h -17.1637 z M 201.58388,79.12157 c 1.1334,3.32559 1.74589,6.97798 1.74589,10.87842 0,3.87376 -0.60919,7.50886 -1.73821,10.82471 -1.13003,-3.31585 -1.73825,-6.95095 -1.73825,-10.82471 0,-3.90044 0.60423,-7.55286 1.73057,-10.87842 z m -28.99762,21.55347 c -2.1037,1.2e-4 -3.80849,1.70661 -3.80647,3.81032 9e-5,2.10223 1.70425,3.80637 3.80647,3.80649 2.10221,-1.2e-4 3.80637,-1.70426 3.80651,-3.80649 0.002,-2.10371 -1.70281,-3.8102 -3.80651,-3.81032 z m 56.4642,0 c -2.10372,1.2e-4 -3.80849,1.70661 -3.80651,3.81032 1.3e-4,2.10223 1.70425,3.80637 3.80651,3.80649 2.10222,-1.2e-4 3.80637,-1.70426 3.80649,-3.80649 0.002,-2.10371 -1.70279,-3.8102 -3.80649,-3.81032 z" />
|
||||
d="m 89.6071,50.4885 c -23.10416,0 -39.60743,16.69024 -39.60743,39.51149 0,22.82124 16.50328,39.51151 39.60743,39.51151 22.06683,0 39.04336,-15.65212 39.04336,-37.90755 v -3.39592 h -40.6473 v 8.57996 h 30.08354 c -1.13163,13.67388 -12.63408,23.85962 -28.0997,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.44569,-30.45956 29.89167,-30.45956 12.91947,0 23.57566,7.07122 26.68766,16.59581 h 10.75176 C 123.27385,61.70793 108.84487,50.48851 89.6071,50.4885 Z m 240.25392,1.32 v 59.3152 L 284.12556,52.28048 h -9.23996 v 75.53498 h 9.89995 V 68.50023 l 45.73537,58.84324 h 9.3359 V 51.80846 Z m 18.51061,0.47198 v 75.53499 h 26.7796 c 26.0276,0 41.1193,-15.1812 41.1193,-37.71954 0,-0.52548 -0.01,-1.04807 -0.027,-1.56558 -0.041,-1.2646 -0.1283,-2.50346 -0.2647,-3.71824 h -0.01 c -2.2059,-19.60648 -16.8839,-32.53165 -40.82,-32.53165 z m 74.6754,0 v 75.53499 h 54.5072 v -8.77182 h -44.6073 V 93.5839 h 40.4593 v -8.77179 h -40.4593 V 61.04843 h 43.7593 v -8.76795 z m 60.6582,0 26.3116,37.34349 -27.2555,38.1915 h 11.5998 l 21.9717,-30.93156 21.8797,30.93156 h 11.7878 l -27.3476,-38.47545 26.4036,-37.05954 h -11.5039 l -21.0277,29.79956 -20.8436,-29.79956 z m -125.4337,8.86387 h 17.1637 c 17.2271,0 28.4182,8.55424 30.4864,23.66776 h -23.3339 v 8.77179 h 23.5335 c 0.098,-1.12825 0.1497,-2.29113 0.1497,-3.48797 0,1.19665 -0.052,2.35989 -0.1497,3.48797 -1.4059,16.20741 -12.7883,25.27173 -30.686,25.27173 h -17.1637 z"
|
||||
sodipodi:nodetypes="ssssccccsssccscccccccccccccsscccsccccccccccccccccccccccccccccsccccccscc" />
|
||||
<path
|
||||
d="m 206.54093,52.264773 h -9.90177 v 75.536347 h 9.90177 z"
|
||||
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';display:none;fill:#808000;stroke-width:7.85855"
|
||||
id="path3" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="OG_Titty"
|
||||
style="display:none">
|
||||
<path
|
||||
d="m 173.33832,50.4885 c -22.91553,0 -39.79544,16.69024 -39.79544,39.51149 0,22.82124 16.97586,39.51151 39.89139,39.51151 11.29137,0 21.11695,-4.05219 28.18029,-10.89376 7.08654,6.84157 16.93497,10.89376 28.22632,10.89376 22.91556,0 39.79544,-16.69026 39.79544,-39.51151 0,-22.82124 -16.97196,-39.51149 -39.88752,-39.51149 -11.29138,0 -21.11698,4.05217 -28.18029,10.89376 -7.08655,-6.84159 -16.9388,-10.89376 -28.23019,-10.89376 z m 3e-5,9.05194 c 9.05961,0 16.87419,3.48312 22.25184,9.3704 -3.60762,5.99921 -5.63683,13.17524 -5.63683,21.08915 0,7.89949 2.03062,15.06595 5.64066,21.05848 -5.36636,5.89579 -13.15175,9.40112 -22.15972,9.40112 -17.2574,0 -29.98763,-12.73069 -29.98763,-30.4596 0,-17.8232 12.63428,-30.45955 29.89168,-30.45955 z m 56.41046,0 c 17.25739,0 29.98763,12.63635 29.98763,30.45955 0,17.72891 -12.73244,30.45958 -29.89553,30.45958 -9.05209,0 -16.85927,-3.50401 -22.23648,-9.39344 3.59921,-5.99469 5.62531,-13.16204 5.62531,-21.06614 0,-7.91897 -2.04458,-15.09915 -5.67135,-21.10067 5.35263,-5.88029 13.13673,-9.35888 22.19042,-9.35888 z m -28.16493,19.58113 c 1.1334,3.32559 1.74589,6.97798 1.74589,10.87842 0,3.87376 -0.60919,7.50886 -1.73821,10.82471 -1.13003,-3.31585 -1.73825,-6.95095 -1.73825,-10.82471 0,-3.90044 0.60423,-7.55286 1.73057,-10.87842 z m -28.99762,21.55347 c -2.1037,1.2e-4 -3.80849,1.70661 -3.80647,3.81032 9e-5,2.10223 1.70425,3.80637 3.80647,3.80649 2.10221,-1.2e-4 3.80637,-1.70426 3.80651,-3.80649 0.002,-2.10371 -1.70281,-3.8102 -3.80651,-3.81032 z m 56.4642,0 c -2.10372,1.2e-4 -3.80849,1.70661 -3.80651,3.81032 1.3e-4,2.10223 1.70425,3.80637 3.80651,3.80649 2.10222,-1.2e-4 3.80637,-1.70426 3.80649,-3.80649 0.002,-2.10371 -1.70279,-3.8102 -3.80649,-3.81032 z"
|
||||
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#ff5fa2;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
|
||||
id="path1-6"
|
||||
sodipodi:nodetypes="ssscssscsscscsssssscscscscsccccccccccc" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="Titty"
|
||||
style="display:none">
|
||||
<path
|
||||
d="m 173.43286,129.49856 c 22.91553,0 39.79568,-16.69155 39.79568,-39.512767 0,-22.82121 -16.97446,-39.512769 -39.88998,-39.512769 -22.91552,0 -39.79568,16.691559 -39.79568,39.512769 0,22.821217 16.97447,39.512767 39.88998,39.512767 z m 0,-9.05304 c -17.25736,0 -29.98821,-12.73084 -29.98821,-30.459727 0,-17.823182 12.63655,-30.459726 29.89391,-30.459726 17.25737,0 29.98822,12.636544 29.98822,30.459726 0,17.728887 -12.73085,30.459727 -29.89392,30.459727 z"
|
||||
id="text3"
|
||||
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855"
|
||||
aria-label="OOI"
|
||||
sodipodi:nodetypes="ssssssssss" />
|
||||
<path
|
||||
d="m 229.84152,129.49856 c 22.91553,0 39.79567,-16.69155 39.79567,-39.512767 0,-22.82121 -16.97445,-39.512769 -39.88998,-39.512769 -22.91551,0 -39.79567,16.691559 -39.79567,39.512769 0,22.821217 16.97446,39.512767 39.88998,39.512767 z m 0,-9.05304 c -17.25736,0 -29.98821,-12.73084 -29.98821,-30.459727 0,-17.823182 12.63654,-30.459726 29.8939,-30.459726 17.25737,0 29.98822,12.636544 29.98822,30.459726 0,17.728887 -12.73085,30.459727 -29.89391,30.459727 z"
|
||||
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855"
|
||||
id="path1-5"
|
||||
sodipodi:nodetypes="ssssssssss" />
|
||||
<path
|
||||
d="m 206.54093,52.264773 h -9.90177 v 75.536347 h 9.90177 z"
|
||||
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855"
|
||||
id="path1-10" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Layer 2">
|
||||
<path
|
||||
d="m 699.60709,50.4885 c -23.10416,0 -39.60742,16.69024 -39.60742,39.51149 0,22.82124 16.50328,39.51151 39.60742,39.51151 22.06684,0 39.04337,-15.65212 39.04337,-37.90755 v -3.39592 h -40.64731 v 8.57996 h 30.08355 c -1.13164,13.67388 -12.63408,23.85962 -28.09971,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.4457,-30.45956 29.89167,-30.45956 12.91948,0 23.57567,7.07122 26.68767,16.59581 h 10.75176 C 733.27385,61.70793 718.84487,50.48851 699.60709,50.4885 Z m 83.73123,0 c -22.91553,0 -39.79545,16.69024 -39.79545,39.51149 0,22.82124 16.97586,39.51151 39.89139,39.51151 11.29137,0 21.11696,-4.05219 28.18029,-10.89376 7.08654,6.84157 16.93497,10.89376 28.22632,10.89376 22.91556,0 39.79545,-16.69026 39.79545,-39.51151 0,-22.82124 -16.97197,-39.51149 -39.88752,-39.51149 -11.29139,0 -21.11698,4.05217 -28.18029,10.89376 C 804.48196,54.54067 794.6297,50.4885 783.33832,50.4885 Z m 156.5227,1.32 v 59.3152 L 894.12555,52.28048 h -9.23995 v 75.53498 h 9.89995 V 68.50023 l 45.73536,58.84324 h 9.3359 V 51.80846 Z m -156.52268,7.73194 c 9.05962,0 16.87419,3.48312 22.25184,9.3704 -3.60761,5.99921 -5.63683,13.17524 -5.63683,21.08915 0,7.89949 2.03062,15.06595 5.64066,21.05848 -5.36635,5.89579 -13.15175,9.40112 -22.15972,9.40112 -17.25739,0 -29.98762,-12.73069 -29.98762,-30.4596 0,-17.8232 12.63428,-30.45955 29.89167,-30.45955 z m 56.41047,0 c 17.25739,0 29.98763,12.63635 29.98763,30.45955 0,17.72891 -12.73244,30.45958 -29.89553,30.45958 -9.0521,0 -16.85928,-3.50401 -22.23649,-9.39344 3.59921,-5.99469 5.62531,-13.16204 5.62531,-21.06614 0,-7.91897 -2.04458,-15.09915 -5.67134,-21.10067 5.35262,-5.88029 13.13673,-9.35888 22.19042,-9.35888 z m -28.16493,19.58113 c 1.13339,3.32559 1.74589,6.97798 1.74589,10.87842 0,3.87376 -0.6092,7.50886 -1.73822,10.82471 -1.13002,-3.31585 -1.73825,-6.95095 -1.73825,-10.82471 0,-3.90044 0.60423,-7.55286 1.73058,-10.87842 z"
|
||||
d="m 699.60709,50.4885 c -23.10416,0 -39.60742,16.69024 -39.60742,39.51149 0,22.82124 16.50328,39.51151 39.60742,39.51151 22.06684,0 39.04337,-15.65212 39.04337,-37.90755 v -3.39592 h -40.64731 v 8.57996 h 30.08355 c -1.13164,13.67388 -12.63408,23.85962 -28.09971,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.4457,-30.45956 29.89167,-30.45956 12.91948,0 23.57567,7.07122 26.68767,16.59581 h 10.75176 C 733.27385,61.70793 718.84487,50.48851 699.60709,50.4885 Z m 240.25393,1.32 v 59.3152 L 894.12555,52.28048 h -9.23995 v 75.53498 h 9.89995 V 68.50023 l 45.73536,58.84324 h 9.3359 V 51.80846 Z"
|
||||
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#483737;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="ssssccccsssccsssscssscscccccccccccscscsssssscscscscsc" />
|
||||
sodipodi:nodetypes="ssssccccsssccsccccccccccc" />
|
||||
<path
|
||||
id="path2"
|
||||
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#8a6f91;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
|
||||
d="m 958.37162,52.28048 v 75.53499 h 26.7796 c 26.02758,0 41.11928,-15.1812 41.11928,-37.71954 0,-0.52548 -0.01,-1.04807 -0.027,-1.56558 -0.041,-1.2646 -0.1283,-2.50346 -0.2647,-3.71824 h -0.01 c -2.2059,-19.60648 -16.8839,-32.53165 -40.81997,-32.53165 z m 9.8999,8.86387 h 17.16371 c 17.22707,0 28.41817,8.55424 30.48637,23.66776 h -23.33388 v 8.77179 h 23.53348 c 0.098,-1.12825 0.1497,-2.29113 0.1497,-3.48797 0,1.19665 -0.052,2.35989 -0.1497,3.48797 -1.4059,16.20741 -12.7883,25.27173 -30.68597,25.27173 h -17.16371 z"
|
||||
sodipodi:nodetypes="ccsscccsccsccccccscc" />
|
||||
</g>
|
||||
<path
|
||||
d="m 782.58626,100.67504 c -2.10371,1.2e-4 -3.8085,1.70661 -3.80647,3.81032 9e-5,2.10223 1.70425,3.80637 3.80647,3.80649 2.10221,-1.2e-4 3.80636,-1.70426 3.8065,-3.80649 0.002,-2.10371 -1.70281,-3.8102 -3.8065,-3.81032 z m 56.46419,0 c -2.10372,1.2e-4 -3.80848,1.70661 -3.8065,3.81032 1.2e-4,2.10223 1.70425,3.80637 3.8065,3.80649 2.10222,-1.2e-4 3.80637,-1.70426 3.80649,-3.80649 0.002,-2.10371 -1.70278,-3.8102 -3.80649,-3.81032 z"
|
||||
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#8a6f91;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
|
||||
id="path1-9" />
|
||||
<path
|
||||
d="m 1033.047,52.28048 v 75.53499 h 54.5072 v -8.77182 h -44.6073 V 93.5839 h 40.4593 v -8.77179 h -40.4593 V 61.04843 h 43.7593 v -8.76795 z m 60.6582,0 26.3116,37.34349 -27.2555,38.1915 h 11.5998 l 21.9717,-30.93156 21.8797,30.93156 h 11.7878 l -27.3476,-38.47545 26.4036,-37.05954 h -11.5039 l -21.0277,29.79956 -20.8436,-29.79956 z"
|
||||
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#ff5fa2;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
|
||||
id="path1-1" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="g9"
|
||||
inkscape:label="Titty">
|
||||
<path
|
||||
id="path13"
|
||||
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855;fill:#ff5fa2;fill-opacity:1"
|
||||
d="M 173.33789 50.472656 C 150.42237 50.472656 133.54297 67.165118 133.54297 89.986328 C 133.54297 112.80755 150.51808 129.49805 173.43359 129.49805 C 184.72527 129.49805 194.54994 125.44543 201.61328 118.60352 C 208.69985 125.44543 218.55013 129.49805 229.8418 129.49805 C 252.75733 129.49805 269.63672 112.80755 269.63672 89.986328 C 269.63672 67.165118 252.66358 50.472656 229.74805 50.472656 C 218.45638 50.472656 208.62975 54.525269 201.56641 61.367188 C 194.47983 54.525267 184.62956 50.472656 173.33789 50.472656 z M 173.33789 59.525391 C 182.39788 59.525391 190.21021 63.008763 195.58789 68.896484 C 198.21228 71.769779 200.25728 75.215888 201.58398 79.109375 C 202.9042 75.210676 204.94121 71.760371 207.55859 68.884766 C 212.91125 63.004031 220.69398 59.525391 229.74805 59.525391 C 247.00542 59.525391 259.73633 72.163146 259.73633 89.986328 C 259.73633 107.71522 247.00486 120.44531 229.8418 120.44531 C 220.78934 120.44531 212.98272 116.94263 207.60547 111.05273 C 204.97114 108.16726 202.91866 104.70856 201.58984 100.80859 C 200.2638 104.70381 198.21994 108.15962 195.5957 111.04297 C 190.22932 116.93923 182.44196 120.44531 173.43359 120.44531 C 156.17623 120.44531 143.44531 107.71522 143.44531 89.986328 C 143.44531 72.163146 156.08053 59.525391 173.33789 59.525391 z M 172.58594 100.67578 C 170.48224 100.6759 168.77728 102.38262 168.7793 104.48633 C 168.77939 106.58856 170.48372 108.2909 172.58594 108.29102 C 174.68815 108.2909 176.39244 106.58856 176.39258 104.48633 C 176.39458 102.38262 174.68964 100.6759 172.58594 100.67578 z M 229.05078 100.67578 C 226.94706 100.6759 225.24216 102.38262 225.24414 104.48633 C 225.24427 106.58856 226.94852 108.2909 229.05078 108.29102 C 231.153 108.2909 232.8573 106.58856 232.85742 104.48633 C 232.85942 102.38262 231.15448 100.6759 229.05078 100.67578 z " />
|
||||
<path
|
||||
id="path19"
|
||||
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';fill:#483737;fill-opacity:1;stroke-width:7.85855"
|
||||
d="m 783.33779,50.472656 c -22.91552,0 -39.79492,16.692462 -39.79492,39.513672 0,22.821222 16.97511,39.511722 39.89062,39.511722 11.29168,0 21.11635,-4.05262 28.17969,-10.89453 7.08657,6.84191 16.93685,10.89453 28.22852,10.89453 22.91553,0 39.79492,-16.6905 39.79492,-39.511722 0,-22.82121 -16.97314,-39.513672 -39.88867,-39.513672 -11.29167,0 -21.1183,4.052613 -28.18164,10.894532 -7.08658,-6.841921 -16.93685,-10.894532 -28.22852,-10.894532 z m 0,9.052735 c 9.05999,0 16.87232,3.483372 22.25,9.371093 2.62439,2.873295 4.66939,6.319404 5.99609,10.212891 1.32022,-3.898699 3.35723,-7.349004 5.97461,-10.224609 5.35266,-5.880735 13.13539,-9.359375 22.18946,-9.359375 17.25737,0 29.98828,12.637755 29.98828,30.460937 0,17.728892 -12.73147,30.458982 -29.89453,30.458982 -9.05246,0 -16.85908,-3.50268 -22.23633,-9.39258 -2.63433,-2.88547 -4.68681,-6.34417 -6.01563,-10.24414 -1.32604,3.89522 -3.3699,7.35103 -5.99414,10.23438 -5.36638,5.89626 -13.15374,9.40234 -22.16211,9.40234 -17.25736,0 -29.98828,-12.73009 -29.98828,-30.458982 0,-17.823182 12.63522,-30.460937 29.89258,-30.460937 z"
|
||||
sodipodi:nodetypes="ssscssscssscssssscssss" />
|
||||
<path
|
||||
d="m 782.58584,100.67578 c -2.1037,1.2e-4 -3.80866,1.70684 -3.80664,3.81055 9e-5,2.10223 1.70442,3.80457 3.80664,3.80469 2.10221,-1.2e-4 3.8065,-1.70246 3.80664,-3.80469 0.002,-2.10371 -1.70294,-3.81043 -3.80664,-3.81055 z m 56.46484,0 c -2.10372,1.2e-4 -3.80862,1.70684 -3.80664,3.81055 1.3e-4,2.10223 1.70438,3.80457 3.80664,3.80469 2.10222,-1.2e-4 3.80652,-1.70246 3.80664,-3.80469 0.002,-2.10371 -1.70294,-3.81043 -3.80664,-3.81055 z"
|
||||
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';fill:#8a6f91;fill-opacity:1;stroke-width:7.85855"
|
||||
id="path1-52" />
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 14 KiB |
BIN
internal/web/static/img/logo/Goondex_LOGO.png
Normal file
BIN
internal/web/static/img/logo/Goondex_LOGO.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
internal/web/static/img/logo/Goondex_LOGO2.png
Normal file
BIN
internal/web/static/img/logo/Goondex_LOGO2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -244,10 +244,37 @@ async function bulkImportScenes() {
|
|||
};
|
||||
}
|
||||
|
||||
function bulkImportMovies() {
|
||||
alert('Bulk movie import is not implemented yet. Use the Adult Empire CLI to scrape movies individually for now.');
|
||||
}
|
||||
|
||||
function toggleFilterbar() {
|
||||
document.getElementById('filterbar').classList.toggle('open');
|
||||
}
|
||||
|
||||
function showTPDBDisabled() {
|
||||
alert('TPDB import/sync is temporarily disabled. Use Adult Empire CLI commands instead:\n\n' +
|
||||
' ./goondex adultemp search-performer "Name"\n' +
|
||||
' ./goondex adultemp scrape-performer <url>\n' +
|
||||
' ./goondex adultemp search-scene "Title"\n' +
|
||||
' ./goondex adultemp scrape-scene <url>');
|
||||
}
|
||||
|
||||
function scrollToAEImport() {
|
||||
const section = document.getElementById('ae-import');
|
||||
if (section) {
|
||||
section.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
alert('Copied to clipboard:\n' + text);
|
||||
}).catch(() => {
|
||||
alert('Could not copy. Please copy manually:\n' + text);
|
||||
});
|
||||
}
|
||||
|
||||
function applyFilters() {
|
||||
// Hook for your search/filter logic
|
||||
console.log("Applying filters…");
|
||||
|
|
|
|||
|
|
@ -93,16 +93,16 @@
|
|||
<!-- HERO -->
|
||||
<section class="hero-section">
|
||||
<h1 class="hero-title">Welcome to Goondex</h1>
|
||||
<p class="hero-subtitle">Your professional adult media indexer powered by ThePornDB</p>
|
||||
<p class="hero-subtitle">Adult Empire-first indexer (TPDB temporarily disabled)</p>
|
||||
|
||||
<div class="hero-actions">
|
||||
<button class="btn" onclick="openModal('import-all-modal')">
|
||||
Get Started
|
||||
<button class="btn" onclick="scrollToAEImport()">
|
||||
Get Started (Adult Empire)
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
|
||||
<button class="btn-secondary" onclick="openModal('sync-modal')">
|
||||
Sync Data
|
||||
<button class="btn-secondary" onclick="showTPDBDisabled()">
|
||||
TPDB Sync (Disabled)
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -126,8 +126,8 @@
|
|||
</div>
|
||||
<div class="stat-actions">
|
||||
<a href="/performers" class="stat-link">View all →</a>
|
||||
<button class="btn-small" onclick="bulkImportPerformers()">
|
||||
Import All
|
||||
<button class="btn-small" onclick="scrollToAEImport()">
|
||||
Import via CLI
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -142,8 +142,8 @@
|
|||
</div>
|
||||
<div class="stat-actions">
|
||||
<a href="/studios" class="stat-link">View all →</a>
|
||||
<button class="btn-small" onclick="bulkImportStudios()">
|
||||
Import All
|
||||
<button class="btn-small" onclick="scrollToAEImport()">
|
||||
Import via CLI
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -158,8 +158,8 @@
|
|||
</div>
|
||||
<div class="stat-actions">
|
||||
<a href="/scenes" class="stat-link">View all →</a>
|
||||
<button class="btn-small" onclick="bulkImportScenes()">
|
||||
Import All
|
||||
<button class="btn-small" onclick="scrollToAEImport()">
|
||||
Import via CLI
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -180,51 +180,37 @@
|
|||
|
||||
<!-- IMPORT SECTION -->
|
||||
<section class="import-section">
|
||||
<h3>Import from ThePornDB</h3>
|
||||
<h3 id="ae-import">Import from Adult Empire (CLI)</h3>
|
||||
<p class="help-text">
|
||||
Import ALL data from ThePornDB. This downloads performers, studios, scenes, and metadata.
|
||||
TPDB bulk import is temporarily disabled. Use the Adult Empire CLI to seed your library with high-quality mainstream data:
|
||||
</p>
|
||||
|
||||
<div class="import-buttons">
|
||||
<button class="btn" onclick="openModal('import-all-modal')">
|
||||
Import Everything
|
||||
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp search-performer \"Name\"')">
|
||||
Copy: Search Performer
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
|
||||
<button class="btn-secondary" onclick="bulkImportPerformers()">
|
||||
Import All Performers
|
||||
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp scrape-performer <url>')">
|
||||
Copy: Import Performer
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
|
||||
<button class="btn-secondary" onclick="bulkImportStudios()">
|
||||
Import All Studios
|
||||
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp search-scene \"Title\"')">
|
||||
Copy: Search Scene
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
|
||||
<button class="btn-secondary" onclick="bulkImportScenes()">
|
||||
Import All Scenes
|
||||
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp scrape-scene <url>')">
|
||||
Copy: Import Scene
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="help-text search-help">Or search for specific items:</p>
|
||||
<p class="help-text">
|
||||
Movies: scraper not finished yet. Use scene/performer imports for now.
|
||||
</p>
|
||||
|
||||
<div class="import-buttons">
|
||||
<button class="btn-secondary" onclick="openModal('search-performer-modal')">
|
||||
Search Performer
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
|
||||
<button class="btn-secondary" onclick="openModal('search-studio-modal')">
|
||||
Search Studio
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
|
||||
<button class="btn-secondary" onclick="openModal('search-scene-modal')">
|
||||
Search Scene
|
||||
<div class="hoverEffect"><div></div></div>
|
||||
</button>
|
||||
</div>
|
||||
<p class="help-text">
|
||||
Bulk “Import All” buttons will stay disabled until an Adult Empire bulk flow is available.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -65,11 +65,19 @@
|
|||
{{else}}
|
||||
<div class="empty-state">
|
||||
<p>No performers found.</p>
|
||||
{{if .Query}}
|
||||
<p>Try a different search term or <a href="/performers">view all performers</a>.</p>
|
||||
{{else}}
|
||||
<p>Import performers using the dashboard or CLI: <code>./goondex import performer "name"</code></p>
|
||||
{{end}}
|
||||
<div class="empty-import-actions">
|
||||
<p class="hint">Kick off a bulk import to seed your library.</p>
|
||||
<div class="action-buttons">
|
||||
<button type="button" class="btn" onclick="showTPDBDisabled()">Import all performers</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="showTPDBDisabled()">Import all studios</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="showTPDBDisabled()">Import all scenes</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="bulkImportMovies()">Import all movies</button>
|
||||
</div>
|
||||
<p class="hint">
|
||||
Bulk import currently targets TPDB endpoints (disabled). Adult Empire bulk import will be added soon.
|
||||
For Adult Empire now, use CLI to pick targets: <code>./goondex adultemp search-performer "Name"</code> then <code>./goondex adultemp scrape-performer <url></code>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</main>
|
||||
|
|
|
|||
1956
package-lock.json
generated
1956
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -1,4 +1,11 @@
|
|||
{
|
||||
"name": "goondex",
|
||||
"version": "0.1.0-dev5",
|
||||
"description": "Goondex web development environment",
|
||||
"scripts": {
|
||||
"dev": "air",
|
||||
"build": "go build -o ./bin/goondex ./cmd/goondex"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.3.8"
|
||||
}
|
||||
|
|
|
|||
16
scripts/build.sh
Executable file
16
scripts/build.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
source "$ROOT/scripts/env.sh"
|
||||
|
||||
GO_BUILD_FLAGS=${GO_BUILD_FLAGS:-"-v"}
|
||||
if [[ "${QUIET:-0}" == "1" ]]; then
|
||||
GO_BUILD_FLAGS=""
|
||||
fi
|
||||
|
||||
mkdir -p "$ROOT/bin"
|
||||
echo "Building Goondex (Adult Empire-only mode)..."
|
||||
echo "go build ${GO_BUILD_FLAGS} -o $ROOT/bin/goondex $ROOT/cmd/goondex"
|
||||
go build ${GO_BUILD_FLAGS} -o "$ROOT/bin/goondex" "$ROOT/cmd/goondex"
|
||||
echo "Built: $ROOT/bin/goondex"
|
||||
15
scripts/env.sh
Executable file
15
scripts/env.sh
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
# Source this to pin Go caches inside the repo (avoids home-level permission issues).
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
||||
echo "Source this script: source scripts/env.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
export GOPATH="$ROOT/tmp/go"
|
||||
export GOMODCACHE="$GOPATH/pkg/mod"
|
||||
export GOCACHE="$ROOT/tmp/.gocache"
|
||||
|
||||
mkdir -p "$ROOT/tmp/go" "$ROOT/tmp/.gocache"
|
||||
15
scripts/run-web.sh
Executable file
15
scripts/run-web.sh
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
source "$ROOT/scripts/env.sh"
|
||||
|
||||
ADDR="${ADDR:-localhost:8080}"
|
||||
|
||||
if [[ ! -x "$ROOT/bin/goondex" ]]; then
|
||||
echo "Binary not found; building first..."
|
||||
"$ROOT/scripts/build.sh"
|
||||
fi
|
||||
|
||||
echo "Starting Goondex web UI on http://$ADDR"
|
||||
"$ROOT/bin/goondex" web --addr "$ADDR"
|
||||
16
scripts/run.sh
Executable file
16
scripts/run.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
source "$ROOT/scripts/env.sh"
|
||||
|
||||
ADDR="${ADDR:-localhost:8788}"
|
||||
|
||||
# Build if missing
|
||||
if [[ ! -x "$ROOT/bin/goondex" ]]; then
|
||||
echo "Binary not found; building first..."
|
||||
"$ROOT/scripts/build.sh"
|
||||
fi
|
||||
|
||||
echo "Starting Goondex web UI on http://$ADDR"
|
||||
"$ROOT/bin/goondex" web --addr "$ADDR"
|
||||
8
scripts/test.sh
Executable file
8
scripts/test.sh
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
source "$ROOT/scripts/env.sh"
|
||||
|
||||
echo "Running focused tests (./cmd/... ./internal/...)"
|
||||
go test ./cmd/... ./internal/...
|
||||
Loading…
Reference in New Issue
Block a user