Skip to content

Commit

Permalink
Allow subdirectories for media
Browse files Browse the repository at this point in the history
  • Loading branch information
Jared K committed Mar 17, 2022
1 parent 7593905 commit dd6ad0f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 83 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/UpDownLeftDie/obs-random-videos/v2

go 1.17
go 1.18

require github.com/sparkdemcisin81/promptui v1.0.0

Expand Down
40 changes: 11 additions & 29 deletions js/main.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
// @ts-check
const mediaFolder = /** @type {string} */ ("http:\\\\absolute\\{{ .MediaFolder }}");
const initMediaFiles = /** @type {string[]} */ (["{{ StringsJoin .MediaFiles "\", \"" }}"]);
const transitionVideo = /** @type {string} */("{{ .TransitionVideo }}");
const transitionVideoPath = /** @type {string} */("{{ .TransitionVideo }}");
const playOnlyOne = /** @type {boolean} */ ({{ .PlayOnlyOne }});
const loopFirstVideo = /** @type {boolean} */ ({{ .LoopFirstVideo }});
const transitionVideoPath = /** @type {string} */ (
`${mediaFolder}${transitionVideo}`
);

let isTransition = true;

/**
* shuffleArr takes in an array and returns a new array in random order
* @param {any[]} a any array to be shuffled
* @param {any[]} originalArray any array to be shuffled
* @return {any[]} shuffled array
*/
function shuffleArr(a) {
var j, x, i;
function shuffleArr(originalArray) {
let a = [...originalArray]
let j, x, i;
for (i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
x = a[i];
Expand All @@ -26,17 +22,6 @@ function shuffleArr(a) {
return a;
}

/**
* prependFolderToFiles simply adds a folder path to a list of files and returns
* the new array
* @param {string} folder folder path, must end with a trailing slash
* @param {string[]} files array of file names
* @returns {string[]} new array with full path to files
*/
function prependFolderToFiles(folder, files) {
return files.map((file) => `${folder}${file}`);
}

/**
* storePlaylistState takes in a playlist and stores it into localstorage
* @param {string[]} state
Expand All @@ -52,10 +37,7 @@ function storePlaylistState(state) {
* @returns {string[]} a new playlist
*/
function getNewPlaylist() {
const playlist = prependFolderToFiles(
mediaFolder,
shuffleArr(initMediaFiles),
);
const playlist = shuffleArr(initMediaFiles);
storePlaylistState(playlist);
return playlist;
}
Expand All @@ -69,9 +51,9 @@ function getPlaylist() {
try {
playlist = JSON.parse(localStorage.getItem('playlist'));
} catch {
console.log('playlist empty!');
console.log('playlist doesn\'t exist yet!');
}
if (!playlist || playlist.length === 0) {
if (!playlist || playlist.length === 0 || typeof playlist.pop === 'undefined') {
playlist = getNewPlaylist();
}
return playlist;
Expand Down Expand Up @@ -99,7 +81,7 @@ function getNextPlaylistItem() {
let mediaItem = playlist.pop();

// check if we played this mediaItem last run
console.log({ lastPlayed: localStorage.getItem('lastPlayed'), mediaItem });
console.log({ lastPlayed: localStorage.getItem('lastPlayed'), mediaItem, wasLastPlayed: localStorage.getItem('lastPlayed') === mediaItem });
if (localStorage.getItem('lastPlayed') === mediaItem) {
// moves the repeated item to the end so its not skipped entirely
storePlaylistState([mediaItem].concat(playlist));
Expand All @@ -124,7 +106,7 @@ function playNext(player, nextPlayer) {
}

let video = localStorage.getItem('lastPlayed');
if (!loopFirstVideo && (!transitionVideo || !isTransition)) {
if (!loopFirstVideo && (!transitionVideoPath || !isTransition)) {
video = getNextPlaylistItem();
console.log(`next video: ${video}`);
}
Expand All @@ -135,7 +117,7 @@ function playNext(player, nextPlayer) {
nextPlayer.style['z-index'] = 0;
nextPlayer.style['opacity'] = '0';

if (transitionVideo && transitionVideo !== '' && isTransition) {
if (transitionVideoPath && transitionVideoPath !== '' && isTransition) {
video = transitionVideoPath;
isTransition = false;
} else {
Expand Down
136 changes: 83 additions & 53 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import (
)

//go:embed template.gohtml
var templateHtml string
var templateHTML string

//go:embed js/main.js
var mainScript string

//go:embed js/body.js
var bodyScript string

// UserAnswers holds config answers from comand line prompt ui
type UserAnswers struct {
MediaFolder string
MediaFiles []string
Expand All @@ -36,6 +37,7 @@ type UserAnswers struct {
TransitionVideo string
}

// Scripts stores javascript scripts that are later injected into templateHTML
type Scripts struct {
MainScript string
BodyScript string
Expand All @@ -46,86 +48,106 @@ var scripts = Scripts{
BodyScript: bodyScript,
}

var outputHtmlName = "obs-random-videos.html"
var audioFileExts = []string{".mp3", ".ogg", ".aac"}
var videoFileExts = []string{".mp4", ".webm", ".mpeg4", ".m4v", ".mov"}
var mediaFileExts = append(audioFileExts, videoFileExts...)
var promptDelay = 100 * time.Millisecond // helps with race conditionsin promptui
var (
outputHTMLName = "obs-random-videos.html"
audioFileExts = []string{".mp3", ".ogg", ".aac"}
videoFileExts = []string{".mp4", ".webm", ".mpeg4", ".m4v", ".mov"}
// imagesFileExts = []string{".png", ".jpg", ".jpeg", ".gif", ".webp"}
// mediaFileExts = append(append(audioFileExts, videoFileExts...), imagesFileExts...)
mediaFileExts = append(audioFileExts, videoFileExts...)
promptDelay = 100 * time.Millisecond // helps with race conditionsin promptui
)

func main() {
currentDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
mainDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
log.Fatalf("Failed to get current directory path: %v", err)
}
separator := string(os.PathSeparator)
currentDirHTML := currentDir + separator
outputHtmlName = currentDirHTML + outputHtmlName
if runtime.GOOS == "windows" {
separatorEscaped := strings.Repeat(separator, 2)
currentDirHTML = strings.Replace(currentDirHTML, separator, separatorEscaped, -1)
}
files, err := os.ReadDir(currentDir)
if err != nil {
log.Fatalf("Failed to read current directory: %v", err)
}
mediaFiles := filterFiles(files, mediaFileExts)
mediaFiles := getMediaFiles(mainDir)
if len(mediaFiles) < 1 {
fmt.Printf("No media files found in: %s", currentDir)
fmt.Printf("No media files found in: %s", mainDir)
fmt.Print("\n\nPress enter to exit...")
input := bufio.NewScanner(os.Stdin)
input.Scan()
return
}

answers, err := askQuestions(currentDirHTML, mediaFiles)
answers, err := askQuestions(mediaFiles, mainDir)
if err != nil {
log.Fatalf("Something went wrong getting user input: %v", err)
}
if answers.TransitionVideo != "" {
answers.MediaFiles = removeTransitionVideo(answers.TransitionVideo, answers.MediaFiles)
}

templateHtml = "<!--\nAUTO GENERATED FILE\nDON'T TOUCH\n-->\n" + templateHtml
var outputHtml bytes.Buffer
t := template.Must(template.New("html").Parse(templateHtml))
err = t.Execute(&outputHtml, scripts)
templateHTML = "<!--\nAUTO GENERATED FILE\nDON'T TOUCH\n-->\n" + templateHTML
var outputHTML bytes.Buffer
t := template.Must(template.New("HTML").Parse(templateHTML))
err = t.Execute(&outputHTML, scripts)
if err != nil {
log.Fatalf("Failed compiling template: %v", err)
}
t = template.Must(template.New("html").Funcs(template.FuncMap{"StringsJoin": strings.Join}).Parse(outputHtml.String()))
outputHtml.Reset()
err = t.Execute(&outputHtml, answers)
t = template.Must(template.New("HTML").Funcs(template.FuncMap{"StringsJoin": strings.Join}).Parse(outputHTML.String()))
outputHTML.Reset()
err = t.Execute(&outputHTML, answers)
if err != nil {
log.Fatalf("Failed compiling template final: %v", err)
}
outputHtmlFile, err := os.Create(outputHtmlName)
outputHTMLFile, err := os.Create(outputHTMLName)
if err != nil {
log.Fatalf("Failed create output file: %v", err)
}
outputHtmlFile.WriteString(outputHtml.String())
outputHtmlFile.Close()
outputHTMLFile.WriteString(outputHTML.String())
outputHTMLFile.Close()
os.Exit(0)
}

func askQuestions(currentDir string, mediaFiles []string) (UserAnswers, error) {
func getMediaFiles(currentDir string) []string {
mediaFiles := []string{}
filepath.WalkDir(currentDir, func(path string, file fs.DirEntry, err error) error {
if err != nil {
return err
}
if !file.IsDir() {
if isValidFileType(file) {
// TODO: move this fix to end of program before injection
// Then clean up getTransitionVideo and show the subpath in the file selector
fixedFilePath := fixFilePath(path)
mediaFiles = append(mediaFiles, fixedFilePath)
}
}
return nil
})
return mediaFiles
}

func fixFilePath(filePath string) string {
separator := string(os.PathSeparator)
newFilePath := fmt.Sprintf("http:%sabsolute%s%s", separator+separator, separator, filePath)
if runtime.GOOS == "windows" {
separatorEscaped := strings.Repeat(separator, 2)
return strings.Replace(newFilePath, separator, separatorEscaped, -1)
}
return newFilePath
}

func askQuestions(mediaFiles []string, mainDir string) (UserAnswers, error) {
answers := UserAnswers{
MediaFolder: currentDir,
MediaFiles: mediaFiles,
PlayOnlyOne: false,
LoopFirstVideo: false,
HaveTransitionVideo: false,
TransitionVideo: "",
}

answers.PlayOnlyOne = ShowQuestion("Do you only want to play one video? (The first random video will play once and then stop)", false)
answers.PlayOnlyOne = showQuestion("Do you only want to play one video? (The first random video will play once and then stop)", false)
if !answers.PlayOnlyOne {
answers.LoopFirstVideo = ShowQuestion("Do you want to loop the first video?", false)
answers.HaveTransitionVideo = ShowQuestion("Do have a transition video? (This video plays after every other video)", false)
answers.LoopFirstVideo = showQuestion("Do you want to loop the first video?", false)
answers.HaveTransitionVideo = showQuestion("Do have a transition video? (This video plays after every other video)", false)
if answers.HaveTransitionVideo {
err := errors.New("")
answers.TransitionVideo, err = GetTransitionVideo(mediaFiles)
answers.TransitionVideo, err = getTransitionVideo(mediaFiles, mainDir)
if err != nil {
fmt.Printf("Prompt failed getting transition video: %v", err)
return answers, err
}
}
Expand All @@ -144,22 +166,24 @@ func removeTransitionVideo(transitionVideo string, mediaFiles []string) []string
return files
}

func filterFiles(files []fs.DirEntry, fileExts []string) []string {
filteredFiles := []string{}
for _, f := range files {
for _, ext := range fileExts {
if strings.HasSuffix(f.Name(), ext) {
filteredFiles = append(filteredFiles, f.Name())
}
func isValidFileType(file fs.DirEntry) bool {
fileExts := mediaFileExts
for _, ext := range fileExts {
if strings.HasSuffix(file.Name(), ext) {
return true
}
}
return filteredFiles
return false
}

func GetTransitionVideo(mediaFiles []string) (string, error) {
func getTransitionVideo(mediaFiles []string, mainDir string) (string, error) {
items := []string{}
for _, f := range mediaFiles {
items = append(items, f)
// Strip full filepath when displaying options to users
for _, filePath := range mediaFiles {
fileParts := strings.Split(filePath, string(os.PathSeparator))
fmt.Printf("%v", fileParts)
fileName := fileParts[len(fileParts)-1]
items = append(items, fileName)
}
items = append(items, "CANCEL")
prompt := promptui.Select{
Expand All @@ -172,12 +196,18 @@ func GetTransitionVideo(mediaFiles []string) (string, error) {
return "", err
}
if strings.ToLower(result) != "cancel" {
return result, nil
// Need to match file name with full path again
for _, filePath := range mediaFiles {
if strings.Contains(filePath, result) {
return filePath, nil
}
}
log.Fatalf("Error occurred when trying to get transition video path for: %s", result)
}
return "", nil
}

func ShowQuestion(message string, defaultValueFlag bool) bool {
func showQuestion(message string, defaultValueFlag bool) bool {
defaultValue := "y"
if !defaultValueFlag {
defaultValue = "n"
Expand All @@ -190,7 +220,7 @@ func ShowQuestion(message string, defaultValueFlag bool) bool {
return nil
}
}
return errors.New(fmt.Sprintf("Number should be one of the values %v", allowedValues))
return fmt.Errorf("number should be one of the values %v", allowedValues)
}

prompt := promptui.Prompt{
Expand All @@ -202,7 +232,7 @@ func ShowQuestion(message string, defaultValueFlag bool) bool {
result, err := prompt.Run()
if err != nil {
time.Sleep(promptDelay)
return ShowQuestion(message, defaultValueFlag)
return showQuestion(message, defaultValueFlag)
}

result = strings.ToLower(result)
Expand Down

0 comments on commit dd6ad0f

Please sign in to comment.