Added music
This commit is contained in:
parent
a9989ad8fa
commit
9161423a4b
@ -9,6 +9,7 @@ GOOGLE_CX=your_google_cx
|
|||||||
TWITCH_CLIENT_ID=your_twitch_client_id
|
TWITCH_CLIENT_ID=your_twitch_client_id
|
||||||
TWITCH_SECRET_ID=your_twitch_secret_id
|
TWITCH_SECRET_ID=your_twitch_secret_id
|
||||||
SPOTIFY_API_KEY=your_spotify_api_key
|
SPOTIFY_API_KEY=your_spotify_api_key
|
||||||
|
SPOTIFY_SECRET_ID=your_spotify_secret_id
|
||||||
|
|
||||||
# PATH to Obisdian files where the information is
|
# PATH to Obisdian files where the information is
|
||||||
OBSIDIAN_BOOKS_FILE=/path/to/your/obsidian/books.yml.md
|
OBSIDIAN_BOOKS_FILE=/path/to/your/obsidian/books.yml.md
|
||||||
|
155
internal/music/api_spotify.go
Normal file
155
internal/music/api_spotify.go
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package music
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"hugo-medialog/utils"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
spotifyAPIBaseURL = "https://api.spotify.com/v1/search"
|
||||||
|
spotifyTokenURL = "https://accounts.spotify.com/api/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSpotifyToken() (string, error) {
|
||||||
|
apiKey := os.Getenv("SPOTIFY_API_KEY")
|
||||||
|
apiSecret := os.Getenv("SPOTIFY_SECRET_ID")
|
||||||
|
|
||||||
|
// Prepare the request body
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("grant_type", "client_credentials")
|
||||||
|
|
||||||
|
// Prepare the request
|
||||||
|
req, err := http.NewRequest("POST", spotifyTokenURL, strings.NewReader(data.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the headers
|
||||||
|
req.SetBasicAuth(apiKey, apiSecret)
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Read the response
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the response
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := json.Unmarshal(body, &result); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the access token
|
||||||
|
accessToken, ok := result["access_token"].(string)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("could not retrieve access token")
|
||||||
|
}
|
||||||
|
|
||||||
|
return accessToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchAlbumByTitle(title string, album *Album) error {
|
||||||
|
// Obtain the access token
|
||||||
|
accessToken, err := getSpotifyToken()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search URL
|
||||||
|
titleEsc := url.QueryEscape(fmt.Sprintf("%s", title))
|
||||||
|
url := fmt.Sprintf("%s?q=%s&type=track&limit=1", spotifyAPIBaseURL, titleEsc)
|
||||||
|
|
||||||
|
// Prepare the request and add the auth header
|
||||||
|
req, _ := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the response
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks := result["tracks"].(map[string]interface{})["items"].([]interface{})
|
||||||
|
track := tracks[0].(map[string]interface{})
|
||||||
|
albumData := track["album"].(map[string]interface{})
|
||||||
|
|
||||||
|
album.Artist = track["artists"].([]interface{})[0].(map[string]interface{})["name"].(string)
|
||||||
|
album.ID = albumData["id"].(string)
|
||||||
|
album.Album = albumData["name"].(string)
|
||||||
|
album.Date = albumData["release_date"].(string)
|
||||||
|
album.Year, _ = strconv.Atoi(strings.Split(album.Date, "-")[0])
|
||||||
|
album.Subtitle = strconv.Itoa(album.Year)
|
||||||
|
album.Tracks = int(albumData["total_tracks"].(float64)) // Spotify envía números como float64
|
||||||
|
album.Link = albumData["href"].(string)
|
||||||
|
images := albumData["images"].([]interface{})
|
||||||
|
if len(images) > 0 {
|
||||||
|
firstImage := images[0].(map[string]interface{})
|
||||||
|
album.Image = firstImage["url"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadImage(url, slug string) error {
|
||||||
|
imageDir := filepath.Join(os.Getenv("MARKDOWN_OUTPUT_MUSIC_DIR"), os.Getenv("IMAGES_OUTPUT_DIR"))
|
||||||
|
if err := utils.CreateDirIfNotExists(imageDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
filename := fmt.Sprintf("%s.jpg", slug)
|
||||||
|
filePath := filepath.Join(imageDir, filename)
|
||||||
|
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error downloading image: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("non-200 response while downloading image: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating image file: %w", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error reading image data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = file.Write(body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing image data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" - Image saved successfully at: %s\n", filePath)
|
||||||
|
return nil
|
||||||
|
}
|
@ -1 +1,83 @@
|
|||||||
|
package music
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"hugo-medialog/utils"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadAlbums() ([]Album, error) {
|
||||||
|
albumsFile := os.Getenv("OBSIDIAN_MUSIC_FILE")
|
||||||
|
fileData, err := os.ReadFile(albumsFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var albums []Album
|
||||||
|
err = yaml.Unmarshal(fileData, &albums)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return albums, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessAlbum(albumList []Album) error {
|
||||||
|
for _, album := range albumList {
|
||||||
|
fmt.Printf("Title: %s\n", album.Title)
|
||||||
|
|
||||||
|
// If we dont have ID, search album by Title and get the ID
|
||||||
|
if album.ID == "" {
|
||||||
|
err := SearchAlbumByTitle(album.Title, &album)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error searching album by title %s: %s\n", album.Title, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
album.Slug = utils.Sluggify(album.Title)
|
||||||
|
|
||||||
|
// Now we need to get the image
|
||||||
|
if album.Image != "" {
|
||||||
|
err := DownloadImage(album.Image, album.Slug)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error downloading %s: %s\n", album.Image, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
album.Image = fmt.Sprintf("%s.jpg", album.Slug)
|
||||||
|
|
||||||
|
err := generateAlbumMarkdown(album)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.Sep()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateAlbumMarkdown(album Album) error {
|
||||||
|
templatePath := filepath.Join(os.Getenv("TEMPLATES_DIR"), "music.md.tpl")
|
||||||
|
outputDir := os.Getenv("MARKDOWN_OUTPUT_MUSIC_DIR")
|
||||||
|
if err := utils.CreateDirIfNotExists(outputDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outputPath := filepath.Join(outputDir, fmt.Sprintf("%s.md", album.Slug))
|
||||||
|
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"Title": album.Title,
|
||||||
|
"Artist": album.Artist,
|
||||||
|
"Link": album.Link,
|
||||||
|
"Subtitle": album.Year,
|
||||||
|
"Year": album.Year,
|
||||||
|
"Rate": album.Rate,
|
||||||
|
"Tracks": album.Tracks,
|
||||||
|
"Image": album.Image,
|
||||||
|
"Date": album.Date,
|
||||||
|
"Tags": "listening",
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.GenerateMarkdown(templatePath, outputPath, data)
|
||||||
|
}
|
||||||
|
@ -2,13 +2,16 @@ package music
|
|||||||
|
|
||||||
type Album struct {
|
type Album struct {
|
||||||
Title string `yaml:"title"`
|
Title string `yaml:"title"`
|
||||||
|
Artist string `yaml:"artist"`
|
||||||
|
Album string `yaml:"album"`
|
||||||
|
Slug string `yaml:"slug"`
|
||||||
|
ID string `yaml:"spotify_id"`
|
||||||
Subtitle string `yaml:"subtitle"`
|
Subtitle string `yaml:"subtitle"`
|
||||||
Link string `yaml:"link"`
|
Link string `yaml:"link"`
|
||||||
Year int `yaml:"year"`
|
Year int `yaml:"year"`
|
||||||
Rate float64 `yaml:"rate"`
|
Rate float64 `yaml:"rate"`
|
||||||
|
Tracks int `yaml:"tracks"`
|
||||||
Image string `yaml:"image"`
|
Image string `yaml:"image"`
|
||||||
Poster string `yaml:"poster-image"`
|
|
||||||
Background string `yaml:"background-image"`
|
|
||||||
Date string `yaml:"date"`
|
Date string `yaml:"date"`
|
||||||
Tags []string
|
Tags []string
|
||||||
}
|
}
|
||||||
|
18
main.go
18
main.go
@ -6,6 +6,7 @@ import (
|
|||||||
"hugo-medialog/internal/books"
|
"hugo-medialog/internal/books"
|
||||||
"hugo-medialog/internal/games"
|
"hugo-medialog/internal/games"
|
||||||
"hugo-medialog/internal/movies"
|
"hugo-medialog/internal/movies"
|
||||||
|
"hugo-medialog/internal/music"
|
||||||
"hugo-medialog/internal/series"
|
"hugo-medialog/internal/series"
|
||||||
"hugo-medialog/utils"
|
"hugo-medialog/utils"
|
||||||
)
|
)
|
||||||
@ -30,8 +31,8 @@ func main() {
|
|||||||
processBooks()
|
processBooks()
|
||||||
case "games":
|
case "games":
|
||||||
processGames()
|
processGames()
|
||||||
// case "music":
|
case "music":
|
||||||
// processMusic()
|
processMusic()
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Invalid media type: %s. Please use movies, series, books, games, or music.\n", *media)
|
fmt.Printf("Invalid media type: %s. Please use movies, series, books, games, or music.\n", *media)
|
||||||
}
|
}
|
||||||
@ -43,6 +44,7 @@ func processAll() {
|
|||||||
processSeries()
|
processSeries()
|
||||||
processBooks()
|
processBooks()
|
||||||
processGames()
|
processGames()
|
||||||
|
processMusic()
|
||||||
}
|
}
|
||||||
|
|
||||||
func processMovies() {
|
func processMovies() {
|
||||||
@ -92,3 +94,15 @@ func processGames() {
|
|||||||
fmt.Printf("Error processing games: %v\n", err)
|
fmt.Printf("Error processing games: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processMusic() {
|
||||||
|
albumList, err := music.LoadAlbums()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading music file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = music.ProcessAlbum(albumList)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error processing music: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
- title: "Random Access Memories"
|
- title: "Random Access Memories"
|
||||||
spotify_id: "4m2880jivSbbyEGAKfITCa"
|
#spotify_id: "4m2880jivSbbyEGAKfITCa"
|
||||||
rate: 9.8
|
rate: 9.8
|
||||||
date: 2024-10-08
|
date: 2024-10-08
|
||||||
|
|
||||||
|
- title: "Lofi [No copyright]"
|
||||||
|
rate: 5.5
|
||||||
|
date: 2024-10-11
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
title: "{{ .Title }}"
|
title: "{{ .Title }}"
|
||||||
link: "{{ .Link }}"
|
link: "{{ .Link }}"
|
||||||
subtitle: "{{ .Subtitle }}"
|
subtitle: "{{ .Subtitle }}"
|
||||||
|
artist: "{{ .Artist }}"
|
||||||
year: {{ .Year }}
|
year: {{ .Year }}
|
||||||
rate: {{ .Rate }}
|
rate: {{ .Rate }}
|
||||||
image: {{ .Image }}
|
image: {{ .Image }}
|
||||||
poster-image: {{ .PosterImage }}
|
tracks: {{ .Tracks }}
|
||||||
background-image: {{ .BackgroundImage }}
|
|
||||||
date: {{ .Date }}
|
date: {{ .Date }}
|
||||||
draft: false
|
draft: false
|
||||||
tags: {{ .Tags }}
|
tags: {{ .Tags }}
|
||||||
|
Loading…
Reference in New Issue
Block a user