Created
June 27, 2018 22:36
-
-
Save severak/58785a9cc192fa7fc642160845b9ceba to your computer and use it in GitHub Desktop.
sotd playlist 2.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"database/sql" | |
"fmt" | |
"flag" | |
"os" | |
// "html/template" | |
"strings" | |
"net/url" | |
"errors" | |
"encoding/json" | |
_ "github.com/mattn/go-sqlite3" | |
) | |
type PlaylistItem struct { | |
Id string `json:"id"` | |
DJ string `json:"dj"` | |
} | |
type Playlist struct { | |
Title string `json:"title"` | |
Videos []PlaylistItem `json:"videos"` | |
} | |
func getYoutubeId(video string) (string, error) { | |
u, err := url.Parse(video) | |
if err != nil { | |
return "", errors.New("Cannot parse URL.") | |
} | |
if (u.Host != "youtu.be" && u.Host != "youtube.com" && u.Host != "www.youtube.com") { | |
return "", errors.New("Not a youtube URL.") | |
} | |
if u.Host=="youtu.be" { | |
return strings.TrimPrefix(u.Path, "/"), nil | |
} | |
q := u.Query() | |
if q.Get("v") != "" { | |
return q.Get("v"), nil | |
} | |
if q.Get("vi") != "" { | |
return q.Get("vi"), nil | |
} | |
return "", errors.New("Missing URL param.") | |
} | |
func main() { | |
dbFile := flag.String("db", "/home/caff/code/sotdbot/sotd.db", "database file to read") | |
limit := flag.Int("limit", 72, "max number of included videos") | |
flag.Parse() | |
if _, err := os.Stat(*dbFile); os.IsNotExist(err) { | |
fmt.Printf("file %s not exists!\n", *dbFile) | |
os.Exit(2) | |
} | |
db, err := sql.Open("sqlite3", *dbFile) | |
checkErr(err) | |
defer db.Close() | |
checkErr(db.Ping()) | |
name := flag.Arg(0) | |
rows, err := db.Query("SELECT username, link FROM sotd ORDER BY created_at DESC") | |
if flag.Arg(0) != "" { | |
rows, err = db.Query("SELECT username, link FROM sotd WHERE username=? ORDER BY created_at DESC", "~" + name ) | |
} | |
if name == "" { | |
name = "town" | |
} | |
checkErr(err) | |
defer rows.Close() | |
plist := Playlist{Title: name + "'s playlist"} | |
added := 0 | |
for rows.Next() { | |
var link string | |
var username string | |
err := rows.Scan(&username, &link) | |
checkErr(err) | |
if vid, viderr := getYoutubeId(link); viderr==nil { | |
plist.Videos = append(plist.Videos, PlaylistItem{Id: vid, DJ: username}) | |
added = added + 1 | |
if added==*limit { | |
break | |
} | |
} | |
} | |
err = rows.Err() | |
checkErr(err) | |
output, err := json.MarshalIndent(plist, "", " ") | |
if err != nil { | |
checkErr(err) | |
} | |
fmt.Println(string(output)) | |
} | |
func checkErr(err error, args ...string) { | |
if err != nil { | |
fmt.Println("Error") | |
fmt.Println("%q: %s", err, args) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> | |
<title>town's radio</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" href="//tilde.town/~severak/flogiston-tui.css"> | |
</head> | |
<body> | |
<div class="flogiston-page"> | |
<div class="flogiston-article"> | |
<h1 id="title">loading...</h1> | |
<p>now playing:<br><strong id="songName">?</strong><br>recommended by DJ <a id="djName" href="#">?</a></p> | |
<div id="player"></div> | |
<p><a href="?shuffle=1">shuffle</a> <a href="?order">play in order</a></p> | |
<hr> | |
<small>generated using <a href="https://gist.github.com/severak/9abf7080d4691d71639d879d6d82a265">this ugly script</a> by <a href="https://tilde.town/~severak">severak</a></small> | |
</div> | |
</div> | |
<script> | |
fetch('town.json').then(function(response) { return response.json() }).then(function(remote){ | |
var playlist = remote.videos; | |
document.title = remote.title; | |
document.getElementById('title').textContent = remote.title; | |
var details = {}; | |
var idList = []; | |
playlist.forEach(function(vid){ | |
details[vid.id] = vid; | |
idList.push(vid.id); | |
}); | |
var url = new URL(window.location.href); | |
var shuffle = url.searchParams.get("shuffle"); | |
// 2. This code loads the IFrame Player API code asynchronously. | |
var tag = document.createElement('script'); | |
tag.src = "https://www.youtube.com/iframe_api"; | |
var firstScriptTag = document.getElementsByTagName('script')[0]; | |
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); | |
// 3. This function creates an <iframe> (and YouTube player) | |
// after the API code downloads. | |
var player; | |
window.onYouTubeIframeAPIReady = function() { | |
player = new YT.Player('player', { | |
height: '360', | |
width: '640', | |
videoId: idList.pop(), | |
events: { | |
'onReady': onPlayerReady, | |
'onStateChange': onPlayerStateChange | |
} | |
}); | |
} | |
// 4. The API will call this function when the video player is ready. | |
function onPlayerReady(event) { | |
event.target.loadPlaylist({playlist: idList}); | |
if (shuffle) { | |
event.target.setShuffle(true); | |
} | |
} | |
function updateNowPlaying() { | |
var vdata = player.getVideoData(); | |
document.getElementById('songName').textContent = vdata.title; | |
var dj = details[vdata.video_id]['dj'] | |
document.getElementById('djName').textContent = dj; | |
document.getElementById('djName').href = 'https://tilde.town/' + dj; | |
} | |
// 5. The API calls this function when the player's state changes. | |
// The function indicates that when playing a video (state=1), | |
// the player should play for six seconds and then stop. | |
function onPlayerStateChange(event) { | |
//if (event.data == 0 || event.data == 5) { | |
updateNowPlaying(); | |
//} | |
} | |
}) | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment