187 lines
4.7 KiB
Go
187 lines
4.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/csv"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Movie struct {
|
|
Adult bool
|
|
Backdrop_path string
|
|
Genre_ids []int
|
|
Id int
|
|
Original_language string
|
|
Original_title string
|
|
Overview string
|
|
Popularity float64
|
|
Poster_path string
|
|
Release_date string
|
|
Title string
|
|
Video bool
|
|
Vote_average float64
|
|
Vote_count int
|
|
}
|
|
|
|
type Response struct {
|
|
Page int
|
|
Results []Movie
|
|
Total_pages int
|
|
Total_results int
|
|
}
|
|
|
|
func main() {
|
|
fmt.Println("Enter the input CSV file name:")
|
|
inputFileName := getInput()
|
|
fmt.Println("Enter the TMDB API Key:")
|
|
apiKey := getInput()
|
|
|
|
// Open output CSV file
|
|
outputFileName := "movies.csv"
|
|
outputFile, err := os.Create(outputFileName)
|
|
if err != nil {
|
|
fmt.Printf("Error creating output file: %v\n", err)
|
|
return
|
|
}
|
|
defer outputFile.Close()
|
|
|
|
writer := csv.NewWriter(outputFile)
|
|
writer.UseCRLF = true
|
|
writer.Comma = ','
|
|
defer writer.Flush()
|
|
|
|
processFile(inputFileName, apiKey, writer)
|
|
|
|
// Check failed.csv
|
|
checkFailedCsv(apiKey, writer)
|
|
}
|
|
|
|
func getInput() string {
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
scanner.Scan()
|
|
return scanner.Text()
|
|
}
|
|
|
|
func processFile(inputFileName, apiKey string, writer *csv.Writer) {
|
|
// Open the file
|
|
file, err := os.Open(inputFileName)
|
|
if err != nil {
|
|
fmt.Printf("Error opening file: %v\n", err)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
// Open failed.csv
|
|
failedFileName := "failed.csv"
|
|
failedFile, err := os.Create(failedFileName)
|
|
if err != nil {
|
|
fmt.Printf("Error creating failed.csv: %v\n", err)
|
|
return
|
|
}
|
|
defer failedFile.Close()
|
|
|
|
failedWriter := csv.NewWriter(failedFile)
|
|
failedWriter.UseCRLF = true
|
|
failedWriter.Comma = ','
|
|
defer failedWriter.Flush()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
requests := time.Tick(time.Millisecond * 20) // Limit requests to 50 per second
|
|
|
|
for scanner.Scan() {
|
|
<-requests // Wait until we are allowed to perform a request
|
|
movie := scanner.Text()
|
|
movie = strings.Trim(movie, "\"") // Remove surrounding quotes
|
|
title, year, err := parseMovieTitleYear(movie)
|
|
if err != nil {
|
|
fmt.Printf("Failed to parse movie: %s, Error: %v\n", movie, err)
|
|
_ = failedWriter.Write([]string{title, year})
|
|
failedWriter.Flush() // Immediately write the failed record to the file
|
|
continue
|
|
}
|
|
fmt.Printf("Searching for movie: %s\n", movie)
|
|
popularity, err := getMovieData(title, year, apiKey)
|
|
if err != nil {
|
|
fmt.Printf("Failed to get data for movie: %s, Error: %v\n", movie, err)
|
|
_ = failedWriter.Write([]string{title, year})
|
|
failedWriter.Flush() // Immediately write the failed record to the file
|
|
continue
|
|
}
|
|
record := []string{title, year, fmt.Sprintf("%f", popularity)}
|
|
_ = writer.Write(record)
|
|
fmt.Printf("Movie: %s, Popularity: %f\n", movie, popularity)
|
|
}
|
|
}
|
|
|
|
func parseMovieTitleYear(movie string) (string, string, error) {
|
|
parts := strings.SplitN(movie, ",", 2)
|
|
if len(parts) < 2 {
|
|
return "", "", fmt.Errorf("invalid movie format: %s", movie)
|
|
}
|
|
title := parts[0]
|
|
year := parts[1]
|
|
return title, year, nil
|
|
}
|
|
|
|
func getMovieData(title, year, apiKey string) (float64, error) {
|
|
// url encode the title
|
|
encodedTitle := url.QueryEscape(title)
|
|
|
|
url := fmt.Sprintf("https://api.themoviedb.org/3/search/movie?include_adult=false&language=en-US&year=%s&page=1&query=%s", year, encodedTitle)
|
|
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
req.Header.Add("Authorization", "Bearer "+apiKey)
|
|
req.Header.Add("accept", "application/json")
|
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
if err != nil || res == nil {
|
|
return 0, fmt.Errorf("failed to make request: %v", err)
|
|
}
|
|
|
|
if res.StatusCode != 200 {
|
|
return 0, fmt.Errorf("received non-200 response: %d", res.StatusCode)
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
var response Response
|
|
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
|
|
return 0, fmt.Errorf("failed to decode response: %v", err)
|
|
}
|
|
|
|
if len(response.Results) == 0 {
|
|
return 0, fmt.Errorf("no results found")
|
|
}
|
|
return response.Results[0].Popularity, nil
|
|
}
|
|
|
|
func checkFailedCsv(apiKey string, writer *csv.Writer) {
|
|
for {
|
|
fmt.Println("Do you want to check failed.csv and retry fetching data for failed movies? (Y/n)")
|
|
retry := getInput()
|
|
if strings.EqualFold(retry, "n") {
|
|
break
|
|
}
|
|
if retry == "" || strings.EqualFold(retry, "y") {
|
|
fmt.Println("Processing failed.csv...")
|
|
// Recreate failed.csv for the next run
|
|
failedFileName := "failed.csv"
|
|
failedFile, err := os.Create(failedFileName)
|
|
if err != nil {
|
|
fmt.Printf("Error creating failed.csv: %v\n", err)
|
|
return
|
|
}
|
|
failedFile.Close()
|
|
|
|
// Process the old failed.csv
|
|
processFile(failedFileName, apiKey, writer)
|
|
}
|
|
}
|
|
}
|