Added music

main
Óscar M. Lage 2024-10-11 13:05:46 +02:00
parent a9989ad8fa
commit 9161423a4b
7 changed files with 274 additions and 15 deletions

View File

@ -9,6 +9,7 @@ GOOGLE_CX=your_google_cx
TWITCH_CLIENT_ID=your_twitch_client_id
TWITCH_SECRET_ID=your_twitch_secret_id
SPOTIFY_API_KEY=your_spotify_api_key
SPOTIFY_SECRET_ID=your_spotify_secret_id
# PATH to Obisdian files where the information is
OBSIDIAN_BOOKS_FILE=/path/to/your/obsidian/books.yml.md

View 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
}

View File

@ -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)
}

View File

@ -2,13 +2,16 @@ package music
type Album struct {
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"`
Link string `yaml:"link"`
Year int `yaml:"year"`
Rate float64 `yaml:"rate"`
Tracks int `yaml:"tracks"`
Image string `yaml:"image"`
Poster string `yaml:"poster-image"`
Background string `yaml:"background-image"`
Date string `yaml:"date"`
Tags []string
}

18
main.go
View File

@ -6,6 +6,7 @@ import (
"hugo-medialog/internal/books"
"hugo-medialog/internal/games"
"hugo-medialog/internal/movies"
"hugo-medialog/internal/music"
"hugo-medialog/internal/series"
"hugo-medialog/utils"
)
@ -30,8 +31,8 @@ func main() {
processBooks()
case "games":
processGames()
// case "music":
// processMusic()
case "music":
processMusic()
default:
fmt.Printf("Invalid media type: %s. Please use movies, series, books, games, or music.\n", *media)
}
@ -43,6 +44,7 @@ func processAll() {
processSeries()
processBooks()
processGames()
processMusic()
}
func processMovies() {
@ -92,3 +94,15 @@ func processGames() {
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)
}
}

View File

@ -1,4 +1,8 @@
- title: "Random Access Memories"
spotify_id: "4m2880jivSbbyEGAKfITCa"
#spotify_id: "4m2880jivSbbyEGAKfITCa"
rate: 9.8
date: 2024-10-08
- title: "Lofi [No copyright]"
rate: 5.5
date: 2024-10-11

View File

@ -2,11 +2,11 @@
title: "{{ .Title }}"
link: "{{ .Link }}"
subtitle: "{{ .Subtitle }}"
artist: "{{ .Artist }}"
year: {{ .Year }}
rate: {{ .Rate }}
image: {{ .Image }}
poster-image: {{ .PosterImage }}
background-image: {{ .BackgroundImage }}
tracks: {{ .Tracks }}
date: {{ .Date }}
draft: false
tags: {{ .Tags }}