Skip to content

Instantly share code, notes, and snippets.

@tioan
Forked from blachniet/stars2drops.go
Last active June 15, 2024 16:53
Show Gist options
  • Save tioan/3e07c2c29baac6bd1dcdeff5f6a336da to your computer and use it in GitHub Desktop.
Save tioan/3e07c2c29baac6bd1dcdeff5f6a336da to your computer and use it in GitHub Desktop.
package main
import (
"encoding/csv"
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"os"
"strconv"
"strings"
)
func usage() {
fmt.Fprintf(flag.CommandLine.Output(), "stars2drops - convert GitHub stars to a Raindrop.io CSV file\n\n")
fmt.Fprintf(flag.CommandLine.Output(), "You can upload the resulting CSV file to your Raindrop.io account here: https://app.raindrop.io/settings/import. See https://help.raindrop.io/import/#csv for more information on the CSV format.")
fmt.Fprintf(flag.CommandLine.Output(), "\n\n")
fmt.Fprintf(flag.CommandLine.Output(), "environment variables:\n")
fmt.Fprintf(flag.CommandLine.Output(), " GH_PAT\n")
fmt.Fprintf(flag.CommandLine.Output(), " \trequired - GitHub fine-grained token with read-only 'starring' permissions: https://github.com/settings/tokens?type=beta\n")
fmt.Fprintf(flag.CommandLine.Output(), "\nargs:\n")
flag.PrintDefaults()
}
func main() {
var folder string
var tags string
flag.StringVar(&folder, "folder", "Unsorted", "Raindrop.io folder to put bookmarks in")
flag.StringVar(&tags, "tags", "", "comma-separated list of tags to apply to all bookmarks")
flag.Usage = usage
flag.Parse()
pat := os.Getenv("GH_PAT")
if pat == "" {
log.Fatalln("err: GH_PAT environment varable not set")
}
stars, err := getStars(pat)
if err != nil {
log.Fatalln("err: retrieving stars: ", err)
}
writer := csv.NewWriter(os.Stdout)
err = writer.Write([]string{"url", "folder", "title", "description", "tags", "created"})
if err != nil {
log.Fatal("err: write csv: ", err)
}
for _, star := range stars {
err = writer.Write([]string{star.Repo.HTMLURL, folder, star.Repo.FullName, star.Repo.Description, tags, star.StarredAt})
if err != nil {
log.Fatalln("err: write csv: ", err)
}
}
writer.Flush()
if err = writer.Error(); err != nil {
log.Fatalln("err: write csv: ", err)
}
}
func getStars(pat string) ([]ghStar, error) {
var stars []ghStar
page := 1
for {
req, err := http.NewRequest(http.MethodGet, "https://api.github.com/user/starred?page="+strconv.Itoa(page), nil)
if err != nil {
return stars, fmt.Errorf("build request: %w", err)
}
req.Header.Set("Accept", "application/vnd.github.star+json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", pat))
req.Header.Set("X-GitHub-Api-Version", "2022-11-28")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return stars, fmt.Errorf("do request: %w", err)
}
var pageStars []ghStar
err = json.NewDecoder(res.Body).Decode(&pageStars)
if err != nil {
return stars, fmt.Errorf("decode json: %w", err)
}
res.Body.Close()
stars = append(stars, pageStars...)
linkHeader := res.Header.Get("Link")
if !strings.Contains(linkHeader, `rel="next"`) {
break
}
page++
}
return stars, nil
}
type ghStar struct {
StarredAt string `json:"starred_at"`
Repo ghStarRepo `json:"repo"`
}
type ghStarRepo struct {
HTMLURL string `json:"html_url"`
FullName string `json:"full_name"`
Description string `json:"description"`
}
@tioan
Copy link
Author

tioan commented Jun 14, 2024

bugfixing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment