Support streaming; error if cmd or types are empty

This commit is contained in:
makeworld 2020-12-24 23:38:12 -05:00
parent 41ebf22df8
commit bf47a1d57a
4 changed files with 74 additions and 10 deletions

View File

@ -50,6 +50,7 @@ var HTTPCommand []string
type MediaHandler struct {
Cmd []string
NoPrompt bool
Stream bool
}
var MediaHandlers = make(map[string]MediaHandler)
@ -365,12 +366,20 @@ func Init() error {
Cmd []string `mapstructure:"cmd"`
Types []string `mapstructure:"types"`
NoPrompt bool `mapstructure:"no_prompt"`
Stream bool `mapstructure:"stream"`
}
err = viper.UnmarshalKey("mediatype-handlers", &rawMediaHandlers)
if err != nil {
return fmt.Errorf("couldn't parse mediatype-handlers section in config: %w", err)
}
for _, rawMediaHandler := range rawMediaHandlers {
if len(rawMediaHandler.Cmd) == 0 {
return fmt.Errorf("empty cmd array in mediatype-handlers section")
}
if len(rawMediaHandler.Types) == 0 {
return fmt.Errorf("empty types array in mediatype-handlers section")
}
for _, typ := range rawMediaHandler.Types {
if _, ok := MediaHandlers[typ]; ok {
return fmt.Errorf("multiple mediatype-handlers defined for %v", typ)
@ -378,6 +387,7 @@ func Init() error {
MediaHandlers[typ] = MediaHandler{
Cmd: rawMediaHandler.Cmd,
NoPrompt: rawMediaHandler.NoPrompt,
Stream: rawMediaHandler.Stream,
}
}
}

View File

@ -162,10 +162,13 @@ other = 'off'
# You only need to configure this section if you want to override your default application,
# or do special things like streaming.
#
# Note the use of single quotes for commands, so that backslashes will not be escaped.
#
#
# To open jpeg files with the feh command:
#
# [[mediatype-handlers]]
# cmd = ["feh"]
# cmd = ['feh']
# types = ["image/jpeg"]
#
# Each command that you specify must come under its own [[mediatype-handlers]]. You may
@ -175,7 +178,7 @@ other = 'off'
# entire type:
#
# [[mediatype-handlers]]
# command = ["vlc", "--flag"]
# command = ['vlc', '--flag']
# types = ["audio", "video"]
#
# A catch-all handler can by specified with "*".
@ -184,17 +187,30 @@ other = 'off'
# want to override that.
#
# [[mediatype-handlers]]
# cmd = ["some-command"]
# cmd = ['some-command']
# types = [
# "application/pdf",
# "*",
# ]
#
# You can also choose to stream the data instead of downloading it all before
# opening it. This is especially useful for large video or audio files, as
# well as radio streams, which will never complete. You can do this like so:
#
# [[mediatype-handlers]]
# cmd = ['vlc', '-']
# types = ["audio", "video"]
# stream = true
#
# This uses vlc to stream all video and audio content.
# By default stream is set to off for all handlers
#
#
# If you want to always open a type in its viewer without the download or open
# prompt appearing, you can add no_prompt = true
#
# [[mediatype-handlers]]
# cmd = ["feh"]
# cmd = ['feh']
# types = ["image"]
# no_prompt = true
#

View File

@ -159,10 +159,13 @@ other = 'off'
# You only need to configure this section if you want to override your default application,
# or do special things like streaming.
#
# Note the use of single quotes for commands, so that backslashes will not be escaped.
#
#
# To open jpeg files with the feh command:
#
# [[mediatype-handlers]]
# cmd = ["feh"]
# cmd = ['feh']
# types = ["image/jpeg"]
#
# Each command that you specify must come under its own [[mediatype-handlers]]. You may
@ -172,7 +175,7 @@ other = 'off'
# entire type:
#
# [[mediatype-handlers]]
# command = ["vlc", "--flag"]
# command = ['vlc', '--flag']
# types = ["audio", "video"]
#
# A catch-all handler can by specified with "*".
@ -181,17 +184,30 @@ other = 'off'
# want to override that.
#
# [[mediatype-handlers]]
# cmd = ["some-command"]
# cmd = ['some-command']
# types = [
# "application/pdf",
# "*",
# ]
#
# You can also choose to stream the data instead of downloading it all before
# opening it. This is especially useful for large video or audio files, as
# well as radio streams, which will never complete. You can do this like so:
#
# [[mediatype-handlers]]
# cmd = ['vlc', '-']
# types = ["audio", "video"]
# stream = true
#
# This uses vlc to stream all video and audio content.
# By default stream is set to off for all handlers
#
#
# If you want to always open a type in its viewer without the download or open
# prompt appearing, you can add no_prompt = true
#
# [[mediatype-handlers]]
# cmd = ["feh"]
# cmd = ['feh']
# types = ["image"]
# no_prompt = true
#

View File

@ -90,6 +90,7 @@ func getMediaHandler(resp *gemini.Response) config.MediaHandler {
def := config.MediaHandler{
Cmd: nil,
NoPrompt: false,
Stream: false,
}
mediatype, _, err := mime.ParseMediaType(resp.Meta)
@ -116,8 +117,6 @@ func getMediaHandler(resp *gemini.Response) config.MediaHandler {
// dlChoice displays the download choice modal and acts on the user's choice.
// It should run in a goroutine.
func dlChoice(text, u string, resp *gemini.Response) {
defer resp.Body.Close()
mediaHandler := getMediaHandler(resp)
var choice string
@ -136,6 +135,7 @@ func dlChoice(text, u string, resp *gemini.Response) {
tabPages.HidePage("dlChoice")
App.Draw()
downloadURL(config.DownloadsDir, u, resp)
resp.Body.Close() // Only close when the file is downloaded
return
}
if choice == "Open" {
@ -154,6 +154,28 @@ func dlChoice(text, u string, resp *gemini.Response) {
// with the default system viewer.
func open(u string, resp *gemini.Response) {
mediaHandler := getMediaHandler(resp)
if mediaHandler.Stream {
// Run command with downloaded data from stdin
cmd := mediaHandler.Cmd
var proc *exec.Cmd
if len(cmd) == 1 {
proc = exec.Command(cmd[0])
} else {
proc = exec.Command(cmd[0], cmd[1:]...)
}
proc.Stdin = resp.Body
err := proc.Start()
if err != nil {
Error("File Opening Error", "Error executing custom command: "+err.Error())
return
}
Info("Opened with " + cmd[0])
return
}
path := downloadURL(config.TempDownloadsDir, u, resp)
if path == "" {
return